Skip to content

Commit

Permalink
Add Certificate::from_pem_bundle() (#2032)
Browse files Browse the repository at this point in the history
  • Loading branch information
gibbz00 authored Jan 29, 2024
1 parent 5d8443d commit ddf7f24
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 10 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ http3 = ["rustls-tls-manual-roots", "h3", "h3-quinn", "quinn", "futures-channel"
# Don't rely on these whatsoever. They may disappear at anytime.

# Enables common types used for TLS. Useless on its own.
__tls = []
__tls = ["dep:rustls-pemfile"]

# Enables common rustls code.
# Equivalent to rustls-tls-manual-roots but shorter :)
__rustls = ["hyper-rustls", "tokio-rustls", "rustls", "__tls", "rustls-pemfile"]
__rustls = ["hyper-rustls", "tokio-rustls", "rustls", "__tls"]

# When enabled, disable using the cached SYS_PROXIES.
__internal_proxy_sys_no_cache = []
Expand Down Expand Up @@ -112,6 +112,7 @@ pin-project-lite = "0.2.0"
ipnet = "2.3"

# Optional deps...
rustls-pemfile = { version = "1.0", optional = true }

## default-tls
hyper-tls = { version = "0.5", optional = true }
Expand All @@ -124,7 +125,6 @@ rustls = { version = "0.21.6", features = ["dangerous_configuration"], optional
tokio-rustls = { version = "0.24", optional = true }
webpki-roots = { version = "0.25", optional = true }
rustls-native-certs = { version = "0.6", optional = true }
rustls-pemfile = { version = "1.0", optional = true }

## cookies
cookie_crate = { version = "0.17.0", package = "cookie", optional = true }
Expand Down
44 changes: 37 additions & 7 deletions src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ use rustls::{
client::HandshakeSignatureValid, client::ServerCertVerified, client::ServerCertVerifier,
DigitallySignedStruct, Error as TLSError, ServerName,
};
use std::fmt;
use std::{
fmt,
io::{BufRead, BufReader},
};

/// Represents a server X509 certificate.
#[derive(Clone)]
Expand Down Expand Up @@ -138,6 +141,32 @@ impl Certificate {
})
}

/// Create a collection of `Certificate`s from a PEM encoded certificate bundle.
/// Example byte sources may be `.crt`, `.cer` or `.pem` files.
///
/// # Examples
///
/// ```
/// # use std::fs::File;
/// # use std::io::Read;
/// # fn cert() -> Result<(), Box<std::error::Error>> {
/// let mut buf = Vec::new();
/// File::open("ca-bundle.crt")?
/// .read_to_end(&mut buf)?;
/// let certs = reqwest::Certificate::from_pem_bundle(&buf)?;
/// # drop(certs);
/// # Ok(())
/// # }
/// ```
pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
let mut reader = BufReader::new(pem_bundle);

Self::read_pem_certs(&mut reader)?
.iter()
.map(|cert_vec| Certificate::from_pem(&cert_vec))
.collect::<crate::Result<Vec<Certificate>>>()
}

#[cfg(feature = "native-tls-crate")]
pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
tls.add_root_certificate(self.native);
Expand All @@ -155,12 +184,8 @@ impl Certificate {
.add(&rustls::Certificate(buf))
.map_err(crate::error::builder)?,
Cert::Pem(buf) => {
let mut pem = Cursor::new(buf);
let certs = rustls_pemfile::certs(&mut pem).map_err(|_| {
crate::error::builder(TLSError::General(String::from(
"No valid certificate was found",
)))
})?;
let mut reader = Cursor::new(buf);
let certs = Self::read_pem_certs(&mut reader)?;
for c in certs {
root_cert_store
.add(&rustls::Certificate(c))
Expand All @@ -170,6 +195,11 @@ impl Certificate {
}
Ok(())
}

fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
rustls_pemfile::certs(reader)
.map_err(|_| crate::error::builder("invalid certificate encoding"))
}
}

impl Identity {
Expand Down

0 comments on commit ddf7f24

Please sign in to comment.