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 std::marker::PhantomData;
8
9use ring::digest::{Context, SHA1_FOR_LEGACY_USE_ONLY, SHA256};
10use ring::rand::SystemRandom;
11use ring::signature::{
12    Ed25519KeyPair, KeyPair, RsaKeyPair, UnparsedPublicKey, ED25519,
13    RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY, RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
14    RSA_PKCS1_SHA256,
15};
16
17use crate::{
18    common::headers::{Writable, Writer},
19    dkim::Canonicalization,
20    Error, Result,
21};
22
23use super::{Algorithm, HashContext, HashImpl, HashOutput, Sha1, Sha256, SigningKey, VerifyingKey};
24
25#[derive(Debug)]
26pub struct RsaKey<T> {
27    inner: RsaKeyPair,
28    rng: SystemRandom,
29    padding: PhantomData<T>,
30}
31
32impl<T: HashImpl> RsaKey<T> {
33    #[cfg(feature = "rustls-pemfile")]
34    pub fn from_pkcs8_pem(pkcs8_pem: &str) -> Result<Self> {
35        let item = rustls_pemfile::read_one(&mut pkcs8_pem.as_bytes())
36            .map_err(|err| Error::CryptoError(err.to_string()))?;
37
38        let pkcs8_der = match item {
39            Some(rustls_pemfile::Item::Pkcs8Key(key)) => key,
40            _ => return Err(Error::CryptoError("No PKCS8 key found in PEM".to_string())),
41        };
42
43        Self::from_pkcs8_der(pkcs8_der.secret_pkcs8_der())
44    }
45
46    /// Creates a new RSA private key from PKCS8 DER-encoded bytes.
47    pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
48        Ok(Self {
49            inner: RsaKeyPair::from_pkcs8(pkcs8_der)
50                .map_err(|err| Error::CryptoError(err.to_string()))?,
51            rng: SystemRandom::new(),
52            padding: PhantomData,
53        })
54    }
55
56    #[cfg(feature = "rustls-pemfile")]
57    pub fn from_rsa_pem(rsa_pem: &str) -> Result<Self> {
58        let item = rustls_pemfile::read_one(&mut rsa_pem.as_bytes())
59            .map_err(|err| Error::CryptoError(err.to_string()))?;
60
61        let rsa_der = match item {
62            Some(rustls_pemfile::Item::Pkcs1Key(key)) => key,
63            _ => return Err(Error::CryptoError("No RSA key found in PEM".to_string())),
64        };
65
66        Self::from_der(rsa_der.secret_pkcs1_der())
67    }
68
69    /// Creates a new RSA private key from a PKCS1 binary slice.
70    pub fn from_der(der: &[u8]) -> Result<Self> {
71        Ok(Self {
72            inner: RsaKeyPair::from_der(der).map_err(|err| Error::CryptoError(err.to_string()))?,
73            rng: SystemRandom::new(),
74            padding: PhantomData,
75        })
76    }
77
78    /// Returns the public key of the RSA key pair.
79    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    // Returns the public key of the Ed25519 key pair.
137    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
179/// Try to strip an ASN.1 DER-encoded RSA public key prefix
180///
181/// Returns the original slice if the prefix is not found.
182fn 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..)?; // skip the RSA encryption OID
198    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..)) // skip the unused bits byte
203}
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}