8000 expose verify helper functions by Fritiofhedstrom · Pull Request #1325 · rustls/rustls · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

expose verify helper functions #1325

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

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions rustls/src/key.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::fmt;

use crate::Error;

/// This type contains a private key by value.
///
/// The private key must be DER-encoded ASN.1 in either
Expand Down Expand Up @@ -97,6 +99,20 @@ impl fmt::Debug for Certificate {
}
}

/// wrapper around internal representation of a parsed certificate. This is used in order to avoid parsing twice when specifying custom verification
#[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))]
pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);

impl<'a> TryFrom<&'a Certificate> for ParsedCertificate<'a> {
type Error = Error;
fn try_from(value: &'a Certificate) -> Result<ParsedCertificate<'a>, Self::Error> {
webpki::EndEntityCert::try_from(value.0.as_ref())
.map_err(crate::verify::pki_error)
.map(ParsedCertificate)
}
}

#[cfg(test)]
mod test {
use super::Certificate;
Expand Down
5 changes: 4 additions & 1 deletion rustls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,8 @@ pub mod client {

#[cfg(feature = "dangerous_configuration")]
pub use crate::verify::{
HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, WebPkiVerifier,
verify_server_cert_signed_by_trust_anchor, verify_server_name, HandshakeSignatureValid,
ServerCertVerified, ServerCertVerifier, WebPkiVerifier,
};
#[cfg(feature = "dangerous_configuration")]
pub use client_conn::danger::DangerousClientConfig;
Expand Down Expand Up @@ -461,6 +462,8 @@ pub mod server {
#[cfg(feature = "dangerous_configuration")]
pub use crate::dns_name::DnsName;
#[cfg(feature = "dangerous_configuration")]
pub use crate::key::ParsedCertificate;
#[cfg(feature = "dangerous_configuration")]
pub use crate::verify::{ClientCertVerified, ClientCertVerifier};
}

Expand Down
147 changes: 85 additions & 62 deletions rustls/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::anchors::{OwnedTrustAnchor, RootCertStore};
use crate::client::ServerName;
use crate::enums::SignatureScheme;
use crate::error::{CertificateError, Error, InvalidMessage, PeerMisbehaved};
use crate::key::Certificate;
use crate::key::{Certificate, ParsedCertificate};
#[cfg(feature = "logging")]
use crate::log::trace;
use crate::msgs::base::PayloadU16;
Expand Down Expand Up @@ -307,6 +307,65 @@ impl fmt::Debug for dyn ClientCertVerifier {
}
}

/// Verify that the end-entity certificate `end_entity` is a valid server cert
/// and chains to at least one of the [OwnedTrustAnchor] in the `roots` [RootCertStore].
///
/// `intermediates` contains all certificates other than `end_entity` that
/// were sent as part of the server's [Certificate] message. It is in the
/// same order that the server sent them and may be empty.
#[allow(dead_code)]
#[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))]
pub fn verify_server_cert_signed_by_trust_anchor(
cert: &ParsedCertificate,
roots: &RootCertStore,
intermediates: &[Certificate],
now: SystemTime,
) -> Result<(), Error> {
let chain = intermediate_chain(intermediates);
let trust_roots = trust_roots(roots);
let webpki_now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?;

cert.0
.verify_is_valid_tls_server_cert(
SUPPORTED_SIG_ALGS,
&webpki::TlsServerTrustAnchors(&trust_roots),
&chain,
webpki_now,
)
.map_err(pki_error)
.map(|_| ())
}

/// Verify that the `end_entity` has a name or alternative name matching the `server_name`
/// note: this only verifies the name and should be used in conjuction with more verification
/// like [verify_server_cert_signed_by_trust_anchor]
#[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))]
#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))]
pub fn verify_server_name(cert: &ParsedCertificate, server_name: &ServerName) -> Result<(), Error> {
match server_name {
ServerName::DnsName(dns_name) => {
// unlikely error because dns_name::DnsNameRef and webpki::DnsNameRef
// should have the same encoding rules.
let dns_name = webpki::DnsNameRef::try_from_ascii_str(dns_name.as_ref())
.map_err(|_| Error::InvalidCertificate(CertificateError::BadEncoding))?;
let name = webpki::SubjectNameRef::DnsName(dns_name);
cert.0
.verify_is_valid_for_subject_name(name)
.map_err(pki_error)?;
}
ServerName::IpAddress(ip_addr) => {
let ip_addr = webpki::IpAddr::from(*ip_addr);
cert.0
.verify_is_valid_for_subject_name(webpki::SubjectNameRef::IpAddress(
webpki::IpAddrRef::from(&ip_addr),
))
.map_err(pki_error)?;
}
}
Ok(())
}

impl ServerCertVerifier for WebPkiVerifier {
/// Will verify the certificate is valid in the following ways:
/// - Signed by a trusted `RootCertStore` CA
Expand All @@ -320,43 +379,16 @@ impl ServerCertVerifier for WebPkiVerifier {
ocsp_response: &[u8],
now: SystemTime,
) -> Result<ServerCertVerified, Error> {
let (cert, chain, trustroots) = prepare(end_entity, intermediates, &self.roots)?;
let webpki_now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?;
let cert = ParsedCertificate::try_from(end_entity)?;

let cert = cert
.verify_is_valid_tls_server_cert(
SUPPORTED_SIG_ALGS,
&webpki::TlsServerTrustAnchors(&trustroots),
&chain,
webpki_now,
)
.map_err(pki_error)
.map(|_| cert)?;
verify_server_cert_signed_by_trust_anchor(&cert, &self.roots, intermediates, now)?;

if !ocsp_response.is_empty() {
trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec());
}

match server_name {
ServerName::DnsName(dns_name) => {
// unlikely error because dns_name::DnsNameRef and webpki::DnsNameRef
// should have the same encoding rules.
let dns_name = webpki::DnsNameRef::try_from_ascii_str(dns_name.as_ref())
.map_err(|_| Error::InvalidCertificate(CertificateError::BadEncoding))?;
let name = webpki::SubjectNameRef::DnsName(dns_name);
cert.verify_is_valid_for_subject_name(name)
.map_err(pki_error)
.map(|_| ServerCertVerified::assertion())
}
ServerName::IpAddress(ip_addr) => {
let ip_addr = webpki::IpAddr::from(*ip_addr);
cert.verify_is_valid_for_subject_name(webpki::SubjectNameRef::IpAddress(
webpki::IpAddrRef::from(&ip_addr),
))
.map_err(pki_error)
.map(|_| ServerCertVerified::assertion())
}
}
verify_server_name(&cert, server_name)?;
Ok(ServerCertVerified::assertion())
}
}

Expand Down Expand Up @@ -393,32 +425,19 @@ impl WebPkiVerifier {
}
}

type CertChainAndRoots<'a, 'b> = (
webpki::EndEntityCert<'a>,
Vec<&'a [u8]>,
Vec<webpki::TrustAnchor<'b>>,
);

fn prepare<'a, 'b>(
end_entity: &'a Certificate,
intermediates: &'a [Certificate],
roots: &'b RootCertStore,
) -> Result<CertChainAndRoots<'a, 'b>, Error> {
// EE cert must appear first.
let cert = webpki::EndEntityCert::try_from(end_entity.0.as_ref()).map_err(pki_error)?;

let intermediates: Vec<&'a [u8]> = intermediates
fn intermediate_chain(intermediates: &[Certificate]) -> Vec<&[u8]> {
intermediates
.iter()
.map(|cert| cert.0.as_ref())
.collect();
.collect()
}

let trustroots: Vec<webpki::TrustAnchor> = roots
fn trust_roots(roots: &RootCertStore) -> Vec<webpki::TrustAnchor> {
roots
.roots
.iter()
.map(OwnedTrustAnchor::to_trust_anchor)
.collect();

Ok((cert, intermediates, trustroots))
.collect()
}

/// A `ClientCertVerifier` that will ensure that every client provides a trusted
Expand Down Expand Up @@ -467,16 +486,20 @@ impl ClientCertVerifier for AllowAnyAuthenticatedClient {
intermediates: &[Certificate],
now: SystemTime,
) -> Result<ClientCertVerified, Error> {
let (cert, chain, trustroots) = prepare(end_entity, intermediates, &self.roots)?;
let cert = ParsedCertificate::try_from(end_entity)?;
let chain = intermediate_chain(intermediates);
let trust_roots = trust_roots(&self.roots);
let now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?;
cert.verify_is_valid_tls_client_cert(
SUPPORTED_SIG_ALGS,
&webpki::TlsClientTrustAnchors(&trustroots),
&chain,
now,
)
.map_err(pki_error)
.map(|_| ClientCertVerified::assertion())

cert.0
.verify_is_valid_tls_client_cert(
SUPPORTED_SIG_ALGS,
&webpki::TlsClientTrustAnchors(&trust_roots),
&chain,
now,
)
.map_err(pki_error)
.map(|_| ClientCertVerified::assertion())
}
}

Expand Down Expand Up @@ -533,7 +556,7 @@ impl ClientCertVerifier for AllowAnyAnonymousOrAuthenticatedClient {
}
}

fn pki_error(error: webpki::Error) -> Error {
pub(crate) fn pki_error(error: webpki::Error) -> Error {
use webpki::Error::*;
match error {
BadDer | BadDerTime => CertificateError::BadEncoding.into(),
Expand Down
0