From 986c825e620bd8e5e7180edc858f17385e89bc23 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 17 Apr 2023 20:30:43 +0300 Subject: [PATCH 1/6] x509-cert: builder: correct Error type in the comment Correct the comment for builder::Error::Signature: it should mention signature::Error instead of siganture::Signer. Signed-off-by: Dmitry Baryshkov --- x509-cert/src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x509-cert/src/builder.rs b/x509-cert/src/builder.rs index 10b050785..3697678e5 100644 --- a/x509-cert/src/builder.rs +++ b/x509-cert/src/builder.rs @@ -32,7 +32,7 @@ pub enum Error { /// Public key errors propagated from the [`spki::Error`] type. PublicKey(spki::Error), - /// Signing error propagated for the [`signature::Signer`] type. + /// Signing error propagated for the [`signature::Error`] or type. Signature(signature::Error), } From ec33c7771ed6c7f7b7f5ba4686da1caec6407470 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 18 Apr 2023 03:32:20 +0300 Subject: [PATCH 2/6] x509-cert: builder: remove unused ::new generic parameter The Signatue parameter of CertificateBuilder::new() is unused. Let's drop it. We still bind the signature type at the time of CertificateBuilder::build() call. Signed-off-by: Dmitry Baryshkov --- x509-cert/src/builder.rs | 7 ++----- x509-cert/tests/builder.rs | 24 ++++++------------------ 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/x509-cert/src/builder.rs b/x509-cert/src/builder.rs index 3697678e5..8935da8f8 100644 --- a/x509-cert/src/builder.rs +++ b/x509-cert/src/builder.rs @@ -244,17 +244,14 @@ where S::VerifyingKey: EncodePublicKey, { /// Creates a new certificate builder - pub fn new( + pub fn new( profile: Profile, serial_number: SerialNumber, mut validity: Validity, subject: Name, subject_public_key_info: SubjectPublicKeyInfoOwned, signer: &'s S, - ) -> Result - where - S: Signer, - { + ) -> Result { let verifying_key = signer.verifying_key(); let signer_pub = verifying_key .to_public_key_der()? diff --git a/x509-cert/tests/builder.rs b/x509-cert/tests/builder.rs index 4dd730fba..72db64d21 100644 --- a/x509-cert/tests/builder.rs +++ b/x509-cert/tests/builder.rs @@ -62,15 +62,9 @@ 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, &signer) + .expect("Create certificate"); let certificate = builder.build::>().unwrap(); @@ -106,15 +100,9 @@ fn leaf_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, &signer) + .expect("Create certificate"); let certificate = builder.build::>().unwrap(); From 2bff011f2183151ad1bb562ddfc3544a868cfa48 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 18 Apr 2023 03:41:38 +0300 Subject: [PATCH 3/6] x509-cert: builder: support signing with RandomizedSigner Add support for using RandomizedSigner for signing certificates in addition to just Signer keys. Signed-off-by: Dmitry Baryshkov --- x509-cert/Cargo.toml | 2 +- x509-cert/src/builder.rs | 39 +++++++++++++++++++++----- x509-cert/tests/builder.rs | 57 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/x509-cert/Cargo.toml b/x509-cert/Cargo.toml index f216f6211..ebdbb5e93 100644 --- a/x509-cert/Cargo.toml +++ b/x509-cert/Cargo.toml @@ -22,7 +22,7 @@ spki = { version = "0.7.1", features = ["alloc"] } # optional dependencies arbitrary = { version = "1.3", features = ["derive"], optional = true } sha1 = { version = "0.10.0", optional = true } -signature = { version = "2.1.0", optional = true } +signature = { version = "2.1.0", features = ["rand_core"], optional = true } [dev-dependencies] hex-literal = "0.4" diff --git a/x509-cert/src/builder.rs b/x509-cert/src/builder.rs index 8935da8f8..ab5aed9f5 100644 --- a/x509-cert/src/builder.rs +++ b/x509-cert/src/builder.rs @@ -3,7 +3,7 @@ use alloc::vec; use core::fmt; use der::{asn1::BitString, referenced::OwnedToRef, Encode}; -use signature::{Keypair, SignatureEncoding, Signer}; +use signature::{rand_core::CryptoRngCore, Keypair, RandomizedSigner, SignatureEncoding, Signer}; use spki::{ DynSignatureAlgorithmIdentifier, EncodePublicKey, SubjectPublicKeyInfoOwned, SubjectPublicKeyInfoRef, @@ -310,12 +310,7 @@ where Ok(()) } - /// Run the certificate through the signer and build the end certificate. - pub fn build(mut self) -> Result - where - S: Signer, - Signature: SignatureEncoding, - { + fn finalize(&mut self) { if self.tbs.extensions.is_none() { if self.tbs.issuer_unique_id.is_some() || self.tbs.subject_unique_id.is_some() { self.tbs.version = Version::V2; @@ -323,6 +318,16 @@ where self.tbs.version = Version::V1; } } + } + + /// Run the certificate through the signer and build the end certificate. + pub fn build(mut self) -> Result + where + S: Signer, + Signature: SignatureEncoding, + { + self.finalize(); + let signature = self.signer.try_sign(&self.tbs.to_der()?)?; let signature = BitString::from_bytes(signature.to_bytes().as_ref())?; @@ -334,4 +339,24 @@ where Ok(cert) } + + /// Run the certificate through the signer and build the end certificate. + pub fn build_with_rng(mut self, rng: &mut impl CryptoRngCore) -> Result + where + S: RandomizedSigner, + Signature: SignatureEncoding, + { + self.finalize(); + + let signature = self.signer.try_sign_with_rng(rng, &self.tbs.to_der()?)?; + let signature = BitString::from_bytes(signature.to_bytes().as_ref())?; + + let cert = Certificate { + tbs_certificate: self.tbs.clone(), + signature_algorithm: self.tbs.signature, + signature, + }; + + Ok(cert) + } } diff --git a/x509-cert/tests/builder.rs b/x509-cert/tests/builder.rs index 72db64d21..efe088403 100644 --- a/x509-cert/tests/builder.rs +++ b/x509-cert/tests/builder.rs @@ -129,6 +129,57 @@ fn leaf_certificate() { zlint::check_certificate(pem.as_bytes(), ignored); } +#[test] +fn pss_certificate() { + let serial_number = SerialNumber::from(42u32); + let validity = Validity::from_now(Duration::new(5, 0)).unwrap(); + + let issuer = + Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap(); + let profile = Profile::Leaf { + issuer, + enable_key_agreement: false, + enable_key_encipherment: false, + }; + + let subject = Name::from_str("CN=service.domination.world").unwrap(); + let pub_key = + 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 certificate = builder + .build_with_rng::(&mut rand::thread_rng()) + .unwrap(); + + let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); + println!("{}", openssl::check_certificate(pem.as_bytes())); + + // TODO(baloo): not too sure we should tackle those in this API. + let ignored = &[ + "e_sub_cert_aia_missing", + "e_sub_cert_crl_distribution_points_missing", + "w_sub_cert_aia_does_not_contain_issuing_ca_url", + // Missing policies + "e_sub_cert_certificate_policies_missing", + "e_sub_cert_cert_policy_empty", + // Needs to be added by the end-user + "e_sub_cert_aia_does_not_contain_ocsp_url", + // SAN needs to include DNS name (if used) + "e_ext_san_missing", + "e_subject_common_name_not_exactly_from_san", + // Extended key usage needs to be added by end-user and is use-case dependent + "e_sub_cert_eku_missing", + // zlint warns on RSAPSS signature algorithms + "e_signature_algorithm_not_supported", + ]; + + zlint::check_certificate(pem.as_bytes(), ignored); +} + const RSA_2048_PRIV_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.der"); fn rsa_signer() -> SigningKey { @@ -137,6 +188,12 @@ fn rsa_signer() -> SigningKey { signing_key } +fn rsa_pss_signer() -> rsa::pss::SigningKey { + let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER_EXAMPLE).unwrap(); + let signing_key = rsa::pss::SigningKey::::new(private_key); + signing_key +} + const PKCS8_PRIVATE_KEY_DER: &[u8] = include_bytes!("examples/p256-priv.der"); fn ecdsa_signer() -> ecdsa::SigningKey { From 9460f8e856c5880a5c5b612e10e09dd96486f7b2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 18 Apr 2023 19:22:25 +0300 Subject: [PATCH 4/6] x509-cert: tests/builder: don't use deprecated rsa API Signed-off-by: Dmitry Baryshkov --- x509-cert/tests/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x509-cert/tests/builder.rs b/x509-cert/tests/builder.rs index efe088403..27961dfe7 100644 --- a/x509-cert/tests/builder.rs +++ b/x509-cert/tests/builder.rs @@ -184,7 +184,7 @@ const RSA_2048_PRIV_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.d fn rsa_signer() -> SigningKey { let private_key = rsa::RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER_EXAMPLE).unwrap(); - let signing_key = SigningKey::::new_with_prefix(private_key); + let signing_key = SigningKey::::new(private_key); signing_key } From baeabba05ef62147b0735967213a4a39e56419d2 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 18 Apr 2023 21:40:28 +0300 Subject: [PATCH 5/6] Update x509-cert/src/builder.rs Co-authored-by: Arthur Gautier --- x509-cert/src/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x509-cert/src/builder.rs b/x509-cert/src/builder.rs index ab5aed9f5..399e7ee25 100644 --- a/x509-cert/src/builder.rs +++ b/x509-cert/src/builder.rs @@ -32,7 +32,7 @@ pub enum Error { /// Public key errors propagated from the [`spki::Error`] type. PublicKey(spki::Error), - /// Signing error propagated for the [`signature::Error`] or type. + /// Signing error propagated for the [`signature::Error`] type. Signature(signature::Error), } From 390cea1ff91abb3b3c7e2fd95d7896ac065f0f3c Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 19 Apr 2023 19:38:46 +0300 Subject: [PATCH 6/6] Cargo.toml: bump up rsa version to pick up RsaPssParams fixes Signed-off-by: Dmitry Baryshkov --- Cargo.lock | 4 ++-- x509-cert/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c644d4c83..eb95d7d02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1240,9 +1240,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.0-pre.1" +version = "0.9.0-pre.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16504cc31b04d2a5ec729f0c7e1b62e76634a9537f089df0ca1981dc8208a89" +checksum = "65db0998ad35adcaca498b7358992e088ee16cc783fe6fb899da203e113a63e5" dependencies = [ "byteorder", "const-oid 0.9.2", diff --git a/x509-cert/Cargo.toml b/x509-cert/Cargo.toml index ebdbb5e93..3ba1503e2 100644 --- a/x509-cert/Cargo.toml +++ b/x509-cert/Cargo.toml @@ -27,7 +27,7 @@ signature = { version = "2.1.0", features = ["rand_core"], optional = true } [dev-dependencies] hex-literal = "0.4" rand = "0.8.5" -rsa = { version = "0.9.0-pre.1", features = ["sha2"] } +rsa = { version = "0.9.0-pre.2", features = ["sha2"] } ecdsa = { version = "0.16.4", features = ["digest", "pem"] } p256 = "0.13.0" rstest = "0.17"