1use 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
31pub 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 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 pub fn min_modulus_len(&self) -> u32 {
173 *self.2.start()
174 }
175
176 #[must_use]
177 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)]
211pub 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#[allow(clippy::module_name_repetitions)]
244pub trait RsaEncoding: 'static + Sync + Sealed + Debug {
245 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}