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::InvalidRsaExponent);
82 }
83
84 let e = rsa::BigUint::from_bytes_be(&e_num.to_bytes_be());
85 let p = rsa::BigUint::from_bytes_be(&p_num.to_bytes_be());
86 let q = rsa::BigUint::from_bytes_be(&q_num.to_bytes_be());
87
88 let key = RsaPrivateKey::from_p_q(p, q, e).map_err(|_| KeyError::InvalidFormat)?;
89
90 match key.size() * 8 {
91 2048 => Ok(ExternalKey::Rsa2048(Box::new(key))),
92 3072 => Ok(ExternalKey::Rsa3072(Box::new(key))),
93 4096 => Ok(ExternalKey::Rsa4096(Box::new(key))),
94 _ => Err(KeyError::InvalidRsaExponent),
95 }
96}
97
98fn parse_pkcs1_rsa_from_der(der_bytes: &[u8]) -> Result<ExternalKey, KeyError> {
100 if let Ok(pkcs1_key) = rasn::der::decode::<RsaPrivateKeyAsn1>(der_bytes) {
101 let version = pkcs1_key.version.to_u8().ok_or(KeyError::InvalidFormat)?;
102 if version != 0 || pkcs1_key.other_prime_infos.is_some() {
103 return Err(KeyError::UnsupportedFileFormat);
104 }
105 return build_external_key_from_primes(
106 &pkcs1_key.public_exponent,
107 &pkcs1_key.prime1,
108 &pkcs1_key.prime2,
109 );
110 }
111
112 if let Ok(pkcs1_v0_key) = rasn::der::decode::<RsaPrivateKeyPkcs1V0>(der_bytes) {
113 if pkcs1_v0_key.other_prime_infos.is_some() {
114 return Err(KeyError::UnsupportedFileFormat);
115 }
116 return build_external_key_from_primes(
117 &pkcs1_v0_key.public_exponent,
118 &pkcs1_v0_key.prime1,
119 &pkcs1_v0_key.prime2,
120 );
121 }
122
123 Err(KeyError::InvalidFormat)
124}
125
126pub fn parse_rsa_from_der(der_bytes: &[u8]) -> Result<ExternalKey, KeyError> {
132 parse_pkcs1_rsa_from_der(der_bytes)
133}
134
135pub fn rsa_to_public(
142 key: &RsaPrivateKey,
143 key_bits: u16,
144 hash_alg: TpmAlgId,
145 symmetric: TpmtSymDefObject,
146) -> Result<tpm2_protocol::data::TpmtPublic, KeyError> {
147 Ok(tpm2_protocol::data::TpmtPublic {
148 object_type: TpmAlgId::Rsa,
149 name_alg: hash_alg,
150 object_attributes: TpmaObject::USER_WITH_AUTH | TpmaObject::DECRYPT,
151 auth_policy: Tpm2bDigest::default(),
152 parameters: TpmuPublicParms::Rsa(TpmsRsaParms {
153 symmetric,
154 scheme: TpmtRsaScheme {
155 scheme: TpmAlgId::Oaep,
156 details: TpmuAsymScheme::Any(TpmsSchemeHash { hash_alg }),
157 },
158 key_bits,
159 exponent: 0,
160 }),
161 unique: TpmuPublicId::Rsa(
162 Tpm2bPublicKeyRsa::try_from(key.n().to_bytes_be().as_slice())
163 .map_err(|_| KeyError::InvalidRsaExponent)?,
164 ),
165 })
166}