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