webpki/
ring_algs.rs

1// Copyright 2015 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use pki_types::{AlgorithmIdentifier, InvalidSignature, SignatureVerificationAlgorithm, alg_id};
16use ring::signature;
17
18/// A `SignatureVerificationAlgorithm` implemented using *ring*.
19#[derive(Debug)]
20struct RingAlgorithm {
21    public_key_alg_id: AlgorithmIdentifier,
22    signature_alg_id: AlgorithmIdentifier,
23    verification_alg: &'static dyn signature::VerificationAlgorithm,
24}
25
26impl SignatureVerificationAlgorithm for RingAlgorithm {
27    fn public_key_alg_id(&self) -> AlgorithmIdentifier {
28        self.public_key_alg_id
29    }
30
31    fn signature_alg_id(&self) -> AlgorithmIdentifier {
32        self.signature_alg_id
33    }
34
35    fn verify_signature(
36        &self,
37        public_key: &[u8],
38        message: &[u8],
39        signature: &[u8],
40    ) -> Result<(), InvalidSignature> {
41        signature::UnparsedPublicKey::new(self.verification_alg, public_key)
42            .verify(message, signature)
43            .map_err(|_| InvalidSignature)
44    }
45}
46
47/// ECDSA signatures using the P-256 curve and SHA-256.
48pub static ECDSA_P256_SHA256: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
49    public_key_alg_id: alg_id::ECDSA_P256,
50    signature_alg_id: alg_id::ECDSA_SHA256,
51    verification_alg: &signature::ECDSA_P256_SHA256_ASN1,
52};
53
54/// ECDSA signatures using the P-256 curve and SHA-384. Deprecated.
55pub static ECDSA_P256_SHA384: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
56    public_key_alg_id: alg_id::ECDSA_P256,
57    signature_alg_id: alg_id::ECDSA_SHA384,
58    verification_alg: &signature::ECDSA_P256_SHA384_ASN1,
59};
60
61/// ECDSA signatures using the P-384 curve and SHA-256. Deprecated.
62pub static ECDSA_P384_SHA256: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
63    public_key_alg_id: alg_id::ECDSA_P384,
64    signature_alg_id: alg_id::ECDSA_SHA256,
65    verification_alg: &signature::ECDSA_P384_SHA256_ASN1,
66};
67
68/// ECDSA signatures using the P-384 curve and SHA-384.
69pub static ECDSA_P384_SHA384: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
70    public_key_alg_id: alg_id::ECDSA_P384,
71    signature_alg_id: alg_id::ECDSA_SHA384,
72    verification_alg: &signature::ECDSA_P384_SHA384_ASN1,
73};
74
75/// RSA PKCS#1 1.5 signatures using SHA-256 for keys of 2048-8192 bits.
76#[cfg(feature = "alloc")]
77pub static RSA_PKCS1_2048_8192_SHA256: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
78    public_key_alg_id: alg_id::RSA_ENCRYPTION,
79    signature_alg_id: alg_id::RSA_PKCS1_SHA256,
80    verification_alg: &signature::RSA_PKCS1_2048_8192_SHA256,
81};
82
83/// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 2048-8192 bits.
84#[cfg(feature = "alloc")]
85pub static RSA_PKCS1_2048_8192_SHA384: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
86    public_key_alg_id: alg_id::RSA_ENCRYPTION,
87    signature_alg_id: alg_id::RSA_PKCS1_SHA384,
88    verification_alg: &signature::RSA_PKCS1_2048_8192_SHA384,
89};
90
91/// RSA PKCS#1 1.5 signatures using SHA-512 for keys of 2048-8192 bits.
92#[cfg(feature = "alloc")]
93pub static RSA_PKCS1_2048_8192_SHA512: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
94    public_key_alg_id: alg_id::RSA_ENCRYPTION,
95    signature_alg_id: alg_id::RSA_PKCS1_SHA512,
96    verification_alg: &signature::RSA_PKCS1_2048_8192_SHA512,
97};
98
99/// RSA PKCS#1 1.5 signatures using SHA-256 for keys of 2048-8192 bits,
100/// with illegally absent AlgorithmIdentifier parameters.
101///
102/// RFC4055 says on sha256WithRSAEncryption and company:
103///
104/// >   When any of these four object identifiers appears within an
105/// >   AlgorithmIdentifier, the parameters MUST be NULL.  Implementations
106/// >   MUST accept the parameters being absent as well as present.
107///
108/// This algorithm covers the absent case, [`RSA_PKCS1_2048_8192_SHA256`] covers
109/// the present case.
110#[cfg(feature = "alloc")]
111pub static RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS: &dyn SignatureVerificationAlgorithm =
112    &RingAlgorithm {
113        public_key_alg_id: alg_id::RSA_ENCRYPTION,
114        signature_alg_id: alg_id::AlgorithmIdentifier::from_slice(include_bytes!(
115            "data/alg-rsa-pkcs1-sha256-absent-params.der"
116        )),
117        verification_alg: &signature::RSA_PKCS1_2048_8192_SHA256,
118    };
119
120/// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 2048-8192 bits,
121/// with illegally absent AlgorithmIdentifier parameters.
122///
123/// RFC4055 says on sha256WithRSAEncryption and company:
124///
125/// >   When any of these four object identifiers appears within an
126/// >   AlgorithmIdentifier, the parameters MUST be NULL.  Implementations
127/// >   MUST accept the parameters being absent as well as present.
128///
129/// This algorithm covers the absent case, [`RSA_PKCS1_2048_8192_SHA384`] covers
130/// the present case.
131#[cfg(feature = "alloc")]
132pub static RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS: &dyn SignatureVerificationAlgorithm =
133    &RingAlgorithm {
134        public_key_alg_id: alg_id::RSA_ENCRYPTION,
135        signature_alg_id: alg_id::AlgorithmIdentifier::from_slice(include_bytes!(
136            "data/alg-rsa-pkcs1-sha384-absent-params.der"
137        )),
138        verification_alg: &signature::RSA_PKCS1_2048_8192_SHA384,
139    };
140
141/// RSA PKCS#1 1.5 signatures using SHA-512 for keys of 2048-8192 bits,
142/// with illegally absent AlgorithmIdentifier parameters.
143///
144/// RFC4055 says on sha256WithRSAEncryption and company:
145///
146/// >   When any of these four object identifiers appears within an
147/// >   AlgorithmIdentifier, the parameters MUST be NULL.  Implementations
148/// >   MUST accept the parameters being absent as well as present.
149///
150/// This algorithm covers the absent case, [`RSA_PKCS1_2048_8192_SHA512`] covers
151/// the present case.
152#[cfg(feature = "alloc")]
153pub static RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS: &dyn SignatureVerificationAlgorithm =
154    &RingAlgorithm {
155        public_key_alg_id: alg_id::RSA_ENCRYPTION,
156        signature_alg_id: alg_id::AlgorithmIdentifier::from_slice(include_bytes!(
157            "data/alg-rsa-pkcs1-sha512-absent-params.der"
158        )),
159        verification_alg: &signature::RSA_PKCS1_2048_8192_SHA512,
160    };
161
162/// RSA PKCS#1 1.5 signatures using SHA-384 for keys of 3072-8192 bits.
163#[cfg(feature = "alloc")]
164pub static RSA_PKCS1_3072_8192_SHA384: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
165    public_key_alg_id: alg_id::RSA_ENCRYPTION,
166    signature_alg_id: alg_id::RSA_PKCS1_SHA384,
167    verification_alg: &signature::RSA_PKCS1_3072_8192_SHA384,
168};
169
170/// RSA PSS signatures using SHA-256 for keys of 2048-8192 bits and of
171/// type rsaEncryption; see [RFC 4055 Section 1.2].
172///
173/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
174#[cfg(feature = "alloc")]
175pub static RSA_PSS_2048_8192_SHA256_LEGACY_KEY: &dyn SignatureVerificationAlgorithm =
176    &RingAlgorithm {
177        public_key_alg_id: alg_id::RSA_ENCRYPTION,
178        signature_alg_id: alg_id::RSA_PSS_SHA256,
179        verification_alg: &signature::RSA_PSS_2048_8192_SHA256,
180    };
181
182/// RSA PSS signatures using SHA-384 for keys of 2048-8192 bits and of
183/// type rsaEncryption; see [RFC 4055 Section 1.2].
184///
185/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
186#[cfg(feature = "alloc")]
187pub static RSA_PSS_2048_8192_SHA384_LEGACY_KEY: &dyn SignatureVerificationAlgorithm =
188    &RingAlgorithm {
189        public_key_alg_id: alg_id::RSA_ENCRYPTION,
190        signature_alg_id: alg_id::RSA_PSS_SHA384,
191        verification_alg: &signature::RSA_PSS_2048_8192_SHA384,
192    };
193
194/// RSA PSS signatures using SHA-512 for keys of 2048-8192 bits and of
195/// type rsaEncryption; see [RFC 4055 Section 1.2].
196///
197/// [RFC 4055 Section 1.2]: https://tools.ietf.org/html/rfc4055#section-1.2
198#[cfg(feature = "alloc")]
199pub static RSA_PSS_2048_8192_SHA512_LEGACY_KEY: &dyn SignatureVerificationAlgorithm =
200    &RingAlgorithm {
201        public_key_alg_id: alg_id::RSA_ENCRYPTION,
202        signature_alg_id: alg_id::RSA_PSS_SHA512,
203        verification_alg: &signature::RSA_PSS_2048_8192_SHA512,
204    };
205
206/// ED25519 signatures according to RFC 8410
207pub static ED25519: &dyn SignatureVerificationAlgorithm = &RingAlgorithm {
208    public_key_alg_id: alg_id::ED25519,
209    signature_alg_id: alg_id::ED25519,
210    verification_alg: &signature::ED25519,
211};
212
213#[cfg(test)]
214#[path = "."]
215mod tests {
216    #[cfg(feature = "alloc")]
217    use crate::error::UnsupportedSignatureAlgorithmForPublicKeyContext;
218    use crate::error::{Error, UnsupportedSignatureAlgorithmContext};
219
220    static SUPPORTED_ALGORITHMS_IN_TESTS: &[&dyn super::SignatureVerificationAlgorithm] = &[
221        // Reasonable algorithms.
222        super::ECDSA_P256_SHA256,
223        super::ECDSA_P384_SHA384,
224        super::ED25519,
225        #[cfg(feature = "alloc")]
226        super::RSA_PKCS1_2048_8192_SHA256,
227        #[cfg(feature = "alloc")]
228        super::RSA_PKCS1_2048_8192_SHA384,
229        #[cfg(feature = "alloc")]
230        super::RSA_PKCS1_2048_8192_SHA512,
231        #[cfg(feature = "alloc")]
232        super::RSA_PKCS1_3072_8192_SHA384,
233        #[cfg(feature = "alloc")]
234        super::RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
235        #[cfg(feature = "alloc")]
236        super::RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
237        #[cfg(feature = "alloc")]
238        super::RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
239        // Algorithms deprecated because they are nonsensical combinations.
240        super::ECDSA_P256_SHA384, // Truncates digest.
241        super::ECDSA_P384_SHA256, // Digest is unnecessarily short.
242    ];
243
244    const OK_IF_POINT_COMPRESSION_SUPPORTED: Result<(), Error> =
245        Err(Error::InvalidSignatureForPublicKey);
246
247    #[path = "alg_tests.rs"]
248    mod alg_tests;
249
250    fn maybe_rsa() -> Result<(), Error> {
251        #[cfg(feature = "alloc")]
252        {
253            Ok(())
254        }
255        #[cfg(not(feature = "alloc"))]
256        {
257            Err(unsupported(&[]))
258        }
259    }
260
261    fn unsupported_for_rsa(sig_alg_id: &[u8], _public_key_alg_id: &[u8]) -> Error {
262        #[cfg(feature = "alloc")]
263        {
264            Error::UnsupportedSignatureAlgorithmForPublicKeyContext(
265                UnsupportedSignatureAlgorithmForPublicKeyContext {
266                    signature_algorithm_id: sig_alg_id.to_vec(),
267                    public_key_algorithm_id: _public_key_alg_id.to_vec(),
268                },
269            )
270        }
271        #[cfg(not(feature = "alloc"))]
272        {
273            unsupported(sig_alg_id)
274        }
275    }
276
277    fn invalid_rsa_signature() -> Error {
278        #[cfg(feature = "alloc")]
279        {
280            Error::InvalidSignatureForPublicKey
281        }
282        #[cfg(not(feature = "alloc"))]
283        {
284            unsupported(&[])
285        }
286    }
287
288    fn unsupported_for_ecdsa(sig_alg_id: &[u8], _public_key_alg_id: &[u8]) -> Error {
289        unsupported(sig_alg_id)
290    }
291
292    fn unsupported(_sig_alg_id: &[u8]) -> Error {
293        Error::UnsupportedSignatureAlgorithmContext(UnsupportedSignatureAlgorithmContext {
294            #[cfg(feature = "alloc")]
295            signature_algorithm_id: _sig_alg_id.to_vec(),
296            #[cfg(feature = "alloc")]
297            supported_algorithms: SUPPORTED_ALGORITHMS_IN_TESTS
298                .iter()
299                .map(|&alg| alg.signature_alg_id())
300                .collect(),
301        })
302    }
303}