diff --git a/Cargo.lock b/Cargo.lock index 225e6a278..727e2e092 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", @@ -1842,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 d53332780..e97f54e45 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", "x509-cert/digest"] [package.metadata.docs.rs] all-features = true diff --git a/cmpv2/src/oob.rs b/cmpv2/src/oob.rs index 7bb4e3014..0fc6804b3 100644 --- a/cmpv2/src/oob.rs +++ b/cmpv2/src/oob.rs @@ -5,6 +5,13 @@ use der::asn1::BitString; use crmf::controls::CertId; use spki::AlgorithmIdentifierOwned; +use x509_cert::certificate::{Profile, Rfc5280}; + +#[cfg(feature = "digest")] +use { + der::{asn1::Null, oid::AssociatedOid}, + x509_cert::{certificate::CertificateInner, ext::pkix::name::GeneralName}, +}; use crate::header::CmpCertificate; @@ -31,7 +38,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", @@ -45,6 +52,30 @@ pub struct OobCertHash { constructed = "true", optional = "true" )] - pub cert_id: Option, + pub cert_id: Option>, pub hash_val: BitString, } + +#[cfg(feature = "digest")] +impl

OobCertHash

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

) -> der::Result + where + D: digest::Digest + AssociatedOid, + { + 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(&cert.hash::()?)?, + }) + } +} 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]. 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()) + } +}