Skip to content

Commit 2b27aa9

Browse files
authored
Merge pull request #23 from ionut-arm/option-provider
Make `implicit_provider` optional
2 parents 21c406f + 734d3a3 commit 2b27aa9

File tree

4 files changed

+104
-50
lines changed

4 files changed

+104
-50
lines changed

src/core/basic_client.rs

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,23 @@ use std::collections::HashSet;
2424
/// The client exposes low-level functionality for using the Parsec service.
2525
/// Below you can see code examples for a few of the operations supported.
2626
///
27+
/// For all cryptographic operations an implicit provider is used which can be
28+
/// changed between operations. The client starts with no such defined provider
29+
/// and it is the responsibility of the user to identify and set an appropriate
30+
/// one. As such, it is critical that before attempting to use cryptographic
31+
/// operations users call [`list_providers`](#method.list_providers)
32+
/// and [`list_opcodes`](#method.list_opcodes)
33+
/// in order to figure out if their desired use case and provider are
34+
/// available.
35+
///
2736
/// Creating a `BasicClient` instance:
2837
///```no_run
2938
///use parsec_client::auth::AuthenticationData;
3039
///use parsec_client::BasicClient;
31-
///use parsec_client::core::ProviderID;
3240
///
3341
///let app_name = String::from("app-name");
3442
///let app_auth_data = AuthenticationData::AppIdentity(app_name);
35-
///let desired_provider = ProviderID::Pkcs11;
36-
///let client: BasicClient = BasicClient::new(app_auth_data, desired_provider);
43+
///let client: BasicClient = BasicClient::new(app_auth_data);
3744
///```
3845
///
3946
/// Performing a Ping operation helps to determine if the service is available
@@ -43,7 +50,7 @@ use std::collections::HashSet;
4350
///# use parsec_client::auth::AuthenticationData;
4451
///# use parsec_client::BasicClient;
4552
///# use parsec_client::core::ProviderID;
46-
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")), ProviderID::Pkcs11);
53+
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
4754
///let res = client.ping();
4855
///
4956
///if let Ok((wire_prot_v_maj, wire_prot_v_min)) = res {
@@ -65,7 +72,7 @@ use std::collections::HashSet;
6572
///# use parsec_client::auth::AuthenticationData;
6673
///# use parsec_client::BasicClient;
6774
///# use parsec_client::core::ProviderID;
68-
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")), ProviderID::Pkcs11);
75+
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
6976
///use uuid::Uuid;
7077
///
7178
///// Identify provider by its UUID (in this case, the PKCS11 provider)
@@ -82,30 +89,33 @@ use std::collections::HashSet;
8289
///```
8390
///
8491
/// Checking operations supported by the provider we're interested in is done
85-
/// through the `list_provider_operations` method:
92+
/// through the `list_opcodes` method:
8693
///```no_run
8794
///# use parsec_client::auth::AuthenticationData;
8895
///# use parsec_client::BasicClient;
8996
///# use parsec_client::core::ProviderID;
90-
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")), ProviderID::Pkcs11);
97+
///# let mut client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
9198
///use parsec_client::core::Opcode;
9299
///
93100
///let desired_provider = ProviderID::Pkcs11;
94101
///let provider_opcodes = client
95-
/// .list_provider_operations(desired_provider)
102+
/// .list_opcodes(desired_provider)
96103
/// .expect("Failed to list opcodes");
97104
///// Each operation is identified by a specific `Opcode`
98105
///assert!(provider_opcodes.contains(&Opcode::PsaGenerateKey));
99106
///assert!(provider_opcodes.contains(&Opcode::PsaSignHash));
100107
///assert!(provider_opcodes.contains(&Opcode::PsaDestroyKey));
108+
///
109+
///// Now that we're certain our desired provider offers all the functionality we need...
110+
///client.set_implicit_provider(desired_provider);
101111
///```
102112
///
103113
/// Creating a key-pair for signing SHA256 digests with RSA PKCS#1 v1.5:
104114
///```no_run
105115
///# use parsec_client::auth::AuthenticationData;
106116
///# use parsec_client::BasicClient;
107117
///# use parsec_client::core::ProviderID;
108-
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")), ProviderID::Pkcs11);
118+
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
109119
///use parsec_client::core::psa_algorithm::{Algorithm, AsymmetricSignature, Hash};
110120
///use parsec_client::core::psa_key_attributes::{KeyAttributes, KeyPolicy, KeyType, UsageFlags};
111121
///
@@ -143,35 +153,25 @@ use std::collections::HashSet;
143153
/// .psa_generate_key(key_name, key_attrs)
144154
/// .expect("Failed to create key!");
145155
///```
146-
///
147-
/// It is recommended that before attempting to use cryptographic
148-
/// operations users call [`list_providers`](#method.list_providers)
149-
/// and [`list_provider_operations`](#method.list_provider_operations)
150-
/// in order to figure out if their desired use case and provider are
151-
/// available.
152156
#[derive(Debug)]
153157
pub struct BasicClient {
154158
pub(crate) op_client: OperationClient,
155159
pub(crate) auth_data: AuthenticationData,
156-
pub(crate) implicit_provider: ProviderID,
160+
pub(crate) implicit_provider: Option<ProviderID>,
157161
}
158162

159163
/// Main client functionality.
160164
impl BasicClient {
161-
/// Create a new Parsec client given the authentication data of the app and a provider ID.
162-
///
163-
/// The `implicit_provider` will be used for all non-core operations. Thus, until a
164-
/// different provider ID is set using [`set_implicit_provider`](#method.set_implicit_provider),
165-
/// all cryptographic operations will be executed in the context of this provider (if it is
166-
/// available within the service).
165+
/// Create a new Parsec client given the authentication data of the app.
167166
///
168-
/// In order to get a list of supported providers, call the [`list_providers`](#method.list_providers)
169-
/// method.
170-
pub fn new(auth_data: AuthenticationData, implicit_provider: ProviderID) -> Self {
167+
/// Before you can use this client for cryptographic operations, you first need to call
168+
/// [`set_implicit_provider`](#method.set_implicit_provider). In order to get a list of
169+
/// supported providers, call the [`list_providers`](#method.list_providers) method.
170+
pub fn new(auth_data: AuthenticationData) -> Self {
171171
BasicClient {
172172
op_client: Default::default(),
173173
auth_data,
174-
implicit_provider,
174+
implicit_provider: None,
175175
}
176176
}
177177

@@ -187,16 +187,16 @@ impl BasicClient {
187187

188188
/// Set the provider that the client will be implicitly working with.
189189
pub fn set_implicit_provider(&mut self, provider: ProviderID) {
190-
self.implicit_provider = provider;
190+
self.implicit_provider = Some(provider);
191191
}
192192

193193
/// Retrieve client's implicit provider.
194-
pub fn implicit_provider(&self) -> ProviderID {
194+
pub fn implicit_provider(&self) -> Option<ProviderID> {
195195
self.implicit_provider
196196
}
197197

198198
/// **[Core Operation]** List the opcodes supported by the specified provider.
199-
pub fn list_provider_operations(&self, provider: ProviderID) -> Result<HashSet<Opcode>> {
199+
pub fn list_opcodes(&self, provider: ProviderID) -> Result<HashSet<Opcode>> {
200200
let res = self.op_client.process_operation(
201201
NativeOperation::ListOpcodes(ListOpcodes {
202202
provider_id: provider,
@@ -271,10 +271,13 @@ impl BasicClient {
271271
/// If the implicit client provider is `ProviderID::Core`, a client error
272272
/// of `InvalidProvider` type is returned.
273273
///
274+
/// If the implicit client provider has not been set, a client error of
275+
/// `NoProvider` type is returned.
276+
///
274277
/// See the operation-specific response codes returned by the service
275278
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_generate_key.html#specific-response-status-codes).
276279
pub fn psa_generate_key(&self, key_name: String, key_attributes: KeyAttributes) -> Result<()> {
277-
self.can_provide_crypto()?;
280+
let crypto_provider = self.can_provide_crypto()?;
278281

279282
let op = PsaGenerateKey {
280283
key_name,
@@ -283,7 +286,7 @@ impl BasicClient {
283286

284287
let _ = self.op_client.process_operation(
285288
NativeOperation::PsaGenerateKey(op),
286-
self.implicit_provider,
289+
crypto_provider,
287290
&self.auth_data,
288291
)?;
289292

@@ -301,16 +304,19 @@ impl BasicClient {
301304
/// If the implicit client provider is `ProviderID::Core`, a client error
302305
/// of `InvalidProvider` type is returned.
303306
///
307+
/// If the implicit client provider has not been set, a client error of
308+
/// `NoProvider` type is returned.
309+
///
304310
/// See the operation-specific response codes returned by the service
305311
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_destroy_key.html#specific-response-status-codes).
306312
pub fn psa_destroy_key(&self, key_name: String) -> Result<()> {
307-
self.can_provide_crypto()?;
313+
let crypto_provider = self.can_provide_crypto()?;
308314

309315
let op = PsaDestroyKey { key_name };
310316

311317
let _ = self.op_client.process_operation(
312318
NativeOperation::PsaDestroyKey(op),
313-
self.implicit_provider,
319+
crypto_provider,
314320
&self.auth_data,
315321
)?;
316322

@@ -341,6 +347,9 @@ impl BasicClient {
341347
/// If the implicit client provider is `ProviderID::Core`, a client error
342348
/// of `InvalidProvider` type is returned.
343349
///
350+
/// If the implicit client provider has not been set, a client error of
351+
/// `NoProvider` type is returned.
352+
///
344353
/// See the operation-specific response codes returned by the service
345354
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_import_key.html#specific-response-status-codes).
346355
pub fn psa_import_key(
@@ -349,7 +358,7 @@ impl BasicClient {
349358
key_material: Vec<u8>,
350359
key_attributes: KeyAttributes,
351360
) -> Result<()> {
352-
self.can_provide_crypto()?;
361+
let crypto_provider = self.can_provide_crypto()?;
353362

354363
let op = PsaImportKey {
355364
key_name,
@@ -359,7 +368,7 @@ impl BasicClient {
359368

360369
let _ = self.op_client.process_operation(
361370
NativeOperation::PsaImportKey(op),
362-
self.implicit_provider,
371+
crypto_provider,
363372
&self.auth_data,
364373
)?;
365374

@@ -382,16 +391,19 @@ impl BasicClient {
382391
/// If the implicit client provider is `ProviderID::Core`, a client error
383392
/// of `InvalidProvider` type is returned.
384393
///
394+
/// If the implicit client provider has not been set, a client error of
395+
/// `NoProvider` type is returned.
396+
///
385397
/// See the operation-specific response codes returned by the service
386398
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_export_public_key.html#specific-response-status-codes).
387399
pub fn psa_export_public_key(&self, key_name: String) -> Result<Vec<u8>> {
388-
self.can_provide_crypto()?;
400+
let crypto_provider = self.can_provide_crypto()?;
389401

390402
let op = PsaExportPublicKey { key_name };
391403

392404
let res = self.op_client.process_operation(
393405
NativeOperation::PsaExportPublicKey(op),
394-
self.implicit_provider,
406+
crypto_provider,
395407
&self.auth_data,
396408
)?;
397409

@@ -421,6 +433,9 @@ impl BasicClient {
421433
/// If the implicit client provider is `ProviderID::Core`, a client error
422434
/// of `InvalidProvider` type is returned.
423435
///
436+
/// If the implicit client provider has not been set, a client error of
437+
/// `NoProvider` type is returned.
438+
///
424439
/// See the operation-specific response codes returned by the service
425440
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_sign_hash.html#specific-response-status-codes).
426441
pub fn psa_sign_hash(
@@ -429,7 +444,7 @@ impl BasicClient {
429444
hash: Vec<u8>,
430445
sign_algorithm: AsymmetricSignature,
431446
) -> Result<Vec<u8>> {
432-
self.can_provide_crypto()?;
447+
let crypto_provider = self.can_provide_crypto()?;
433448

434449
let op = PsaSignHash {
435450
key_name,
@@ -439,7 +454,7 @@ impl BasicClient {
439454

440455
let res = self.op_client.process_operation(
441456
NativeOperation::PsaSignHash(op),
442-
self.implicit_provider,
457+
crypto_provider,
443458
&self.auth_data,
444459
)?;
445460

@@ -469,6 +484,9 @@ impl BasicClient {
469484
/// If the implicit client provider is `ProviderID::Core`, a client error
470485
/// of `InvalidProvider` type is returned.
471486
///
487+
/// If the implicit client provider has not been set, a client error of
488+
/// `NoProvider` type is returned.
489+
///
472490
/// See the operation-specific response codes returned by the service
473491
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_verify_hash.html#specific-response-status-codes).
474492
pub fn psa_verify_hash(
@@ -478,7 +496,7 @@ impl BasicClient {
478496
sign_algorithm: AsymmetricSignature,
479497
signature: Vec<u8>,
480498
) -> Result<()> {
481-
self.can_provide_crypto()?;
499+
let crypto_provider = self.can_provide_crypto()?;
482500

483501
let op = PsaVerifyHash {
484502
key_name,
@@ -489,17 +507,18 @@ impl BasicClient {
489507

490508
let _ = self.op_client.process_operation(
491509
NativeOperation::PsaVerifyHash(op),
492-
self.implicit_provider,
510+
crypto_provider,
493511
&self.auth_data,
494512
)?;
495513

496514
Ok(())
497515
}
498516

499-
fn can_provide_crypto(&self) -> Result<()> {
517+
fn can_provide_crypto(&self) -> Result<ProviderID> {
500518
match self.implicit_provider {
501-
ProviderID::Core => Err(Error::Client(ClientErrorKind::InvalidProvider)),
502-
_ => Ok(()),
519+
None => Err(Error::Client(ClientErrorKind::NoProvider)),
520+
Some(ProviderID::Core) => Err(Error::Client(ClientErrorKind::InvalidProvider)),
521+
Some(crypto_provider) => Ok(crypto_provider),
503522
}
504523
}
505524
}

src/core/testing/core_tests.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Copyright 2020 Contributors to the Parsec project.
22
// SPDX-License-Identifier: Apache-2.0
33
use super::{FailingMockIpc, TestBasicClient, DEFAULT_APP_NAME};
4+
use crate::auth::AuthenticationData;
45
use crate::core::ProviderID;
56
use crate::error::{ClientErrorKind, Error};
7+
use crate::BasicClient;
68
use mockstream::{FailingMockStream, MockStream};
79
use parsec_interface::operations;
810
use parsec_interface::operations::list_providers::ProviderInfo;
@@ -95,7 +97,7 @@ fn list_provider_test() {
9597
}
9698

9799
#[test]
98-
fn list_provider_operations_test() {
100+
fn list_opcodes_test() {
99101
let mut client: TestBasicClient = Default::default();
100102
let mut opcodes = HashSet::new();
101103
let _ = opcodes.insert(Opcode::PsaDestroyKey);
@@ -104,7 +106,7 @@ fn list_provider_operations_test() {
104106
operations::list_opcodes::Result { opcodes },
105107
)));
106108
let opcodes = client
107-
.list_provider_operations(ProviderID::MbedCrypto)
109+
.list_opcodes(ProviderID::MbedCrypto)
108110
.expect("Failed to retrieve opcodes");
109111
// Check request:
110112
// ListOpcodes request is empty so no checking to be done
@@ -114,6 +116,29 @@ fn list_provider_operations_test() {
114116
assert!(opcodes.contains(&Opcode::PsaGenerateKey) && opcodes.contains(&Opcode::PsaDestroyKey));
115117
}
116118

119+
#[test]
120+
fn no_crypto_provider_test() {
121+
let client = BasicClient::new(AuthenticationData::AppIdentity(String::from("oops")));
122+
123+
let res = client
124+
.psa_destroy_key(String::from("random key"))
125+
.expect_err("Expected a failure!!");
126+
127+
assert_eq!(res, Error::Client(ClientErrorKind::NoProvider));
128+
}
129+
130+
#[test]
131+
fn core_provider_for_crypto_test() {
132+
let mut client = BasicClient::new(AuthenticationData::AppIdentity(String::from("oops")));
133+
134+
client.set_implicit_provider(ProviderID::Core);
135+
let res = client
136+
.psa_destroy_key(String::from("random key"))
137+
.expect_err("Expected a failure!!");
138+
139+
assert_eq!(res, Error::Client(ClientErrorKind::InvalidProvider));
140+
}
141+
117142
#[test]
118143
fn psa_generate_key_test() {
119144
let mut client: TestBasicClient = Default::default();

src/core/testing/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,14 @@ impl DerefMut for TestBasicClient {
6161
impl Default for TestBasicClient {
6262
fn default() -> Self {
6363
let mut client = TestBasicClient {
64-
core_client: BasicClient::new(
65-
AuthenticationData::AppIdentity(String::from(DEFAULT_APP_NAME)),
66-
ProviderID::Pkcs11,
67-
),
64+
core_client: BasicClient::new(AuthenticationData::AppIdentity(String::from(
65+
DEFAULT_APP_NAME,
66+
))),
6867
mock_stream: SyncMockStream::new(),
6968
};
7069

70+
client.core_client.set_implicit_provider(ProviderID::Pkcs11);
71+
7172
client
7273
.core_client
7374
.set_ipc_handler(Box::from(MockIpc(client.mock_stream.clone())));

0 commit comments

Comments
 (0)