1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
use super::hash::Algorithm as HashAlgorithm;
use alloc::vec;
use mbedtls::pk::{EcGroupId, Pk};
use rustls::pki_types::{AlgorithmIdentifier, InvalidSignature, SignatureVerificationAlgorithm};
use rustls::SignatureScheme;
use webpki::alg_id;

/// ECDSA signatures using the P-256 curve and SHA-256.
pub static ECDSA_P256_SHA256: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::ECDSA_NISTP256_SHA256,
    hash_algo: &super::hash::MBED_SHA_256,
    public_key_alg_id: alg_id::ECDSA_P256,
    ec_group_id: Some(EcGroupId::SecP256R1),
    signature_alg_id: alg_id::ECDSA_SHA256,
};
/// ECDSA signatures using the P-384 curve and SHA-256.
pub static ECDSA_P384_SHA256: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::ECDSA_NISTP256_SHA256,
    hash_algo: &super::hash::MBED_SHA_256,
    public_key_alg_id: alg_id::ECDSA_P384,
    ec_group_id: Some(EcGroupId::SecP384R1),
    signature_alg_id: alg_id::ECDSA_SHA256,
};
/// ECDSA signatures using the P-384 curve and SHA-384.
pub static ECDSA_P384_SHA384: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::ECDSA_NISTP384_SHA384,
    hash_algo: &super::hash::MBED_SHA_384,
    public_key_alg_id: alg_id::ECDSA_P384,
    ec_group_id: Some(EcGroupId::SecP384R1),
    signature_alg_id: alg_id::ECDSA_SHA384,
};
/// ECDSA signatures using the P-256 curve and SHA-384.
pub static ECDSA_P256_SHA384: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::ECDSA_NISTP384_SHA384,
    hash_algo: &super::hash::MBED_SHA_384,
    public_key_alg_id: alg_id::ECDSA_P256,
    ec_group_id: Some(EcGroupId::SecP256R1),
    signature_alg_id: alg_id::ECDSA_SHA384,
};
/// RSA PKCS#1 1.5 signatures using SHA-256.
pub static RSA_PKCS1_SHA256: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::RSA_PKCS1_SHA256,
    hash_algo: &super::hash::MBED_SHA_256,
    public_key_alg_id: alg_id::RSA_ENCRYPTION,
    ec_group_id: None,
    signature_alg_id: alg_id::RSA_PKCS1_SHA256,
};
/// RSA PKCS#1 1.5 signatures using SHA-384.
pub static RSA_PKCS1_SHA384: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::RSA_PKCS1_SHA384,
    hash_algo: &super::hash::MBED_SHA_384,
    public_key_alg_id: alg_id::RSA_ENCRYPTION,
    ec_group_id: None,
    signature_alg_id: alg_id::RSA_PKCS1_SHA384,
};
/// RSA PKCS#1 1.5 signatures using SHA-512.
pub static RSA_PKCS1_SHA512: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::RSA_PKCS1_SHA512,
    hash_algo: &super::hash::MBED_SHA_512,
    public_key_alg_id: alg_id::RSA_ENCRYPTION,
    ec_group_id: None,
    signature_alg_id: alg_id::RSA_PKCS1_SHA512,
};
/// RSA PSS signatures using SHA-256 and of
/// type rsaEncryption; see [RFC 4055 Section 1.2].
///
/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
pub static RSA_PSS_SHA256: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::RSA_PSS_SHA256,
    hash_algo: &super::hash::MBED_SHA_256,
    public_key_alg_id: alg_id::RSA_ENCRYPTION,
    ec_group_id: None,
    signature_alg_id: alg_id::RSA_PSS_SHA256,
};
/// RSA PSS signatures using SHA-384 and of
/// type rsaEncryption; see [RFC 4055 Section 1.2].
///
/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
pub static RSA_PSS_SHA384: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::RSA_PSS_SHA384,
    hash_algo: &super::hash::MBED_SHA_384,
    public_key_alg_id: alg_id::RSA_ENCRYPTION,
    ec_group_id: None,
    signature_alg_id: alg_id::RSA_PSS_SHA384,
};
/// RSA PSS signatures using SHA-512 and of
/// type rsaEncryption; see [RFC 4055 Section 1.2].
///
/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
pub static RSA_PSS_SHA512: &Algorithm = &Algorithm {
    signature_scheme: SignatureScheme::RSA_PSS_SHA512,
    hash_algo: &super::hash::MBED_SHA_512,
    public_key_alg_id: alg_id::RSA_ENCRYPTION,
    ec_group_id: None,
    signature_alg_id: alg_id::RSA_PSS_SHA512,
};

/// A signature verify algorithm type
#[derive(Clone, Debug, PartialEq)]
pub struct Algorithm {
    signature_scheme: SignatureScheme,
    hash_algo: &'static HashAlgorithm,
    public_key_alg_id: AlgorithmIdentifier,
    ec_group_id: Option<EcGroupId>,
    signature_alg_id: AlgorithmIdentifier,
}

impl SignatureVerificationAlgorithm for Algorithm {
    fn verify_signature(&self, public_key: &[u8], message: &[u8], signature: &[u8]) -> Result<(), InvalidSignature> {
        let mut pk = match self.ec_group_id {
            None => Pk::from_public_key(public_key).map_err(|_| InvalidSignature)?,
            Some(ec_group_id) => {
                let spki = yasna::construct_der(|writer| {
                    writer.write_sequence(|writer| {
                        writer.next().write_sequence(|w| {
                            w.next()
                                .write_der(&self.public_key_alg_id)
                        });
                        writer
                            .next()
                            .write_bitvec(&bit_vec::BitVec::from_bytes(public_key));
                    })
                });
                let ec_pk = Pk::from_public_key(&spki).map_err(|_| InvalidSignature)?;
                let curves_match = ec_pk
                    .curve()
                    .is_ok_and(|pk_curve| pk_curve == ec_group_id);
                if !curves_match {
                    return Err(InvalidSignature);
                };
                ec_pk
            }
        };

        if let Some(opts) = utils::pk::rustls_signature_scheme_to_mbedtls_pk_options(self.signature_scheme) {
            pk.set_options(opts);
        }
        let mut hash = vec![0u8; self.hash_algo.output_len];
        mbedtls::hash::Md::hash(self.hash_algo.hash_type, message, &mut hash).map_err(|_| InvalidSignature)?;
        pk.verify(self.hash_algo.hash_type, &hash, signature)
            .map_err(|_| InvalidSignature)
    }

    fn public_key_alg_id(&self) -> AlgorithmIdentifier {
        self.public_key_alg_id
    }

    fn signature_alg_id(&self) -> AlgorithmIdentifier {
        self.signature_alg_id
    }
}