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