|
9 | 9 | //! https://datatracker.ietf.org/doc/html/rfc8017 |
10 | 10 |
|
11 | 11 | use rsa::pkcs1v15::Signature; |
12 | | -use rsa::pkcs8::{ |
13 | | - DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey, Error, LineEnding, |
14 | | -}; |
| 12 | +use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey, Error}; |
15 | 13 | use rsa::rand_core::OsRng; |
16 | 14 | use rsa::sha2::{Digest, Sha256}; |
17 | 15 | use rsa::signature::hazmat::PrehashVerifier; |
@@ -48,21 +46,48 @@ impl SecretKey { |
48 | 46 | let e = BigUint::from_bytes_be(&bytes[512..520]); |
49 | 47 |
|
50 | 48 | let n = &p * &q; |
| 49 | + |
| 50 | + // Whilst the RSA algorithm permits different exponents, every modern |
| 51 | + // system only ever uses 65537 and most also enforce this. Might as |
| 52 | + // well do the same. |
| 53 | + if e != BigUint::from(65537u32) { |
| 54 | + return Err(rsa::Error::InvalidExponent); |
| 55 | + } |
51 | 56 | let key = RsaPrivateKey::from_components(n, e, d, vec![p, q])?; |
52 | 57 | let sig = rsa::pkcs1v15::SigningKey::<Sha256>::new(key); |
53 | 58 | Ok(Self { inner: sig }) |
54 | 59 | } |
55 | 60 |
|
56 | 61 | /// from_der parses a DER buffer into a private key. |
57 | | - pub fn from_der(der: &[u8]) -> Result<Self, Error> { |
| 62 | + pub fn from_der(der: &[u8]) -> Result<Self, Box<dyn std::error::Error>> { |
58 | 63 | let inner = rsa::pkcs1v15::SigningKey::<Sha256>::from_pkcs8_der(der)?; |
| 64 | + |
| 65 | + // Whilst the RSA algorithm permits different exponents, every modern |
| 66 | + // system only ever uses 65537 and most also enforce this. Might as |
| 67 | + // well do the same. |
| 68 | + let key: &RsaPrivateKey = inner.as_ref(); |
| 69 | + if *key.e() != BigUint::from(65537u32) { |
| 70 | + return Err(Error::KeyMalformed.into()); |
| 71 | + } |
| 72 | + // The upstream rsa crate ignores CRT parameters (dP, dQ, qInv) and |
| 73 | + // recomputes them, accepting malformed values. We don't want to allow |
| 74 | + // that, so just round trip the format and see if it's matching or not. |
| 75 | + let recoded = rsa::pkcs1v15::SigningKey::<Sha256>::to_pkcs8_der(&inner)?; |
| 76 | + if recoded.as_bytes() != der { |
| 77 | + return Err(Error::KeyMalformed.into()); |
| 78 | + } |
59 | 79 | Ok(Self { inner }) |
60 | 80 | } |
61 | 81 |
|
62 | 82 | /// from_pem parses a PEM string into a private key. |
63 | | - pub fn from_pem(pem: &str) -> Result<Self, Error> { |
64 | | - let inner = rsa::pkcs1v15::SigningKey::<Sha256>::from_pkcs8_pem(pem)?; |
65 | | - Ok(Self { inner }) |
| 83 | + pub fn from_pem(pem: &str) -> Result<Self, Box<dyn std::error::Error>> { |
| 84 | + // Crack open the PEM to get to the private key info |
| 85 | + let res = pem::parse(pem.as_bytes())?; |
| 86 | + if res.tag() != "PRIVATE KEY" { |
| 87 | + return Err(format!("invalid PEM tag {}", res.tag()).into()); |
| 88 | + } |
| 89 | + // Parse the DER content |
| 90 | + Self::from_der(res.contents()) |
66 | 91 | } |
67 | 92 |
|
68 | 93 | /// to_bytes serializes a private key into a 520-byte array. |
@@ -98,12 +123,12 @@ impl SecretKey { |
98 | 123 | .to_vec() |
99 | 124 | } |
100 | 125 |
|
101 | | - /// to_pem serializes a public key into a PEM string. |
| 126 | + /// to_pem serializes a private key into a PEM string. |
102 | 127 | pub fn to_pem(&self) -> String { |
103 | | - rsa::pkcs1v15::SigningKey::<Sha256>::to_pkcs8_pem(&self.inner, LineEnding::LF) |
104 | | - .unwrap() |
105 | | - .as_str() |
106 | | - .to_string() |
| 128 | + pem::encode_config( |
| 129 | + &pem::Pem::new("PRIVATE KEY", self.to_der()), |
| 130 | + pem::EncodeConfig::new().set_line_ending(pem::LineEnding::LF), |
| 131 | + ) |
107 | 132 | } |
108 | 133 |
|
109 | 134 | /// public_key retrieves the public counterpart of the secret key. |
@@ -153,15 +178,28 @@ impl PublicKey { |
153 | 178 | } |
154 | 179 |
|
155 | 180 | /// from_der parses a DER buffer into a public key. |
156 | | - pub fn from_der(der: &[u8]) -> Result<Self, Error> { |
| 181 | + pub fn from_der(der: &[u8]) -> Result<Self, Box<dyn std::error::Error>> { |
157 | 182 | let inner = rsa::pkcs1v15::VerifyingKey::<Sha256>::from_public_key_der(der)?; |
| 183 | + |
| 184 | + // Whilst the RSA algorithm permits different exponents, every modern |
| 185 | + // system only ever uses 65537 and most also enforce this. Might as |
| 186 | + // well do the same. |
| 187 | + let key: &RsaPublicKey = inner.as_ref(); |
| 188 | + if *key.e() != BigUint::from(65537u32) { |
| 189 | + return Err(Error::KeyMalformed.into()); |
| 190 | + } |
158 | 191 | Ok(Self { inner }) |
159 | 192 | } |
160 | 193 |
|
161 | 194 | /// from_pem parses a PEM string into a public key. |
162 | | - pub fn from_pem(pem: &str) -> Result<Self, Error> { |
163 | | - let inner = rsa::pkcs1v15::VerifyingKey::<Sha256>::from_public_key_pem(pem)?; |
164 | | - Ok(Self { inner }) |
| 195 | + pub fn from_pem(pem: &str) -> Result<Self, Box<dyn std::error::Error>> { |
| 196 | + // Crack open the PEM to get to the public key info |
| 197 | + let res = pem::parse(pem.as_bytes())?; |
| 198 | + if res.tag() != "PUBLIC KEY" { |
| 199 | + return Err(format!("invalid PEM tag {}", res.tag()).into()); |
| 200 | + } |
| 201 | + // Parse the DER content |
| 202 | + Self::from_der(res.contents()) |
165 | 203 | } |
166 | 204 |
|
167 | 205 | /// to_bytes serializes a public key into a 264-byte array. |
@@ -191,8 +229,10 @@ impl PublicKey { |
191 | 229 |
|
192 | 230 | /// to_pem serializes a public key into a PEM string. |
193 | 231 | pub fn to_pem(&self) -> String { |
194 | | - rsa::pkcs1v15::VerifyingKey::<Sha256>::to_public_key_pem(&self.inner, LineEnding::LF) |
195 | | - .unwrap() |
| 232 | + pem::encode_config( |
| 233 | + &pem::Pem::new("PUBLIC KEY", self.to_der()), |
| 234 | + pem::EncodeConfig::new().set_line_ending(pem::LineEnding::LF), |
| 235 | + ) |
196 | 236 | } |
197 | 237 |
|
198 | 238 | /// fingerprint returns a 256bit unique identified for this key. For RSA, that |
|
0 commit comments