1 //! Traits for parsing objects from PKCS#1 encoded documents
2 
3 use crate::Result;
4 
5 #[cfg(feature = "alloc")]
6 use der::{Document, SecretDocument};
7 
8 #[cfg(feature = "pem")]
9 use {
10     crate::LineEnding,
11     alloc::string::String,
12     der::{pem::PemLabel, zeroize::Zeroizing},
13 };
14 
15 #[cfg(feature = "pkcs8")]
16 use {
17     crate::{ALGORITHM_ID, ALGORITHM_OID},
18     der::asn1::BitStringRef,
19 };
20 
21 #[cfg(feature = "std")]
22 use std::path::Path;
23 
24 #[cfg(all(feature = "alloc", feature = "pkcs8"))]
25 use der::Decode;
26 
27 #[cfg(all(feature = "alloc", any(feature = "pem", feature = "pkcs8")))]
28 use crate::{RsaPrivateKey, RsaPublicKey};
29 
30 /// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document.
31 pub trait DecodeRsaPrivateKey: Sized {
32     /// Deserialize PKCS#1 private key from ASN.1 DER-encoded data
33     /// (binary format).
from_pkcs1_der(bytes: &[u8]) -> Result<Self>34     fn from_pkcs1_der(bytes: &[u8]) -> Result<Self>;
35 
36     /// Deserialize PKCS#1-encoded private key from PEM.
37     ///
38     /// Keys in this format begin with the following:
39     ///
40     /// ```text
41     /// -----BEGIN RSA PRIVATE KEY-----
42     /// ```
43     #[cfg(feature = "pem")]
from_pkcs1_pem(s: &str) -> Result<Self>44     fn from_pkcs1_pem(s: &str) -> Result<Self> {
45         let (label, doc) = SecretDocument::from_pem(s)?;
46         RsaPrivateKey::validate_pem_label(label)?;
47         Self::from_pkcs1_der(doc.as_bytes())
48     }
49 
50     /// Load PKCS#1 private key from an ASN.1 DER-encoded file on the local
51     /// filesystem (binary format).
52     #[cfg(feature = "std")]
read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self>53     fn read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self> {
54         Self::from_pkcs1_der(SecretDocument::read_der_file(path)?.as_bytes())
55     }
56 
57     /// Load PKCS#1 private key from a PEM-encoded file on the local filesystem.
58     #[cfg(all(feature = "pem", feature = "std"))]
read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self>59     fn read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
60         let (label, doc) = SecretDocument::read_pem_file(path)?;
61         RsaPrivateKey::validate_pem_label(&label)?;
62         Self::from_pkcs1_der(doc.as_bytes())
63     }
64 }
65 
66 /// Parse a [`RsaPublicKey`] from a PKCS#1-encoded document.
67 pub trait DecodeRsaPublicKey: Sized {
68     /// Deserialize object from ASN.1 DER-encoded [`RsaPublicKey`]
69     /// (binary format).
from_pkcs1_der(bytes: &[u8]) -> Result<Self>70     fn from_pkcs1_der(bytes: &[u8]) -> Result<Self>;
71 
72     /// Deserialize PEM-encoded [`RsaPublicKey`].
73     ///
74     /// Keys in this format begin with the following:
75     ///
76     /// ```text
77     /// -----BEGIN RSA PUBLIC KEY-----
78     /// ```
79     #[cfg(feature = "pem")]
from_pkcs1_pem(s: &str) -> Result<Self>80     fn from_pkcs1_pem(s: &str) -> Result<Self> {
81         let (label, doc) = Document::from_pem(s)?;
82         RsaPublicKey::validate_pem_label(label)?;
83         Self::from_pkcs1_der(doc.as_bytes())
84     }
85 
86     /// Load [`RsaPublicKey`] from an ASN.1 DER-encoded file on the local
87     /// filesystem (binary format).
88     #[cfg(feature = "std")]
read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self>89     fn read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self> {
90         let doc = Document::read_der_file(path)?;
91         Self::from_pkcs1_der(doc.as_bytes())
92     }
93 
94     /// Load [`RsaPublicKey`] from a PEM-encoded file on the local filesystem.
95     #[cfg(all(feature = "pem", feature = "std"))]
read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self>96     fn read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
97         let (label, doc) = Document::read_pem_file(path)?;
98         RsaPublicKey::validate_pem_label(&label)?;
99         Self::from_pkcs1_der(doc.as_bytes())
100     }
101 }
102 
103 /// Serialize a [`RsaPrivateKey`] to a PKCS#1 encoded document.
104 #[cfg(feature = "alloc")]
105 pub trait EncodeRsaPrivateKey {
106     /// Serialize a [`SecretDocument`] containing a PKCS#1-encoded private key.
to_pkcs1_der(&self) -> Result<SecretDocument>107     fn to_pkcs1_der(&self) -> Result<SecretDocument>;
108 
109     /// Serialize this private key as PEM-encoded PKCS#1 with the given [`LineEnding`].
110     #[cfg(feature = "pem")]
to_pkcs1_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>>111     fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>> {
112         let doc = self.to_pkcs1_der()?;
113         Ok(doc.to_pem(RsaPrivateKey::PEM_LABEL, line_ending)?)
114     }
115 
116     /// Write ASN.1 DER-encoded PKCS#1 private key to the given path.
117     #[cfg(feature = "std")]
write_pkcs1_der_file(&self, path: impl AsRef<Path>) -> Result<()>118     fn write_pkcs1_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
119         Ok(self.to_pkcs1_der()?.write_der_file(path)?)
120     }
121 
122     /// Write ASN.1 DER-encoded PKCS#1 private key to the given path.
123     #[cfg(all(feature = "pem", feature = "std"))]
write_pkcs1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()>124     fn write_pkcs1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> {
125         let doc = self.to_pkcs1_der()?;
126         Ok(doc.write_pem_file(path, RsaPrivateKey::PEM_LABEL, line_ending)?)
127     }
128 }
129 
130 /// Serialize a [`RsaPublicKey`] to a PKCS#1-encoded document.
131 #[cfg(feature = "alloc")]
132 pub trait EncodeRsaPublicKey {
133     /// Serialize a [`Document`] containing a PKCS#1-encoded public key.
to_pkcs1_der(&self) -> Result<Document>134     fn to_pkcs1_der(&self) -> Result<Document>;
135 
136     /// Serialize this public key as PEM-encoded PKCS#1 with the given line ending.
137     #[cfg(feature = "pem")]
to_pkcs1_pem(&self, line_ending: LineEnding) -> Result<String>138     fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result<String> {
139         let doc = self.to_pkcs1_der()?;
140         Ok(doc.to_pem(RsaPublicKey::PEM_LABEL, line_ending)?)
141     }
142 
143     /// Write ASN.1 DER-encoded public key to the given path.
144     #[cfg(feature = "std")]
write_pkcs1_der_file(&self, path: impl AsRef<Path>) -> Result<()>145     fn write_pkcs1_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
146         Ok(self.to_pkcs1_der()?.write_der_file(path)?)
147     }
148 
149     /// Write ASN.1 DER-encoded public key to the given path.
150     #[cfg(all(feature = "pem", feature = "std"))]
write_pkcs1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()>151     fn write_pkcs1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> {
152         let doc = self.to_pkcs1_der()?;
153         Ok(doc.write_pem_file(path, RsaPublicKey::PEM_LABEL, line_ending)?)
154     }
155 }
156 
157 #[cfg(feature = "pkcs8")]
158 impl<T> DecodeRsaPrivateKey for T
159 where
160     T: for<'a> TryFrom<pkcs8::PrivateKeyInfo<'a>, Error = pkcs8::Error>,
161 {
from_pkcs1_der(private_key: &[u8]) -> Result<Self>162     fn from_pkcs1_der(private_key: &[u8]) -> Result<Self> {
163         Ok(Self::try_from(pkcs8::PrivateKeyInfo {
164             algorithm: ALGORITHM_ID,
165             private_key,
166             public_key: None,
167         })?)
168     }
169 }
170 
171 #[cfg(feature = "pkcs8")]
172 impl<T> DecodeRsaPublicKey for T
173 where
174     T: for<'a> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'a>, Error = pkcs8::spki::Error>,
175 {
from_pkcs1_der(public_key: &[u8]) -> Result<Self>176     fn from_pkcs1_der(public_key: &[u8]) -> Result<Self> {
177         Ok(Self::try_from(pkcs8::SubjectPublicKeyInfoRef {
178             algorithm: ALGORITHM_ID,
179             subject_public_key: BitStringRef::from_bytes(public_key)?,
180         })?)
181     }
182 }
183 
184 #[cfg(all(feature = "alloc", feature = "pkcs8"))]
185 impl<T: pkcs8::EncodePrivateKey> EncodeRsaPrivateKey for T {
to_pkcs1_der(&self) -> Result<SecretDocument>186     fn to_pkcs1_der(&self) -> Result<SecretDocument> {
187         let pkcs8_doc = self.to_pkcs8_der()?;
188         let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(pkcs8_doc.as_bytes())?;
189         pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?;
190         RsaPrivateKey::from_der(pkcs8_key.private_key)?.try_into()
191     }
192 }
193 
194 #[cfg(all(feature = "alloc", feature = "pkcs8"))]
195 impl<T: pkcs8::EncodePublicKey> EncodeRsaPublicKey for T {
to_pkcs1_der(&self) -> Result<Document>196     fn to_pkcs1_der(&self) -> Result<Document> {
197         let doc = self.to_public_key_der()?;
198         let spki = pkcs8::SubjectPublicKeyInfoRef::from_der(doc.as_bytes())?;
199         spki.algorithm.assert_algorithm_oid(ALGORITHM_OID)?;
200         RsaPublicKey::from_der(spki.subject_public_key.raw_bytes())?.try_into()
201     }
202 }
203