pkcs1/
traits.rs

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