Start moving types over
This commit is contained in:
@@ -48,7 +48,7 @@ mod async_connection;
|
||||
mod async_net;
|
||||
mod connection;
|
||||
mod net;
|
||||
mod tls;
|
||||
pub mod tls;
|
||||
|
||||
/// The codec used for transparency
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1 +1,42 @@
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use crate::transport::smtp::error::{self, Error};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Certificate(pub(super) boring::x509::X509);
|
||||
|
||||
impl Certificate {
|
||||
pub fn from_pem(pem: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self(boring::x509::X509::from_pem(pem).map_err(error::tls)?))
|
||||
}
|
||||
|
||||
pub fn from_der(der: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self(boring::x509::X509::from_der(der).map_err(error::tls)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Certificate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Certificate").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Identity {
|
||||
pub(super) chain: boring::x509::X509,
|
||||
pub(super) key: PKey<boring::pkey::Private>,
|
||||
}
|
||||
|
||||
impl Identity {
|
||||
pub fn from_pem(pem: &[u8], key: &[u8]) -> Result<Self, Error> {
|
||||
let cert = boring::x509::X509::from_pem(pem).map_err(error::tls)?;
|
||||
let key = boring::pkey::PKey::private_key_from_pem(key).map_err(error::tls)?;
|
||||
Ok(Self { cert, key })
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Identity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Identity").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,7 @@ use boring::{
|
||||
#[cfg(feature = "native-tls")]
|
||||
use native_tls::{Protocol, TlsConnector};
|
||||
#[cfg(feature = "rustls")]
|
||||
use rustls::{
|
||||
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
|
||||
crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider},
|
||||
pki_types::{self, pem::PemObject, CertificateDer, PrivateKeyDer, ServerName, UnixTime},
|
||||
server::ParsedCertificate,
|
||||
ClientConfig, DigitallySignedStruct, Error as TlsError, RootCertStore, SignatureScheme,
|
||||
};
|
||||
use rustls::{ClientConfig, RootCertStore};
|
||||
|
||||
#[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
|
||||
use crate::transport::smtp::{error, Error};
|
||||
@@ -372,7 +366,7 @@ impl TlsParametersBuilder {
|
||||
}
|
||||
}
|
||||
for cert in self.root_certs {
|
||||
tls_builder.add_root_certificate(cert.native_tls);
|
||||
tls_builder.add_root_certificate(cert.native_tls.0);
|
||||
}
|
||||
tls_builder.danger_accept_invalid_hostnames(self.accept_invalid_hostnames);
|
||||
tls_builder.danger_accept_invalid_certs(self.accept_invalid_certs);
|
||||
@@ -390,7 +384,7 @@ impl TlsParametersBuilder {
|
||||
|
||||
tls_builder.min_protocol_version(Some(min_tls_version));
|
||||
if let Some(identity) = self.identity {
|
||||
tls_builder.identity(identity.native_tls);
|
||||
tls_builder.identity(identity.native_tls.0);
|
||||
}
|
||||
|
||||
let connector = tls_builder.build().map_err(error::tls)?;
|
||||
@@ -547,12 +541,12 @@ impl TlsParametersBuilder {
|
||||
}
|
||||
for cert in self.root_certs {
|
||||
for rustls_cert in cert.rustls {
|
||||
root_cert_store.add(rustls_cert).map_err(error::tls)?;
|
||||
root_cert_store.add(rustls_cert.0).map_err(error::tls)?;
|
||||
}
|
||||
}
|
||||
|
||||
let tls = if self.accept_invalid_certs || self.accept_invalid_hostnames {
|
||||
let verifier = InvalidCertsVerifier {
|
||||
let verifier = super::rustls::InvalidCertsVerifier {
|
||||
ignore_invalid_hostnames: self.accept_invalid_hostnames,
|
||||
ignore_invalid_certs: self.accept_invalid_certs,
|
||||
roots: root_cert_store,
|
||||
@@ -565,8 +559,7 @@ impl TlsParametersBuilder {
|
||||
};
|
||||
|
||||
let tls = if let Some(identity) = self.identity {
|
||||
let (client_certificates, private_key) = identity.rustls_tls;
|
||||
tls.with_client_auth_cert(client_certificates, private_key)
|
||||
tls.with_client_auth_cert(identity.rustls_tls.chain, identity.rustls_tls.key)
|
||||
.map_err(error::tls)?
|
||||
} else {
|
||||
tls.with_no_client_auth()
|
||||
@@ -644,55 +637,46 @@ impl TlsParameters {
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct Certificate {
|
||||
#[cfg(feature = "native-tls")]
|
||||
native_tls: native_tls::Certificate,
|
||||
native_tls: super::native_tls::Certificate,
|
||||
#[cfg(feature = "rustls")]
|
||||
rustls: Vec<CertificateDer<'static>>,
|
||||
rustls: Vec<super::rustls::Certificate>,
|
||||
#[cfg(feature = "boring-tls")]
|
||||
boring_tls: boring::x509::X509,
|
||||
boring_tls: super::boring_tls::Certificate,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
|
||||
impl Certificate {
|
||||
/// Create a `Certificate` from a DER encoded certificate
|
||||
pub fn from_der(der: Vec<u8>) -> Result<Self, Error> {
|
||||
#[cfg(feature = "native-tls")]
|
||||
let native_tls_cert = native_tls::Certificate::from_der(&der).map_err(error::tls)?;
|
||||
|
||||
#[cfg(feature = "boring-tls")]
|
||||
let boring_tls_cert = boring::x509::X509::from_der(&der).map_err(error::tls)?;
|
||||
|
||||
Ok(Self {
|
||||
#[cfg(feature = "native-tls")]
|
||||
native_tls: native_tls_cert,
|
||||
#[cfg(feature = "rustls")]
|
||||
rustls: vec![der.into()],
|
||||
native_tls: super::native_tls::Certificate::from_der(&der)?,
|
||||
#[cfg(feature = "boring-tls")]
|
||||
boring_tls: boring_tls_cert,
|
||||
boring_tls: super::boring_tls::Certificate::from_der(&der)?,
|
||||
#[cfg(feature = "rustls")]
|
||||
rustls: vec![super::rustls::Certificate::from_der(der)?],
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a `Certificate` from a PEM encoded certificate
|
||||
pub fn from_pem(pem: &[u8]) -> Result<Self, Error> {
|
||||
#[cfg(feature = "native-tls")]
|
||||
let native_tls_cert = native_tls::Certificate::from_pem(pem).map_err(error::tls)?;
|
||||
|
||||
#[cfg(feature = "boring-tls")]
|
||||
let boring_tls_cert = boring::x509::X509::from_pem(pem).map_err(error::tls)?;
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
let rustls_cert = {
|
||||
use rustls::pki_types::{self, pem::PemObject as _, CertificateDer};
|
||||
|
||||
CertificateDer::pem_slice_iter(pem)
|
||||
.map(|cert| Ok(super::rustls::Certificate(cert?)))
|
||||
.collect::<Result<Vec<_>, pki_types::pem::Error>>()
|
||||
.map_err(|_| error::tls("invalid certificates"))?
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
#[cfg(feature = "native-tls")]
|
||||
native_tls: native_tls_cert,
|
||||
native_tls: super::native_tls::Certificate::from_pem(pem)?,
|
||||
#[cfg(feature = "rustls")]
|
||||
rustls: rustls_cert,
|
||||
#[cfg(feature = "boring-tls")]
|
||||
boring_tls: boring_tls_cert,
|
||||
boring_tls: super::boring_tls::Certificate::from_pem(pem)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -704,14 +688,15 @@ impl Debug for Certificate {
|
||||
}
|
||||
|
||||
/// An identity that can be used with [`TlsParametersBuilder::identify_with`]
|
||||
#[derive(Clone)]
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct Identity {
|
||||
#[cfg(feature = "native-tls")]
|
||||
native_tls: native_tls::Identity,
|
||||
native_tls: super::native_tls::Identity,
|
||||
#[cfg(feature = "rustls")]
|
||||
rustls_tls: (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>),
|
||||
rustls_tls: super::rustls::Identity,
|
||||
#[cfg(feature = "boring-tls")]
|
||||
boring_tls: (boring::x509::X509, PKey<boring::pkey::Private>),
|
||||
boring_tls: super::boring_tls::Identity,
|
||||
}
|
||||
|
||||
impl Debug for Identity {
|
||||
@@ -720,132 +705,16 @@ impl Debug for Identity {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Identity {
|
||||
fn clone(&self) -> Self {
|
||||
Identity {
|
||||
#[cfg(feature = "native-tls")]
|
||||
native_tls: self.native_tls.clone(),
|
||||
#[cfg(feature = "rustls")]
|
||||
rustls_tls: (self.rustls_tls.0.clone(), self.rustls_tls.1.clone_key()),
|
||||
#[cfg(feature = "boring-tls")]
|
||||
boring_tls: (self.boring_tls.0.clone(), self.boring_tls.1.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
|
||||
impl Identity {
|
||||
pub fn from_pem(pem: &[u8], key: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
#[cfg(feature = "native-tls")]
|
||||
native_tls: Identity::from_pem_native_tls(pem, key)?,
|
||||
native_tls: super::native_tls::Identity::from_pem(pem, key)?,
|
||||
#[cfg(feature = "rustls")]
|
||||
rustls_tls: Identity::from_pem_rustls_tls(pem, key)?,
|
||||
rustls_tls: super::rustls::Identity::from_pem(pem, key)?,
|
||||
#[cfg(feature = "boring-tls")]
|
||||
boring_tls: Identity::from_pem_boring_tls(pem, key)?,
|
||||
boring_tls: super::boring_tls::Identity::from_pem(pem, key)?,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "native-tls")]
|
||||
fn from_pem_native_tls(pem: &[u8], key: &[u8]) -> Result<native_tls::Identity, Error> {
|
||||
native_tls::Identity::from_pkcs8(pem, key).map_err(error::tls)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
fn from_pem_rustls_tls(
|
||||
pem: &[u8],
|
||||
key: &[u8],
|
||||
) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), Error> {
|
||||
let key = match PrivateKeyDer::from_pem_slice(key) {
|
||||
Ok(key) => key,
|
||||
Err(pki_types::pem::Error::NoItemsFound) => {
|
||||
return Err(error::tls("no private key found"))
|
||||
}
|
||||
Err(err) => return Err(error::tls(err)),
|
||||
};
|
||||
|
||||
Ok((vec![pem.to_owned().into()], key))
|
||||
}
|
||||
|
||||
#[cfg(feature = "boring-tls")]
|
||||
fn from_pem_boring_tls(
|
||||
pem: &[u8],
|
||||
key: &[u8],
|
||||
) -> Result<(boring::x509::X509, PKey<boring::pkey::Private>), Error> {
|
||||
let cert = boring::x509::X509::from_pem(pem).map_err(error::tls)?;
|
||||
let key = boring::pkey::PKey::private_key_from_pem(key).map_err(error::tls)?;
|
||||
Ok((cert, key))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
#[derive(Debug)]
|
||||
struct InvalidCertsVerifier {
|
||||
ignore_invalid_hostnames: bool,
|
||||
ignore_invalid_certs: bool,
|
||||
roots: RootCertStore,
|
||||
crypto_provider: Arc<CryptoProvider>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustls")]
|
||||
impl ServerCertVerifier for InvalidCertsVerifier {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
end_entity: &CertificateDer<'_>,
|
||||
intermediates: &[CertificateDer<'_>],
|
||||
server_name: &ServerName<'_>,
|
||||
_ocsp_response: &[u8],
|
||||
now: UnixTime,
|
||||
) -> Result<ServerCertVerified, TlsError> {
|
||||
let cert = ParsedCertificate::try_from(end_entity)?;
|
||||
|
||||
if !self.ignore_invalid_certs {
|
||||
rustls::client::verify_server_cert_signed_by_trust_anchor(
|
||||
&cert,
|
||||
&self.roots,
|
||||
intermediates,
|
||||
now,
|
||||
self.crypto_provider.signature_verification_algorithms.all,
|
||||
)?;
|
||||
}
|
||||
|
||||
if !self.ignore_invalid_hostnames {
|
||||
rustls::client::verify_server_name(&cert, server_name)?;
|
||||
}
|
||||
Ok(ServerCertVerified::assertion())
|
||||
}
|
||||
|
||||
fn verify_tls12_signature(
|
||||
&self,
|
||||
message: &[u8],
|
||||
cert: &CertificateDer<'_>,
|
||||
dss: &DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, TlsError> {
|
||||
verify_tls12_signature(
|
||||
message,
|
||||
cert,
|
||||
dss,
|
||||
&self.crypto_provider.signature_verification_algorithms,
|
||||
)
|
||||
}
|
||||
|
||||
fn verify_tls13_signature(
|
||||
&self,
|
||||
message: &[u8],
|
||||
cert: &CertificateDer<'_>,
|
||||
dss: &DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, TlsError> {
|
||||
verify_tls13_signature(
|
||||
message,
|
||||
cert,
|
||||
dss,
|
||||
&self.crypto_provider.signature_verification_algorithms,
|
||||
)
|
||||
}
|
||||
|
||||
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
||||
self.crypto_provider
|
||||
.signature_verification_algorithms
|
||||
.supported_schemes()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#[cfg(feature = "boring-tls")]
|
||||
mod boring_tls;
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "boring-tls")))]
|
||||
pub mod boring_tls;
|
||||
pub(super) mod deprecated;
|
||||
#[cfg(feature = "native-tls")]
|
||||
mod native_tls;
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
|
||||
pub mod native_tls;
|
||||
#[cfg(feature = "rustls")]
|
||||
mod rustls;
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
|
||||
pub mod rustls;
|
||||
|
||||
@@ -1 +1,43 @@
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use crate::transport::smtp::error::{self, Error};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Certificate(pub(super) native_tls::Certificate);
|
||||
|
||||
impl Certificate {
|
||||
pub fn from_pem(pem: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self(
|
||||
native_tls::Certificate::from_pem(pem).map_err(error::tls)?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn from_der(der: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self(
|
||||
native_tls::Certificate::from_der(der).map_err(error::tls)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Certificate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Certificate").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Identity(pub(super) native_tls::Identity);
|
||||
|
||||
impl Identity {
|
||||
pub fn from_pem(pem: &[u8], key: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self(
|
||||
native_tls::Identity::from_pkcs8(pem, key).map_err(error::tls)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Identity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Identity").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,148 @@
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use rustls::{
|
||||
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
|
||||
crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider},
|
||||
pki_types::{self, ServerName, UnixTime},
|
||||
server::ParsedCertificate,
|
||||
DigitallySignedStruct, RootCertStore, SignatureScheme,
|
||||
};
|
||||
|
||||
use crate::transport::smtp::error::{self, Error};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Certificate(pub(super) pki_types::CertificateDer<'static>);
|
||||
|
||||
impl Certificate {
|
||||
pub fn from_pem(pem: &[u8]) -> Result<Self, Error> {
|
||||
use rustls::pki_types::pem::PemObject as _;
|
||||
|
||||
Ok(Self(
|
||||
pki_types::CertificateDer::from_pem_slice(pem)
|
||||
.map_err(|_| error::tls("invalid certificate"))?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn from_der(der: Vec<u8>) -> Result<Self, Error> {
|
||||
Ok(Self(der.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Certificate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Certificate").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Identity {
|
||||
pub(super) chain: Vec<pki_types::CertificateDer<'static>>,
|
||||
pub(super) key: pki_types::PrivateKeyDer<'static>,
|
||||
}
|
||||
|
||||
impl Identity {
|
||||
pub fn from_pem(pem: &[u8], key: &[u8]) -> Result<Self, Error> {
|
||||
use rustls::pki_types::pem::PemObject as _;
|
||||
|
||||
let key = match pki_types::PrivateKeyDer::from_pem_slice(key) {
|
||||
Ok(key) => key,
|
||||
Err(pki_types::pem::Error::NoItemsFound) => {
|
||||
return Err(error::tls("no private key found"))
|
||||
}
|
||||
Err(err) => return Err(error::tls(err)),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
chain: vec![pem.to_owned().into()],
|
||||
key,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Identity {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
chain: self.chain.clone(),
|
||||
key: self.key.clone_key(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Identity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Identity").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: remove `pub(super)`
|
||||
#[derive(Debug)]
|
||||
pub(super) struct InvalidCertsVerifier {
|
||||
pub(super) ignore_invalid_hostnames: bool,
|
||||
pub(super) ignore_invalid_certs: bool,
|
||||
pub(super) roots: RootCertStore,
|
||||
pub(super) crypto_provider: Arc<CryptoProvider>,
|
||||
}
|
||||
|
||||
impl ServerCertVerifier for InvalidCertsVerifier {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
end_entity: &pki_types::CertificateDer<'_>,
|
||||
intermediates: &[pki_types::CertificateDer<'_>],
|
||||
server_name: &ServerName<'_>,
|
||||
_ocsp_response: &[u8],
|
||||
now: UnixTime,
|
||||
) -> Result<ServerCertVerified, rustls::Error> {
|
||||
let cert = ParsedCertificate::try_from(end_entity)?;
|
||||
|
||||
if !self.ignore_invalid_certs {
|
||||
rustls::client::verify_server_cert_signed_by_trust_anchor(
|
||||
&cert,
|
||||
&self.roots,
|
||||
intermediates,
|
||||
now,
|
||||
self.crypto_provider.signature_verification_algorithms.all,
|
||||
)?;
|
||||
}
|
||||
|
||||
if !self.ignore_invalid_hostnames {
|
||||
rustls::client::verify_server_name(&cert, server_name)?;
|
||||
}
|
||||
Ok(ServerCertVerified::assertion())
|
||||
}
|
||||
|
||||
fn verify_tls12_signature(
|
||||
&self,
|
||||
message: &[u8],
|
||||
cert: &pki_types::CertificateDer<'_>,
|
||||
dss: &DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, rustls::Error> {
|
||||
verify_tls12_signature(
|
||||
message,
|
||||
cert,
|
||||
dss,
|
||||
&self.crypto_provider.signature_verification_algorithms,
|
||||
)
|
||||
}
|
||||
|
||||
fn verify_tls13_signature(
|
||||
&self,
|
||||
message: &[u8],
|
||||
cert: &pki_types::CertificateDer<'_>,
|
||||
dss: &DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, rustls::Error> {
|
||||
verify_tls13_signature(
|
||||
message,
|
||||
cert,
|
||||
dss,
|
||||
&self.crypto_provider.signature_verification_algorithms,
|
||||
)
|
||||
}
|
||||
|
||||
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
||||
self.crypto_provider
|
||||
.signature_verification_algorithms
|
||||
.supported_schemes()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user