Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load client cert from format *.crt and *.key (native-tls) #1655

Merged
merged 8 commits into from Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -110,7 +110,7 @@ ipnet = "2.3"

## default-tls
hyper-tls = { version = "0.5", optional = true }
native-tls-crate = { version = "0.2.8", optional = true, package = "native-tls" }
native-tls-crate = { version = "0.2.10", optional = true, package = "native-tls" }
tokio-native-tls = { version = "0.3.0", optional = true }

# rustls-tls
Expand Down
47 changes: 45 additions & 2 deletions src/tls.rs
Expand Up @@ -45,6 +45,8 @@ pub struct Identity {
enum ClientCert {
#[cfg(feature = "native-tls")]
Pkcs12(native_tls_crate::Identity),
#[cfg(feature = "native-tls")]
Pkcs8(native_tls_crate::Identity),
#[cfg(feature = "__rustls")]
Pem {
key: rustls::PrivateKey,
Expand Down Expand Up @@ -179,6 +181,39 @@ impl Identity {
})
}

/// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
/// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
///
/// The certificate chain should contain any intermediate cerficates that should be sent to
/// clients to allow them to build a chain to a trusted root.
///
/// A certificate chain here means a series of PEM encoded certificates concatenated together.
///
/// # Examples
///
/// ```
/// # use std::fs;
/// # fn pkcs8() -> Result<(), Box<std::error::Error>> {
/// let cert = fs::read("client.pem")?;
/// let key = fs::read("key.pem")?;
/// let pkcs8 = reqwest::Identity::from_pkcs8_pem(&cert, &key)?;
/// # drop(pkcs8);
/// # Ok(())
/// # }
/// ```
///
/// # Optional
///
/// This requires the `native-tls` Cargo feature enabled.
#[cfg(feature = "native-tls")]
pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
Ok(Identity {
inner: ClientCert::Pkcs8(
native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
),
})
}

/// Parses PEM encoded private key and certificate.
///
/// The input should contain a PEM encoded private key
Expand Down Expand Up @@ -253,7 +288,7 @@ impl Identity {
tls: &mut native_tls_crate::TlsConnectorBuilder,
) -> crate::Result<()> {
match self.inner {
ClientCert::Pkcs12(id) => {
ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
tls.identity(id);
Ok(())
}
Expand All @@ -275,7 +310,9 @@ impl Identity {
.with_single_cert(certs, key)
.map_err(crate::error::builder),
#[cfg(feature = "native-tls")]
ClientCert::Pkcs12(..) => Err(crate::error::builder("incompatible TLS identity type")),
ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
Err(crate::error::builder("incompatible TLS identity type"))
}
}
}
}
Expand Down Expand Up @@ -443,6 +480,12 @@ mod tests {
Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
}

#[cfg(feature = "native-tls")]
#[test]
fn identity_from_pkcs8_pem_invalid() {
Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
}

#[cfg(feature = "__rustls")]
#[test]
fn identity_from_pem_invalid() {
Expand Down