1use alloc::{borrow::Cow, string::String, vec::Vec};
4use core::{fmt, str::FromStr};
5
6use rand_core::CryptoRng;
7use rsa::{
8 BoxedUint, Pkcs1v15Sign, Pss,
9 traits::{PrivateKeyParts, PublicKeyParts},
10};
11pub use rsa::{RsaPrivateKey, RsaPublicKey, errors::Error as RsaError};
12use sha2::{Digest, Sha256, Sha384, Sha512};
13
14use crate::{
15 Algorithm, AlgorithmSignature,
16 alg::{SecretBytes, StrongKey, WeakKeyError},
17 jwk::{JsonWebKey, JwkError, KeyType, RsaPrimeFactor, RsaPrivateParts},
18};
19
20#[derive(Debug)]
22#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
23pub struct RsaSignature(Vec<u8>);
24
25impl AlgorithmSignature for RsaSignature {
26 fn try_from_slice(bytes: &[u8]) -> anyhow::Result<Self> {
27 Ok(RsaSignature(bytes.to_vec()))
28 }
29
30 fn as_bytes(&self) -> Cow<'_, [u8]> {
31 Cow::Borrowed(&self.0)
32 }
33}
34
35#[derive(Debug, Copy, Clone, Eq, PartialEq)]
37enum HashAlg {
38 Sha256,
39 Sha384,
40 Sha512,
41}
42
43impl HashAlg {
44 fn digest(self, message: &[u8]) -> HashDigest {
45 match self {
46 Self::Sha256 => HashDigest::Sha256(Sha256::digest(message).into()),
47 Self::Sha384 => HashDigest::Sha384(Sha384::digest(message).into()),
48 Self::Sha512 => HashDigest::Sha512(Sha512::digest(message).into()),
49 }
50 }
51}
52
53#[derive(Debug)]
55enum HashDigest {
56 Sha256([u8; 32]),
57 Sha384([u8; 48]),
58 Sha512([u8; 64]),
59}
60
61impl AsRef<[u8]> for HashDigest {
62 fn as_ref(&self) -> &[u8] {
63 match self {
64 Self::Sha256(bytes) => bytes,
65 Self::Sha384(bytes) => bytes,
66 Self::Sha512(bytes) => bytes,
67 }
68 }
69}
70
71#[derive(Debug, Copy, Clone, Eq, PartialEq)]
73enum Padding {
74 Pkcs1v15,
75 Pss,
76}
77
78#[derive(Debug)]
79enum PaddingScheme {
80 Pkcs1v15(Pkcs1v15Sign),
81 Pss256(Pss<Sha256>),
82 Pss384(Pss<Sha384>),
83 Pss512(Pss<Sha512>),
84}
85
86#[derive(Debug, Copy, Clone, Eq, PartialEq)]
88#[non_exhaustive]
89#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
90pub enum ModulusBits {
91 TwoKibibytes,
93 ThreeKibibytes,
95 FourKibibytes,
97}
98
99impl ModulusBits {
100 pub fn bits(self) -> usize {
102 match self {
103 Self::TwoKibibytes => 2_048,
104 Self::ThreeKibibytes => 3_072,
105 Self::FourKibibytes => 4_096,
106 }
107 }
108
109 fn is_valid_bits(bits: u32) -> bool {
110 matches!(bits, 2_048 | 3_072 | 4_096)
111 }
112}
113
114impl TryFrom<usize> for ModulusBits {
115 type Error = ModulusBitsError;
116
117 fn try_from(value: usize) -> Result<Self, Self::Error> {
118 match value {
119 2_048 => Ok(Self::TwoKibibytes),
120 3_072 => Ok(Self::ThreeKibibytes),
121 4_096 => Ok(Self::FourKibibytes),
122 _ => Err(ModulusBitsError(())),
123 }
124 }
125}
126
127#[derive(Debug)]
129#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
130pub struct ModulusBitsError(());
131
132impl fmt::Display for ModulusBitsError {
133 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
134 formatter.write_str(
135 "Unsupported bit length of RSA modulus; only lengths 2048, 3072 and 4096 \
136 are supported.",
137 )
138 }
139}
140
141impl core::error::Error for ModulusBitsError {}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq)]
166#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
167pub struct Rsa {
168 hash_alg: HashAlg,
169 padding_alg: Padding,
170}
171
172impl Algorithm for Rsa {
173 type SigningKey = RsaPrivateKey;
174 type VerifyingKey = RsaPublicKey;
175 type Signature = RsaSignature;
176
177 fn name(&self) -> Cow<'static, str> {
178 Cow::Borrowed(self.alg_name())
179 }
180
181 fn sign(&self, signing_key: &Self::SigningKey, message: &[u8]) -> Self::Signature {
182 let digest = self.hash_alg.digest(message);
183 let digest = digest.as_ref();
184 let signing_result = match self.padding_scheme() {
185 PaddingScheme::Pkcs1v15(padding) => signing_key.sign_with_rng(
186 &mut rand_core::UnwrapErr(getrandom::SysRng),
187 padding,
188 digest,
189 ),
190 PaddingScheme::Pss256(padding) => signing_key.sign_with_rng(
191 &mut rand_core::UnwrapErr(getrandom::SysRng),
192 padding,
193 digest,
194 ),
195 PaddingScheme::Pss384(padding) => signing_key.sign_with_rng(
196 &mut rand_core::UnwrapErr(getrandom::SysRng),
197 padding,
198 digest,
199 ),
200 PaddingScheme::Pss512(padding) => signing_key.sign_with_rng(
201 &mut rand_core::UnwrapErr(getrandom::SysRng),
202 padding,
203 digest,
204 ),
205 };
206 RsaSignature(signing_result.expect("Unexpected RSA signature failure"))
207 }
208
209 fn verify_signature(
210 &self,
211 signature: &Self::Signature,
212 verifying_key: &Self::VerifyingKey,
213 message: &[u8],
214 ) -> bool {
215 let digest = self.hash_alg.digest(message);
216 let digest = digest.as_ref();
217 let verify_result = match self.padding_scheme() {
218 PaddingScheme::Pkcs1v15(padding) => verifying_key.verify(padding, digest, &signature.0),
219 PaddingScheme::Pss256(padding) => verifying_key.verify(padding, digest, &signature.0),
220 PaddingScheme::Pss384(padding) => verifying_key.verify(padding, digest, &signature.0),
221 PaddingScheme::Pss512(padding) => verifying_key.verify(padding, digest, &signature.0),
222 };
223 verify_result.is_ok()
224 }
225}
226
227impl Rsa {
228 const fn new(hash_alg: HashAlg, padding_alg: Padding) -> Self {
229 Rsa {
230 hash_alg,
231 padding_alg,
232 }
233 }
234
235 pub const fn rs256() -> Rsa {
237 Rsa::new(HashAlg::Sha256, Padding::Pkcs1v15)
238 }
239
240 pub const fn rs384() -> Rsa {
242 Rsa::new(HashAlg::Sha384, Padding::Pkcs1v15)
243 }
244
245 pub const fn rs512() -> Rsa {
247 Rsa::new(HashAlg::Sha512, Padding::Pkcs1v15)
248 }
249
250 pub const fn ps256() -> Rsa {
252 Rsa::new(HashAlg::Sha256, Padding::Pss)
253 }
254
255 pub const fn ps384() -> Rsa {
257 Rsa::new(HashAlg::Sha384, Padding::Pss)
258 }
259
260 pub const fn ps512() -> Rsa {
262 Rsa::new(HashAlg::Sha512, Padding::Pss)
263 }
264
265 pub fn with_name(name: &str) -> Self {
272 name.parse().unwrap()
273 }
274
275 fn padding_scheme(self) -> PaddingScheme {
276 match self.padding_alg {
277 Padding::Pkcs1v15 => PaddingScheme::Pkcs1v15(match self.hash_alg {
278 HashAlg::Sha256 => Pkcs1v15Sign::new::<Sha256>(),
279 HashAlg::Sha384 => Pkcs1v15Sign::new::<Sha384>(),
280 HashAlg::Sha512 => Pkcs1v15Sign::new::<Sha512>(),
281 }),
282 Padding::Pss => {
283 match self.hash_alg {
286 HashAlg::Sha256 => {
287 PaddingScheme::Pss256(Pss::new_with_salt(Sha256::output_size()))
288 }
289 HashAlg::Sha384 => {
290 PaddingScheme::Pss384(Pss::new_with_salt(Sha384::output_size()))
291 }
292 HashAlg::Sha512 => {
293 PaddingScheme::Pss512(Pss::new_with_salt(Sha512::output_size()))
294 }
295 }
296 }
297 }
298 }
299
300 fn alg_name(self) -> &'static str {
301 match (self.padding_alg, self.hash_alg) {
302 (Padding::Pkcs1v15, HashAlg::Sha256) => "RS256",
303 (Padding::Pkcs1v15, HashAlg::Sha384) => "RS384",
304 (Padding::Pkcs1v15, HashAlg::Sha512) => "RS512",
305 (Padding::Pss, HashAlg::Sha256) => "PS256",
306 (Padding::Pss, HashAlg::Sha384) => "PS384",
307 (Padding::Pss, HashAlg::Sha512) => "PS512",
308 }
309 }
310
311 pub fn generate<R: CryptoRng>(
313 rng: &mut R,
314 modulus_bits: ModulusBits,
315 ) -> rsa::errors::Result<(StrongKey<RsaPrivateKey>, StrongKey<RsaPublicKey>)> {
316 let signing_key = RsaPrivateKey::new(rng, modulus_bits.bits())?;
317 let verifying_key = signing_key.to_public_key();
318 Ok((StrongKey(signing_key), StrongKey(verifying_key)))
319 }
320}
321
322impl FromStr for Rsa {
323 type Err = RsaParseError;
324
325 fn from_str(s: &str) -> Result<Self, Self::Err> {
326 Ok(match s {
327 "RS256" => Self::rs256(),
328 "RS384" => Self::rs384(),
329 "RS512" => Self::rs512(),
330 "PS256" => Self::ps256(),
331 "PS384" => Self::ps384(),
332 "PS512" => Self::ps512(),
333 _ => return Err(RsaParseError(s.into())),
334 })
335 }
336}
337
338#[derive(Debug)]
340#[cfg_attr(docsrs, doc(cfg(feature = "rsa")))]
341pub struct RsaParseError(String);
342
343impl fmt::Display for RsaParseError {
344 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
345 write!(formatter, "Invalid RSA algorithm name: {}", self.0)
346 }
347}
348
349impl core::error::Error for RsaParseError {}
350
351impl StrongKey<RsaPrivateKey> {
352 pub fn to_public_key(&self) -> StrongKey<RsaPublicKey> {
354 StrongKey(self.0.to_public_key())
355 }
356}
357
358impl TryFrom<RsaPrivateKey> for StrongKey<RsaPrivateKey> {
359 type Error = WeakKeyError<RsaPrivateKey>;
360
361 fn try_from(key: RsaPrivateKey) -> Result<Self, Self::Error> {
362 if ModulusBits::is_valid_bits(key.n().bits()) {
363 Ok(StrongKey(key))
364 } else {
365 Err(WeakKeyError(key))
366 }
367 }
368}
369
370impl TryFrom<RsaPublicKey> for StrongKey<RsaPublicKey> {
371 type Error = WeakKeyError<RsaPublicKey>;
372
373 fn try_from(key: RsaPublicKey) -> Result<Self, Self::Error> {
374 if ModulusBits::is_valid_bits(key.n().bits()) {
375 Ok(StrongKey(key))
376 } else {
377 Err(WeakKeyError(key))
378 }
379 }
380}
381
382impl<'a> From<&'a RsaPublicKey> for JsonWebKey<'a> {
383 fn from(key: &'a RsaPublicKey) -> JsonWebKey<'a> {
384 JsonWebKey::Rsa {
385 modulus: Cow::Owned(key.n().to_be_bytes_trimmed_vartime().into()),
386 public_exponent: Cow::Owned(key.e().to_be_bytes_trimmed_vartime().into()),
387 private_parts: None,
388 }
389 }
390}
391
392#[allow(clippy::cast_possible_truncation)] fn secret_uint_from_slice(slice: &[u8], precision: u32) -> Result<BoxedUint, JwkError> {
394 debug_assert!(precision <= RsaPublicKey::MAX_SIZE as u32);
395 BoxedUint::from_be_slice(slice, precision).map_err(|err| JwkError::custom(anyhow::anyhow!(err)))
396}
397
398fn secret_uint_to_slice(secret: &BoxedUint, precision: u32) -> SecretBytes<'static> {
400 let bytes = secret.to_be_bytes();
401 let precision_bytes = precision.div_ceil(8) as usize;
402 SecretBytes::owned_slice(if bytes.len() > precision_bytes {
403 let first_idx = bytes.len() - precision_bytes;
404 bytes[first_idx..].into()
405 } else {
406 bytes
407 })
408}
409
410fn pub_exponent_from_slice(slice: &[u8]) -> Result<BoxedUint, JwkError> {
411 BoxedUint::from_be_slice(slice, RsaPublicKey::MAX_PUB_EXPONENT.ilog2() + 1)
412 .map_err(|err| JwkError::custom(anyhow::anyhow!(err)))
413}
414
415impl TryFrom<&JsonWebKey<'_>> for RsaPublicKey {
416 type Error = JwkError;
417
418 fn try_from(jwk: &JsonWebKey<'_>) -> Result<Self, Self::Error> {
419 let JsonWebKey::Rsa {
420 modulus,
421 public_exponent,
422 ..
423 } = jwk
424 else {
425 return Err(JwkError::key_type(jwk, KeyType::Rsa));
426 };
427
428 let e = pub_exponent_from_slice(public_exponent)?;
429 let n = BoxedUint::from_be_slice_vartime(modulus);
430 Self::new(n, e).map_err(|err| JwkError::custom(anyhow::anyhow!(err)))
431 }
432}
433
434impl<'a> From<&'a RsaPrivateKey> for JsonWebKey<'a> {
440 fn from(key: &'a RsaPrivateKey) -> JsonWebKey<'a> {
441 const MSG: &str = "RsaPrivateKey must have at least 2 prime factors";
442
443 let p = key.primes().first().expect(MSG);
444 let q = key.primes().get(1).expect(MSG);
445 let precision = key.n().bits_precision();
450
451 let private_parts = RsaPrivateParts {
452 private_exponent: secret_uint_to_slice(key.d(), precision),
453 prime_factor_p: secret_uint_to_slice(p, precision),
454 prime_factor_q: secret_uint_to_slice(q, precision),
455 p_crt_exponent: None,
456 q_crt_exponent: None,
457 q_crt_coefficient: None,
458 other_prime_factors: key.primes()[2..]
459 .iter()
460 .map(|factor| RsaPrimeFactor {
461 factor: secret_uint_to_slice(factor, precision),
462 crt_exponent: None,
463 crt_coefficient: None,
464 })
465 .collect(),
466 };
467
468 JsonWebKey::Rsa {
469 modulus: Cow::Owned(key.n().to_be_bytes_trimmed_vartime().into()),
470 public_exponent: Cow::Owned(key.e().to_be_bytes_trimmed_vartime().into()),
471 private_parts: Some(private_parts),
472 }
473 }
474}
475
476impl TryFrom<&JsonWebKey<'_>> for RsaPrivateKey {
481 type Error = JwkError;
482
483 fn try_from(jwk: &JsonWebKey<'_>) -> Result<Self, Self::Error> {
484 let JsonWebKey::Rsa {
485 modulus,
486 public_exponent,
487 private_parts,
488 } = jwk
489 else {
490 return Err(JwkError::key_type(jwk, KeyType::Rsa));
491 };
492
493 let RsaPrivateParts {
494 private_exponent: d,
495 prime_factor_p,
496 prime_factor_q,
497 other_prime_factors,
498 ..
499 } = private_parts
500 .as_ref()
501 .ok_or_else(|| JwkError::NoField("d".into()))?;
502
503 let e = pub_exponent_from_slice(public_exponent)?;
504 let n = BoxedUint::from_be_slice_vartime(modulus);
505
506 let precision = n.bits().div_ceil(8) * 8;
508 if precision as usize > RsaPublicKey::MAX_SIZE {
509 return Err(JwkError::Custom(anyhow::anyhow!(
510 "Modulus precision ({got}) exceeds maximum supported value ({max})",
511 got = n.bits(),
512 max = RsaPublicKey::MAX_SIZE
513 )));
514 }
515
516 let d = secret_uint_from_slice(d, precision)?;
517 let mut factors = Vec::with_capacity(2 + other_prime_factors.len());
518 factors.push(secret_uint_from_slice(prime_factor_p, precision)?);
519 factors.push(secret_uint_from_slice(prime_factor_q, precision)?);
520 for other_factor in other_prime_factors {
521 factors.push(secret_uint_from_slice(&other_factor.factor, precision)?);
522 }
523
524 let key = Self::from_components(n, e, d, factors);
525 let key = key.map_err(|err| JwkError::custom(anyhow::anyhow!(err)))?;
526 key.validate()
527 .map_err(|err| JwkError::custom(anyhow::anyhow!(err)))?;
528 Ok(key)
529 }
530}