1*9860b763SAndroid Build Coastguard Worker // Copyright 2022, The Android Open Source Project
2*9860b763SAndroid Build Coastguard Worker //
3*9860b763SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9860b763SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9860b763SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9860b763SAndroid Build Coastguard Worker //
7*9860b763SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*9860b763SAndroid Build Coastguard Worker //
9*9860b763SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9860b763SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9860b763SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9860b763SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9860b763SAndroid Build Coastguard Worker // limitations under the License.
14*9860b763SAndroid Build Coastguard Worker
15*9860b763SAndroid Build Coastguard Worker //! Functionality related to RSA.
16*9860b763SAndroid Build Coastguard Worker
17*9860b763SAndroid Build Coastguard Worker use super::{KeyMaterial, KeySizeInBits, OpaqueOr, RsaExponent};
18*9860b763SAndroid Build Coastguard Worker use crate::{der_err, km_err, tag, try_to_vec, Error, FallibleAllocExt};
19*9860b763SAndroid Build Coastguard Worker use alloc::vec::Vec;
20*9860b763SAndroid Build Coastguard Worker use der::{asn1::BitStringRef, Decode, Encode};
21*9860b763SAndroid Build Coastguard Worker use kmr_wire::keymint::{Digest, KeyParam, PaddingMode};
22*9860b763SAndroid Build Coastguard Worker use pkcs1::RsaPrivateKey;
23*9860b763SAndroid Build Coastguard Worker use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo, SubjectPublicKeyInfoRef};
24*9860b763SAndroid Build Coastguard Worker use zeroize::ZeroizeOnDrop;
25*9860b763SAndroid Build Coastguard Worker
26*9860b763SAndroid Build Coastguard Worker /// Overhead for PKCS#1 v1.5 signature padding of undigested messages. Digested messages have
27*9860b763SAndroid Build Coastguard Worker /// additional overhead, for the digest algorithmIdentifier required by PKCS#1.
28*9860b763SAndroid Build Coastguard Worker pub const PKCS1_UNDIGESTED_SIGNATURE_PADDING_OVERHEAD: usize = 11;
29*9860b763SAndroid Build Coastguard Worker
30*9860b763SAndroid Build Coastguard Worker /// OID value for PKCS#1-encoded RSA keys held in PKCS#8 and X.509; see RFC 3447 A.1.
31*9860b763SAndroid Build Coastguard Worker pub const X509_OID: pkcs8::ObjectIdentifier =
32*9860b763SAndroid Build Coastguard Worker pkcs8::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1");
33*9860b763SAndroid Build Coastguard Worker
34*9860b763SAndroid Build Coastguard Worker /// OID value for PKCS#1 signature with SHA-256 and RSA, see RFC 4055 s5.
35*9860b763SAndroid Build Coastguard Worker pub const SHA256_PKCS1_SIGNATURE_OID: pkcs8::ObjectIdentifier =
36*9860b763SAndroid Build Coastguard Worker pkcs8::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11");
37*9860b763SAndroid Build Coastguard Worker
38*9860b763SAndroid Build Coastguard Worker /// An RSA key, in the form of an ASN.1 DER encoding of an PKCS#1 `RSAPrivateKey` structure,
39*9860b763SAndroid Build Coastguard Worker /// as specified by RFC 3447 sections A.1.2 and 3.2:
40*9860b763SAndroid Build Coastguard Worker ///
41*9860b763SAndroid Build Coastguard Worker /// ```asn1
42*9860b763SAndroid Build Coastguard Worker /// RSAPrivateKey ::= SEQUENCE {
43*9860b763SAndroid Build Coastguard Worker /// version Version,
44*9860b763SAndroid Build Coastguard Worker /// modulus INTEGER, -- n
45*9860b763SAndroid Build Coastguard Worker /// publicExponent INTEGER, -- e
46*9860b763SAndroid Build Coastguard Worker /// privateExponent INTEGER, -- d
47*9860b763SAndroid Build Coastguard Worker /// prime1 INTEGER, -- p
48*9860b763SAndroid Build Coastguard Worker /// prime2 INTEGER, -- q
49*9860b763SAndroid Build Coastguard Worker /// exponent1 INTEGER, -- d mod (p-1)
50*9860b763SAndroid Build Coastguard Worker /// exponent2 INTEGER, -- d mod (q-1)
51*9860b763SAndroid Build Coastguard Worker /// coefficient INTEGER, -- (inverse of q) mod p
52*9860b763SAndroid Build Coastguard Worker /// otherPrimeInfos OtherPrimeInfos OPTIONAL
53*9860b763SAndroid Build Coastguard Worker /// }
54*9860b763SAndroid Build Coastguard Worker ///
55*9860b763SAndroid Build Coastguard Worker /// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
56*9860b763SAndroid Build Coastguard Worker ///
57*9860b763SAndroid Build Coastguard Worker /// OtherPrimeInfo ::= SEQUENCE {
58*9860b763SAndroid Build Coastguard Worker /// prime INTEGER, -- ri
59*9860b763SAndroid Build Coastguard Worker /// exponent INTEGER, -- di
60*9860b763SAndroid Build Coastguard Worker /// coefficient INTEGER -- ti
61*9860b763SAndroid Build Coastguard Worker /// }
62*9860b763SAndroid Build Coastguard Worker /// ```
63*9860b763SAndroid Build Coastguard Worker #[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)]
64*9860b763SAndroid Build Coastguard Worker pub struct Key(pub Vec<u8>);
65*9860b763SAndroid Build Coastguard Worker
66*9860b763SAndroid Build Coastguard Worker impl Key {
67*9860b763SAndroid Build Coastguard Worker /// Return the `subjectPublicKey` that holds an ASN.1 DER-encoded `SEQUENCE`
68*9860b763SAndroid Build Coastguard Worker /// as per RFC 3279 section 2.3.1:
69*9860b763SAndroid Build Coastguard Worker /// ```asn1
70*9860b763SAndroid Build Coastguard Worker /// RSAPublicKey ::= SEQUENCE {
71*9860b763SAndroid Build Coastguard Worker /// modulus INTEGER, -- n
72*9860b763SAndroid Build Coastguard Worker /// publicExponent INTEGER } -- e
73*9860b763SAndroid Build Coastguard Worker /// ```
subject_public_key(&self) -> Result<Vec<u8>, Error>74*9860b763SAndroid Build Coastguard Worker pub fn subject_public_key(&self) -> Result<Vec<u8>, Error> {
75*9860b763SAndroid Build Coastguard Worker let rsa_pvt_key = RsaPrivateKey::from_der(self.0.as_slice())
76*9860b763SAndroid Build Coastguard Worker .map_err(|e| der_err!(e, "failed to parse RsaPrivateKey"))?;
77*9860b763SAndroid Build Coastguard Worker
78*9860b763SAndroid Build Coastguard Worker let rsa_pub_key = rsa_pvt_key.public_key();
79*9860b763SAndroid Build Coastguard Worker let mut encoded_data = Vec::<u8>::new();
80*9860b763SAndroid Build Coastguard Worker rsa_pub_key
81*9860b763SAndroid Build Coastguard Worker .encode_to_vec(&mut encoded_data)
82*9860b763SAndroid Build Coastguard Worker .map_err(|e| der_err!(e, "failed to encode RSA PublicKey"))?;
83*9860b763SAndroid Build Coastguard Worker Ok(encoded_data)
84*9860b763SAndroid Build Coastguard Worker }
85*9860b763SAndroid Build Coastguard Worker
86*9860b763SAndroid Build Coastguard Worker /// Size of the key in bytes.
size(&self) -> usize87*9860b763SAndroid Build Coastguard Worker pub fn size(&self) -> usize {
88*9860b763SAndroid Build Coastguard Worker let rsa_pvt_key = match RsaPrivateKey::from_der(self.0.as_slice()) {
89*9860b763SAndroid Build Coastguard Worker Ok(k) => k,
90*9860b763SAndroid Build Coastguard Worker Err(e) => {
91*9860b763SAndroid Build Coastguard Worker log::error!("failed to determine RSA key length: {:?}", e);
92*9860b763SAndroid Build Coastguard Worker return 0;
93*9860b763SAndroid Build Coastguard Worker }
94*9860b763SAndroid Build Coastguard Worker };
95*9860b763SAndroid Build Coastguard Worker let len = u32::from(rsa_pvt_key.modulus.len());
96*9860b763SAndroid Build Coastguard Worker len as usize
97*9860b763SAndroid Build Coastguard Worker }
98*9860b763SAndroid Build Coastguard Worker }
99*9860b763SAndroid Build Coastguard Worker
100*9860b763SAndroid Build Coastguard Worker impl OpaqueOr<Key> {
101*9860b763SAndroid Build Coastguard Worker /// Encode into `buf` the public key information as an ASN.1 DER encodable
102*9860b763SAndroid Build Coastguard Worker /// `SubjectPublicKeyInfo`, as described in RFC 5280 section 4.1.
103*9860b763SAndroid Build Coastguard Worker ///
104*9860b763SAndroid Build Coastguard Worker /// ```asn1
105*9860b763SAndroid Build Coastguard Worker /// SubjectPublicKeyInfo ::= SEQUENCE {
106*9860b763SAndroid Build Coastguard Worker /// algorithm AlgorithmIdentifier,
107*9860b763SAndroid Build Coastguard Worker /// subjectPublicKey BIT STRING }
108*9860b763SAndroid Build Coastguard Worker ///
109*9860b763SAndroid Build Coastguard Worker /// AlgorithmIdentifier ::= SEQUENCE {
110*9860b763SAndroid Build Coastguard Worker /// algorithm OBJECT IDENTIFIER,
111*9860b763SAndroid Build Coastguard Worker /// parameters ANY DEFINED BY algorithm OPTIONAL }
112*9860b763SAndroid Build Coastguard Worker /// ```
113*9860b763SAndroid Build Coastguard Worker ///
114*9860b763SAndroid Build Coastguard Worker /// For RSA keys, the contents are described in RFC 3279 section 2.3.1.
115*9860b763SAndroid Build Coastguard Worker ///
116*9860b763SAndroid Build Coastguard Worker /// - The `AlgorithmIdentifier` has an algorithm OID of 1.2.840.113549.1.1.1.
117*9860b763SAndroid Build Coastguard Worker /// - The `AlgorithmIdentifier` has `NULL` parameters.
118*9860b763SAndroid Build Coastguard Worker /// - The `subjectPublicKey` bit string holds an ASN.1 DER-encoded `SEQUENCE`:
119*9860b763SAndroid Build Coastguard Worker /// ```asn1
120*9860b763SAndroid Build Coastguard Worker /// RSAPublicKey ::= SEQUENCE {
121*9860b763SAndroid Build Coastguard Worker /// modulus INTEGER, -- n
122*9860b763SAndroid Build Coastguard Worker /// publicExponent INTEGER } -- e
123*9860b763SAndroid Build Coastguard Worker /// ```
subject_public_key_info<'a>( &'a self, buf: &'a mut Vec<u8>, rsa: &dyn super::Rsa, ) -> Result<SubjectPublicKeyInfoRef<'a>, Error>124*9860b763SAndroid Build Coastguard Worker pub fn subject_public_key_info<'a>(
125*9860b763SAndroid Build Coastguard Worker &'a self,
126*9860b763SAndroid Build Coastguard Worker buf: &'a mut Vec<u8>,
127*9860b763SAndroid Build Coastguard Worker rsa: &dyn super::Rsa,
128*9860b763SAndroid Build Coastguard Worker ) -> Result<SubjectPublicKeyInfoRef<'a>, Error> {
129*9860b763SAndroid Build Coastguard Worker let pub_key = rsa.subject_public_key(self)?;
130*9860b763SAndroid Build Coastguard Worker buf.try_extend_from_slice(&pub_key)?;
131*9860b763SAndroid Build Coastguard Worker Ok(SubjectPublicKeyInfo {
132*9860b763SAndroid Build Coastguard Worker algorithm: AlgorithmIdentifier { oid: X509_OID, parameters: Some(der::AnyRef::NULL) },
133*9860b763SAndroid Build Coastguard Worker subject_public_key: BitStringRef::from_bytes(buf)
134*9860b763SAndroid Build Coastguard Worker .map_err(|e| km_err!(UnknownError, "invalid bitstring: {e:?}"))?,
135*9860b763SAndroid Build Coastguard Worker })
136*9860b763SAndroid Build Coastguard Worker }
137*9860b763SAndroid Build Coastguard Worker }
138*9860b763SAndroid Build Coastguard Worker
139*9860b763SAndroid Build Coastguard Worker /// RSA decryption mode.
140*9860b763SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)]
141*9860b763SAndroid Build Coastguard Worker pub enum DecryptionMode {
142*9860b763SAndroid Build Coastguard Worker /// No padding.
143*9860b763SAndroid Build Coastguard Worker NoPadding,
144*9860b763SAndroid Build Coastguard Worker /// RSA-OAEP padding.
145*9860b763SAndroid Build Coastguard Worker OaepPadding {
146*9860b763SAndroid Build Coastguard Worker /// Digest to use for the message
147*9860b763SAndroid Build Coastguard Worker msg_digest: Digest,
148*9860b763SAndroid Build Coastguard Worker /// Digest to use in the MGF1 function.
149*9860b763SAndroid Build Coastguard Worker mgf_digest: Digest,
150*9860b763SAndroid Build Coastguard Worker },
151*9860b763SAndroid Build Coastguard Worker /// PKCS#1 v1.5 padding.
152*9860b763SAndroid Build Coastguard Worker Pkcs1_1_5Padding,
153*9860b763SAndroid Build Coastguard Worker }
154*9860b763SAndroid Build Coastguard Worker
155*9860b763SAndroid Build Coastguard Worker impl DecryptionMode {
156*9860b763SAndroid Build Coastguard Worker /// Determine the [`DecryptionMode`] from parameters.
new(params: &[KeyParam]) -> Result<Self, Error>157*9860b763SAndroid Build Coastguard Worker pub fn new(params: &[KeyParam]) -> Result<Self, Error> {
158*9860b763SAndroid Build Coastguard Worker let padding = tag::get_padding_mode(params)?;
159*9860b763SAndroid Build Coastguard Worker match padding {
160*9860b763SAndroid Build Coastguard Worker PaddingMode::None => Ok(DecryptionMode::NoPadding),
161*9860b763SAndroid Build Coastguard Worker PaddingMode::RsaOaep => {
162*9860b763SAndroid Build Coastguard Worker let msg_digest = tag::get_digest(params)?;
163*9860b763SAndroid Build Coastguard Worker let mgf_digest = tag::get_mgf_digest(params)?;
164*9860b763SAndroid Build Coastguard Worker Ok(DecryptionMode::OaepPadding { msg_digest, mgf_digest })
165*9860b763SAndroid Build Coastguard Worker }
166*9860b763SAndroid Build Coastguard Worker PaddingMode::RsaPkcs115Encrypt => Ok(DecryptionMode::Pkcs1_1_5Padding),
167*9860b763SAndroid Build Coastguard Worker _ => Err(km_err!(
168*9860b763SAndroid Build Coastguard Worker UnsupportedPaddingMode,
169*9860b763SAndroid Build Coastguard Worker "padding mode {:?} not supported for RSA decryption",
170*9860b763SAndroid Build Coastguard Worker padding
171*9860b763SAndroid Build Coastguard Worker )),
172*9860b763SAndroid Build Coastguard Worker }
173*9860b763SAndroid Build Coastguard Worker }
174*9860b763SAndroid Build Coastguard Worker }
175*9860b763SAndroid Build Coastguard Worker
176*9860b763SAndroid Build Coastguard Worker /// RSA signature mode.
177*9860b763SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq)]
178*9860b763SAndroid Build Coastguard Worker pub enum SignMode {
179*9860b763SAndroid Build Coastguard Worker /// No padding.
180*9860b763SAndroid Build Coastguard Worker NoPadding,
181*9860b763SAndroid Build Coastguard Worker /// RSA-PSS signature scheme using the given digest.
182*9860b763SAndroid Build Coastguard Worker PssPadding(Digest),
183*9860b763SAndroid Build Coastguard Worker /// PKCS#1 v1.5 padding using the given digest.
184*9860b763SAndroid Build Coastguard Worker Pkcs1_1_5Padding(Digest),
185*9860b763SAndroid Build Coastguard Worker }
186*9860b763SAndroid Build Coastguard Worker
187*9860b763SAndroid Build Coastguard Worker impl SignMode {
188*9860b763SAndroid Build Coastguard Worker /// Determine the [`SignMode`] from parameters.
new(params: &[KeyParam]) -> Result<Self, Error>189*9860b763SAndroid Build Coastguard Worker pub fn new(params: &[KeyParam]) -> Result<Self, Error> {
190*9860b763SAndroid Build Coastguard Worker let padding = tag::get_padding_mode(params)?;
191*9860b763SAndroid Build Coastguard Worker match padding {
192*9860b763SAndroid Build Coastguard Worker PaddingMode::None => Ok(SignMode::NoPadding),
193*9860b763SAndroid Build Coastguard Worker PaddingMode::RsaPss => {
194*9860b763SAndroid Build Coastguard Worker let digest = tag::get_digest(params)?;
195*9860b763SAndroid Build Coastguard Worker Ok(SignMode::PssPadding(digest))
196*9860b763SAndroid Build Coastguard Worker }
197*9860b763SAndroid Build Coastguard Worker PaddingMode::RsaPkcs115Sign => {
198*9860b763SAndroid Build Coastguard Worker let digest = tag::get_digest(params)?;
199*9860b763SAndroid Build Coastguard Worker Ok(SignMode::Pkcs1_1_5Padding(digest))
200*9860b763SAndroid Build Coastguard Worker }
201*9860b763SAndroid Build Coastguard Worker _ => Err(km_err!(
202*9860b763SAndroid Build Coastguard Worker UnsupportedPaddingMode,
203*9860b763SAndroid Build Coastguard Worker "padding mode {:?} not supported for RSA signing",
204*9860b763SAndroid Build Coastguard Worker padding
205*9860b763SAndroid Build Coastguard Worker )),
206*9860b763SAndroid Build Coastguard Worker }
207*9860b763SAndroid Build Coastguard Worker }
208*9860b763SAndroid Build Coastguard Worker }
209*9860b763SAndroid Build Coastguard Worker
210*9860b763SAndroid Build Coastguard Worker /// Import an RSA key in PKCS#8 format, also returning the key size in bits and public exponent.
import_pkcs8_key(data: &[u8]) -> Result<(KeyMaterial, KeySizeInBits, RsaExponent), Error>211*9860b763SAndroid Build Coastguard Worker pub fn import_pkcs8_key(data: &[u8]) -> Result<(KeyMaterial, KeySizeInBits, RsaExponent), Error> {
212*9860b763SAndroid Build Coastguard Worker let key_info = pkcs8::PrivateKeyInfo::try_from(data)
213*9860b763SAndroid Build Coastguard Worker .map_err(|_| km_err!(InvalidArgument, "failed to parse PKCS#8 RSA key"))?;
214*9860b763SAndroid Build Coastguard Worker if key_info.algorithm.oid != X509_OID {
215*9860b763SAndroid Build Coastguard Worker return Err(km_err!(
216*9860b763SAndroid Build Coastguard Worker InvalidArgument,
217*9860b763SAndroid Build Coastguard Worker "unexpected OID {:?} for PKCS#1 RSA key import",
218*9860b763SAndroid Build Coastguard Worker key_info.algorithm.oid
219*9860b763SAndroid Build Coastguard Worker ));
220*9860b763SAndroid Build Coastguard Worker }
221*9860b763SAndroid Build Coastguard Worker // For RSA, the inner private key is an ASN.1 `RSAPrivateKey`, as per PKCS#1 (RFC 3447 A.1.2).
222*9860b763SAndroid Build Coastguard Worker import_pkcs1_key(key_info.private_key)
223*9860b763SAndroid Build Coastguard Worker }
224*9860b763SAndroid Build Coastguard Worker
225*9860b763SAndroid Build Coastguard Worker /// Import an RSA key in PKCS#1 format, also returning the key size in bits and public exponent.
import_pkcs1_key( private_key: &[u8], ) -> Result<(KeyMaterial, KeySizeInBits, RsaExponent), Error>226*9860b763SAndroid Build Coastguard Worker pub fn import_pkcs1_key(
227*9860b763SAndroid Build Coastguard Worker private_key: &[u8],
228*9860b763SAndroid Build Coastguard Worker ) -> Result<(KeyMaterial, KeySizeInBits, RsaExponent), Error> {
229*9860b763SAndroid Build Coastguard Worker let key = Key(try_to_vec(private_key)?);
230*9860b763SAndroid Build Coastguard Worker
231*9860b763SAndroid Build Coastguard Worker // Need to parse it to find size/exponent.
232*9860b763SAndroid Build Coastguard Worker let parsed_key = pkcs1::RsaPrivateKey::try_from(private_key)
233*9860b763SAndroid Build Coastguard Worker .map_err(|_| km_err!(InvalidArgument, "failed to parse inner PKCS#1 key"))?;
234*9860b763SAndroid Build Coastguard Worker let key_size = parsed_key.modulus.as_bytes().len() as u32 * 8;
235*9860b763SAndroid Build Coastguard Worker
236*9860b763SAndroid Build Coastguard Worker let pub_exponent_bytes = parsed_key.public_exponent.as_bytes();
237*9860b763SAndroid Build Coastguard Worker if pub_exponent_bytes.len() > 8 {
238*9860b763SAndroid Build Coastguard Worker return Err(km_err!(
239*9860b763SAndroid Build Coastguard Worker InvalidArgument,
240*9860b763SAndroid Build Coastguard Worker "public exponent of length {} too big",
241*9860b763SAndroid Build Coastguard Worker pub_exponent_bytes.len()
242*9860b763SAndroid Build Coastguard Worker ));
243*9860b763SAndroid Build Coastguard Worker }
244*9860b763SAndroid Build Coastguard Worker let offset = 8 - pub_exponent_bytes.len();
245*9860b763SAndroid Build Coastguard Worker let mut pub_exponent_arr = [0u8; 8];
246*9860b763SAndroid Build Coastguard Worker pub_exponent_arr[offset..].copy_from_slice(pub_exponent_bytes);
247*9860b763SAndroid Build Coastguard Worker let pub_exponent = u64::from_be_bytes(pub_exponent_arr);
248*9860b763SAndroid Build Coastguard Worker
249*9860b763SAndroid Build Coastguard Worker Ok((KeyMaterial::Rsa(key.into()), KeySizeInBits(key_size), RsaExponent(pub_exponent)))
250*9860b763SAndroid Build Coastguard Worker }
251