From 8fa3ab3c8b157d047fb6631a980b0ebe551e2dfb Mon Sep 17 00:00:00 2001 From: Zhang Jingqiang Date: Sun, 24 Dec 2023 15:59:01 +0800 Subject: [PATCH] add various X509 digest methods via macro --- openssl-sys/src/handwritten/x509.rs | 19 +++++++++ openssl/src/macros.rs | 25 +++++++++++ openssl/src/x509/mod.rs | 65 +++++++++++++++++++++-------- openssl/src/x509/tests.rs | 12 ++++++ 4 files changed, 103 insertions(+), 18 deletions(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 107e8182d1..b65e50d4f7 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -151,8 +151,20 @@ extern "C" { buf: *mut c_uchar, len: *mut c_uint, ) -> c_int; + pub fn X509_pubkey_digest( + x: *const X509, + digest: *const EVP_MD, + buf: *mut c_uchar, + len: *mut c_uint, + ) -> c_int; pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + pub fn X509_REQ_digest( + x: *const X509_REQ, + digest: *const EVP_MD, + md: *mut c_uchar, + len: *mut c_uint, + ) -> c_int; } const_ptr_api! { @@ -281,6 +293,13 @@ extern "C" { pub fn X509_NAME_cmp(x: *const X509_NAME, y: *const X509_NAME) -> c_int; pub fn X509_NAME_free(x: *mut X509_NAME); + pub fn X509_NAME_digest( + data: *const X509_NAME, + type_: *const EVP_MD, + md: *mut c_uchar, + len: *mut c_uint, + ) -> c_int; + pub fn X509_new() -> *mut X509; pub fn X509_free(x: *mut X509); } diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 671a11b82d..17232f750b 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -131,6 +131,31 @@ macro_rules! from_pem { } } +macro_rules! digest { + ($(#[$m:meta])* $n:ident, $f:path) => { + $(#[$m])* + pub fn $n(&self, hash_type: crate::hash::MessageDigest) + -> Result { + unsafe { + let mut digest = DigestBytes { + buf: [0; ffi::EVP_MAX_MD_SIZE as usize], + len: ffi::EVP_MAX_MD_SIZE as usize, + }; + let mut len = ffi::EVP_MAX_MD_SIZE as c_uint; + crate::cvt($f( + ::foreign_types::ForeignTypeRef::as_ptr(self), + hash_type.as_ptr(), + digest.buf.as_mut_ptr() as *mut _, + &mut len, + ))?; + digest.len = len as usize; + + Ok(digest) + } + } + }; +} + macro_rules! foreign_type_and_impl_send_sync { ( $(#[$impl_attr:meta])* diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 115193ee05..ab4293a075 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -534,25 +534,24 @@ impl X509Ref { } } - /// Returns a digest of the DER representation of the certificate. - #[corresponds(X509_digest)] - pub fn digest(&self, hash_type: MessageDigest) -> Result { - unsafe { - let mut digest = DigestBytes { - buf: [0; ffi::EVP_MAX_MD_SIZE as usize], - len: ffi::EVP_MAX_MD_SIZE as usize, - }; - let mut len = ffi::EVP_MAX_MD_SIZE as c_uint; - cvt(ffi::X509_digest( - self.as_ptr(), - hash_type.as_ptr(), - digest.buf.as_mut_ptr() as *mut _, - &mut len, - ))?; - digest.len = len as usize; + digest! { + /// Returns a digest of the DER representation of the certificate. + /// + /// This corresponds to [`X509_digest`]. + /// + /// [`X509_digest`]: https://www.openssl.org/docs/manmaster/man3/X509_digest.html + digest, + ffi::X509_digest + } - Ok(digest) - } + digest! { + /// Returns a digest of the DER representation of the public key in the specified X509 data object. + /// + /// This corresponds to [`X509_pubkey_digest`]. + /// + /// [`X509_pubkey_digest`]: https://www.openssl.org/docs/manmaster/man3/X509_pubkey_digest.html + pubkey_digest, + ffi::X509_pubkey_digest } #[deprecated(since = "0.10.9", note = "renamed to digest")] @@ -1261,6 +1260,16 @@ impl X509NameRef { to_der, ffi::i2d_X509_NAME } + + digest! { + /// Returns a digest of the DER representation of this 'X509Name'. + /// + /// This corresponds to [`X509_NAME_digest`]. + /// + /// [`X509_NAME_digest`]: https://www.openssl.org/docs/manmaster/man3/X509_NAME_digest.html + digest, + ffi::X509_NAME_digest + } } impl fmt::Debug for X509NameRef { @@ -1542,6 +1551,16 @@ impl X509ReqRef { ffi::X509_REQ_print } + digest! { + /// Returns a digest of the DER representation of this 'X509Req'. + /// + /// This corresponds to [`X509_REQ_digest`]. + /// + /// [`X509_REQ_digest`]: https://www.openssl.org/docs/manmaster/man3/X509_REQ_digest.html + digest, + ffi::X509_REQ_digest + } + /// Returns the numerical value of the version field of the certificate request. /// /// This corresponds to [`X509_REQ_get_version`] @@ -1845,6 +1864,16 @@ impl X509CrlRef { ffi::i2d_X509_CRL } + digest! { + /// Returns a digest of the DER representation of this 'X509Crl'. + /// + /// This corresponds to [`X509_CRL_digest`]. + /// + /// [`X509_CRL_digest`]: https://www.openssl.org/docs/manmaster/man3/X509_CRL_digest.html + digest, + ffi::X509_CRL_digest + } + /// Get the stack of revocation entries pub fn get_revoked(&self) -> Option<&StackRef> { unsafe { diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 0444a067dd..2a9456600c 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -98,6 +98,18 @@ fn test_subject_read_cn() { assert_eq!(cn.data().as_slice(), b"foobar.com") } +#[test] +fn test_subject_digest() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let subject = cert.subject_name(); + let digest = subject.digest(MessageDigest::sha1()).unwrap(); + assert_eq!( + hex::encode(digest), + "9665d6f11a76d066813bffd6031856f076684e05" + ) +} + #[test] fn test_nid_values() { let cert = include_bytes!("../../test/nid_test_cert.pem");