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