diff --git a/tonic/src/transport/tls.rs b/tonic/src/transport/tls.rs index c2b7ef23f..aa273a501 100644 --- a/tonic/src/transport/tls.rs +++ b/tonic/src/transport/tls.rs @@ -1,3 +1,5 @@ +use base64::Engine as _; + /// Represents a X509 certificate. #[derive(Debug, Clone)] pub struct Certificate { @@ -20,6 +22,17 @@ impl Certificate { Self { pem } } + /// Parse a DER encoded X509 Certificate. + /// + /// The provided DER should include exactly one DER encoded certificate. + pub fn from_der(der: impl AsRef<[u8]>) -> Self { + let der = der.as_ref(); + let pem = der2pem(der); + Self { + pem: pem.into_bytes(), + } + } + /// Get a immutable reference to underlying certificate pub fn get_ref(&self) -> &[u8] { self.pem.as_slice() @@ -57,4 +70,20 @@ impl Identity { let key = key.as_ref().into(); Self { cert, key } } + + /// Parse a DER encoded certificate and private key. + /// + /// The provided cert must contain exactly one DER encoded certificate. + pub fn from_der(cert: impl AsRef<[u8]>, key: impl AsRef<[u8]>) -> Self { + let cert = Certificate::from_der(cert); + let key = key.as_ref().into(); + Self { cert, key } + } +} + +fn der2pem(der: &[u8]) -> String { + const RFC7468_HEADER: &str = "-----BEGIN CERTIFICATE-----"; + const RFC7468_FOOTER: &str = "-----END CERTIFICATE-----"; + let pem = crate::util::base64::STANDARD_NO_PAD.encode(der); + format!("{RFC7468_HEADER}\n{pem}\n{RFC7468_FOOTER}\n") }