From a6ce7daf5ae5650113031af5083384f6720b27c7 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 18 Apr 2025 11:04:33 +0000 Subject: [PATCH 1/3] cmpv2: build `OobCertHash` from a certificate --- Cargo.lock | 1 + cmpv2/Cargo.toml | 3 +++ cmpv2/src/oob.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 225e6a278..52aaad297 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -272,6 +272,7 @@ dependencies = [ "const-oid", "crmf", "der", + "digest", "hex-literal 0.4.1", "spki", "x509-cert", diff --git a/cmpv2/Cargo.toml b/cmpv2/Cargo.toml index d53332780..fe8b8ac0e 100644 --- a/cmpv2/Cargo.toml +++ b/cmpv2/Cargo.toml @@ -21,6 +21,8 @@ der = { version = "0.8.0-rc.0", features = ["alloc", "derive", "flagset", "oid"] spki = { version = "0.8.0-rc.0" } x509-cert = { version = "=0.3.0-pre.0", default-features = false } +digest = { version = "0.11.0-pre.10", optional = true, default-features = false } + [dev-dependencies] const-oid = { version = "0.10.0-rc.0", features = ["db"] } hex-literal = "0.4" @@ -30,6 +32,7 @@ alloc = ["der/alloc"] std = ["der/std", "spki/std"] pem = ["alloc", "der/pem"] +digest = ["dep:digest", "spki/digest"] [package.metadata.docs.rs] all-features = true diff --git a/cmpv2/src/oob.rs b/cmpv2/src/oob.rs index 7bb4e3014..a154eb9f4 100644 --- a/cmpv2/src/oob.rs +++ b/cmpv2/src/oob.rs @@ -6,6 +6,13 @@ use der::asn1::BitString; use crmf::controls::CertId; use spki::AlgorithmIdentifierOwned; +#[cfg(feature = "digest")] +use { + der::{Encode, asn1::Null, oid::AssociatedOid}, + spki::DigestWriter, + x509_cert::{Certificate, ext::pkix::name::GeneralName}, +}; + use crate::header::CmpCertificate; /// The `OOBCert` type is defined in [RFC 4210 Section 5.2.5]. @@ -48,3 +55,28 @@ pub struct OobCertHash { pub cert_id: Option, pub hash_val: BitString, } + +#[cfg(feature = "digest")] +impl OobCertHash { + /// Create an [`OobCertHash`] from a given certificate + pub fn from_certificate(cert: &Certificate) -> der::Result + where + D: digest::Digest + AssociatedOid, + { + let mut digest = D::new(); + + cert.encode(&mut DigestWriter(&mut digest))?; + + Ok(Self { + hash_alg: Some(AlgorithmIdentifierOwned { + oid: D::OID, + parameters: Some(Null.into()), + }), + cert_id: Some(CertId { + issuer: GeneralName::DirectoryName(cert.tbs_certificate().issuer().clone()), + serial_number: cert.tbs_certificate().serial_number().clone(), + }), + hash_val: BitString::from_bytes(&digest.finalize())?, + }) + } +} From a06407fdc84bd5cbad7f284d8185f1108e750425 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 18 Apr 2025 11:25:21 +0000 Subject: [PATCH 2/3] crmf: make `CertId` not profile specific --- cmpv2/src/oob.rs | 14 +++++++++----- crmf/src/controls.rs | 11 +++++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cmpv2/src/oob.rs b/cmpv2/src/oob.rs index a154eb9f4..3b4e9dfb1 100644 --- a/cmpv2/src/oob.rs +++ b/cmpv2/src/oob.rs @@ -5,12 +5,13 @@ use der::asn1::BitString; use crmf::controls::CertId; use spki::AlgorithmIdentifierOwned; +use x509_cert::certificate::{Profile, Rfc5280}; #[cfg(feature = "digest")] use { der::{Encode, asn1::Null, oid::AssociatedOid}, spki::DigestWriter, - x509_cert::{Certificate, ext::pkix::name::GeneralName}, + x509_cert::{certificate::CertificateInner, ext::pkix::name::GeneralName}, }; use crate::header::CmpCertificate; @@ -38,7 +39,7 @@ pub type OobCert = CmpCertificate; /// [RFC 4210 Section 5.2.5]: https://www.rfc-editor.org/rfc/rfc4210#section-5.2.5 #[derive(Clone, Debug, Eq, PartialEq, Sequence)] #[allow(missing_docs)] -pub struct OobCertHash { +pub struct OobCertHash { #[asn1( context_specific = "0", tag_mode = "EXPLICIT", @@ -52,14 +53,17 @@ pub struct OobCertHash { constructed = "true", optional = "true" )] - pub cert_id: Option, + pub cert_id: Option>, pub hash_val: BitString, } #[cfg(feature = "digest")] -impl OobCertHash { +impl

OobCertHash

+where + P: Profile, +{ /// Create an [`OobCertHash`] from a given certificate - pub fn from_certificate(cert: &Certificate) -> der::Result + pub fn from_certificate(cert: &CertificateInner

) -> der::Result where D: digest::Digest + AssociatedOid, { diff --git a/crmf/src/controls.rs b/crmf/src/controls.rs index bdf2d7ab0..0ccb4164e 100644 --- a/crmf/src/controls.rs +++ b/crmf/src/controls.rs @@ -9,7 +9,10 @@ use cms::enveloped_data::EnvelopedData; use spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned}; use x509_cert::attr::AttributeTypeAndValue; use x509_cert::ext::pkix::name::GeneralName; -use x509_cert::serial_number::SerialNumber; +use x509_cert::{ + certificate::{Profile, Rfc5280}, + serial_number::SerialNumber, +}; /// The `Controls` type is defined in [RFC 4211 Section 6]. /// @@ -231,7 +234,7 @@ pub type KeyGenParameters = OctetString; /// ``` /// /// [RFC 4211 Section 6.5]: https://www.rfc-editor.org/rfc/rfc4211#section-6.5 -pub type OldCertId = CertId; +pub type OldCertId

= CertId

; /// The `CertId` control is defined in [RFC 4211 Section 6.5]. /// @@ -244,9 +247,9 @@ pub type OldCertId = CertId; /// [RFC 4211 Section 6.5]: https://www.rfc-editor.org/rfc/rfc4211#section-6.5 #[derive(Clone, Debug, Eq, PartialEq, Sequence)] #[allow(missing_docs)] -pub struct CertId { +pub struct CertId { pub issuer: GeneralName, - pub serial_number: SerialNumber, + pub serial_number: SerialNumber

, } /// The `ProtocolEncrKey` control is defined in [RFC 4211 Section 6.6]. From db223c2a933e4415cff6403433fc04cb0803c95c Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 18 Apr 2025 11:25:21 +0000 Subject: [PATCH 3/3] x509-cert: provide hash method to certificate --- Cargo.lock | 1 + cmpv2/Cargo.toml | 2 +- cmpv2/src/oob.rs | 9 ++------- x509-cert/Cargo.toml | 2 ++ x509-cert/src/certificate.rs | 25 +++++++++++++++++++++++++ 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 52aaad297..727e2e092 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1843,6 +1843,7 @@ dependencies = [ "arbitrary", "const-oid", "der", + "digest", "ecdsa", "hex-literal 0.4.1", "p256", diff --git a/cmpv2/Cargo.toml b/cmpv2/Cargo.toml index fe8b8ac0e..e97f54e45 100644 --- a/cmpv2/Cargo.toml +++ b/cmpv2/Cargo.toml @@ -32,7 +32,7 @@ alloc = ["der/alloc"] std = ["der/std", "spki/std"] pem = ["alloc", "der/pem"] -digest = ["dep:digest", "spki/digest"] +digest = ["dep:digest", "x509-cert/digest"] [package.metadata.docs.rs] all-features = true diff --git a/cmpv2/src/oob.rs b/cmpv2/src/oob.rs index 3b4e9dfb1..0fc6804b3 100644 --- a/cmpv2/src/oob.rs +++ b/cmpv2/src/oob.rs @@ -9,8 +9,7 @@ use x509_cert::certificate::{Profile, Rfc5280}; #[cfg(feature = "digest")] use { - der::{Encode, asn1::Null, oid::AssociatedOid}, - spki::DigestWriter, + der::{asn1::Null, oid::AssociatedOid}, x509_cert::{certificate::CertificateInner, ext::pkix::name::GeneralName}, }; @@ -67,10 +66,6 @@ where where D: digest::Digest + AssociatedOid, { - let mut digest = D::new(); - - cert.encode(&mut DigestWriter(&mut digest))?; - Ok(Self { hash_alg: Some(AlgorithmIdentifierOwned { oid: D::OID, @@ -80,7 +75,7 @@ where issuer: GeneralName::DirectoryName(cert.tbs_certificate().issuer().clone()), serial_number: cert.tbs_certificate().serial_number().clone(), }), - hash_val: BitString::from_bytes(&digest.finalize())?, + hash_val: BitString::from_bytes(&cert.hash::()?)?, }) } } diff --git a/x509-cert/Cargo.toml b/x509-cert/Cargo.toml index 7a38b49f5..c1fa66aab 100644 --- a/x509-cert/Cargo.toml +++ b/x509-cert/Cargo.toml @@ -22,6 +22,7 @@ spki = { version = "0.8.0-rc.0", features = ["alloc"] } # optional dependencies arbitrary = { version = "1.4", features = ["derive"], optional = true } +digest = { version = "0.11.0-pre.10", optional = true, default-features = false } sha1 = { version = "0.11.0-pre.5", optional = true } signature = { version = "=2.3.0-pre.6", features = ["rand_core"], optional = true } tls_codec = { version = "0.4.0", default-features = false, features = ["derive"], optional = true } @@ -44,6 +45,7 @@ std = ["der/std", "spki/std", "tls_codec?/std"] arbitrary = ["dep:arbitrary", "std", "der/arbitrary", "spki/arbitrary"] builder = ["std", "sha1/default", "signature"] +digest = ["dep:digest", "spki/digest"] hazmat = [] pem = ["der/pem", "spki/pem"] sct = ["dep:tls_codec"] diff --git a/x509-cert/src/certificate.rs b/x509-cert/src/certificate.rs index c2f57af3e..49e1acb2f 100644 --- a/x509-cert/src/certificate.rs +++ b/x509-cert/src/certificate.rs @@ -13,6 +13,13 @@ use der::{ pem::{self, PemLabel}, }; +#[cfg(feature = "digest")] +use { + der::Encode, + digest::{Digest, Output}, + spki::DigestWriter, +}; + use crate::time::Time; /// [`Profile`] allows the consumer of this crate to customize the behavior when parsing @@ -420,3 +427,21 @@ impl CertificateInner

{ Ok(certs) } } + +#[cfg(feature = "digest")] +impl

CertificateInner

+where + P: Profile, +{ + /// Return the hash of the DER serialization of this cetificate + pub fn hash(&self) -> der::Result> + where + D: Digest, + { + let mut digest = D::new(); + + self.encode(&mut DigestWriter(&mut digest))?; + + Ok(digest.finalize()) + } +}