Skip to main content

webpki/
aws_lc_rs_algs.rs

1use aws_lc_rs::{signature, try_fips_mode};
2use pki_types::{AlgorithmIdentifier, InvalidSignature, SignatureVerificationAlgorithm, alg_id};
3
4// nb. aws-lc-rs has an API that is broadly compatible with *ring*,
5// so this is very similar to ring_algs.rs.
6
7/// A `SignatureVerificationAlgorithm` implemented using aws-lc-rs.
8#[derive(Debug)]
9struct AwsLcRsAlgorithm {
10    public_key_alg_id: AlgorithmIdentifier,
11    signature_alg_id: AlgorithmIdentifier,
12    verification_alg: &'static dyn signature::VerificationAlgorithm,
13    in_fips_submission: bool,
14}
15
16impl SignatureVerificationAlgorithm for AwsLcRsAlgorithm {
17    fn public_key_alg_id(&self) -> AlgorithmIdentifier {
18        self.public_key_alg_id
19    }
20
21    fn signature_alg_id(&self) -> AlgorithmIdentifier {
22        self.signature_alg_id
23    }
24
25    fn verify_signature(
26        &self,
27        public_key: &[u8],
28        message: &[u8],
29        signature: &[u8],
30    ) -> Result<(), InvalidSignature> {
31        if matches!(
32            self.public_key_alg_id,
33            alg_id::ECDSA_P256 | alg_id::ECDSA_P384 | alg_id::ECDSA_P521
34        ) {
35            // Restrict the allowed encodings of EC public keys.
36            //
37            // "The first octet of the OCTET STRING indicates whether the key is
38            //  compressed or uncompressed.  The uncompressed form is indicated
39            //  by 0x04 and the compressed form is indicated by either 0x02 or
40            //  0x03 (see 2.3.3 in [SEC1]).  The public key MUST be rejected if
41            //  any other value is included in the first octet."
42            // -- <https://datatracker.ietf.org/doc/html/rfc5480#section-2.2>
43            match public_key.first() {
44                Some(0x04) | Some(0x02) | Some(0x03) => {}
45                _ => return Err(InvalidSignature),
46            };
47        }
48        signature::UnparsedPublicKey::new(self.verification_alg, public_key)
49            .verify(message, signature)
50            .map_err(|_| InvalidSignature)
51    }
52
53    fn fips(&self) -> bool {
54        self.in_fips_submission && try_fips_mode().is_ok()
55    }
56}
57
58/// ML-DSA signatures using the [4, 4] matrix (security strength category 2).
59pub static ML_DSA_44: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
60    public_key_alg_id: alg_id::ML_DSA_44,
61    signature_alg_id: alg_id::ML_DSA_44,
62    verification_alg: &signature::ML_DSA_44,
63    // Not included in AWS-LC-FIPS 3.0 FIPS scope
64    in_fips_submission: false,
65};
66
67/// ML-DSA signatures using the [6, 5] matrix (security strength category 3).
68pub static ML_DSA_65: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
69    public_key_alg_id: alg_id::ML_DSA_65,
70    signature_alg_id: alg_id::ML_DSA_65,
71    verification_alg: &signature::ML_DSA_65,
72    // Not included in AWS-LC-FIPS 3.0 FIPS scope
73    in_fips_submission: false,
74};
75
76/// ML-DSA signatures using the [8. 7] matrix (security strength category 5).
77pub static ML_DSA_87: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
78    public_key_alg_id: alg_id::ML_DSA_87,
79    signature_alg_id: alg_id::ML_DSA_87,
80    verification_alg: &signature::ML_DSA_87,
81    // Not included in AWS-LC-FIPS 3.0 FIPS scope
82    in_fips_submission: false,
83};
84
85/// ECDSA signatures using the P-256 curve and SHA-256.
86pub static ECDSA_P256_SHA256: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
87    public_key_alg_id: alg_id::ECDSA_P256,
88    signature_alg_id: alg_id::ECDSA_SHA256,
89    verification_alg: &signature::ECDSA_P256_SHA256_ASN1,
90    in_fips_submission: true,
91};
92
93/// ECDSA signatures using the P-256 curve and SHA-384. Deprecated.
94pub static ECDSA_P256_SHA384: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
95    public_key_alg_id: alg_id::ECDSA_P256,
96    signature_alg_id: alg_id::ECDSA_SHA384,
97    verification_alg: &signature::ECDSA_P256_SHA384_ASN1,
98    in_fips_submission: true,
99};
100
101/// ECDSA signatures using the P-256 curve and SHA-512. Deprecated.
102pub static ECDSA_P256_SHA512: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
103    public_key_alg_id: alg_id::ECDSA_P256,
104    signature_alg_id: alg_id::ECDSA_SHA512,
105    verification_alg: &signature::ECDSA_P256_SHA512_ASN1,
106    in_fips_submission: true,
107};
108
109/// ECDSA signatures using the P-384 curve and SHA-256. Deprecated.
110pub static ECDSA_P384_SHA256: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
111    public_key_alg_id: alg_id::ECDSA_P384,
112    signature_alg_id: alg_id::ECDSA_SHA256,
113    verification_alg: &signature::ECDSA_P384_SHA256_ASN1,
114    in_fips_submission: true,
115};
116
117/// ECDSA signatures using the P-384 curve and SHA-384.
118pub static ECDSA_P384_SHA384: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
119    public_key_alg_id: alg_id::ECDSA_P384,
120    signature_alg_id: alg_id::ECDSA_SHA384,
121    verification_alg: &signature::ECDSA_P384_SHA384_ASN1,
122    in_fips_submission: true,
123};
124
125/// ECDSA signatures using the P-384 curve and SHA-512. Deprecated.
126pub static ECDSA_P384_SHA512: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
127    public_key_alg_id: alg_id::ECDSA_P384,
128    signature_alg_id: alg_id::ECDSA_SHA512,
129    verification_alg: &signature::ECDSA_P384_SHA512_ASN1,
130    in_fips_submission: true,
131};
132
133/// ECDSA signatures using the P-521 curve and SHA-256.
134pub static ECDSA_P521_SHA256: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
135    public_key_alg_id: alg_id::ECDSA_P521,
136    signature_alg_id: alg_id::ECDSA_SHA256,
137    verification_alg: &signature::ECDSA_P521_SHA256_ASN1,
138    in_fips_submission: true,
139};
140
141/// ECDSA signatures using the P-521 curve and SHA-384.
142pub static ECDSA_P521_SHA384: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
143    public_key_alg_id: alg_id::ECDSA_P521,
144    signature_alg_id: alg_id::ECDSA_SHA384,
145    verification_alg: &signature::ECDSA_P521_SHA384_ASN1,
146    in_fips_submission: true,
147};
148
149/// ECDSA signatures using the P-521 curve and SHA-512.
150pub static ECDSA_P521_SHA512: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
151    public_key_alg_id: alg_id::ECDSA_P521,
152    signature_alg_id: alg_id::ECDSA_SHA512,
153    verification_alg: &signature::ECDSA_P521_SHA512_ASN1,
154    in_fips_submission: true,
155};
156
157/// RSA PKCS#1 1.5 signatures using SHA-256 for keys of 2048-8192 bits.
158pub static RSA_PKCS1_2048_8192_SHA256: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
159    public_key_alg_id: alg_id::RSA_ENCRYPTION,
160    signature_alg_id: alg_id::RSA_PKCS1_SHA256,
161    verification_alg: &signature::RSA_PKCS1_2048_8192_SHA256,
162    in_fips_submission: true,
163};
164
165/// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 2048-8192 bits.
166pub static RSA_PKCS1_2048_8192_SHA384: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
167    public_key_alg_id: alg_id::RSA_ENCRYPTION,
168    signature_alg_id: alg_id::RSA_PKCS1_SHA384,
169    verification_alg: &signature::RSA_PKCS1_2048_8192_SHA384,
170    in_fips_submission: true,
171};
172
173/// RSA PKCS#1 1.5 signatures using SHA-512 for keys of 2048-8192 bits.
174pub static RSA_PKCS1_2048_8192_SHA512: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
175    public_key_alg_id: alg_id::RSA_ENCRYPTION,
176    signature_alg_id: alg_id::RSA_PKCS1_SHA512,
177    verification_alg: &signature::RSA_PKCS1_2048_8192_SHA512,
178    in_fips_submission: true,
179};
180
181/// RSA PKCS#1 1.5 signatures using SHA-256 for keys of 2048-8192 bits,
182/// with illegally absent AlgorithmIdentifier parameters.
183///
184/// RFC4055 says on sha256WithRSAEncryption and company:
185///
186/// >   When any of these four object identifiers appears within an
187/// >   AlgorithmIdentifier, the parameters MUST be NULL.  Implementations
188/// >   MUST accept the parameters being absent as well as present.
189///
190/// This algorithm covers the absent case, [`RSA_PKCS1_2048_8192_SHA256`] covers
191/// the present case.
192pub static RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS: &dyn SignatureVerificationAlgorithm =
193    &AwsLcRsAlgorithm {
194        public_key_alg_id: alg_id::RSA_ENCRYPTION,
195        signature_alg_id: alg_id::AlgorithmIdentifier::from_slice(include_bytes!(
196            "data/alg-rsa-pkcs1-sha256-absent-params.der"
197        )),
198        verification_alg: &signature::RSA_PKCS1_2048_8192_SHA256,
199        in_fips_submission: true,
200    };
201
202/// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 2048-8192 bits,
203/// with illegally absent AlgorithmIdentifier parameters.
204///
205/// RFC4055 says on sha256WithRSAEncryption and company:
206///
207/// >   When any of these four object identifiers appears within an
208/// >   AlgorithmIdentifier, the parameters MUST be NULL.  Implementations
209/// >   MUST accept the parameters being absent as well as present.
210///
211/// This algorithm covers the absent case, [`RSA_PKCS1_2048_8192_SHA384`] covers
212/// the present case.
213pub static RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS: &dyn SignatureVerificationAlgorithm =
214    &AwsLcRsAlgorithm {
215        public_key_alg_id: alg_id::RSA_ENCRYPTION,
216        signature_alg_id: alg_id::AlgorithmIdentifier::from_slice(include_bytes!(
217            "data/alg-rsa-pkcs1-sha384-absent-params.der"
218        )),
219        verification_alg: &signature::RSA_PKCS1_2048_8192_SHA384,
220        in_fips_submission: true,
221    };
222
223/// RSA PKCS#1 1.5 signatures using SHA-512 for keys of 2048-8192 bits,
224/// with illegally absent AlgorithmIdentifier parameters.
225///
226/// RFC4055 says on sha256WithRSAEncryption and company:
227///
228/// >   When any of these four object identifiers appears within an
229/// >   AlgorithmIdentifier, the parameters MUST be NULL.  Implementations
230/// >   MUST accept the parameters being absent as well as present.
231///
232/// This algorithm covers the absent case, [`RSA_PKCS1_2048_8192_SHA512`] covers
233/// the present case.
234pub static RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS: &dyn SignatureVerificationAlgorithm =
235    &AwsLcRsAlgorithm {
236        public_key_alg_id: alg_id::RSA_ENCRYPTION,
237        signature_alg_id: alg_id::AlgorithmIdentifier::from_slice(include_bytes!(
238            "data/alg-rsa-pkcs1-sha512-absent-params.der"
239        )),
240        verification_alg: &signature::RSA_PKCS1_2048_8192_SHA512,
241        in_fips_submission: true,
242    };
243
244/// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 3072-8192 bits.
245pub static RSA_PKCS1_3072_8192_SHA384: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
246    public_key_alg_id: alg_id::RSA_ENCRYPTION,
247    signature_alg_id: alg_id::RSA_PKCS1_SHA384,
248    verification_alg: &signature::RSA_PKCS1_3072_8192_SHA384,
249    in_fips_submission: true,
250};
251
252/// RSA PSS signatures using SHA-256 for keys of 2048-8192 bits and of
253/// type rsaEncryption; see [RFC 4055 Section 1.2].
254///
255/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
256pub static RSA_PSS_2048_8192_SHA256_LEGACY_KEY: &dyn SignatureVerificationAlgorithm =
257    &AwsLcRsAlgorithm {
258        public_key_alg_id: alg_id::RSA_ENCRYPTION,
259        signature_alg_id: alg_id::RSA_PSS_SHA256,
260        verification_alg: &signature::RSA_PSS_2048_8192_SHA256,
261        in_fips_submission: true,
262    };
263
264/// RSA PSS signatures using SHA-384 for keys of 2048-8192 bits and of
265/// type rsaEncryption; see [RFC 4055 Section 1.2].
266///
267/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
268pub static RSA_PSS_2048_8192_SHA384_LEGACY_KEY: &dyn SignatureVerificationAlgorithm =
269    &AwsLcRsAlgorithm {
270        public_key_alg_id: alg_id::RSA_ENCRYPTION,
271        signature_alg_id: alg_id::RSA_PSS_SHA384,
272        verification_alg: &signature::RSA_PSS_2048_8192_SHA384,
273        in_fips_submission: true,
274    };
275
276/// RSA PSS signatures using SHA-512 for keys of 2048-8192 bits and of
277/// type rsaEncryption; see [RFC 4055 Section 1.2].
278///
279/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
280pub static RSA_PSS_2048_8192_SHA512_LEGACY_KEY: &dyn SignatureVerificationAlgorithm =
281    &AwsLcRsAlgorithm {
282        public_key_alg_id: alg_id::RSA_ENCRYPTION,
283        signature_alg_id: alg_id::RSA_PSS_SHA512,
284        verification_alg: &signature::RSA_PSS_2048_8192_SHA512,
285        in_fips_submission: true,
286    };
287
288/// ED25519 signatures according to RFC 8410
289pub static ED25519: &dyn SignatureVerificationAlgorithm = &AwsLcRsAlgorithm {
290    public_key_alg_id: alg_id::ED25519,
291    signature_alg_id: alg_id::ED25519,
292    verification_alg: &signature::ED25519,
293    in_fips_submission: true,
294};
295
296#[cfg(test)]
297#[path = "."]
298mod tests {
299    use crate::error::{
300        Error, UnsupportedSignatureAlgorithmContext,
301        UnsupportedSignatureAlgorithmForPublicKeyContext,
302    };
303
304    static SUPPORTED_ALGORITHMS_IN_TESTS: &[&dyn super::SignatureVerificationAlgorithm] = &[
305        // Reasonable algorithms.
306        super::ECDSA_P256_SHA256,
307        super::ECDSA_P384_SHA384,
308        super::ECDSA_P521_SHA256,
309        super::ECDSA_P521_SHA384,
310        super::ECDSA_P521_SHA512,
311        super::ED25519,
312        super::RSA_PKCS1_2048_8192_SHA256,
313        super::RSA_PKCS1_2048_8192_SHA384,
314        super::RSA_PKCS1_2048_8192_SHA512,
315        super::RSA_PKCS1_3072_8192_SHA384,
316        super::RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
317        super::RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
318        super::RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
319        // Algorithms deprecated because they are nonsensical combinations.
320        super::ECDSA_P256_SHA384, // Truncates digest.
321        super::ECDSA_P384_SHA256, // Digest is unnecessarily short.
322        super::ML_DSA_44,
323        super::ML_DSA_65,
324        super::ML_DSA_87,
325    ];
326
327    const OK_IF_POINT_COMPRESSION_SUPPORTED: Result<(), Error> = Ok(());
328
329    #[path = "alg_tests.rs"]
330    mod alg_tests;
331
332    fn maybe_rsa() -> Result<(), Error> {
333        Ok(())
334    }
335
336    fn unsupported_for_rsa(_sig_alg_id: &[u8], _public_key_alg_id: &[u8]) -> Error {
337        Error::UnsupportedSignatureAlgorithmForPublicKeyContext(
338            UnsupportedSignatureAlgorithmForPublicKeyContext {
339                #[cfg(feature = "alloc")]
340                signature_algorithm_id: _sig_alg_id.to_vec(),
341                #[cfg(feature = "alloc")]
342                public_key_algorithm_id: _public_key_alg_id.to_vec(),
343            },
344        )
345    }
346
347    fn invalid_rsa_signature() -> Error {
348        Error::InvalidSignatureForPublicKey
349    }
350
351    fn unsupported_for_ecdsa(_sig_alg_id: &[u8], _public_key_alg_id: &[u8]) -> Error {
352        Error::UnsupportedSignatureAlgorithmForPublicKeyContext(
353            UnsupportedSignatureAlgorithmForPublicKeyContext {
354                #[cfg(feature = "alloc")]
355                signature_algorithm_id: _sig_alg_id.to_vec(),
356                #[cfg(feature = "alloc")]
357                public_key_algorithm_id: _public_key_alg_id.to_vec(),
358            },
359        )
360    }
361
362    fn unsupported(_sig_alg_id: &[u8]) -> Error {
363        Error::UnsupportedSignatureAlgorithmContext(UnsupportedSignatureAlgorithmContext {
364            #[cfg(feature = "alloc")]
365            signature_algorithm_id: _sig_alg_id.to_vec(),
366            #[cfg(feature = "alloc")]
367            supported_algorithms: SUPPORTED_ALGORITHMS_IN_TESTS
368                .iter()
369                .map(|&alg| alg.signature_alg_id())
370                .collect(),
371        })
372    }
373}