1use super::{Algorithm, HashContext, HashImpl, HashOutput, Sha1, Sha256, SigningKey, VerifyingKey};
8use crate::{
9 Error, Result,
10 common::headers::{Writable, Writer},
11 dkim::Canonicalization,
12};
13use ring::digest::{Context, SHA1_FOR_LEGACY_USE_ONLY, SHA256};
14use ring::rand::SystemRandom;
15use ring::signature::{
16 ED25519, Ed25519KeyPair, KeyPair, RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
17 RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY, RSA_PKCS1_SHA256, RsaKeyPair,
18 UnparsedPublicKey,
19};
20use rustls_pki_types::{PrivateKeyDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer, pem::PemObject};
21use std::marker::PhantomData;
22
23#[derive(Debug)]
24pub struct RsaKey<T> {
25 inner: RsaKeyPair,
26 rng: SystemRandom,
27 padding: PhantomData<T>,
28}
29
30impl<T: HashImpl> RsaKey<T> {
31 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
32 pub fn from_pkcs8_pem(pkcs8_pem: &str) -> Result<Self> {
33 Self::from_key_der(PrivateKeyDer::Pkcs8(
34 PrivatePkcs8KeyDer::from_pem_slice(pkcs8_pem.as_bytes())
35 .map_err(|err| Error::CryptoError(err.to_string()))?,
36 ))
37 }
38
39 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
41 pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
42 Self::from_key_der(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(pkcs8_der)))
43 }
44
45 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
46 pub fn from_rsa_pem(rsa_pem: &str) -> Result<Self> {
47 Self::from_key_der(PrivateKeyDer::Pkcs1(
48 PrivatePkcs1KeyDer::from_pem_slice(rsa_pem.as_bytes())
49 .map_err(|err| Error::CryptoError(err.to_string()))?,
50 ))
51 }
52
53 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
55 pub fn from_der(der: &[u8]) -> Result<Self> {
56 Self::from_key_der(PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(der)))
57 }
58
59 pub fn from_key_der(key_der: PrivateKeyDer<'_>) -> Result<Self> {
63 let inner = match key_der {
64 PrivateKeyDer::Pkcs1(der) => RsaKeyPair::from_der(der.secret_pkcs1_der())
65 .map_err(|err| Error::CryptoError(err.to_string()))?,
66 PrivateKeyDer::Pkcs8(der) => RsaKeyPair::from_pkcs8(der.secret_pkcs8_der())
67 .map_err(|err| Error::CryptoError(err.to_string()))?,
68 _ => return Err(Error::CryptoError("Unsupported RSA key format".to_string())),
69 };
70
71 Ok(Self {
72 inner,
73 rng: SystemRandom::new(),
74 padding: PhantomData,
75 })
76 }
77
78 pub fn public_key(&self) -> Vec<u8> {
80 self.inner.public().as_ref().to_vec()
81 }
82}
83
84impl SigningKey for RsaKey<Sha256> {
85 type Hasher = Sha256;
86
87 fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
88 let mut data = Vec::with_capacity(256);
89 input.write(&mut data);
90
91 let mut signature = vec![0; self.inner.public().modulus_len()];
92 self.inner
93 .sign(&RSA_PKCS1_SHA256, &self.rng, &data, &mut signature)
94 .map_err(|err| Error::CryptoError(err.to_string()))?;
95 Ok(signature)
96 }
97
98 fn algorithm(&self) -> Algorithm {
99 Algorithm::RsaSha256
100 }
101}
102
103pub struct Ed25519Key {
104 inner: Ed25519KeyPair,
105}
106
107impl Ed25519Key {
108 pub fn generate_pkcs8() -> Result<Vec<u8>> {
109 Ok(Ed25519KeyPair::generate_pkcs8(&SystemRandom::new())
110 .map_err(|err| Error::CryptoError(err.to_string()))?
111 .as_ref()
112 .to_vec())
113 }
114
115 pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
116 Ok(Self {
117 inner: Ed25519KeyPair::from_pkcs8(pkcs8_der)
118 .map_err(|err| Error::CryptoError(err.to_string()))?,
119 })
120 }
121
122 pub fn from_pkcs8_maybe_unchecked_der(pkcs8_der: &[u8]) -> Result<Self> {
123 Ok(Self {
124 inner: Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8_der)
125 .map_err(|err| Error::CryptoError(err.to_string()))?,
126 })
127 }
128
129 pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self> {
130 Ok(Self {
131 inner: Ed25519KeyPair::from_seed_and_public_key(seed, public_key)
132 .map_err(|err| Error::CryptoError(err.to_string()))?,
133 })
134 }
135
136 pub fn public_key(&self) -> Vec<u8> {
138 self.inner.public_key().as_ref().to_vec()
139 }
140}
141
142impl SigningKey for Ed25519Key {
143 type Hasher = Sha256;
144
145 fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
146 let mut data = Sha256::hasher();
147 input.write(&mut data);
148 Ok(self.inner.sign(data.complete().as_ref()).as_ref().to_vec())
149 }
150
151 fn algorithm(&self) -> Algorithm {
152 Algorithm::Ed25519Sha256
153 }
154}
155
156pub(crate) struct RsaPublicKey {
157 sha1: UnparsedPublicKey<Vec<u8>>,
158 sha2: UnparsedPublicKey<Vec<u8>>,
159}
160
161impl RsaPublicKey {
162 pub(crate) fn verifying_key_from_bytes(
163 bytes: &[u8],
164 ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
165 let key = try_strip_rsa_prefix(bytes).unwrap_or(bytes);
166 Ok(Box::new(Self {
167 sha1: UnparsedPublicKey::new(
168 &RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
169 key.to_vec(),
170 ),
171 sha2: UnparsedPublicKey::new(
172 &RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
173 key.to_vec(),
174 ),
175 }))
176 }
177}
178
179fn try_strip_rsa_prefix(bytes: &[u8]) -> Option<&[u8]> {
183 if *bytes.first()? != DER_SEQUENCE_TAG {
184 return None;
185 }
186
187 let (_, bytes) = decode_multi_byte_len(&bytes[1..])?;
188 if *bytes.first()? != DER_SEQUENCE_TAG {
189 return None;
190 }
191
192 let (byte_len, bytes) = decode_multi_byte_len(&bytes[1..])?;
193 if *bytes.first()? != DER_OBJECT_ID_TAG || byte_len != 13 {
194 return None;
195 }
196
197 let bytes = bytes.get(13..)?; if *bytes.first()? != DER_BIT_STRING_TAG {
199 return None;
200 }
201
202 decode_multi_byte_len(&bytes[1..]).and_then(|(_, bytes)| bytes.get(1..)) }
204
205fn decode_multi_byte_len(bytes: &[u8]) -> Option<(usize, &[u8])> {
206 if bytes.first()? & 0x80 == 0 {
207 return Some((bytes[0] as usize, &bytes[1..]));
208 }
209
210 let len_len = (bytes[0] & 0x7f) as usize;
211 if bytes.len() < len_len + 1 {
212 return None;
213 }
214
215 let mut len = 0;
216 for i in 0..len_len {
217 len = (len << 8) | bytes[1 + i] as usize;
218 }
219
220 Some((len, &bytes[len_len + 1..]))
221}
222
223const DER_OBJECT_ID_TAG: u8 = 0x06;
224const DER_BIT_STRING_TAG: u8 = 0x03;
225const DER_SEQUENCE_TAG: u8 = 0x30;
226
227impl VerifyingKey for RsaPublicKey {
228 fn verify<'a>(
229 &self,
230 headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
231 signature: &[u8],
232 canonicalization: Canonicalization,
233 algorithm: Algorithm,
234 ) -> Result<()> {
235 let mut data = Vec::with_capacity(256);
236 canonicalization.canonicalize_headers(headers, &mut data);
237
238 match algorithm {
239 Algorithm::RsaSha256 => self
240 .sha2
241 .verify(&data, signature)
242 .map_err(|_| Error::FailedVerification),
243 Algorithm::RsaSha1 => self
244 .sha1
245 .verify(&data, signature)
246 .map_err(|_| Error::FailedVerification),
247 Algorithm::Ed25519Sha256 => Err(Error::IncompatibleAlgorithms),
248 }
249 }
250}
251
252pub(crate) struct Ed25519PublicKey {
253 inner: UnparsedPublicKey<Vec<u8>>,
254}
255
256impl Ed25519PublicKey {
257 pub(crate) fn verifying_key_from_bytes(
258 bytes: &[u8],
259 ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
260 Ok(Box::new(Self {
261 inner: UnparsedPublicKey::new(&ED25519, bytes.to_vec()),
262 }))
263 }
264}
265
266impl VerifyingKey for Ed25519PublicKey {
267 fn verify<'a>(
268 &self,
269 headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
270 signature: &[u8],
271 canonicalization: Canonicalization,
272 algorithm: Algorithm,
273 ) -> Result<()> {
274 if !matches!(algorithm, Algorithm::Ed25519Sha256) {
275 return Err(Error::IncompatibleAlgorithms);
276 }
277
278 let mut hasher = Sha256::hasher();
279 canonicalization.canonicalize_headers(headers, &mut hasher);
280 self.inner
281 .verify(hasher.complete().as_ref(), signature)
282 .map_err(|err| Error::CryptoError(err.to_string()))
283 }
284}
285
286impl HashImpl for Sha1 {
287 type Context = Context;
288
289 fn hasher() -> Self::Context {
290 Context::new(&SHA1_FOR_LEGACY_USE_ONLY)
291 }
292}
293
294impl HashImpl for Sha256 {
295 type Context = Context;
296
297 fn hasher() -> Self::Context {
298 Context::new(&SHA256)
299 }
300}
301
302impl HashContext for Context {
303 fn complete(self) -> HashOutput {
304 HashOutput::Ring(self.finish())
305 }
306}
307
308impl Writer for Context {
309 fn write(&mut self, data: &[u8]) {
310 self.update(data);
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 #[test]
319 fn from_key_der_pkcs1() {
320 let key_der = PrivateKeyDer::from_pem_slice(PKCS1_PEM.as_bytes()).unwrap();
321 assert!(matches!(key_der, PrivateKeyDer::Pkcs1(_)));
322 RsaKey::<Sha256>::from_key_der(key_der).unwrap();
323 }
324
325 #[test]
326 fn from_key_der_pkcs8() {
327 let key_der = PrivateKeyDer::from_pem_slice(PKCS8_PEM.as_bytes()).unwrap();
328 assert!(matches!(key_der, PrivateKeyDer::Pkcs8(_)));
329 RsaKey::<Sha256>::from_key_der(key_der).unwrap();
330 }
331
332 const PKCS1_PEM: &str = r#"-----BEGIN RSA PRIVATE KEY-----
333MIIEoAIBAAKCAQEAplSshLNG7gYj7LckWBQ5Gg1mrFGj2soo3VuMKSbvfR6tMrnj
334khKUSl3TWQyKdkuOOf4EzAyxhJdq/hWGvMdwfwH2q4UzjjcaRHDP54oBH6WHxyAn
335UUkJTFfJo2i8jFE/um09igLr5sEaKMiHgjQIdUScuQRGqKhqS9e4tPpTnfP4ayvM
336zVvD1ptUnaV4O9+GkpEwx/vLVXItMO2KNXXKADYBuWcY9g+Dlpp637radmLJjnvj
337bCJipWjuVzUEQvIvf3x1dZ4b899Bycp4uScmdz5brfxkhLaA9vchnmr+F7aAuwwK
338N5X2Ep6n5d1M0XjA02Z9Zi2W4NkZiNBBmb/f6QIDAQABAoIBAAPzPANNGv4L98jx
339+C3o/F/YbyE1sXmV9lP8I1nr1+FbETvEleQSHGL1aPpIVbZ6/gugXdP3E4qFqmUS
340ik1hQtRFWJVuDPwk5ghiPHxwIYLd+cRFHiHsT96isWzNJTiDinWpN/5XKkE5QfTe
341KaJc4tGJebEG1LhsgtUTxbTImCPxYvKUItDlApOusVvhARjqCnXunNEu5iDiADHH
342Wsv3eSPdWkdF5Jjgt/bI4I9XmagX3e1z6ZQiGvdBwCc8ccwkU6yTswXgWCPqyw/t
343lbTFqE19lEoHGTYYElKaHUo9hCmI3HZS69ShYKG7dMT9dVLhzRlNx7AzZcYWh8Mx
344Ptc8OY0CgYEA1LJe5EpfJ/XvzbiVtNiq07CGhlQj62DAH+XpyqtWHHrUNgMbnBZS
34529had9h2NyfIFDIZAKPGWRuSB6PSyDR6w5Sugh5nRoXshzaFr1pAHmo18s+QELjj
346XyccwivxRXurwmdDL5Bx0YCKII4LJyE3CBlJzq0/wOxvi+iKDRG+TIUCgYEAyDG8
347DXk+E6f9Vd4phaN3sLVDd228U/NNuEr+K74AFHwomgEv//KdK2i/EjFq0zGf31jE
348QMoVbnTDmmzVPfKRDlD3tk5XIz2TDzgGxOYBIWJLUiOlkXxckbLVJBR3NxKn561n
349id7vMR8ik+hAhEp9yZishZr+QrS/4AyHR3ahBRUCgYBYgoGKboh6kJVh/lYOE7vC
350q8rPS2RHJtPMclh/xhznbRWyBEkRAxkn8zhydtl6ykswXEibQ4veuOJj24BzX6NW
351kCCudQh1CHYNLlsjRWM5ROl+SXGiA85aYmRNSQv15ijrlR0YRfuXOu4/7dwmRGQq
352MpvMLbxCBCHHDtWj6qZOIQKBgF+3F7hBbaKsQP2bGLMicwlzwOwK9W4V9+TTRi7X
353yuYAbtEjHDX9Y5Prot8p7W9IXK3GnR51AEYtYZAl1NancR8tKyJo1lStDfDK0sG1
354TnkNrAF7tZ+XnBK1NB7qAg28x7aHO+e5RRdxUXDyLFaT3wxSCLpgXoy6KrsOgmdy
355mo35An9pYQ3Ik9ghh3PJsQ0r/TywuKIzmSvLJZfI/cuBOFkPDoWCleQGdzyQcxuc
356PSCtw8eXUj/Oc09qo5dRWXQkt5uW8sJB0k5fNnfCDqNReUXavDNXOHq31J5USy5R
3578ts1bmtZtK0oRci6A8PcgWChUvSfFUT5IrQM/x4rxabn8qIK
358-----END RSA PRIVATE KEY-----
359"#;
360
361 const PKCS8_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
362MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXxo5+n7aZ0psn
363dNjs53za9Af657AuG3sVnvWEBf24OvwwWClJ5vN+cWA7V2yIuuVvd40RxX1N4HLX
364QewaUBVw+XlHanskcYA8WTVuMTI6XNY6hIAtU1ETSWAPke5sH6DyrAzxIoC2R+IH
365ejqwjtdWdQ0MNVudqY3BO6mAH+zYblRzytMmcols+aqYNgZeAYuEie+EiJiTT65v
366y0mG24k0ALF5XLPahxhoUK/xuhjjG/Y/InD8s6C4BksO29bStnyqhMToSGMtUyOT
367PTyh1XgrUB4dlfEnpfX9F/wU8a7ijrD38Qtg935c08Qg9YcwVXzpFHWRw/ZF/auq
368lcazbMaHAgMBAAECggEAOKmhncrfLsHJkLD0jjGz7eOLfO3+q/z3c5QMsSDJoemL
369dD6SiR+m7ZtkQ/EPRVCfE4h3eSU9ZIf+YFylXbuOBd7dZE2oDMfpfu+GQmuU3xKm
370BzPoXP62GbR5D12pGKetokxgEaqX1kZGKuSEKP05uzB9vqj8aAiwev/p4QWBMsw6
3712stumeWMuZortwL9PZpXgzpJPHXDnFdsn3OIINBMFYFdqda8RhL3rWWsbV5nL1oR
372Q2/SMPLc1dQ8ZQKdPmbVhdfnPitVKVEkn8xIiFPWNS3SfYIi+wQj0lWdJbvUUJ1i
3737BIXvnXeeVLyYhekTpE5ZnGeGI4A5lix4PN+GIao8QKBgQDtuPW8BaXWfPHb93Kl
374mWBQNHz0I71p8GL9/+xRpA9SMuUtYS0jJ1whNgcwoSI4cOKo1UsIMDPAPpTU47Ul
3750D+vXr/GyiONL6+IsXAf5xhaQnUWRWKs4G9obadyGkT8aH6y8W+ddKD1JWQKUf4t
376Bmpeim+Ck0I8POhDbNNfThTLwwKBgQDoXZ70Pb6HViZAbzf+rEznNycgG8IqtTSc
377V7YoSMZe17u0AQjE9XZizBrhpz47N6/JvyYTBIh6VPQe880FTnHdUjvbqn8bmLE7
378QEYwvgF5hmHVXlWXUsyKbfMH5Dp8Uy74FV2VTd1hJ7UMSke7LQT41Hgyaz32x7Lm
379r0P63fgh7QKBgQDMrnCGz6YWo8XrS4efJgxTgp4D57HzQVM6t9xV/xhiAghppj4j
380AoTE46wVJug8CJZgICZWiopEgJ3NH7KdOE1dRguBshIiQmi1HXIZRfUl4grGfj+T
3818jp6g8+k4xF68s4EbPVZcU4VRXh5mldrlRaJCFEy8HAbRaYGR/FHIget2QKBgGd/
382o9h4VBAmAD29DDzkdBCc0VGM66xoL/nfW6SP3cPK5bFksIpCJywUa3jNLHvl7ue2
383u3fHEh8jDeVnhI9zhGYnRcAvLhSVq4OPunPlffSqNZN7RDZ1y+Nw28pNDvvndUlN
384AvUIzK2EqTDDOTYW9Fr9EFisydnM01PLB0WLbwV1AoGAGmaWcbNfPyPnJU1nIHGG
385fPlEpGn+3Oxr1ja02FPwexk/bg6CRVIqP2x7RtR1cH9fOqiDOoIqyfKswuZkwVj3
386EMeos/WHHrw+UzXem+IswmwG9rnUBMlMRCkJ9GhXk98bqoWeJpMhlj1L+oBQ3Spj
387j8T1spkdY4jj3CvmzQ0ha0U=
388-----END PRIVATE KEY-----
389"#;
390}