Skip to content
This repository was archived by the owner on Oct 15, 2025. It is now read-only.

Commit 4216267

Browse files
committed
Extend support for TrustAnchors extension
1 parent 420d1d1 commit 4216267

File tree

6 files changed

+132
-43
lines changed

6 files changed

+132
-43
lines changed

rustls/src/client/builder.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ impl ConfigBuilder<ClientConfig, WantsClientCert> {
192192
cert_compression_cache: Arc::new(compress::CompressionCache::default()),
193193
cert_decompressors: compress::default_cert_decompressors().to_vec(),
194194
ech_mode: self.state.client_ech_mode,
195+
supported_server_certificate_types: Vec::new(),
196+
supported_client_certificate_types: Vec::new(),
197+
trusted_trust_anchors: Vec::new(),
195198
}
196199
}
197200
}

rustls/src/client/client_conn.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use crate::crypto::{CryptoProvider, SupportedKxGroup};
1616
use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme};
1717
use crate::error::Error;
1818
use crate::log::trace;
19-
use crate::msgs::enums::NamedGroup;
20-
use crate::msgs::handshake::ClientExtension;
19+
use crate::msgs::enums::{CertificateType, NamedGroup};
20+
use crate::msgs::handshake::{ClientExtension, TrustAnchorIdentifier};
2121
use crate::msgs::persist;
2222
use crate::suites::SupportedCipherSuite;
2323
#[cfg(feature = "std")]
@@ -257,6 +257,12 @@ pub struct ClientConfig {
257257

258258
/// How to offer Encrypted Client Hello (ECH). The default is to not offer ECH.
259259
pub(super) ech_mode: Option<EchMode>,
260+
261+
pub supported_server_certificate_types: Vec<CertificateType>,
262+
263+
pub supported_client_certificate_types: Vec<CertificateType>,
264+
265+
pub trusted_trust_anchors: Vec<TrustAnchorIdentifier>,
260266
}
261267

262268
impl ClientConfig {

rustls/src/client/hs.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use alloc::sync::Arc;
44
use alloc::vec;
55
use alloc::vec::Vec;
66
use core::ops::Deref;
7-
87
use pki_types::ServerName;
98

109
#[cfg(feature = "tls12")]
@@ -25,7 +24,9 @@ use crate::error::{Error, PeerIncompatible, PeerMisbehaved};
2524
use crate::hash_hs::HandshakeHashBuffer;
2625
use crate::log::{debug, trace};
2726
use crate::msgs::base::Payload;
28-
use crate::msgs::enums::{Compression, ECPointFormat, ExtensionType, PSKKeyExchangeMode};
27+
use crate::msgs::enums::{
28+
CertificateType, Compression, ECPointFormat, ExtensionType, PSKKeyExchangeMode,
29+
};
2930
use crate::msgs::handshake::{
3031
CertificateStatusRequest, ClientExtension, ClientHelloPayload, ClientSessionTicket,
3132
ConvertProtocolNameList, HandshakeMessagePayload, HandshakePayload, HasServerExtensions,
@@ -339,6 +340,36 @@ fn emit_client_hello_for_retry(
339340
false
340341
};
341342

343+
if support_tls13 {
344+
if config
345+
.supported_client_certificate_types
346+
.iter()
347+
.any(|t| !matches!(t, CertificateType::X509))
348+
{
349+
exts.push(ClientExtension::ClientCertificateType(
350+
config
351+
.supported_client_certificate_types
352+
.clone(),
353+
));
354+
}
355+
if config
356+
.supported_server_certificate_types
357+
.iter()
358+
.any(|t| !matches!(t, CertificateType::X509))
359+
{
360+
exts.push(ClientExtension::ServerCertificateType(
361+
config
362+
.supported_server_certificate_types
363+
.clone(),
364+
));
365+
}
366+
if !config.trusted_trust_anchors.is_empty() {
367+
exts.push(ClientExtension::TrustAnchors(
368+
config.trusted_trust_anchors.clone(),
369+
))
370+
}
371+
}
372+
342373
// Extra extensions must be placed before the PSK extension
343374
exts.extend(extra_exts.iter().cloned());
344375

rustls/src/client/tls13.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,10 +1165,10 @@ fn emit_compressed_certificate_tls13(
11651165
) {
11661166
let mut cert_payload = match certkey {
11671167
CertifiedKey::X509 { cert, .. } => {
1168-
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None)
1168+
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None, false)
11691169
}
11701170
CertifiedKey::Bikeshed { cert, .. } => {
1171-
CertificatePayloadTls13::from_bikeshed_certificate(cert)
1171+
CertificatePayloadTls13::from_bikeshed_certificate(cert, false)
11721172
}
11731173
};
11741174
cert_payload.context = PayloadU8::new(auth_context.clone().unwrap_or_default());
@@ -1194,10 +1194,10 @@ fn emit_certificate_tls13(
11941194
) {
11951195
let mut cert_payload = match certkey {
11961196
Some(CertifiedKey::X509 { cert, .. }) => {
1197-
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None)
1197+
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None, false)
11981198
}
11991199
Some(CertifiedKey::Bikeshed { cert, .. }) => {
1200-
CertificatePayloadTls13::from_bikeshed_certificate(cert)
1200+
CertificatePayloadTls13::from_bikeshed_certificate(cert, false)
12011201
}
12021202
None => CertificatePayloadTls13::empty(),
12031203
};

rustls/src/msgs/handshake.rs

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ pub enum ClientExtension {
567567
ServerCertificateType(Vec<CertificateType>),
568568
ClientCertificateType(Vec<CertificateType>),
569569

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

572573
Unknown(UnknownExtension),
@@ -754,6 +755,9 @@ pub enum ServerExtension {
754755
ServerCertificateType(CertificateType),
755756
ClientCertificateType(CertificateType),
756757

758+
// https://datatracker.ietf.org/doc/html/draft-beck-tls-trust-anchor-ids-01
759+
TrustAnchors(Vec<TrustAnchorIdentifier>),
760+
757761
Unknown(UnknownExtension),
758762
}
759763

@@ -776,6 +780,7 @@ impl ServerExtension {
776780
Self::EncryptedClientHello(_) => ExtensionType::EncryptedClientHello,
777781
Self::ServerCertificateType(_) => ExtensionType::ServerCertificateType,
778782
Self::ClientCertificateType(_) => ExtensionType::ClientCertificateType,
783+
Self::TrustAnchors(_) => ExtensionType::TrustAnchors,
779784
Self::Unknown(ref r) => r.typ,
780785
}
781786
}
@@ -805,6 +810,7 @@ impl Codec<'_> for ServerExtension {
805810
Self::ClientCertificateType(ref r) | Self::ServerCertificateType(ref r) => {
806811
r.encode(nested.buf)
807812
}
813+
Self::TrustAnchors(ref r) => r.encode(nested.buf),
808814
Self::Unknown(ref r) => r.encode(nested.buf),
809815
}
810816
}
@@ -841,6 +847,7 @@ impl Codec<'_> for ServerExtension {
841847
ExtensionType::ClientCertificateType => {
842848
Self::ClientCertificateType(CertificateType::read(&mut sub)?)
843849
}
850+
ExtensionType::TrustAnchors => Self::TrustAnchors(Vec::read(&mut sub)?),
844851
_ => Self::Unknown(UnknownExtension::read(typ, &mut sub)),
845852
};
846853

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

15521560
impl<'a> CertificateExtension<'a> {
15531561
pub(crate) fn ext_type(&self) -> ExtensionType {
15541562
match *self {
15551563
Self::CertificateStatus(_) => ExtensionType::StatusRequest,
1556-
Self::ServerCertificateType(_) => ExtensionType::ServerCertificateType,
1564+
Self::ClientCertificateType(_) => ExtensionType::ServerCertificateType,
1565+
Self::TrustAnchors(_) => ExtensionType::TrustAnchors,
15571566
Self::Unknown(ref r) => r.typ,
15581567
}
15591568
}
@@ -1568,7 +1577,8 @@ impl<'a> CertificateExtension<'a> {
15681577
pub(crate) fn into_owned(self) -> CertificateExtension<'static> {
15691578
match self {
15701579
Self::CertificateStatus(st) => CertificateExtension::CertificateStatus(st.into_owned()),
1571-
Self::ServerCertificateType(sct) => CertificateExtension::ServerCertificateType(sct),
1580+
Self::ClientCertificateType(sct) => CertificateExtension::ClientCertificateType(sct),
1581+
Self::TrustAnchors(tai) => CertificateExtension::TrustAnchors(tai),
15721582
Self::Unknown(unk) => CertificateExtension::Unknown(unk),
15731583
}
15741584
}
@@ -1581,7 +1591,8 @@ impl<'a> Codec<'a> for CertificateExtension<'a> {
15811591
let nested = LengthPrefixedBuffer::new(ListLength::U16, bytes);
15821592
match *self {
15831593
Self::CertificateStatus(ref r) => r.encode(nested.buf),
1584-
Self::ServerCertificateType(r) => r.encode(nested.buf),
1594+
Self::ClientCertificateType(r) => r.encode(nested.buf),
1595+
Self::TrustAnchors(ref r) => r.encode(nested.buf),
15851596
Self::Unknown(ref r) => r.encode(nested.buf),
15861597
}
15871598
}
@@ -1598,7 +1609,11 @@ impl<'a> Codec<'a> for CertificateExtension<'a> {
15981609
}
15991610
ExtensionType::ServerCertificateType => {
16001611
let sct = CertificateType::read(&mut sub)?;
1601-
Self::ServerCertificateType(sct)
1612+
Self::ClientCertificateType(sct)
1613+
}
1614+
ExtensionType::TrustAnchors => {
1615+
let tai = Vec::<TrustAnchorIdentifier>::read(&mut sub)?;
1616+
Self::TrustAnchors(tai)
16021617
}
16031618
_ => Self::Unknown(UnknownExtension::read(typ, &mut sub)),
16041619
};
@@ -1660,9 +1675,7 @@ impl<'a> CertificateEntry<'a> {
16601675
}
16611676

16621677
pub(crate) fn has_unknown_extension(&self) -> bool {
1663-
self.exts
1664-
.iter()
1665-
.any(|ext| ext.ext_type() != ExtensionType::StatusRequest)
1678+
self.exts.iter().any(|ext| matches!(ext, CertificateExtension::Unknown(_)))
16661679
}
16671680

16681681
pub(crate) fn ocsp_response(&self) -> Option<&[u8]> {
@@ -1671,6 +1684,15 @@ impl<'a> CertificateEntry<'a> {
16711684
.find(|ext| ext.ext_type() == ExtensionType::StatusRequest)
16721685
.and_then(CertificateExtension::cert_status)
16731686
}
1687+
1688+
pub(crate) fn trust_anchor_ext(&self) -> Option<&[TrustAnchorIdentifier]> {
1689+
self.exts
1690+
.first()
1691+
.and_then(|ext| match ext {
1692+
CertificateExtension::TrustAnchors(tai) => Some(tai.as_slice()),
1693+
_ => None,
1694+
})
1695+
}
16741696
}
16751697

16761698
impl<'a> TlsListElement for CertificateEntry<'a> {
@@ -1704,36 +1726,60 @@ impl<'a> CertificatePayloadTls13<'a> {
17041726
pub(crate) fn from_x509_certificates(
17051727
certs: impl Iterator<Item = &'a CertificateDer<'a>>,
17061728
ocsp_response: Option<&'a [u8]>,
1729+
matches_requested_trust_anchors: bool,
17071730
) -> Self {
1731+
let mut entries: Vec<_> = certs
1732+
// zip certificate iterator with `ocsp_response` followed by
1733+
// an infinite-length iterator of `None`.
1734+
.zip(
1735+
ocsp_response
1736+
.into_iter()
1737+
.map(Some)
1738+
.chain(iter::repeat(None)),
1739+
)
1740+
.map(|(cert, ocsp)| {
1741+
let mut e = CertificateEntry::new(cert.to_vec());
1742+
if let Some(ocsp) = ocsp {
1743+
e.exts
1744+
.push(CertificateExtension::CertificateStatus(
1745+
CertificateStatus::new(ocsp),
1746+
));
1747+
}
1748+
e
1749+
})
1750+
.collect();
1751+
1752+
if matches_requested_trust_anchors {
1753+
entries
1754+
.first_mut()
1755+
.iter_mut()
1756+
.for_each(|entry| {
1757+
entry
1758+
.exts
1759+
.push(CertificateExtension::TrustAnchors(Vec::new()))
1760+
});
1761+
};
1762+
17081763
Self {
17091764
context: PayloadU8::empty(),
1710-
entries: certs
1711-
// zip certificate iterator with `ocsp_response` followed by
1712-
// an infinite-length iterator of `None`.
1713-
.zip(
1714-
ocsp_response
1715-
.into_iter()
1716-
.map(Some)
1717-
.chain(iter::repeat(None)),
1718-
)
1719-
.map(|(cert, ocsp)| {
1720-
let mut e = CertificateEntry::new(cert.to_vec());
1721-
if let Some(ocsp) = ocsp {
1722-
e.exts
1723-
.push(CertificateExtension::CertificateStatus(
1724-
CertificateStatus::new(ocsp),
1725-
));
1726-
}
1727-
e
1728-
})
1729-
.collect(),
1765+
entries,
17301766
}
17311767
}
17321768

1733-
pub(crate) fn from_bikeshed_certificate(cert: &BikeshedCertificate<'_>) -> Self {
1769+
pub(crate) fn from_bikeshed_certificate(
1770+
cert: &BikeshedCertificate<'_>,
1771+
matches_requested_trust_anchors: bool,
1772+
) -> Self {
1773+
let mut entry = CertificateEntry::new(cert.encode());
1774+
if matches_requested_trust_anchors {
1775+
entry
1776+
.exts
1777+
.push(CertificateExtension::TrustAnchors(Vec::new()));
1778+
}
1779+
17341780
Self {
17351781
context: PayloadU8::empty(),
1736-
entries: vec![CertificateEntry::new(cert.encode())],
1782+
entries: vec![entry],
17371783
}
17381784
}
17391785

rustls/src/server/tls13.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,12 +372,15 @@ mod client_hello {
372372
let doing_client_auth = if full_handshake {
373373
let client_auth = emit_certificate_req_tls13(&mut flight, &self.config)?;
374374

375+
// TODO @max set the `matches_requested_trust_anchors` to a meaningful values
375376
let payload = match server_key.get_cert() {
376-
Certificate::X509(cert) => {
377-
CertificatePayloadTls13::from_x509_certificates(cert.iter(), ocsp_response)
378-
}
377+
Certificate::X509(cert) => CertificatePayloadTls13::from_x509_certificates(
378+
cert.iter(),
379+
ocsp_response,
380+
false,
381+
),
379382
Certificate::Bikeshed(cert) => {
380-
CertificatePayloadTls13::from_bikeshed_certificate(cert)
383+
CertificatePayloadTls13::from_bikeshed_certificate(cert, false)
381384
}
382385
};
383386
if let Some(compressor) = cert_compressor {

0 commit comments

Comments
 (0)