1use std::ffi::c_int;
5use std::fmt::{self, Debug, Formatter};
6use std::ops::RangeInclusive;
7
8use crate::aws_lc::{
9 EVP_PKEY_CTX_set_rsa_padding, EVP_PKEY_CTX_set_rsa_pss_saltlen, EVP_PKEY_CTX_set_signature_md,
10 RSA_bits, EVP_PKEY, EVP_PKEY_CTX, RSA_PKCS1_PSS_PADDING, RSA_PSS_SALTLEN_DIGEST,
11};
12
13use crate::digest::{self, match_digest_type, Digest};
14use crate::error::Unspecified;
15use crate::ptr::LcPtr;
16use crate::rsa::key::parse_rsa_public_key;
17use crate::sealed::Sealed;
18use crate::signature::{ParsedPublicKey, ParsedVerificationAlgorithm, VerificationAlgorithm};
19
20use super::encoding;
21#[cfg(feature = "ring-sig-verify")]
22use untrusted::Input;
23
24#[allow(non_camel_case_types)]
25#[allow(clippy::module_name_repetitions)]
26#[derive(Debug, Eq, PartialEq)]
27pub enum RsaPadding {
28 RSA_PKCS1_PADDING,
29 RSA_PKCS1_PSS_PADDING,
30}
31
32#[allow(clippy::module_name_repetitions)]
42#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
43#[non_exhaustive]
44pub enum RsaPssSaltLength {
45 #[default]
49 Digest,
50 Max,
60 Custom(u16),
65}
66
67impl RsaPssSaltLength {
68 pub(crate) fn into_value(
69 self,
70 algorithm: &'static digest::Algorithm,
71 pkey: &LcPtr<EVP_PKEY>,
72 ) -> Result<c_int, ()> {
73 match self {
74 RsaPssSaltLength::Digest => Ok(RSA_PSS_SALTLEN_DIGEST),
75 RsaPssSaltLength::Max => {
76 let digest_len = u16::try_from(algorithm.output_len()).map_err(|_| ())?;
77 let pkey_size_bits =
78 u16::try_from(pkey.as_const().key_size_bits()).map_err(|_| ())?;
79 let em_len = pkey_size_bits.checked_add(6).ok_or(())? / 8;
80 let max_len = em_len
81 .checked_sub(digest_len)
82 .ok_or(())?
83 .checked_sub(2)
84 .ok_or(())?;
85 Ok(max_len.into())
86 }
87 RsaPssSaltLength::Custom(val) => Ok(val.into()),
88 }
89 }
90}
91
92#[derive(Eq, PartialEq)]
99pub struct RsaParameters {
100 digest_alg: &'static digest::Algorithm,
101 padding: &'static RsaPadding,
102 pss_salt_length: RsaPssSaltLength,
103 range: RangeInclusive<u32>,
104 verification_alg: &'static RsaVerificationAlgorithmId,
105}
106
107impl RsaParameters {
108 #[inline]
109 pub(crate) fn digest_algorithm(&self) -> &'static digest::Algorithm {
110 self.digest_alg
111 }
112
113 #[inline]
114 pub(crate) fn padding(&self) -> &'static RsaPadding {
115 self.padding
116 }
117
118 #[inline]
119 pub(crate) fn pss_salt_length(&self) -> RsaPssSaltLength {
120 self.pss_salt_length
121 }
122
123 #[inline]
124 pub(crate) fn bit_size_range(&self) -> &RangeInclusive<u32> {
125 &self.range
126 }
127}
128
129impl ParsedVerificationAlgorithm for RsaParameters {
130 fn parsed_verify_sig(
131 &self,
132 public_key: &ParsedPublicKey,
133 msg: &[u8],
134 signature: &[u8],
135 ) -> Result<(), Unspecified> {
136 let evp_pkey = public_key.key();
137 verify_rsa_signature(
138 self.digest_algorithm(),
139 self.padding(),
140 self.pss_salt_length,
141 evp_pkey,
142 msg,
143 signature,
144 self.bit_size_range(),
145 )
146 }
147
148 fn parsed_verify_digest_sig(
149 &self,
150 public_key: &ParsedPublicKey,
151 digest: &Digest,
152 signature: &[u8],
153 ) -> Result<(), Unspecified> {
154 let evp_pkey = public_key.key();
155 verify_rsa_digest_signature(
156 self.digest_algorithm(),
157 self.padding(),
158 self.pss_salt_length,
159 evp_pkey,
160 digest,
161 signature,
162 self.bit_size_range(),
163 )
164 }
165}
166
167impl VerificationAlgorithm for RsaParameters {
168 #[cfg(feature = "ring-sig-verify")]
169 fn verify(
170 &self,
171 public_key: Input<'_>,
172 msg: Input<'_>,
173 signature: Input<'_>,
174 ) -> Result<(), Unspecified> {
175 self.verify_sig(
176 public_key.as_slice_less_safe(),
177 msg.as_slice_less_safe(),
178 signature.as_slice_less_safe(),
179 )
180 }
181
182 fn verify_sig(
183 &self,
184 public_key: &[u8],
185 msg: &[u8],
186 signature: &[u8],
187 ) -> Result<(), Unspecified> {
188 let evp_pkey = parse_rsa_public_key(public_key)?;
189 verify_rsa_signature(
190 self.digest_algorithm(),
191 self.padding(),
192 self.pss_salt_length,
193 &evp_pkey,
194 msg,
195 signature,
196 self.bit_size_range(),
197 )
198 }
199
200 fn verify_digest_sig(
201 &self,
202 public_key: &[u8],
203 digest: &Digest,
204 signature: &[u8],
205 ) -> Result<(), Unspecified> {
206 let evp_pkey = parse_rsa_public_key(public_key)?;
207 verify_rsa_digest_signature(
208 self.digest_algorithm(),
209 self.padding(),
210 self.pss_salt_length,
211 &evp_pkey,
212 digest,
213 signature,
214 self.bit_size_range(),
215 )
216 }
217}
218
219impl Sealed for RsaParameters {}
220
221impl Debug for RsaParameters {
222 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
223 write!(f, "{{ {:?}", self.verification_alg)?;
224
225 if self.pss_salt_length != RsaPssSaltLength::Digest {
226 write!(f, ", RSA-PSS salt length: {:?}", self.pss_salt_length)?;
227 }
228
229 write!(f, " }}")?;
230 Ok(())
231 }
232}
233
234impl RsaParameters {
235 pub(crate) const fn new(
236 digest_alg: &'static digest::Algorithm,
237 padding: &'static RsaPadding,
238 range: RangeInclusive<u32>,
239 verification_alg: &'static RsaVerificationAlgorithmId,
240 ) -> Self {
241 Self {
242 digest_alg,
243 padding,
244 range,
245 verification_alg,
246 pss_salt_length: RsaPssSaltLength::Digest,
247 }
248 }
249
250 #[must_use]
268 pub const fn with_pss_salt_length(mut self, saltlen: RsaPssSaltLength) -> Self {
269 self.pss_salt_length = saltlen;
270 self
271 }
272
273 pub fn public_modulus_len(public_key: &[u8]) -> Result<u32, Unspecified> {
278 let rsa = encoding::rfc8017::decode_public_key_der(public_key)?;
279 Ok(unsafe { RSA_bits(rsa.as_const().get_rsa()?.as_const_ptr()) })
280 }
281
282 #[must_use]
283 pub fn min_modulus_len(&self) -> u32 {
285 *self.range.start()
286 }
287
288 #[must_use]
289 pub fn max_modulus_len(&self) -> u32 {
291 *self.range.end()
292 }
293}
294
295#[derive(Debug, Eq, PartialEq)]
296#[allow(non_camel_case_types)]
297pub(crate) enum RsaVerificationAlgorithmId {
298 RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
299 RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
300 RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY,
301 RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY,
302 RSA_PKCS1_2048_8192_SHA256,
303 RSA_PKCS1_2048_8192_SHA384,
304 RSA_PKCS1_2048_8192_SHA512,
305 RSA_PKCS1_3072_8192_SHA384,
306 RSA_PSS_2048_8192_SHA256,
307 RSA_PSS_2048_8192_SHA384,
308 RSA_PSS_2048_8192_SHA512,
309}
310
311#[derive(Debug)]
312#[allow(non_camel_case_types)]
313pub(crate) enum RsaSigningAlgorithmId {
314 RSA_PSS_SHA256,
315 RSA_PSS_SHA384,
316 RSA_PSS_SHA512,
317 RSA_PKCS1_SHA256,
318 RSA_PKCS1_SHA384,
319 RSA_PKCS1_SHA512,
320}
321
322#[allow(clippy::module_name_repetitions)]
323pub struct RsaSignatureEncoding {
325 digest_alg: &'static digest::Algorithm,
326 padding: &'static RsaPadding,
327 pss_salt_length: RsaPssSaltLength,
328 sig_alg: &'static RsaSigningAlgorithmId,
329}
330
331impl RsaSignatureEncoding {
332 pub(crate) const fn new(
333 digest_alg: &'static digest::Algorithm,
334 padding: &'static RsaPadding,
335 sig_alg: &'static RsaSigningAlgorithmId,
336 ) -> Self {
337 Self {
338 digest_alg,
339 padding,
340 sig_alg,
341 pss_salt_length: RsaPssSaltLength::Digest,
342 }
343 }
344
345 #[inline]
346 pub(super) fn digest_algorithm(&self) -> &'static digest::Algorithm {
347 self.digest_alg
348 }
349
350 #[inline]
351 pub(super) fn padding(&self) -> &'static RsaPadding {
352 self.padding
353 }
354
355 #[inline]
356 pub(super) fn pss_salt_length(&self) -> RsaPssSaltLength {
357 self.pss_salt_length
358 }
359
360 #[must_use]
378 pub const fn with_pss_salt_length(mut self, saltlen: RsaPssSaltLength) -> Self {
379 self.pss_salt_length = saltlen;
380 self
381 }
382}
383
384impl Sealed for RsaSignatureEncoding {}
385
386#[allow(clippy::module_name_repetitions)]
390pub trait RsaEncoding: 'static + Sync + Sealed + Debug {
391 fn encoding(&'static self) -> &'static RsaSignatureEncoding;
393}
394
395impl RsaEncoding for RsaSignatureEncoding {
396 fn encoding(&'static self) -> &'static RsaSignatureEncoding {
397 self
398 }
399}
400
401impl Debug for RsaSignatureEncoding {
402 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
403 write!(f, "{{ {:?}", self.sig_alg)?;
404
405 if self.pss_salt_length != RsaPssSaltLength::Digest {
406 write!(f, ", RSA-PSS salt length: {:?}", self.pss_salt_length)?;
407 }
408
409 write!(f, " }}")?;
410 Ok(())
411 }
412}
413
414#[inline]
415pub(crate) fn configure_rsa_pkcs1_pss_padding(
416 pctx: *mut EVP_PKEY_CTX,
417 saltlen: RsaPssSaltLength,
418 algorithm: &'static digest::Algorithm,
419 pkey: &LcPtr<EVP_PKEY>,
420) -> Result<(), ()> {
421 if 1 != unsafe { EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) } {
422 return Err(());
423 }
424
425 let saltlen = saltlen.into_value(algorithm, pkey)?;
426
427 if 1 != unsafe { EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, saltlen) } {
428 return Err(());
429 }
430
431 Ok(())
432}
433
434#[inline]
435pub(crate) fn verify_rsa_signature(
436 algorithm: &'static digest::Algorithm,
437 padding: &'static RsaPadding,
438 pss_salt_length: RsaPssSaltLength,
439 public_key: &LcPtr<EVP_PKEY>,
440 msg: &[u8],
441 signature: &[u8],
442 allowed_bit_size: &RangeInclusive<u32>,
443) -> Result<(), Unspecified> {
444 if !allowed_bit_size.contains(&public_key.as_const().key_size_bits().try_into()?) {
445 return Err(Unspecified);
446 }
447
448 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = padding {
449 Some(|pctx: *mut EVP_PKEY_CTX| {
450 configure_rsa_pkcs1_pss_padding(pctx, pss_salt_length, algorithm, public_key)
451 })
452 } else {
453 None
454 };
455
456 public_key.verify(msg, Some(algorithm), padding_fn, signature)
457}
458
459#[inline]
460pub(crate) fn verify_rsa_digest_signature(
461 algorithm: &'static digest::Algorithm,
462 padding: &'static RsaPadding,
463 pss_salt_length: RsaPssSaltLength,
464 public_key: &LcPtr<EVP_PKEY>,
465 digest: &Digest,
466 signature: &[u8],
467 allowed_bit_size: &RangeInclusive<u32>,
468) -> Result<(), Unspecified> {
469 if algorithm != digest.algorithm() {
471 return Err(Unspecified);
472 }
473
474 if !allowed_bit_size.contains(&public_key.as_const().key_size_bits().try_into()?) {
475 return Err(Unspecified);
476 }
477
478 let padding_fn = Some({
479 |pctx: *mut EVP_PKEY_CTX| {
480 let evp_md = match_digest_type(&digest.algorithm().id);
481 if 1 != unsafe { EVP_PKEY_CTX_set_signature_md(pctx, evp_md.as_const_ptr()) } {
482 return Err(());
483 }
484 if let RsaPadding::RSA_PKCS1_PSS_PADDING = padding {
485 configure_rsa_pkcs1_pss_padding(pctx, pss_salt_length, algorithm, public_key)
486 } else {
487 Ok(())
488 }
489 }
490 });
491
492 public_key.verify_digest_sig(digest, padding_fn, signature)
493}