blob: 4f96959e3a0115d64f56cad93119140b94a73bc7 [file] [log] [blame]
//! Functionality related to RSA.
use super::{KeyMaterial, KeySizeInBits, OpaqueOr, RsaExponent};
use crate::{der_err, km_err, tag, try_to_vec, Error, FallibleAllocExt};
use alloc::vec::Vec;
use der::{Decode, Encode};
use kmr_wire::keymint::{Digest, KeyParam, PaddingMode};
use pkcs1::RsaPrivateKey;
use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo};
use zeroize::ZeroizeOnDrop;
/// Overhead for PKCS#1 v1.5 signature padding of undigested messages. Digested messages have
/// additional overhead, for the digest algorithmIdentifier required by PKCS#1.
pub const PKCS1_UNDIGESTED_SIGNATURE_PADDING_OVERHEAD: usize = 11;
/// OID value for PKCS#1-encoded RSA keys held in PKCS#8 and X.509; see RFC 3447 A.1.
pub const X509_OID: pkcs8::ObjectIdentifier =
pkcs8::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1");
/// OID value for PKCS#1 signature with SHA-256 and RSA, see RFC 4055 s5.
pub const SHA256_PKCS1_SIGNATURE_OID: pkcs8::ObjectIdentifier =
pkcs8::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11");
/// An RSA key, in the form of an ASN.1 DER encoding of an PKCS#1 `RSAPrivateKey` structure,
/// as specified by RFC 3447 sections A.1.2 and 3.2:
///
/// ```asn1
/// RSAPrivateKey ::= SEQUENCE {
/// version Version,
/// modulus INTEGER, -- n
/// publicExponent INTEGER, -- e
/// privateExponent INTEGER, -- d
/// prime1 INTEGER, -- p
/// prime2 INTEGER, -- q
/// exponent1 INTEGER, -- d mod (p-1)
/// exponent2 INTEGER, -- d mod (q-1)
/// coefficient INTEGER, -- (inverse of q) mod p
/// otherPrimeInfos OtherPrimeInfos OPTIONAL
/// }
///
/// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
///
/// OtherPrimeInfo ::= SEQUENCE {
/// prime INTEGER, -- ri
/// exponent INTEGER, -- di
/// coefficient INTEGER -- ti
/// }
/// ```
#[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)]
pub struct Key(pub Vec<u8>);
impl Key {
/// Return the `subjectPublicKey` that holds an ASN.1 DER-encoded `SEQUENCE`
/// as per RFC 3279 section 2.3.1:
/// ```asn1
/// RSAPublicKey ::= SEQUENCE {
/// modulus INTEGER, -- n
/// publicExponent INTEGER } -- e
/// ```
pub fn subject_public_key(&self) -> Result<Vec<u8>, Error> {
let rsa_pvt_key = RsaPrivateKey::from_der(self.0.as_slice())
.map_err(|e| der_err!(e, "failed to parse RsaPrivateKey"))?;
let rsa_pub_key = rsa_pvt_key.public_key();
let mut encoded_data = Vec::<u8>::new();
rsa_pub_key
.encode_to_vec(&mut encoded_data)
.map_err(|e| der_err!(e, "failed to encode RSA PublicKey"))?;
Ok(encoded_data)
}
/// Size of the key in bytes.
pub fn size(&self) -> usize {
let rsa_pvt_key = match RsaPrivateKey::from_der(self.0.as_slice()) {
Ok(k) => k,
Err(e) => {
log::error!("failed to determine RSA key length: {:?}", e);
return 0;
}
};
let len = u32::from(rsa_pvt_key.modulus.len());
len as usize
}
}
impl OpaqueOr<Key> {
/// Encode into `buf` the public key information as an ASN.1 DER encodable
/// `SubjectPublicKeyInfo`, as described in RFC 5280 section 4.1.
///
/// ```asn1
/// SubjectPublicKeyInfo ::= SEQUENCE {
/// algorithm AlgorithmIdentifier,
/// subjectPublicKey BIT STRING }
///
/// AlgorithmIdentifier ::= SEQUENCE {
/// algorithm OBJECT IDENTIFIER,
/// parameters ANY DEFINED BY algorithm OPTIONAL }
/// ```
///
/// For RSA keys, the contents are described in RFC 3279 section 2.3.1.
///
/// - The `AlgorithmIdentifier` has an algorithm OID of 1.2.840.113549.1.1.1.
/// - The `AlgorithmIdentifier` has `NULL` parameters.
/// - The `subjectPublicKey` bit string holds an ASN.1 DER-encoded `SEQUENCE`:
/// ```asn1
/// RSAPublicKey ::= SEQUENCE {
/// modulus INTEGER, -- n
/// publicExponent INTEGER } -- e
/// ```
pub fn subject_public_key_info<'a>(
&'a self,
buf: &'a mut Vec<u8>,
rsa: &dyn super::Rsa,
) -> Result<SubjectPublicKeyInfo<'a>, Error> {
let pub_key = rsa.subject_public_key(self)?;
buf.try_extend_from_slice(&pub_key)?;
Ok(SubjectPublicKeyInfo {
algorithm: AlgorithmIdentifier { oid: X509_OID, parameters: Some(der::AnyRef::NULL) },
subject_public_key: buf,
})
}
}
/// RSA decryption mode.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DecryptionMode {
/// No padding.
NoPadding,
/// RSA-OAEP padding.
OaepPadding {
/// Digest to use for the message
msg_digest: Digest,
/// Digest to use in the MGF1 function.
mgf_digest: Digest,
},
/// PKCS#1 v1.5 padding.
Pkcs1_1_5Padding,
}
impl DecryptionMode {
/// Determine the [`DecryptionMode`] from parameters.
pub fn new(params: &[KeyParam]) -> Result<Self, Error> {
let padding = tag::get_padding_mode(params)?;
match padding {
PaddingMode::None => Ok(DecryptionMode::NoPadding),
PaddingMode::RsaOaep => {
let msg_digest = tag::get_digest(params)?;
let mgf_digest = tag::get_mgf_digest(params)?;
Ok(DecryptionMode::OaepPadding { msg_digest, mgf_digest })
}
PaddingMode::RsaPkcs115Encrypt => Ok(DecryptionMode::Pkcs1_1_5Padding),
_ => Err(km_err!(
UnsupportedPaddingMode,
"padding mode {:?} not supported for RSA decryption",
padding
)),
}
}
}
/// RSA signature mode.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SignMode {
/// No padding.
NoPadding,
/// RSA-PSS signature scheme using the given digest.
PssPadding(Digest),
/// PKCS#1 v1.5 padding using the given digest.
Pkcs1_1_5Padding(Digest),
}
impl SignMode {
/// Determine the [`SignMode`] from parameters.
pub fn new(params: &[KeyParam]) -> Result<Self, Error> {
let padding = tag::get_padding_mode(params)?;
match padding {
PaddingMode::None => Ok(SignMode::NoPadding),
PaddingMode::RsaPss => {
let digest = tag::get_digest(params)?;
Ok(SignMode::PssPadding(digest))
}
PaddingMode::RsaPkcs115Sign => {
let digest = tag::get_digest(params)?;
Ok(SignMode::Pkcs1_1_5Padding(digest))
}
_ => Err(km_err!(
UnsupportedPaddingMode,
"padding mode {:?} not supported for RSA signing",
padding
)),
}
}
}
/// Import an RSA key in PKCS#8 format, also returning the key size in bits and public exponent.
pub fn import_pkcs8_key(data: &[u8]) -> Result<(KeyMaterial, KeySizeInBits, RsaExponent), Error> {
let key_info = pkcs8::PrivateKeyInfo::try_from(data)
.map_err(|_| km_err!(InvalidArgument, "failed to parse PKCS#8 RSA key"))?;
if key_info.algorithm.oid != X509_OID {
return Err(km_err!(
InvalidArgument,
"unexpected OID {:?} for PKCS#1 RSA key import",
key_info.algorithm.oid
));
}
// For RSA, the inner private key is an ASN.1 `RSAPrivateKey`, as per PKCS#1 (RFC 3447 A.1.2).
import_pkcs1_key(key_info.private_key)
}
/// Import an RSA key in PKCS#1 format, also returning the key size in bits and public exponent.
pub fn import_pkcs1_key(
private_key: &[u8],
) -> Result<(KeyMaterial, KeySizeInBits, RsaExponent), Error> {
let key = Key(try_to_vec(private_key)?);
// Need to parse it to find size/exponent.
let parsed_key = pkcs1::RsaPrivateKey::try_from(private_key)
.map_err(|_| km_err!(InvalidArgument, "failed to parse inner PKCS#1 key"))?;
let key_size = parsed_key.modulus.as_bytes().len() as u32 * 8;
let pub_exponent_bytes = parsed_key.public_exponent.as_bytes();
if pub_exponent_bytes.len() > 8 {
return Err(km_err!(
InvalidArgument,
"public exponent of length {} too big",
pub_exponent_bytes.len()
));
}
let offset = 8 - pub_exponent_bytes.len();
let mut pub_exponent_arr = [0u8; 8];
pub_exponent_arr[offset..].copy_from_slice(pub_exponent_bytes);
let pub_exponent = u64::from_be_bytes(pub_exponent_arr);
Ok((KeyMaterial::Rsa(key.into()), KeySizeInBits(key_size), RsaExponent(pub_exponent)))
}