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}