uselesskey_rsa/keypair.rs
1use std::fmt;
2use std::sync::Arc;
3
4#[cfg(feature = "legacy-rsa09")]
5use rand_chacha::ChaCha20Rng;
6#[cfg(feature = "legacy-rsa09")]
7use rand_chacha::rand_core::SeedableRng;
8#[cfg(not(feature = "legacy-rsa09"))]
9use rand_chacha10::ChaCha20Rng;
10#[cfg(not(feature = "legacy-rsa09"))]
11use rand_chacha10::rand_core::SeedableRng;
12use rsa as rsa10;
13#[cfg(feature = "legacy-rsa09")]
14use rsa09::pkcs8::{EncodePrivateKey, EncodePublicKey, LineEnding};
15#[cfg(feature = "legacy-rsa09")]
16use rsa09::{RsaPrivateKey, RsaPublicKey};
17#[cfg(feature = "legacy-rsa09")]
18use rsa10::pkcs8::DecodePrivateKey;
19#[cfg(feature = "jwk")]
20use rsa10::pkcs8::DecodePublicKey;
21#[cfg(not(feature = "legacy-rsa09"))]
22use rsa10::pkcs8::{EncodePrivateKey, EncodePublicKey, LineEnding};
23use uselesskey_core::negative::CorruptPem;
24use uselesskey_core::sink::TempArtifact;
25use uselesskey_core::{Error, Factory};
26use uselesskey_core_keypair_material::Pkcs8SpkiKeyMaterial;
27
28use crate::RsaSpec;
29
30/// Cache domain for RSA keypair fixtures.
31///
32/// Keep this stable: changing it changes deterministic outputs.
33pub const DOMAIN_RSA_KEYPAIR: &str = "uselesskey:rsa:keypair";
34
35/// An RSA keypair fixture with various output formats.
36///
37/// Created via [`RsaFactoryExt::rsa()`]. Provides access to:
38/// - Private key in PKCS#8 PEM and DER formats
39/// - Public key in SPKI PEM and DER formats
40/// - Negative fixtures (corrupted PEM, truncated DER, mismatched keys)
41/// - JWK output (with the `jwk` feature)
42///
43/// # Examples
44///
45/// ```
46/// use uselesskey_core::Factory;
47/// use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
48///
49/// let fx = Factory::random();
50/// let keypair = fx.rsa("my-service", RsaSpec::rs256());
51///
52/// // Access key material
53/// let private_pem = keypair.private_key_pkcs8_pem();
54/// let public_der = keypair.public_key_spki_der();
55///
56/// assert!(private_pem.contains("BEGIN PRIVATE KEY"));
57/// assert!(!public_der.is_empty());
58/// ```
59#[derive(Clone)]
60pub struct RsaKeyPair {
61 factory: Factory,
62 label: String,
63 spec: RsaSpec,
64 inner: Arc<Inner>,
65}
66
67struct Inner {
68 /// Kept for potential signing methods; not currently used.
69 _private: rsa10::RsaPrivateKey,
70 #[cfg(feature = "jwk")]
71 public: rsa10::RsaPublicKey,
72 material: Pkcs8SpkiKeyMaterial,
73}
74
75impl fmt::Debug for RsaKeyPair {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 f.debug_struct("RsaKeyPair")
78 .field("label", &self.label)
79 .field("spec", &self.spec)
80 .finish_non_exhaustive()
81 }
82}
83
84/// Extension trait to hang RSA helpers off the core [`Factory`].
85pub trait RsaFactoryExt {
86 /// Generate (or retrieve from cache) an RSA keypair fixture.
87 ///
88 /// The `label` identifies this keypair within your test suite.
89 /// In deterministic mode, `seed + label + spec` always produces the same key.
90 ///
91 /// # Examples
92 ///
93 /// ```
94 /// use uselesskey_core::{Factory, Seed};
95 /// use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
96 ///
97 /// let seed = Seed::from_env_value("test-seed").unwrap();
98 /// let fx = Factory::deterministic(seed);
99 /// let keypair = fx.rsa("my-service", RsaSpec::rs256());
100 ///
101 /// let pem = keypair.private_key_pkcs8_pem();
102 /// assert!(pem.contains("BEGIN PRIVATE KEY"));
103 /// ```
104 fn rsa(&self, label: impl AsRef<str>, spec: RsaSpec) -> RsaKeyPair;
105}
106
107impl RsaFactoryExt for Factory {
108 fn rsa(&self, label: impl AsRef<str>, spec: RsaSpec) -> RsaKeyPair {
109 RsaKeyPair::new(self.clone(), label.as_ref(), spec)
110 }
111}
112
113impl RsaKeyPair {
114 fn new(factory: Factory, label: &str, spec: RsaSpec) -> Self {
115 let inner = load_inner(&factory, label, spec, "good");
116 Self {
117 factory,
118 label: label.to_string(),
119 spec,
120 inner,
121 }
122 }
123
124 fn load_variant(&self, variant: &str) -> Arc<Inner> {
125 load_inner(&self.factory, &self.label, self.spec, variant)
126 }
127
128 /// Returns the spec used to create this keypair.
129 ///
130 /// # Examples
131 ///
132 /// ```no_run
133 /// # use uselesskey_core::Factory;
134 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
135 /// let fx = Factory::random();
136 /// let kp = fx.rsa("svc", RsaSpec::rs256());
137 /// assert_eq!(kp.spec(), RsaSpec::rs256());
138 /// ```
139 pub fn spec(&self) -> RsaSpec {
140 self.spec
141 }
142
143 /// Returns the label used to create this keypair.
144 ///
145 /// # Examples
146 ///
147 /// ```no_run
148 /// # use uselesskey_core::Factory;
149 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
150 /// let fx = Factory::random();
151 /// let kp = fx.rsa("my-svc", RsaSpec::rs256());
152 /// assert_eq!(kp.label(), "my-svc");
153 /// ```
154 pub fn label(&self) -> &str {
155 &self.label
156 }
157
158 #[cfg(feature = "jwk")]
159 fn jwk_alg(&self) -> &'static str {
160 match self.spec.bits {
161 3072 => "RS384",
162 4096 => "RS512",
163 _ => "RS256",
164 }
165 }
166
167 /// PKCS#8 DER-encoded private key bytes.
168 ///
169 /// # Examples
170 ///
171 /// ```no_run
172 /// # use uselesskey_core::{Factory, Seed};
173 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
174 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
175 /// let kp = fx.rsa("svc", RsaSpec::rs256());
176 /// let der = kp.private_key_pkcs8_der();
177 /// assert!(!der.is_empty());
178 /// ```
179 pub fn private_key_pkcs8_der(&self) -> &[u8] {
180 self.inner.material.private_key_pkcs8_der()
181 }
182
183 /// PKCS#8 PEM-encoded private key.
184 ///
185 /// # Examples
186 ///
187 /// ```no_run
188 /// # use uselesskey_core::{Factory, Seed};
189 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
190 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
191 /// let kp = fx.rsa("svc", RsaSpec::rs256());
192 /// let pem = kp.private_key_pkcs8_pem();
193 /// assert!(pem.starts_with("-----BEGIN PRIVATE KEY-----"));
194 /// ```
195 pub fn private_key_pkcs8_pem(&self) -> &str {
196 self.inner.material.private_key_pkcs8_pem()
197 }
198
199 /// SPKI DER-encoded public key bytes.
200 ///
201 /// # Examples
202 ///
203 /// ```no_run
204 /// # use uselesskey_core::{Factory, Seed};
205 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
206 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
207 /// let kp = fx.rsa("svc", RsaSpec::rs256());
208 /// let der = kp.public_key_spki_der();
209 /// assert!(!der.is_empty());
210 /// ```
211 pub fn public_key_spki_der(&self) -> &[u8] {
212 self.inner.material.public_key_spki_der()
213 }
214
215 /// SPKI PEM-encoded public key.
216 ///
217 /// # Examples
218 ///
219 /// ```no_run
220 /// # use uselesskey_core::{Factory, Seed};
221 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
222 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
223 /// let kp = fx.rsa("svc", RsaSpec::rs256());
224 /// let pem = kp.public_key_spki_pem();
225 /// assert!(pem.starts_with("-----BEGIN PUBLIC KEY-----"));
226 /// ```
227 pub fn public_key_spki_pem(&self) -> &str {
228 self.inner.material.public_key_spki_pem()
229 }
230
231 /// Write the PKCS#8 PEM private key to a tempfile and return the handle.
232 ///
233 /// # Examples
234 ///
235 /// ```no_run
236 /// # use uselesskey_core::{Factory, Seed};
237 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
238 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
239 /// let kp = fx.rsa("svc", RsaSpec::rs256());
240 /// let temp = kp.write_private_key_pkcs8_pem().unwrap();
241 /// assert!(temp.path().exists());
242 /// ```
243 pub fn write_private_key_pkcs8_pem(&self) -> Result<TempArtifact, Error> {
244 self.inner.material.write_private_key_pkcs8_pem()
245 }
246
247 /// Write the SPKI PEM public key to a tempfile and return the handle.
248 ///
249 /// # Examples
250 ///
251 /// ```no_run
252 /// # use uselesskey_core::{Factory, Seed};
253 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
254 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
255 /// let kp = fx.rsa("svc", RsaSpec::rs256());
256 /// let temp = kp.write_public_key_spki_pem().unwrap();
257 /// assert!(temp.path().exists());
258 /// ```
259 pub fn write_public_key_spki_pem(&self) -> Result<TempArtifact, Error> {
260 self.inner.material.write_public_key_spki_pem()
261 }
262
263 /// Produce a corrupted variant of the PKCS#8 PEM.
264 ///
265 /// # Examples
266 ///
267 /// ```no_run
268 /// # use uselesskey_core::{Factory, Seed};
269 /// # use uselesskey_core::negative::CorruptPem;
270 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
271 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
272 /// let kp = fx.rsa("svc", RsaSpec::rs256());
273 /// let bad = kp.private_key_pkcs8_pem_corrupt(CorruptPem::BadHeader);
274 /// assert!(bad.contains("CORRUPTED"));
275 /// ```
276 pub fn private_key_pkcs8_pem_corrupt(&self, how: CorruptPem) -> String {
277 self.inner.material.private_key_pkcs8_pem_corrupt(how)
278 }
279
280 /// Produce a deterministic corrupted PKCS#8 PEM using a variant string.
281 ///
282 /// # Examples
283 ///
284 /// ```no_run
285 /// # use uselesskey_core::{Factory, Seed};
286 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
287 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
288 /// let kp = fx.rsa("svc", RsaSpec::rs256());
289 /// let bad = kp.private_key_pkcs8_pem_corrupt_deterministic("corrupt:v1");
290 /// assert!(!bad.is_empty());
291 /// ```
292 pub fn private_key_pkcs8_pem_corrupt_deterministic(&self, variant: &str) -> String {
293 self.inner
294 .material
295 .private_key_pkcs8_pem_corrupt_deterministic(variant)
296 }
297
298 /// Produce a truncated variant of the PKCS#8 DER.
299 ///
300 /// # Examples
301 ///
302 /// ```no_run
303 /// # use uselesskey_core::{Factory, Seed};
304 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
305 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
306 /// let kp = fx.rsa("svc", RsaSpec::rs256());
307 /// let truncated = kp.private_key_pkcs8_der_truncated(10);
308 /// assert_eq!(truncated.len(), 10);
309 /// ```
310 pub fn private_key_pkcs8_der_truncated(&self, len: usize) -> Vec<u8> {
311 self.inner.material.private_key_pkcs8_der_truncated(len)
312 }
313
314 /// Produce a deterministic corrupted PKCS#8 DER using a variant string.
315 ///
316 /// # Examples
317 ///
318 /// ```no_run
319 /// # use uselesskey_core::{Factory, Seed};
320 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
321 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
322 /// let kp = fx.rsa("svc", RsaSpec::rs256());
323 /// let bad = kp.private_key_pkcs8_der_corrupt_deterministic("corrupt:v1");
324 /// assert!(!bad.is_empty());
325 /// ```
326 pub fn private_key_pkcs8_der_corrupt_deterministic(&self, variant: &str) -> Vec<u8> {
327 self.inner
328 .material
329 .private_key_pkcs8_der_corrupt_deterministic(variant)
330 }
331
332 /// Return a valid (parseable) public key that does *not* match this private key.
333 ///
334 /// # Examples
335 ///
336 /// ```no_run
337 /// # use uselesskey_core::{Factory, Seed};
338 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
339 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
340 /// let kp = fx.rsa("svc", RsaSpec::rs256());
341 /// let wrong_pub = kp.mismatched_public_key_spki_der();
342 /// assert_ne!(wrong_pub, kp.public_key_spki_der());
343 /// ```
344 pub fn mismatched_public_key_spki_der(&self) -> Vec<u8> {
345 let other = self.load_variant("mismatch");
346 other.material.public_key_spki_der().to_vec()
347 }
348
349 /// A stable key identifier derived from the public key (base64url blake3 hash prefix).
350 ///
351 /// # Examples
352 ///
353 /// ```no_run
354 /// # use uselesskey_core::{Factory, Seed};
355 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
356 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
357 /// let kp = fx.rsa("svc", RsaSpec::rs256());
358 /// let kid = kp.kid();
359 /// assert!(!kid.is_empty());
360 /// ```
361 #[cfg(feature = "jwk")]
362 pub fn kid(&self) -> String {
363 self.inner.material.kid()
364 }
365
366 /// Alias for [`Self::public_jwk`].
367 ///
368 /// Requires the `jwk` feature.
369 ///
370 /// # Examples
371 ///
372 /// ```no_run
373 /// # use uselesskey_core::{Factory, Seed};
374 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
375 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
376 /// let kp = fx.rsa("svc", RsaSpec::rs256());
377 /// let jwk = kp.public_key_jwk();
378 /// assert_eq!(jwk.to_value()["kty"], "RSA");
379 /// ```
380 #[cfg(feature = "jwk")]
381 pub fn public_key_jwk(&self) -> uselesskey_jwk::PublicJwk {
382 self.public_jwk()
383 }
384
385 /// Public JWK for this keypair (kty=RSA, use=sig, kid=...).
386 ///
387 /// Requires the `jwk` feature.
388 ///
389 /// # Examples
390 ///
391 /// ```no_run
392 /// # use uselesskey_core::{Factory, Seed};
393 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
394 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
395 /// let kp = fx.rsa("svc", RsaSpec::rs256());
396 /// let jwk = kp.public_jwk();
397 /// let val = jwk.to_value();
398 /// assert_eq!(val["kty"], "RSA");
399 /// assert_eq!(val["alg"], "RS256");
400 /// ```
401 #[cfg(feature = "jwk")]
402 pub fn public_jwk(&self) -> uselesskey_jwk::PublicJwk {
403 use base64::Engine as _;
404 use base64::engine::general_purpose::URL_SAFE_NO_PAD;
405 use rsa10::traits::PublicKeyParts;
406 use uselesskey_jwk::{PublicJwk, RsaPublicJwk};
407
408 let n = self.inner.public.n_bytes();
409 let e = self.inner.public.e_bytes();
410
411 PublicJwk::Rsa(RsaPublicJwk {
412 kty: "RSA",
413 use_: "sig",
414 alg: self.jwk_alg(),
415 kid: self.kid(),
416 n: URL_SAFE_NO_PAD.encode(n),
417 e: URL_SAFE_NO_PAD.encode(e),
418 })
419 }
420
421 /// Private JWK for this keypair (kty=RSA, use=sig, kid=...).
422 ///
423 /// Requires the `jwk` feature.
424 ///
425 /// # Examples
426 ///
427 /// ```no_run
428 /// # use uselesskey_core::{Factory, Seed};
429 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
430 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
431 /// let kp = fx.rsa("svc", RsaSpec::rs256());
432 /// let jwk = kp.private_key_jwk();
433 /// let val = jwk.to_value();
434 /// assert_eq!(val["kty"], "RSA");
435 /// assert!(val["d"].is_string());
436 /// ```
437 #[cfg(feature = "jwk")]
438 pub fn private_key_jwk(&self) -> uselesskey_jwk::PrivateJwk {
439 use base64::Engine as _;
440 use base64::engine::general_purpose::URL_SAFE_NO_PAD;
441 use rsa10::traits::{PrivateKeyParts, PublicKeyParts};
442 use uselesskey_jwk::{PrivateJwk, RsaPrivateJwk};
443
444 let private = &self.inner._private;
445 let primes = private.primes();
446 assert!(primes.len() >= 2, "expected at least two RSA primes");
447
448 let n = private.n_bytes();
449 let e = private.e_bytes();
450 let d = private.d().to_be_bytes_trimmed_vartime();
451 let p = primes[0].to_be_bytes_trimmed_vartime();
452 let q = primes[1].to_be_bytes_trimmed_vartime();
453 let dp = private.dp().expect("dp").to_be_bytes_trimmed_vartime();
454 let dq = private.dq().expect("dq").to_be_bytes_trimmed_vartime();
455 let qi = private
456 .qinv()
457 .expect("qinv")
458 .retrieve()
459 .to_be_bytes_trimmed_vartime();
460
461 PrivateJwk::Rsa(RsaPrivateJwk {
462 kty: "RSA",
463 use_: "sig",
464 alg: self.jwk_alg(),
465 kid: self.kid(),
466 n: URL_SAFE_NO_PAD.encode(n),
467 e: URL_SAFE_NO_PAD.encode(e),
468 d: URL_SAFE_NO_PAD.encode(d),
469 p: URL_SAFE_NO_PAD.encode(p),
470 q: URL_SAFE_NO_PAD.encode(q),
471 dp: URL_SAFE_NO_PAD.encode(dp),
472 dq: URL_SAFE_NO_PAD.encode(dq),
473 qi: URL_SAFE_NO_PAD.encode(qi),
474 })
475 }
476
477 /// JWKS containing a single public key.
478 ///
479 /// # Examples
480 ///
481 /// ```no_run
482 /// # use uselesskey_core::{Factory, Seed};
483 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
484 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
485 /// let kp = fx.rsa("svc", RsaSpec::rs256());
486 /// let jwks = kp.public_jwks();
487 /// assert!(jwks.to_value()["keys"].is_array());
488 /// ```
489 #[cfg(feature = "jwk")]
490 pub fn public_jwks(&self) -> uselesskey_jwk::Jwks {
491 use uselesskey_jwk::JwksBuilder;
492
493 let mut builder = JwksBuilder::new();
494 builder.push_public(self.public_jwk());
495 builder.build()
496 }
497
498 /// Public JWK serialized to `serde_json::Value`.
499 ///
500 /// Requires the `jwk` feature.
501 ///
502 /// # Examples
503 ///
504 /// ```no_run
505 /// # use uselesskey_core::{Factory, Seed};
506 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
507 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
508 /// let kp = fx.rsa("svc", RsaSpec::rs256());
509 /// let val = kp.public_jwk_json();
510 /// assert_eq!(val["kty"], "RSA");
511 /// ```
512 #[cfg(feature = "jwk")]
513 pub fn public_jwk_json(&self) -> serde_json::Value {
514 self.public_jwk().to_value()
515 }
516
517 /// JWKS serialized to `serde_json::Value`.
518 ///
519 /// Requires the `jwk` feature.
520 ///
521 /// # Examples
522 ///
523 /// ```no_run
524 /// # use uselesskey_core::{Factory, Seed};
525 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
526 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
527 /// let kp = fx.rsa("svc", RsaSpec::rs256());
528 /// let val = kp.public_jwks_json();
529 /// assert!(val["keys"].is_array());
530 /// ```
531 #[cfg(feature = "jwk")]
532 pub fn public_jwks_json(&self) -> serde_json::Value {
533 self.public_jwks().to_value()
534 }
535
536 /// Private JWK serialized to `serde_json::Value`.
537 ///
538 /// Requires the `jwk` feature.
539 ///
540 /// # Examples
541 ///
542 /// ```no_run
543 /// # use uselesskey_core::{Factory, Seed};
544 /// # use uselesskey_rsa::{RsaFactoryExt, RsaSpec};
545 /// let fx = Factory::deterministic(Seed::from_env_value("test-seed").unwrap());
546 /// let kp = fx.rsa("svc", RsaSpec::rs256());
547 /// let val = kp.private_key_jwk_json();
548 /// assert_eq!(val["kty"], "RSA");
549 /// assert!(val["d"].is_string());
550 /// ```
551 #[cfg(feature = "jwk")]
552 pub fn private_key_jwk_json(&self) -> serde_json::Value {
553 self.private_key_jwk().to_value()
554 }
555}
556
557fn load_inner(factory: &Factory, label: &str, spec: RsaSpec, variant: &str) -> Arc<Inner> {
558 // Validate what we can, up front.
559 assert!(
560 spec.bits >= 1024,
561 "RSA bits too small for most parsers; got {}",
562 spec.bits
563 );
564 assert!(
565 spec.exponent == 65537,
566 "custom RSA public exponent not supported in v1; got {}",
567 spec.exponent
568 );
569
570 let spec_bytes = spec.stable_bytes();
571
572 factory.get_or_init(DOMAIN_RSA_KEYPAIR, label, &spec_bytes, variant, |seed| {
573 let mut rng = ChaCha20Rng::from_seed(*seed.bytes());
574
575 #[cfg(feature = "legacy-rsa09")]
576 let private09 = RsaPrivateKey::new(&mut rng, spec.bits).expect("RSA keygen failed");
577 #[cfg(feature = "legacy-rsa09")]
578 let public09 = RsaPublicKey::from(&private09);
579
580 #[cfg(feature = "legacy-rsa09")]
581 let pkcs8_der_doc = private09
582 .to_pkcs8_der()
583 .expect("failed to encode RSA private key as PKCS#8 DER");
584 #[cfg(feature = "legacy-rsa09")]
585 let pkcs8_der: Arc<[u8]> = Arc::from(pkcs8_der_doc.as_bytes());
586
587 #[cfg(feature = "legacy-rsa09")]
588 let pkcs8_pem = private09
589 .to_pkcs8_pem(LineEnding::LF)
590 .expect("failed to encode RSA private key as PKCS#8 PEM")
591 .to_string();
592
593 #[cfg(feature = "legacy-rsa09")]
594 let spki_der_doc = public09
595 .to_public_key_der()
596 .expect("failed to encode RSA public key as SPKI DER");
597 #[cfg(feature = "legacy-rsa09")]
598 let spki_der: Arc<[u8]> = Arc::from(spki_der_doc.as_bytes());
599
600 #[cfg(feature = "legacy-rsa09")]
601 let spki_pem = public09
602 .to_public_key_pem(LineEnding::LF)
603 .expect("failed to encode RSA public key as SPKI PEM")
604 .to_string();
605
606 #[cfg(feature = "legacy-rsa09")]
607 let private = rsa10::RsaPrivateKey::from_pkcs8_der(&pkcs8_der)
608 .expect("failed to parse V1 RSA private key into rsa 0.10");
609 #[cfg(feature = "jwk")]
610 #[cfg(feature = "legacy-rsa09")]
611 let public = rsa10::RsaPublicKey::from_public_key_der(&spki_der)
612 .expect("failed to parse V1 RSA public key into rsa 0.10");
613 #[cfg(not(feature = "legacy-rsa09"))]
614 let private = rsa10::RsaPrivateKey::new(&mut rng, spec.bits).expect("RSA keygen failed");
615 #[cfg(not(feature = "legacy-rsa09"))]
616 let public = rsa10::RsaPublicKey::from(&private);
617 #[cfg(not(feature = "legacy-rsa09"))]
618 let pkcs8_der_doc = private
619 .to_pkcs8_der()
620 .expect("failed to encode RSA private key as PKCS#8 DER");
621 #[cfg(not(feature = "legacy-rsa09"))]
622 let pkcs8_der: Arc<[u8]> = Arc::from(pkcs8_der_doc.as_bytes());
623 #[cfg(not(feature = "legacy-rsa09"))]
624 let pkcs8_pem = private
625 .to_pkcs8_pem(LineEnding::LF)
626 .expect("failed to encode RSA private key as PKCS#8 PEM")
627 .to_string();
628 #[cfg(not(feature = "legacy-rsa09"))]
629 let spki_der_doc = public
630 .to_public_key_der()
631 .expect("failed to encode RSA public key as SPKI DER");
632 #[cfg(not(feature = "legacy-rsa09"))]
633 let spki_der: Arc<[u8]> = Arc::from(spki_der_doc.as_bytes());
634 #[cfg(not(feature = "legacy-rsa09"))]
635 let spki_pem = public
636 .to_public_key_pem(LineEnding::LF)
637 .expect("failed to encode RSA public key as SPKI PEM")
638 .to_string();
639
640 let material = Pkcs8SpkiKeyMaterial::new(pkcs8_der, pkcs8_pem, spki_der, spki_pem);
641
642 Inner {
643 _private: private,
644 #[cfg(feature = "jwk")]
645 public,
646 material,
647 }
648 })
649}