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, RSA_new, RSA_set0_key, RSA_size, EVP_PKEY, EVP_PKEY_CTX, EVP_PKEY_RSA,
10 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
100impl KeyPair {
101 fn new(evp_pkey: LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
102 KeyPair::validate_private_key(&evp_pkey)?;
103 let serialized_public_key = PublicKey::new(&evp_pkey)?;
104 Ok(KeyPair {
105 evp_pkey,
106 serialized_public_key,
107 })
108 }
109
110 pub fn generate(size: KeySize) -> Result<Self, Unspecified> {
121 let private_key = generate_rsa_key(size.bits())?;
122 Ok(Self::new(private_key)?)
123 }
124
125 #[cfg(feature = "fips")]
133 #[deprecated]
134 pub fn generate_fips(size: KeySize) -> Result<Self, Unspecified> {
135 Self::generate(size)
136 }
137
138 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
154 let key = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_RSA)?;
155 Self::new(key)
156 }
157
158 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
163 let key = encoding::rfc8017::decode_private_key_der(input)?;
164 Self::new(key)
165 }
166
167 #[cfg(feature = "fips")]
169 #[must_use]
170 pub fn is_valid_fips_key(&self) -> bool {
171 is_valid_fips_key(&self.evp_pkey)
172 }
173
174 fn validate_private_key(key: &LcPtr<EVP_PKEY>) -> Result<(), KeyRejected> {
175 validate_rsa_key(key)
176 }
177
178 pub fn sign(
198 &self,
199 padding_alg: &'static dyn RsaEncoding,
200 _rng: &dyn rand::SecureRandom,
201 msg: &[u8],
202 signature: &mut [u8],
203 ) -> Result<(), Unspecified> {
204 let encoding = padding_alg.encoding();
205 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
206 Some(configure_rsa_pkcs1_pss_padding)
207 } else {
208 None
209 };
210
211 let sig_bytes = self
212 .evp_pkey
213 .sign(msg, Some(encoding.digest_algorithm()), padding_fn)?;
214
215 signature.copy_from_slice(&sig_bytes);
216 Ok(())
217 }
218
219 pub fn sign_digest(
234 &self,
235 padding_alg: &'static dyn RsaEncoding,
236 digest: &Digest,
237 signature: &mut [u8],
238 ) -> Result<(), Unspecified> {
239 let encoding = padding_alg.encoding();
240 if encoding.digest_algorithm() != digest.algorithm() {
241 return Err(Unspecified);
242 }
243
244 let padding_fn = Some({
245 |pctx: *mut EVP_PKEY_CTX| {
246 let evp_md = match_digest_type(&digest.algorithm().id);
247 if 1 != unsafe { EVP_PKEY_CTX_set_signature_md(pctx, evp_md.as_const_ptr()) } {
248 return Err(());
249 }
250 if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
251 configure_rsa_pkcs1_pss_padding(pctx)
252 } else {
253 Ok(())
254 }
255 }
256 });
257
258 let sig_bytes = self.evp_pkey.sign_digest(digest, padding_fn)?;
259
260 signature.copy_from_slice(&sig_bytes);
261 Ok(())
262 }
263
264 #[must_use]
268 pub fn public_modulus_len(&self) -> usize {
269 match self.evp_pkey.as_const().get_rsa() {
271 Ok(rsa) => {
272 unsafe { RSA_size(rsa.as_const_ptr()) as usize }
274 }
275 Err(_) => unreachable!(),
276 }
277 }
278}
279
280impl Debug for KeyPair {
281 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
282 f.write_str(&format!(
283 "RsaKeyPair {{ public_key: {:?} }}",
284 self.serialized_public_key
285 ))
286 }
287}
288
289impl crate::signature::KeyPair for KeyPair {
290 type PublicKey = PublicKey;
291
292 fn public_key(&self) -> &Self::PublicKey {
293 &self.serialized_public_key
294 }
295}
296
297impl AsDer<Pkcs8V1Der<'static>> for KeyPair {
298 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
299 Ok(Pkcs8V1Der::new(
300 self.evp_pkey
301 .as_const()
302 .marshal_rfc5208_private_key(Version::V1)?,
303 ))
304 }
305}
306
307#[derive(Clone)]
309#[allow(clippy::module_name_repetitions)]
310pub struct PublicKey {
311 key: Box<[u8]>,
312 #[cfg(feature = "ring-io")]
313 modulus: Box<[u8]>,
314 #[cfg(feature = "ring-io")]
315 exponent: Box<[u8]>,
316}
317
318impl Drop for PublicKey {
319 fn drop(&mut self) {
320 self.key.zeroize();
321 #[cfg(feature = "ring-io")]
322 self.modulus.zeroize();
323 #[cfg(feature = "ring-io")]
324 self.exponent.zeroize();
325 }
326}
327
328impl PublicKey {
329 pub(super) fn new(evp_pkey: &LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
330 let key = encoding::rfc8017::encode_public_key_der(evp_pkey)?;
331 #[cfg(feature = "ring-io")]
332 {
333 let evp_pkey = evp_pkey.as_const();
334 let pubkey = evp_pkey.get_rsa()?;
335 let modulus = pubkey
336 .project_const_lifetime(unsafe { |pubkey| RSA_get0_n(pubkey.as_const_ptr()) })?;
337 let modulus = modulus.to_be_bytes().into_boxed_slice();
338 let exponent = pubkey
339 .project_const_lifetime(unsafe { |pubkey| RSA_get0_e(pubkey.as_const_ptr()) })?;
340 let exponent = exponent.to_be_bytes().into_boxed_slice();
341 Ok(PublicKey {
342 key,
343 modulus,
344 exponent,
345 })
346 }
347
348 #[cfg(not(feature = "ring-io"))]
349 Ok(PublicKey { key })
350 }
351
352 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
356 PublicKey::new(
359 &rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))?,
360 )
361 }
362}
363
364pub(crate) fn parse_rsa_public_key(input: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
365 rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))
366}
367
368impl Debug for PublicKey {
369 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
370 f.write_str(&format!(
371 "RsaPublicKey(\"{}\")",
372 hex::encode(self.key.as_ref())
373 ))
374 }
375}
376
377impl AsRef<[u8]> for PublicKey {
378 fn as_ref(&self) -> &[u8] {
380 self.key.as_ref()
381 }
382}
383
384impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
385 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
386 let evp_pkey = rfc8017::decode_public_key_der(self.as_ref())?;
388 rfc5280::encode_public_key_der(&evp_pkey)
389 }
390}
391
392#[cfg(feature = "ring-io")]
393impl PublicKey {
394 #[must_use]
396 pub fn modulus(&self) -> io::Positive<'_> {
397 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.modulus.as_ref()))
398 }
399
400 #[must_use]
402 pub fn exponent(&self) -> io::Positive<'_> {
403 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.exponent.as_ref()))
404 }
405
406 #[must_use]
408 pub fn modulus_len(&self) -> usize {
409 self.modulus.len()
410 }
411}
412
413#[allow(clippy::module_name_repetitions)]
422#[derive(Clone)]
423pub struct PublicKeyComponents<B>
424where
425 B: AsRef<[u8]> + Debug,
426{
427 pub n: B,
429 pub e: B,
431}
432
433impl<B: AsRef<[u8]> + Debug> Debug for PublicKeyComponents<B> {
434 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
435 f.debug_struct("RsaPublicKeyComponents")
436 .field("n", &self.n)
437 .field("e", &self.e)
438 .finish()
439 }
440}
441
442impl<B: Copy + AsRef<[u8]> + Debug> Copy for PublicKeyComponents<B> {}
443
444impl<B> PublicKeyComponents<B>
445where
446 B: AsRef<[u8]> + Debug,
447{
448 #[inline]
449 fn build_rsa(&self) -> Result<LcPtr<EVP_PKEY>, ()> {
450 let n_bytes = self.n.as_ref();
451 if n_bytes.is_empty() || n_bytes[0] == 0u8 {
452 return Err(());
453 }
454 let mut n_bn = DetachableLcPtr::try_from(n_bytes)?;
455
456 let e_bytes = self.e.as_ref();
457 if e_bytes.is_empty() || e_bytes[0] == 0u8 {
458 return Err(());
459 }
460 let mut e_bn = DetachableLcPtr::try_from(e_bytes)?;
461
462 let mut rsa = DetachableLcPtr::new(unsafe { RSA_new() })?;
463 if 1 != unsafe {
464 RSA_set0_key(
465 rsa.as_mut_ptr(),
466 n_bn.as_mut_ptr(),
467 e_bn.as_mut_ptr(),
468 null_mut(),
469 )
470 } {
471 return Err(());
472 }
473 n_bn.detach();
474 e_bn.detach();
475
476 let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
477 if 1 != unsafe { EVP_PKEY_assign_RSA(pkey.as_mut_ptr(), rsa.as_mut_ptr()) } {
478 return Err(());
479 }
480 rsa.detach();
481
482 Ok(pkey)
483 }
484
485 pub fn verify(
493 &self,
494 params: &RsaParameters,
495 message: &[u8],
496 signature: &[u8],
497 ) -> Result<(), Unspecified> {
498 let rsa = self.build_rsa()?;
499 super::signature::verify_rsa_signature(
500 params.digest_algorithm(),
501 params.padding(),
502 &rsa,
503 message,
504 signature,
505 params.bit_size_range(),
506 )
507 }
508
509 pub fn to_parsed_public_key(
546 &self,
547 params: &'static RsaParameters,
548 ) -> Result<crate::signature::ParsedPublicKey, KeyRejected> {
549 let pkey = self
550 .build_rsa()
551 .map_err(|()| KeyRejected::inconsistent_components())?;
552 Ok(crate::signature::ParsedPublicKey::from_rsa_evp_pkey(
553 params, pkey,
554 )?)
555 }
556}
557
558#[cfg(feature = "ring-io")]
559impl From<&PublicKey> for PublicKeyComponents<Vec<u8>> {
560 fn from(public_key: &PublicKey) -> Self {
561 PublicKeyComponents {
562 n: public_key.modulus.to_vec(),
563 e: public_key.exponent.to_vec(),
564 }
565 }
566}
567
568impl<B> TryInto<PublicEncryptingKey> for PublicKeyComponents<B>
569where
570 B: AsRef<[u8]> + Debug,
571{
572 type Error = Unspecified;
573
574 fn try_into(self) -> Result<PublicEncryptingKey, Self::Error> {
579 let rsa = self.build_rsa()?;
580 Ok(PublicEncryptingKey::new(rsa)?)
581 }
582}
583
584impl<B> AsDer<PublicKeyX509Der<'static>> for PublicKeyComponents<B>
585where
586 B: AsRef<[u8]> + Debug,
587{
588 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
596 let pkey = self.build_rsa()?;
597 rfc5280::encode_public_key_der(&pkey)
598 }
599}
600
601pub(super) fn generate_rsa_key(size: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
602 let params_fn = |ctx| {
603 if 1 == unsafe { EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, size) } {
604 Ok(())
605 } else {
606 Err(())
607 }
608 };
609
610 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_RSA, Some(params_fn))
611}
612
613#[cfg(feature = "fips")]
614#[must_use]
615pub(super) fn is_valid_fips_key(key: &LcPtr<EVP_PKEY>) -> bool {
616 let evp_pkey = key.as_const();
618 let rsa_key = evp_pkey.get_rsa().expect("RSA EVP_PKEY");
619
620 1 == unsafe { RSA_check_fips((rsa_key.as_const_ptr()).cast_mut()) }
621}
622
623pub(super) fn is_rsa_key(key: &LcPtr<EVP_PKEY>) -> bool {
624 let id = key.as_const().id();
625 id == EVP_PKEY_RSA || id == EVP_PKEY_RSA_PSS
626}
627
628pub(super) fn validate_rsa_key(key: &LcPtr<EVP_PKEY>) -> Result<(), KeyRejected> {
629 if !is_rsa_key(key) {
630 return Err(KeyRejected::unspecified());
631 }
632 match key.as_const().key_size_bits() {
633 2048..=8192 => Ok(()),
634 0..=2047 => Err(KeyRejected::too_small()),
635 _ => Err(KeyRejected::too_large()),
636 }
637}