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 if !is_rsa_key(key) {
176 return Err(KeyRejected::unspecified());
177 }
178 match key.as_const().key_size_bits() {
179 2048..=8192 => Ok(()),
180 _ => Err(KeyRejected::unspecified()),
181 }
182 }
183
184 pub fn sign(
204 &self,
205 padding_alg: &'static dyn RsaEncoding,
206 _rng: &dyn rand::SecureRandom,
207 msg: &[u8],
208 signature: &mut [u8],
209 ) -> Result<(), Unspecified> {
210 let encoding = padding_alg.encoding();
211 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
212 Some(configure_rsa_pkcs1_pss_padding)
213 } else {
214 None
215 };
216
217 let sig_bytes = self
218 .evp_pkey
219 .sign(msg, Some(encoding.digest_algorithm()), padding_fn)?;
220
221 signature.copy_from_slice(&sig_bytes);
222 Ok(())
223 }
224
225 pub fn sign_digest(
240 &self,
241 padding_alg: &'static dyn RsaEncoding,
242 digest: &Digest,
243 signature: &mut [u8],
244 ) -> Result<(), Unspecified> {
245 let encoding = padding_alg.encoding();
246 if encoding.digest_algorithm() != digest.algorithm() {
247 return Err(Unspecified);
248 }
249
250 let padding_fn = Some({
251 |pctx: *mut EVP_PKEY_CTX| {
252 let evp_md = match_digest_type(&digest.algorithm().id);
253 if 1 != unsafe { EVP_PKEY_CTX_set_signature_md(pctx, *evp_md) } {
254 return Err(());
255 }
256 if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
257 configure_rsa_pkcs1_pss_padding(pctx)
258 } else {
259 Ok(())
260 }
261 }
262 });
263
264 let sig_bytes = self.evp_pkey.sign_digest(digest, padding_fn)?;
265
266 signature.copy_from_slice(&sig_bytes);
267 Ok(())
268 }
269
270 #[must_use]
274 pub fn public_modulus_len(&self) -> usize {
275 match self.evp_pkey.as_const().get_rsa() {
277 Ok(rsa) => {
278 unsafe { RSA_size(*rsa) as usize }
280 }
281 Err(_) => unreachable!(),
282 }
283 }
284}
285
286impl Debug for KeyPair {
287 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
288 f.write_str(&format!(
289 "RsaKeyPair {{ public_key: {:?} }}",
290 self.serialized_public_key
291 ))
292 }
293}
294
295impl crate::signature::KeyPair for KeyPair {
296 type PublicKey = PublicKey;
297
298 fn public_key(&self) -> &Self::PublicKey {
299 &self.serialized_public_key
300 }
301}
302
303impl AsDer<Pkcs8V1Der<'static>> for KeyPair {
304 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
305 Ok(Pkcs8V1Der::new(
306 self.evp_pkey
307 .as_const()
308 .marshal_rfc5208_private_key(Version::V1)?,
309 ))
310 }
311}
312
313#[derive(Clone)]
315#[allow(clippy::module_name_repetitions)]
316pub struct PublicKey {
317 key: Box<[u8]>,
318 #[cfg(feature = "ring-io")]
319 modulus: Box<[u8]>,
320 #[cfg(feature = "ring-io")]
321 exponent: Box<[u8]>,
322}
323
324impl Drop for PublicKey {
325 fn drop(&mut self) {
326 self.key.zeroize();
327 #[cfg(feature = "ring-io")]
328 self.modulus.zeroize();
329 #[cfg(feature = "ring-io")]
330 self.exponent.zeroize();
331 }
332}
333
334impl PublicKey {
335 pub(super) fn new(evp_pkey: &LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
336 let key = encoding::rfc8017::encode_public_key_der(evp_pkey)?;
337 #[cfg(feature = "ring-io")]
338 {
339 let evp_pkey = evp_pkey.as_const();
340 let pubkey = evp_pkey.get_rsa()?;
341 let modulus =
342 pubkey.project_const_lifetime(unsafe { |pubkey| RSA_get0_n(**pubkey) })?;
343 let modulus = modulus.to_be_bytes().into_boxed_slice();
344 let exponent =
345 pubkey.project_const_lifetime(unsafe { |pubkey| RSA_get0_e(**pubkey) })?;
346 let exponent = exponent.to_be_bytes().into_boxed_slice();
347 Ok(PublicKey {
348 key,
349 modulus,
350 exponent,
351 })
352 }
353
354 #[cfg(not(feature = "ring-io"))]
355 Ok(PublicKey { key })
356 }
357
358 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
362 PublicKey::new(
365 &rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))?,
366 )
367 }
368}
369
370pub(crate) fn parse_rsa_public_key(input: &[u8]) -> Result<LcPtr<EVP_PKEY>, KeyRejected> {
371 rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))
372}
373
374impl Debug for PublicKey {
375 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
376 f.write_str(&format!(
377 "RsaPublicKey(\"{}\")",
378 hex::encode(self.key.as_ref())
379 ))
380 }
381}
382
383impl AsRef<[u8]> for PublicKey {
384 fn as_ref(&self) -> &[u8] {
386 self.key.as_ref()
387 }
388}
389
390impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
391 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
392 let evp_pkey = rfc8017::decode_public_key_der(self.as_ref())?;
394 rfc5280::encode_public_key_der(&evp_pkey)
395 }
396}
397
398#[cfg(feature = "ring-io")]
399impl PublicKey {
400 #[must_use]
402 pub fn modulus(&self) -> io::Positive<'_> {
403 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.modulus.as_ref()))
404 }
405
406 #[must_use]
408 pub fn exponent(&self) -> io::Positive<'_> {
409 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.exponent.as_ref()))
410 }
411
412 #[must_use]
414 pub fn modulus_len(&self) -> usize {
415 self.modulus.len()
416 }
417}
418
419#[allow(clippy::module_name_repetitions)]
428#[derive(Clone)]
429pub struct PublicKeyComponents<B>
430where
431 B: AsRef<[u8]> + Debug,
432{
433 pub n: B,
435 pub e: B,
437}
438
439impl<B: AsRef<[u8]> + Debug> Debug for PublicKeyComponents<B> {
440 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
441 f.debug_struct("RsaPublicKeyComponents")
442 .field("n", &self.n)
443 .field("e", &self.e)
444 .finish()
445 }
446}
447
448impl<B: Copy + AsRef<[u8]> + Debug> Copy for PublicKeyComponents<B> {}
449
450impl<B> PublicKeyComponents<B>
451where
452 B: AsRef<[u8]> + Debug,
453{
454 #[inline]
455 fn build_rsa(&self) -> Result<LcPtr<EVP_PKEY>, ()> {
456 let n_bytes = self.n.as_ref();
457 if n_bytes.is_empty() || n_bytes[0] == 0u8 {
458 return Err(());
459 }
460 let n_bn = DetachableLcPtr::try_from(n_bytes)?;
461
462 let e_bytes = self.e.as_ref();
463 if e_bytes.is_empty() || e_bytes[0] == 0u8 {
464 return Err(());
465 }
466 let e_bn = DetachableLcPtr::try_from(e_bytes)?;
467
468 let rsa = DetachableLcPtr::new(unsafe { RSA_new() })?;
469 if 1 != unsafe { RSA_set0_key(*rsa, *n_bn, *e_bn, null_mut()) } {
470 return Err(());
471 }
472 n_bn.detach();
473 e_bn.detach();
474
475 let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
476 if 1 != unsafe { EVP_PKEY_assign_RSA(*pkey.as_mut(), *rsa) } {
477 return Err(());
478 }
479 rsa.detach();
480
481 Ok(pkey)
482 }
483
484 pub fn verify(
492 &self,
493 params: &RsaParameters,
494 message: &[u8],
495 signature: &[u8],
496 ) -> Result<(), Unspecified> {
497 let rsa = self.build_rsa()?;
498 super::signature::verify_rsa_signature(
499 params.digest_algorithm(),
500 params.padding(),
501 &rsa,
502 message,
503 signature,
504 params.bit_size_range(),
505 )
506 }
507}
508
509#[cfg(feature = "ring-io")]
510impl From<&PublicKey> for PublicKeyComponents<Vec<u8>> {
511 fn from(public_key: &PublicKey) -> Self {
512 PublicKeyComponents {
513 n: public_key.modulus.to_vec(),
514 e: public_key.exponent.to_vec(),
515 }
516 }
517}
518
519impl<B> TryInto<PublicEncryptingKey> for PublicKeyComponents<B>
520where
521 B: AsRef<[u8]> + Debug,
522{
523 type Error = Unspecified;
524
525 fn try_into(self) -> Result<PublicEncryptingKey, Self::Error> {
530 let rsa = self.build_rsa()?;
531 PublicEncryptingKey::new(rsa)
532 }
533}
534
535pub(super) fn generate_rsa_key(size: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
536 let params_fn = |ctx| {
537 if 1 == unsafe { EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, size) } {
538 Ok(())
539 } else {
540 Err(())
541 }
542 };
543
544 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_RSA, Some(params_fn))
545}
546
547#[cfg(feature = "fips")]
548#[must_use]
549pub(super) fn is_valid_fips_key(key: &LcPtr<EVP_PKEY>) -> bool {
550 let evp_pkey = key.as_const();
552 let rsa_key = evp_pkey.get_rsa().expect("RSA EVP_PKEY");
553
554 1 == unsafe { RSA_check_fips((*rsa_key).cast_mut()) }
555}
556
557pub(super) fn is_rsa_key(key: &LcPtr<EVP_PKEY>) -> bool {
558 let id = key.as_const().id();
559 id == EVP_PKEY_RSA || id == EVP_PKEY_RSA_PSS
560}