pkcs1/
traits.rs

1//! Traits for parsing objects from PKCS#1 encoded documents
2
3use crate::Result;
4
5#[cfg(feature = "alloc")]
6use der::{Document, SecretDocument};
7
8#[cfg(feature = "pem")]
9use {
10    crate::LineEnding,
11    alloc::string::String,
12    der::{pem::PemLabel, zeroize::Zeroizing},
13};
14
15#[cfg(feature = "pkcs8")]
16use {
17    crate::{ALGORITHM_ID, ALGORITHM_OID},
18    der::asn1::BitStringRef,
19};
20
21#[cfg(feature = "std")]
22use std::path::Path;
23
24#[cfg(all(feature = "alloc", feature = "pkcs8"))]
25use der::Decode;
26
27#[cfg(all(feature = "alloc", any(feature = "pem", feature = "pkcs8")))]
28use crate::{RsaPrivateKey, RsaPublicKey};
29
30/// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document.
31pub trait DecodeRsaPrivateKey: Sized {
32    /// Deserialize PKCS#1 private key from ASN.1 DER-encoded data
33    /// (binary format).
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")]
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")]
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"))]
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.
67pub trait DecodeRsaPublicKey: Sized {
68    /// Deserialize object from ASN.1 DER-encoded [`RsaPublicKey`]
69    /// (binary format).
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")]
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")]
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"))]
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")]
105pub trait EncodeRsaPrivateKey {
106    /// Serialize a [`SecretDocument`] containing a PKCS#1-encoded private key.
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")]
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")]
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"))]
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")]
132pub trait EncodeRsaPublicKey {
133    /// Serialize a [`Document`] containing a PKCS#1-encoded public key.
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")]
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")]
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"))]
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")]
158impl<T> DecodeRsaPrivateKey for T
159where
160    T: for<'a> TryFrom<pkcs8::PrivateKeyInfo<'a>, Error = pkcs8::Error>,
161{
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")]
172impl<T> DecodeRsaPublicKey for T
173where
174    T: for<'a> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'a>, Error = pkcs8::spki::Error>,
175{
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"))]
185impl<T: pkcs8::EncodePrivateKey> EncodeRsaPrivateKey for T {
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"))]
195impl<T: pkcs8::EncodePublicKey> EncodeRsaPublicKey for T {
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}