248 lines
7.6 KiB
Rust
248 lines
7.6 KiB
Rust
|
|
//! PKCS#1 RSA Private Keys.
|
||
|
|
|
||
|
|
#[cfg(feature = "alloc")]
|
||
|
|
pub(crate) mod other_prime_info;
|
||
|
|
|
||
|
|
use crate::{Error, Result, RsaPublicKey, Version};
|
||
|
|
use core::fmt;
|
||
|
|
use der::{
|
||
|
|
asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag,
|
||
|
|
Writer,
|
||
|
|
};
|
||
|
|
|
||
|
|
#[cfg(feature = "alloc")]
|
||
|
|
use {self::other_prime_info::OtherPrimeInfo, alloc::vec::Vec, der::SecretDocument};
|
||
|
|
|
||
|
|
#[cfg(feature = "pem")]
|
||
|
|
use der::pem::PemLabel;
|
||
|
|
|
||
|
|
/// PKCS#1 RSA Private Keys as defined in [RFC 8017 Appendix 1.2].
|
||
|
|
///
|
||
|
|
/// ASN.1 structure containing a serialized RSA private key:
|
||
|
|
///
|
||
|
|
/// ```text
|
||
|
|
/// 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
|
||
|
|
/// }
|
||
|
|
/// ```
|
||
|
|
///
|
||
|
|
/// Note: the `version` field is selected automatically based on the absence or
|
||
|
|
/// presence of the `other_prime_infos` field.
|
||
|
|
///
|
||
|
|
/// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2
|
||
|
|
#[derive(Clone)]
|
||
|
|
pub struct RsaPrivateKey<'a> {
|
||
|
|
/// `n`: RSA modulus.
|
||
|
|
pub modulus: UintRef<'a>,
|
||
|
|
|
||
|
|
/// `e`: RSA public exponent.
|
||
|
|
pub public_exponent: UintRef<'a>,
|
||
|
|
|
||
|
|
/// `d`: RSA private exponent.
|
||
|
|
pub private_exponent: UintRef<'a>,
|
||
|
|
|
||
|
|
/// `p`: first prime factor of `n`.
|
||
|
|
pub prime1: UintRef<'a>,
|
||
|
|
|
||
|
|
/// `q`: Second prime factor of `n`.
|
||
|
|
pub prime2: UintRef<'a>,
|
||
|
|
|
||
|
|
/// First exponent: `d mod (p-1)`.
|
||
|
|
pub exponent1: UintRef<'a>,
|
||
|
|
|
||
|
|
/// Second exponent: `d mod (q-1)`.
|
||
|
|
pub exponent2: UintRef<'a>,
|
||
|
|
|
||
|
|
/// CRT coefficient: `(inverse of q) mod p`.
|
||
|
|
pub coefficient: UintRef<'a>,
|
||
|
|
|
||
|
|
/// Additional primes `r_3`, ..., `r_u`, in order, if this is a multi-prime
|
||
|
|
/// RSA key (i.e. `version` is `multi`).
|
||
|
|
pub other_prime_infos: Option<OtherPrimeInfos<'a>>,
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'a> RsaPrivateKey<'a> {
|
||
|
|
/// Get the public key that corresponds to this [`RsaPrivateKey`].
|
||
|
|
pub fn public_key(&self) -> RsaPublicKey<'a> {
|
||
|
|
RsaPublicKey {
|
||
|
|
modulus: self.modulus,
|
||
|
|
public_exponent: self.public_exponent,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Get the [`Version`] for this key.
|
||
|
|
///
|
||
|
|
/// Determined by the presence or absence of the
|
||
|
|
/// [`RsaPrivateKey::other_prime_infos`] field.
|
||
|
|
pub fn version(&self) -> Version {
|
||
|
|
if self.other_prime_infos.is_some() {
|
||
|
|
Version::Multi
|
||
|
|
} else {
|
||
|
|
Version::TwoPrime
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> {
|
||
|
|
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
|
||
|
|
reader.read_nested(header.length, |reader| {
|
||
|
|
let version = Version::decode(reader)?;
|
||
|
|
|
||
|
|
let result = Self {
|
||
|
|
modulus: reader.decode()?,
|
||
|
|
public_exponent: reader.decode()?,
|
||
|
|
private_exponent: reader.decode()?,
|
||
|
|
prime1: reader.decode()?,
|
||
|
|
prime2: reader.decode()?,
|
||
|
|
exponent1: reader.decode()?,
|
||
|
|
exponent2: reader.decode()?,
|
||
|
|
coefficient: reader.decode()?,
|
||
|
|
other_prime_infos: reader.decode()?,
|
||
|
|
};
|
||
|
|
|
||
|
|
// Ensure version is set correctly for two-prime vs multi-prime key.
|
||
|
|
if version.is_multi() != result.other_prime_infos.is_some() {
|
||
|
|
return Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }));
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok(result)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl EncodeValue for RsaPrivateKey<'_> {
|
||
|
|
fn value_len(&self) -> der::Result<Length> {
|
||
|
|
self.version().encoded_len()?
|
||
|
|
+ self.modulus.encoded_len()?
|
||
|
|
+ self.public_exponent.encoded_len()?
|
||
|
|
+ self.private_exponent.encoded_len()?
|
||
|
|
+ self.prime1.encoded_len()?
|
||
|
|
+ self.prime2.encoded_len()?
|
||
|
|
+ self.exponent1.encoded_len()?
|
||
|
|
+ self.exponent2.encoded_len()?
|
||
|
|
+ self.coefficient.encoded_len()?
|
||
|
|
+ self.other_prime_infos.encoded_len()?
|
||
|
|
}
|
||
|
|
|
||
|
|
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
|
||
|
|
self.version().encode(writer)?;
|
||
|
|
self.modulus.encode(writer)?;
|
||
|
|
self.public_exponent.encode(writer)?;
|
||
|
|
self.private_exponent.encode(writer)?;
|
||
|
|
self.prime1.encode(writer)?;
|
||
|
|
self.prime2.encode(writer)?;
|
||
|
|
self.exponent1.encode(writer)?;
|
||
|
|
self.exponent2.encode(writer)?;
|
||
|
|
self.coefficient.encode(writer)?;
|
||
|
|
self.other_prime_infos.encode(writer)?;
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'a> Sequence<'a> for RsaPrivateKey<'a> {}
|
||
|
|
|
||
|
|
impl<'a> From<RsaPrivateKey<'a>> for RsaPublicKey<'a> {
|
||
|
|
fn from(private_key: RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
|
||
|
|
private_key.public_key()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKey<'a> {
|
||
|
|
fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
|
||
|
|
private_key.public_key()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> {
|
||
|
|
type Error = Error;
|
||
|
|
|
||
|
|
fn try_from(bytes: &'a [u8]) -> Result<Self> {
|
||
|
|
Ok(Self::from_der(bytes)?)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl fmt::Debug for RsaPrivateKey<'_> {
|
||
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
|
f.debug_struct("RsaPrivateKey")
|
||
|
|
.field("version", &self.version())
|
||
|
|
.field("modulus", &self.modulus)
|
||
|
|
.field("public_exponent", &self.public_exponent)
|
||
|
|
.finish_non_exhaustive()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(feature = "alloc")]
|
||
|
|
impl TryFrom<RsaPrivateKey<'_>> for SecretDocument {
|
||
|
|
type Error = Error;
|
||
|
|
|
||
|
|
fn try_from(private_key: RsaPrivateKey<'_>) -> Result<SecretDocument> {
|
||
|
|
SecretDocument::try_from(&private_key)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(feature = "alloc")]
|
||
|
|
impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument {
|
||
|
|
type Error = Error;
|
||
|
|
|
||
|
|
fn try_from(private_key: &RsaPrivateKey<'_>) -> Result<SecretDocument> {
|
||
|
|
Ok(Self::encode_msg(private_key)?)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(feature = "pem")]
|
||
|
|
impl PemLabel for RsaPrivateKey<'_> {
|
||
|
|
const PEM_LABEL: &'static str = "RSA PRIVATE KEY";
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Placeholder struct for `OtherPrimeInfos` in the no-`alloc` case.
|
||
|
|
///
|
||
|
|
/// This type is unconstructable by design, but supports the same traits.
|
||
|
|
#[cfg(not(feature = "alloc"))]
|
||
|
|
#[derive(Clone)]
|
||
|
|
#[non_exhaustive]
|
||
|
|
pub struct OtherPrimeInfos<'a> {
|
||
|
|
_lifetime: core::marker::PhantomData<&'a ()>,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(not(feature = "alloc"))]
|
||
|
|
impl<'a> DecodeValue<'a> for OtherPrimeInfos<'a> {
|
||
|
|
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
|
||
|
|
// Placeholder decoder that always returns an error.
|
||
|
|
// Uses `Tag::Integer` to signal an unsupported version.
|
||
|
|
Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(not(feature = "alloc"))]
|
||
|
|
impl EncodeValue for OtherPrimeInfos<'_> {
|
||
|
|
fn value_len(&self) -> der::Result<Length> {
|
||
|
|
// Placeholder decoder that always returns an error.
|
||
|
|
// Uses `Tag::Integer` to signal an unsupported version.
|
||
|
|
Err(der::ErrorKind::Value { tag: Tag::Integer }.into())
|
||
|
|
}
|
||
|
|
|
||
|
|
fn encode_value(&self, _writer: &mut impl Writer) -> der::Result<()> {
|
||
|
|
// Placeholder decoder that always returns an error.
|
||
|
|
// Uses `Tag::Integer` to signal an unsupported version.
|
||
|
|
Err(der::ErrorKind::Value { tag: Tag::Integer }.into())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(not(feature = "alloc"))]
|
||
|
|
impl<'a> der::FixedTag for OtherPrimeInfos<'a> {
|
||
|
|
const TAG: Tag = Tag::Sequence;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Additional RSA prime info in a multi-prime RSA key.
|
||
|
|
#[cfg(feature = "alloc")]
|
||
|
|
pub type OtherPrimeInfos<'a> = Vec<OtherPrimeInfo<'a>>;
|