1use super::signature::{RsaEncoding, RsaPadding};
6use super::{encoding, RsaParameters};
7#[cfg(feature = "fips")]
8use crate::aws_lc::RSA;
9use crate::aws_lc::{
10 EVP_PKEY_CTX_set_rsa_keygen_bits, EVP_PKEY_assign_RSA, EVP_PKEY_new, RSA_new, RSA_set0_key,
11 RSA_size, EVP_PKEY, EVP_PKEY_RSA, EVP_PKEY_RSA_PSS,
12};
13#[cfg(feature = "ring-io")]
14use crate::aws_lc::{RSA_get0_e, RSA_get0_n};
15use crate::encoding::{AsDer, Pkcs8V1Der, PublicKeyX509Der};
16use crate::error::{KeyRejected, Unspecified};
17#[cfg(feature = "ring-io")]
18use crate::io;
19use crate::ptr::{DetachableLcPtr, LcPtr};
20use crate::rsa::PublicEncryptingKey;
21use crate::sealed::Sealed;
22use crate::{hex, rand};
23#[cfg(feature = "fips")]
24use aws_lc::RSA_check_fips;
25use core::fmt::{self, Debug, Formatter};
26use core::ptr::null_mut;
27
28use std::os::raw::c_int;
31
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(
206 &self,
207 padding_alg: &'static dyn RsaEncoding,
208 _rng: &dyn rand::SecureRandom,
209 msg: &[u8],
210 signature: &mut [u8],
211 ) -> Result<(), Unspecified> {
212 let encoding = padding_alg.encoding();
213 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
214 Some(configure_rsa_pkcs1_pss_padding)
215 } else {
216 None
217 };
218
219 let sig_bytes = self
220 .evp_pkey
221 .sign(msg, Some(encoding.digest_algorithm()), padding_fn)?;
222
223 signature.copy_from_slice(&sig_bytes);
224 Ok(())
225 }
226
227 #[must_use]
231 pub fn public_modulus_len(&self) -> usize {
232 match self.evp_pkey.as_const().get_rsa() {
234 Ok(rsa) => {
235 unsafe { RSA_size(*rsa) as usize }
237 }
238 Err(_) => unreachable!(),
239 }
240 }
241}
242
243impl Debug for KeyPair {
244 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
245 f.write_str(&format!(
246 "RsaKeyPair {{ public_key: {:?} }}",
247 self.serialized_public_key
248 ))
249 }
250}
251
252impl crate::signature::KeyPair for KeyPair {
253 type PublicKey = PublicKey;
254
255 fn public_key(&self) -> &Self::PublicKey {
256 &self.serialized_public_key
257 }
258}
259
260impl AsDer<Pkcs8V1Der<'static>> for KeyPair {
261 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
262 Ok(Pkcs8V1Der::new(
263 self.evp_pkey
264 .as_const()
265 .marshal_rfc5208_private_key(Version::V1)?,
266 ))
267 }
268}
269
270#[derive(Clone)]
272#[allow(clippy::module_name_repetitions)]
273pub struct PublicKey {
274 key: Box<[u8]>,
275 #[cfg(feature = "ring-io")]
276 modulus: Box<[u8]>,
277 #[cfg(feature = "ring-io")]
278 exponent: Box<[u8]>,
279}
280
281impl Drop for PublicKey {
282 fn drop(&mut self) {
283 self.key.zeroize();
284 #[cfg(feature = "ring-io")]
285 self.modulus.zeroize();
286 #[cfg(feature = "ring-io")]
287 self.exponent.zeroize();
288 }
289}
290
291impl PublicKey {
292 pub(super) fn new(evp_pkey: &LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
293 let key = encoding::rfc8017::encode_public_key_der(evp_pkey)?;
294 #[cfg(feature = "ring-io")]
295 {
296 let evp_pkey = evp_pkey.as_const();
297 let pubkey = evp_pkey.get_rsa()?;
298 let modulus =
299 pubkey.project_const_lifetime(unsafe { |pubkey| RSA_get0_n(**pubkey) })?;
300 let modulus = modulus.to_be_bytes().into_boxed_slice();
301 let exponent =
302 pubkey.project_const_lifetime(unsafe { |pubkey| RSA_get0_e(**pubkey) })?;
303 let exponent = exponent.to_be_bytes().into_boxed_slice();
304 Ok(PublicKey {
305 key,
306 modulus,
307 exponent,
308 })
309 }
310
311 #[cfg(not(feature = "ring-io"))]
312 Ok(PublicKey { key })
313 }
314
315 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
319 PublicKey::new(
322 &rfc8017::decode_public_key_der(input).or(rfc5280::decode_public_key_der(input))?,
323 )
324 }
325}
326
327impl Debug for PublicKey {
328 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
329 f.write_str(&format!(
330 "RsaPublicKey(\"{}\")",
331 hex::encode(self.key.as_ref())
332 ))
333 }
334}
335
336impl AsRef<[u8]> for PublicKey {
337 fn as_ref(&self) -> &[u8] {
339 self.key.as_ref()
340 }
341}
342
343impl AsDer<PublicKeyX509Der<'static>> for PublicKey {
344 fn as_der(&self) -> Result<PublicKeyX509Der<'static>, Unspecified> {
345 let evp_pkey = rfc8017::decode_public_key_der(self.as_ref())?;
347 rfc5280::encode_public_key_der(&evp_pkey)
348 }
349}
350
351#[cfg(feature = "ring-io")]
352impl PublicKey {
353 #[must_use]
355 pub fn modulus(&self) -> io::Positive<'_> {
356 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.modulus.as_ref()))
357 }
358
359 #[must_use]
361 pub fn exponent(&self) -> io::Positive<'_> {
362 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.exponent.as_ref()))
363 }
364
365 #[must_use]
367 pub fn modulus_len(&self) -> usize {
368 self.modulus.len()
369 }
370}
371
372#[allow(clippy::module_name_repetitions)]
381#[derive(Clone)]
382pub struct PublicKeyComponents<B>
383where
384 B: AsRef<[u8]> + Debug,
385{
386 pub n: B,
388 pub e: B,
390}
391
392impl<B: AsRef<[u8]> + Debug> Debug for PublicKeyComponents<B> {
393 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
394 f.debug_struct("RsaPublicKeyComponents")
395 .field("n", &self.n)
396 .field("e", &self.e)
397 .finish()
398 }
399}
400
401impl<B: Copy + AsRef<[u8]> + Debug> Copy for PublicKeyComponents<B> {}
402
403impl<B> PublicKeyComponents<B>
404where
405 B: AsRef<[u8]> + Debug,
406{
407 #[inline]
408 fn build_rsa(&self) -> Result<LcPtr<EVP_PKEY>, ()> {
409 let n_bytes = self.n.as_ref();
410 if n_bytes.is_empty() || n_bytes[0] == 0u8 {
411 return Err(());
412 }
413 let n_bn = DetachableLcPtr::try_from(n_bytes)?;
414
415 let e_bytes = self.e.as_ref();
416 if e_bytes.is_empty() || e_bytes[0] == 0u8 {
417 return Err(());
418 }
419 let e_bn = DetachableLcPtr::try_from(e_bytes)?;
420
421 let rsa = DetachableLcPtr::new(unsafe { RSA_new() })?;
422 if 1 != unsafe { RSA_set0_key(*rsa, *n_bn, *e_bn, null_mut()) } {
423 return Err(());
424 }
425 n_bn.detach();
426 e_bn.detach();
427
428 let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
429 if 1 != unsafe { EVP_PKEY_assign_RSA(*pkey.as_mut(), *rsa) } {
430 return Err(());
431 }
432 rsa.detach();
433
434 Ok(pkey)
435 }
436
437 pub fn verify(
445 &self,
446 params: &RsaParameters,
447 message: &[u8],
448 signature: &[u8],
449 ) -> Result<(), Unspecified> {
450 let rsa = self.build_rsa()?;
451 super::signature::verify_rsa_signature(
452 params.digest_algorithm(),
453 params.padding(),
454 &rsa,
455 message,
456 signature,
457 params.bit_size_range(),
458 )
459 }
460}
461
462#[cfg(feature = "ring-io")]
463impl From<&PublicKey> for PublicKeyComponents<Vec<u8>> {
464 fn from(public_key: &PublicKey) -> Self {
465 PublicKeyComponents {
466 n: public_key.modulus.to_vec(),
467 e: public_key.exponent.to_vec(),
468 }
469 }
470}
471
472impl<B> TryInto<PublicEncryptingKey> for PublicKeyComponents<B>
473where
474 B: AsRef<[u8]> + Debug,
475{
476 type Error = Unspecified;
477
478 fn try_into(self) -> Result<PublicEncryptingKey, Self::Error> {
483 let rsa = self.build_rsa()?;
484 PublicEncryptingKey::new(rsa)
485 }
486}
487
488pub(super) fn generate_rsa_key(size: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
489 let params_fn = |ctx| {
490 if 1 == unsafe { EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, size) } {
491 Ok(())
492 } else {
493 Err(())
494 }
495 };
496
497 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_RSA, Some(params_fn))
498}
499
500#[cfg(feature = "fips")]
501#[must_use]
502pub(super) fn is_valid_fips_key(key: &LcPtr<EVP_PKEY>) -> bool {
503 let evp_pkey = key.as_const();
505 let rsa_key = evp_pkey.get_rsa().expect("RSA EVP_PKEY");
506
507 1 == unsafe { RSA_check_fips(*rsa_key as *mut RSA) }
508}
509
510pub(super) fn is_rsa_key(key: &LcPtr<EVP_PKEY>) -> bool {
511 let id = key.as_const().id();
512 id == EVP_PKEY_RSA || id == EVP_PKEY_RSA_PSS
513}