aws_lc_rs/rsa/
signature.rs1use 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, RSA_bits, EVP_PKEY,
9 EVP_PKEY_CTX, RSA_PKCS1_PSS_PADDING, RSA_PSS_SALTLEN_DIGEST,
10};
11
12use crate::digest::{self};
13use crate::error::Unspecified;
14use crate::ptr::LcPtr;
15use crate::sealed::Sealed;
16use crate::signature::VerificationAlgorithm;
17
18use super::encoding;
19#[cfg(feature = "ring-sig-verify")]
20use untrusted::Input;
21
22#[allow(non_camel_case_types)]
23#[allow(clippy::module_name_repetitions)]
24#[derive(Debug)]
25pub enum RsaPadding {
26 RSA_PKCS1_PADDING,
27 RSA_PKCS1_PSS_PADDING,
28}
29
30pub struct RsaParameters(
32 &'static digest::Algorithm,
33 &'static RsaPadding,
34 RangeInclusive<u32>,
35 &'static RsaVerificationAlgorithmId,
36);
37
38impl RsaParameters {
39 #[inline]
40 pub(crate) fn digest_algorithm(&self) -> &'static digest::Algorithm {
41 self.0
42 }
43
44 #[inline]
45 pub(crate) fn padding(&self) -> &'static RsaPadding {
46 self.1
47 }
48
49 #[inline]
50 pub(crate) fn bit_size_range(&self) -> &RangeInclusive<u32> {
51 &self.2
52 }
53}
54
55impl VerificationAlgorithm for RsaParameters {
56 #[cfg(feature = "ring-sig-verify")]
57 fn verify(
58 &self,
59 public_key: Input<'_>,
60 msg: Input<'_>,
61 signature: Input<'_>,
62 ) -> Result<(), Unspecified> {
63 self.verify_sig(
64 public_key.as_slice_less_safe(),
65 msg.as_slice_less_safe(),
66 signature.as_slice_less_safe(),
67 )
68 }
69
70 fn verify_sig(
71 &self,
72 public_key: &[u8],
73 msg: &[u8],
74 signature: &[u8],
75 ) -> Result<(), Unspecified> {
76 let evp_pkey = encoding::rfc8017::decode_public_key_der(public_key)?;
77 verify_rsa_signature(
78 self.digest_algorithm(),
79 self.padding(),
80 &evp_pkey,
81 msg,
82 signature,
83 self.bit_size_range(),
84 )
85 }
86}
87
88impl Sealed for RsaParameters {}
89
90impl Debug for RsaParameters {
91 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
92 f.write_str(&format!("{{ {:?} }}", self.3))
93 }
94}
95
96impl RsaParameters {
97 pub(crate) const fn new(
98 digest_alg: &'static digest::Algorithm,
99 padding: &'static RsaPadding,
100 range: RangeInclusive<u32>,
101 verification_alg: &'static RsaVerificationAlgorithmId,
102 ) -> Self {
103 Self(digest_alg, padding, range, verification_alg)
104 }
105
106 pub fn public_modulus_len(public_key: &[u8]) -> Result<u32, Unspecified> {
111 let rsa = encoding::rfc8017::decode_public_key_der(public_key)?;
112 Ok(unsafe { RSA_bits(*rsa.get_rsa()?) })
113 }
114
115 #[must_use]
116 pub fn min_modulus_len(&self) -> u32 {
118 *self.2.start()
119 }
120
121 #[must_use]
122 pub fn max_modulus_len(&self) -> u32 {
124 *self.2.end()
125 }
126}
127
128#[derive(Debug)]
129#[allow(non_camel_case_types)]
130pub(crate) enum RsaVerificationAlgorithmId {
131 RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
132 RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
133 RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY,
134 RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY,
135 RSA_PKCS1_2048_8192_SHA256,
136 RSA_PKCS1_2048_8192_SHA384,
137 RSA_PKCS1_2048_8192_SHA512,
138 RSA_PKCS1_3072_8192_SHA384,
139 RSA_PSS_2048_8192_SHA256,
140 RSA_PSS_2048_8192_SHA384,
141 RSA_PSS_2048_8192_SHA512,
142}
143
144#[derive(Debug)]
145#[allow(non_camel_case_types)]
146pub(crate) enum RsaSigningAlgorithmId {
147 RSA_PSS_SHA256,
148 RSA_PSS_SHA384,
149 RSA_PSS_SHA512,
150 RSA_PKCS1_SHA256,
151 RSA_PKCS1_SHA384,
152 RSA_PKCS1_SHA512,
153}
154
155#[allow(clippy::module_name_repetitions)]
156pub struct RsaSignatureEncoding(
157 &'static digest::Algorithm,
158 &'static RsaPadding,
159 &'static RsaSigningAlgorithmId,
160);
161
162impl RsaSignatureEncoding {
163 pub(crate) const fn new(
164 digest_alg: &'static digest::Algorithm,
165 padding: &'static RsaPadding,
166 sig_alg: &'static RsaSigningAlgorithmId,
167 ) -> Self {
168 Self(digest_alg, padding, sig_alg)
169 }
170
171 #[inline]
172 pub(super) fn digest_algorithm(&self) -> &'static digest::Algorithm {
173 self.0
174 }
175
176 #[inline]
177 pub(super) fn padding(&self) -> &'static RsaPadding {
178 self.1
179 }
180}
181
182impl Sealed for RsaSignatureEncoding {}
183
184#[allow(clippy::module_name_repetitions)]
188pub trait RsaEncoding: 'static + Sync + Sealed + Debug {
189 fn encoding(&'static self) -> &'static RsaSignatureEncoding;
191}
192
193impl RsaEncoding for RsaSignatureEncoding {
194 fn encoding(&'static self) -> &'static RsaSignatureEncoding {
195 self
196 }
197}
198
199impl Debug for RsaSignatureEncoding {
200 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
201 f.write_str(&format!("{{ {:?} }}", self.2))
202 }
203}
204
205#[inline]
206pub(crate) fn configure_rsa_pkcs1_pss_padding(pctx: *mut EVP_PKEY_CTX) -> Result<(), ()> {
207 if 1 != unsafe { EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) } {
208 return Err(());
209 }
210 if 1 != unsafe { EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST) } {
211 return Err(());
212 }
213 Ok(())
214}
215
216#[inline]
217pub(crate) fn verify_rsa_signature(
218 algorithm: &'static digest::Algorithm,
219 padding: &'static RsaPadding,
220 public_key: &LcPtr<EVP_PKEY>,
221 msg: &[u8],
222 signature: &[u8],
223 allowed_bit_size: &RangeInclusive<u32>,
224) -> Result<(), Unspecified> {
225 if !allowed_bit_size.contains(&public_key.key_size_bits().try_into()?) {
226 return Err(Unspecified);
227 }
228
229 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = padding {
230 Some(configure_rsa_pkcs1_pss_padding)
231 } else {
232 None
233 };
234
235 public_key.verify(msg, Some(algorithm), padding_fn, signature)
236}