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};
16use crate::error::{KeyRejected, Unspecified};
17#[cfg(feature = "ring-io")]
18use crate::io;
19#[cfg(feature = "ring-io")]
20use crate::ptr::ConstPointer;
21use crate::ptr::{DetachableLcPtr, LcPtr};
22use crate::rsa::PublicEncryptingKey;
23use crate::sealed::Sealed;
24use crate::{hex, rand};
25#[cfg(feature = "fips")]
26use aws_lc::RSA_check_fips;
27use core::fmt::{self, Debug, Formatter};
28use core::ptr::null_mut;
29
30use std::os::raw::c_int;
33
34use crate::pkcs8::Version;
35use crate::rsa::signature::configure_rsa_pkcs1_pss_padding;
36#[cfg(feature = "ring-io")]
37use untrusted::Input;
38use zeroize::Zeroize;
39
40#[allow(clippy::module_name_repetitions)]
42#[non_exhaustive]
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum KeySize {
45 Rsa2048,
47
48 Rsa3072,
50
51 Rsa4096,
53
54 Rsa8192,
56}
57
58#[allow(clippy::len_without_is_empty)]
59impl KeySize {
60 #[inline]
62 #[must_use]
63 pub fn len(self) -> usize {
64 match self {
65 Self::Rsa2048 => 256,
66 Self::Rsa3072 => 384,
67 Self::Rsa4096 => 512,
68 Self::Rsa8192 => 1024,
69 }
70 }
71
72 #[inline]
74 pub(super) fn bits(self) -> i32 {
75 match self {
76 Self::Rsa2048 => 2048,
77 Self::Rsa3072 => 3072,
78 Self::Rsa4096 => 4096,
79 Self::Rsa8192 => 8192,
80 }
81 }
82}
83
84#[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
101impl KeyPair {
102 fn new(evp_pkey: LcPtr<EVP_PKEY>) -> Result<Self, KeyRejected> {
103 KeyPair::validate_private_key(&evp_pkey)?;
104 let serialized_public_key = PublicKey::new(&evp_pkey)?;
105 Ok(KeyPair {
106 evp_pkey,
107 serialized_public_key,
108 })
109 }
110
111 pub fn generate(size: KeySize) -> Result<Self, Unspecified> {
122 let private_key = generate_rsa_key(size.bits())?;
123 Ok(Self::new(private_key)?)
124 }
125
126 #[cfg(feature = "fips")]
134 #[deprecated]
135 pub fn generate_fips(size: KeySize) -> Result<Self, Unspecified> {
136 Self::generate(size)
137 }
138
139 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
155 let key = LcPtr::<EVP_PKEY>::parse_rfc5208_private_key(pkcs8, EVP_PKEY_RSA)?;
156 Self::new(key)
157 }
158
159 pub fn from_der(input: &[u8]) -> Result<Self, KeyRejected> {
164 let key = encoding::rfc8017::decode_private_key_der(input)?;
165 Self::new(key)
166 }
167
168 #[cfg(feature = "fips")]
170 #[must_use]
171 pub fn is_valid_fips_key(&self) -> bool {
172 is_valid_fips_key(&self.evp_pkey)
173 }
174
175 fn validate_private_key(key: &LcPtr<EVP_PKEY>) -> Result<(), KeyRejected> {
176 if !is_rsa_key(key) {
177 return Err(KeyRejected::unspecified());
178 }
179 match key.key_size_bits() {
180 2048..=8192 => Ok(()),
181 _ => Err(KeyRejected::unspecified()),
182 }
183 }
184
185 pub fn sign(
207 &self,
208 padding_alg: &'static dyn RsaEncoding,
209 _rng: &dyn rand::SecureRandom,
210 msg: &[u8],
211 signature: &mut [u8],
212 ) -> Result<(), Unspecified> {
213 let encoding = padding_alg.encoding();
214 let padding_fn = if let RsaPadding::RSA_PKCS1_PSS_PADDING = encoding.padding() {
215 Some(configure_rsa_pkcs1_pss_padding)
216 } else {
217 None
218 };
219
220 let sig_bytes = self
221 .evp_pkey
222 .sign(msg, Some(encoding.digest_algorithm()), padding_fn)?;
223
224 signature.copy_from_slice(&sig_bytes);
225 Ok(())
226 }
227
228 #[must_use]
232 pub fn public_modulus_len(&self) -> usize {
233 match self.evp_pkey.get_rsa() {
235 Ok(rsa) => {
236 unsafe { RSA_size(*rsa) as usize }
238 }
239 Err(_) => unreachable!(),
240 }
241 }
242}
243
244impl Debug for KeyPair {
245 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
246 f.write_str(&format!(
247 "RsaKeyPair {{ public_key: {:?} }}",
248 self.serialized_public_key
249 ))
250 }
251}
252
253impl crate::signature::KeyPair for KeyPair {
254 type PublicKey = PublicKey;
255
256 fn public_key(&self) -> &Self::PublicKey {
257 &self.serialized_public_key
258 }
259}
260
261impl AsDer<Pkcs8V1Der<'static>> for KeyPair {
262 fn as_der(&self) -> Result<Pkcs8V1Der<'static>, Unspecified> {
263 Ok(Pkcs8V1Der::new(
264 self.evp_pkey.marshal_rfc5208_private_key(Version::V1)?,
265 ))
266 }
267}
268
269#[derive(Clone)]
271#[allow(clippy::module_name_repetitions)]
272pub struct PublicKey {
273 key: Box<[u8]>,
274 #[cfg(feature = "ring-io")]
275 modulus: Box<[u8]>,
276 #[cfg(feature = "ring-io")]
277 exponent: Box<[u8]>,
278}
279
280impl Drop for PublicKey {
281 fn drop(&mut self) {
282 self.key.zeroize();
283 #[cfg(feature = "ring-io")]
284 self.modulus.zeroize();
285 #[cfg(feature = "ring-io")]
286 self.exponent.zeroize();
287 }
288}
289
290impl PublicKey {
291 pub(super) fn new(evp_pkey: &LcPtr<EVP_PKEY>) -> Result<Self, Unspecified> {
292 let key = encoding::rfc8017::encode_public_key_der(evp_pkey)?;
293 #[cfg(feature = "ring-io")]
294 {
295 let pubkey = evp_pkey.get_rsa()?;
296 let modulus = ConstPointer::new(unsafe { RSA_get0_n(*pubkey) })?;
297 let modulus = modulus.to_be_bytes().into_boxed_slice();
298 let exponent = ConstPointer::new(unsafe { RSA_get0_e(*pubkey) })?;
299 let exponent = exponent.to_be_bytes().into_boxed_slice();
300 Ok(PublicKey {
301 key,
302 modulus,
303 exponent,
304 })
305 }
306
307 #[cfg(not(feature = "ring-io"))]
308 Ok(PublicKey { key })
309 }
310}
311
312impl Debug for PublicKey {
313 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
314 f.write_str(&format!(
315 "RsaPublicKey(\"{}\")",
316 hex::encode(self.key.as_ref())
317 ))
318 }
319}
320
321impl AsRef<[u8]> for PublicKey {
322 fn as_ref(&self) -> &[u8] {
324 self.key.as_ref()
325 }
326}
327
328#[cfg(feature = "ring-io")]
329impl PublicKey {
330 #[must_use]
332 pub fn modulus(&self) -> io::Positive<'_> {
333 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.modulus.as_ref()))
334 }
335
336 #[must_use]
338 pub fn exponent(&self) -> io::Positive<'_> {
339 io::Positive::new_non_empty_without_leading_zeros(Input::from(self.exponent.as_ref()))
340 }
341
342 #[must_use]
344 pub fn modulus_len(&self) -> usize {
345 self.modulus.len()
346 }
347}
348
349#[allow(clippy::module_name_repetitions)]
358#[derive(Clone)]
359pub struct PublicKeyComponents<B>
360where
361 B: AsRef<[u8]> + Debug,
362{
363 pub n: B,
365 pub e: B,
367}
368
369impl<B: AsRef<[u8]> + Debug> Debug for PublicKeyComponents<B> {
370 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
371 f.debug_struct("RsaPublicKeyComponents")
372 .field("n", &self.n)
373 .field("e", &self.e)
374 .finish()
375 }
376}
377
378impl<B: Copy + AsRef<[u8]> + Debug> Copy for PublicKeyComponents<B> {}
379
380impl<B> PublicKeyComponents<B>
381where
382 B: AsRef<[u8]> + Debug,
383{
384 #[inline]
385 fn build_rsa(&self) -> Result<LcPtr<EVP_PKEY>, ()> {
386 let n_bytes = self.n.as_ref();
387 if n_bytes.is_empty() || n_bytes[0] == 0u8 {
388 return Err(());
389 }
390 let n_bn = DetachableLcPtr::try_from(n_bytes)?;
391
392 let e_bytes = self.e.as_ref();
393 if e_bytes.is_empty() || e_bytes[0] == 0u8 {
394 return Err(());
395 }
396 let e_bn = DetachableLcPtr::try_from(e_bytes)?;
397
398 let rsa = DetachableLcPtr::new(unsafe { RSA_new() })?;
399 if 1 != unsafe { RSA_set0_key(*rsa, *n_bn, *e_bn, null_mut()) } {
400 return Err(());
401 }
402 n_bn.detach();
403 e_bn.detach();
404
405 let mut pkey = LcPtr::new(unsafe { EVP_PKEY_new() })?;
406 if 1 != unsafe { EVP_PKEY_assign_RSA(*pkey.as_mut(), *rsa) } {
407 return Err(());
408 }
409 rsa.detach();
410
411 Ok(pkey)
412 }
413
414 pub fn verify(
422 &self,
423 params: &RsaParameters,
424 message: &[u8],
425 signature: &[u8],
426 ) -> Result<(), Unspecified> {
427 let rsa = self.build_rsa()?;
428 super::signature::verify_rsa_signature(
429 params.digest_algorithm(),
430 params.padding(),
431 &rsa,
432 message,
433 signature,
434 params.bit_size_range(),
435 )
436 }
437}
438
439#[cfg(feature = "ring-io")]
440impl From<&PublicKey> for PublicKeyComponents<Vec<u8>> {
441 fn from(public_key: &PublicKey) -> Self {
442 PublicKeyComponents {
443 n: public_key.modulus.to_vec(),
444 e: public_key.exponent.to_vec(),
445 }
446 }
447}
448
449impl<B> TryInto<PublicEncryptingKey> for PublicKeyComponents<B>
450where
451 B: AsRef<[u8]> + Debug,
452{
453 type Error = Unspecified;
454
455 fn try_into(self) -> Result<PublicEncryptingKey, Self::Error> {
460 let rsa = self.build_rsa()?;
461 PublicEncryptingKey::new(rsa)
462 }
463}
464
465pub(super) fn generate_rsa_key(size: c_int) -> Result<LcPtr<EVP_PKEY>, Unspecified> {
466 let params_fn = |ctx| {
467 if 1 == unsafe { EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, size) } {
468 Ok(())
469 } else {
470 Err(())
471 }
472 };
473
474 LcPtr::<EVP_PKEY>::generate(EVP_PKEY_RSA, Some(params_fn))
475}
476
477#[cfg(feature = "fips")]
478#[must_use]
479pub(super) fn is_valid_fips_key(key: &LcPtr<EVP_PKEY>) -> bool {
480 let rsa_key = key.get_rsa().expect("RSA EVP_PKEY");
482
483 1 == unsafe { RSA_check_fips(*rsa_key as *mut RSA) }
484}
485
486pub(super) fn is_rsa_key(key: &LcPtr<EVP_PKEY>) -> bool {
487 let id = key.id();
488 id == EVP_PKEY_RSA || id == EVP_PKEY_RSA_PSS
489}