From 345ac96a5e2300dacd9093552ec17770e9ce05d0 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 20 Jan 2024 04:55:44 +0000 Subject: [PATCH] x509-cert: don't bind builder with signer early (#1161) * x509-cert: don't bind builder with signer early This is mostly a draft after discussion in #1160 Signed-off-by: Arthur Gautier * cms: pull builder changes Signed-off-by: Arthur Gautier --------- Signed-off-by: Arthur Gautier --- cms/src/builder.rs | 56 ++++++------ cms/tests/builder.rs | 14 ++- x509-cert/src/builder.rs | 182 ++++++++++++++++++++----------------- x509-cert/tests/builder.rs | 68 ++++++++------ 4 files changed, 177 insertions(+), 143 deletions(-) diff --git a/cms/src/builder.rs b/cms/src/builder.rs index 906ed6bf7..806cc8522 100644 --- a/cms/src/builder.rs +++ b/cms/src/builder.rs @@ -35,11 +35,14 @@ use rsa::Pkcs1v15Encrypt; use sha2::digest; use signature::digest::DynDigest; use signature::{Keypair, Signer}; -use spki::{AlgorithmIdentifierOwned, DynSignatureAlgorithmIdentifier, SignatureBitStringEncoding}; +use spki::{ + AlgorithmIdentifierOwned, DynSignatureAlgorithmIdentifier, EncodePublicKey, + SignatureBitStringEncoding, +}; use std::time::SystemTime; use std::vec; use x509_cert::attr::{Attribute, AttributeValue, Attributes}; -use x509_cert::builder::Builder; +use x509_cert::builder::{self, Builder}; use zeroize::Zeroize; /// Error type @@ -96,8 +99,7 @@ type Result = core::result::Result; /// - calculate the signature /// - set the signing time attribute /// - create a `SignerInfo` object -pub struct SignerInfoBuilder<'s, S> { - signer: &'s S, +pub struct SignerInfoBuilder<'s> { sid: SignerIdentifier, digest_algorithm: AlgorithmIdentifierOwned, signed_attributes: Option>, @@ -106,24 +108,19 @@ pub struct SignerInfoBuilder<'s, S> { external_message_digest: Option<&'s [u8]>, } -impl<'s, S> SignerInfoBuilder<'s, S> -where - S: Keypair + DynSignatureAlgorithmIdentifier, -{ +impl<'s> SignerInfoBuilder<'s> { /// Create a new `SignerInfoBuilder`. This is used for adding `SignerInfo`s to `SignedData` /// structures. /// The content to be signed can be stored externally. In this case `eContent` in /// `encapsulated_content_info` must be `None` and the message digest must be passed with /// `external_message_digest`. `digest_algorithm` must match the used digest algorithm. pub fn new( - signer: &'s S, sid: SignerIdentifier, digest_algorithm: AlgorithmIdentifierOwned, encapsulated_content_info: &'s EncapsulatedContentInfo, external_message_digest: Option<&'s [u8]>, ) -> Result { Ok(SignerInfoBuilder { - signer, sid, digest_algorithm, signed_attributes: None, @@ -167,28 +164,24 @@ where } } -impl<'s, S> Builder for SignerInfoBuilder<'s, S> -where - S: Keypair + DynSignatureAlgorithmIdentifier, -{ - type Signer = S; +impl<'s> Builder for SignerInfoBuilder<'s> { type Output = SignerInfo; - fn signer(&self) -> &Self::Signer { - self.signer - } - /// Calculate the data to be signed /// [RFC 5652 § 5.4](https://datatracker.ietf.org/doc/html/rfc5652#section-5.4) /// If an `external_message_digest` is passed in, it is assumed, that we are signing external /// content (see RFC 5652 § 5.2). In this case, the `eContent` in `EncapsulatedContentInfo` /// must be `None`. - fn finalize(&mut self) -> der::Result> { + fn finalize(&mut self, _signer: &S) -> builder::Result> + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { let message_digest = match self.external_message_digest { Some(external_content_digest) => { if self.encapsulated_content_info.econtent.is_some() { // Encapsulated content must be empty, if external digest is given. - return Err(der::Error::from(ErrorKind::Failed)); + return Err(der::Error::from(ErrorKind::Failed).into()); } Some(external_content_digest.to_vec()) } @@ -201,7 +194,7 @@ where Some(content) => { let mut hasher = get_hasher(&self.digest_algorithm).ok_or_else(|| { // Unsupported hash algorithm: {}, &self.digest_algorithm.oid.to_string() - der::Error::from(ErrorKind::Failed) + x509_cert::builder::Error::from(der::Error::from(ErrorKind::Failed)) })?; // Only the octets comprising the value of the eContent // OCTET STRING are input to the message digest algorithm, not the tag @@ -245,7 +238,7 @@ where // Check against `eContentType` if signed_attributes_content_type.oid != econtent_type { // Mismatch between content types: encapsulated content info <-> signed attributes. - return Err(der::Error::from(ErrorKind::Failed)); + return Err(der::Error::from(ErrorKind::Failed).into()); } } else { signed_attributes.push( @@ -264,10 +257,11 @@ where Ok(signed_attributes_der) } - fn assemble( - self, - signature: BitString, - ) -> core::result::Result { + fn assemble(self, signature: BitString, signer: &S) -> builder::Result + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { let signed_attrs = self.signed_attributes.as_ref().map(|signed_attributes| { SignedAttributes::try_from(signed_attributes.to_owned()).unwrap() }); @@ -281,7 +275,7 @@ where let signature_value = SignatureValue::new(signature.raw_bytes()).map_err(x509_cert::builder::Error::from)?; - let signature_algorithm = self.signer.signature_algorithm_identifier()?; + let signature_algorithm = signer.signature_algorithm_identifier()?; Ok(SignerInfo { version: self.version(), @@ -379,15 +373,17 @@ impl<'s> SignedDataBuilder<'s> { /// must not be changed after the first signer info was added. pub fn add_signer_info( &mut self, - signer_info_builder: SignerInfoBuilder<'_, S>, + signer_info_builder: SignerInfoBuilder<'_>, + signer: &S, ) -> Result<&mut Self> where S: Keypair + DynSignatureAlgorithmIdentifier, S: Signer, + S::VerifyingKey: EncodePublicKey, Signature: SignatureBitStringEncoding, { let signer_info = signer_info_builder - .build::() + .build::(signer) .map_err(|_| der::Error::from(ErrorKind::Failed))?; self.signer_infos.push(signer_info); diff --git a/cms/tests/builder.rs b/cms/tests/builder.rs index 3273829d0..56c362145 100644 --- a/cms/tests/builder.rs +++ b/cms/tests/builder.rs @@ -104,7 +104,6 @@ fn test_build_signed_data() { }; let external_message_digest = None; let signer_info_builder_1 = SignerInfoBuilder::new( - &signer, signer_identifier(1), digest_algorithm.clone(), &content, @@ -119,7 +118,6 @@ fn test_build_signed_data() { }; let external_message_digest_2 = None; let signer_info_builder_2 = SignerInfoBuilder::new( - &signer_2, signer_identifier(1), digest_algorithm_2.clone(), &content, @@ -137,10 +135,14 @@ fn test_build_signed_data() { .expect("could not add a digest algorithm") .add_certificate(CertificateChoices::Certificate(certificate)) .expect("error adding certificate") - .add_signer_info::, rsa::pkcs1v15::Signature>(signer_info_builder_1) + .add_signer_info::, rsa::pkcs1v15::Signature>( + signer_info_builder_1, + &signer, + ) .expect("error adding RSA signer info") .add_signer_info::, p256::ecdsa::DerSignature>( signer_info_builder_2, + &signer_2, ) .expect("error adding P256 signer info") .build() @@ -324,7 +326,6 @@ fn test_build_pkcs7_scep_pkcsreq() { parameters: None, }; let mut signer_info_builder = SignerInfoBuilder::new( - &signer, signer_identifier(1), digest_algorithm.clone(), &content, @@ -380,7 +381,10 @@ fn test_build_pkcs7_scep_pkcsreq() { .unwrap() .add_certificate(CertificateChoices::Certificate(certificate)) .unwrap() - .add_signer_info::, rsa::pkcs1v15::Signature>(signer_info_builder) + .add_signer_info::, rsa::pkcs1v15::Signature>( + signer_info_builder, + &signer, + ) .unwrap() .build() .unwrap(); diff --git a/x509-cert/src/builder.rs b/x509-cert/src/builder.rs index 53ee81095..a637f8c5c 100644 --- a/x509-cert/src/builder.rs +++ b/x509-cert/src/builder.rs @@ -5,8 +5,8 @@ use core::fmt; use der::{asn1::BitString, referenced::OwnedToRef, Encode}; use signature::{rand_core::CryptoRngCore, Keypair, RandomizedSigner, Signer}; use spki::{ - DynSignatureAlgorithmIdentifier, EncodePublicKey, SignatureBitStringEncoding, - SubjectPublicKeyInfoOwned, SubjectPublicKeyInfoRef, + AlgorithmIdentifier, DynSignatureAlgorithmIdentifier, EncodePublicKey, ObjectIdentifier, + SignatureBitStringEncoding, SubjectPublicKeyInfoOwned, SubjectPublicKeyInfoRef, }; use crate::{ @@ -23,6 +23,8 @@ use crate::{ time::Validity, }; +const NULL_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("0.0.0"); + /// Error type #[derive(Debug)] #[non_exhaustive] @@ -68,7 +70,8 @@ impl From for Error { } } -type Result = core::result::Result; +/// Result type +pub type Result = core::result::Result; /// The type of certificate to build #[derive(Clone, Debug, Eq, PartialEq)] @@ -219,7 +222,7 @@ impl Profile { /// ``` /// use der::Decode; /// use x509_cert::spki::SubjectPublicKeyInfoOwned; -/// use x509_cert::builder::{CertificateBuilder, Profile}; +/// use x509_cert::builder::{CertificateBuilder, Profile, Builder}; /// use x509_cert::name::Name; /// use x509_cert::serial_number::SerialNumber; /// use x509_cert::time::Validity; @@ -251,21 +254,18 @@ impl Profile { /// validity, /// subject, /// pub_key, -/// &signer, /// ) -/// .expect("Create certificate"); +/// .expect("Create certificate builder"); +/// +/// let cert = builder.build(&signer).expect("Create certificate"); /// ``` -pub struct CertificateBuilder<'s, S> { +pub struct CertificateBuilder { tbs: TbsCertificate, extensions: Extensions, - cert_signer: &'s S, + profile: Profile, } -impl<'s, S> CertificateBuilder<'s, S> -where - S: Keypair + DynSignatureAlgorithmIdentifier, - S::VerifyingKey: EncodePublicKey, -{ +impl CertificateBuilder { /// Creates a new certificate builder pub fn new( profile: Profile, @@ -273,12 +273,12 @@ where mut validity: Validity, subject: Name, subject_public_key_info: SubjectPublicKeyInfoOwned, - cert_signer: &'s S, ) -> Result { - let verifying_key = cert_signer.verifying_key(); - let signer_pub = SubjectPublicKeyInfoOwned::from_key(&verifying_key)?; + let signature_alg = AlgorithmIdentifier { + oid: NULL_OID, + parameters: None, + }; - let signature_alg = cert_signer.signature_algorithm_identifier()?; let issuer = profile.get_issuer(&subject); validity.not_before.rfc5280_adjust_utc_time()?; @@ -303,15 +303,11 @@ where subject_unique_id: None, }; - let extensions = profile.build_extensions( - tbs.subject_public_key_info.owned_to_ref(), - signer_pub.owned_to_ref(), - &tbs, - )?; + let extensions = Extensions::default(); Ok(Self { tbs, extensions, - cert_signer, + profile, }) } @@ -344,31 +340,34 @@ where /// let subject = Name::from_str("CN=service.domination.world").unwrap(); /// /// let signer = ecdsa_signer(); -/// let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request"); +/// let mut builder = RequestBuilder::new(subject).expect("Create certificate request"); /// builder /// .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4( /// Ipv4Addr::new(192, 0, 2, 0), /// ))])) /// .unwrap(); /// -/// let cert_req = builder.build::().unwrap(); +/// let cert_req = builder.build::<_, DerSignature>(&signer).unwrap(); /// ``` -pub struct RequestBuilder<'s, S> { +pub struct RequestBuilder { info: CertReqInfo, extension_req: ExtensionReq, - req_signer: &'s S, } -impl<'s, S> RequestBuilder<'s, S> -where - S: Keypair + DynSignatureAlgorithmIdentifier, - S::VerifyingKey: EncodePublicKey, -{ +impl RequestBuilder { /// Creates a new certificate request builder - pub fn new(subject: Name, req_signer: &'s S) -> Result { + pub fn new(subject: Name) -> Result { let version = Default::default(); - let verifying_key = req_signer.verifying_key(); - let public_key = SubjectPublicKeyInfoOwned::from_key(&verifying_key)?; + + let algorithm = AlgorithmIdentifier { + oid: NULL_OID, + parameters: None, + }; + let public_key = SubjectPublicKeyInfoOwned { + algorithm, + subject_public_key: BitString::from_bytes(&[]).expect("unable to parse empty object"), + }; + let attributes = Default::default(); let extension_req = Default::default(); @@ -380,7 +379,6 @@ where attributes, }, extension_req, - req_signer, }) } @@ -406,64 +404,77 @@ where /// /// This trait defines the interface between builder and the signers. pub trait Builder: Sized { - /// The builder's object signer - type Signer; - /// Type built by this builder type Output: Sized; - /// Return a reference to the signer. - fn signer(&self) -> &Self::Signer; - /// Assemble the final object from signature. - fn assemble(self, signature: BitString) -> Result; + fn assemble(self, signature: BitString, signer: &S) -> Result + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey; /// Finalize and return a serialization of the object for signature. - fn finalize(&mut self) -> der::Result>; + fn finalize(&mut self, signer: &S) -> Result> + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey; /// Run the object through the signer and build it. - fn build(mut self) -> Result + fn build(mut self, signer: &S) -> Result where - Self::Signer: Signer, + S: Signer, + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, Signature: SignatureBitStringEncoding, { - let blob = self.finalize()?; + let blob = self.finalize(signer)?; - let signature = self.signer().try_sign(&blob)?.to_bitstring()?; + let signature = signer.try_sign(&blob)?.to_bitstring()?; - self.assemble(signature) + self.assemble(signature, signer) } /// Run the object through the signer and build it. - fn build_with_rng(mut self, rng: &mut impl CryptoRngCore) -> Result + fn build_with_rng( + mut self, + signer: &S, + rng: &mut impl CryptoRngCore, + ) -> Result where - Self::Signer: RandomizedSigner, + S: RandomizedSigner, + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, Signature: SignatureBitStringEncoding, { - let blob = self.finalize()?; + let blob = self.finalize(signer)?; - let signature = self - .signer() - .try_sign_with_rng(rng, &blob)? - .to_bitstring()?; + let signature = signer.try_sign_with_rng(rng, &blob)?.to_bitstring()?; - self.assemble(signature) + self.assemble(signature, signer) } } -impl<'s, S> Builder for CertificateBuilder<'s, S> -where - S: Keypair + DynSignatureAlgorithmIdentifier, - S::VerifyingKey: EncodePublicKey, -{ - type Signer = S; +impl Builder for CertificateBuilder { type Output = Certificate; - fn signer(&self) -> &Self::Signer { - self.cert_signer - } + fn finalize(&mut self, cert_signer: &S) -> Result> + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { + let verifying_key = cert_signer.verifying_key(); + let signer_pub = SubjectPublicKeyInfoOwned::from_key(&verifying_key)?; + + self.tbs.signature = cert_signer.signature_algorithm_identifier()?; + + let mut default_extensions = self.profile.build_extensions( + self.tbs.subject_public_key_info.owned_to_ref(), + signer_pub.owned_to_ref(), + &self.tbs, + )?; + + self.extensions.append(&mut default_extensions); - fn finalize(&mut self) -> der::Result> { if !self.extensions.is_empty() { self.tbs.extensions = Some(self.extensions.clone()); } @@ -476,10 +487,14 @@ where } } - self.tbs.to_der() + self.tbs.to_der().map_err(Error::from) } - fn assemble(self, signature: BitString) -> Result { + fn assemble(self, signature: BitString, _signer: &S) -> Result + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { let signature_algorithm = self.tbs.signature.clone(); Ok(Certificate { @@ -490,28 +505,31 @@ where } } -impl<'s, S> Builder for RequestBuilder<'s, S> -where - S: Keypair + DynSignatureAlgorithmIdentifier, - S::VerifyingKey: EncodePublicKey, -{ - type Signer = S; +impl Builder for RequestBuilder { type Output = CertReq; - fn signer(&self) -> &Self::Signer { - self.req_signer - } + fn finalize(&mut self, signer: &S) -> Result> + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { + let verifying_key = signer.verifying_key(); + let public_key = SubjectPublicKeyInfoOwned::from_key(&verifying_key)?; + self.info.public_key = public_key; - fn finalize(&mut self) -> der::Result> { self.info .attributes .insert(self.extension_req.clone().try_into()?)?; - self.info.to_der() + self.info.to_der().map_err(Error::from) } - fn assemble(self, signature: BitString) -> Result { - let algorithm = self.req_signer.signature_algorithm_identifier()?; + fn assemble(self, signature: BitString, signer: &S) -> Result + where + S: Keypair + DynSignatureAlgorithmIdentifier, + S::VerifyingKey: EncodePublicKey, + { + let algorithm = signer.signature_algorithm_identifier()?; Ok(CertReq { info: self.info, diff --git a/x509-cert/tests/builder.rs b/x509-cert/tests/builder.rs index 6a8a55a85..8ae1de912 100644 --- a/x509-cert/tests/builder.rs +++ b/x509-cert/tests/builder.rs @@ -2,6 +2,7 @@ use der::{asn1::PrintableString, pem::LineEnding, Decode, Encode, EncodePem}; use p256::{ecdsa::DerSignature, pkcs8::DecodePrivateKey, NistP256}; +use rand::rngs::OsRng; use rsa::pkcs1::DecodeRsaPrivateKey; use rsa::pkcs1v15::SigningKey; use sha2::Sha256; @@ -37,11 +38,10 @@ fn root_ca_certificate() { SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key"); let signer = rsa_signer(); - let builder = - CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) - .expect("Create certificate"); + let builder = CertificateBuilder::new(profile, serial_number, validity, subject, pub_key) + .expect("Create certificate"); - let certificate = builder.build().unwrap(); + let certificate = builder.build(&signer).unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", openssl::check_certificate(pem.as_bytes())); @@ -64,11 +64,10 @@ fn root_ca_certificate_ecdsa() { SubjectPublicKeyInfoOwned::try_from(PKCS8_PUBLIC_KEY_DER).expect("get ecdsa pub key"); let signer = ecdsa_signer(); - let builder = - CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) - .expect("Create certificate"); + let builder = CertificateBuilder::new(profile, serial_number, validity, subject, pub_key) + .expect("Create certificate"); - let certificate = builder.build::().unwrap(); + let certificate = builder.build::<_, DerSignature>(&signer).unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", openssl::check_certificate(pem.as_bytes())); @@ -95,11 +94,10 @@ fn sub_ca_certificate() { SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key"); let signer = ecdsa_signer(); - let builder = - CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) - .expect("Create certificate"); + let builder = CertificateBuilder::new(profile, serial_number, validity, subject, pub_key) + .expect("Create certificate"); - let certificate = builder.build::().unwrap(); + let certificate = builder.build::<_, DerSignature>(&signer).unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", openssl::check_certificate(pem.as_bytes())); @@ -141,11 +139,10 @@ fn leaf_certificate() { validity, subject.clone(), pub_key.clone(), - &signer, ) .expect("Create certificate"); - let certificate = builder.build::().unwrap(); + let certificate = builder.build::<_, DerSignature>(&signer).unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", openssl::check_certificate(pem.as_bytes())); @@ -180,11 +177,10 @@ fn leaf_certificate() { enable_key_encipherment: false, include_subject_key_identifier: false, }; - let builder = - CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) - .expect("Create certificate"); + let builder = CertificateBuilder::new(profile, serial_number, validity, subject, pub_key) + .expect("Create certificate"); - let certificate = builder.build::().unwrap(); + let certificate = builder.build::<_, DerSignature>(&signer).unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", openssl::check_certificate(pem.as_bytes())); @@ -217,12 +213,11 @@ fn pss_certificate() { SubjectPublicKeyInfoOwned::try_from(RSA_2048_DER_EXAMPLE).expect("get rsa pub key"); let signer = rsa_pss_signer(); - let builder = - CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) - .expect("Create certificate"); + let builder = CertificateBuilder::new(profile, serial_number, validity, subject, pub_key) + .expect("Create certificate"); let certificate = builder - .build_with_rng::(&mut rand::thread_rng()) + .build_with_rng::<_, rsa::pss::Signature>(&signer, &mut rand::thread_rng()) .unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); @@ -278,14 +273,14 @@ fn certificate_request() { let subject = Name::from_str("CN=service.domination.world").unwrap(); let signer = ecdsa_signer(); - let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request"); + let mut builder = RequestBuilder::new(subject).expect("Create certificate request"); builder .add_extension(&SubjectAltName(vec![GeneralName::from(IpAddr::V4( Ipv4Addr::new(192, 0, 2, 0), ))])) .unwrap(); - let cert_req = builder.build::().unwrap(); + let cert_req = builder.build::<_, DerSignature>(&signer).unwrap(); let pem = cert_req.to_pem(LineEnding::LF).expect("generate pem"); use std::fs::File; use std::io::Write; @@ -299,7 +294,7 @@ fn certificate_request_attributes() { let subject = Name::from_str("CN=service.domination.world").unwrap(); let signer = ecdsa_signer(); - let mut builder = RequestBuilder::new(subject, &signer).expect("Create certificate request"); + let mut builder = RequestBuilder::new(subject).expect("Create certificate request"); builder .add_attribute(&request::attributes::ChallengePassword( DirectoryString::PrintableString( @@ -309,7 +304,7 @@ fn certificate_request_attributes() { )) .expect("unable to add attribute"); - let cert_req = builder.build::().unwrap(); + let cert_req = builder.build::<_, DerSignature>(&signer).unwrap(); let pem = cert_req.to_pem(LineEnding::LF).expect("generate pem"); use std::fs::File; use std::io::Write; @@ -317,3 +312,24 @@ fn certificate_request_attributes() { file.write_all(pem.as_bytes()).expect("Create pem file"); println!("{}", openssl::check_request(pem.as_bytes())); } + +#[test] +fn dynamic_signer() { + let subject = Name::from_str("CN=Test").expect("parse common name"); + + let csr_builder = RequestBuilder::new(subject).expect("construct builder"); + + let csr = if true { + let req_signer = p256::ecdsa::SigningKey::random(&mut OsRng); + csr_builder + .build::<_, p256::ecdsa::DerSignature>(&req_signer) + .expect("Sign request") + } else { + let req_signer = rsa_signer(); + csr_builder.build(&req_signer).expect("Sign request") + }; + + let csr_pem = csr.to_pem(LineEnding::LF).expect("format CSR"); + + println!("{}", csr_pem); +}