parsec_client/core/basic_client.rs
1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Basic client for Parsec integration
4use super::operation_client::OperationClient;
5use crate::auth::Authentication;
6use crate::error::{ClientErrorKind, Error, Result};
7use log::{debug, warn};
8use parsec_interface::operations::attest_key::{Operation as AttestKey, Result as AttestKeyResult};
9use parsec_interface::operations::can_do_crypto::{CheckType, Operation as CanDoCrypto};
10use parsec_interface::operations::delete_client::Operation as DeleteClient;
11use parsec_interface::operations::list_authenticators::{
12 AuthenticatorInfo, Operation as ListAuthenticators,
13};
14use parsec_interface::operations::list_clients::Operation as ListClients;
15use parsec_interface::operations::list_keys::{KeyInfo, Operation as ListKeys};
16use parsec_interface::operations::list_opcodes::Operation as ListOpcodes;
17use parsec_interface::operations::list_providers::{Operation as ListProviders, ProviderInfo};
18use parsec_interface::operations::ping::Operation as Ping;
19use parsec_interface::operations::prepare_key_attestation::{
20 Operation as PrepareKeyAttestation, Result as PrepareKeyAttestationResult,
21};
22use parsec_interface::operations::psa_aead_decrypt::Operation as PsaAeadDecrypt;
23use parsec_interface::operations::psa_aead_encrypt::Operation as PsaAeadEncrypt;
24use parsec_interface::operations::psa_algorithm::{
25 Aead, AsymmetricEncryption, AsymmetricSignature, Cipher, Hash, RawKeyAgreement,
26};
27use parsec_interface::operations::psa_asymmetric_decrypt::Operation as PsaAsymDecrypt;
28use parsec_interface::operations::psa_asymmetric_encrypt::Operation as PsaAsymEncrypt;
29use parsec_interface::operations::psa_cipher_decrypt::Operation as PsaCipherDecrypt;
30use parsec_interface::operations::psa_cipher_encrypt::Operation as PsaCipherEncrypt;
31use parsec_interface::operations::psa_destroy_key::Operation as PsaDestroyKey;
32use parsec_interface::operations::psa_export_key::Operation as PsaExportKey;
33use parsec_interface::operations::psa_export_public_key::Operation as PsaExportPublicKey;
34use parsec_interface::operations::psa_generate_key::Operation as PsaGenerateKey;
35use parsec_interface::operations::psa_generate_random::Operation as PsaGenerateRandom;
36use parsec_interface::operations::psa_hash_compare::Operation as PsaHashCompare;
37use parsec_interface::operations::psa_hash_compute::Operation as PsaHashCompute;
38use parsec_interface::operations::psa_import_key::Operation as PsaImportKey;
39use parsec_interface::operations::psa_key_attributes::Attributes;
40use parsec_interface::operations::psa_raw_key_agreement::Operation as PsaRawKeyAgreement;
41use parsec_interface::operations::psa_sign_hash::Operation as PsaSignHash;
42use parsec_interface::operations::psa_sign_message::Operation as PsaSignMessage;
43use parsec_interface::operations::psa_verify_hash::Operation as PsaVerifyHash;
44use parsec_interface::operations::psa_verify_message::Operation as PsaVerifyMessage;
45use parsec_interface::operations::{NativeOperation, NativeResult};
46use parsec_interface::requests::AuthType;
47use parsec_interface::requests::{Opcode, ProviderId};
48use parsec_interface::secrecy::{ExposeSecret, Secret};
49use std::collections::HashSet;
50use zeroize::Zeroizing;
51
52/// Core client for the Parsec service
53///
54/// The client exposes low-level functionality for using the Parsec service.
55/// Below you can see code examples for a few of the operations supported.
56///
57/// Providers are abstracted representations of the secure elements that
58/// Parsec offers abstraction over. Providers are the ones to execute the
59/// cryptographic operations requested by the user.
60///
61/// For all cryptographic operations an implicit provider is used which can be
62/// changed between operations. The client starts with the default provider, the first
63/// one returned by the ListProviders operation.
64///
65/// For crypto operations, if the implicit client provider is `ProviderId::Core`, a client error
66/// of `InvalidProvider` type is returned.
67/// See the operation-specific response codes returned by the service in the operation's page
68/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/index.html).
69#[derive(Debug)]
70pub struct BasicClient {
71 pub(crate) op_client: OperationClient,
72 pub(crate) auth_data: Authentication,
73 pub(crate) implicit_provider: ProviderId,
74}
75
76/// Main client functionality.
77impl BasicClient {
78 /// Create a new Parsec client.
79 ///
80 /// The client will be initialised with default values obtained from the service for the
81 /// implicit provider and for application identity.
82 ///
83 /// * `app_name` is the application name to be used if direct authentication is the default
84 /// authentication choice
85 ///
86 /// This client will use the default configuration. That includes using a Protobuf converter
87 /// for message bodies and a Unix Domain Socket IPC handler. The default timeout length is 60
88 /// seconds.
89 ///
90 /// # Example
91 ///
92 ///```no_run
93 ///# use std::error::Error;
94 ///#
95 ///# fn main() -> Result<(), Box<dyn Error>> {
96 ///use parsec_client::BasicClient;
97 ///
98 ///let client: BasicClient = BasicClient::new(None)?;
99 ///# Ok(())}
100 ///```
101 pub fn new(app_name: Option<String>) -> Result<Self> {
102 let mut client = BasicClient {
103 op_client: OperationClient::new()?,
104 auth_data: Authentication::None,
105 implicit_provider: ProviderId::Core,
106 };
107 client.set_default_provider()?;
108 client.set_default_auth(app_name)?;
109 debug!("Parsec BasicClient created with implicit provider \"{}\" and authentication data \"{:?}\"", client.implicit_provider(), client.auth_data());
110 Ok(client)
111 }
112
113 /// Create a client that can initially only be used with Core operations not necessitating
114 /// authentication (eg ping).
115 ///
116 /// Setting an authentication method and an implicit provider is needed before calling crypto
117 /// operations.
118 ///
119 /// # Example
120 ///
121 /// ```no_run
122 ///# use std::error::Error;
123 ///#
124 ///# fn main() -> Result<(), Box<dyn Error>> {
125 ///use parsec_client::BasicClient;
126 ///let client = BasicClient::new_naked()?;
127 ///let (major, minor) = client.ping()?;
128 ///# Ok(())}
129 /// ```
130 pub fn new_naked() -> Result<Self> {
131 Ok(BasicClient {
132 op_client: OperationClient::new()?,
133 auth_data: Authentication::None,
134 implicit_provider: ProviderId::Core,
135 })
136 }
137
138 /// Query the service for the list of authenticators provided and use the first one as default
139 ///
140 /// * `app_name` is to be used if direct authentication is the default choice
141 ///
142 /// # Errors
143 ///
144 /// If no authenticator is reported by the service, a `NoAuthenticator` error kind is returned.
145 ///
146 /// If the default authenticator is `DirectAuthenticator` and `app_name` was set to `None`,
147 /// an error of type `MissingParam` is returned.
148 ///
149 /// If none of the authenticators returned by the service is supported, `NoAuthenticator` is
150 /// returned.
151 ///
152 /// # Example
153 ///
154 /// ```no_run
155 ///# use std::error::Error;
156 ///#
157 ///# fn main() -> Result<(), Box<dyn Error>> {
158 ///use parsec_client::BasicClient;
159 ///use parsec_client::core::interface::requests::ProviderId;
160 ///let mut client = BasicClient::new_naked()?;
161 ///// Set the default authenticator but choose a specific provider.
162 ///client.set_implicit_provider(ProviderId::Pkcs11);
163 ///client.set_default_auth(Some("main_client".to_string()))?;
164 ///# Ok(())}
165 /// ```
166 pub fn set_default_auth(&mut self, app_name: Option<String>) -> Result<()> {
167 let authenticators = self.list_authenticators()?;
168 if authenticators.is_empty() {
169 return Err(Error::Client(ClientErrorKind::NoAuthenticator));
170 }
171 for authenticator in authenticators {
172 match authenticator.id {
173 AuthType::Direct => {
174 self.auth_data = Authentication::Direct(
175 app_name.ok_or(Error::Client(ClientErrorKind::MissingParam))?,
176 )
177 }
178 AuthType::UnixPeerCredentials => {
179 self.auth_data = Authentication::UnixPeerCredentials
180 }
181 #[cfg(feature = "spiffe-auth")]
182 AuthType::JwtSvid => self.auth_data = Authentication::JwtSvid,
183 auth => {
184 warn!(
185 "Authenticator of type \"{:?}\" not supported by this client library",
186 auth
187 );
188 continue;
189 }
190 }
191 return Ok(());
192 }
193
194 Err(Error::Client(ClientErrorKind::NoAuthenticator))
195 }
196
197 /// Update the authentication data of the client.
198 ///
199 /// This is useful if you want to use a different authentication method than
200 /// the default one.
201 ///
202 /// # Example
203 ///
204 /// See [`set_default_provider`].
205 pub fn set_auth_data(&mut self, auth_data: Authentication) {
206 self.auth_data = auth_data;
207 }
208
209 /// Retrieve authentication data of the client.
210 ///
211 /// # Example
212 ///
213 /// ```no_run
214 ///# use std::error::Error;
215 ///#
216 ///# fn main() -> Result<(), Box<dyn Error>> {
217 ///use parsec_client::BasicClient;
218 ///use parsec_client::auth::Authentication;
219 ///let mut client = BasicClient::new_naked()?;
220 ///client.set_auth_data(Authentication::UnixPeerCredentials);
221 ///assert_eq!(Authentication::UnixPeerCredentials, client.auth_data());
222 ///# Ok(())}
223 /// ```
224 pub fn auth_data(&self) -> Authentication {
225 self.auth_data.clone()
226 }
227
228 /// Query for the service provider list and set the default one as implicit
229 ///
230 /// # Errors
231 ///
232 /// If no provider is returned by the service, an client error of `NoProvider`
233 /// type is returned.
234 ///
235 /// # Example
236 ///
237 /// ```no_run
238 ///# use std::error::Error;
239 ///#
240 ///# fn main() -> Result<(), Box<dyn Error>> {
241 ///use parsec_client::BasicClient;
242 ///use parsec_client::auth::Authentication;
243 ///let mut client = BasicClient::new_naked()?;
244 ///// Use the default provider but use a specific authentication.
245 ///client.set_default_provider()?;
246 ///client.set_auth_data(Authentication::UnixPeerCredentials);
247 ///# Ok(())}
248 /// ```
249 pub fn set_default_provider(&mut self) -> Result<()> {
250 let providers = self.list_providers()?;
251 if providers.is_empty() {
252 return Err(Error::Client(ClientErrorKind::NoProvider));
253 }
254 self.implicit_provider = providers[0].id;
255
256 Ok(())
257 }
258
259 /// Set the provider that the client will be implicitly working with.
260 ///
261 /// # Example
262 ///
263 /// See [`set_default_auth`].
264 pub fn set_implicit_provider(&mut self, provider: ProviderId) {
265 self.implicit_provider = provider;
266 }
267
268 /// Retrieve client's implicit provider.
269 ///
270 /// # Example
271 ///
272 /// ```no_run
273 ///# use std::error::Error;
274 ///#
275 ///# fn main() -> Result<(), Box<dyn Error>> {
276 ///use parsec_client::BasicClient;
277 ///use parsec_client::core::interface::requests::ProviderId;
278 ///let mut client = BasicClient::new_naked()?;
279 ///client.set_implicit_provider(ProviderId::Pkcs11);
280 ///assert_eq!(ProviderId::Pkcs11, client.implicit_provider());
281 ///# Ok(())}
282 /// ```
283 pub fn implicit_provider(&self) -> ProviderId {
284 self.implicit_provider
285 }
286
287 /// **[Core Operation]** List the opcodes supported by the specified provider.
288 ///
289 /// # Example
290 ///
291 ///```no_run
292 ///# use std::error::Error;
293 ///#
294 ///# fn main() -> Result<(), Box<dyn Error>> {
295 ///# use std::error::Error;
296 ///#
297 ///# fn main() -> Result<(), Box<dyn Error>> {
298 ///use parsec_client::BasicClient;
299 ///use parsec_client::core::interface::requests::{Opcode, ProviderId};
300 ///
301 ///let client: BasicClient = BasicClient::new(None)?;
302 ///let opcodes = client.list_opcodes(ProviderId::Pkcs11)?;
303 ///if opcodes.contains(&Opcode::PsaGenerateRandom) {
304 /// let random_bytes = client.psa_generate_random(10)?;
305 ///}
306 ///# Ok(())}
307 ///# Ok(())}
308 ///```
309 pub fn list_opcodes(&self, provider: ProviderId) -> Result<HashSet<Opcode>> {
310 let res = self.op_client.process_operation(
311 NativeOperation::ListOpcodes(ListOpcodes {
312 provider_id: provider,
313 }),
314 ProviderId::Core,
315 &self.auth_data,
316 )?;
317
318 if let NativeResult::ListOpcodes(res) = res {
319 Ok(res.opcodes)
320 } else {
321 // Should really not be reached given the checks we do, but it's not impossible if some
322 // changes happen in the interface
323 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
324 }
325 }
326
327 /// **[Core Operation]** List the providers that are supported by the service.
328 ///
329 /// # Example
330 ///
331 ///```no_run
332 ///# use std::error::Error;
333 ///#
334 ///# fn main() -> Result<(), Box<dyn Error>> {
335 ///use parsec_client::BasicClient;
336 ///
337 ///let mut client: BasicClient = BasicClient::new_naked()?;
338 ///let providers = client.list_providers()?;
339 ///// Set the second most prioritary provider
340 ///client.set_implicit_provider(providers[1].id);
341 ///# Ok(())}
342 ///```
343 pub fn list_providers(&self) -> Result<Vec<ProviderInfo>> {
344 let res = self.op_client.process_operation(
345 NativeOperation::ListProviders(ListProviders {}),
346 ProviderId::Core,
347 &self.auth_data,
348 )?;
349 if let NativeResult::ListProviders(res) = res {
350 Ok(res.providers)
351 } else {
352 // Should really not be reached given the checks we do, but it's not impossible if some
353 // changes happen in the interface
354 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
355 }
356 }
357
358 /// **[Core Operation]** List the authenticators that are supported by the service.
359 ///
360 /// # Example
361 ///
362 ///```no_run
363 ///# use std::error::Error;
364 ///#
365 ///# fn main() -> Result<(), Box<dyn Error>> {
366 ///use parsec_client::BasicClient;
367 ///
368 ///let client: BasicClient = BasicClient::new(None)?;
369 ///let opcodes = client.list_authenticators()?;
370 ///# Ok(())}
371 ///```
372 pub fn list_authenticators(&self) -> Result<Vec<AuthenticatorInfo>> {
373 let res = self.op_client.process_operation(
374 NativeOperation::ListAuthenticators(ListAuthenticators {}),
375 ProviderId::Core,
376 &self.auth_data,
377 )?;
378 if let NativeResult::ListAuthenticators(res) = res {
379 Ok(res.authenticators)
380 } else {
381 // Should really not be reached given the checks we do, but it's not impossible if some
382 // changes happen in the interface
383 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
384 }
385 }
386
387 /// **[Core Operation]** List all keys belonging to the application.
388 ///
389 /// # Example
390 ///
391 ///```no_run
392 ///# use std::error::Error;
393 ///#
394 ///# fn main() -> Result<(), Box<dyn Error>> {
395 ///use parsec_client::BasicClient;
396 ///
397 ///let client: BasicClient = BasicClient::new(None)?;
398 ///let keys = client.list_keys()?;
399 ///# Ok(())}
400 ///```
401 pub fn list_keys(&self) -> Result<Vec<KeyInfo>> {
402 let res = self.op_client.process_operation(
403 NativeOperation::ListKeys(ListKeys {}),
404 ProviderId::Core,
405 &self.auth_data,
406 )?;
407 if let NativeResult::ListKeys(res) = res {
408 Ok(res.keys)
409 } else {
410 // Should really not be reached given the checks we do, but it's not impossible if some
411 // changes happen in the interface
412 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
413 }
414 }
415
416 /// Get the key attributes.
417 ///
418 /// This is a convenience method that uses `list_keys` underneath.
419 ///
420 /// # Errors
421 ///
422 /// Returns `NotFound` if a key with this name does not exist.
423 ///
424 /// # Example
425 ///
426 ///```no_run
427 ///# use std::error::Error;
428 ///#
429 ///# fn main() -> Result<(), Box<dyn Error>> {
430 ///use parsec_client::BasicClient;
431 ///
432 ///let client: BasicClient = BasicClient::new(None)?;
433 ///let attributes = client.key_attributes("my_key")?;
434 ///# Ok(())}
435 ///```
436 pub fn key_attributes(&self, key_name: &str) -> Result<Attributes> {
437 Ok(self
438 .list_keys()?
439 .into_iter()
440 .find(|key_info| key_info.name == key_name)
441 .ok_or(crate::error::Error::Client(ClientErrorKind::NotFound))?
442 .attributes)
443 }
444
445 /// **[Core Operation, Admin Operation]** Lists all clients currently having
446 /// data in the service.
447 ///
448 /// # Example
449 ///
450 ///```no_run
451 ///# use std::error::Error;
452 ///#
453 ///# fn main() -> Result<(), Box<dyn Error>> {
454 ///use parsec_client::BasicClient;
455 ///
456 ///let client: BasicClient = BasicClient::new(None)?;
457 ///let clients = client.list_clients()?;
458 ///# Ok(())}
459 ///```
460 pub fn list_clients(&self) -> Result<Vec<String>> {
461 let res = self.op_client.process_operation(
462 NativeOperation::ListClients(ListClients {}),
463 ProviderId::Core,
464 &self.auth_data,
465 )?;
466 if let NativeResult::ListClients(res) = res {
467 Ok(res.clients)
468 } else {
469 // Should really not be reached given the checks we do, but it's not impossible if some
470 // changes happen in the interface
471 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
472 }
473 }
474
475 /// **[Core Operation, Admin Operation]** Delete all data a client has in the service.
476 ///
477 /// # Example
478 ///
479 ///```no_run
480 ///# use std::error::Error;
481 ///#
482 ///# fn main() -> Result<(), Box<dyn Error>> {
483 ///use parsec_client::BasicClient;
484 ///
485 ///let client: BasicClient = BasicClient::new(None)?;
486 ///client.delete_client("main_client")?;
487 ///# Ok(())}
488 ///```
489 pub fn delete_client(&self, client: &str) -> Result<()> {
490 let res = self.op_client.process_operation(
491 NativeOperation::DeleteClient(DeleteClient {
492 client: client.to_string(),
493 }),
494 ProviderId::Core,
495 &self.auth_data,
496 )?;
497 if let NativeResult::DeleteClient(_) = res {
498 Ok(())
499 } else {
500 // Should really not be reached given the checks we do, but it's not impossible if some
501 // changes happen in the interface
502 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
503 }
504 }
505
506 /// **[Core Operation]** Send a ping request to the service.
507 ///
508 /// This operation is intended for testing connectivity to the
509 /// service and for retrieving the maximum wire protocol version
510 /// it supports.
511 ///
512 /// # Example
513 ///
514 /// See [`new_naked`].
515 pub fn ping(&self) -> Result<(u8, u8)> {
516 let res = self.op_client.process_operation(
517 NativeOperation::Ping(Ping {}),
518 ProviderId::Core,
519 &Authentication::None,
520 )?;
521
522 if let NativeResult::Ping(res) = res {
523 Ok((res.wire_protocol_version_maj, res.wire_protocol_version_min))
524 } else {
525 // Should really not be reached given the checks we do, but it's not impossible if some
526 // changes happen in the interface
527 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
528 }
529 }
530
531 /// **[Cryptographic Operation]** Generate a key.
532 ///
533 /// Creates a new key with the given name within the namespace of the
534 /// implicit client provider. Any UTF-8 string is considered a valid key name,
535 /// however names must be unique per provider.
536 ///
537 /// Persistence of keys is implemented at provider level, and currently all
538 /// providers persist all the keys users create.
539 ///
540 /// If this method returns an error, no key will have been generated and
541 /// the name used will still be available for another key.
542 ///
543 /// # Example
544 ///
545 ///```no_run
546 ///# use std::error::Error;
547 ///#
548 ///# fn main() -> Result<(), Box<dyn Error>> {
549 ///use parsec_client::BasicClient;
550 ///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags};
551 ///use parsec_client::core::interface::operations::psa_algorithm::{AsymmetricSignature, Hash};
552 ///
553 ///let client: BasicClient = BasicClient::new(None)?;
554 ///let key_attrs = Attributes {
555 /// lifetime: Lifetime::Persistent,
556 /// key_type: Type::RsaKeyPair,
557 /// bits: 2048,
558 /// policy: Policy {
559 /// usage_flags: UsageFlags::default(),
560 /// permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
561 /// hash_alg: Hash::Sha256.into(),
562 /// }.into(),
563 /// },
564 ///};
565 ///client.psa_generate_key("my_key", key_attrs)?;
566 ///# Ok(())}
567 ///```
568 pub fn psa_generate_key(&self, key_name: &str, key_attributes: Attributes) -> Result<()> {
569 let crypto_provider = self.can_provide_crypto()?;
570
571 let op = PsaGenerateKey {
572 key_name: String::from(key_name),
573 attributes: key_attributes,
574 };
575
576 let _ = self.op_client.process_operation(
577 NativeOperation::PsaGenerateKey(op),
578 crypto_provider,
579 &self.auth_data,
580 )?;
581
582 Ok(())
583 }
584
585 /// **[Cryptographic Operation]** Destroy a key.
586 ///
587 /// Given that keys are namespaced at a provider level, it is
588 /// important to call `psa_destroy_key` on the correct combination of
589 /// implicit client provider and `key_name`.
590 ///
591 /// # Example
592 ///
593 ///```no_run
594 ///# use std::error::Error;
595 ///#
596 ///# fn main() -> Result<(), Box<dyn Error>> {
597 ///use parsec_client::BasicClient;
598 ///
599 ///let client: BasicClient = BasicClient::new(None)?;
600 ///client.psa_destroy_key("my_key")?;
601 ///# Ok(())}
602 ///```
603 pub fn psa_destroy_key(&self, key_name: &str) -> Result<()> {
604 let crypto_provider = self.can_provide_crypto()?;
605
606 let op = PsaDestroyKey {
607 key_name: String::from(key_name),
608 };
609
610 let _ = self.op_client.process_operation(
611 NativeOperation::PsaDestroyKey(op),
612 crypto_provider,
613 &self.auth_data,
614 )?;
615
616 Ok(())
617 }
618
619 /// **[Cryptographic Operation]** Import a key.
620 ///
621 /// Creates a new key with the given name within the namespace of the
622 /// implicit client provider using the user-provided data. Any UTF-8 string is
623 /// considered a valid key name, however names must be unique per provider.
624 ///
625 /// The key material should follow the appropriate binary format expressed
626 /// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_export_public_key.html).
627 /// Several crates (e.g. [`picky-asn1`](https://crates.io/crates/picky-asn1))
628 /// can greatly help in dealing with binary encodings.
629 ///
630 /// If this method returns an error, no key will have been imported and the
631 /// name used will still be available for another key.
632 ///
633 /// # Example
634 ///
635 ///```no_run
636 ///# use std::error::Error;
637 ///#
638 ///# fn main() -> Result<(), Box<dyn Error>> {
639 ///use parsec_client::BasicClient;
640 ///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags, EccFamily};
641 ///use parsec_client::core::interface::operations::psa_algorithm::{AsymmetricSignature, Hash};
642 ///
643 ///let client: BasicClient = BasicClient::new(None)?;
644 ///let ecc_private_key = vec![
645 /// 0x26, 0xc8, 0x82, 0x9e, 0x22, 0xe3, 0x0c, 0xa6, 0x3d, 0x29, 0xf5, 0xf7, 0x27, 0x39, 0x58, 0x47,
646 /// 0x41, 0x81, 0xf6, 0x57, 0x4f, 0xdb, 0xcb, 0x4d, 0xbb, 0xdd, 0x52, 0xff, 0x3a, 0xc0, 0xf6, 0x0d,
647 ///];
648 ///let key_attrs = Attributes {
649 /// lifetime: Lifetime::Persistent,
650 /// key_type: Type::EccKeyPair {
651 /// curve_family: EccFamily::SecpR1,
652 /// },
653 /// bits: 256,
654 /// policy: Policy {
655 /// usage_flags: UsageFlags::default(),
656 /// permitted_algorithms: AsymmetricSignature::RsaPkcs1v15Sign {
657 /// hash_alg: Hash::Sha256.into(),
658 /// }.into(),
659 /// },
660 ///};
661 ///client.psa_import_key("my_key", &ecc_private_key, key_attrs)?;
662 ///# Ok(())}
663 ///```
664 pub fn psa_import_key(
665 &self,
666 key_name: &str,
667 key_material: &[u8],
668 key_attributes: Attributes,
669 ) -> Result<()> {
670 let key_material = Secret::new(key_material.to_vec());
671 let crypto_provider = self.can_provide_crypto()?;
672
673 let op = PsaImportKey {
674 key_name: String::from(key_name),
675 attributes: key_attributes,
676 data: key_material,
677 };
678
679 let _ = self.op_client.process_operation(
680 NativeOperation::PsaImportKey(op),
681 crypto_provider,
682 &self.auth_data,
683 )?;
684
685 Ok(())
686 }
687
688 /// **[Cryptographic Operation]** Export a public key or the public part of a key pair.
689 ///
690 /// The returned key material will follow the appropriate binary format expressed
691 /// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_export_public_key.html).
692 /// Several crates (e.g. [`picky-asn1`](https://crates.io/crates/picky-asn1))
693 /// can greatly help in dealing with binary encodings.
694 ///
695 /// # Example
696 ///
697 ///```no_run
698 ///# use std::error::Error;
699 ///#
700 ///# fn main() -> Result<(), Box<dyn Error>> {
701 ///use parsec_client::BasicClient;
702 ///
703 ///let client: BasicClient = BasicClient::new(None)?;
704 ///let public_key_data = client.psa_export_public_key("my_key");
705 ///# Ok(())}
706 ///```
707 pub fn psa_export_public_key(&self, key_name: &str) -> Result<Vec<u8>> {
708 let crypto_provider = self.can_provide_crypto()?;
709
710 let op = PsaExportPublicKey {
711 key_name: String::from(key_name),
712 };
713
714 let res = self.op_client.process_operation(
715 NativeOperation::PsaExportPublicKey(op),
716 crypto_provider,
717 &self.auth_data,
718 )?;
719
720 if let NativeResult::PsaExportPublicKey(res) = res {
721 Ok(res.data.to_vec())
722 } else {
723 // Should really not be reached given the checks we do, but it's not impossible if some
724 // changes happen in the interface
725 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
726 }
727 }
728
729 /// **[Cryptographic Operation]** Export a key.
730 ///
731 /// The returned key material will follow the appropriate binary format expressed
732 /// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_export_key.html).
733 /// Several crates (e.g. [`picky-asn1`](https://crates.io/crates/picky-asn1))
734 /// can greatly help in dealing with binary encodings.
735 ///
736 /// # Example
737 ///
738 ///```no_run
739 ///# use std::error::Error;
740 ///#
741 ///# fn main() -> Result<(), Box<dyn Error>> {
742 ///use parsec_client::BasicClient;
743 ///
744 ///let client: BasicClient = BasicClient::new(None)?;
745 ///let key_data = client.psa_export_key("my_key");
746 ///# Ok(())}
747 ///```
748 pub fn psa_export_key(&self, key_name: &str) -> Result<Vec<u8>> {
749 let crypto_provider = self.can_provide_crypto()?;
750
751 let op = PsaExportKey {
752 key_name: String::from(key_name),
753 };
754
755 let res = self.op_client.process_operation(
756 NativeOperation::PsaExportKey(op),
757 crypto_provider,
758 &self.auth_data,
759 )?;
760
761 if let NativeResult::PsaExportKey(res) = res {
762 Ok(res.data.expose_secret().to_vec())
763 } else {
764 // Should really not be reached given the checks we do, but it's not impossible if some
765 // changes happen in the interface
766 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
767 }
768 }
769
770 /// **[Cryptographic Operation]** Create an asymmetric signature on a pre-computed message digest.
771 ///
772 /// The key intended for signing **must** have its `sign_hash` flag set
773 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
774 ///
775 /// The signature will be created with the algorithm defined in
776 /// `sign_algorithm`, but only after checking that the key policy
777 /// and type conform with it.
778 ///
779 /// `hash` must be a hash pre-computed over the message of interest
780 /// with the algorithm specified within `sign_algorithm`.
781 ///
782 /// # Example
783 ///
784 ///```no_run
785 ///# use std::error::Error;
786 ///#
787 ///# fn main() -> Result<(), Box<dyn Error>> {
788 ///use parsec_client::BasicClient;
789 ///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags};
790 ///use parsec_client::core::interface::operations::psa_algorithm::{AsymmetricSignature, Hash};
791 ///
792 ///let client: BasicClient = BasicClient::new(None)?;
793 ///// Hash of a message pre-calculated with SHA-256.
794 ///let hash = vec![
795 /// 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
796 /// 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
797 ///];
798 ///let signature = client.psa_sign_hash("my_key", &hash, AsymmetricSignature::RsaPkcs1v15Sign {
799 ///hash_alg: Hash::Sha256.into(),
800 ///})?;
801 ///# Ok(())}
802 ///```
803 pub fn psa_sign_hash(
804 &self,
805 key_name: &str,
806 hash: &[u8],
807 sign_algorithm: AsymmetricSignature,
808 ) -> Result<Vec<u8>> {
809 let hash = Zeroizing::new(hash.to_vec());
810 let crypto_provider = self.can_provide_crypto()?;
811
812 let op = PsaSignHash {
813 key_name: String::from(key_name),
814 alg: sign_algorithm,
815 hash,
816 };
817
818 let res = self.op_client.process_operation(
819 NativeOperation::PsaSignHash(op),
820 crypto_provider,
821 &self.auth_data,
822 )?;
823
824 if let NativeResult::PsaSignHash(res) = res {
825 Ok(res.signature.to_vec())
826 } else {
827 // Should really not be reached given the checks we do, but it's not impossible if some
828 // changes happen in the interface
829 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
830 }
831 }
832
833 /// **[Cryptographic Operation]** Verify an existing asymmetric signature over a pre-computed message digest.
834 ///
835 /// The key intended for signing **must** have its `verify_hash` flag set
836 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
837 ///
838 /// The signature will be verifyied with the algorithm defined in
839 /// `sign_algorithm`, but only after checking that the key policy
840 /// and type conform with it.
841 ///
842 /// `hash` must be a hash pre-computed over the message of interest
843 /// with the algorithm specified within `sign_algorithm`.
844 ///
845 /// # Example
846 ///
847 ///```no_run
848 ///# use std::error::Error;
849 ///#
850 ///# fn main() -> Result<(), Box<dyn Error>> {
851 ///use parsec_client::BasicClient;
852 ///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags};
853 ///use parsec_client::core::interface::operations::psa_algorithm::{AsymmetricSignature, Hash};
854 ///
855 ///let client: BasicClient = BasicClient::new(None)?;
856 ///// Hash of a message pre-calculated with SHA-256.
857 ///let hash = vec![
858 /// 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2,
859 /// 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78,
860 ///];
861 ///let alg = AsymmetricSignature::RsaPkcs1v15Sign {
862 /// hash_alg: Hash::Sha256.into(),
863 ///};
864 ///let signature = client.psa_sign_hash("my_key", &hash, alg)?;
865 ///client.psa_verify_hash("my_key", &hash, alg, &signature)?;
866 ///# Ok(())}
867 ///```
868 pub fn psa_verify_hash(
869 &self,
870 key_name: &str,
871 hash: &[u8],
872 sign_algorithm: AsymmetricSignature,
873 signature: &[u8],
874 ) -> Result<()> {
875 let hash = Zeroizing::new(hash.to_vec());
876 let signature = Zeroizing::new(signature.to_vec());
877 let crypto_provider = self.can_provide_crypto()?;
878
879 let op = PsaVerifyHash {
880 key_name: String::from(key_name),
881 alg: sign_algorithm,
882 hash,
883 signature,
884 };
885
886 let _ = self.op_client.process_operation(
887 NativeOperation::PsaVerifyHash(op),
888 crypto_provider,
889 &self.auth_data,
890 )?;
891
892 Ok(())
893 }
894
895 /// **[Cryptographic Operation]** Create an asymmetric signature on a message.
896 ///
897 /// The key intended for signing **must** have its `sign_message` flag set
898 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
899 ///
900 /// The signature will be created with the algorithm defined in
901 /// `sign_algorithm`, but only after checking that the key policy
902 /// and type conform with it.
903 ///
904 /// # Example
905 ///
906 ///```no_run
907 ///# use std::error::Error;
908 ///#
909 ///# fn main() -> Result<(), Box<dyn Error>> {
910 ///use parsec_client::BasicClient;
911 ///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags};
912 ///use parsec_client::core::interface::operations::psa_algorithm::{AsymmetricSignature, Hash};
913 ///
914 ///let client: BasicClient = BasicClient::new(None)?;
915 ///let message = "This is the message to sign which can be of any size!".as_bytes();
916 ///let signature = client.psa_sign_message(
917 /// "my_key",
918 /// message,
919 /// AsymmetricSignature::RsaPkcs1v15Sign {
920 /// hash_alg: Hash::Sha256.into(),
921 /// }
922 ///)?;
923 ///# Ok(())}
924 ///```
925 pub fn psa_sign_message(
926 &self,
927 key_name: &str,
928 msg: &[u8],
929 sign_algorithm: AsymmetricSignature,
930 ) -> Result<Vec<u8>> {
931 let message = Zeroizing::new(msg.to_vec());
932 let crypto_provider = self.can_provide_crypto()?;
933
934 let op = PsaSignMessage {
935 key_name: String::from(key_name),
936 alg: sign_algorithm,
937 message,
938 };
939
940 let res = self.op_client.process_operation(
941 NativeOperation::PsaSignMessage(op),
942 crypto_provider,
943 &self.auth_data,
944 )?;
945
946 if let NativeResult::PsaSignMessage(res) = res {
947 Ok(res.signature.to_vec())
948 } else {
949 // Should really not be reached given the checks we do, but it's not impossible if some
950 // changes happen in the interface
951 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
952 }
953 }
954
955 /// **[Cryptographic Operation]** Verify an existing asymmetric signature over a message.
956 ///
957 /// The key intended for signing **must** have its `verify_message` flag set
958 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
959 ///
960 /// The signature will be verifyied with the algorithm defined in
961 /// `sign_algorithm`, but only after checking that the key policy
962 /// and type conform with it.
963 ///
964 /// # Example
965 ///
966 ///```no_run
967 ///# use std::error::Error;
968 ///#
969 ///# fn main() -> Result<(), Box<dyn Error>> {
970 ///use parsec_client::BasicClient;
971 ///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags};
972 ///use parsec_client::core::interface::operations::psa_algorithm::{AsymmetricSignature, Hash};
973 ///
974 ///let client: BasicClient = BasicClient::new(None)?;
975 ///let message = "This is the message to sign which can be of any size!".as_bytes();
976 ///let alg = AsymmetricSignature::RsaPkcs1v15Sign {
977 /// hash_alg: Hash::Sha256.into(),
978 ///};
979 ///let signature = client.psa_sign_message("my_key", message, alg)?;
980 ///client.psa_verify_message("my_key", message, alg, &signature)?;
981 ///# Ok(())}
982 ///```
983 pub fn psa_verify_message(
984 &self,
985 key_name: &str,
986 msg: &[u8],
987 sign_algorithm: AsymmetricSignature,
988 signature: &[u8],
989 ) -> Result<()> {
990 let message = Zeroizing::new(msg.to_vec());
991 let signature = Zeroizing::new(signature.to_vec());
992 let crypto_provider = self.can_provide_crypto()?;
993
994 let op = PsaVerifyMessage {
995 key_name: String::from(key_name),
996 alg: sign_algorithm,
997 message,
998 signature,
999 };
1000
1001 let _ = self.op_client.process_operation(
1002 NativeOperation::PsaVerifyMessage(op),
1003 crypto_provider,
1004 &self.auth_data,
1005 )?;
1006
1007 Ok(())
1008 }
1009
1010 /// **[Cryptographic Operation]** Encrypt a short message.
1011 ///
1012 /// The key intended for encrypting **must** have its `encrypt` flag set
1013 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
1014 ///
1015 /// The encryption will be performed with the algorithm defined in `alg`,
1016 /// but only after checking that the key policy and type conform with it.
1017 ///
1018 /// `salt` can be provided if supported by the algorithm. If the algorithm does not support salt, pass
1019 /// an empty vector. If the algorithm supports optional salt, pass an empty vector to indicate no
1020 /// salt. For RSA PKCS#1 v1.5 encryption, no salt is supported.
1021 pub fn psa_asymmetric_encrypt(
1022 &self,
1023 key_name: &str,
1024 encrypt_alg: AsymmetricEncryption,
1025 plaintext: &[u8],
1026 salt: Option<&[u8]>,
1027 ) -> Result<Vec<u8>> {
1028 let salt = salt.map(|salt_ref| salt_ref.to_vec().into());
1029 let crypto_provider = self.can_provide_crypto()?;
1030
1031 let op = PsaAsymEncrypt {
1032 key_name: String::from(key_name),
1033 alg: encrypt_alg,
1034 plaintext: plaintext.to_vec().into(),
1035 salt,
1036 };
1037
1038 let encrypt_res = self.op_client.process_operation(
1039 NativeOperation::PsaAsymmetricEncrypt(op),
1040 crypto_provider,
1041 &self.auth_data,
1042 )?;
1043
1044 if let NativeResult::PsaAsymmetricEncrypt(res) = encrypt_res {
1045 Ok(res.ciphertext.to_vec())
1046 } else {
1047 // Should really not be reached given the checks we do, but it's not impossible if some
1048 // changes happen in the interface
1049 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1050 }
1051 }
1052
1053 /// **[Cryptographic Operation]** Decrypt a short message.
1054 ///
1055 /// The key intended for decrypting **must** have its `decrypt` flag set
1056 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
1057 ///
1058 /// `salt` can be provided if supported by the algorithm. If the algorithm does not support salt, pass
1059 /// an empty vector. If the algorithm supports optional salt, pass an empty vector to indicate no
1060 /// salt. For RSA PKCS#1 v1.5 encryption, no salt is supported.
1061 ///
1062 ///
1063 /// The decryption will be performed with the algorithm defined in `alg`,
1064 /// but only after checking that the key policy and type conform with it.
1065 pub fn psa_asymmetric_decrypt(
1066 &self,
1067 key_name: &str,
1068 encrypt_alg: AsymmetricEncryption,
1069 ciphertext: &[u8],
1070 salt: Option<&[u8]>,
1071 ) -> Result<Vec<u8>> {
1072 let salt = salt.map(|salt| Zeroizing::new(salt.to_vec()));
1073 let crypto_provider = self.can_provide_crypto()?;
1074
1075 let op = PsaAsymDecrypt {
1076 key_name: String::from(key_name),
1077 alg: encrypt_alg,
1078 ciphertext: Zeroizing::new(ciphertext.to_vec()),
1079 salt,
1080 };
1081
1082 let decrypt_res = self.op_client.process_operation(
1083 NativeOperation::PsaAsymmetricDecrypt(op),
1084 crypto_provider,
1085 &self.auth_data,
1086 )?;
1087
1088 if let NativeResult::PsaAsymmetricDecrypt(res) = decrypt_res {
1089 Ok(res.plaintext.to_vec())
1090 } else {
1091 // Should really not be reached given the checks we do, but it's not impossible if some
1092 // changes happen in the interface
1093 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1094 }
1095 }
1096 /// **[Cryptographic Operation]** Compute hash of a message.
1097 ///
1098 /// The hash computation will be performed with the algorithm defined in `alg`.
1099 pub fn psa_hash_compute(&self, alg: Hash, input: &[u8]) -> Result<Vec<u8>> {
1100 let crypto_provider = self.can_provide_crypto()?;
1101 let op = PsaHashCompute {
1102 alg,
1103 input: input.to_vec().into(),
1104 };
1105 let hash_compute_res = self.op_client.process_operation(
1106 NativeOperation::PsaHashCompute(op),
1107 crypto_provider,
1108 &self.auth_data,
1109 )?;
1110 if let NativeResult::PsaHashCompute(res) = hash_compute_res {
1111 Ok(res.hash.to_vec())
1112 } else {
1113 // Should really not be reached given the checks we do, but it's not impossible if some
1114 // changes happen in the interface
1115 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1116 }
1117 }
1118
1119 /// **[Cryptographic Operation]** Compute hash of a message and compare it with a reference value.
1120 ///
1121 /// The hash computation will be performed with the algorithm defined in `alg`.
1122 ///
1123 /// If this operation returns no error, the hash was computed successfully and it matches the reference value.
1124 pub fn psa_hash_compare(&self, alg: Hash, input: &[u8], hash: &[u8]) -> Result<()> {
1125 let crypto_provider = self.can_provide_crypto()?;
1126 let op = PsaHashCompare {
1127 alg,
1128 input: input.to_vec().into(),
1129 hash: hash.to_vec().into(),
1130 };
1131 let _ = self.op_client.process_operation(
1132 NativeOperation::PsaHashCompare(op),
1133 crypto_provider,
1134 &self.auth_data,
1135 )?;
1136 Ok(())
1137 }
1138
1139 /// **[Cryptographic Operation]** Authenticate and encrypt a short message.
1140 ///
1141 /// The key intended for decrypting **must** have its `encrypt` flag set
1142 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
1143 ///
1144 /// The encryption will be performed with the algorithm defined in `alg`,
1145 /// but only after checking that the key policy and type conform with it.
1146 ///
1147 /// `nonce` must be appropriate for the selected `alg`.
1148 ///
1149 /// For algorithms where the encrypted data and the authentication tag are defined as separate outputs,
1150 /// the returned buffer will contain the encrypted data followed by the authentication data.
1151 pub fn psa_aead_encrypt(
1152 &self,
1153 key_name: &str,
1154 encrypt_alg: Aead,
1155 nonce: &[u8],
1156 additional_data: &[u8],
1157 plaintext: &[u8],
1158 ) -> Result<Vec<u8>> {
1159 let crypto_provider = self.can_provide_crypto()?;
1160
1161 let op = PsaAeadEncrypt {
1162 key_name: String::from(key_name),
1163 alg: encrypt_alg,
1164 nonce: nonce.to_vec().into(),
1165 additional_data: additional_data.to_vec().into(),
1166 plaintext: plaintext.to_vec().into(),
1167 };
1168
1169 let encrypt_res = self.op_client.process_operation(
1170 NativeOperation::PsaAeadEncrypt(op),
1171 crypto_provider,
1172 &self.auth_data,
1173 )?;
1174
1175 if let NativeResult::PsaAeadEncrypt(res) = encrypt_res {
1176 Ok(res.ciphertext.to_vec())
1177 } else {
1178 // Should really not be reached given the checks we do, but it's not impossible if some
1179 // changes happen in the interface
1180 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1181 }
1182 }
1183
1184 /// **[Cryptographic Operation]** Decrypt and authenticate a short message.
1185 ///
1186 /// The key intended for decrypting **must** have its `decrypt` flag set
1187 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
1188 ///
1189 /// The decryption will be performed with the algorithm defined in `alg`,
1190 /// but only after checking that the key policy and type conform with it.
1191 ///
1192 /// `nonce` must be appropriate for the selected `alg`.
1193 ///
1194 /// For algorithms where the encrypted data and the authentication tag are defined as separate inputs,
1195 /// `ciphertext` must contain the encrypted data followed by the authentication data.
1196 pub fn psa_aead_decrypt(
1197 &self,
1198 key_name: &str,
1199 encrypt_alg: Aead,
1200 nonce: &[u8],
1201 additional_data: &[u8],
1202 ciphertext: &[u8],
1203 ) -> Result<Vec<u8>> {
1204 let crypto_provider = self.can_provide_crypto()?;
1205
1206 let op = PsaAeadDecrypt {
1207 key_name: String::from(key_name),
1208 alg: encrypt_alg,
1209 nonce: nonce.to_vec().into(),
1210 additional_data: additional_data.to_vec().into(),
1211 ciphertext: ciphertext.to_vec().into(),
1212 };
1213
1214 let decrypt_res = self.op_client.process_operation(
1215 NativeOperation::PsaAeadDecrypt(op),
1216 crypto_provider,
1217 &self.auth_data,
1218 )?;
1219
1220 if let NativeResult::PsaAeadDecrypt(res) = decrypt_res {
1221 Ok(res.plaintext.to_vec())
1222 } else {
1223 // Should really not be reached given the checks we do, but it's not impossible if some
1224 // changes happen in the interface
1225 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1226 }
1227 }
1228
1229 /// **[Cryptographic Operation]** Encrypt a short message with a symmetric cipher.
1230 ///
1231 /// The key intended for encrypting **must** have its `encrypt` flag set
1232 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
1233 ///
1234 /// This function will encrypt a short message with a random initialisation vector (IV).
1235 pub fn psa_cipher_encrypt(
1236 &self,
1237 key_name: String,
1238 alg: Cipher,
1239 plaintext: &[u8],
1240 ) -> Result<Vec<u8>> {
1241 let crypto_provider = self.can_provide_crypto()?;
1242
1243 let op = PsaCipherEncrypt {
1244 key_name,
1245 alg,
1246 plaintext: plaintext.to_vec().into(),
1247 };
1248
1249 let res = self.op_client.process_operation(
1250 NativeOperation::PsaCipherEncrypt(op),
1251 crypto_provider,
1252 &self.auth_data,
1253 )?;
1254
1255 if let NativeResult::PsaCipherEncrypt(res) = res {
1256 Ok(res.ciphertext.to_vec())
1257 } else {
1258 // Should really not be reached given the checks we do, but it's not impossible if some
1259 // changes happen in the interface
1260 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1261 }
1262 }
1263
1264 /// **[Cryptographic Operation]** Decrypt a short message with a symmetric cipher.
1265 ///
1266 /// The key intended for decrypting **must** have its `decrypt` flag set
1267 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
1268 ///
1269 /// `ciphertext` must be the IV followed by the ciphertext.
1270 ///
1271 /// This function will decrypt a short message using the provided initialisation vector (IV).
1272 pub fn psa_cipher_decrypt(
1273 &self,
1274 key_name: String,
1275 alg: Cipher,
1276 ciphertext: &[u8],
1277 ) -> Result<Vec<u8>> {
1278 let crypto_provider = self.can_provide_crypto()?;
1279
1280 let op = PsaCipherDecrypt {
1281 key_name,
1282 alg,
1283 ciphertext: ciphertext.to_vec().into(),
1284 };
1285
1286 let res = self.op_client.process_operation(
1287 NativeOperation::PsaCipherDecrypt(op),
1288 crypto_provider,
1289 &self.auth_data,
1290 )?;
1291
1292 if let NativeResult::PsaCipherDecrypt(res) = res {
1293 Ok(res.plaintext.to_vec())
1294 } else {
1295 // Should really not be reached given the checks we do, but it's not impossible if some
1296 // changes happen in the interface
1297 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1298 }
1299 }
1300
1301 /// **[Cryptographic Operation]** Perform a raw key agreement.
1302 ///
1303 /// The provided private key **must** have its `derive` flag set
1304 /// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
1305 ///
1306 /// The raw_key_agreement will be performed with the algorithm defined in `alg`,
1307 /// but only after checking that the key policy and type conform with it.
1308 ///
1309 /// `peer_key` must be the peer public key to use in the raw key derivation. It must
1310 /// be in a format supported by [`PsaImportKey`](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_import_key.html).
1311 pub fn psa_raw_key_agreement(
1312 &self,
1313 alg: RawKeyAgreement,
1314 private_key_name: &str,
1315 peer_key: &[u8],
1316 ) -> Result<Vec<u8>> {
1317 let op = PsaRawKeyAgreement {
1318 alg,
1319 private_key_name: String::from(private_key_name),
1320 peer_key: Zeroizing::new(peer_key.to_vec()),
1321 };
1322 let crypto_provider = self.can_provide_crypto()?;
1323 let raw_key_agreement_res = self.op_client.process_operation(
1324 NativeOperation::PsaRawKeyAgreement(op),
1325 crypto_provider,
1326 &self.auth_data,
1327 )?;
1328 if let NativeResult::PsaRawKeyAgreement(res) = raw_key_agreement_res {
1329 Ok(res.shared_secret.expose_secret().to_vec())
1330 } else {
1331 // Should really not be reached given the checks we do, but it's not impossible if some
1332 // changes happen in the interface
1333 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1334 }
1335 }
1336
1337 /// **[Cryptographic Operation]** Generate some random bytes.
1338 ///
1339 /// Generates a sequence of random bytes and returns them to the user.
1340 ///
1341 /// If this method returns an error, no bytes will have been generated.
1342 ///
1343 /// # Example
1344 ///
1345 /// See [`list_opcodes`].
1346 pub fn psa_generate_random(&self, nbytes: usize) -> Result<Vec<u8>> {
1347 let crypto_provider = self.can_provide_crypto()?;
1348
1349 let op = PsaGenerateRandom { size: nbytes };
1350
1351 let res = self.op_client.process_operation(
1352 NativeOperation::PsaGenerateRandom(op),
1353 crypto_provider,
1354 &self.auth_data,
1355 )?;
1356
1357 if let NativeResult::PsaGenerateRandom(res) = res {
1358 Ok(res.random_bytes.to_vec())
1359 } else {
1360 // Should really not be reached given the checks we do, but it's not impossible if some
1361 // changes happen in the interface
1362 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1363 }
1364 }
1365
1366 /// **[Capability Discovery Operation]** Check if attributes are supported.
1367 ///
1368 /// Checks if the given attributes are supported for the given type of operation.
1369 ///
1370 /// #Errors
1371 ///
1372 /// This operation will either return Ok(()) or Err(PsaErrorNotSupported) indicating whether the attributes are supported.
1373 ///
1374 /// See the operation-specific response codes returned by the service
1375 /// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/can_do_crypto.html#specific-response-status-codes).
1376 pub fn can_do_crypto(&self, check_type: CheckType, attributes: Attributes) -> Result<()> {
1377 let crypto_provider = self.can_provide_crypto()?;
1378 let op = CanDoCrypto {
1379 check_type,
1380 attributes,
1381 };
1382 let _ = self.op_client.process_operation(
1383 NativeOperation::CanDoCrypto(op),
1384 crypto_provider,
1385 &self.auth_data,
1386 )?;
1387 Ok(())
1388 }
1389
1390 /// **[Cryptographic Operation]** Get data required to prepare an
1391 /// ActivateCredential key attestation.
1392 ///
1393 /// Retrieve the binary blobs required by a third party to perform a
1394 /// MakeCredential operation, in preparation for a key attestation using
1395 /// ActivateCredential.
1396 ///
1397 /// **This key attestation method is TPM-specific**
1398 pub fn prepare_activate_credential(
1399 &self,
1400 attested_key_name: String,
1401 attesting_key_name: Option<String>,
1402 ) -> Result<PrepareActivateCredential> {
1403 self.can_use_provider(ProviderId::Tpm)?;
1404
1405 let op = PrepareKeyAttestation::ActivateCredential {
1406 attested_key_name,
1407 attesting_key_name,
1408 };
1409
1410 let res = self.op_client.process_operation(
1411 NativeOperation::PrepareKeyAttestation(op),
1412 ProviderId::Tpm,
1413 &self.auth_data,
1414 )?;
1415
1416 if let NativeResult::PrepareKeyAttestation(
1417 PrepareKeyAttestationResult::ActivateCredential {
1418 name,
1419 public,
1420 attesting_key_pub,
1421 },
1422 ) = res
1423 {
1424 Ok(PrepareActivateCredential {
1425 name: name.to_vec(),
1426 public: public.to_vec(),
1427 attesting_key_pub: attesting_key_pub.to_vec(),
1428 })
1429 } else {
1430 // Should really not be reached given the checks we do, but it's not impossible if some
1431 // changes happen in the interface
1432 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1433 }
1434 }
1435
1436 /// **[Cryptographic Operation]** Perform a key attestation operation via
1437 /// ActivateCredential
1438 ///
1439 /// **This key attestation method is TPM-specific**
1440 ///
1441 /// You can see more details on the inner-workings, and on the requirements
1442 /// for this operation [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/attest_key.html).
1443 ///
1444 /// Before performing an ActivateCredential attestation you must compute
1445 /// the `credential_blob` and `secret` parameters using the outputs from
1446 /// the `prepare_activate_credential` method.
1447 pub fn activate_credential_attestation(
1448 &self,
1449 attested_key_name: String,
1450 attesting_key_name: Option<String>,
1451 credential_blob: Vec<u8>,
1452 secret: Vec<u8>,
1453 ) -> Result<Vec<u8>> {
1454 self.can_use_provider(ProviderId::Tpm)?;
1455
1456 let op = AttestKey::ActivateCredential {
1457 attested_key_name,
1458 attesting_key_name,
1459 credential_blob: credential_blob.into(),
1460 secret: secret.into(),
1461 };
1462
1463 let res = self.op_client.process_operation(
1464 NativeOperation::AttestKey(op),
1465 ProviderId::Tpm,
1466 &self.auth_data,
1467 )?;
1468
1469 if let NativeResult::AttestKey(AttestKeyResult::ActivateCredential { credential }) = res {
1470 Ok(credential.to_vec())
1471 } else {
1472 // Should really not be reached given the checks we do, but it's not impossible if some
1473 // changes happen in the interface
1474 Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
1475 }
1476 }
1477
1478 fn can_provide_crypto(&self) -> Result<ProviderId> {
1479 match self.implicit_provider {
1480 ProviderId::Core => Err(Error::Client(ClientErrorKind::InvalidProvider)),
1481 crypto_provider => Ok(crypto_provider),
1482 }
1483 }
1484
1485 fn can_use_provider(&self, provider: ProviderId) -> Result<()> {
1486 let providers = self.list_providers()?;
1487 if providers.iter().any(|prov| prov.id == provider) {
1488 Ok(())
1489 } else {
1490 Err(Error::Client(ClientErrorKind::NoProvider))
1491 }
1492 }
1493}
1494
1495impl Default for BasicClient {
1496 fn default() -> Self {
1497 BasicClient {
1498 op_client: Default::default(),
1499 auth_data: Authentication::None,
1500 implicit_provider: ProviderId::Core,
1501 }
1502 }
1503}
1504
1505/// Wrapper for the data needed to prepare for an
1506/// ActivateCredential attestation.
1507#[derive(Debug)]
1508pub struct PrepareActivateCredential {
1509 /// TPM name of key to be attested
1510 pub name: Vec<u8>,
1511 /// Bytes representing the serialized version of the key public parameters
1512 pub public: Vec<u8>,
1513 /// The public part of the attesting key
1514 pub attesting_key_pub: Vec<u8>,
1515}