Skip to main content

rustls_openssl/
verify.rs

1use core::fmt;
2use once_cell::sync::Lazy;
3use openssl::{
4    bn::BigNumContext,
5    ec::{EcGroup, EcKey, EcPoint},
6    hash::MessageDigest,
7    nid::Nid,
8    pkey::{Id, PKey, Public},
9    rsa::{Padding, Rsa},
10    sign::{RsaPssSaltlen, Verifier},
11};
12use rustls::pki_types::alg_id;
13use rustls::{
14    SignatureScheme,
15    crypto::WebPkiSupportedAlgorithms,
16    pki_types::{AlgorithmIdentifier, InvalidSignature, SignatureVerificationAlgorithm},
17};
18
19/// A [WebPkiSupportedAlgorithms] value defining the supported signature algorithms.
20pub static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
21    all: &[
22        ECDSA_P256_SHA256,
23        ECDSA_P256_SHA384,
24        ECDSA_P384_SHA256,
25        ECDSA_P384_SHA384,
26        ECDSA_P521_SHA256,
27        ECDSA_P521_SHA384,
28        ECDSA_P521_SHA512,
29        ED25519,
30        RSA_PSS_SHA512,
31        RSA_PSS_SHA384,
32        RSA_PSS_SHA256,
33        RSA_PKCS1_SHA512,
34        RSA_PKCS1_SHA384,
35        RSA_PKCS1_SHA256,
36    ],
37    mapping: &[
38        //Note: for TLS1.2 the curve is not fixed by SignatureScheme. For TLS1.3 it is.
39        (
40            SignatureScheme::ECDSA_NISTP384_SHA384,
41            &[ECDSA_P384_SHA384, ECDSA_P256_SHA384, ECDSA_P521_SHA384],
42        ),
43        (
44            SignatureScheme::ECDSA_NISTP256_SHA256,
45            &[ECDSA_P256_SHA256, ECDSA_P384_SHA256, ECDSA_P521_SHA256],
46        ),
47        (SignatureScheme::ECDSA_NISTP521_SHA512, &[ECDSA_P521_SHA512]),
48        (SignatureScheme::ED25519, &[ED25519]),
49        (SignatureScheme::RSA_PSS_SHA512, &[RSA_PSS_SHA512]),
50        (SignatureScheme::RSA_PSS_SHA384, &[RSA_PSS_SHA384]),
51        (SignatureScheme::RSA_PSS_SHA256, &[RSA_PSS_SHA256]),
52        (SignatureScheme::RSA_PKCS1_SHA512, &[RSA_PKCS1_SHA512]),
53        (SignatureScheme::RSA_PKCS1_SHA384, &[RSA_PKCS1_SHA384]),
54        (SignatureScheme::RSA_PKCS1_SHA256, &[RSA_PKCS1_SHA256]),
55    ],
56};
57
58/// A [WebPkiSupportedAlgorithms] value defining the supported signature algorithms,
59/// excluding ED25519 which is not available on fips enabled OpenSSL < 3.4.
60static SUPPORTED_SIG_ALGS_NO_ED25519: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
61    all: &[
62        ECDSA_P256_SHA256,
63        ECDSA_P256_SHA384,
64        ECDSA_P384_SHA256,
65        ECDSA_P384_SHA384,
66        ECDSA_P521_SHA256,
67        ECDSA_P521_SHA384,
68        ECDSA_P521_SHA512,
69        RSA_PSS_SHA512,
70        RSA_PSS_SHA384,
71        RSA_PSS_SHA256,
72        RSA_PKCS1_SHA512,
73        RSA_PKCS1_SHA384,
74        RSA_PKCS1_SHA256,
75    ],
76    mapping: &[
77        (
78            SignatureScheme::ECDSA_NISTP384_SHA384,
79            &[ECDSA_P384_SHA384, ECDSA_P256_SHA384, ECDSA_P521_SHA384],
80        ),
81        (
82            SignatureScheme::ECDSA_NISTP256_SHA256,
83            &[ECDSA_P256_SHA256, ECDSA_P384_SHA256, ECDSA_P521_SHA256],
84        ),
85        (SignatureScheme::ECDSA_NISTP521_SHA512, &[ECDSA_P521_SHA512]),
86        (SignatureScheme::RSA_PSS_SHA512, &[RSA_PSS_SHA512]),
87        (SignatureScheme::RSA_PSS_SHA384, &[RSA_PSS_SHA384]),
88        (SignatureScheme::RSA_PSS_SHA256, &[RSA_PSS_SHA256]),
89        (SignatureScheme::RSA_PKCS1_SHA512, &[RSA_PKCS1_SHA512]),
90        (SignatureScheme::RSA_PKCS1_SHA384, &[RSA_PKCS1_SHA384]),
91        (SignatureScheme::RSA_PKCS1_SHA256, &[RSA_PKCS1_SHA256]),
92    ],
93};
94
95static AVAILABLE_SIG_ALGS: Lazy<&'static WebPkiSupportedAlgorithms> = Lazy::new(|| {
96    // ED25519 won't be available on fips enabled OpenSSL < 3.4.
97    if ed25519_available() {
98        &SUPPORTED_SIG_ALGS
99    } else {
100        &SUPPORTED_SIG_ALGS_NO_ED25519
101    }
102});
103
104static ED25519_AVAILABLE: Lazy<bool> = Lazy::new(|| PKey::generate_ed25519().is_ok());
105
106pub(crate) fn available_supported_sig_algs() -> &'static WebPkiSupportedAlgorithms {
107    *AVAILABLE_SIG_ALGS
108}
109
110pub(crate) fn ed25519_available() -> bool {
111    *ED25519_AVAILABLE
112}
113
114/// RSA PKCS#1 1.5 signatures using SHA-256.
115pub(crate) static RSA_PKCS1_SHA256: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
116    display_name: "RSA_PKCS1_SHA256",
117    public_key_alg_id: alg_id::RSA_ENCRYPTION,
118    signature_alg_id: alg_id::RSA_PKCS1_SHA256,
119};
120
121/// RSA PKCS#1 1.5 signatures using SHA-384.
122pub(crate) static RSA_PKCS1_SHA384: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
123    display_name: "RSA_PKCS1_SHA384",
124    public_key_alg_id: alg_id::RSA_ENCRYPTION,
125    signature_alg_id: alg_id::RSA_PKCS1_SHA384,
126};
127
128/// RSA PKCS#1 1.5 signatures using SHA-512.
129pub(crate) static RSA_PKCS1_SHA512: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
130    display_name: "RSA_PKCS1_SHA512",
131    public_key_alg_id: alg_id::RSA_ENCRYPTION,
132    signature_alg_id: alg_id::RSA_PKCS1_SHA512,
133};
134
135/// RSA PSS signatures using SHA-256.
136pub(crate) static RSA_PSS_SHA256: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
137    display_name: "RSA_PSS_SHA256",
138    public_key_alg_id: alg_id::RSA_ENCRYPTION,
139    signature_alg_id: alg_id::RSA_PSS_SHA256,
140};
141
142/// RSA PSS signatures using SHA-384.
143pub(crate) static RSA_PSS_SHA384: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
144    display_name: "RSA_PSS_SHA384",
145    public_key_alg_id: alg_id::RSA_ENCRYPTION,
146    signature_alg_id: alg_id::RSA_PSS_SHA384,
147};
148
149/// RSA PSS signatures using SHA-512.
150pub(crate) static RSA_PSS_SHA512: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
151    display_name: "RSA_PSS_SHA512",
152    public_key_alg_id: alg_id::RSA_ENCRYPTION,
153    signature_alg_id: alg_id::RSA_PSS_SHA512,
154};
155
156/// ED25519 signatures according to RFC 8410
157pub(crate) static ED25519: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
158    display_name: "ED25519",
159    public_key_alg_id: alg_id::ED25519,
160    signature_alg_id: alg_id::ED25519,
161};
162
163/// ECDSA signatures using the P-256 curve and SHA-256.
164pub(crate) static ECDSA_P256_SHA256: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
165    display_name: "ECDSA_P256_SHA256",
166    public_key_alg_id: alg_id::ECDSA_P256,
167    signature_alg_id: alg_id::ECDSA_SHA256,
168};
169
170/// ECDSA signatures using the P-256 curve and SHA-384. Deprecated.
171pub(crate) static ECDSA_P256_SHA384: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
172    display_name: "ECDSA_P256_SHA384",
173    public_key_alg_id: alg_id::ECDSA_P256,
174    signature_alg_id: alg_id::ECDSA_SHA384,
175};
176
177/// ECDSA signatures using the P-384 curve and SHA-256. Deprecated.
178pub(crate) static ECDSA_P384_SHA256: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
179    display_name: "ECDSA_P384_SHA256",
180    public_key_alg_id: alg_id::ECDSA_P384,
181    signature_alg_id: alg_id::ECDSA_SHA256,
182};
183
184/// ECDSA signatures using the P-384 curve and SHA-384.
185pub(crate) static ECDSA_P384_SHA384: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
186    display_name: "ECDSA_P384_SHA384",
187    public_key_alg_id: alg_id::ECDSA_P384,
188    signature_alg_id: alg_id::ECDSA_SHA384,
189};
190
191/// ECDSA signatures using the P-521 curve and SHA-256.
192pub(crate) static ECDSA_P521_SHA256: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
193    display_name: "ECDSA_P521_SHA256",
194    public_key_alg_id: alg_id::ECDSA_P521,
195    signature_alg_id: alg_id::ECDSA_SHA256,
196};
197
198/// ECDSA signatures using the P-521 curve and SHA-384.
199pub(crate) static ECDSA_P521_SHA384: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
200    display_name: "ECDSA_P521_SHA384",
201    public_key_alg_id: alg_id::ECDSA_P521,
202    signature_alg_id: alg_id::ECDSA_SHA384,
203};
204
205/// ECDSA signatures using the P-521 curve and SHA-512.
206pub(crate) static ECDSA_P521_SHA512: &dyn SignatureVerificationAlgorithm = &OpenSslAlgorithm {
207    display_name: "ECDSA_P521_SHA512",
208    public_key_alg_id: alg_id::ECDSA_P521,
209    signature_alg_id: alg_id::ECDSA_SHA512,
210};
211
212struct OpenSslAlgorithm {
213    display_name: &'static str,
214    public_key_alg_id: AlgorithmIdentifier,
215    signature_alg_id: AlgorithmIdentifier,
216}
217
218impl fmt::Debug for OpenSslAlgorithm {
219    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220        write!(
221            f,
222            "rustls_openssl Signature Verification Algorithm: {}",
223            self.display_name
224        )
225    }
226}
227
228fn ecdsa_public_key(curve_name: Nid, public_key: &[u8]) -> Result<PKey<Public>, InvalidSignature> {
229    EcGroup::from_curve_name(curve_name)
230        .and_then(|group| {
231            let mut ctx = BigNumContext::new()?;
232            let point = EcPoint::from_bytes(&group, public_key, &mut ctx)?;
233            let key = EcKey::from_public_key(&group, &point)?;
234            key.try_into()
235        })
236        .map_err(|_| InvalidSignature)
237}
238
239impl OpenSslAlgorithm {
240    fn public_key(&self, public_key: &[u8]) -> Result<PKey<Public>, InvalidSignature> {
241        match self.public_key_alg_id {
242            alg_id::RSA_ENCRYPTION => Rsa::public_key_from_der_pkcs1(public_key)
243                .and_then(std::convert::TryInto::try_into)
244                .map_err(|_| InvalidSignature),
245            alg_id::ECDSA_P521 => ecdsa_public_key(Nid::SECP521R1, public_key),
246            alg_id::ECDSA_P384 => ecdsa_public_key(Nid::SECP384R1, public_key),
247            alg_id::ECDSA_P256 => ecdsa_public_key(Nid::X9_62_PRIME256V1, public_key),
248            alg_id::ED25519 => PKey::public_key_from_raw_bytes(public_key, Id::ED25519)
249                .map_err(|_| InvalidSignature),
250
251            _ => Err(InvalidSignature),
252        }
253    }
254
255    fn message_digest(&self) -> Option<MessageDigest> {
256        match self.signature_alg_id {
257            alg_id::RSA_PKCS1_SHA256 | alg_id::ECDSA_SHA256 | alg_id::RSA_PSS_SHA256 => {
258                Some(MessageDigest::sha256())
259            }
260            alg_id::RSA_PKCS1_SHA384 | alg_id::ECDSA_SHA384 | alg_id::RSA_PSS_SHA384 => {
261                Some(MessageDigest::sha384())
262            }
263            alg_id::RSA_PKCS1_SHA512 | alg_id::ECDSA_SHA512 | alg_id::RSA_PSS_SHA512 => {
264                Some(MessageDigest::sha512())
265            }
266            _ => None,
267        }
268    }
269
270    fn mgf1(&self) -> Option<MessageDigest> {
271        match self.signature_alg_id {
272            alg_id::RSA_PSS_SHA256 => Some(MessageDigest::sha256()),
273            alg_id::RSA_PSS_SHA384 => Some(MessageDigest::sha384()),
274            alg_id::RSA_PSS_SHA512 => Some(MessageDigest::sha512()),
275            _ => None,
276        }
277    }
278
279    fn pss_salt_len(&self) -> Option<RsaPssSaltlen> {
280        match self.signature_alg_id {
281            alg_id::RSA_PSS_SHA256 | alg_id::RSA_PSS_SHA384 | alg_id::RSA_PSS_SHA512 => {
282                Some(RsaPssSaltlen::DIGEST_LENGTH)
283            }
284            _ => None,
285        }
286    }
287
288    fn rsa_padding(&self) -> Option<Padding> {
289        match self.signature_alg_id {
290            alg_id::RSA_PSS_SHA512 | alg_id::RSA_PSS_SHA384 | alg_id::RSA_PSS_SHA256 => {
291                Some(Padding::PKCS1_PSS)
292            }
293            alg_id::RSA_PKCS1_SHA512 | alg_id::RSA_PKCS1_SHA384 | alg_id::RSA_PKCS1_SHA256 => {
294                Some(Padding::PKCS1)
295            }
296            _ => None,
297        }
298    }
299}
300
301impl SignatureVerificationAlgorithm for OpenSslAlgorithm {
302    fn public_key_alg_id(&self) -> AlgorithmIdentifier {
303        self.public_key_alg_id
304    }
305
306    fn signature_alg_id(&self) -> AlgorithmIdentifier {
307        self.signature_alg_id
308    }
309
310    fn verify_signature(
311        &self,
312        public_key: &[u8],
313        message: &[u8],
314        signature: &[u8],
315    ) -> Result<(), InvalidSignature> {
316        if matches!(
317            self.public_key_alg_id,
318            alg_id::ECDSA_P256 | alg_id::ECDSA_P384 | alg_id::ECDSA_P521
319        ) {
320            // Restrict the allowed encodings of EC public keys.
321            //
322            // "The first octet of the OCTET STRING indicates whether the key is
323            //  compressed or uncompressed.  The uncompressed form is indicated
324            //  by 0x04 and the compressed form is indicated by either 0x02 or
325            //  0x03 (see 2.3.3 in [SEC1]).  The public key MUST be rejected if
326            //  any other value is included in the first octet."
327            // -- <https://datatracker.ietf.org/doc/html/rfc5480#section-2.2>
328            match public_key.first() {
329                Some(0x02..=0x04) => {}
330                _ => {
331                    return Err(InvalidSignature);
332                }
333            };
334        }
335        let pkey = self.public_key(public_key)?;
336
337        if let Some(message_digest) = self.message_digest() {
338            Verifier::new(message_digest, &pkey).and_then(|mut verifier| {
339                if let Some(padding) = self.rsa_padding() {
340                    verifier.set_rsa_padding(padding)?;
341                }
342                if let Some(mgf1_md) = self.mgf1() {
343                    verifier.set_rsa_mgf1_md(mgf1_md)?;
344                }
345                if let Some(salt_len) = self.pss_salt_len() {
346                    verifier.set_rsa_pss_saltlen(salt_len)?;
347                }
348                verifier.update(message)?;
349                verifier.verify(signature)
350            })
351        } else {
352            Verifier::new_without_digest(&pkey)
353                .and_then(|mut verifier| verifier.verify_oneshot(signature, message))
354        }
355        .map_err(|e| {
356            std::dbg!(e);
357            InvalidSignature
358        })
359        .and_then(|valid| if valid { Ok(()) } else { Err(InvalidSignature) })
360    }
361
362    fn fips(&self) -> bool {
363        crate::fips::enabled()
364    }
365}
366
367#[cfg(test)]
368mod tests {
369    use super::*;
370
371    #[test]
372    fn test_open_ssl_algorithm_debug() {
373        assert_eq!(
374            format!("{:?}", ECDSA_P256_SHA256),
375            "rustls_openssl Signature Verification Algorithm: ECDSA_P256_SHA256"
376        );
377        assert_eq!(
378            format!("{:?}", RSA_PSS_SHA256),
379            "rustls_openssl Signature Verification Algorithm: RSA_PSS_SHA256"
380        );
381    }
382}