mirror of https://github.com/ctz/rustls
210 lines
6.9 KiB
Rust
210 lines
6.9 KiB
Rust
//! Tests for configuring and using a [`ClientCertVerifier`] for a server.
|
|
|
|
#![cfg(feature = "dangerous_configuration")]
|
|
|
|
mod common;
|
|
|
|
use crate::common::{
|
|
dns_name, do_handshake_until_both_error, do_handshake_until_error, get_client_root_store,
|
|
make_client_config_with_versions, make_client_config_with_versions_with_auth,
|
|
make_pair_for_arc_configs, ErrorFromPeer, KeyType, ALL_KEY_TYPES,
|
|
};
|
|
use rustls::client::WebPkiVerifier;
|
|
use rustls::internal::msgs::handshake::DistinguishedName;
|
|
use rustls::server::{ClientCertVerified, ClientCertVerifier};
|
|
use rustls::{
|
|
AlertDescription, Certificate, ClientConnection, Error, InvalidMessage, ServerConfig,
|
|
ServerConnection, SignatureScheme,
|
|
};
|
|
use std::sync::Arc;
|
|
|
|
// Client is authorized!
|
|
fn ver_ok() -> Result<ClientCertVerified, Error> {
|
|
Ok(rustls::server::ClientCertVerified::assertion())
|
|
}
|
|
|
|
// Use when we shouldn't even attempt verification
|
|
fn ver_unreachable() -> Result<ClientCertVerified, Error> {
|
|
unreachable!()
|
|
}
|
|
|
|
// Verifier that returns an error that we can expect
|
|
fn ver_err() -> Result<ClientCertVerified, Error> {
|
|
Err(Error::General("test err".to_string()))
|
|
}
|
|
|
|
fn server_config_with_verifier(
|
|
kt: KeyType,
|
|
client_cert_verifier: MockClientVerifier,
|
|
) -> ServerConfig {
|
|
ServerConfig::builder()
|
|
.with_safe_defaults()
|
|
.with_client_cert_verifier(Arc::new(client_cert_verifier))
|
|
.with_single_cert(kt.get_chain(), kt.get_key())
|
|
.unwrap()
|
|
}
|
|
|
|
#[test]
|
|
// Happy path, we resolve to a root, it is verified OK, should be able to connect
|
|
fn client_verifier_works() {
|
|
for kt in ALL_KEY_TYPES.iter() {
|
|
let client_verifier = MockClientVerifier {
|
|
verified: ver_ok,
|
|
subjects: get_client_root_store(*kt)
|
|
.roots
|
|
.iter()
|
|
.map(|r| r.subject().clone())
|
|
.collect(),
|
|
mandatory: true,
|
|
offered_schemes: None,
|
|
};
|
|
|
|
let server_config = server_config_with_verifier(*kt, client_verifier);
|
|
let server_config = Arc::new(server_config);
|
|
|
|
for version in rustls::ALL_VERSIONS {
|
|
let client_config = make_client_config_with_versions_with_auth(*kt, &[version]);
|
|
let (mut client, mut server) =
|
|
make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config);
|
|
let err = do_handshake_until_error(&mut client, &mut server);
|
|
assert_eq!(err, Ok(()));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Server offers no verification schemes
|
|
#[test]
|
|
fn client_verifier_no_schemes() {
|
|
for kt in ALL_KEY_TYPES.iter() {
|
|
let client_verifier = MockClientVerifier {
|
|
verified: ver_ok,
|
|
subjects: get_client_root_store(*kt)
|
|
.roots
|
|
.iter()
|
|
.map(|r| r.subject().clone())
|
|
.collect(),
|
|
mandatory: true,
|
|
offered_schemes: Some(vec![]),
|
|
};
|
|
|
|
let server_config = server_config_with_verifier(*kt, client_verifier);
|
|
let server_config = Arc::new(server_config);
|
|
|
|
for version in rustls::ALL_VERSIONS {
|
|
let client_config = make_client_config_with_versions_with_auth(*kt, &[version]);
|
|
let (mut client, mut server) =
|
|
make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config);
|
|
let err = do_handshake_until_error(&mut client, &mut server);
|
|
assert_eq!(
|
|
err,
|
|
Err(ErrorFromPeer::Client(Error::InvalidMessage(
|
|
InvalidMessage::NoSignatureSchemes,
|
|
))),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we do have a root, we must do auth
|
|
#[test]
|
|
fn client_verifier_no_auth_yes_root() {
|
|
for kt in ALL_KEY_TYPES.iter() {
|
|
let client_verifier = MockClientVerifier {
|
|
verified: ver_unreachable,
|
|
subjects: get_client_root_store(*kt)
|
|
.roots
|
|
.iter()
|
|
.map(|r| r.subject().clone())
|
|
.collect(),
|
|
mandatory: true,
|
|
offered_schemes: None,
|
|
};
|
|
|
|
let server_config = server_config_with_verifier(*kt, client_verifier);
|
|
let server_config = Arc::new(server_config);
|
|
|
|
for version in rustls::ALL_VERSIONS {
|
|
let client_config = make_client_config_with_versions(*kt, &[version]);
|
|
let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap();
|
|
let mut client =
|
|
ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap();
|
|
let errs = do_handshake_until_both_error(&mut client, &mut server);
|
|
assert_eq!(
|
|
errs,
|
|
Err(vec![
|
|
ErrorFromPeer::Server(Error::NoCertificatesPresented),
|
|
ErrorFromPeer::Client(Error::AlertReceived(
|
|
AlertDescription::CertificateRequired
|
|
))
|
|
])
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
// Triple checks we propagate the rustls::Error through
|
|
fn client_verifier_fails_properly() {
|
|
for kt in ALL_KEY_TYPES.iter() {
|
|
let client_verifier = MockClientVerifier {
|
|
verified: ver_err,
|
|
subjects: get_client_root_store(*kt)
|
|
.roots
|
|
.iter()
|
|
.map(|r| r.subject().clone())
|
|
.collect(),
|
|
mandatory: true,
|
|
offered_schemes: None,
|
|
};
|
|
|
|
let server_config = server_config_with_verifier(*kt, client_verifier);
|
|
let server_config = Arc::new(server_config);
|
|
|
|
for version in rustls::ALL_VERSIONS {
|
|
let client_config = make_client_config_with_versions_with_auth(*kt, &[version]);
|
|
let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap();
|
|
let mut client =
|
|
ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap();
|
|
let err = do_handshake_until_error(&mut client, &mut server);
|
|
assert_eq!(
|
|
err,
|
|
Err(ErrorFromPeer::Server(Error::General("test err".into())))
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct MockClientVerifier {
|
|
pub verified: fn() -> Result<ClientCertVerified, Error>,
|
|
pub subjects: Vec<DistinguishedName>,
|
|
pub mandatory: bool,
|
|
pub offered_schemes: Option<Vec<SignatureScheme>>,
|
|
}
|
|
|
|
impl ClientCertVerifier for MockClientVerifier {
|
|
fn client_auth_mandatory(&self) -> bool {
|
|
self.mandatory
|
|
}
|
|
|
|
fn client_auth_root_subjects(&self) -> &[DistinguishedName] {
|
|
&self.subjects
|
|
}
|
|
|
|
fn verify_client_cert(
|
|
&self,
|
|
_end_entity: &Certificate,
|
|
_intermediates: &[Certificate],
|
|
_now: std::time::SystemTime,
|
|
) -> Result<ClientCertVerified, Error> {
|
|
(self.verified)()
|
|
}
|
|
|
|
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
|
if let Some(schemes) = &self.offered_schemes {
|
|
schemes.clone()
|
|
} else {
|
|
WebPkiVerifier::verification_schemes()
|
|
}
|
|
}
|
|
}
|