Revert "Revert "Remove support for SCT stapling""

This reverts commit 777cc07a4b.
This commit is contained in:
Joseph Birr-Pixton 2023-07-06 11:08:05 +01:00 committed by ctz
parent 06b44be5d2
commit 1d659a4689
25 changed files with 46 additions and 529 deletions

View File

@ -23,6 +23,8 @@ If you'd like to help out, please see [CONTRIBUTING.md](CONTRIBUTING.md).
* Next release:
- `RootCertStore::add_parsable_certificates` now takes a
`impl IntoIterator<Item = impl AsRef<[u8]>>`.
- *Breaking change*: remove support for SCT stapling. Ecosystem support for this is rare compared to
inclusion of SCTs in certificates.
* Release 0.21.3 (2023-07-05)
- Added `with_crls` function to `AllowAnyAuthenticatedClient` and
`AllowAnyAnonymousOrAuthenticatedClient` client certificate verifiers to
@ -120,8 +122,6 @@ obsolete cryptography.
* Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)).
* Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)).
* OCSP stapling by servers.
* SCT stapling by servers.
* SCT verification by clients.
## Possible future features

View File

@ -40,6 +40,11 @@
"EmptyExtensions-ServerHello-TLS12": "",
"Server-JDK11*": "workarounds for oracle engineering quality",
"Client-RejectJDK11DowngradeRandom": "",
"SendUnsolicitedSCTOnCertificate-TLS13": "SCT stapling not supported",
"SignedCertificateTimestampListEmpty-Client-*": "",
"SignedCertificateTimestampListEmptySCT-Client-*": "",
"SendSCTListOnResume-TLS-TLS12": "",
"IgnoreExtensionsOnIntermediates-TLS13": "assumes SCT support",
"CBCRecordSplitting*": "insane ciphersuites",
"*CBCPadding*": "",
"RSAEphemeralKey": "",
@ -322,7 +327,6 @@
"NegotiatePSKResumption-TLS13": ":PEER_MISBEHAVIOUR:",
"PointFormat-Client-MissingUncompressed": ":PEER_MISBEHAVIOUR:",
"SendUnsolicitedOCSPOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
"SendUnsolicitedSCTOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
"UnsolicitedServerNameAck-TLS-TLS12": ":PEER_MISBEHAVIOUR:",
"UnsolicitedServerNameAck-TLS-TLS13": ":PEER_MISBEHAVIOUR:",
"TicketSessionIDLength-33-TLS-TLS12": ":BAD_HANDSHAKE_MSG:",
@ -332,10 +336,6 @@
"Ed25519DefaultDisable-NoAccept": ":PEER_MISBEHAVIOUR:",
"SendUnknownExtensionOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
"SendDuplicateExtensionsOnCerts-TLS13": ":PEER_MISBEHAVIOUR:",
"SignedCertificateTimestampListEmpty-Client-TLS-TLS12": ":PEER_MISBEHAVIOUR:",
"SignedCertificateTimestampListEmpty-Client-TLS-TLS13": ":PEER_MISBEHAVIOUR:",
"SignedCertificateTimestampListEmptySCT-Client-TLS-TLS12": ":PEER_MISBEHAVIOUR:",
"SignedCertificateTimestampListEmptySCT-Client-TLS-TLS13": ":PEER_MISBEHAVIOUR:",
"EMS-Forbidden-TLS13": ":PEER_MISBEHAVIOUR:",
"Unclean-Shutdown": ":CLOSE_WITHOUT_CLOSE_NOTIFY:",
"SendExtensionOnClientCertificate-TLS13": ":PEER_MISBEHAVIOUR:",

View File

@ -344,7 +344,6 @@ mod danger {
_end_entity: &rustls::Certificate,
_intermediates: &[rustls::Certificate],
_server_name: &rustls::ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp: &[u8],
_now: std::time::SystemTime,
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {

View File

@ -622,7 +622,7 @@ fn make_config(args: &Args) -> Arc<rustls::ServerConfig> {
.with_protocol_versions(&versions)
.expect("inconsistent cipher-suites/versions specified")
.with_client_cert_verifier(client_auth)
.with_single_cert_with_ocsp_and_sct(certs, privkey, ocsp, vec![])
.with_single_cert_with_ocsp(certs, privkey, ocsp)
.expect("bad certificates/private key");
config.key_log = Arc::new(rustls::KeyLogFile::new());

View File

@ -18,7 +18,6 @@ rustversion = { version = "1.0.6", optional = true }
[dependencies]
log = { version = "0.4.4", optional = true }
ring = "0.16.20"
sct = "0.7.0"
webpki = { package = "rustls-webpki", version = "0.101.0", features = ["alloc", "std"] }
[features]

View File

@ -50,7 +50,6 @@ struct Options {
check_close_notify: bool,
host_name: String,
use_sni: bool,
send_sct: bool,
key_file: String,
cert_file: String,
protocols: Vec<String>,
@ -60,7 +59,6 @@ struct Options {
min_version: Option<ProtocolVersion>,
max_version: Option<ProtocolVersion>,
server_ocsp_response: Vec<u8>,
server_sct_list: Vec<u8>,
use_signing_scheme: u16,
curves: Option<Vec<u16>>,
export_keying_material: usize,
@ -91,7 +89,6 @@ impl Options {
resume_with_tickets_disabled: false,
host_name: "example.com".to_string(),
use_sni: false,
send_sct: false,
queue_data: false,
queue_data_on_resume: false,
only_write_one_byte_after_handshake: false,
@ -109,7 +106,6 @@ impl Options {
min_version: None,
max_version: None,
server_ocsp_response: vec![],
server_sct_list: vec![],
use_signing_scheme: 0,
curves: None,
export_keying_material: 0,
@ -215,9 +211,7 @@ impl server::ClientCertVerifier for DummyClientAuth {
}
}
struct DummyServerAuth {
send_sct: bool,
}
struct DummyServerAuth {}
impl client::ServerCertVerifier for DummyServerAuth {
fn verify_server_cert(
@ -225,16 +219,11 @@ impl client::ServerCertVerifier for DummyServerAuth {
_end_entity: &Certificate,
_certs: &[Certificate],
_hostname: &ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp: &[u8],
_now: SystemTime,
) -> Result<client::ServerCertVerified, Error> {
Ok(client::ServerCertVerified::assertion())
}
fn request_scts(&self) -> bool {
self.send_sct
}
}
struct FixedSignatureSchemeSigningKey {
@ -418,12 +407,7 @@ fn make_server_cfg(opts: &Options) -> Arc<ServerConfig> {
.with_protocol_versions(&opts.supported_versions())
.unwrap()
.with_client_cert_verifier(client_auth)
.with_single_cert_with_ocsp_and_sct(
cert.clone(),
key,
opts.server_ocsp_response.clone(),
opts.server_sct_list.clone(),
)
.with_single_cert_with_ocsp(cert.clone(), key, opts.server_ocsp_response.clone())
.unwrap();
cfg.session_storage = ServerCacheWithResumptionDelay::new(opts.resumption_delay);
@ -538,9 +522,7 @@ fn make_client_cfg(opts: &Options) -> Arc<ClientConfig> {
.with_kx_groups(&kx_groups)
.with_protocol_versions(&opts.supported_versions())
.expect("inconsistent settings")
.with_custom_certificate_verifier(Arc::new(DummyServerAuth {
send_sct: opts.send_sct,
}));
.with_custom_certificate_verifier(Arc::new(DummyServerAuth {}));
let mut cfg = if !opts.cert_file.is_empty() && !opts.key_file.is_empty() {
let cert = load_cert(&opts.cert_file);
@ -991,6 +973,7 @@ fn main() {
"-on-resume-expect-no-offer-early-data" |
"-key-update" | //< we could implement an API for this
"-expect-tls13-downgrade" |
"-enable-signed-cert-timestamps" |
"-expect-session-id" => {
println!("not checking {}; NYI", arg);
}
@ -1020,16 +1003,6 @@ fn main() {
opts.server_ocsp_response = BASE64_STANDARD.decode(args.remove(0).as_bytes())
.expect("invalid base64");
}
"-signed-cert-timestamps" => {
opts.server_sct_list = BASE64_STANDARD.decode(args.remove(0).as_bytes())
.expect("invalid base64");
if opts.server_sct_list.len() == 2 &&
opts.server_sct_list[0] == 0x00 &&
opts.server_sct_list[1] == 0x00 {
quit(":INVALID_SCT_LIST:");
}
}
"-select-alpn" => {
opts.protocols.push(args.remove(0));
}
@ -1065,9 +1038,6 @@ fn main() {
"-use-null-client-ca-list" => {
opts.offer_no_client_cas = true;
}
"-enable-signed-cert-timestamps" => {
opts.send_sct = true;
}
"-enable-early-data" => {
opts.tickets = false;
opts.enable_early_data = true;
@ -1200,6 +1170,7 @@ fn main() {
"-wpa-202304" |
"-srtp-profiles" |
"-permute-extensions" |
"-signed-cert-timestamps" |
"-on-initial-expect-peer-cert-file" => {
println!("NYI option {:?}", arg);
process::exit(BOGO_NACK);

View File

@ -4,27 +4,26 @@ use crate::error::Error;
use crate::key_log::NoKeyLog;
use crate::kx::SupportedKxGroup;
use crate::suites::SupportedCipherSuite;
use crate::verify::{self, CertificateTransparencyPolicy};
use crate::verify;
use crate::{anchors, key, versions};
use super::client_conn::Resumption;
use std::marker::PhantomData;
use std::sync::Arc;
use std::time::SystemTime;
impl ConfigBuilder<ClientConfig, WantsVerifier> {
/// Choose how to verify server certificates.
pub fn with_root_certificates(
self,
root_store: anchors::RootCertStore,
) -> ConfigBuilder<ClientConfig, WantsTransparencyPolicyOrClientCert> {
) -> ConfigBuilder<ClientConfig, WantsClientCert> {
ConfigBuilder {
state: WantsTransparencyPolicyOrClientCert {
state: WantsClientCert {
cipher_suites: self.state.cipher_suites,
kx_groups: self.state.kx_groups,
versions: self.state.versions,
root_store,
verifier: Arc::new(verify::WebPkiVerifier::new(root_store)),
},
side: PhantomData,
}
@ -48,90 +47,6 @@ impl ConfigBuilder<ClientConfig, WantsVerifier> {
}
}
/// A config builder state where the caller needs to supply a certificate transparency policy or
/// client certificate resolver.
///
/// In this state, the caller can optionally enable certificate transparency, or ignore CT and
/// invoke one of the methods related to client certificates (as in the [`WantsClientCert`] state).
///
/// For more information, see the [`ConfigBuilder`] documentation.
#[derive(Clone, Debug)]
pub struct WantsTransparencyPolicyOrClientCert {
cipher_suites: Vec<SupportedCipherSuite>,
kx_groups: Vec<&'static SupportedKxGroup>,
versions: versions::EnabledVersions,
root_store: anchors::RootCertStore,
}
impl ConfigBuilder<ClientConfig, WantsTransparencyPolicyOrClientCert> {
/// Set Certificate Transparency logs to use for server certificate validation.
///
/// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or
/// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will
/// be validated against the configured CT logs until the deadline expires. After the deadline,
/// certificates will no longer be validated, and a warning message will be logged. The deadline
/// may vary depending on how often you deploy builds with updated dependencies.
pub fn with_certificate_transparency_logs(
self,
logs: &'static [&'static sct::Log],
validation_deadline: SystemTime,
) -> ConfigBuilder<ClientConfig, WantsClientCert> {
self.with_logs(Some(CertificateTransparencyPolicy::new(
logs,
validation_deadline,
)))
}
/// Sets a single certificate chain and matching private key for use
/// in client authentication.
///
/// `cert_chain` is a vector of DER-encoded certificates.
/// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key.
///
/// This function fails if `key_der` is invalid.
pub fn with_single_cert(
self,
cert_chain: Vec<key::Certificate>,
key_der: key::PrivateKey,
) -> Result<ClientConfig, Error> {
self.with_logs(None)
.with_single_cert(cert_chain, key_der)
}
/// Do not support client auth.
pub fn with_no_client_auth(self) -> ClientConfig {
self.with_logs(None)
.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {}))
}
/// Sets a custom [`ResolvesClientCert`].
pub fn with_client_cert_resolver(
self,
client_auth_cert_resolver: Arc<dyn ResolvesClientCert>,
) -> ClientConfig {
self.with_logs(None)
.with_client_cert_resolver(client_auth_cert_resolver)
}
fn with_logs(
self,
ct_policy: Option<CertificateTransparencyPolicy>,
) -> ConfigBuilder<ClientConfig, WantsClientCert> {
ConfigBuilder {
state: WantsClientCert {
cipher_suites: self.state.cipher_suites,
kx_groups: self.state.kx_groups,
versions: self.state.versions,
verifier: Arc::new(verify::WebPkiVerifier::new(
self.state.root_store,
ct_policy,
)),
},
side: PhantomData,
}
}
}
/// A config builder state where the caller needs to supply whether and how to provide a client
/// certificate.
///

View File

@ -2,8 +2,8 @@ use super::ResolvesClientCert;
#[cfg(feature = "logging")]
use crate::log::{debug, trace};
use crate::msgs::enums::ExtensionType;
use crate::msgs::handshake::ServerExtension;
use crate::msgs::handshake::{CertificatePayload, DistinguishedName};
use crate::msgs::handshake::{Sct, ServerExtension};
use crate::{sign, SignatureScheme};
use std::sync::Arc;
@ -12,29 +12,15 @@ use std::sync::Arc;
pub(super) struct ServerCertDetails {
pub(super) cert_chain: CertificatePayload,
pub(super) ocsp_response: Vec<u8>,
pub(super) scts: Option<Vec<Sct>>,
}
impl ServerCertDetails {
pub(super) fn new(
cert_chain: CertificatePayload,
ocsp_response: Vec<u8>,
scts: Option<Vec<Sct>>,
) -> Self {
pub(super) fn new(cert_chain: CertificatePayload, ocsp_response: Vec<u8>) -> Self {
Self {
cert_chain,
ocsp_response,
scts,
}
}
pub(super) fn scts(&self) -> impl Iterator<Item = &[u8]> {
self.scts
.as_deref()
.unwrap_or(&[])
.iter()
.map(|payload| payload.as_ref())
}
}
pub(super) struct ClientHelloDetails {
@ -48,11 +34,6 @@ impl ClientHelloDetails {
}
}
pub(super) fn server_may_send_sct_list(&self) -> bool {
self.sent_extensions
.contains(&ExtensionType::SCT)
}
pub(super) fn server_sent_unsolicited_extensions(
&self,
received_exts: &[ServerExtension],

View File

@ -13,7 +13,7 @@ use crate::msgs::base::Payload;
use crate::msgs::enums::{Compression, ExtensionType};
use crate::msgs::enums::{ECPointFormat, PSKKeyExchangeMode};
use crate::msgs::handshake::ConvertProtocolNameList;
use crate::msgs::handshake::{CertificateStatusRequest, ClientSessionTicket, Sct};
use crate::msgs::handshake::{CertificateStatusRequest, ClientSessionTicket};
use crate::msgs::handshake::{ClientExtension, HasServerExtensions};
use crate::msgs::handshake::{ClientHelloPayload, HandshakeMessagePayload, HandshakePayload};
use crate::msgs::handshake::{HelloRetryRequest, KeyShareEntry};
@ -141,13 +141,11 @@ pub(super) fn start_handshake(
None => SessionId::random()?,
};
let may_send_sct_list = config.verifier.request_scts();
Ok(emit_client_hello_for_retry(
transcript_buffer,
None,
key_share,
extra_exts,
may_send_sct_list,
None,
ClientHelloInput {
config,
@ -194,7 +192,6 @@ fn emit_client_hello_for_retry(
retryreq: Option<&HelloRetryRequest>,
key_share: Option<kx::KeyExchange>,
extra_exts: Vec<ClientExtension>,
may_send_sct_list: bool,
suite: Option<SupportedCipherSuite>,
mut input: ClientHelloInput,
cx: &mut ClientContext<'_>,
@ -238,10 +235,6 @@ fn emit_client_hello_for_retry(
exts.push(ClientExtension::make_sni(sni_name));
}
if may_send_sct_list {
exts.push(ClientExtension::SignedCertificateTimestampRequest);
}
if let Some(key_share) = &key_share {
debug_assert!(support_tls13);
let key_share = KeyShareEntry::new(key_share.group(), key_share.pubkey.as_ref());
@ -479,13 +472,6 @@ pub(super) fn process_alpn_protocol(
Ok(())
}
pub(super) fn sct_list_is_invalid(scts: &[Sct]) -> bool {
scts.is_empty()
|| scts
.iter()
.any(|sct| sct.as_ref().is_empty())
}
impl State<ClientConnectionData> for ExpectServerHello {
fn handle(mut self: Box<Self>, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError {
let server_hello =
@ -800,12 +786,6 @@ impl ExpectServerHelloOrHelloRetryRequest {
cx.data.early_data.rejected();
}
let may_send_sct_list = self
.next
.input
.hello
.server_may_send_sct_list();
let key_share = match req_group {
Some(group) if group != offered_key_share.group() => {
let group = kx::KeyExchange::choose(group, &config.kx_groups).ok_or_else(|| {
@ -824,7 +804,6 @@ impl ExpectServerHelloOrHelloRetryRequest {
Some(hrr),
Some(key_share),
self.extra_exts,
may_send_sct_list,
Some(cs),
self.next.input,
cx,

View File

@ -12,7 +12,7 @@ use crate::msgs::base::{Payload, PayloadU8};
use crate::msgs::ccs::ChangeCipherSpecPayload;
use crate::msgs::codec::Codec;
use crate::msgs::handshake::{
CertificatePayload, HandshakeMessagePayload, HandshakePayload, NewSessionTicketPayload, Sct,
CertificatePayload, HandshakeMessagePayload, HandshakePayload, NewSessionTicketPayload,
ServerECDHParams, SessionId,
};
use crate::msgs::message::{Message, MessagePayload};
@ -102,18 +102,6 @@ mod server_hello {
debug!("Server may staple OCSP response");
}
// Save any sent SCTs for verification against the certificate.
let server_cert_sct_list = if let Some(sct_list) = server_hello.get_sct_list() {
debug!("Server sent {:?} SCTs", sct_list.len());
if hs::sct_list_is_invalid(sct_list) {
return Err(PeerMisbehaved::InvalidSctList.into());
}
Some(sct_list.to_owned())
} else {
None
};
// See if we're successfully resuming.
if let Some(ref resuming) = self.resuming_session {
if resuming.session_id == server_hello.session_id {
@ -187,7 +175,6 @@ mod server_hello {
suite,
may_send_cert_status,
must_issue_new_ticket,
server_cert_sct_list,
}))
}
}
@ -204,7 +191,6 @@ struct ExpectCertificate {
pub(super) suite: &'static Tls12CipherSuite,
may_send_cert_status: bool,
must_issue_new_ticket: bool,
server_cert_sct_list: Option<Vec<Sct>>,
}
impl State<ClientConnectionData> for ExpectCertificate {
@ -230,13 +216,11 @@ impl State<ClientConnectionData> for ExpectCertificate {
using_ems: self.using_ems,
transcript: self.transcript,
suite: self.suite,
server_cert_sct_list: self.server_cert_sct_list,
server_cert_chain,
must_issue_new_ticket: self.must_issue_new_ticket,
}))
} else {
let server_cert =
ServerCertDetails::new(server_cert_chain, vec![], self.server_cert_sct_list);
let server_cert = ServerCertDetails::new(server_cert_chain, vec![]);
Ok(Box::new(ExpectServerKx {
config: self.config,
@ -263,7 +247,6 @@ struct ExpectCertificateStatusOrServerKx {
using_ems: bool,
transcript: HandshakeHash,
suite: &'static Tls12CipherSuite,
server_cert_sct_list: Option<Vec<Sct>>,
server_cert_chain: CertificatePayload,
must_issue_new_ticket: bool,
}
@ -287,11 +270,7 @@ impl State<ClientConnectionData> for ExpectCertificateStatusOrServerKx {
using_ems: self.using_ems,
transcript: self.transcript,
suite: self.suite,
server_cert: ServerCertDetails::new(
self.server_cert_chain,
vec![],
self.server_cert_sct_list,
),
server_cert: ServerCertDetails::new(self.server_cert_chain, vec![]),
must_issue_new_ticket: self.must_issue_new_ticket,
})
.handle(cx, m),
@ -311,7 +290,6 @@ impl State<ClientConnectionData> for ExpectCertificateStatusOrServerKx {
using_ems: self.using_ems,
transcript: self.transcript,
suite: self.suite,
server_cert_sct_list: self.server_cert_sct_list,
server_cert_chain: self.server_cert_chain,
must_issue_new_ticket: self.must_issue_new_ticket,
})
@ -337,7 +315,6 @@ struct ExpectCertificateStatus {
using_ems: bool,
transcript: HandshakeHash,
suite: &'static Tls12CipherSuite,
server_cert_sct_list: Option<Vec<Sct>>,
server_cert_chain: CertificatePayload,
must_issue_new_ticket: bool,
}
@ -361,11 +338,7 @@ impl State<ClientConnectionData> for ExpectCertificateStatus {
&server_cert_ocsp_response
);
let server_cert = ServerCertDetails::new(
self.server_cert_chain,
server_cert_ocsp_response,
self.server_cert_sct_list,
);
let server_cert = ServerCertDetails::new(self.server_cert_chain, server_cert_ocsp_response);
Ok(Box::new(ExpectServerKx {
config: self.config,
@ -741,7 +714,6 @@ impl State<ClientConnectionData> for ExpectServerDone {
end_entity,
intermediates,
&st.server_name,
&mut st.server_cert.scts(),
&st.server_cert.ocsp_response,
now,
)

View File

@ -448,7 +448,6 @@ impl State<ClientConnectionData> for ExpectEncryptedExtensions {
suite: self.suite,
transcript: self.transcript,
key_schedule: self.key_schedule,
may_send_sct_list: self.hello.server_may_send_sct_list(),
}))
}
}
@ -461,7 +460,6 @@ struct ExpectCertificateOrCertReq {
suite: &'static Tls13CipherSuite,
transcript: HandshakeHash,
key_schedule: KeyScheduleHandshake,
may_send_sct_list: bool,
}
impl State<ClientConnectionData> for ExpectCertificateOrCertReq {
@ -481,7 +479,6 @@ impl State<ClientConnectionData> for ExpectCertificateOrCertReq {
suite: self.suite,
transcript: self.transcript,
key_schedule: self.key_schedule,
may_send_sct_list: self.may_send_sct_list,
client_auth: None,
})
.handle(cx, m),
@ -499,7 +496,6 @@ impl State<ClientConnectionData> for ExpectCertificateOrCertReq {
suite: self.suite,
transcript: self.transcript,
key_schedule: self.key_schedule,
may_send_sct_list: self.may_send_sct_list,
})
.handle(cx, m),
payload => Err(inappropriate_handshake_message(
@ -524,7 +520,6 @@ struct ExpectCertificateRequest {
suite: &'static Tls13CipherSuite,
transcript: HandshakeHash,
key_schedule: KeyScheduleHandshake,
may_send_sct_list: bool,
}
impl State<ClientConnectionData> for ExpectCertificateRequest {
@ -582,7 +577,6 @@ impl State<ClientConnectionData> for ExpectCertificateRequest {
suite: self.suite,
transcript: self.transcript,
key_schedule: self.key_schedule,
may_send_sct_list: self.may_send_sct_list,
client_auth: Some(client_auth),
}))
}
@ -595,7 +589,6 @@ struct ExpectCertificate {
suite: &'static Tls13CipherSuite,
transcript: HandshakeHash,
key_schedule: KeyScheduleHandshake,
may_send_sct_list: bool,
client_auth: Option<ClientAuthDetails>,
}
@ -625,23 +618,8 @@ impl State<ClientConnectionData> for ExpectCertificate {
));
}
let server_cert = ServerCertDetails::new(
cert_chain.convert(),
cert_chain.get_end_entity_ocsp(),
cert_chain
.get_end_entity_scts()
.map(|scts| scts.to_vec()),
);
if let Some(sct_list) = server_cert.scts.as_ref() {
if hs::sct_list_is_invalid(sct_list) {
return Err(PeerMisbehaved::InvalidSctList.into());
}
if !self.may_send_sct_list {
return Err(PeerMisbehaved::UnsolicitedSctList.into());
}
}
let server_cert =
ServerCertDetails::new(cert_chain.convert(), cert_chain.get_end_entity_ocsp());
Ok(Box::new(ExpectCertificateVerify {
config: self.config,
@ -692,7 +670,6 @@ impl State<ClientConnectionData> for ExpectCertificateVerify {
end_entity,
intermediates,
&self.server_name,
&mut self.server_cert.scts(),
&self.server_cert.ocsp_response,
now,
)

View File

@ -66,9 +66,6 @@ pub enum Error {
/// implementation.
InvalidCertificate(CertificateError),
/// The presented SCT(s) were invalid.
InvalidSct(sct::Error),
/// A provided certificate revocation list (CRL) was invalid.
InvalidCertRevocationList(CertRevocationListError),
@ -188,7 +185,6 @@ pub enum PeerMisbehaved {
IncorrectBinder,
InvalidMaxEarlyDataSize,
InvalidKeyShare,
InvalidSctList,
KeyEpochWithPendingFragment,
KeyUpdateReceivedInQuicConnection,
MessageInterleavedWithHandshakeMessage,
@ -525,7 +521,6 @@ impl fmt::Display for Error {
Self::PeerSentOversizedRecord => write!(f, "peer sent excess record size"),
Self::HandshakeNotComplete => write!(f, "handshake not complete"),
Self::NoApplicationProtocol => write!(f, "peer doesn't support any known protocol"),
Self::InvalidSct(ref err) => write!(f, "invalid certificate timestamp: {:?}", err),
Self::FailedToGetCurrentTime => write!(f, "failed to get current time"),
Self::FailedToGetRandomBytes => write!(f, "failed to get random bytes"),
Self::BadMaxFragmentSize => {
@ -653,7 +648,6 @@ mod tests {
#[test]
fn smoke() {
use crate::enums::{AlertDescription, ContentType, HandshakeType};
use sct;
let all = vec![
Error::InappropriateMessage {
@ -671,7 +665,6 @@ mod tests {
super::PeerMisbehaved::UnsolicitedCertExtension.into(),
Error::AlertReceived(AlertDescription::ExportRestriction),
super::CertificateError::Expired.into(),
Error::InvalidSct(sct::Error::MalformedSct),
Error::General("undocumented error".to_string()),
Error::FailedToGetCurrentTime,
Error::FailedToGetRandomBytes,

View File

@ -25,8 +25,6 @@
//! * Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)).
//! * Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)).
//! * OCSP stapling by servers.
//! * SCT stapling by servers.
//! * SCT verification by clients.
//!
//! ## Possible future features
//!
@ -417,7 +415,7 @@ pub mod client {
mod tls13;
pub use crate::dns_name::InvalidDnsNameError;
pub use builder::{WantsClientCert, WantsTransparencyPolicyOrClientCert};
pub use builder::WantsClientCert;
pub use client_conn::{
ClientConfig, ClientConnection, ClientConnectionData, ClientSessionStore,
ResolvesClientCert, Resumption, ServerName, Tls12Resumption, WriteEarlyData,
@ -426,9 +424,8 @@ pub mod client {
#[cfg(feature = "dangerous_configuration")]
pub use crate::verify::{
verify_server_cert_signed_by_trust_anchor, verify_server_name,
CertificateTransparencyPolicy, 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;

View File

@ -516,15 +516,6 @@ impl CertificateStatusRequest {
}
}
// ---
// SCTs
wrapped_payload!(Sct, PayloadU16,);
impl TlsListElement for Sct {
const SIZE_LEN: ListLength = ListLength::U16;
}
// ---
impl TlsListElement for PSKKeyExchangeMode {
@ -554,7 +545,6 @@ pub enum ClientExtension {
Cookie(PayloadU16),
ExtendedMasterSecretRequest,
CertificateStatusRequest(CertificateStatusRequest),
SignedCertificateTimestampRequest,
TransportParameters(Vec<u8>),
TransportParametersDraft(Vec<u8>),
EarlyData,
@ -577,7 +567,6 @@ impl ClientExtension {
Self::Cookie(_) => ExtensionType::Cookie,
Self::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret,
Self::CertificateStatusRequest(_) => ExtensionType::StatusRequest,
Self::SignedCertificateTimestampRequest => ExtensionType::SCT,
Self::TransportParameters(_) => ExtensionType::TransportParameters,
Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft,
Self::EarlyData => ExtensionType::EarlyData,
@ -598,7 +587,6 @@ impl Codec for ClientExtension {
Self::ServerName(ref r) => r.encode(&mut sub),
Self::SessionTicket(ClientSessionTicket::Request)
| Self::ExtendedMasterSecretRequest
| Self::SignedCertificateTimestampRequest
| Self::EarlyData => {}
Self::SessionTicket(ClientSessionTicket::Offer(ref r)) => r.encode(&mut sub),
Self::Protocols(ref r) => r.encode(&mut sub),
@ -649,7 +637,6 @@ impl Codec for ClientExtension {
let csr = CertificateStatusRequest::read(&mut sub)?;
Self::CertificateStatusRequest(csr)
}
ExtensionType::SCT if !sub.any_left() => Self::SignedCertificateTimestampRequest,
ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()),
ExtensionType::TransportParametersDraft => {
Self::TransportParametersDraft(sub.rest().to_vec())
@ -707,7 +694,6 @@ pub enum ServerExtension {
PresharedKey(u16),
ExtendedMasterSecretAck,
CertificateStatusAck,
SignedCertificateTimestamp(Vec<Sct>),
SupportedVersions(ProtocolVersion),
TransportParameters(Vec<u8>),
TransportParametersDraft(Vec<u8>),
@ -727,7 +713,6 @@ impl ServerExtension {
Self::PresharedKey(_) => ExtensionType::PreSharedKey,
Self::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret,
Self::CertificateStatusAck => ExtensionType::StatusRequest,
Self::SignedCertificateTimestamp(_) => ExtensionType::SCT,
Self::SupportedVersions(_) => ExtensionType::SupportedVersions,
Self::TransportParameters(_) => ExtensionType::TransportParameters,
Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft,
@ -753,7 +738,6 @@ impl Codec for ServerExtension {
Self::Protocols(ref r) => r.encode(&mut sub),
Self::KeyShare(ref r) => r.encode(&mut sub),
Self::PresharedKey(r) => r.encode(&mut sub),
Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub),
Self::SupportedVersions(ref r) => r.encode(&mut sub),
Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => {
sub.extend_from_slice(r);
@ -780,7 +764,6 @@ impl Codec for ServerExtension {
ExtensionType::KeyShare => Self::KeyShare(KeyShareEntry::read(&mut sub)?),
ExtensionType::PreSharedKey => Self::PresharedKey(u16::read(&mut sub)?),
ExtensionType::ExtendedMasterSecret => Self::ExtendedMasterSecretAck,
ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?),
ExtensionType::SupportedVersions => {
Self::SupportedVersions(ProtocolVersion::read(&mut sub)?)
}
@ -806,11 +789,6 @@ impl ServerExtension {
let empty = Vec::new();
Self::RenegotiationInfo(PayloadU8::new(empty))
}
pub fn make_sct(sctl: Vec<u8>) -> Self {
let scts = Vec::read_bytes(&sctl).expect("invalid SCT list");
Self::SignedCertificateTimestamp(scts)
}
}
#[derive(Debug)]
@ -1264,14 +1242,6 @@ impl ServerHelloPayload {
.is_some()
}
pub fn get_sct_list(&self) -> Option<&[Sct]> {
let ext = self.find_extension(ExtensionType::SCT)?;
match *ext {
ServerExtension::SignedCertificateTimestamp(ref sctl) => Some(sctl),
_ => None,
}
}
pub fn get_supported_versions(&self) -> Option<ProtocolVersion> {
let ext = self.find_extension(ExtensionType::SupportedVersions)?;
match *ext {
@ -1294,7 +1264,6 @@ impl TlsListElement for key::Certificate {
#[derive(Debug)]
pub enum CertificateExtension {
CertificateStatus(CertificateStatus),
SignedCertificateTimestamp(Vec<Sct>),
Unknown(UnknownExtension),
}
@ -1302,29 +1271,16 @@ impl CertificateExtension {
pub fn get_type(&self) -> ExtensionType {
match *self {
Self::CertificateStatus(_) => ExtensionType::StatusRequest,
Self::SignedCertificateTimestamp(_) => ExtensionType::SCT,
Self::Unknown(ref r) => r.typ,
}
}
pub fn make_sct(sct_list: Vec<u8>) -> Self {
let sctl = Vec::read_bytes(&sct_list).expect("invalid SCT list");
Self::SignedCertificateTimestamp(sctl)
}
pub fn get_cert_status(&self) -> Option<&Vec<u8>> {
match *self {
Self::CertificateStatus(ref cs) => Some(&cs.ocsp_response.0),
_ => None,
}
}
pub fn get_sct_list(&self) -> Option<&[Sct]> {
match *self {
Self::SignedCertificateTimestamp(ref sctl) => Some(sctl),
_ => None,
}
}
}
impl Codec for CertificateExtension {
@ -1334,7 +1290,6 @@ impl Codec for CertificateExtension {
let mut sub: Vec<u8> = Vec::new();
match *self {
Self::CertificateStatus(ref r) => r.encode(&mut sub),
Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub),
Self::Unknown(ref r) => r.encode(&mut sub),
}
@ -1352,7 +1307,6 @@ impl Codec for CertificateExtension {
let st = CertificateStatus::read(&mut sub)?;
Self::CertificateStatus(st)
}
ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?),
_ => Self::Unknown(UnknownExtension::read(typ, &mut sub)),
};
@ -1409,9 +1363,9 @@ impl CertificateEntry {
}
pub fn has_unknown_extension(&self) -> bool {
self.exts.iter().any(|ext| {
ext.get_type() != ExtensionType::StatusRequest && ext.get_type() != ExtensionType::SCT
})
self.exts
.iter()
.any(|ext| ext.get_type() != ExtensionType::StatusRequest)
}
pub fn get_ocsp_response(&self) -> Option<&Vec<u8>> {
@ -1420,13 +1374,6 @@ impl CertificateEntry {
.find(|ext| ext.get_type() == ExtensionType::StatusRequest)
.and_then(CertificateExtension::get_cert_status)
}
pub fn get_scts(&self) -> Option<&[Sct]> {
self.exts
.iter()
.find(|ext| ext.get_type() == ExtensionType::SCT)
.and_then(CertificateExtension::get_sct_list)
}
}
impl TlsListElement for CertificateEntry {
@ -1499,12 +1446,6 @@ impl CertificatePayloadTLS13 {
.unwrap_or_default()
}
pub fn get_end_entity_scts(&self) -> Option<&[Sct]> {
self.entries
.first()
.and_then(CertificateEntry::get_scts)
}
pub fn convert(&self) -> CertificatePayload {
let mut ret = Vec::new();
for entry in &self.entries {

View File

@ -15,7 +15,7 @@ use crate::msgs::handshake::{
ECParameters, HandshakeMessagePayload, HandshakePayload, HasServerExtensions,
HelloRetryExtension, HelloRetryRequest, KeyShareEntry, NewSessionTicketExtension,
NewSessionTicketPayload, NewSessionTicketPayloadTLS13, PresharedKeyBinder,
PresharedKeyIdentity, PresharedKeyOffer, ProtocolName, Random, Sct, ServerECDHParams,
PresharedKeyIdentity, PresharedKeyOffer, ProtocolName, Random, ServerECDHParams,
ServerExtension, ServerHelloPayload, ServerKeyExchangePayload, SessionId, UnknownExtension,
};
use crate::verify::DigitallySignedStruct;
@ -131,7 +131,7 @@ fn refuses_server_ext_with_unparsed_bytes() {
#[test]
fn refuses_certificate_ext_with_unparsed_bytes() {
let bytes = [0x00u8, 0x12, 0x00, 0x03, 0x00, 0x00, 0x01];
let bytes = [0x00u8, 0x05, 0x00, 0x03, 0x00, 0x00, 0x01];
let mut rd = Reader::init(&bytes);
assert!(CertificateExtension::read(&mut rd).is_err());
}
@ -385,7 +385,6 @@ fn get_sample_clienthellopayload() -> ClientHelloPayload {
ClientExtension::Cookie(PayloadU16(vec![1, 2, 3])),
ClientExtension::ExtendedMasterSecretRequest,
ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()),
ClientExtension::SignedCertificateTimestampRequest,
ClientExtension::TransportParameters(vec![1, 2, 3]),
ClientExtension::Unknown(UnknownExtension {
typ: ExtensionType::Unknown(12345),
@ -704,11 +703,6 @@ fn server_get_ecpoints_extension() {
});
}
#[test]
fn server_get_sct_list() {
test_server_extension_getter(ExtensionType::SCT, |shp| shp.get_sct_list().is_some());
}
#[test]
fn server_get_supported_versions() {
test_server_extension_getter(ExtensionType::SupportedVersions, |shp| {
@ -742,11 +736,6 @@ fn certentry_get_ocsp_response() {
});
}
#[test]
fn certentry_get_scts() {
test_cert_extension_getter(ExtensionType::SCT, |ce| ce.get_scts().is_some());
}
fn get_sample_serverhellopayload() -> ServerHelloPayload {
ServerHelloPayload {
legacy_version: ProtocolVersion::TLSv1_2,
@ -764,7 +753,6 @@ fn get_sample_serverhellopayload() -> ServerHelloPayload {
ServerExtension::PresharedKey(3),
ServerExtension::ExtendedMasterSecretAck,
ServerExtension::CertificateStatusAck,
ServerExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]),
ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_2),
ServerExtension::TransportParameters(vec![1, 2, 3]),
ServerExtension::Unknown(UnknownExtension {
@ -811,7 +799,6 @@ fn get_sample_certificatepayloadtls13() -> CertificatePayloadTLS13 {
CertificateExtension::CertificateStatus(CertificateStatus {
ocsp_response: PayloadU24(vec![1, 2, 3]),
}),
CertificateExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]),
CertificateExtension::Unknown(UnknownExtension {
typ: ExtensionType::Unknown(12345),
payload: Payload(vec![1, 2, 3]),

View File

@ -77,19 +77,15 @@ impl ConfigBuilder<ServerConfig, WantsServerCert> {
/// `cert_chain` is a vector of DER-encoded certificates.
/// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key.
/// `ocsp` is a DER-encoded OCSP response. Ignored if zero length.
/// `scts` is an `SignedCertificateTimestampList` encoding (see RFC6962)
/// and is ignored if empty.
///
/// This function fails if `key_der` is invalid.
pub fn with_single_cert_with_ocsp_and_sct(
pub fn with_single_cert_with_ocsp(
self,
cert_chain: Vec<key::Certificate>,
key_der: key::PrivateKey,
ocsp: Vec<u8>,
scts: Vec<u8>,
) -> Result<ServerConfig, Error> {
let resolver =
handy::AlwaysResolvesChain::new_with_extras(cert_chain, &key_der, ocsp, scts)?;
let resolver = handy::AlwaysResolvesChain::new_with_extras(cert_chain, &key_der, ocsp)?;
Ok(self.with_cert_resolver(Arc::new(resolver)))
}

View File

@ -5,7 +5,6 @@ use crate::{key, sign};
pub(super) struct ActiveCertifiedKey<'a> {
key: &'a sign::CertifiedKey,
ocsp: Option<&'a [u8]>,
sct_list: Option<&'a [u8]>,
}
impl<'a> ActiveCertifiedKey<'a> {
@ -13,7 +12,6 @@ impl<'a> ActiveCertifiedKey<'a> {
ActiveCertifiedKey {
key,
ocsp: key.ocsp.as_deref(),
sct_list: key.sct_list.as_deref(),
}
}
@ -33,9 +31,4 @@ impl<'a> ActiveCertifiedKey<'a> {
pub(super) fn get_ocsp(&self) -> Option<&[u8]> {
self.ocsp
}
#[inline]
pub(super) fn get_sct_list(&self) -> Option<&[u8]> {
self.sct_list
}
}

View File

@ -112,7 +112,6 @@ impl AlwaysResolvesChain {
chain: Vec<key::Certificate>,
priv_key: &key::PrivateKey,
ocsp: Vec<u8>,
scts: Vec<u8>,
) -> Result<Self, Error> {
let mut r = Self::new(chain, priv_key)?;
@ -121,9 +120,6 @@ impl AlwaysResolvesChain {
if !ocsp.is_empty() {
cert.ocsp = Some(ocsp);
}
if !scts.is_empty() {
cert.sct_list = Some(scts);
}
}
Ok(r)

View File

@ -67,7 +67,6 @@ impl ExtensionProcessing {
config: &ServerConfig,
cx: &mut ServerContext<'_>,
ocsp_response: &mut Option<&[u8]>,
sct_list: &mut Option<&[u8]>,
hello: &ClientHelloPayload,
resumedata: Option<&persist::ServerSessionValue>,
extra_exts: Vec<ServerExtension>,
@ -156,24 +155,6 @@ impl ExtensionProcessing {
ocsp_response.take();
}
if !for_resume
&& hello
.find_extension(ExtensionType::SCT)
.is_some()
{
if !cx.common.is_tls13() {
// Take the SCT list, if any, so we don't send it later,
// and put it in the legacy extension.
if let Some(sct_list) = sct_list.take() {
self.exts
.push(ServerExtension::make_sct(sct_list.to_vec()));
}
}
} else {
// Throw away any SCT list so we don't send it later.
sct_list.take();
}
self.exts.extend(extra_exts);
Ok(())

View File

@ -193,8 +193,7 @@ mod client_hello {
debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed);
let (mut ocsp_response, mut sct_list) =
(server_key.get_ocsp(), server_key.get_sct_list());
let mut ocsp_response = server_key.get_ocsp();
// If we're not offered a ticket or a potential session ID, allocate a session ID.
if !self.config.session_storage.can_cache() {
@ -211,7 +210,6 @@ mod client_hello {
self.suite,
self.using_ems,
&mut ocsp_response,
&mut sct_list,
client_hello,
None,
&self.randoms,
@ -283,7 +281,6 @@ mod client_hello {
self.suite,
self.using_ems,
&mut None,
&mut None,
client_hello,
Some(&resumedata),
&self.randoms,
@ -339,22 +336,13 @@ mod client_hello {
suite: &'static Tls12CipherSuite,
using_ems: bool,
ocsp_response: &mut Option<&[u8]>,
sct_list: &mut Option<&[u8]>,
hello: &ClientHelloPayload,
resumedata: Option<&persist::ServerSessionValue>,
randoms: &ConnectionRandoms,
extra_exts: Vec<ServerExtension>,
) -> Result<bool, Error> {
let mut ep = hs::ExtensionProcessing::new();
ep.process_common(
config,
cx,
ocsp_response,
sct_list,
hello,
resumedata,
extra_exts,
)?;
ep.process_common(config, cx, ocsp_response, hello, resumedata, extra_exts)?;
ep.process_tls12(config, hello, using_ems);
let sh = Message {

View File

@ -372,14 +372,12 @@ mod client_hello {
emit_fake_ccs(cx.common);
}
let (mut ocsp_response, mut sct_list) =
(server_key.get_ocsp(), server_key.get_sct_list());
let mut ocsp_response = server_key.get_ocsp();
let doing_early_data = emit_encrypted_extensions(
&mut self.transcript,
self.suite,
cx,
&mut ocsp_response,
&mut sct_list,
client_hello,
resumedata.as_ref(),
self.extra_exts,
@ -394,7 +392,6 @@ mod client_hello {
cx.common,
server_key.get_cert(),
ocsp_response,
sct_list,
);
emit_certificate_verify_tls13(
&mut self.transcript,
@ -666,22 +663,13 @@ mod client_hello {
suite: &'static Tls13CipherSuite,
cx: &mut ServerContext<'_>,
ocsp_response: &mut Option<&[u8]>,
sct_list: &mut Option<&[u8]>,
hello: &ClientHelloPayload,
resumedata: Option<&persist::ServerSessionValue>,
extra_exts: Vec<ServerExtension>,
config: &ServerConfig,
) -> Result<EarlyDataDecision, Error> {
let mut ep = hs::ExtensionProcessing::new();
ep.process_common(
config,
cx,
ocsp_response,
sct_list,
hello,
resumedata,
extra_exts,
)?;
ep.process_common(config, cx, ocsp_response, hello, resumedata, extra_exts)?;
let early_data = decide_if_early_data_allowed(cx, hello, resumedata, suite, config);
if early_data == EarlyDataDecision::Accepted {
@ -751,7 +739,6 @@ mod client_hello {
common: &mut CommonState,
cert_chain: &[Certificate],
ocsp_response: Option<&[u8]>,
sct_list: Option<&[u8]>,
) {
let mut cert_entries = vec![];
for cert in cert_chain {
@ -772,13 +759,6 @@ mod client_hello {
.exts
.push(CertificateExtension::CertificateStatus(cst));
}
// Likewise, SCT
if let Some(sct_list) = sct_list {
end_entity_cert
.exts
.push(CertificateExtension::make_sct(sct_list.to_owned()));
}
}
let cert_body = CertificatePayloadTLS13::new(cert_entries);

View File

@ -44,11 +44,6 @@ pub struct CertifiedKey {
/// An optional OCSP response from the certificate issuer,
/// attesting to its continued validity.
pub ocsp: Option<Vec<u8>>,
/// An optional collection of SCTs from CT logs, proving the
/// certificate is included on those logs. This must be
/// a `SignedCertificateTimestampList` encoding; see RFC6962.
pub sct_list: Option<Vec<u8>>,
}
impl CertifiedKey {
@ -61,7 +56,6 @@ impl CertifiedKey {
cert,
key,
ocsp: None,
sct_list: None,
}
}

View File

@ -8,7 +8,7 @@ use crate::error::{
};
use crate::key::{Certificate, ParsedCertificate};
#[cfg(feature = "logging")]
use crate::log::{debug, trace, warn};
use crate::log::trace;
use crate::msgs::base::PayloadU16;
use crate::msgs::codec::{Codec, Reader};
use crate::msgs::handshake::DistinguishedName;
@ -110,16 +110,12 @@ pub trait ServerCertVerifier: Send + Sync {
/// the implementor to handle invalid data. It is recommended that the implementor returns
/// [`Error::InvalidCertificate(CertificateError::BadEncoding)`] when these cases are encountered.
///
/// `scts` contains the Signed Certificate Timestamps (SCTs) the server
/// sent with the end-entity certificate, if any.
///
/// [Certificate]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2
fn verify_server_cert(
&self,
end_entity: &Certificate,
intermediates: &[Certificate],
server_name: &ServerName,
scts: &mut dyn Iterator<Item = &[u8]>,
ocsp_response: &[u8],
now: SystemTime,
) -> Result<ServerCertVerified, Error>;
@ -187,16 +183,6 @@ pub trait ServerCertVerifier: Send + Sync {
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
WebPkiVerifier::verification_schemes()
}
/// Returns `true` if Rustls should ask the server to send SCTs.
///
/// Signed Certificate Timestamps (SCTs) are used for Certificate
/// Transparency validation.
///
/// The default implementation of this function returns true.
fn request_scts(&self) -> bool {
true
}
}
impl fmt::Debug for dyn ServerCertVerifier {
@ -392,7 +378,6 @@ impl ServerCertVerifier for WebPkiVerifier {
end_entity: &Certificate,
intermediates: &[Certificate],
server_name: &ServerName,
scts: &mut dyn Iterator<Item = &[u8]>,
ocsp_response: &[u8],
now: SystemTime,
) -> Result<ServerCertVerified, Error> {
@ -400,10 +385,6 @@ impl ServerCertVerifier for WebPkiVerifier {
verify_server_cert_signed_by_trust_anchor(&cert, &self.roots, intermediates, now)?;
if let Some(policy) = &self.ct_policy {
policy.verify(end_entity, now, scts)?;
}
if !ocsp_response.is_empty() {
trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec());
}
@ -418,7 +399,6 @@ impl ServerCertVerifier for WebPkiVerifier {
#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))]
pub struct WebPkiVerifier {
roots: RootCertStore,
ct_policy: Option<CertificateTransparencyPolicy>,
}
#[allow(unreachable_pub)]
@ -426,12 +406,8 @@ impl WebPkiVerifier {
/// Constructs a new `WebPkiVerifier`.
///
/// `roots` is the set of trust anchors to trust for issuing server certs.
///
/// `ct_logs` is the list of logs that are trusted for Certificate
/// Transparency. Currently CT log enforcement is opportunistic; see
/// <https://github.com/rustls/rustls/issues/479>.
pub fn new(roots: RootCertStore, ct_policy: Option<CertificateTransparencyPolicy>) -> Self {
Self { roots, ct_policy }
pub fn new(roots: RootCertStore) -> Self {
Self { roots }
}
/// Returns the signature verification methods supported by
@ -451,83 +427,6 @@ impl WebPkiVerifier {
}
}
/// Policy for enforcing Certificate Transparency.
///
/// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or
/// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will
/// be validated against the configured CT logs until the deadline expires. After the deadline,
/// certificates will no longer be validated, and a warning message will be logged. The deadline
/// may vary depending on how often you deploy builds with updated dependencies.
#[allow(unreachable_pub)]
#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))]
pub struct CertificateTransparencyPolicy {
logs: &'static [&'static sct::Log<'static>],
validation_deadline: SystemTime,
}
impl CertificateTransparencyPolicy {
/// Create a new policy.
#[allow(unreachable_pub)]
pub fn new(
logs: &'static [&'static sct::Log<'static>],
validation_deadline: SystemTime,
) -> Self {
Self {
logs,
validation_deadline,
}
}
fn verify(
&self,
cert: &Certificate,
now: SystemTime,
scts: &mut dyn Iterator<Item = &[u8]>,
) -> Result<(), Error> {
if self.logs.is_empty() {
return Ok(());
} else if self
.validation_deadline
.duration_since(now)
.is_err()
{
warn!("certificate transparency logs have expired, validation disabled");
return Ok(());
}
let now = unix_time_millis(now)?;
let mut last_sct_error = None;
for sct in scts {
#[cfg_attr(not(feature = "logging"), allow(unused_variables))]
match sct::verify_sct(&cert.0, sct, now, self.logs) {
Ok(index) => {
debug!(
"Valid SCT signed by {} on {}",
self.logs[index].operated_by, self.logs[index].description
);
return Ok(());
}
Err(e) => {
if e.should_be_fatal() {
return Err(Error::InvalidSct(e));
}
debug!("SCT ignored because {:?}", e);
last_sct_error = Some(e);
}
}
}
/* If we were supplied with some logs, and some SCTs,
* but couldn't verify any of them, fail the handshake. */
if let Some(last_sct_error) = last_sct_error {
warn!("No valid SCTs provided");
return Err(Error::InvalidSct(last_sct_error));
}
Ok(())
}
}
fn intermediate_chain(intermediates: &[Certificate]) -> Vec<&[u8]> {
intermediates
.iter()
@ -920,16 +819,6 @@ fn verify_tls13(
.map(|_| HandshakeSignatureValid::assertion())
}
fn unix_time_millis(now: SystemTime) -> Result<u64, Error> {
now.duration_since(std::time::UNIX_EPOCH)
.map(|dur| dur.as_secs())
.map_err(|_| Error::FailedToGetCurrentTime)
.and_then(|secs| {
secs.checked_mul(1000)
.ok_or(Error::FailedToGetCurrentTime)
})
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -213,8 +213,7 @@ impl Context {
}
fn bench(&self, count: usize) {
let verifier = verify::WebPkiVerifier::new(self.roots.clone(), None);
const SCTS: &[&[u8]] = &[];
let verifier = verify::WebPkiVerifier::new(self.roots.clone());
const OCSP_RESPONSE: &[u8] = &[];
let mut times = Vec::new();
@ -227,7 +226,6 @@ impl Context {
end_entity,
intermediates,
&server_name,
&mut SCTS.iter().copied(),
OCSP_RESPONSE,
self.now,
)

View File

@ -157,7 +157,6 @@ pub struct MockServerVerifier {
cert_rejection_error: Option<Error>,
tls12_signature_error: Option<Error>,
tls13_signature_error: Option<Error>,
wants_scts: bool,
signature_schemes: Vec<SignatureScheme>,
}
@ -167,14 +166,12 @@ impl ServerCertVerifier for MockServerVerifier {
end_entity: &rustls::Certificate,
intermediates: &[rustls::Certificate],
server_name: &rustls::ServerName,
scts: &mut dyn Iterator<Item = &[u8]>,
oscp_response: &[u8],
now: std::time::SystemTime,
) -> Result<ServerCertVerified, Error> {
let scts: Vec<Vec<u8>> = scts.map(|x| x.to_owned()).collect();
println!(
"verify_server_cert({:?}, {:?}, {:?}, {:?}, {:?}, {:?})",
end_entity, intermediates, server_name, scts, oscp_response, now
"verify_server_cert({:?}, {:?}, {:?}, {:?}, {:?})",
end_entity, intermediates, server_name, oscp_response, now
);
if let Some(error) = &self.cert_rejection_error {
Err(error.clone())
@ -220,11 +217,6 @@ impl ServerCertVerifier for MockServerVerifier {
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.signature_schemes.clone()
}
fn request_scts(&self) -> bool {
println!("request_scts? {:?}", self.wants_scts);
self.wants_scts
}
}
impl MockServerVerifier {
@ -270,7 +262,6 @@ impl Default for MockServerVerifier {
cert_rejection_error: None,
tls12_signature_error: None,
tls13_signature_error: None,
wants_scts: false,
signature_schemes: WebPkiVerifier::verification_schemes(),
}
}