pkcs1/
private_key.rs

1//! PKCS#1 RSA Private Keys.
2
3#[cfg(feature = "alloc")]
4pub(crate) mod other_prime_info;
5
6use crate::{Error, Result, RsaPublicKey, Version};
7use core::fmt;
8use der::{asn1::UIntRef, Decode, DecodeValue, Encode, Header, Reader, Sequence, Tag};
9
10#[cfg(feature = "alloc")]
11use {self::other_prime_info::OtherPrimeInfo, alloc::vec::Vec, der::SecretDocument};
12
13#[cfg(feature = "pem")]
14use der::pem::PemLabel;
15
16/// PKCS#1 RSA Private Keys as defined in [RFC 8017 Appendix 1.2].
17///
18/// ASN.1 structure containing a serialized RSA private key:
19///
20/// ```text
21/// RSAPrivateKey ::= SEQUENCE {
22///     version           Version,
23///     modulus           INTEGER,  -- n
24///     publicExponent    INTEGER,  -- e
25///     privateExponent   INTEGER,  -- d
26///     prime1            INTEGER,  -- p
27///     prime2            INTEGER,  -- q
28///     exponent1         INTEGER,  -- d mod (p-1)
29///     exponent2         INTEGER,  -- d mod (q-1)
30///     coefficient       INTEGER,  -- (inverse of q) mod p
31///     otherPrimeInfos   OtherPrimeInfos OPTIONAL
32/// }
33/// ```
34///
35/// Note: the `version` field is selected automatically based on the absence or
36/// presence of the `other_prime_infos` field.
37///
38/// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2
39#[derive(Clone)]
40pub struct RsaPrivateKey<'a> {
41    /// `n`: RSA modulus.
42    pub modulus: UIntRef<'a>,
43
44    /// `e`: RSA public exponent.
45    pub public_exponent: UIntRef<'a>,
46
47    /// `d`: RSA private exponent.
48    pub private_exponent: UIntRef<'a>,
49
50    /// `p`: first prime factor of `n`.
51    pub prime1: UIntRef<'a>,
52
53    /// `q`: Second prime factor of `n`.
54    pub prime2: UIntRef<'a>,
55
56    /// First exponent: `d mod (p-1)`.
57    pub exponent1: UIntRef<'a>,
58
59    /// Second exponent: `d mod (q-1)`.
60    pub exponent2: UIntRef<'a>,
61
62    /// CRT coefficient: `(inverse of q) mod p`.
63    pub coefficient: UIntRef<'a>,
64
65    /// Additional primes `r_3`, ..., `r_u`, in order, if this is a multi-prime
66    /// RSA key (i.e. `version` is `multi`).
67    pub other_prime_infos: Option<OtherPrimeInfos<'a>>,
68}
69
70impl<'a> RsaPrivateKey<'a> {
71    /// Get the public key that corresponds to this [`RsaPrivateKey`].
72    pub fn public_key(&self) -> RsaPublicKey<'a> {
73        RsaPublicKey {
74            modulus: self.modulus,
75            public_exponent: self.public_exponent,
76        }
77    }
78
79    /// Get the [`Version`] for this key.
80    ///
81    /// Determined by the presence or absence of the
82    /// [`RsaPrivateKey::other_prime_infos`] field.
83    pub fn version(&self) -> Version {
84        if self.other_prime_infos.is_some() {
85            Version::Multi
86        } else {
87            Version::TwoPrime
88        }
89    }
90}
91
92impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> {
93    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
94        reader.read_nested(header.length, |reader| {
95            let version = Version::decode(reader)?;
96
97            let result = Self {
98                modulus: reader.decode()?,
99                public_exponent: reader.decode()?,
100                private_exponent: reader.decode()?,
101                prime1: reader.decode()?,
102                prime2: reader.decode()?,
103                exponent1: reader.decode()?,
104                exponent2: reader.decode()?,
105                coefficient: reader.decode()?,
106                other_prime_infos: reader.decode()?,
107            };
108
109            // Ensure version is set correctly for two-prime vs multi-prime key.
110            if version.is_multi() != result.other_prime_infos.is_some() {
111                return Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }));
112            }
113
114            Ok(result)
115        })
116    }
117}
118
119impl<'a> Sequence<'a> for RsaPrivateKey<'a> {
120    fn fields<F, T>(&self, f: F) -> der::Result<T>
121    where
122        F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
123    {
124        f(&[
125            &self.version(),
126            &self.modulus,
127            &self.public_exponent,
128            &self.private_exponent,
129            &self.prime1,
130            &self.prime2,
131            &self.exponent1,
132            &self.exponent2,
133            &self.coefficient,
134            #[cfg(feature = "alloc")]
135            &self.other_prime_infos,
136        ])
137    }
138}
139
140impl<'a> From<RsaPrivateKey<'a>> for RsaPublicKey<'a> {
141    fn from(private_key: RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
142        private_key.public_key()
143    }
144}
145
146impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKey<'a> {
147    fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
148        private_key.public_key()
149    }
150}
151
152impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> {
153    type Error = Error;
154
155    fn try_from(bytes: &'a [u8]) -> Result<Self> {
156        Ok(Self::from_der(bytes)?)
157    }
158}
159
160impl fmt::Debug for RsaPrivateKey<'_> {
161    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162        f.debug_struct("RsaPrivateKey")
163            .field("version", &self.version())
164            .field("modulus", &self.modulus)
165            .field("public_exponent", &self.public_exponent)
166            .finish_non_exhaustive()
167    }
168}
169
170#[cfg(feature = "alloc")]
171#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
172impl TryFrom<RsaPrivateKey<'_>> for SecretDocument {
173    type Error = Error;
174
175    fn try_from(private_key: RsaPrivateKey<'_>) -> Result<SecretDocument> {
176        SecretDocument::try_from(&private_key)
177    }
178}
179
180#[cfg(feature = "alloc")]
181#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
182impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument {
183    type Error = Error;
184
185    fn try_from(private_key: &RsaPrivateKey<'_>) -> Result<SecretDocument> {
186        Ok(Self::encode_msg(private_key)?)
187    }
188}
189
190#[cfg(feature = "pem")]
191#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
192impl PemLabel for RsaPrivateKey<'_> {
193    const PEM_LABEL: &'static str = "RSA PRIVATE KEY";
194}
195
196/// Placeholder struct for `OtherPrimeInfos` in the no-`alloc` case.
197#[cfg(not(feature = "alloc"))]
198#[derive(Clone)]
199#[non_exhaustive]
200pub struct OtherPrimeInfos<'a> {
201    _lifetime: core::marker::PhantomData<&'a ()>,
202}
203
204#[cfg(not(feature = "alloc"))]
205impl<'a> Decode<'a> for OtherPrimeInfos<'a> {
206    fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> {
207        // Placeholder decoder that always returns an error.
208        // Use `Tag::Integer` to signal an unsupported version.
209        Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }))
210    }
211}
212
213#[cfg(not(feature = "alloc"))]
214impl<'a> der::FixedTag for OtherPrimeInfos<'a> {
215    const TAG: Tag = Tag::Sequence;
216}
217
218/// Additional RSA prime info in a multi-prime RSA key.
219#[cfg(feature = "alloc")]
220pub type OtherPrimeInfos<'a> = Vec<OtherPrimeInfo<'a>>;