Skip to main content

tss_esapi/structures/tagged/
schemes.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4    Error, Result, WrapperErrorKind,
5    interface_types::algorithm::{
6        EccSchemeAlgorithm, HashingAlgorithm, KeyDerivationFunction, KeyedHashSchemeAlgorithm,
7        RsaDecryptAlgorithm, RsaSchemeAlgorithm, SignatureSchemeAlgorithm,
8    },
9    structures::schemes::{EcDaaScheme, HashScheme, HmacScheme, XorScheme},
10    tss2_esys::{
11        TPMT_ECC_SCHEME, TPMT_KDF_SCHEME, TPMT_KEYEDHASH_SCHEME, TPMT_RSA_DECRYPT, TPMT_RSA_SCHEME,
12        TPMT_SIG_SCHEME, TPMU_ASYM_SCHEME, TPMU_KDF_SCHEME, TPMU_SCHEME_KEYEDHASH, TPMU_SIG_SCHEME,
13    },
14};
15use log::error;
16use std::convert::{TryFrom, TryInto};
17
18/// Enum representing the keyed hash scheme.
19///
20/// # Details
21/// This corresponds to TPMT_SCHEME_KEYEDHASH.
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum KeyedHashScheme {
24    Xor { xor_scheme: XorScheme },
25    Hmac { hmac_scheme: HmacScheme },
26    Null,
27}
28
29impl KeyedHashScheme {
30    pub const HMAC_SHA_256: KeyedHashScheme = KeyedHashScheme::Hmac {
31        hmac_scheme: HmacScheme::new(HashingAlgorithm::Sha256),
32    };
33}
34
35impl From<KeyedHashScheme> for TPMT_KEYEDHASH_SCHEME {
36    fn from(keyed_hash_scheme: KeyedHashScheme) -> Self {
37        match keyed_hash_scheme {
38            KeyedHashScheme::Xor { xor_scheme } => TPMT_KEYEDHASH_SCHEME {
39                scheme: KeyedHashSchemeAlgorithm::Xor.into(),
40                details: TPMU_SCHEME_KEYEDHASH {
41                    exclusiveOr: xor_scheme.into(),
42                },
43            },
44            KeyedHashScheme::Hmac { hmac_scheme } => TPMT_KEYEDHASH_SCHEME {
45                scheme: KeyedHashSchemeAlgorithm::Hmac.into(),
46                details: TPMU_SCHEME_KEYEDHASH {
47                    hmac: hmac_scheme.into(),
48                },
49            },
50            KeyedHashScheme::Null => TPMT_KEYEDHASH_SCHEME {
51                scheme: KeyedHashSchemeAlgorithm::Null.into(),
52                details: Default::default(),
53            },
54        }
55    }
56}
57
58impl TryFrom<TPMT_KEYEDHASH_SCHEME> for KeyedHashScheme {
59    type Error = Error;
60    fn try_from(tpmt_keyedhash_scheme: TPMT_KEYEDHASH_SCHEME) -> Result<KeyedHashScheme> {
61        match KeyedHashSchemeAlgorithm::try_from(tpmt_keyedhash_scheme.scheme)? {
62            KeyedHashSchemeAlgorithm::Xor => Ok(KeyedHashScheme::Xor {
63                xor_scheme: unsafe { tpmt_keyedhash_scheme.details.exclusiveOr }.try_into()?,
64            }),
65            KeyedHashSchemeAlgorithm::Hmac => Ok(KeyedHashScheme::Hmac {
66                hmac_scheme: unsafe { tpmt_keyedhash_scheme.details.hmac }.try_into()?,
67            }),
68            KeyedHashSchemeAlgorithm::Null => Ok(KeyedHashScheme::Null),
69        }
70    }
71}
72
73/// Enum representing the rsa scheme
74///
75/// # Details
76/// This corresponds to TPMT_RSA_SCHEME.
77/// This uses a subset of the TPMU_ASYM_SCHEME
78/// that has the TPMI_ALG_RSA_SCHEME as selector.
79#[derive(Clone, Copy, Debug, PartialEq, Eq)]
80pub enum RsaScheme {
81    RsaSsa(HashScheme),
82    RsaEs,
83    RsaPss(HashScheme),
84    Oaep(HashScheme),
85    Null,
86}
87
88impl RsaScheme {
89    /// Creates a new RsaScheme
90    ///
91    /// # Arguments
92    /// `rsa_scheme_algorithm` - The [RsaSchemeAlgorithm] associated with variant.
93    /// `hashing_algorithm`    - A hashing algorithm that is required by some of the
94    ///                          variants.
95    ///
96    /// # Errors
97    /// `ParamMissing`       - If optional parameter is not provided when it is required.
98    ///                        I.e. when creating RSA scheme of type RSA SSA, RSA PSS and
99    ///                        OAEP.
100    ///
101    /// `InconsistentParams` - If the optional parameter has been provided when it is
102    ///                        not required. I.e. if a hashing algorithm is provided
103    ///                        when creating a the RSA scheme of type Null.
104    pub fn create(
105        rsa_scheme_algorithm: RsaSchemeAlgorithm,
106        hashing_algorithm: Option<HashingAlgorithm>,
107    ) -> Result<RsaScheme> {
108        match rsa_scheme_algorithm {
109            RsaSchemeAlgorithm::RsaSsa => Ok(RsaScheme::RsaSsa(HashScheme::new(
110                hashing_algorithm.ok_or_else(|| {
111                    error!(
112                        "Hashing algorithm is required when creating RSA scheme of type RSA SSA"
113                    );
114                    Error::local_error(WrapperErrorKind::ParamsMissing)
115                })?,
116            ))),
117            RsaSchemeAlgorithm::RsaEs => {
118                if hashing_algorithm.is_some() {
119                    error!(
120                        "A hashing algorithm shall not be provided when creating RSA scheme of type RSA ES"
121                    );
122                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
123                }
124                Ok(RsaScheme::RsaEs)
125            }
126            RsaSchemeAlgorithm::RsaPss => Ok(RsaScheme::RsaPss(HashScheme::new(
127                hashing_algorithm.ok_or_else(|| {
128                    error!(
129                        "Hashing algorithm is required when creating RSA scheme of type RSA PSS"
130                    );
131                    Error::local_error(WrapperErrorKind::ParamsMissing)
132                })?,
133            ))),
134            RsaSchemeAlgorithm::Oaep => Ok(RsaScheme::Oaep(HashScheme::new(
135                hashing_algorithm.ok_or_else(|| {
136                    error!("Hashing algorithm is required when creating RSA scheme of type OAEP");
137                    Error::local_error(WrapperErrorKind::ParamsMissing)
138                })?,
139            ))),
140            RsaSchemeAlgorithm::Null => {
141                if hashing_algorithm.is_some() {
142                    error!(
143                        "A hashing algorithm shall not be provided when creating RSA scheme of type Null"
144                    );
145                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
146                }
147                Ok(RsaScheme::Null)
148            }
149        }
150    }
151
152    /// Returns the rsa scheme algorithm
153    pub fn algorithm(&self) -> RsaSchemeAlgorithm {
154        match self {
155            RsaScheme::RsaSsa(_) => RsaSchemeAlgorithm::RsaSsa,
156            RsaScheme::RsaEs => RsaSchemeAlgorithm::RsaEs,
157            RsaScheme::RsaPss(_) => RsaSchemeAlgorithm::RsaPss,
158            RsaScheme::Oaep(_) => RsaSchemeAlgorithm::Oaep,
159            RsaScheme::Null => RsaSchemeAlgorithm::Null,
160        }
161    }
162}
163
164impl From<RsaScheme> for TPMT_RSA_SCHEME {
165    fn from(rsa_scheme: RsaScheme) -> Self {
166        match rsa_scheme {
167            RsaScheme::RsaSsa(hash_scheme) => TPMT_RSA_SCHEME {
168                scheme: rsa_scheme.algorithm().into(),
169                details: TPMU_ASYM_SCHEME {
170                    rsassa: hash_scheme.into(),
171                },
172            },
173            RsaScheme::RsaEs => TPMT_RSA_SCHEME {
174                scheme: rsa_scheme.algorithm().into(),
175                details: TPMU_ASYM_SCHEME {
176                    rsaes: Default::default(),
177                },
178            },
179            RsaScheme::RsaPss(hash_scheme) => TPMT_RSA_SCHEME {
180                scheme: rsa_scheme.algorithm().into(),
181                details: TPMU_ASYM_SCHEME {
182                    rsapss: hash_scheme.into(),
183                },
184            },
185            RsaScheme::Oaep(hash_scheme) => TPMT_RSA_SCHEME {
186                scheme: rsa_scheme.algorithm().into(),
187                details: TPMU_ASYM_SCHEME {
188                    oaep: hash_scheme.into(),
189                },
190            },
191            RsaScheme::Null => TPMT_RSA_SCHEME {
192                scheme: rsa_scheme.algorithm().into(),
193                details: Default::default(),
194            },
195        }
196    }
197}
198
199impl TryFrom<TPMT_RSA_SCHEME> for RsaScheme {
200    type Error = Error;
201
202    fn try_from(tpmt_rsa_scheme: TPMT_RSA_SCHEME) -> Result<Self> {
203        match RsaSchemeAlgorithm::try_from(tpmt_rsa_scheme.scheme)? {
204            RsaSchemeAlgorithm::RsaSsa => Ok(RsaScheme::RsaSsa(
205                unsafe { tpmt_rsa_scheme.details.rsassa }.try_into()?,
206            )),
207            RsaSchemeAlgorithm::RsaEs => Ok(RsaScheme::RsaEs),
208            RsaSchemeAlgorithm::RsaPss => Ok(RsaScheme::RsaPss(
209                unsafe { tpmt_rsa_scheme.details.rsapss }.try_into()?,
210            )),
211            RsaSchemeAlgorithm::Oaep => Ok(RsaScheme::Oaep(
212                unsafe { tpmt_rsa_scheme.details.oaep }.try_into()?,
213            )),
214            RsaSchemeAlgorithm::Null => Ok(RsaScheme::Null),
215        }
216    }
217}
218
219/// Enum representing the ecc scheme
220///
221/// # Details
222/// This corresponds to TPMT_ECC_SCHEME.
223/// This uses a subset of the TPMU_ASYM_SCHEME
224/// that has the TPMI_ALG_ECC_SCHEME as selector.
225#[derive(Clone, Copy, Debug, PartialEq, Eq)]
226pub enum EccScheme {
227    EcDsa(HashScheme),
228    EcDh(HashScheme),
229    EcDaa(EcDaaScheme),
230    Sm2(HashScheme),
231    EcSchnorr(HashScheme),
232    EcMqv(HashScheme),
233    Null,
234}
235
236impl EccScheme {
237    /// Creates a EccScheme.
238    ///
239    /// # Arguments
240    /// `ecc_scheme_algorithm` - The ECC scheme algorithm.
241    /// `hashing_algorithm` - The hashing algorithm associated with some variants.
242    /// `count` - The counter value that is used between TPM2_Commit() and the sign
243    ///           operation used in the EcDaa variant.
244    ///
245    /// # Errors
246    /// `ParamMissing`       - If the algorithm indicates a variant that requires
247    ///                        one or more of the optional parameters and they have
248    ///                        not been provided.
249    ///
250    /// `InconsistentParams` - If an optional parameter has been set but it is
251    ///                        not required.
252    pub fn create(
253        ecc_scheme_algorithm: EccSchemeAlgorithm,
254        hashing_algorithm: Option<HashingAlgorithm>,
255        count: Option<u16>,
256    ) -> Result<Self> {
257        match ecc_scheme_algorithm {
258            EccSchemeAlgorithm::EcDsa => {
259                if count.is_some() {
260                    error!(
261                        "`count` should not be provided when creating ECC scheme of type EC DSA."
262                    );
263                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
264                }
265
266                hashing_algorithm
267                    .ok_or_else(|| {
268                        error!(
269                            "Hashing algorithm is required when creating ECC scheme of type EC DSA."
270                        );
271                        Error::local_error(WrapperErrorKind::ParamsMissing)
272                    })
273                    .map(|v| EccScheme::EcDsa(HashScheme::new(v)))
274            }
275            EccSchemeAlgorithm::EcDh => {
276                if count.is_some() {
277                    error!(
278                        "`count` should not be provided when creating ECC scheme of type EC DH."
279                    );
280                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
281                }
282
283                hashing_algorithm
284                    .ok_or_else(|| {
285                        error!(
286                            "Hashing algorithm is required when creating ECC scheme of type EC DH."
287                        );
288                        Error::local_error(WrapperErrorKind::ParamsMissing)
289                    })
290                    .map(|v| EccScheme::EcDh(HashScheme::new(v)))
291            }
292            EccSchemeAlgorithm::EcDaa => Ok(EccScheme::EcDaa(EcDaaScheme::new(
293                hashing_algorithm.ok_or_else(|| {
294                    error!(
295                        "Hashing algorithm is required when creating ECC scheme of type EC DAA."
296                    );
297                    Error::local_error(WrapperErrorKind::ParamsMissing)
298                })?,
299                count.ok_or_else(|| {
300                    error!("Count is required when creating ECC scheme of type EC DAA.");
301                    Error::local_error(WrapperErrorKind::ParamsMissing)
302                })?,
303            ))),
304            EccSchemeAlgorithm::Sm2 => {
305                if count.is_some() {
306                    error!("`count` should not be provided when creating ECC scheme of type SM2.");
307                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
308                }
309
310                hashing_algorithm
311                    .ok_or_else(|| {
312                        error!(
313                            "Hashing algorithm is required when creating ECC scheme of type SM2."
314                        );
315                        Error::local_error(WrapperErrorKind::ParamsMissing)
316                    })
317                    .map(|v| EccScheme::Sm2(HashScheme::new(v)))
318            }
319            EccSchemeAlgorithm::EcSchnorr => {
320                if count.is_some() {
321                    error!(
322                        "`count` should not be provided when creating ECC scheme of type EC SCHNORR."
323                    );
324                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
325                }
326
327                hashing_algorithm
328                    .ok_or_else(|| {
329                        error!(
330                            "Hashing algorithm is required when creating ECC scheme of type EC SCHNORR."
331                        );
332                        Error::local_error(WrapperErrorKind::ParamsMissing)
333                    })
334                    .map(|v| EccScheme::EcSchnorr(HashScheme::new(v)))
335            }
336            EccSchemeAlgorithm::EcMqv => {
337                if count.is_some() {
338                    error!(
339                        "`count` should not be provided when creating ECC scheme of type EC MQV."
340                    );
341                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
342                }
343
344                hashing_algorithm
345                    .ok_or_else(|| {
346                        error!(
347                            "Hashing algorithm is required when creating ECC scheme of type EC MQV."
348                        );
349                        Error::local_error(WrapperErrorKind::ParamsMissing)
350                    })
351                    .map(|v| EccScheme::EcMqv(HashScheme::new(v)))
352            }
353            EccSchemeAlgorithm::Null => {
354                if count.is_some() {
355                    error!("`count` should not be provided when creating ECC scheme of type Null.");
356                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
357                }
358                if hashing_algorithm.is_some() {
359                    error!(
360                        "A hashing algorithm shall not be provided when creating ECC scheme of type Null."
361                    );
362                    return Err(Error::local_error(WrapperErrorKind::InconsistentParams));
363                }
364                Ok(EccScheme::Null)
365            }
366        }
367    }
368
369    pub fn algorithm(&self) -> EccSchemeAlgorithm {
370        match self {
371            EccScheme::EcDsa(_) => EccSchemeAlgorithm::EcDsa,
372            EccScheme::EcDh(_) => EccSchemeAlgorithm::EcDh,
373            EccScheme::EcDaa(_) => EccSchemeAlgorithm::EcDaa,
374            EccScheme::Sm2(_) => EccSchemeAlgorithm::Sm2,
375            EccScheme::EcSchnorr(_) => EccSchemeAlgorithm::EcSchnorr,
376            EccScheme::EcMqv(_) => EccSchemeAlgorithm::EcMqv,
377            EccScheme::Null => EccSchemeAlgorithm::Null,
378        }
379    }
380}
381
382impl From<EccScheme> for TPMT_ECC_SCHEME {
383    fn from(ecc_scheme: EccScheme) -> Self {
384        match ecc_scheme {
385            EccScheme::EcDsa(hash_scheme) => TPMT_ECC_SCHEME {
386                scheme: ecc_scheme.algorithm().into(),
387                details: TPMU_ASYM_SCHEME {
388                    ecdsa: hash_scheme.into(),
389                },
390            },
391            EccScheme::EcDh(hash_scheme) => TPMT_ECC_SCHEME {
392                scheme: ecc_scheme.algorithm().into(),
393                details: TPMU_ASYM_SCHEME {
394                    ecdh: hash_scheme.into(),
395                },
396            },
397            EccScheme::EcDaa(ec_daa_scheme) => TPMT_ECC_SCHEME {
398                scheme: ecc_scheme.algorithm().into(),
399                details: TPMU_ASYM_SCHEME {
400                    ecdaa: ec_daa_scheme.into(),
401                },
402            },
403
404            EccScheme::Sm2(hash_scheme) => TPMT_ECC_SCHEME {
405                scheme: ecc_scheme.algorithm().into(),
406                details: TPMU_ASYM_SCHEME {
407                    sm2: hash_scheme.into(),
408                },
409            },
410            EccScheme::EcSchnorr(hash_scheme) => TPMT_ECC_SCHEME {
411                scheme: ecc_scheme.algorithm().into(),
412                details: TPMU_ASYM_SCHEME {
413                    ecschnorr: hash_scheme.into(),
414                },
415            },
416            EccScheme::EcMqv(hash_scheme) => TPMT_ECC_SCHEME {
417                scheme: ecc_scheme.algorithm().into(),
418                details: TPMU_ASYM_SCHEME {
419                    ecmqv: hash_scheme.into(),
420                },
421            },
422            EccScheme::Null => TPMT_ECC_SCHEME {
423                scheme: ecc_scheme.algorithm().into(),
424                details: Default::default(),
425            },
426        }
427    }
428}
429
430impl TryFrom<TPMT_ECC_SCHEME> for EccScheme {
431    type Error = Error;
432
433    fn try_from(tpmt_ecc_scheme: TPMT_ECC_SCHEME) -> Result<Self> {
434        match EccSchemeAlgorithm::try_from(tpmt_ecc_scheme.scheme)? {
435            EccSchemeAlgorithm::EcDsa => Ok(EccScheme::EcDsa(
436                unsafe { tpmt_ecc_scheme.details.ecdsa }.try_into()?,
437            )),
438            EccSchemeAlgorithm::EcDh => Ok(EccScheme::EcDh(
439                unsafe { tpmt_ecc_scheme.details.ecdh }.try_into()?,
440            )),
441            EccSchemeAlgorithm::EcDaa => Ok(EccScheme::EcDaa(
442                unsafe { tpmt_ecc_scheme.details.ecdaa }.try_into()?,
443            )),
444            EccSchemeAlgorithm::Sm2 => Ok(EccScheme::Sm2(
445                unsafe { tpmt_ecc_scheme.details.sm2 }.try_into()?,
446            )),
447            EccSchemeAlgorithm::EcSchnorr => Ok(EccScheme::EcSchnorr(
448                unsafe { tpmt_ecc_scheme.details.ecschnorr }.try_into()?,
449            )),
450            EccSchemeAlgorithm::EcMqv => Ok(EccScheme::EcMqv(
451                unsafe { tpmt_ecc_scheme.details.ecmqv }.try_into()?,
452            )),
453            EccSchemeAlgorithm::Null => Ok(EccScheme::Null),
454        }
455    }
456}
457
458/// Enum representing the kdf scheme
459///
460/// # Details
461/// This corresponds to TPMT_KDF_SCHEME.
462#[derive(Clone, Copy, Debug, PartialEq, Eq)]
463pub enum KeyDerivationFunctionScheme {
464    Kdf1Sp800_56a(HashScheme),
465    Kdf2(HashScheme),
466    Kdf1Sp800_108(HashScheme),
467    Mgf1(HashScheme),
468    Null,
469}
470
471impl From<KeyDerivationFunctionScheme> for TPMT_KDF_SCHEME {
472    fn from(key_derivation_function_scheme: KeyDerivationFunctionScheme) -> Self {
473        match key_derivation_function_scheme {
474            KeyDerivationFunctionScheme::Kdf1Sp800_56a(hash_scheme) => TPMT_KDF_SCHEME {
475                scheme: KeyDerivationFunction::Kdf1Sp800_56a.into(),
476                details: TPMU_KDF_SCHEME {
477                    kdf1_sp800_56a: hash_scheme.into(),
478                },
479            },
480            KeyDerivationFunctionScheme::Kdf2(hash_scheme) => TPMT_KDF_SCHEME {
481                scheme: KeyDerivationFunction::Kdf2.into(),
482                details: TPMU_KDF_SCHEME {
483                    kdf2: hash_scheme.into(),
484                },
485            },
486            KeyDerivationFunctionScheme::Kdf1Sp800_108(hash_scheme) => TPMT_KDF_SCHEME {
487                scheme: KeyDerivationFunction::Kdf1Sp800_108.into(),
488                details: TPMU_KDF_SCHEME {
489                    kdf1_sp800_108: hash_scheme.into(),
490                },
491            },
492            KeyDerivationFunctionScheme::Mgf1(hash_scheme) => TPMT_KDF_SCHEME {
493                scheme: KeyDerivationFunction::Mgf1.into(),
494                details: TPMU_KDF_SCHEME {
495                    mgf1: hash_scheme.into(),
496                },
497            },
498            KeyDerivationFunctionScheme::Null => TPMT_KDF_SCHEME {
499                scheme: KeyDerivationFunction::Null.into(),
500                details: Default::default(),
501            },
502        }
503    }
504}
505
506impl TryFrom<TPMT_KDF_SCHEME> for KeyDerivationFunctionScheme {
507    type Error = Error;
508
509    fn try_from(tpmt_kdf_scheme: TPMT_KDF_SCHEME) -> Result<Self> {
510        match KeyDerivationFunction::try_from(tpmt_kdf_scheme.scheme)? {
511            KeyDerivationFunction::Kdf1Sp800_56a => Ok(KeyDerivationFunctionScheme::Kdf1Sp800_56a(
512                unsafe { tpmt_kdf_scheme.details.kdf1_sp800_56a }.try_into()?,
513            )),
514            KeyDerivationFunction::Kdf2 => Ok(KeyDerivationFunctionScheme::Kdf2(
515                unsafe { tpmt_kdf_scheme.details.kdf2 }.try_into()?,
516            )),
517            KeyDerivationFunction::Kdf1Sp800_108 => Ok(KeyDerivationFunctionScheme::Kdf1Sp800_108(
518                unsafe { tpmt_kdf_scheme.details.kdf1_sp800_108 }.try_into()?,
519            )),
520            KeyDerivationFunction::Mgf1 => Ok(KeyDerivationFunctionScheme::Mgf1(
521                unsafe { tpmt_kdf_scheme.details.mgf1 }.try_into()?,
522            )),
523            KeyDerivationFunction::Null => Ok(KeyDerivationFunctionScheme::Null),
524        }
525    }
526}
527
528/// Enum representing the rsa decryption scheme
529///
530/// # Details
531/// This corresponds to TPMT_RSA_DECRYPT.
532#[derive(Clone, Copy, Debug, PartialEq, Eq)]
533pub enum RsaDecryptionScheme {
534    RsaEs,
535    Oaep(HashScheme),
536    Null,
537}
538
539impl RsaDecryptionScheme {
540    /// Creates a new rsa decrypt scheme.
541    ///
542    /// # Arguments
543    /// `rsa_decrypt_algorithm` - The RSA decryption algorithm.
544    /// `hashing_algorithm` - The hashing algorithm used in some variants of the scheme.
545    ///
546    /// # Errors
547    /// `InconsistentParams` - If a parameter has been provided when it is not required.
548    /// `ParamsMissing` - If a required parameter has not been provided.
549    pub fn create(
550        rsa_decrypt_algorithm: RsaDecryptAlgorithm,
551        hashing_algorithm: Option<HashingAlgorithm>,
552    ) -> Result<RsaDecryptionScheme> {
553        match rsa_decrypt_algorithm {
554            RsaDecryptAlgorithm::RsaEs => {
555                if hashing_algorithm.is_none() {
556                    Ok(RsaDecryptionScheme::RsaEs)
557                } else {
558                    error!("A hashing algorithm shall not be provided when creating RSA decryption scheme of type RSA ES");
559                    Err(Error::local_error(WrapperErrorKind::InconsistentParams))
560                }
561            },
562            RsaDecryptAlgorithm::Oaep => Ok(RsaDecryptionScheme::Oaep(HashScheme::new(
563                hashing_algorithm.ok_or_else(|| {
564                    error!("Hashing algorithm is required when creating RSA decrypt scheme of type OEAP");
565                    Error::local_error(WrapperErrorKind::ParamsMissing)
566                })?,
567            ))),
568            RsaDecryptAlgorithm::Null => {
569                if hashing_algorithm.is_none() {
570                    Ok(RsaDecryptionScheme::Null)
571                } else {
572                    error!("A hashing algorithm shall not be provided when creating RSA decryption scheme of type Null");
573                    Err(Error::local_error(WrapperErrorKind::InconsistentParams))
574                }
575            }
576        }
577    }
578
579    /// Returns the rsa decrypt scheme algorithm
580    pub fn algorithm(&self) -> RsaDecryptAlgorithm {
581        match self {
582            RsaDecryptionScheme::RsaEs => RsaDecryptAlgorithm::RsaEs,
583            RsaDecryptionScheme::Oaep(_) => RsaDecryptAlgorithm::Oaep,
584            RsaDecryptionScheme::Null => RsaDecryptAlgorithm::Null,
585        }
586    }
587}
588
589impl From<RsaDecryptionScheme> for TPMT_RSA_DECRYPT {
590    fn from(rsa_decryption_scheme: RsaDecryptionScheme) -> Self {
591        match rsa_decryption_scheme {
592            RsaDecryptionScheme::RsaEs => TPMT_RSA_DECRYPT {
593                scheme: rsa_decryption_scheme.algorithm().into(),
594                details: TPMU_ASYM_SCHEME {
595                    rsaes: Default::default(),
596                },
597            },
598            RsaDecryptionScheme::Oaep(hash_scheme) => TPMT_RSA_DECRYPT {
599                scheme: rsa_decryption_scheme.algorithm().into(),
600                details: TPMU_ASYM_SCHEME {
601                    oaep: hash_scheme.into(),
602                },
603            },
604            RsaDecryptionScheme::Null => TPMT_RSA_DECRYPT {
605                scheme: rsa_decryption_scheme.algorithm().into(),
606                details: Default::default(),
607            },
608        }
609    }
610}
611
612impl TryFrom<TPMT_RSA_DECRYPT> for RsaDecryptionScheme {
613    type Error = Error;
614
615    fn try_from(tpmt_rsa_decrypt: TPMT_RSA_DECRYPT) -> Result<Self> {
616        match RsaDecryptAlgorithm::try_from(tpmt_rsa_decrypt.scheme)? {
617            RsaDecryptAlgorithm::RsaEs => Ok(RsaDecryptionScheme::RsaEs),
618            RsaDecryptAlgorithm::Oaep => Ok(RsaDecryptionScheme::Oaep(
619                unsafe { tpmt_rsa_decrypt.details.oaep }.try_into()?,
620            )),
621            RsaDecryptAlgorithm::Null => Ok(RsaDecryptionScheme::Null),
622        }
623    }
624}
625
626impl TryFrom<RsaScheme> for RsaDecryptionScheme {
627    type Error = Error;
628
629    fn try_from(rsa_scheme: RsaScheme) -> Result<Self> {
630        match rsa_scheme {
631            RsaScheme::RsaEs => Ok(RsaDecryptionScheme::RsaEs),
632            RsaScheme::Oaep(hash_scheme) => Ok(RsaDecryptionScheme::Oaep(hash_scheme)),
633            RsaScheme::Null => Ok(RsaDecryptionScheme::Null),
634            _ => Err(Error::local_error(WrapperErrorKind::InvalidParam)),
635        }
636    }
637}
638
639/// Full description of signature schemes.
640///
641/// # Details
642/// Corresponds to `TPMT_SIG_SCHEME`.
643#[derive(Clone, Copy, Debug, Eq, PartialEq)]
644pub enum SignatureScheme {
645    RsaSsa { scheme: HashScheme },
646    RsaPss { scheme: HashScheme },
647    EcDsa { scheme: HashScheme },
648    Sm2 { scheme: HashScheme },
649    EcSchnorr { scheme: HashScheme },
650    EcDaa { scheme: EcDaaScheme },
651    Hmac { scheme: HmacScheme },
652    Null,
653}
654
655impl SignatureScheme {
656    /// Returns the digest( i.e. hashing algorithm) of a signing scheme.
657    ///
658    /// # Details
659    /// This is intended to provide the functionality of reading
660    /// from the `any` field in the TPMU_SIG_SCHEME union.
661    ///
662    /// # Errors
663    /// Returns an InvalidParam error if the trying to read from
664    /// SignatureScheme that is not a signing scheme.
665    pub fn signing_scheme(&self) -> Result<HashingAlgorithm> {
666        match self {
667            SignatureScheme::RsaSsa { scheme }
668            | SignatureScheme::RsaPss { scheme }
669            | SignatureScheme::EcDsa { scheme }
670            | SignatureScheme::Sm2 { scheme }
671            | SignatureScheme::EcSchnorr { scheme } => Ok(scheme.hashing_algorithm()),
672            SignatureScheme::EcDaa { scheme } => Ok(scheme.hashing_algorithm()),
673            SignatureScheme::Hmac { scheme } => Ok(scheme.hashing_algorithm()),
674            _ => {
675                error!("Cannot access digest for a non signing scheme");
676                Err(Error::local_error(WrapperErrorKind::InvalidParam))
677            }
678        }
679    }
680
681    /// Sets digest( i.e. hashing algorithm) of a signing scheme.
682    ///
683    /// # Details
684    /// This is intended to provide the functionality of writing
685    /// to the `any` field in the TPMU_SIG_SCHEME union.
686    ///
687    /// # Errors
688    /// Returns an InvalidParam error if the trying to read from
689    /// SignatureScheme that is not a signing scheme.
690    pub fn set_signing_scheme(&mut self, hashing_algorithm: HashingAlgorithm) -> Result<()> {
691        match self {
692            SignatureScheme::RsaSsa { scheme }
693            | SignatureScheme::RsaPss { scheme }
694            | SignatureScheme::EcDsa { scheme }
695            | SignatureScheme::Sm2 { scheme }
696            | SignatureScheme::EcSchnorr { scheme } => {
697                *scheme = HashScheme::new(hashing_algorithm);
698                Ok(())
699            }
700            SignatureScheme::EcDaa { scheme } => {
701                *scheme = EcDaaScheme::new(hashing_algorithm, scheme.count());
702                Ok(())
703            }
704            SignatureScheme::Hmac { scheme } => {
705                *scheme = HmacScheme::new(hashing_algorithm);
706                Ok(())
707            }
708            _ => {
709                error!("Cannot access digest for a non signing scheme");
710                Err(Error::local_error(WrapperErrorKind::InvalidParam))
711            }
712        }
713    }
714}
715
716impl From<SignatureScheme> for TPMT_SIG_SCHEME {
717    fn from(native: SignatureScheme) -> TPMT_SIG_SCHEME {
718        match native {
719            SignatureScheme::EcDaa { scheme } => TPMT_SIG_SCHEME {
720                scheme: SignatureSchemeAlgorithm::EcDaa.into(),
721                details: TPMU_SIG_SCHEME {
722                    ecdaa: scheme.into(),
723                },
724            },
725            SignatureScheme::EcDsa { scheme } => TPMT_SIG_SCHEME {
726                scheme: SignatureSchemeAlgorithm::EcDsa.into(),
727                details: TPMU_SIG_SCHEME {
728                    ecdsa: scheme.into(),
729                },
730            },
731            SignatureScheme::EcSchnorr { scheme } => TPMT_SIG_SCHEME {
732                scheme: SignatureSchemeAlgorithm::EcSchnorr.into(),
733                details: TPMU_SIG_SCHEME {
734                    ecschnorr: scheme.into(),
735                },
736            },
737            SignatureScheme::Hmac { scheme } => TPMT_SIG_SCHEME {
738                scheme: SignatureSchemeAlgorithm::Hmac.into(),
739                details: TPMU_SIG_SCHEME {
740                    hmac: scheme.into(),
741                },
742            },
743            SignatureScheme::Null => TPMT_SIG_SCHEME {
744                scheme: SignatureSchemeAlgorithm::Null.into(),
745                details: Default::default(),
746            },
747            SignatureScheme::RsaPss { scheme } => TPMT_SIG_SCHEME {
748                scheme: SignatureSchemeAlgorithm::RsaPss.into(),
749                details: TPMU_SIG_SCHEME {
750                    rsapss: scheme.into(),
751                },
752            },
753            SignatureScheme::RsaSsa { scheme } => TPMT_SIG_SCHEME {
754                scheme: SignatureSchemeAlgorithm::RsaSsa.into(),
755                details: TPMU_SIG_SCHEME {
756                    rsassa: scheme.into(),
757                },
758            },
759            SignatureScheme::Sm2 { scheme } => TPMT_SIG_SCHEME {
760                scheme: SignatureSchemeAlgorithm::Sm2.into(),
761                details: TPMU_SIG_SCHEME { sm2: scheme.into() },
762            },
763        }
764    }
765}
766
767impl TryFrom<TPMT_SIG_SCHEME> for SignatureScheme {
768    type Error = Error;
769
770    fn try_from(tss: TPMT_SIG_SCHEME) -> Result<Self> {
771        match SignatureSchemeAlgorithm::try_from(tss.scheme)? {
772            SignatureSchemeAlgorithm::EcDaa => Ok(SignatureScheme::EcDaa {
773                scheme: unsafe { tss.details.ecdaa }.try_into()?,
774            }),
775            SignatureSchemeAlgorithm::EcDsa => Ok(SignatureScheme::EcDsa {
776                scheme: unsafe { tss.details.ecdsa }.try_into()?,
777            }),
778            SignatureSchemeAlgorithm::EcSchnorr => Ok(SignatureScheme::EcSchnorr {
779                scheme: unsafe { tss.details.ecschnorr }.try_into()?,
780            }),
781            SignatureSchemeAlgorithm::Hmac => Ok(SignatureScheme::Hmac {
782                scheme: unsafe { tss.details.hmac }.try_into()?,
783            }),
784            SignatureSchemeAlgorithm::Null => Ok(SignatureScheme::Null),
785            SignatureSchemeAlgorithm::RsaPss => Ok(SignatureScheme::RsaPss {
786                scheme: unsafe { tss.details.rsapss }.try_into()?,
787            }),
788            SignatureSchemeAlgorithm::RsaSsa => Ok(SignatureScheme::RsaSsa {
789                scheme: unsafe { tss.details.rsassa }.try_into()?,
790            }),
791            SignatureSchemeAlgorithm::Sm2 => Ok(SignatureScheme::Sm2 {
792                scheme: unsafe { tss.details.sm2 }.try_into()?,
793            }),
794        }
795    }
796}