1use super::signature::{RsaEncoding, RsaPadding};
6use super::{encoding, RsaParameters};
7use crate::aws_lc::{
8 EVP_PKEY_CTX_set_rsa_keygen_bits, EVP_PKEY_CTX_set_signature_md, EVP_PKEY_assign_RSA,
9 EVP_PKEY_new, EVP_PKEY_set1_RSA, RSA_check_key, RSA_new, RSA_set0_crt_params, RSA_set0_factors,
10 RSA_set0_key, RSA_size, BIGNUM, EVP_PKEY, EVP_PKEY_CTX, EVP_PKEY_RSA, EVP_PKEY_RSA_PSS,
11};
12#[cfg(feature = "ring-io")]
13use crate::aws_lc::{RSA_get0_e, RSA_get0_n};
14use crate::encoding::{AsDer, Pkcs8V1Der, PublicKeyX509Der};
15use crate::error::{KeyRejected, Unspecified};
16#[cfg(feature = "ring-io")]
17use crate::io;
18use crate::ptr::{DetachableLcPtr, LcPtr};
19use crate::rsa::PublicEncryptingKey;
20use crate::sealed::Sealed;
21use crate::{hex, rand};
22#[cfg(feature = "fips")]
23use aws_lc::RSA_check_fips;
24use core::fmt::{self, Debug, Formatter};
25use core::ptr::null_mut;
26
27use std::os::raw::c_int;
30
31use crate::digest::{match_digest_type, Digest};
32use crate::pkcs8::Version;
33use crate::rsa::encoding::{rfc5280, rfc8017};
34use crate::rsa::signature::configure_rsa_pkcs1_pss_padding;
35#[cfg(feature = "ring-io")]
36use untrusted::Input;
37use zeroize::Zeroize;
38
39#[allow(clippy::module_name_repetitions)]
41#[non_exhaustive]
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub enum KeySize {
44 Rsa2048,
46
47 Rsa3072,
49
50 Rsa4096,
52
53 Rsa8192,
55}
56
57#[allow(clippy::len_without_is_empty)]
58impl KeySize {
59 #[inline]
61 #[must_use]
62 pub fn len(self) -> usize {
63 match self {
64 Self::Rsa2048 => 256,
65 Self::Rsa3072 => 384,
66 Self::Rsa4096 => 512,
67 Self::Rsa8192 => 1024,
68 }
69 }
70
71 #[inline]
73 pub(super) fn bits(self) -> i32 {
74 match self {
75 Self::Rsa2048 => 2048,
76 Self::Rsa3072 => 3072,
77 Self::Rsa4096 => 4096,
78 Self::Rsa8192 => 8192,
79 }
80 }
81}
82
83#[allow(clippy::module_name_repetitions)]
85pub struct KeyPair {
86 pub(super) evp_pkey: LcPtr<EVP_PKEY>,
93 pub(super) serialized_public_key: PublicKey,
94}
95
96impl Sealed for KeyPair {}
97unsafe impl Send for KeyPair {}
98unsafe impl Sync for KeyPair {}
99
100#[allow(non_snake_case)]
102#[derive(Clone, Copy)]
103pub struct KeyPairComponents<Public, Private = Public> {
104 pub public_key: PublicKeyComponents<Public>,
106
107 pub d: Private,
109
110 pub p: Private,
112
113 pub q: Private,
115
116 pub dP: Private,
118
119 pub dQ: Private,
121
122 pub qInv: Private,
124}
125
126#[allow(clippy::missing_fields_in_debug)]
128impl<Public, Private> Debug for KeyPairComponents<Public, Private>
129where
130 PublicKeyComponents<Public>: Debug,
131{
132 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
133 f.debug_struct("KeyPairComponents")
134 .field("public_key", &self.public_key)
135 .finish()
136 }
137}
138
139impl KeyPair {
140 fn new(evp_pkey: LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
141 KeyPair::validate_private_key(&evp_pkey)?;
142 let serialized_public_key = PublicKey::new(&evp_pkey)?;
143 Ok(KeyPair {
144 evp_pkey,
145 serialized_public_key,
146 })
147 }
148
149 pub fn generate(size: KeySize) -> Result<Self, Unspecified> {
160 let private_key = generate_rsa_key(size.bits())?;
161 Ok(Self::new(private_key)?)
162 }
163
164 #[cfg(feature = "fips")]
172 #[deprecated]
173 pub fn generate_fips(size: KeySize) -> Result<Self, Unspecified> {
174 Self::generate(size)
175 }
176
177 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
193 let key = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_RSA)?;
194 Self::new(key)
195 }
196
197 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
202 let key = encoding::rfc8017::decode_private_key_der(input)?;
203 Self::new(key)
204 }
205
206 #[cfg(feature = "fips")]
208 #[must_use]
209 pub fn is_valid_fips_key(&self) -> bool {
210 is_valid_fips_key(&self.evp_pkey)
211 }
212
213 fn validate_private_key(key: &LcPtr<EVP_PKEY>) -> Result<(), KeyRejected> {
214 validate_rsa_key(key)
215 }
216
217 pub fn sign(
237 &self,
238 padding_alg: &'static dyn RsaEncoding,
239 _rng: &dyn rand::SecureRandom,
240 msg: &[u8],
241 signature: &mut [u8],
242 ) -> Result<(), Unspecified> {
243 let encoding = padding_alg.encoding();
244 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
245 Some(configure_rsa_pkcs1_pss_padding)
246 } else {
247 None
248 };
249
250 let sig_bytes = self
251 .evp_pkey
252 .sign(msg, Some(encoding.digest_algorithm()), padding_fn)?;
253
254 signature.copy_from_slice(&sig_bytes);
255 Ok(())
256 }
257
258 pub fn sign_digest(
273 &self,
274 padding_alg: &'static dyn RsaEncoding,
275 digest: &Digest,
276 signature: &mut [u8],
277 ) -> Result<(), Unspecified> {
278 let encoding = padding_alg.encoding();
279 if encoding.digest_algorithm() != digest.algorithm() {
280 return Err(Unspecified);
281 }
282
283 let padding_fn = Some({
284 |pctx: *mut EVP_PKEY_CTX| {
285 let evp_md = match_digest_type(&digest.algorithm().id);
286 if 1 != unsafe { EVP_PKEY_CTX_set_signature_md(pctx, evp_md.as_const_ptr()) } {
287 return Err(());
288 }
289 if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
290 configure_rsa_pkcs1_pss_padding(pctx)
291 } else {
292 Ok(())
293 }
294 }
295 });
296
297 let sig_bytes = self.evp_pkey.sign_digest(digest, padding_fn)?;
298
299 signature.copy_from_slice(&sig_bytes);
300 Ok(())
301 }
302
303 #[must_use]
307 pub fn public_modulus_len(&self) -> usize {
308 match self.evp_pkey.as_const().get_rsa() {
310 Ok(rsa) => {
311 unsafe { RSA_size(rsa.as_const_ptr()) as usize }
313 }
314 Err(_) => unreachable!(),
315 }
316 }
317
318 #[allow(clippy::many_single_char_names, clippy::similar_names)]
357 pub fn from_components<Public, Private>(
358 components: &KeyPairComponents<Public, Private>,
359 ) -> Result<Self, KeyRejected>
360 where
361 Public: AsRef<[u8]>,
362 Private: AsRef<[u8]>,
363 {
364 let mut rsa = LcPtr::new(unsafe { RSA_new() })?;
365 let mut p = DetachableLcPtr::try_from(components.p.as_ref())?;
366 let mut q = DetachableLcPtr::try_from(components.q.as_ref())?;
367 if 1 != unsafe { RSA_set0_factors(rsa.as_mut_ptr(), p.as_mut_ptr(), q.as_mut_ptr()) } {
368 return Err(KeyRejected::unspecified());
369 }
370 p.detach();
371 q.detach();
372
373 let mut n = public_component_to_bn(components.public_key.n.as_ref())?;
374 let mut e = public_component_to_bn(components.public_key.e.as_ref())?;
375 let mut d = DetachableLcPtr::try_from(components.d.as_ref())?;
376 if 1 != unsafe {
377 RSA_set0_key(
378 rsa.as_mut_ptr(),
379 n.as_mut_ptr(),
380 e.as_mut_ptr(),
381 d.as_mut_ptr(),
382 )
383 } {
384 return Err(KeyRejected::unspecified());
385 }
386 n.detach();
387 e.detach();
388 d.detach();
389
390 let mut dmp1 = DetachableLcPtr::try_from(components.dP.as_ref())?;
391 let mut dmq1 = DetachableLcPtr::try_from(components.dQ.as_ref())?;
392 let mut iqmp = DetachableLcPtr::try_from(components.qInv.as_ref())?;
393 if 1 != unsafe {
394 RSA_set0_crt_params(
395 rsa.as_mut_ptr(),
396 dmp1.as_mut_ptr(),
397 dmq1.as_mut_ptr(),
398 iqmp.as_mut_ptr(),
399 )
400 } {
401 return Err(KeyRejected::unspecified());
402 }
403 dmp1.detach();
404 dmq1.detach();
405 iqmp.detach();
406
407 if 1 != unsafe { RSA_check_key(rsa.as_mut_ptr()) } {
408 return Err(KeyRejected::inconsistent_components());
409 }
410 let mut evp_pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
411 if 1 != unsafe { EVP_PKEY_set1_RSA(evp_pkey.as_mut_ptr(), rsa.as_mut_ptr()) } {
416 return Err(KeyRejected::unspecified());
417 }
418
419 Self::new(evp_pkey)
420 }
421}
422
423impl Debug for KeyPair {
424 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
425 f.write_str(&format!(
426 "RsaKeyPair {{ public_key: {:?} }}",
427 self.serialized_public_key
428 ))
429 }
430}
431
432impl crate::signature::KeyPair for KeyPair {
433 type PublicKey = PublicKey;
434
435 fn public_key(&self) -> &Self::PublicKey {
436 &self.serialized_public_key
437 }
438}
439
440impl AsDer<Pkcs8V1Der<'static>> for KeyPair {
441 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
442 Ok(Pkcs8V1Der::new(
443 self.evp_pkey
444 .as_const()
445 .marshal_rfc5208_private_key(Version::V1)?,
446 ))
447 }
448}
449
450#[derive(Clone)]
452#[allow(clippy::module_name_repetitions)]
453pub struct PublicKey {
454 key: Box<[u8]>,
455 #[cfg(feature = "ring-io")]
456 modulus: Box<[u8]>,
457 #[cfg(feature = "ring-io")]
458 exponent: Box<[u8]>,
459}
460
461impl Drop for PublicKey {
462 fn drop(&mut self) {
463 self.key.zeroize();
464 #[cfg(feature = "ring-io")]
465 self.modulus.zeroize();
466 #[cfg(feature = "ring-io")]
467 self.exponent.zeroize();
468 }
469}
470
471impl PublicKey {
472 pub(super) fn new(evp_pkey: &LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
473 let key = encoding::rfc8017::encode_public_key_der(evp_pkey)?;
474 #[cfg(feature = "ring-io")]
475 {
476 let evp_pkey = evp_pkey.as_const();
477 let pubkey = evp_pkey.get_rsa()?;
478 let modulus = pubkey
479 .project_const_lifetime(unsafe { |pubkey| RSA_get0_n(pubkey.as_const_ptr()) })?;
480 let modulus = modulus.to_be_bytes().into_boxed_slice();
481 let exponent = pubkey
482 .project_const_lifetime(unsafe { |pubkey| RSA_get0_e(pubkey.as_const_ptr()) })?;
483 let exponent = exponent.to_be_bytes().into_boxed_slice();
484 Ok(PublicKey {
485 key,
486 modulus,
487 exponent,
488 })
489 }
490
491 #[cfg(not(feature = "ring-io"))]
492 Ok(PublicKey { key })
493 }
494
495 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
499 PublicKey::new(
502 &rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))?,
503 )
504 }
505}
506
507pub(crate) fn parse_rsa_public_key(input: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
508 rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))
509}
510
511impl Debug for PublicKey {
512 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
513 f.write_str(&format!(
514 "RsaPublicKey(\"{}\")",
515 hex::encode(self.key.as_ref())
516 ))
517 }
518}
519
520impl AsRef<[u8]> for PublicKey {
521 fn as_ref(&self) -> &[u8] {
523 self.key.as_ref()
524 }
525}
526
527impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
528 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
529 let evp_pkey = rfc8017::decode_public_key_der(self.as_ref())?;
531 rfc5280::encode_public_key_der(&evp_pkey)
532 }
533}
534
535#[cfg(feature = "ring-io")]
536impl PublicKey {
537 #[must_use]
539 pub fn modulus(&self) -> io::Positive<'_> {
540 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.modulus.as_ref()))
541 }
542
543 #[must_use]
545 pub fn exponent(&self) -> io::Positive<'_> {
546 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.exponent.as_ref()))
547 }
548
549 #[must_use]
551 pub fn modulus_len(&self) -> usize {
552 self.modulus.len()
553 }
554}
555
556#[allow(clippy::module_name_repetitions)]
565#[derive(Clone)]
566pub struct PublicKeyComponents<B> {
567 pub n: B,
569 pub e: B,
571}
572
573impl<B: Debug> Debug for PublicKeyComponents<B> {
574 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
575 f.debug_struct("RsaPublicKeyComponents")
576 .field("n", &self.n)
577 .field("e", &self.e)
578 .finish()
579 }
580}
581
582impl<B: Copy> Copy for PublicKeyComponents<B> {}
583
584fn public_component_to_bn(bytes: &[u8]) -> Result<DetachableLcPtr<BIGNUM>, KeyRejected> {
590 if bytes.is_empty() || bytes[0] == 0u8 {
591 return Err(KeyRejected::invalid_encoding());
592 }
593 Ok(DetachableLcPtr::try_from(bytes)?)
594}
595
596impl<B> PublicKeyComponents<B>
597where
598 B: AsRef<[u8]>,
599{
600 #[inline]
601 fn build_rsa(&self) -> Result<LcPtr<EVP_PKEY>, ()> {
602 let mut n_bn = public_component_to_bn(self.n.as_ref()).map_err(|_| ())?;
603 let mut e_bn = public_component_to_bn(self.e.as_ref()).map_err(|_| ())?;
604
605 let mut rsa = DetachableLcPtr::new(unsafe { RSA_new() })?;
606 if 1 != unsafe {
607 RSA_set0_key(
608 rsa.as_mut_ptr(),
609 n_bn.as_mut_ptr(),
610 e_bn.as_mut_ptr(),
611 null_mut(),
612 )
613 } {
614 return Err(());
615 }
616 n_bn.detach();
617 e_bn.detach();
618
619 let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
620 if 1 != unsafe { EVP_PKEY_assign_RSA(pkey.as_mut_ptr(), rsa.as_mut_ptr()) } {
621 return Err(());
622 }
623 rsa.detach();
624
625 Ok(pkey)
626 }
627
628 pub fn verify(
636 &self,
637 params: &RsaParameters,
638 message: &[u8],
639 signature: &[u8],
640 ) -> Result<(), Unspecified> {
641 let rsa = self.build_rsa()?;
642 super::signature::verify_rsa_signature(
643 params.digest_algorithm(),
644 params.padding(),
645 &rsa,
646 message,
647 signature,
648 params.bit_size_range(),
649 )
650 }
651
652 pub fn to_parsed_public_key(
689 &self,
690 params: &'static RsaParameters,
691 ) -> Result<crate::signature::ParsedPublicKey, KeyRejected> {
692 let pkey = self
693 .build_rsa()
694 .map_err(|()| KeyRejected::inconsistent_components())?;
695 Ok(crate::signature::ParsedPublicKey::from_rsa_evp_pkey(
696 params, pkey,
697 )?)
698 }
699}
700
701#[cfg(feature = "ring-io")]
702impl From<&PublicKey> for PublicKeyComponents<Vec<u8>> {
703 fn from(public_key: &PublicKey) -> Self {
704 PublicKeyComponents {
705 n: public_key.modulus.to_vec(),
706 e: public_key.exponent.to_vec(),
707 }
708 }
709}
710
711impl<B> TryInto<PublicEncryptingKey> for PublicKeyComponents<B>
712where
713 B: AsRef<[u8]>,
714{
715 type Error = Unspecified;
716
717 fn try_into(self) -> Result<PublicEncryptingKey, Self::Error> {
722 let rsa = self.build_rsa()?;
723 Ok(PublicEncryptingKey::new(rsa)?)
724 }
725}
726
727impl<B> AsDer<PublicKeyX509Der<'static>> for PublicKeyComponents<B>
728where
729 B: AsRef<[u8]>,
730{
731 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
739 let pkey = self.build_rsa()?;
740 rfc5280::encode_public_key_der(&pkey)
741 }
742}
743
744pub(super) fn generate_rsa_key(size: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
745 let params_fn = |ctx| {
746 if 1 == unsafe { EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, size) } {
747 Ok(())
748 } else {
749 Err(())
750 }
751 };
752
753 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_RSA, Some(params_fn))
754}
755
756#[cfg(feature = "fips")]
757#[must_use]
758pub(super) fn is_valid_fips_key(key: &LcPtr<EVP_PKEY>) -> bool {
759 let evp_pkey = key.as_const();
761 let rsa_key = evp_pkey.get_rsa().expect("RSA EVP_PKEY");
762
763 1 == unsafe { RSA_check_fips((rsa_key.as_const_ptr()).cast_mut()) }
764}
765
766pub(super) fn is_rsa_key(key: &LcPtr<EVP_PKEY>) -> bool {
767 let id = key.as_const().id();
768 id == EVP_PKEY_RSA || id == EVP_PKEY_RSA_PSS
769}
770
771pub(super) fn validate_rsa_key(key: &LcPtr<EVP_PKEY>) -> Result<(), KeyRejected> {
772 if !is_rsa_key(key) {
773 return Err(KeyRejected::unspecified());
774 }
775 match key.as_const().key_size_bits() {
776 2048..=8192 => Ok(()),
777 0..=2047 => Err(KeyRejected::too_small()),
778 _ => Err(KeyRejected::too_large()),
779 }
780}