From 40410e4365e77cafd433e47ed9b5540a077e3e3c Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Wed, 7 Jun 2023 17:59:59 -0700 Subject: [PATCH] Add 'mtls::Certificate::as_bytes()' method. --- core/http/src/tls/mtls.rs | 40 ++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/core/http/src/tls/mtls.rs b/core/http/src/tls/mtls.rs index f8b67dac..9d7554fb 100644 --- a/core/http/src/tls/mtls.rs +++ b/core/http/src/tls/mtls.rs @@ -142,9 +142,11 @@ pub type Result = std::result::Result; /// // _does_ run if a valid (Ok) or invalid (Err) one was presented. /// } /// ``` -#[repr(transparent)] #[derive(Debug, PartialEq)] -pub struct Certificate<'a>(X509Certificate<'a>); +pub struct Certificate<'a> { + x509: X509Certificate<'a>, + data: &'a CertificateData, +} /// An X.509 Distinguished Name (DN) found in a [`Certificate`]. /// @@ -218,16 +220,15 @@ impl<'a> Certificate<'a> { #[inline(always)] fn inner(&self) -> &TbsCertificate<'a> { - &self.0.tbs_certificate + &self.x509.tbs_certificate } /// PRIVATE: For internal Rocket use only! #[doc(hidden)] pub fn parse(chain: &[CertificateData]) -> Result> { - match chain.first() { - Some(cert) => Certificate::parse_one(&cert.0).map(Certificate), - None => Err(Error::Empty) - } + let data = chain.first().ok_or_else(|| Error::Empty)?; + let x509 = Certificate::parse_one(&data.0)?; + Ok(Certificate { x509, data }) } /// Returns the serial number of the X.509 certificate. @@ -364,6 +365,31 @@ impl<'a> Certificate<'a> { let uint: bigint::BigUint = number.parse().ok()?; Some(&uint == self.serial()) } + + /// Returns the raw, unmodified, DER-encoded X.509 certificate data bytes. + /// + /// # Example + /// + /// ```rust + /// # extern crate rocket; + /// # use rocket::get; + /// use rocket::mtls::Certificate; + /// + /// const SHA256_FINGERPRINT: &str = + /// "CE C2 4E 01 00 FF F7 78 CB A4 AA CB D2 49 DD 09 \ + /// 02 EF 0E 9B DA 89 2A E4 0D F4 09 83 97 C1 97 0D"; + /// + /// #[get("/auth")] + /// fn auth(cert: Certificate<'_>) { + /// # fn sha256_fingerprint(bytes: &[u8]) -> String { todo!() } + /// if sha256_fingerprint(cert.as_bytes()) == SHA256_FINGERPRINT { + /// println!("certificate fingerprint matched"); + /// } + /// } + /// ``` + pub fn as_bytes(&self) -> &'a [u8] { + &self.data.0 + } } impl<'a> Deref for Certificate<'a> {