Skip to main content

mail_auth/common/crypto/
ring_impls.rs

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