Skip to main content

mail_auth/common/crypto/
mod.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::headers::{Writable, Writer};
8use crate::{Result, dkim::Canonicalization};
9
10#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
11mod ring_impls;
12#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
13pub use ring_impls::{Ed25519Key, RsaKey};
14#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
15pub(crate) use ring_impls::{Ed25519PublicKey, RsaPublicKey};
16
17pub trait SigningKey {
18    type Hasher: HashImpl;
19
20    fn sign(&self, input: impl Writable) -> Result<Vec<u8>>;
21
22    fn hash(&self, data: impl Writable) -> HashOutput {
23        let mut hasher = <Self::Hasher as HashImpl>::hasher();
24        data.write(&mut hasher);
25        hasher.complete()
26    }
27
28    fn algorithm(&self) -> Algorithm;
29}
30
31pub trait VerifyingKey {
32    fn verify<'a>(
33        &self,
34        headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
35        signature: &[u8],
36        canonicalication: Canonicalization,
37        algorithm: Algorithm,
38    ) -> Result<()>;
39}
40
41pub(crate) enum VerifyingKeyType {
42    Rsa,
43    Ed25519,
44}
45
46impl VerifyingKeyType {
47    pub(crate) fn verifying_key(
48        &self,
49        bytes: &[u8],
50    ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
51        match self {
52            #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
53            Self::Rsa => RsaPublicKey::verifying_key_from_bytes(bytes),
54            #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
55            Self::Ed25519 => Ed25519PublicKey::verifying_key_from_bytes(bytes),
56        }
57    }
58}
59
60pub trait HashContext: Writer + Sized {
61    fn complete(self) -> HashOutput;
62}
63
64pub trait HashImpl {
65    type Context: HashContext;
66
67    fn hasher() -> Self::Context;
68}
69
70#[derive(Clone, Copy)]
71pub struct Sha1;
72
73#[derive(Clone, Copy)]
74pub struct Sha256;
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77#[repr(u64)]
78pub enum HashAlgorithm {
79    Sha1 = R_HASH_SHA1,
80    Sha256 = R_HASH_SHA256,
81}
82
83#[cfg(feature = "aws-lc-rs")]
84use aws_lc_rs as crypto_backend;
85#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
86use ring as crypto_backend;
87
88#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
89impl HashAlgorithm {
90    pub fn hash(&self, data: impl Writable) -> HashOutput {
91        match self {
92            Self::Sha1 => {
93                let mut hasher = crypto_backend::digest::Context::new(
94                    &crypto_backend::digest::SHA1_FOR_LEGACY_USE_ONLY,
95                );
96                data.write(&mut hasher);
97                HashOutput::Digest(hasher.finish())
98            }
99            Self::Sha256 => {
100                let mut hasher =
101                    crypto_backend::digest::Context::new(&crypto_backend::digest::SHA256);
102                data.write(&mut hasher);
103                HashOutput::Digest(hasher.finish())
104            }
105        }
106    }
107}
108
109#[non_exhaustive]
110pub enum HashOutput {
111    #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
112    Digest(crypto_backend::digest::Digest),
113}
114
115impl AsRef<[u8]> for HashOutput {
116    fn as_ref(&self) -> &[u8] {
117        match self {
118            #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
119            Self::Digest(output) => output.as_ref(),
120        }
121    }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
125#[repr(u8)]
126pub enum Algorithm {
127    RsaSha1,
128    #[default]
129    RsaSha256,
130    Ed25519Sha256,
131}
132
133pub(crate) const R_HASH_SHA1: u64 = 0x01;
134pub(crate) const R_HASH_SHA256: u64 = 0x02;