aws_lc_rs/rsa/
signature.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4use std::fmt::{self, Debug, Formatter};
5use std::ops::RangeInclusive;
6
7use crate::aws_lc::{
8    EVP_PKEY_CTX_set_rsa_padding, EVP_PKEY_CTX_set_rsa_pss_saltlen, EVP_PKEY_CTX_set_signature_md,
9    RSA_bits, EVP_PKEY, EVP_PKEY_CTX, RSA_PKCS1_PSS_PADDING, RSA_PSS_SALTLEN_DIGEST,
10};
11
12use crate::digest::{self, match_digest_type, Digest};
13use crate::error::Unspecified;
14use crate::ptr::LcPtr;
15use crate::rsa::key::parse_rsa_public_key;
16use crate::sealed::Sealed;
17use crate::signature::{ParsedPublicKey, ParsedVerificationAlgorithm, VerificationAlgorithm};
18
19use super::encoding;
20#[cfg(feature = "ring-sig-verify")]
21use untrusted::Input;
22
23#[allow(non_camel_case_types)]
24#[allow(clippy::module_name_repetitions)]
25#[derive(Debug)]
26pub enum RsaPadding {
27    RSA_PKCS1_PADDING,
28    RSA_PKCS1_PSS_PADDING,
29}
30
31/// Parameters for RSA verification.
32pub struct RsaParameters(
33    &'static digest::Algorithm,
34    &'static RsaPadding,
35    RangeInclusive<u32>,
36    &'static RsaVerificationAlgorithmId,
37);
38
39impl RsaParameters {
40    #[inline]
41    pub(crate) fn digest_algorithm(&self) -> &'static digest::Algorithm {
42        self.0
43    }
44
45    #[inline]
46    pub(crate) fn padding(&self) -> &'static RsaPadding {
47        self.1
48    }
49
50    #[inline]
51    pub(crate) fn bit_size_range(&self) -> &RangeInclusive<u32> {
52        &self.2
53    }
54}
55
56impl ParsedVerificationAlgorithm for RsaParameters {
57    fn parsed_verify_sig(
58        &self,
59        public_key: &ParsedPublicKey,
60        msg: &[u8],
61        signature: &[u8],
62    ) -> Result<(), Unspecified> {
63        let evp_pkey = public_key.key();
64        verify_rsa_signature(
65            self.digest_algorithm(),
66            self.padding(),
67            evp_pkey,
68            msg,
69            signature,
70            self.bit_size_range(),
71        )
72    }
73
74    fn parsed_verify_digest_sig(
75        &self,
76        public_key: &ParsedPublicKey,
77        digest: &Digest,
78        signature: &[u8],
79    ) -> Result<(), Unspecified> {
80        let evp_pkey = public_key.key();
81        verify_rsa_digest_signature(
82            self.padding(),
83            evp_pkey,
84            digest,
85            signature,
86            self.bit_size_range(),
87        )
88    }
89}
90
91impl VerificationAlgorithm for RsaParameters {
92    #[cfg(feature = "ring-sig-verify")]
93    fn verify(
94        &self,
95        public_key: Input<'_>,
96        msg: Input<'_>,
97        signature: Input<'_>,
98    ) -> Result<(), Unspecified> {
99        self.verify_sig(
100            public_key.as_slice_less_safe(),
101            msg.as_slice_less_safe(),
102            signature.as_slice_less_safe(),
103        )
104    }
105
106    fn verify_sig(
107        &self,
108        public_key: &[u8],
109        msg: &[u8],
110        signature: &[u8],
111    ) -> Result<(), Unspecified> {
112        let evp_pkey = parse_rsa_public_key(public_key)?;
113        verify_rsa_signature(
114            self.digest_algorithm(),
115            self.padding(),
116            &evp_pkey,
117            msg,
118            signature,
119            self.bit_size_range(),
120        )
121    }
122
123    fn verify_digest_sig(
124        &self,
125        public_key: &[u8],
126        digest: &Digest,
127        signature: &[u8],
128    ) -> Result<(), Unspecified> {
129        if self.digest_algorithm() != digest.algorithm() {
130            return Err(Unspecified);
131        }
132        let evp_pkey = parse_rsa_public_key(public_key)?;
133        verify_rsa_digest_signature(
134            self.padding(),
135            &evp_pkey,
136            digest,
137            signature,
138            self.bit_size_range(),
139        )
140    }
141}
142
143impl Sealed for RsaParameters {}
144
145impl Debug for RsaParameters {
146    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
147        f.write_str(&format!("{{ {:?} }}", self.3))
148    }
149}
150
151impl RsaParameters {
152    pub(crate) const fn new(
153        digest_alg: &'static digest::Algorithm,
154        padding: &'static RsaPadding,
155        range: RangeInclusive<u32>,
156        verification_alg: &'static RsaVerificationAlgorithmId,
157    ) -> Self {
158        Self(digest_alg, padding, range, verification_alg)
159    }
160
161    /// Parses a DER-encoded `RSAPublicKey` structure (RFC 8017) to determine its size in bits.
162    ///
163    /// # Errors
164    /// `error::Unspecified` on parse error.
165    pub fn public_modulus_len(public_key: &[u8]) -> Result<u32, Unspecified> {
166        let rsa = encoding::rfc8017::decode_public_key_der(public_key)?;
167        Ok(unsafe { RSA_bits(*rsa.as_const().get_rsa()?) })
168    }
169
170    #[must_use]
171    /// Minimum modulus length in bits.
172    pub fn min_modulus_len(&self) -> u32 {
173        *self.2.start()
174    }
175
176    #[must_use]
177    /// Maximum modulus length in bits.
178    pub fn max_modulus_len(&self) -> u32 {
179        *self.2.end()
180    }
181}
182
183#[derive(Debug)]
184#[allow(non_camel_case_types)]
185pub(crate) enum RsaVerificationAlgorithmId {
186    RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
187    RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
188    RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY,
189    RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY,
190    RSA_PKCS1_2048_8192_SHA256,
191    RSA_PKCS1_2048_8192_SHA384,
192    RSA_PKCS1_2048_8192_SHA512,
193    RSA_PKCS1_3072_8192_SHA384,
194    RSA_PSS_2048_8192_SHA256,
195    RSA_PSS_2048_8192_SHA384,
196    RSA_PSS_2048_8192_SHA512,
197}
198
199#[derive(Debug)]
200#[allow(non_camel_case_types)]
201pub(crate) enum RsaSigningAlgorithmId {
202    RSA_PSS_SHA256,
203    RSA_PSS_SHA384,
204    RSA_PSS_SHA512,
205    RSA_PKCS1_SHA256,
206    RSA_PKCS1_SHA384,
207    RSA_PKCS1_SHA512,
208}
209
210#[allow(clippy::module_name_repetitions)]
211/// Encoding type for an RSA signature
212pub struct RsaSignatureEncoding(
213    &'static digest::Algorithm,
214    &'static RsaPadding,
215    &'static RsaSigningAlgorithmId,
216);
217
218impl RsaSignatureEncoding {
219    pub(crate) const fn new(
220        digest_alg: &'static digest::Algorithm,
221        padding: &'static RsaPadding,
222        sig_alg: &'static RsaSigningAlgorithmId,
223    ) -> Self {
224        Self(digest_alg, padding, sig_alg)
225    }
226
227    #[inline]
228    pub(super) fn digest_algorithm(&self) -> &'static digest::Algorithm {
229        self.0
230    }
231
232    #[inline]
233    pub(super) fn padding(&self) -> &'static RsaPadding {
234        self.1
235    }
236}
237
238impl Sealed for RsaSignatureEncoding {}
239
240/// An RSA signature encoding as described in [RFC 3447 Section 8].
241///
242/// [RFC 3447 Section 8]: https://tools.ietf.org/html/rfc3447#section-8
243#[allow(clippy::module_name_repetitions)]
244pub trait RsaEncoding: 'static + Sync + Sealed + Debug {
245    /// The signature encoding.
246    fn encoding(&'static self) -> &'static RsaSignatureEncoding;
247}
248
249impl RsaEncoding for RsaSignatureEncoding {
250    fn encoding(&'static self) -> &'static RsaSignatureEncoding {
251        self
252    }
253}
254
255impl Debug for RsaSignatureEncoding {
256    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
257        f.write_str(&format!("{{ {:?} }}", self.2))
258    }
259}
260
261#[inline]
262pub(crate) fn configure_rsa_pkcs1_pss_padding(pctx: *mut EVP_PKEY_CTX) -> Result<(), ()> {
263    if 1 != unsafe { EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) } {
264        return Err(());
265    }
266    if 1 != unsafe { EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST) } {
267        return Err(());
268    }
269    Ok(())
270}
271
272#[inline]
273pub(crate) fn verify_rsa_signature(
274    algorithm: &'static digest::Algorithm,
275    padding: &'static RsaPadding,
276    public_key: &LcPtr<EVP_PKEY>,
277    msg: &[u8],
278    signature: &[u8],
279    allowed_bit_size: &RangeInclusive<u32>,
280) -> Result<(), Unspecified> {
281    if !allowed_bit_size.contains(&public_key.as_const().key_size_bits().try_into()?) {
282        return Err(Unspecified);
283    }
284
285    let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = padding {
286        Some(configure_rsa_pkcs1_pss_padding)
287    } else {
288        None
289    };
290
291    public_key.verify(msg, Some(algorithm), padding_fn, signature)
292}
293
294#[inline]
295pub(crate) fn verify_rsa_digest_signature(
296    padding: &'static RsaPadding,
297    public_key: &LcPtr<EVP_PKEY>,
298    digest: &Digest,
299    signature: &[u8],
300    allowed_bit_size: &RangeInclusive<u32>,
301) -> Result<(), Unspecified> {
302    if !allowed_bit_size.contains(&public_key.as_const().key_size_bits().try_into()?) {
303        return Err(Unspecified);
304    }
305
306    let padding_fn = Some({
307        |pctx: *mut EVP_PKEY_CTX| {
308            let evp_md = match_digest_type(&digest.algorithm().id);
309            if 1 != unsafe { EVP_PKEY_CTX_set_signature_md(pctx, *evp_md) } {
310                return Err(());
311            }
312            if let RsaPadding::RSA_PKCS1_PSS_PADDING = padding {
313                configure_rsa_pkcs1_pss_padding(pctx)
314            } else {
315                Ok(())
316            }
317        }
318    });
319
320    public_key.verify_digest_sig(digest, padding_fn, signature)
321}