Skip to main content

tss_esapi/abstraction/
public.rs

1// Copyright 2022 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::interface_types::ecc::EccCurve;
5use crate::structures::Public;
6use crate::utils::PublicKey as TpmPublicKey;
7use crate::{Error, WrapperErrorKind};
8
9use core::convert::TryFrom;
10use elliptic_curve::{
11    generic_array::typenum::Unsigned,
12    sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint},
13    AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey,
14};
15
16use x509_cert::spki::SubjectPublicKeyInfoOwned;
17
18#[cfg(feature = "rsa")]
19use {
20    crate::structures::RsaExponent,
21    rsa::{BigUint, RsaPublicKey},
22};
23
24#[cfg(any(
25    feature = "p192",
26    feature = "p224",
27    feature = "p256",
28    feature = "p384",
29    feature = "p521",
30    feature = "rsa",
31    feature = "sm2"
32))]
33use pkcs8::EncodePublicKey;
34
35/// Default exponent for RSA keys.
36// Also known as 0x10001
37#[cfg(feature = "rsa")]
38const RSA_DEFAULT_EXP: u64 = 65537;
39
40impl<C> TryFrom<&Public> for PublicKey<C>
41where
42    C: CurveArithmetic + AssociatedTpmCurve,
43    FieldBytesSize<C>: ModulusSize,
44    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
45{
46    type Error = Error;
47
48    fn try_from(value: &Public) -> Result<Self, Self::Error> {
49        match value {
50            Public::Ecc {
51                parameters, unique, ..
52            } => {
53                if parameters.ecc_curve() != C::TPM_CURVE {
54                    return Err(Error::local_error(WrapperErrorKind::InvalidParam));
55                }
56
57                let x = unique.x().as_bytes();
58                let y = unique.y().as_bytes();
59
60                if x.len() != FieldBytesSize::<C>::USIZE {
61                    return Err(Error::local_error(WrapperErrorKind::InvalidParam));
62                }
63                if y.len() != FieldBytesSize::<C>::USIZE {
64                    return Err(Error::local_error(WrapperErrorKind::InvalidParam));
65                }
66
67                let encoded_point =
68                    EncodedPoint::<C>::from_affine_coordinates(x.into(), y.into(), false);
69                let public_key = PublicKey::<C>::try_from(&encoded_point)
70                    .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
71
72                Ok(public_key)
73            }
74            _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
75        }
76    }
77}
78
79#[cfg(feature = "rsa")]
80impl TryFrom<&Public> for RsaPublicKey {
81    type Error = Error;
82
83    fn try_from(value: &Public) -> Result<Self, Self::Error> {
84        match value {
85            Public::Rsa {
86                unique, parameters, ..
87            } => {
88                let exponent = match parameters.exponent() {
89                    RsaExponent::ZERO_EXPONENT => BigUint::from(RSA_DEFAULT_EXP),
90                    _ => BigUint::from(parameters.exponent().value()),
91                };
92                let modulus = BigUint::from_bytes_be(unique.as_bytes());
93
94                let public_key = RsaPublicKey::new(modulus, exponent)
95                    .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
96
97                Ok(public_key)
98            }
99            _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
100        }
101    }
102}
103
104impl TryFrom<&Public> for SubjectPublicKeyInfoOwned {
105    type Error = Error;
106
107    /// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`x509_cert::spki::SubjectPublicKeyInfoOwned`].
108    ///
109    /// # Details
110    /// The result can be used to convert TPM public keys to DER using `x509-cert`.
111    ///
112    /// # Errors
113    /// * if other instances of [`crate::structures::Public`] are used `UnsupportedParam` will be returned.
114    fn try_from(value: &Public) -> Result<Self, Self::Error> {
115        match value {
116            #[cfg(feature = "rsa")]
117            Public::Rsa { .. } => {
118                let public_key = RsaPublicKey::try_from(value)?;
119
120                Ok(public_key
121                    .to_public_key_der()
122                    .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?
123                    .decode_msg::<Self>()
124                    .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?)
125            }
126            #[allow(unused)]
127            Public::Ecc { parameters, .. } => {
128                macro_rules! read_key {
129                    ($key_type:ty) => {
130                        if parameters.ecc_curve() == <$key_type>::TPM_CURVE {
131                            let public_key = PublicKey::<$key_type>::try_from(value)?;
132
133                            return public_key
134                                .to_public_key_der()
135                                .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?
136                                .decode_msg::<Self>()
137                                .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam));
138                        }
139                    };
140                }
141
142                #[cfg(feature = "p192")]
143                read_key!(p192::NistP192);
144                #[cfg(feature = "p224")]
145                read_key!(p224::NistP224);
146                #[cfg(feature = "p256")]
147                read_key!(p256::NistP256);
148                #[cfg(feature = "p384")]
149                read_key!(p384::NistP384);
150                #[cfg(feature = "p521")]
151                read_key!(p521::NistP521);
152                #[cfg(feature = "sm2")]
153                read_key!(sm2::Sm2);
154
155                Err(Error::local_error(WrapperErrorKind::UnsupportedParam))
156            }
157            _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
158        }
159    }
160}
161
162impl<C> TryFrom<&TpmPublicKey> for PublicKey<C>
163where
164    C: CurveArithmetic + AssociatedTpmCurve,
165    FieldBytesSize<C>: ModulusSize,
166    AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
167{
168    type Error = Error;
169
170    fn try_from(value: &TpmPublicKey) -> Result<Self, Self::Error> {
171        match value {
172            TpmPublicKey::Ecc { x, y } => {
173                let x = x.as_slice();
174                let y = y.as_slice();
175
176                // TODO: When elliptic_curve bumps to 0.14, we can use the TryFrom implementation instead
177                // of checking lengths manually
178                if x.len() != FieldBytesSize::<C>::USIZE {
179                    return Err(Error::local_error(WrapperErrorKind::InvalidParam));
180                }
181                if y.len() != FieldBytesSize::<C>::USIZE {
182                    return Err(Error::local_error(WrapperErrorKind::InvalidParam));
183                }
184
185                let encoded_point =
186                    EncodedPoint::<C>::from_affine_coordinates(x.into(), y.into(), false);
187                let public_key = PublicKey::<C>::try_from(&encoded_point)
188                    .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
189
190                Ok(public_key)
191            }
192            _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
193        }
194    }
195}
196
197#[cfg(feature = "rsa")]
198impl TryFrom<&TpmPublicKey> for RsaPublicKey {
199    type Error = Error;
200
201    fn try_from(value: &TpmPublicKey) -> Result<Self, Self::Error> {
202        match value {
203            TpmPublicKey::Rsa(modulus) => {
204                let exponent = BigUint::from(RSA_DEFAULT_EXP);
205                let modulus = BigUint::from_bytes_be(modulus.as_slice());
206
207                let public_key = RsaPublicKey::new(modulus, exponent)
208                    .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?;
209
210                Ok(public_key)
211            }
212            _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
213        }
214    }
215}
216
217/// Provides the value of the curve used in this crate for the specific curve.
218pub trait AssociatedTpmCurve {
219    /// Value of the curve when interacting with the TPM.
220    const TPM_CURVE: EccCurve;
221}
222
223#[cfg(feature = "p192")]
224impl AssociatedTpmCurve for p192::NistP192 {
225    const TPM_CURVE: EccCurve = EccCurve::NistP192;
226}
227
228#[cfg(feature = "p224")]
229impl AssociatedTpmCurve for p224::NistP224 {
230    const TPM_CURVE: EccCurve = EccCurve::NistP224;
231}
232
233#[cfg(feature = "p256")]
234impl AssociatedTpmCurve for p256::NistP256 {
235    const TPM_CURVE: EccCurve = EccCurve::NistP256;
236}
237
238#[cfg(feature = "p384")]
239impl AssociatedTpmCurve for p384::NistP384 {
240    const TPM_CURVE: EccCurve = EccCurve::NistP384;
241}
242
243#[cfg(feature = "p521")]
244impl AssociatedTpmCurve for p521::NistP521 {
245    const TPM_CURVE: EccCurve = EccCurve::NistP521;
246}
247
248#[cfg(feature = "sm2")]
249impl AssociatedTpmCurve for sm2::Sm2 {
250    const TPM_CURVE: EccCurve = EccCurve::Sm2P256;
251}