1#![allow(clippy::no_effect_underscore_binding)]
5
6use crate::key::{external_key::ExternalKey, KeyError};
7use num_bigint::{BigUint, ToBigInt};
8use num_traits::ToPrimitive;
9use rasn::{
10 types::{Integer, SequenceOf},
11 AsnType, Decode, Decoder, Encode,
12};
13use rsa::{traits::PublicKeyParts, RsaPrivateKey};
14use tpm2_protocol::data::{
15 Tpm2bDigest, Tpm2bPublicKeyRsa, TpmAlgId, TpmaObject, TpmsRsaParms, TpmsSchemeHash,
16 TpmtRsaScheme, TpmtSymDefObject, TpmuAsymScheme, TpmuPublicId, TpmuPublicParms,
17};
18
19#[derive(AsnType, Decode, Encode, Debug)]
20pub struct OtherPrimeInfo {
21 pub prime: Integer,
22 pub exponent: Integer,
23 pub coefficient: Integer,
24}
25
26#[allow(clippy::no_effect_underscore_binding)]
28#[derive(AsnType, Decode, Encode, Debug)]
29pub struct RsaPrivateKeyAsn1 {
30 pub version: Integer,
31 pub modulus: Integer,
32 pub public_exponent: Integer,
33 pub private_exponent: Integer,
34 pub prime1: Integer,
35 pub prime2: Integer,
36 pub exponent1: Integer,
37 pub exponent2: Integer,
38 pub coefficient: Integer,
39 pub other_prime_infos: Option<SequenceOf<OtherPrimeInfo>>,
40}
41
42#[allow(clippy::no_effect_underscore_binding)]
45#[derive(AsnType, Decode, Encode, Debug)]
46pub struct RsaPrivateKeyPkcs1V0 {
47 pub modulus: Integer,
48 pub public_exponent: Integer,
49 pub private_exponent: Integer,
50 pub prime1: Integer,
51 pub prime2: Integer,
52 pub exponent1: Integer,
53 pub exponent2: Integer,
54 pub coefficient: Integer,
55 pub other_prime_infos: Option<SequenceOf<OtherPrimeInfo>>,
56}
57
58fn build_external_key_from_primes(
60 public_exponent: &Integer,
61 prime1: &Integer,
62 prime2: &Integer,
63) -> Result<ExternalKey, KeyError> {
64 let e_num = public_exponent
65 .to_bigint()
66 .ok_or(KeyError::InvalidFormat)?
67 .to_biguint()
68 .ok_or(KeyError::InvalidFormat)?;
69 let p_num = prime1
70 .to_bigint()
71 .ok_or(KeyError::InvalidFormat)?
72 .to_biguint()
73 .ok_or(KeyError::InvalidFormat)?;
74 let q_num = prime2
75 .to_bigint()
76 .ok_or(KeyError::InvalidFormat)?
77 .to_biguint()
78 .ok_or(KeyError::InvalidFormat)?;
79
80 if e_num != BigUint::from(65537u32) {
81 return Err(KeyError::ValueConversionFailed(
82 "unsupported RSA exponent: must be 65537".to_string(),
83 ));
84 }
85
86 let e = rsa::BigUint::from_bytes_be(&e_num.to_bytes_be());
87 let p = rsa::BigUint::from_bytes_be(&p_num.to_bytes_be());
88 let q = rsa::BigUint::from_bytes_be(&q_num.to_bytes_be());
89
90 let key = RsaPrivateKey::from_p_q(p, q, e).map_err(|_| KeyError::InvalidFormat)?;
91
92 match key.size() * 8 {
93 2048 => Ok(ExternalKey::Rsa2048(Box::new(key))),
94 3072 => Ok(ExternalKey::Rsa3072(Box::new(key))),
95 4096 => Ok(ExternalKey::Rsa4096(Box::new(key))),
96 bits => Err(KeyError::ValueConversionFailed(format!(
97 "invalid RSA key size: {bits}"
98 ))),
99 }
100}
101
102fn parse_pkcs1_rsa_from_der(der_bytes: &[u8]) -> Result<ExternalKey, KeyError> {
104 if let Ok(pkcs1_key) = rasn::der::decode::<RsaPrivateKeyAsn1>(der_bytes) {
105 let version = pkcs1_key.version.to_u8().ok_or(KeyError::InvalidFormat)?;
106 if version != 0 || pkcs1_key.other_prime_infos.is_some() {
107 return Err(KeyError::UnsupportedFileFormat);
108 }
109 return build_external_key_from_primes(
110 &pkcs1_key.public_exponent,
111 &pkcs1_key.prime1,
112 &pkcs1_key.prime2,
113 );
114 }
115
116 if let Ok(pkcs1_v0_key) = rasn::der::decode::<RsaPrivateKeyPkcs1V0>(der_bytes) {
117 if pkcs1_v0_key.other_prime_infos.is_some() {
118 return Err(KeyError::UnsupportedFileFormat);
119 }
120 return build_external_key_from_primes(
121 &pkcs1_v0_key.public_exponent,
122 &pkcs1_v0_key.prime1,
123 &pkcs1_v0_key.prime2,
124 );
125 }
126
127 Err(KeyError::InvalidFormat)
128}
129
130pub fn parse_rsa_from_der(der_bytes: &[u8]) -> Result<ExternalKey, KeyError> {
136 parse_pkcs1_rsa_from_der(der_bytes)
137}
138
139pub fn rsa_to_public(
146 key: &RsaPrivateKey,
147 key_bits: u16,
148 hash_alg: TpmAlgId,
149 symmetric: TpmtSymDefObject,
150) -> Result<tpm2_protocol::data::TpmtPublic, KeyError> {
151 Ok(tpm2_protocol::data::TpmtPublic {
152 object_type: TpmAlgId::Rsa,
153 name_alg: hash_alg,
154 object_attributes: TpmaObject::USER_WITH_AUTH | TpmaObject::DECRYPT,
155 auth_policy: Tpm2bDigest::default(),
156 parameters: TpmuPublicParms::Rsa(TpmsRsaParms {
157 symmetric,
158 scheme: TpmtRsaScheme {
159 scheme: TpmAlgId::Oaep,
160 details: TpmuAsymScheme::Any(TpmsSchemeHash { hash_alg }),
161 },
162 key_bits,
163 exponent: 0,
164 }),
165 unique: TpmuPublicId::Rsa(
166 Tpm2bPublicKeyRsa::try_from(key.n().to_bytes_be().as_slice())
167 .map_err(|e| KeyError::ValueConversionFailed(e.to_string()))?,
168 ),
169 })
170}