|
3 | 3 |
|
4 | 4 | use crate::interface_types::ecc::EccCurve;
|
5 | 5 | use crate::structures::{Public, RsaExponent};
|
| 6 | +use crate::utils::PublicKey as TpmPublicKey; |
6 | 7 | use crate::{Error, WrapperErrorKind};
|
7 | 8 |
|
8 | 9 | use core::convert::TryFrom;
|
9 |
| -use oid::ObjectIdentifier; |
10 |
| -use picky_asn1::bit_string::BitString; |
11 |
| -use picky_asn1::wrapper::{IntegerAsn1, OctetStringAsn1}; |
12 |
| -use picky_asn1_x509::{ |
13 |
| - AlgorithmIdentifier, EcParameters, EcPoint, PublicKey, RsaPublicKey, SubjectPublicKeyInfo, |
| 10 | +use elliptic_curve::{ |
| 11 | + // See TODO below, you're upgrading from 0.13 to 0.14 and |
| 12 | + // that moved the implementation from generic-array to |
| 13 | + // hybrid-array, you can now use TryFrom |
| 14 | + generic_array::typenum::Unsigned, |
| 15 | + sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, |
| 16 | + AffinePoint, |
| 17 | + CurveArithmetic, |
| 18 | + FieldBytesSize, |
| 19 | + PublicKey, |
14 | 20 | };
|
| 21 | +use rsa::{pkcs8::EncodePublicKey, BigUint, RsaPublicKey}; |
| 22 | +use x509_cert::spki::SubjectPublicKeyInfoOwned; |
15 | 23 |
|
16 |
| -/// Can be converted from [`crate::structures::Public`] when not a fully constructed |
17 |
| -/// [`picky_asn1_x509::SubjectPublicKeyInfo`] is required. |
18 |
| -/// |
19 |
| -/// # Details |
20 |
| -/// Holds either [`picky_asn1_x509::RsaPublicKey`] for [`crate::structures::Public::Rsa`] or |
21 |
| -/// [`picky_asn1_x509::EcPoint`] for [`crate::structures::Public::Ecc`]. |
22 |
| -/// |
23 |
| -/// This object can be serialized and deserialized |
24 |
| -/// using serde if the `serde` feature is enabled. |
25 |
| -#[derive(Debug, PartialEq, Eq, Clone)] |
26 |
| -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] |
27 |
| -pub enum DecodedKey { |
28 |
| - RsaPublicKey(RsaPublicKey), |
29 |
| - EcPoint(EcPoint), |
| 24 | +/// Default exponent for RSA keys. |
| 25 | +// Also known as 0x10001 |
| 26 | +const RSA_DEFAULT_EXP: u64 = 65537; |
| 27 | + |
| 28 | +impl<C> TryFrom<&Public> for PublicKey<C> |
| 29 | +where |
| 30 | + C: CurveArithmetic + AssociatedTpmCurve, |
| 31 | + FieldBytesSize<C>: ModulusSize, |
| 32 | + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, |
| 33 | +{ |
| 34 | + type Error = Error; |
| 35 | + |
| 36 | + fn try_from(value: &Public) -> Result<Self, Self::Error> { |
| 37 | + match value { |
| 38 | + Public::Ecc { |
| 39 | + parameters, unique, .. |
| 40 | + } => { |
| 41 | + if parameters.ecc_curve() != C::TPM_CURVE { |
| 42 | + return Err(Error::local_error(WrapperErrorKind::InvalidParam)); |
| 43 | + } |
| 44 | + |
| 45 | + let x = unique.x().as_bytes(); |
| 46 | + let y = unique.y().as_bytes(); |
| 47 | + |
| 48 | + // TODO: When elliptic_curve bumps to 0.14, we can use the TryFrom implementation instead |
| 49 | + // of checking lengths manually |
| 50 | + if x.len() != FieldBytesSize::<C>::USIZE { |
| 51 | + return Err(Error::local_error(WrapperErrorKind::InvalidParam)); |
| 52 | + } |
| 53 | + if y.len() != FieldBytesSize::<C>::USIZE { |
| 54 | + return Err(Error::local_error(WrapperErrorKind::InvalidParam)); |
| 55 | + } |
| 56 | + |
| 57 | + let encoded_point = |
| 58 | + EncodedPoint::<C>::from_affine_coordinates(x.into(), y.into(), false); |
| 59 | + let public_key = PublicKey::<C>::try_from(&encoded_point) |
| 60 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; |
| 61 | + |
| 62 | + Ok(public_key) |
| 63 | + } |
| 64 | + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), |
| 65 | + } |
| 66 | + } |
30 | 67 | }
|
31 | 68 |
|
32 |
| -impl TryFrom<Public> for DecodedKey { |
| 69 | +impl TryFrom<&Public> for RsaPublicKey { |
33 | 70 | type Error = Error;
|
34 | 71 |
|
35 |
| - fn try_from(value: Public) -> Result<Self, Self::Error> { |
36 |
| - public_to_decoded_key(&value) |
| 72 | + fn try_from(value: &Public) -> Result<Self, Self::Error> { |
| 73 | + match value { |
| 74 | + Public::Rsa { |
| 75 | + unique, parameters, .. |
| 76 | + } => { |
| 77 | + let exponent = match parameters.exponent() { |
| 78 | + RsaExponent::ZERO_EXPONENT => BigUint::from(RSA_DEFAULT_EXP), |
| 79 | + _ => BigUint::from(parameters.exponent().value()), |
| 80 | + }; |
| 81 | + let modulus = BigUint::from_bytes_be(unique.as_bytes()); |
| 82 | + |
| 83 | + let public_key = RsaPublicKey::new(modulus, exponent) |
| 84 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; |
| 85 | + |
| 86 | + Ok(public_key) |
| 87 | + } |
| 88 | + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), |
| 89 | + } |
37 | 90 | }
|
38 | 91 | }
|
39 | 92 |
|
40 |
| -impl TryFrom<Public> for SubjectPublicKeyInfo { |
| 93 | +impl TryFrom<&Public> for SubjectPublicKeyInfoOwned { |
41 | 94 | type Error = Error;
|
42 | 95 |
|
43 |
| - /// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`picky_asn1_x509::SubjectPublicKeyInfo`]. |
| 96 | + /// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [`x509_cert::spki::SubjectPublicKeyInfoOwned`]. |
44 | 97 | ///
|
45 | 98 | /// # Details
|
46 |
| - /// The result can be used to convert TPM public keys to DER using `picky_asn1_der`. |
| 99 | + /// The result can be used to convert TPM public keys to DER using `x509-cert`. |
47 | 100 | ///
|
48 | 101 | /// # Errors
|
49 | 102 | /// * if other instances of [`crate::structures::Public`] are used `UnsupportedParam` will be returned.
|
50 |
| - fn try_from(value: Public) -> Result<Self, Self::Error> { |
51 |
| - let decoded_key = public_to_decoded_key(&value)?; |
52 |
| - |
53 |
| - match (value, decoded_key) { |
54 |
| - (Public::Rsa { .. }, DecodedKey::RsaPublicKey(key)) => Ok(SubjectPublicKeyInfo { |
55 |
| - algorithm: AlgorithmIdentifier::new_rsa_encryption(), |
56 |
| - subject_public_key: PublicKey::Rsa(key.into()), |
57 |
| - }), |
58 |
| - (Public::Ecc { parameters, .. }, DecodedKey::EcPoint(point)) => { |
59 |
| - Ok(SubjectPublicKeyInfo { |
60 |
| - algorithm: AlgorithmIdentifier::new_elliptic_curve(EcParameters::NamedCurve( |
61 |
| - curve_oid(parameters.ecc_curve())?.into(), |
62 |
| - )), |
63 |
| - subject_public_key: PublicKey::Ec(BitString::with_bytes(point).into()), |
64 |
| - }) |
| 103 | + fn try_from(value: &Public) -> Result<Self, Self::Error> { |
| 104 | + match value { |
| 105 | + Public::Rsa { .. } => { |
| 106 | + let public_key = RsaPublicKey::try_from(value)?; |
| 107 | + |
| 108 | + Ok(public_key |
| 109 | + .to_public_key_der() |
| 110 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))? |
| 111 | + .decode_msg::<Self>() |
| 112 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?) |
| 113 | + } |
| 114 | + #[allow(unused)] |
| 115 | + Public::Ecc { parameters, .. } => { |
| 116 | + macro_rules! read_key { |
| 117 | + ($curve:expr, $key_type:ty) => { |
| 118 | + if parameters.ecc_curve() == <$key_type>::TPM_CURVE { |
| 119 | + let public_key = PublicKey::<$key_type>::try_from(value)?; |
| 120 | + |
| 121 | + return public_key |
| 122 | + .to_public_key_der() |
| 123 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))? |
| 124 | + .decode_msg::<Self>() |
| 125 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam)); |
| 126 | + } |
| 127 | + }; |
| 128 | + } |
| 129 | + |
| 130 | + #[cfg(feature = "p192")] |
| 131 | + read_key!(EccCurve::NistP192, p192::NistP192); |
| 132 | + #[cfg(feature = "p224")] |
| 133 | + read_key!(EccCurve::NistP224, p224::NistP224); |
| 134 | + #[cfg(feature = "p256")] |
| 135 | + read_key!(EccCurve::NistP256, p256::NistP256); |
| 136 | + #[cfg(feature = "p384")] |
| 137 | + read_key!(EccCurve::NistP384, p384::NistP384); |
| 138 | + #[cfg(feature = "p521")] |
| 139 | + read_key!(EccCurve::NistP521, p521::NistP521); |
| 140 | + #[cfg(feature = "sm2")] |
| 141 | + read_key!(EccCurve::Sm2P256, sm2::Sm2); |
| 142 | + |
| 143 | + Err(Error::local_error(WrapperErrorKind::UnsupportedParam)) |
65 | 144 | }
|
66 | 145 | _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)),
|
67 | 146 | }
|
68 | 147 | }
|
69 | 148 | }
|
70 | 149 |
|
71 |
| -/// Converts [`crate::structures::Public::Rsa`] and [`crate::structures::Public::Ecc`] to [DecodedKey]. |
72 |
| -/// |
73 |
| -/// # Details |
74 |
| -/// Does basic key conversion to either RSA or ECC. In RSA conversion the TPM zero exponent is replaced with `65537`. |
75 |
| -/// |
76 |
| -/// # Errors |
77 |
| -/// * if other instances of [`crate::structures::Public`] are used `UnsupportedParam` will be returned. |
78 |
| -fn public_to_decoded_key(public: &Public) -> Result<DecodedKey, Error> { |
79 |
| - match public { |
80 |
| - Public::Rsa { |
81 |
| - unique, parameters, .. |
82 |
| - } => { |
83 |
| - let exponent = match parameters.exponent() { |
84 |
| - RsaExponent::ZERO_EXPONENT => 65537, |
85 |
| - _ => parameters.exponent().value(), |
| 150 | +impl<C> TryFrom<&TpmPublicKey> for PublicKey<C> |
| 151 | +where |
| 152 | + C: CurveArithmetic + AssociatedTpmCurve, |
| 153 | + FieldBytesSize<C>: ModulusSize, |
| 154 | + AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, |
| 155 | +{ |
| 156 | + type Error = Error; |
| 157 | + |
| 158 | + fn try_from(value: &TpmPublicKey) -> Result<Self, Self::Error> { |
| 159 | + match value { |
| 160 | + TpmPublicKey::Ecc { x, y } => { |
| 161 | + let x = x.as_slice(); |
| 162 | + let y = y.as_slice(); |
| 163 | + |
| 164 | + // TODO: When elliptic_curve bumps to 0.14, we can use the TryFrom implementation instead |
| 165 | + // of checking lengths manually |
| 166 | + if x.len() != FieldBytesSize::<C>::USIZE { |
| 167 | + return Err(Error::local_error(WrapperErrorKind::InvalidParam)); |
| 168 | + } |
| 169 | + if y.len() != FieldBytesSize::<C>::USIZE { |
| 170 | + return Err(Error::local_error(WrapperErrorKind::InvalidParam)); |
| 171 | + } |
| 172 | + |
| 173 | + let encoded_point = |
| 174 | + EncodedPoint::<C>::from_affine_coordinates(x.into(), y.into(), false); |
| 175 | + let public_key = PublicKey::<C>::try_from(&encoded_point) |
| 176 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; |
| 177 | + |
| 178 | + Ok(public_key) |
86 | 179 | }
|
87 |
| - .to_be_bytes(); |
88 |
| - Ok(DecodedKey::RsaPublicKey(RsaPublicKey { |
89 |
| - modulus: IntegerAsn1::from_bytes_be_unsigned(unique.as_bytes().to_vec()), |
90 |
| - public_exponent: IntegerAsn1::from_bytes_be_signed(exponent.to_vec()), |
91 |
| - })) |
92 |
| - } |
93 |
| - Public::Ecc { unique, .. } => { |
94 |
| - let x = unique.x().as_bytes().to_vec(); |
95 |
| - let y = unique.y().as_bytes().to_vec(); |
96 |
| - Ok(DecodedKey::EcPoint(OctetStringAsn1( |
97 |
| - elliptic_curve_point_to_octet_string(x, y), |
98 |
| - ))) |
| 180 | + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), |
99 | 181 | }
|
| 182 | + } |
| 183 | +} |
100 | 184 |
|
101 |
| - _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), |
| 185 | +impl TryFrom<&TpmPublicKey> for RsaPublicKey { |
| 186 | + type Error = Error; |
| 187 | + |
| 188 | + fn try_from(value: &TpmPublicKey) -> Result<Self, Self::Error> { |
| 189 | + match value { |
| 190 | + TpmPublicKey::Rsa(modulus) => { |
| 191 | + let exponent = BigUint::from(RSA_DEFAULT_EXP); |
| 192 | + let modulus = BigUint::from_bytes_be(modulus.as_slice()); |
| 193 | + |
| 194 | + let public_key = RsaPublicKey::new(modulus, exponent) |
| 195 | + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; |
| 196 | + |
| 197 | + Ok(public_key) |
| 198 | + } |
| 199 | + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), |
| 200 | + } |
102 | 201 | }
|
103 | 202 | }
|
104 | 203 |
|
105 |
| -// Taken from https://github.com/parallaxsecond/parsec/blob/561235f3cc37bcff3d9a6cb29c84eeae5d55100b/src/providers/tpm/utils.rs#L319 |
106 |
| -// Points on elliptic curves are represented as defined in section 2.3.3 of https://www.secg.org/sec1-v2.pdf |
107 |
| -// The (uncompressed) representation is [ 0x04 || x || y ] where x and y are the coordinates of the point |
108 |
| -fn elliptic_curve_point_to_octet_string(mut x: Vec<u8>, mut y: Vec<u8>) -> Vec<u8> { |
109 |
| - let mut octet_string = vec![0x04]; |
110 |
| - octet_string.append(&mut x); |
111 |
| - octet_string.append(&mut y); |
112 |
| - octet_string |
| 204 | +/// Provides the value of the curve used in this crate for the specific curve. |
| 205 | +pub trait AssociatedTpmCurve { |
| 206 | + /// Value of the curve when interacting with the TPM. |
| 207 | + const TPM_CURVE: EccCurve; |
113 | 208 | }
|
114 | 209 |
|
115 |
| -// Map TPM supported ECC curves to their respective OIDs |
116 |
| -fn curve_oid(ecc_curve: EccCurve) -> Result<ObjectIdentifier, Error> { |
117 |
| - match ecc_curve { |
118 |
| - EccCurve::NistP192 => Ok(picky_asn1_x509::oids::secp192r1()), |
119 |
| - EccCurve::NistP224 => Ok(picky_asn1_x509::oids::secp256r1()), |
120 |
| - EccCurve::NistP256 => Ok(picky_asn1_x509::oids::secp256r1()), |
121 |
| - EccCurve::NistP384 => Ok(picky_asn1_x509::oids::secp384r1()), |
122 |
| - EccCurve::NistP521 => Ok(picky_asn1_x509::oids::secp521r1()), |
123 |
| - // Barreto-Naehrig curves seem to not have any OIDs |
124 |
| - EccCurve::BnP256 => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), |
125 |
| - EccCurve::BnP638 => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), |
126 |
| - EccCurve::Sm2P256 => Ok(ObjectIdentifier::try_from("1.2.156.10197.1.301").unwrap()), |
127 |
| - } |
| 210 | +#[cfg(feature = "p192")] |
| 211 | +impl AssociatedTpmCurve for p192::NistP192 { |
| 212 | + const TPM_CURVE: EccCurve = EccCurve::NistP192; |
| 213 | +} |
| 214 | + |
| 215 | +#[cfg(feature = "p224")] |
| 216 | +impl AssociatedTpmCurve for p224::NistP224 { |
| 217 | + const TPM_CURVE: EccCurve = EccCurve::NistP224; |
| 218 | +} |
| 219 | + |
| 220 | +#[cfg(feature = "p256")] |
| 221 | +impl AssociatedTpmCurve for p256::NistP256 { |
| 222 | + const TPM_CURVE: EccCurve = EccCurve::NistP256; |
| 223 | +} |
| 224 | + |
| 225 | +#[cfg(feature = "p384")] |
| 226 | +impl AssociatedTpmCurve for p384::NistP384 { |
| 227 | + const TPM_CURVE: EccCurve = EccCurve::NistP384; |
| 228 | +} |
| 229 | + |
| 230 | +#[cfg(feature = "p521")] |
| 231 | +impl AssociatedTpmCurve for p521::NistP521 { |
| 232 | + const TPM_CURVE: EccCurve = EccCurve::NistP521; |
| 233 | +} |
| 234 | + |
| 235 | +#[cfg(feature = "sm2")] |
| 236 | +impl AssociatedTpmCurve for sm2::Sm2 { |
| 237 | + const TPM_CURVE: EccCurve = EccCurve::Sm2P256; |
128 | 238 | }
|
0 commit comments