Skip to content

Commit

Permalink
Extend support for TrustAnchors extension
Browse files Browse the repository at this point in the history
  • Loading branch information
pohlm01 committed Oct 2, 2024
1 parent 420d1d1 commit 4216267
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 43 deletions.
3 changes: 3 additions & 0 deletions rustls/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ impl ConfigBuilder<ClientConfig, WantsClientCert> {
cert_compression_cache: Arc::new(compress::CompressionCache::default()),
cert_decompressors: compress::default_cert_decompressors().to_vec(),
ech_mode: self.state.client_ech_mode,
supported_server_certificate_types: Vec::new(),
supported_client_certificate_types: Vec::new(),
trusted_trust_anchors: Vec::new(),
}
}
}
10 changes: 8 additions & 2 deletions rustls/src/client/client_conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::crypto::{CryptoProvider, SupportedKxGroup};
use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme};
use crate::error::Error;
use crate::log::trace;
use crate::msgs::enums::NamedGroup;
use crate::msgs::handshake::ClientExtension;
use crate::msgs::enums::{CertificateType, NamedGroup};
use crate::msgs::handshake::{ClientExtension, TrustAnchorIdentifier};
use crate::msgs::persist;
use crate::suites::SupportedCipherSuite;
#[cfg(feature = "std")]
Expand Down Expand Up @@ -257,6 +257,12 @@ pub struct ClientConfig {

/// How to offer Encrypted Client Hello (ECH). The default is to not offer ECH.
pub(super) ech_mode: Option<EchMode>,

pub supported_server_certificate_types: Vec<CertificateType>,

pub supported_client_certificate_types: Vec<CertificateType>,

pub trusted_trust_anchors: Vec<TrustAnchorIdentifier>,
}

impl ClientConfig {
Expand Down
35 changes: 33 additions & 2 deletions rustls/src/client/hs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use core::ops::Deref;

use pki_types::ServerName;

#[cfg(feature = "tls12")]
Expand All @@ -25,7 +24,9 @@ use crate::error::{Error, PeerIncompatible, PeerMisbehaved};
use crate::hash_hs::HandshakeHashBuffer;
use crate::log::{debug, trace};
use crate::msgs::base::Payload;
use crate::msgs::enums::{Compression, ECPointFormat, ExtensionType, PSKKeyExchangeMode};
use crate::msgs::enums::{
CertificateType, Compression, ECPointFormat, ExtensionType, PSKKeyExchangeMode,
};
use crate::msgs::handshake::{
CertificateStatusRequest, ClientExtension, ClientHelloPayload, ClientSessionTicket,
ConvertProtocolNameList, HandshakeMessagePayload, HandshakePayload, HasServerExtensions,
Expand Down Expand Up @@ -339,6 +340,36 @@ fn emit_client_hello_for_retry(
false
};

if support_tls13 {
if config
.supported_client_certificate_types
.iter()
.any(|t| !matches!(t, CertificateType::X509))
{
exts.push(ClientExtension::ClientCertificateType(
config
.supported_client_certificate_types
.clone(),
));
}
if config
.supported_server_certificate_types
.iter()
.any(|t| !matches!(t, CertificateType::X509))
{
exts.push(ClientExtension::ServerCertificateType(
config
.supported_server_certificate_types
.clone(),
));
}
if !config.trusted_trust_anchors.is_empty() {
exts.push(ClientExtension::TrustAnchors(
config.trusted_trust_anchors.clone(),
))
}
}

// Extra extensions must be placed before the PSK extension
exts.extend(extra_exts.iter().cloned());

Expand Down
8 changes: 4 additions & 4 deletions rustls/src/client/tls13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1165,10 +1165,10 @@ fn emit_compressed_certificate_tls13(
) {
let mut cert_payload = match certkey {
CertifiedKey::X509 { cert, .. } => {
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None)
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None, false)
}
CertifiedKey::Bikeshed { cert, .. } => {
CertificatePayloadTls13::from_bikeshed_certificate(cert)
CertificatePayloadTls13::from_bikeshed_certificate(cert, false)
}
};
cert_payload.context = PayloadU8::new(auth_context.clone().unwrap_or_default());
Expand All @@ -1194,10 +1194,10 @@ fn emit_certificate_tls13(
) {
let mut cert_payload = match certkey {
Some(CertifiedKey::X509 { cert, .. }) => {
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None)
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None, false)
}
Some(CertifiedKey::Bikeshed { cert, .. }) => {
CertificatePayloadTls13::from_bikeshed_certificate(cert)
CertificatePayloadTls13::from_bikeshed_certificate(cert, false)
}
None => CertificatePayloadTls13::empty(),
};
Expand Down
108 changes: 77 additions & 31 deletions rustls/src/msgs/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ pub enum ClientExtension {
ServerCertificateType(Vec<CertificateType>),
ClientCertificateType(Vec<CertificateType>),

// https://datatracker.ietf.org/doc/html/draft-beck-tls-trust-anchor-ids-01
TrustAnchors(Vec<TrustAnchorIdentifier>),

Unknown(UnknownExtension),
Expand Down Expand Up @@ -754,6 +755,9 @@ pub enum ServerExtension {
ServerCertificateType(CertificateType),
ClientCertificateType(CertificateType),

// https://datatracker.ietf.org/doc/html/draft-beck-tls-trust-anchor-ids-01
TrustAnchors(Vec<TrustAnchorIdentifier>),

Unknown(UnknownExtension),
}

Expand All @@ -776,6 +780,7 @@ impl ServerExtension {
Self::EncryptedClientHello(_) => ExtensionType::EncryptedClientHello,
Self::ServerCertificateType(_) => ExtensionType::ServerCertificateType,
Self::ClientCertificateType(_) => ExtensionType::ClientCertificateType,
Self::TrustAnchors(_) => ExtensionType::TrustAnchors,
Self::Unknown(ref r) => r.typ,
}
}
Expand Down Expand Up @@ -805,6 +810,7 @@ impl Codec<'_> for ServerExtension {
Self::ClientCertificateType(ref r) | Self::ServerCertificateType(ref r) => {
r.encode(nested.buf)
}
Self::TrustAnchors(ref r) => r.encode(nested.buf),
Self::Unknown(ref r) => r.encode(nested.buf),
}
}
Expand Down Expand Up @@ -841,6 +847,7 @@ impl Codec<'_> for ServerExtension {
ExtensionType::ClientCertificateType => {
Self::ClientCertificateType(CertificateType::read(&mut sub)?)
}
ExtensionType::TrustAnchors => Self::TrustAnchors(Vec::read(&mut sub)?),
_ => Self::Unknown(UnknownExtension::read(typ, &mut sub)),
};

Expand Down Expand Up @@ -1544,16 +1551,18 @@ pub(crate) const CERTIFICATE_MAX_SIZE_LIMIT: usize = 0x1_0000;
#[derive(Debug)]
pub(crate) enum CertificateExtension<'a> {
CertificateStatus(CertificateStatus<'a>),
// TODO @max add support for client certificate type
ServerCertificateType(CertificateType),
// TODO @max this is based on https://datatracker.ietf.org/doc/html/draft-davidben-tls-merkle-tree-certs-03#appendix-B.1
ClientCertificateType(CertificateType),
TrustAnchors(Vec<TrustAnchorIdentifier>),
Unknown(UnknownExtension),
}

impl<'a> CertificateExtension<'a> {
pub(crate) fn ext_type(&self) -> ExtensionType {
match *self {
Self::CertificateStatus(_) => ExtensionType::StatusRequest,
Self::ServerCertificateType(_) => ExtensionType::ServerCertificateType,
Self::ClientCertificateType(_) => ExtensionType::ServerCertificateType,
Self::TrustAnchors(_) => ExtensionType::TrustAnchors,
Self::Unknown(ref r) => r.typ,
}
}
Expand All @@ -1568,7 +1577,8 @@ impl<'a> CertificateExtension<'a> {
pub(crate) fn into_owned(self) -> CertificateExtension<'static> {
match self {
Self::CertificateStatus(st) => CertificateExtension::CertificateStatus(st.into_owned()),
Self::ServerCertificateType(sct) => CertificateExtension::ServerCertificateType(sct),
Self::ClientCertificateType(sct) => CertificateExtension::ClientCertificateType(sct),
Self::TrustAnchors(tai) => CertificateExtension::TrustAnchors(tai),
Self::Unknown(unk) => CertificateExtension::Unknown(unk),
}
}
Expand All @@ -1581,7 +1591,8 @@ impl<'a> Codec<'a> for CertificateExtension<'a> {
let nested = LengthPrefixedBuffer::new(ListLength::U16, bytes);
match *self {
Self::CertificateStatus(ref r) => r.encode(nested.buf),
Self::ServerCertificateType(r) => r.encode(nested.buf),
Self::ClientCertificateType(r) => r.encode(nested.buf),
Self::TrustAnchors(ref r) => r.encode(nested.buf),
Self::Unknown(ref r) => r.encode(nested.buf),
}
}
Expand All @@ -1598,7 +1609,11 @@ impl<'a> Codec<'a> for CertificateExtension<'a> {
}
ExtensionType::ServerCertificateType => {
let sct = CertificateType::read(&mut sub)?;
Self::ServerCertificateType(sct)
Self::ClientCertificateType(sct)
}
ExtensionType::TrustAnchors => {
let tai = Vec::<TrustAnchorIdentifier>::read(&mut sub)?;
Self::TrustAnchors(tai)
}
_ => Self::Unknown(UnknownExtension::read(typ, &mut sub)),
};
Expand Down Expand Up @@ -1660,9 +1675,7 @@ impl<'a> CertificateEntry<'a> {
}

pub(crate) fn has_unknown_extension(&self) -> bool {
self.exts
.iter()
.any(|ext| ext.ext_type() != ExtensionType::StatusRequest)
self.exts.iter().any(|ext| matches!(ext, CertificateExtension::Unknown(_)))
}

pub(crate) fn ocsp_response(&self) -> Option<&[u8]> {
Expand All @@ -1671,6 +1684,15 @@ impl<'a> CertificateEntry<'a> {
.find(|ext| ext.ext_type() == ExtensionType::StatusRequest)
.and_then(CertificateExtension::cert_status)
}

pub(crate) fn trust_anchor_ext(&self) -> Option<&[TrustAnchorIdentifier]> {
self.exts
.first()
.and_then(|ext| match ext {
CertificateExtension::TrustAnchors(tai) => Some(tai.as_slice()),
_ => None,
})
}
}

impl<'a> TlsListElement for CertificateEntry<'a> {
Expand Down Expand Up @@ -1704,36 +1726,60 @@ impl<'a> CertificatePayloadTls13<'a> {
pub(crate) fn from_x509_certificates(
certs: impl Iterator<Item = &'a CertificateDer<'a>>,
ocsp_response: Option<&'a [u8]>,
matches_requested_trust_anchors: bool,
) -> Self {
let mut entries: Vec<_> = certs
// zip certificate iterator with `ocsp_response` followed by
// an infinite-length iterator of `None`.
.zip(
ocsp_response
.into_iter()
.map(Some)
.chain(iter::repeat(None)),
)
.map(|(cert, ocsp)| {
let mut e = CertificateEntry::new(cert.to_vec());
if let Some(ocsp) = ocsp {
e.exts
.push(CertificateExtension::CertificateStatus(
CertificateStatus::new(ocsp),
));
}
e
})
.collect();

if matches_requested_trust_anchors {
entries
.first_mut()
.iter_mut()
.for_each(|entry| {
entry
.exts
.push(CertificateExtension::TrustAnchors(Vec::new()))
});
};

Self {
context: PayloadU8::empty(),
entries: certs
// zip certificate iterator with `ocsp_response` followed by
// an infinite-length iterator of `None`.
.zip(
ocsp_response
.into_iter()
.map(Some)
.chain(iter::repeat(None)),
)
.map(|(cert, ocsp)| {
let mut e = CertificateEntry::new(cert.to_vec());
if let Some(ocsp) = ocsp {
e.exts
.push(CertificateExtension::CertificateStatus(
CertificateStatus::new(ocsp),
));
}
e
})
.collect(),
entries,
}
}

pub(crate) fn from_bikeshed_certificate(cert: &BikeshedCertificate<'_>) -> Self {
pub(crate) fn from_bikeshed_certificate(
cert: &BikeshedCertificate<'_>,
matches_requested_trust_anchors: bool,
) -> Self {
let mut entry = CertificateEntry::new(cert.encode());
if matches_requested_trust_anchors {
entry
.exts
.push(CertificateExtension::TrustAnchors(Vec::new()));
}

Self {
context: PayloadU8::empty(),
entries: vec![CertificateEntry::new(cert.encode())],
entries: vec![entry],
}
}

Expand Down
11 changes: 7 additions & 4 deletions rustls/src/server/tls13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,15 @@ mod client_hello {
let doing_client_auth = if full_handshake {
let client_auth = emit_certificate_req_tls13(&mut flight, &self.config)?;

// TODO @max set the `matches_requested_trust_anchors` to a meaningful values
let payload = match server_key.get_cert() {
Certificate::X509(cert) => {
CertificatePayloadTls13::from_x509_certificates(cert.iter(), ocsp_response)
}
Certificate::X509(cert) => CertificatePayloadTls13::from_x509_certificates(
cert.iter(),
ocsp_response,
false,
),
Certificate::Bikeshed(cert) => {
CertificatePayloadTls13::from_bikeshed_certificate(cert)
CertificatePayloadTls13::from_bikeshed_certificate(cert, false)
}
};
if let Some(compressor) = cert_compressor {
Expand Down

0 comments on commit 4216267

Please sign in to comment.