Skip to main content

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}