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#[derive(Clone)]
85#[allow(clippy::module_name_repetitions)]
86pub struct KeyPair {
87 pub(super) evp_pkey: LcPtr<EVP_PKEY>,
94 pub(super) serialized_public_key: PublicKey,
95}
96
97impl Sealed for KeyPair {}
98unsafe impl Send for KeyPair {}
99unsafe impl Sync for KeyPair {}
100
101#[allow(non_snake_case)]
103#[derive(Clone, Copy)]
104pub struct KeyPairComponents<Public, Private = Public> {
105 pub public_key: PublicKeyComponents<Public>,
107
108 pub d: Private,
110
111 pub p: Private,
113
114 pub q: Private,
116
117 pub dP: Private,
119
120 pub dQ: Private,
122
123 pub qInv: Private,
125}
126
127#[allow(clippy::missing_fields_in_debug)]
129impl<Public, Private> Debug for KeyPairComponents<Public, Private>
130where
131 PublicKeyComponents<Public>: Debug,
132{
133 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
134 f.debug_struct("KeyPairComponents")
135 .field("public_key", &self.public_key)
136 .finish()
137 }
138}
139
140impl KeyPair {
141 fn new(evp_pkey: LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
142 KeyPair::validate_private_key(&evp_pkey)?;
143 let serialized_public_key = PublicKey::new(&evp_pkey)?;
144 Ok(KeyPair {
145 evp_pkey,
146 serialized_public_key,
147 })
148 }
149
150 pub fn generate(size: KeySize) -> Result<Self, Unspecified> {
161 let private_key = generate_rsa_key(size.bits())?;
162 Ok(Self::new(private_key)?)
163 }
164
165 #[cfg(feature = "fips")]
173 #[deprecated(
174 since = "1.12.3",
175 note = "Equivalent to `KeyPair::generate`; use that instead."
176 )]
177 pub fn generate_fips(size: KeySize) -> Result<Self, Unspecified> {
178 Self::generate(size)
179 }
180
181 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
197 let key = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_RSA)?;
198 Self::new(key)
199 }
200
201 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
206 let key = encoding::rfc8017::decode_private_key_der(input)?;
207 Self::new(key)
208 }
209
210 #[cfg(feature = "fips")]
212 #[must_use]
213 pub fn is_valid_fips_key(&self) -> bool {
214 is_valid_fips_key(&self.evp_pkey)
215 }
216
217 fn validate_private_key(key: &LcPtr<EVP_PKEY>) -> Result<(), KeyRejected> {
218 validate_rsa_key(key)
219 }
220
221 pub fn sign(
241 &self,
242 padding_alg: &'static dyn RsaEncoding,
243 _rng: &dyn rand::SecureRandom,
244 msg: &[u8],
245 signature: &mut [u8],
246 ) -> Result<(), Unspecified> {
247 let encoding = padding_alg.encoding();
248 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
249 Some(|pctx: *mut EVP_PKEY_CTX| {
250 configure_rsa_pkcs1_pss_padding(
251 pctx,
252 encoding.pss_salt_length(),
253 encoding.digest_algorithm(),
254 &self.evp_pkey,
255 )
256 })
257 } else {
258 None
259 };
260
261 let sig_bytes = self
262 .evp_pkey
263 .sign(msg, Some(encoding.digest_algorithm()), padding_fn)?;
264
265 signature.copy_from_slice(&sig_bytes);
266 Ok(())
267 }
268
269 pub fn sign_digest(
284 &self,
285 padding_alg: &'static dyn RsaEncoding,
286 digest: &Digest,
287 signature: &mut [u8],
288 ) -> Result<(), Unspecified> {
289 let encoding = padding_alg.encoding();
290 if encoding.digest_algorithm() != digest.algorithm() {
291 return Err(Unspecified);
292 }
293
294 let padding_fn = Some({
295 |pctx: *mut EVP_PKEY_CTX| {
296 let evp_md = match_digest_type(&digest.algorithm().id);
297 if 1 != unsafe { EVP_PKEY_CTX_set_signature_md(pctx, evp_md.as_const_ptr()) } {
298 return Err(());
299 }
300 if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
301 configure_rsa_pkcs1_pss_padding(
302 pctx,
303 encoding.pss_salt_length(),
304 encoding.digest_algorithm(),
305 &self.evp_pkey,
306 )
307 } else {
308 Ok(())
309 }
310 }
311 });
312
313 let sig_bytes = self.evp_pkey.sign_digest(digest, padding_fn)?;
314
315 signature.copy_from_slice(&sig_bytes);
316 Ok(())
317 }
318
319 #[must_use]
323 pub fn public_modulus_len(&self) -> usize {
324 match self.evp_pkey.as_const().get_rsa() {
326 Ok(rsa) => {
327 unsafe { RSA_size(rsa.as_const_ptr()) as usize }
329 }
330 Err(_) => unreachable!(),
331 }
332 }
333
334 #[allow(clippy::many_single_char_names, clippy::similar_names)]
373 pub fn from_components<Public, Private>(
374 components: &KeyPairComponents<Public, Private>,
375 ) -> Result<Self, KeyRejected>
376 where
377 Public: AsRef<[u8]>,
378 Private: AsRef<[u8]>,
379 {
380 let mut rsa = LcPtr::new(unsafe { RSA_new() })?;
381 let mut p = DetachableLcPtr::try_from(components.p.as_ref())?;
382 let mut q = DetachableLcPtr::try_from(components.q.as_ref())?;
383 if 1 != unsafe { RSA_set0_factors(rsa.as_mut_ptr(), p.as_mut_ptr(), q.as_mut_ptr()) } {
384 return Err(KeyRejected::unspecified());
385 }
386 p.detach();
387 q.detach();
388
389 let mut n = public_component_to_bn(components.public_key.n.as_ref())?;
390 let mut e = public_component_to_bn(components.public_key.e.as_ref())?;
391 let mut d = DetachableLcPtr::try_from(components.d.as_ref())?;
392 if 1 != unsafe {
393 RSA_set0_key(
394 rsa.as_mut_ptr(),
395 n.as_mut_ptr(),
396 e.as_mut_ptr(),
397 d.as_mut_ptr(),
398 )
399 } {
400 return Err(KeyRejected::unspecified());
401 }
402 n.detach();
403 e.detach();
404 d.detach();
405
406 let mut dmp1 = DetachableLcPtr::try_from(components.dP.as_ref())?;
407 let mut dmq1 = DetachableLcPtr::try_from(components.dQ.as_ref())?;
408 let mut iqmp = DetachableLcPtr::try_from(components.qInv.as_ref())?;
409 if 1 != unsafe {
410 RSA_set0_crt_params(
411 rsa.as_mut_ptr(),
412 dmp1.as_mut_ptr(),
413 dmq1.as_mut_ptr(),
414 iqmp.as_mut_ptr(),
415 )
416 } {
417 return Err(KeyRejected::unspecified());
418 }
419 dmp1.detach();
420 dmq1.detach();
421 iqmp.detach();
422
423 if 1 != unsafe { RSA_check_key(rsa.as_mut_ptr()) } {
424 return Err(KeyRejected::inconsistent_components());
425 }
426 let mut evp_pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
427 if 1 != unsafe { EVP_PKEY_set1_RSA(evp_pkey.as_mut_ptr(), rsa.as_mut_ptr()) } {
432 return Err(KeyRejected::unspecified());
433 }
434
435 Self::new(evp_pkey)
436 }
437}
438
439impl Debug for KeyPair {
440 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
441 f.write_str(&format!(
442 "RsaKeyPair {{ public_key: {:?} }}",
443 self.serialized_public_key
444 ))
445 }
446}
447
448impl crate::signature::KeyPair for KeyPair {
449 type PublicKey = PublicKey;
450
451 fn public_key(&self) -> &Self::PublicKey {
452 &self.serialized_public_key
453 }
454}
455
456impl AsDer<Pkcs8V1Der<'static>> for KeyPair {
457 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
458 Ok(Pkcs8V1Der::new(
459 self.evp_pkey
460 .as_const()
461 .marshal_rfc5208_private_key(Version::V1)?,
462 ))
463 }
464}
465
466#[derive(Clone)]
468#[allow(clippy::module_name_repetitions)]
469pub struct PublicKey {
470 key: Box<[u8]>,
471 #[cfg(feature = "ring-io")]
472 modulus: Box<[u8]>,
473 #[cfg(feature = "ring-io")]
474 exponent: Box<[u8]>,
475}
476
477impl Drop for PublicKey {
478 fn drop(&mut self) {
479 self.key.zeroize();
480 #[cfg(feature = "ring-io")]
481 self.modulus.zeroize();
482 #[cfg(feature = "ring-io")]
483 self.exponent.zeroize();
484 }
485}
486
487impl PublicKey {
488 pub(super) fn new(evp_pkey: &LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
489 let key = encoding::rfc8017::encode_public_key_der(evp_pkey)?;
490 #[cfg(feature = "ring-io")]
491 {
492 let evp_pkey = evp_pkey.as_const();
493 let pubkey = evp_pkey.get_rsa()?;
494 let modulus = pubkey
495 .project_const_lifetime(unsafe { |pubkey| RSA_get0_n(pubkey.as_const_ptr()) })?;
496 let modulus = modulus.to_be_bytes().into_boxed_slice();
497 let exponent = pubkey
498 .project_const_lifetime(unsafe { |pubkey| RSA_get0_e(pubkey.as_const_ptr()) })?;
499 let exponent = exponent.to_be_bytes().into_boxed_slice();
500 Ok(PublicKey {
501 key,
502 modulus,
503 exponent,
504 })
505 }
506
507 #[cfg(not(feature = "ring-io"))]
508 Ok(PublicKey { key })
509 }
510
511 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
515 PublicKey::new(
518 &rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))?,
519 )
520 }
521}
522
523pub(crate) fn parse_rsa_public_key(input: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
524 rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))
525}
526
527impl Debug for PublicKey {
528 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
529 f.write_str(&format!(
530 "RsaPublicKey(\"{}\")",
531 hex::encode(self.key.as_ref())
532 ))
533 }
534}
535
536impl AsRef<[u8]> for PublicKey {
537 fn as_ref(&self) -> &[u8] {
539 self.key.as_ref()
540 }
541}
542
543impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
544 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
545 let evp_pkey = rfc8017::decode_public_key_der(self.as_ref())?;
547 rfc5280::encode_public_key_der(&evp_pkey)
548 }
549}
550
551#[cfg(feature = "ring-io")]
552impl PublicKey {
553 #[must_use]
555 pub fn modulus(&self) -> io::Positive<'_> {
556 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.modulus.as_ref()))
557 }
558
559 #[must_use]
561 pub fn exponent(&self) -> io::Positive<'_> {
562 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.exponent.as_ref()))
563 }
564
565 #[must_use]
567 pub fn modulus_len(&self) -> usize {
568 self.modulus.len()
569 }
570}
571
572#[allow(clippy::module_name_repetitions)]
581#[derive(Clone)]
582pub struct PublicKeyComponents<B> {
583 pub n: B,
585 pub e: B,
587}
588
589impl<B: Debug> Debug for PublicKeyComponents<B> {
590 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
591 f.debug_struct("RsaPublicKeyComponents")
592 .field("n", &self.n)
593 .field("e", &self.e)
594 .finish()
595 }
596}
597
598impl<B: Copy> Copy for PublicKeyComponents<B> {}
599
600fn public_component_to_bn(bytes: &[u8]) -> Result<DetachableLcPtr<BIGNUM>, KeyRejected> {
606 if bytes.is_empty() || bytes[0] == 0u8 {
607 return Err(KeyRejected::invalid_encoding());
608 }
609 Ok(DetachableLcPtr::try_from(bytes)?)
610}
611
612impl<B> PublicKeyComponents<B>
613where
614 B: AsRef<[u8]>,
615{
616 #[inline]
617 fn build_rsa(&self) -> Result<LcPtr<EVP_PKEY>, ()> {
618 let mut n_bn = public_component_to_bn(self.n.as_ref()).map_err(|_| ())?;
619 let mut e_bn = public_component_to_bn(self.e.as_ref()).map_err(|_| ())?;
620
621 let mut rsa = DetachableLcPtr::new(unsafe { RSA_new() })?;
622 if 1 != unsafe {
623 RSA_set0_key(
624 rsa.as_mut_ptr(),
625 n_bn.as_mut_ptr(),
626 e_bn.as_mut_ptr(),
627 null_mut(),
628 )
629 } {
630 return Err(());
631 }
632 n_bn.detach();
633 e_bn.detach();
634
635 let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
636 if 1 != unsafe { EVP_PKEY_assign_RSA(pkey.as_mut_ptr(), rsa.as_mut_ptr()) } {
637 return Err(());
638 }
639 rsa.detach();
640
641 Ok(pkey)
642 }
643
644 pub fn verify(
652 &self,
653 params: &RsaParameters,
654 message: &[u8],
655 signature: &[u8],
656 ) -> Result<(), Unspecified> {
657 let rsa = self.build_rsa()?;
658 super::signature::verify_rsa_signature(
659 params.digest_algorithm(),
660 params.padding(),
661 params.pss_salt_length(),
662 &rsa,
663 message,
664 signature,
665 params.bit_size_range(),
666 )
667 }
668
669 pub fn to_parsed_public_key(
706 &self,
707 params: &'static RsaParameters,
708 ) -> Result<crate::signature::ParsedPublicKey, KeyRejected> {
709 let pkey = self
710 .build_rsa()
711 .map_err(|()| KeyRejected::inconsistent_components())?;
712 Ok(crate::signature::ParsedPublicKey::from_rsa_evp_pkey(
713 params, pkey,
714 )?)
715 }
716}
717
718#[cfg(feature = "ring-io")]
719impl From<&PublicKey> for PublicKeyComponents<Vec<u8>> {
720 fn from(public_key: &PublicKey) -> Self {
721 PublicKeyComponents {
722 n: public_key.modulus.to_vec(),
723 e: public_key.exponent.to_vec(),
724 }
725 }
726}
727
728impl<B> TryInto<PublicEncryptingKey> for PublicKeyComponents<B>
729where
730 B: AsRef<[u8]>,
731{
732 type Error = Unspecified;
733
734 fn try_into(self) -> Result<PublicEncryptingKey, Self::Error> {
739 let rsa = self.build_rsa()?;
740 Ok(PublicEncryptingKey::new(rsa)?)
741 }
742}
743
744impl<B> AsDer<PublicKeyX509Der<'static>> for PublicKeyComponents<B>
745where
746 B: AsRef<[u8]>,
747{
748 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
756 let pkey = self.build_rsa()?;
757 rfc5280::encode_public_key_der(&pkey)
758 }
759}
760
761pub(super) fn generate_rsa_key(size: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
762 let params_fn = |ctx| {
763 if 1 == unsafe { EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, size) } {
764 Ok(())
765 } else {
766 Err(())
767 }
768 };
769
770 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_RSA, Some(params_fn))
771}
772
773#[cfg(feature = "fips")]
774#[must_use]
775pub(super) fn is_valid_fips_key(key: &LcPtr<EVP_PKEY>) -> bool {
776 let evp_pkey = key.as_const();
778 let rsa_key = evp_pkey.get_rsa().expect("RSA EVP_PKEY");
779
780 1 == unsafe { RSA_check_fips((rsa_key.as_const_ptr()).cast_mut()) }
781}
782
783pub(super) fn is_rsa_key(key: &LcPtr<EVP_PKEY>) -> bool {
784 let id = key.as_const().id();
785 id == EVP_PKEY_RSA || id == EVP_PKEY_RSA_PSS
786}
787
788pub(super) fn validate_rsa_key(key: &LcPtr<EVP_PKEY>) -> Result<(), KeyRejected> {
789 if !is_rsa_key(key) {
790 return Err(KeyRejected::unspecified());
791 }
792 match key.as_const().key_size_bits() {
793 2048..=8192 => Ok(()),
794 0..=2047 => Err(KeyRejected::too_small()),
795 _ => Err(KeyRejected::too_large()),
796 }
797}