Skip to content

Commit

Permalink
Add client certificate validation.
Browse files Browse the repository at this point in the history
Related to sfackler#161

Co-authored-by: Aleksei Volkov <[email protected]>
  • Loading branch information
gxtaillon and AlgebraicWolf committed Oct 16, 2023
1 parent 481b979 commit 7d2f60b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
17 changes: 16 additions & 1 deletion src/imp/openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use std::fmt;
use std::io;
use std::sync::Once;

use {Protocol, TlsAcceptorBuilder, TlsConnectorBuilder};

use {Protocol, TlsAcceptorBuilder, TlsConnectorBuilder, TlsClientCertificateVerification};

#[cfg(have_min_max_version)]
fn supported_protocols(
Expand Down Expand Up @@ -365,6 +366,20 @@ impl TlsAcceptor {
let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
acceptor.set_private_key(&builder.identity.0.pkey)?;
acceptor.set_certificate(&builder.identity.0.cert)?;

if let Some(client_ca_cert) = &builder.client_cert_verification_ca_cert {
if builder.client_cert_verification_trust {
acceptor.cert_store_mut().add_cert((client_ca_cert.0).0.to_owned())?;
}
acceptor.add_client_ca((client_ca_cert.0).0.as_ref())?;
}
let verify_mode = match &builder.client_cert_verification {
TlsClientCertificateVerification::DoNotRequestCertificate => SslVerifyMode::NONE,
TlsClientCertificateVerification::RequestCertificate => SslVerifyMode::PEER,
TlsClientCertificateVerification::RequireCertificate => SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT,
};
acceptor.set_verify(verify_mode);

for cert in builder.identity.0.chain.iter() {
// https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html
// specifies that "When sending a certificate chain, extra chain certificates are
Expand Down
50 changes: 50 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,13 +507,31 @@ impl TlsConnector {
}
}

/// Client certificate verification modes
pub enum TlsClientCertificateVerification {
/// The server will not request certificates from the client.
///
/// # Warning
/// The client will not be able to send any certificates with this setting.
DoNotRequestCertificate,
/// The server will request a certificate from the client, then will validate
/// any certificate it receives. The client may choose not to send any.
RequestCertificate,
/// The server will request a certificate from the client, then will validate
/// any certificate it receives or reject the connection none are provided.
RequireCertificate,
}

/// A builder for `TlsAcceptor`s.
///
/// You can get one from [`TlsAcceptor::builder()`](TlsAcceptor::builder)
pub struct TlsAcceptorBuilder {
identity: Identity,
min_protocol: Option<Protocol>,
max_protocol: Option<Protocol>,
client_cert_verification: TlsClientCertificateVerification,
client_cert_verification_ca_cert: Option<Certificate>,
client_cert_verification_trust: bool
}

impl TlsAcceptorBuilder {
Expand All @@ -537,6 +555,35 @@ impl TlsAcceptorBuilder {
self
}

/// Sets the verification mode for client certificates.
///
/// Defaults to `TlsClientCertificateVerification::DoNotRequestCertificate`.
pub fn client_cert_verification(&mut self, client_cert_verification: TlsClientCertificateVerification) -> &mut TlsAcceptorBuilder {
self.client_cert_verification = client_cert_verification;
self
}

/// Sets which ca to tell the client is acceptable to send to the server.
///
/// A value of `None` will not tell the client it is acceptable to send certificates signed by any ca.
///
/// Defaults `None`.
pub fn client_cert_verification_ca_cert(&mut self, client_cert_verification_ca_cert: Option<Certificate>) -> &mut TlsAcceptorBuilder {
self.client_cert_verification_ca_cert = client_cert_verification_ca_cert;
self
}

/// Trust the ca certificate used for client verification
///
/// Adds client ca to the list of trusted certificates. This is intended for
/// testing purposes only and must not be used in production code.
///
/// Defaults `false`
pub fn trust_client_ca_cert(&mut self, should_trust: bool) -> &mut TlsAcceptorBuilder {
self.client_cert_verification_trust = should_trust;
self
}

/// Creates a new `TlsAcceptor`.
pub fn build(&self) -> Result<TlsAcceptor> {
let acceptor = imp::TlsAcceptor::new(self)?;
Expand Down Expand Up @@ -601,6 +648,9 @@ impl TlsAcceptor {
identity,
min_protocol: Some(Protocol::Tlsv10),
max_protocol: None,
client_cert_verification: TlsClientCertificateVerification::DoNotRequestCertificate,
client_cert_verification_ca_cert: None,
client_cert_verification_trust: false
}
}

Expand Down

0 comments on commit 7d2f60b

Please sign in to comment.