mirror of https://github.com/ctz/rustls
Revert "Revert "Remove support for SCT stapling""
This reverts commit 777cc07a4b
.
This commit is contained in:
parent
06b44be5d2
commit
1d659a4689
|
@ -23,6 +23,8 @@ If you'd like to help out, please see [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||||
* Next release:
|
* Next release:
|
||||||
- `RootCertStore::add_parsable_certificates` now takes a
|
- `RootCertStore::add_parsable_certificates` now takes a
|
||||||
`impl IntoIterator<Item = impl AsRef<[u8]>>`.
|
`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)
|
* Release 0.21.3 (2023-07-05)
|
||||||
- Added `with_crls` function to `AllowAnyAuthenticatedClient` and
|
- Added `with_crls` function to `AllowAnyAuthenticatedClient` and
|
||||||
`AllowAnyAnonymousOrAuthenticatedClient` client certificate verifiers to
|
`AllowAnyAnonymousOrAuthenticatedClient` client certificate verifiers to
|
||||||
|
@ -120,8 +122,6 @@ obsolete cryptography.
|
||||||
* Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)).
|
* Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)).
|
||||||
* Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)).
|
* Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)).
|
||||||
* OCSP stapling by servers.
|
* OCSP stapling by servers.
|
||||||
* SCT stapling by servers.
|
|
||||||
* SCT verification by clients.
|
|
||||||
|
|
||||||
## Possible future features
|
## Possible future features
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,11 @@
|
||||||
"EmptyExtensions-ServerHello-TLS12": "",
|
"EmptyExtensions-ServerHello-TLS12": "",
|
||||||
"Server-JDK11*": "workarounds for oracle engineering quality",
|
"Server-JDK11*": "workarounds for oracle engineering quality",
|
||||||
"Client-RejectJDK11DowngradeRandom": "",
|
"Client-RejectJDK11DowngradeRandom": "",
|
||||||
|
"SendUnsolicitedSCTOnCertificate-TLS13": "SCT stapling not supported",
|
||||||
|
"SignedCertificateTimestampListEmpty-Client-*": "",
|
||||||
|
"SignedCertificateTimestampListEmptySCT-Client-*": "",
|
||||||
|
"SendSCTListOnResume-TLS-TLS12": "",
|
||||||
|
"IgnoreExtensionsOnIntermediates-TLS13": "assumes SCT support",
|
||||||
"CBCRecordSplitting*": "insane ciphersuites",
|
"CBCRecordSplitting*": "insane ciphersuites",
|
||||||
"*CBCPadding*": "",
|
"*CBCPadding*": "",
|
||||||
"RSAEphemeralKey": "",
|
"RSAEphemeralKey": "",
|
||||||
|
@ -322,7 +327,6 @@
|
||||||
"NegotiatePSKResumption-TLS13": ":PEER_MISBEHAVIOUR:",
|
"NegotiatePSKResumption-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||||
"PointFormat-Client-MissingUncompressed": ":PEER_MISBEHAVIOUR:",
|
"PointFormat-Client-MissingUncompressed": ":PEER_MISBEHAVIOUR:",
|
||||||
"SendUnsolicitedOCSPOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
"SendUnsolicitedOCSPOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||||
"SendUnsolicitedSCTOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
|
||||||
"UnsolicitedServerNameAck-TLS-TLS12": ":PEER_MISBEHAVIOUR:",
|
"UnsolicitedServerNameAck-TLS-TLS12": ":PEER_MISBEHAVIOUR:",
|
||||||
"UnsolicitedServerNameAck-TLS-TLS13": ":PEER_MISBEHAVIOUR:",
|
"UnsolicitedServerNameAck-TLS-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||||
"TicketSessionIDLength-33-TLS-TLS12": ":BAD_HANDSHAKE_MSG:",
|
"TicketSessionIDLength-33-TLS-TLS12": ":BAD_HANDSHAKE_MSG:",
|
||||||
|
@ -332,10 +336,6 @@
|
||||||
"Ed25519DefaultDisable-NoAccept": ":PEER_MISBEHAVIOUR:",
|
"Ed25519DefaultDisable-NoAccept": ":PEER_MISBEHAVIOUR:",
|
||||||
"SendUnknownExtensionOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
"SendUnknownExtensionOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||||
"SendDuplicateExtensionsOnCerts-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:",
|
"EMS-Forbidden-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||||
"Unclean-Shutdown": ":CLOSE_WITHOUT_CLOSE_NOTIFY:",
|
"Unclean-Shutdown": ":CLOSE_WITHOUT_CLOSE_NOTIFY:",
|
||||||
"SendExtensionOnClientCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
"SendExtensionOnClientCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||||
|
|
|
@ -344,7 +344,6 @@ mod danger {
|
||||||
_end_entity: &rustls::Certificate,
|
_end_entity: &rustls::Certificate,
|
||||||
_intermediates: &[rustls::Certificate],
|
_intermediates: &[rustls::Certificate],
|
||||||
_server_name: &rustls::ServerName,
|
_server_name: &rustls::ServerName,
|
||||||
_scts: &mut dyn Iterator<Item = &[u8]>,
|
|
||||||
_ocsp: &[u8],
|
_ocsp: &[u8],
|
||||||
_now: std::time::SystemTime,
|
_now: std::time::SystemTime,
|
||||||
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
|
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
|
||||||
|
|
|
@ -622,7 +622,7 @@ fn make_config(args: &Args) -> Arc<rustls::ServerConfig> {
|
||||||
.with_protocol_versions(&versions)
|
.with_protocol_versions(&versions)
|
||||||
.expect("inconsistent cipher-suites/versions specified")
|
.expect("inconsistent cipher-suites/versions specified")
|
||||||
.with_client_cert_verifier(client_auth)
|
.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");
|
.expect("bad certificates/private key");
|
||||||
|
|
||||||
config.key_log = Arc::new(rustls::KeyLogFile::new());
|
config.key_log = Arc::new(rustls::KeyLogFile::new());
|
||||||
|
|
|
@ -18,7 +18,6 @@ rustversion = { version = "1.0.6", optional = true }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = { version = "0.4.4", optional = true }
|
log = { version = "0.4.4", optional = true }
|
||||||
ring = "0.16.20"
|
ring = "0.16.20"
|
||||||
sct = "0.7.0"
|
|
||||||
webpki = { package = "rustls-webpki", version = "0.101.0", features = ["alloc", "std"] }
|
webpki = { package = "rustls-webpki", version = "0.101.0", features = ["alloc", "std"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -50,7 +50,6 @@ struct Options {
|
||||||
check_close_notify: bool,
|
check_close_notify: bool,
|
||||||
host_name: String,
|
host_name: String,
|
||||||
use_sni: bool,
|
use_sni: bool,
|
||||||
send_sct: bool,
|
|
||||||
key_file: String,
|
key_file: String,
|
||||||
cert_file: String,
|
cert_file: String,
|
||||||
protocols: Vec<String>,
|
protocols: Vec<String>,
|
||||||
|
@ -60,7 +59,6 @@ struct Options {
|
||||||
min_version: Option<ProtocolVersion>,
|
min_version: Option<ProtocolVersion>,
|
||||||
max_version: Option<ProtocolVersion>,
|
max_version: Option<ProtocolVersion>,
|
||||||
server_ocsp_response: Vec<u8>,
|
server_ocsp_response: Vec<u8>,
|
||||||
server_sct_list: Vec<u8>,
|
|
||||||
use_signing_scheme: u16,
|
use_signing_scheme: u16,
|
||||||
curves: Option<Vec<u16>>,
|
curves: Option<Vec<u16>>,
|
||||||
export_keying_material: usize,
|
export_keying_material: usize,
|
||||||
|
@ -91,7 +89,6 @@ impl Options {
|
||||||
resume_with_tickets_disabled: false,
|
resume_with_tickets_disabled: false,
|
||||||
host_name: "example.com".to_string(),
|
host_name: "example.com".to_string(),
|
||||||
use_sni: false,
|
use_sni: false,
|
||||||
send_sct: false,
|
|
||||||
queue_data: false,
|
queue_data: false,
|
||||||
queue_data_on_resume: false,
|
queue_data_on_resume: false,
|
||||||
only_write_one_byte_after_handshake: false,
|
only_write_one_byte_after_handshake: false,
|
||||||
|
@ -109,7 +106,6 @@ impl Options {
|
||||||
min_version: None,
|
min_version: None,
|
||||||
max_version: None,
|
max_version: None,
|
||||||
server_ocsp_response: vec![],
|
server_ocsp_response: vec![],
|
||||||
server_sct_list: vec![],
|
|
||||||
use_signing_scheme: 0,
|
use_signing_scheme: 0,
|
||||||
curves: None,
|
curves: None,
|
||||||
export_keying_material: 0,
|
export_keying_material: 0,
|
||||||
|
@ -215,9 +211,7 @@ impl server::ClientCertVerifier for DummyClientAuth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DummyServerAuth {
|
struct DummyServerAuth {}
|
||||||
send_sct: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl client::ServerCertVerifier for DummyServerAuth {
|
impl client::ServerCertVerifier for DummyServerAuth {
|
||||||
fn verify_server_cert(
|
fn verify_server_cert(
|
||||||
|
@ -225,16 +219,11 @@ impl client::ServerCertVerifier for DummyServerAuth {
|
||||||
_end_entity: &Certificate,
|
_end_entity: &Certificate,
|
||||||
_certs: &[Certificate],
|
_certs: &[Certificate],
|
||||||
_hostname: &ServerName,
|
_hostname: &ServerName,
|
||||||
_scts: &mut dyn Iterator<Item = &[u8]>,
|
|
||||||
_ocsp: &[u8],
|
_ocsp: &[u8],
|
||||||
_now: SystemTime,
|
_now: SystemTime,
|
||||||
) -> Result<client::ServerCertVerified, Error> {
|
) -> Result<client::ServerCertVerified, Error> {
|
||||||
Ok(client::ServerCertVerified::assertion())
|
Ok(client::ServerCertVerified::assertion())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_scts(&self) -> bool {
|
|
||||||
self.send_sct
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FixedSignatureSchemeSigningKey {
|
struct FixedSignatureSchemeSigningKey {
|
||||||
|
@ -418,12 +407,7 @@ fn make_server_cfg(opts: &Options) -> Arc<ServerConfig> {
|
||||||
.with_protocol_versions(&opts.supported_versions())
|
.with_protocol_versions(&opts.supported_versions())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_client_cert_verifier(client_auth)
|
.with_client_cert_verifier(client_auth)
|
||||||
.with_single_cert_with_ocsp_and_sct(
|
.with_single_cert_with_ocsp(cert.clone(), key, opts.server_ocsp_response.clone())
|
||||||
cert.clone(),
|
|
||||||
key,
|
|
||||||
opts.server_ocsp_response.clone(),
|
|
||||||
opts.server_sct_list.clone(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
cfg.session_storage = ServerCacheWithResumptionDelay::new(opts.resumption_delay);
|
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_kx_groups(&kx_groups)
|
||||||
.with_protocol_versions(&opts.supported_versions())
|
.with_protocol_versions(&opts.supported_versions())
|
||||||
.expect("inconsistent settings")
|
.expect("inconsistent settings")
|
||||||
.with_custom_certificate_verifier(Arc::new(DummyServerAuth {
|
.with_custom_certificate_verifier(Arc::new(DummyServerAuth {}));
|
||||||
send_sct: opts.send_sct,
|
|
||||||
}));
|
|
||||||
|
|
||||||
let mut cfg = if !opts.cert_file.is_empty() && !opts.key_file.is_empty() {
|
let mut cfg = if !opts.cert_file.is_empty() && !opts.key_file.is_empty() {
|
||||||
let cert = load_cert(&opts.cert_file);
|
let cert = load_cert(&opts.cert_file);
|
||||||
|
@ -991,6 +973,7 @@ fn main() {
|
||||||
"-on-resume-expect-no-offer-early-data" |
|
"-on-resume-expect-no-offer-early-data" |
|
||||||
"-key-update" | //< we could implement an API for this
|
"-key-update" | //< we could implement an API for this
|
||||||
"-expect-tls13-downgrade" |
|
"-expect-tls13-downgrade" |
|
||||||
|
"-enable-signed-cert-timestamps" |
|
||||||
"-expect-session-id" => {
|
"-expect-session-id" => {
|
||||||
println!("not checking {}; NYI", arg);
|
println!("not checking {}; NYI", arg);
|
||||||
}
|
}
|
||||||
|
@ -1020,16 +1003,6 @@ fn main() {
|
||||||
opts.server_ocsp_response = BASE64_STANDARD.decode(args.remove(0).as_bytes())
|
opts.server_ocsp_response = BASE64_STANDARD.decode(args.remove(0).as_bytes())
|
||||||
.expect("invalid base64");
|
.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" => {
|
"-select-alpn" => {
|
||||||
opts.protocols.push(args.remove(0));
|
opts.protocols.push(args.remove(0));
|
||||||
}
|
}
|
||||||
|
@ -1065,9 +1038,6 @@ fn main() {
|
||||||
"-use-null-client-ca-list" => {
|
"-use-null-client-ca-list" => {
|
||||||
opts.offer_no_client_cas = true;
|
opts.offer_no_client_cas = true;
|
||||||
}
|
}
|
||||||
"-enable-signed-cert-timestamps" => {
|
|
||||||
opts.send_sct = true;
|
|
||||||
}
|
|
||||||
"-enable-early-data" => {
|
"-enable-early-data" => {
|
||||||
opts.tickets = false;
|
opts.tickets = false;
|
||||||
opts.enable_early_data = true;
|
opts.enable_early_data = true;
|
||||||
|
@ -1200,6 +1170,7 @@ fn main() {
|
||||||
"-wpa-202304" |
|
"-wpa-202304" |
|
||||||
"-srtp-profiles" |
|
"-srtp-profiles" |
|
||||||
"-permute-extensions" |
|
"-permute-extensions" |
|
||||||
|
"-signed-cert-timestamps" |
|
||||||
"-on-initial-expect-peer-cert-file" => {
|
"-on-initial-expect-peer-cert-file" => {
|
||||||
println!("NYI option {:?}", arg);
|
println!("NYI option {:?}", arg);
|
||||||
process::exit(BOGO_NACK);
|
process::exit(BOGO_NACK);
|
||||||
|
|
|
@ -4,27 +4,26 @@ use crate::error::Error;
|
||||||
use crate::key_log::NoKeyLog;
|
use crate::key_log::NoKeyLog;
|
||||||
use crate::kx::SupportedKxGroup;
|
use crate::kx::SupportedKxGroup;
|
||||||
use crate::suites::SupportedCipherSuite;
|
use crate::suites::SupportedCipherSuite;
|
||||||
use crate::verify::{self, CertificateTransparencyPolicy};
|
use crate::verify;
|
||||||
use crate::{anchors, key, versions};
|
use crate::{anchors, key, versions};
|
||||||
|
|
||||||
use super::client_conn::Resumption;
|
use super::client_conn::Resumption;
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
impl ConfigBuilder<ClientConfig, WantsVerifier> {
|
impl ConfigBuilder<ClientConfig, WantsVerifier> {
|
||||||
/// Choose how to verify server certificates.
|
/// Choose how to verify server certificates.
|
||||||
pub fn with_root_certificates(
|
pub fn with_root_certificates(
|
||||||
self,
|
self,
|
||||||
root_store: anchors::RootCertStore,
|
root_store: anchors::RootCertStore,
|
||||||
) -> ConfigBuilder<ClientConfig, WantsTransparencyPolicyOrClientCert> {
|
) -> ConfigBuilder<ClientConfig, WantsClientCert> {
|
||||||
ConfigBuilder {
|
ConfigBuilder {
|
||||||
state: WantsTransparencyPolicyOrClientCert {
|
state: WantsClientCert {
|
||||||
cipher_suites: self.state.cipher_suites,
|
cipher_suites: self.state.cipher_suites,
|
||||||
kx_groups: self.state.kx_groups,
|
kx_groups: self.state.kx_groups,
|
||||||
versions: self.state.versions,
|
versions: self.state.versions,
|
||||||
root_store,
|
verifier: Arc::new(verify::WebPkiVerifier::new(root_store)),
|
||||||
},
|
},
|
||||||
side: PhantomData,
|
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
|
/// A config builder state where the caller needs to supply whether and how to provide a client
|
||||||
/// certificate.
|
/// certificate.
|
||||||
///
|
///
|
||||||
|
|
|
@ -2,8 +2,8 @@ use super::ResolvesClientCert;
|
||||||
#[cfg(feature = "logging")]
|
#[cfg(feature = "logging")]
|
||||||
use crate::log::{debug, trace};
|
use crate::log::{debug, trace};
|
||||||
use crate::msgs::enums::ExtensionType;
|
use crate::msgs::enums::ExtensionType;
|
||||||
|
use crate::msgs::handshake::ServerExtension;
|
||||||
use crate::msgs::handshake::{CertificatePayload, DistinguishedName};
|
use crate::msgs::handshake::{CertificatePayload, DistinguishedName};
|
||||||
use crate::msgs::handshake::{Sct, ServerExtension};
|
|
||||||
use crate::{sign, SignatureScheme};
|
use crate::{sign, SignatureScheme};
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -12,29 +12,15 @@ use std::sync::Arc;
|
||||||
pub(super) struct ServerCertDetails {
|
pub(super) struct ServerCertDetails {
|
||||||
pub(super) cert_chain: CertificatePayload,
|
pub(super) cert_chain: CertificatePayload,
|
||||||
pub(super) ocsp_response: Vec<u8>,
|
pub(super) ocsp_response: Vec<u8>,
|
||||||
pub(super) scts: Option<Vec<Sct>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerCertDetails {
|
impl ServerCertDetails {
|
||||||
pub(super) fn new(
|
pub(super) fn new(cert_chain: CertificatePayload, ocsp_response: Vec<u8>) -> Self {
|
||||||
cert_chain: CertificatePayload,
|
|
||||||
ocsp_response: Vec<u8>,
|
|
||||||
scts: Option<Vec<Sct>>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
cert_chain,
|
cert_chain,
|
||||||
ocsp_response,
|
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 {
|
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(
|
pub(super) fn server_sent_unsolicited_extensions(
|
||||||
&self,
|
&self,
|
||||||
received_exts: &[ServerExtension],
|
received_exts: &[ServerExtension],
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::msgs::base::Payload;
|
||||||
use crate::msgs::enums::{Compression, ExtensionType};
|
use crate::msgs::enums::{Compression, ExtensionType};
|
||||||
use crate::msgs::enums::{ECPointFormat, PSKKeyExchangeMode};
|
use crate::msgs::enums::{ECPointFormat, PSKKeyExchangeMode};
|
||||||
use crate::msgs::handshake::ConvertProtocolNameList;
|
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::{ClientExtension, HasServerExtensions};
|
||||||
use crate::msgs::handshake::{ClientHelloPayload, HandshakeMessagePayload, HandshakePayload};
|
use crate::msgs::handshake::{ClientHelloPayload, HandshakeMessagePayload, HandshakePayload};
|
||||||
use crate::msgs::handshake::{HelloRetryRequest, KeyShareEntry};
|
use crate::msgs::handshake::{HelloRetryRequest, KeyShareEntry};
|
||||||
|
@ -141,13 +141,11 @@ pub(super) fn start_handshake(
|
||||||
None => SessionId::random()?,
|
None => SessionId::random()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let may_send_sct_list = config.verifier.request_scts();
|
|
||||||
Ok(emit_client_hello_for_retry(
|
Ok(emit_client_hello_for_retry(
|
||||||
transcript_buffer,
|
transcript_buffer,
|
||||||
None,
|
None,
|
||||||
key_share,
|
key_share,
|
||||||
extra_exts,
|
extra_exts,
|
||||||
may_send_sct_list,
|
|
||||||
None,
|
None,
|
||||||
ClientHelloInput {
|
ClientHelloInput {
|
||||||
config,
|
config,
|
||||||
|
@ -194,7 +192,6 @@ fn emit_client_hello_for_retry(
|
||||||
retryreq: Option<&HelloRetryRequest>,
|
retryreq: Option<&HelloRetryRequest>,
|
||||||
key_share: Option<kx::KeyExchange>,
|
key_share: Option<kx::KeyExchange>,
|
||||||
extra_exts: Vec<ClientExtension>,
|
extra_exts: Vec<ClientExtension>,
|
||||||
may_send_sct_list: bool,
|
|
||||||
suite: Option<SupportedCipherSuite>,
|
suite: Option<SupportedCipherSuite>,
|
||||||
mut input: ClientHelloInput,
|
mut input: ClientHelloInput,
|
||||||
cx: &mut ClientContext<'_>,
|
cx: &mut ClientContext<'_>,
|
||||||
|
@ -238,10 +235,6 @@ fn emit_client_hello_for_retry(
|
||||||
exts.push(ClientExtension::make_sni(sni_name));
|
exts.push(ClientExtension::make_sni(sni_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
if may_send_sct_list {
|
|
||||||
exts.push(ClientExtension::SignedCertificateTimestampRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(key_share) = &key_share {
|
if let Some(key_share) = &key_share {
|
||||||
debug_assert!(support_tls13);
|
debug_assert!(support_tls13);
|
||||||
let key_share = KeyShareEntry::new(key_share.group(), key_share.pubkey.as_ref());
|
let key_share = KeyShareEntry::new(key_share.group(), key_share.pubkey.as_ref());
|
||||||
|
@ -479,13 +472,6 @@ pub(super) fn process_alpn_protocol(
|
||||||
Ok(())
|
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 {
|
impl State<ClientConnectionData> for ExpectServerHello {
|
||||||
fn handle(mut self: Box<Self>, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError {
|
fn handle(mut self: Box<Self>, cx: &mut ClientContext<'_>, m: Message) -> NextStateOrError {
|
||||||
let server_hello =
|
let server_hello =
|
||||||
|
@ -800,12 +786,6 @@ impl ExpectServerHelloOrHelloRetryRequest {
|
||||||
cx.data.early_data.rejected();
|
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 {
|
let key_share = match req_group {
|
||||||
Some(group) if group != offered_key_share.group() => {
|
Some(group) if group != offered_key_share.group() => {
|
||||||
let group = kx::KeyExchange::choose(group, &config.kx_groups).ok_or_else(|| {
|
let group = kx::KeyExchange::choose(group, &config.kx_groups).ok_or_else(|| {
|
||||||
|
@ -824,7 +804,6 @@ impl ExpectServerHelloOrHelloRetryRequest {
|
||||||
Some(hrr),
|
Some(hrr),
|
||||||
Some(key_share),
|
Some(key_share),
|
||||||
self.extra_exts,
|
self.extra_exts,
|
||||||
may_send_sct_list,
|
|
||||||
Some(cs),
|
Some(cs),
|
||||||
self.next.input,
|
self.next.input,
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::msgs::base::{Payload, PayloadU8};
|
||||||
use crate::msgs::ccs::ChangeCipherSpecPayload;
|
use crate::msgs::ccs::ChangeCipherSpecPayload;
|
||||||
use crate::msgs::codec::Codec;
|
use crate::msgs::codec::Codec;
|
||||||
use crate::msgs::handshake::{
|
use crate::msgs::handshake::{
|
||||||
CertificatePayload, HandshakeMessagePayload, HandshakePayload, NewSessionTicketPayload, Sct,
|
CertificatePayload, HandshakeMessagePayload, HandshakePayload, NewSessionTicketPayload,
|
||||||
ServerECDHParams, SessionId,
|
ServerECDHParams, SessionId,
|
||||||
};
|
};
|
||||||
use crate::msgs::message::{Message, MessagePayload};
|
use crate::msgs::message::{Message, MessagePayload};
|
||||||
|
@ -102,18 +102,6 @@ mod server_hello {
|
||||||
debug!("Server may staple OCSP response");
|
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.
|
// See if we're successfully resuming.
|
||||||
if let Some(ref resuming) = self.resuming_session {
|
if let Some(ref resuming) = self.resuming_session {
|
||||||
if resuming.session_id == server_hello.session_id {
|
if resuming.session_id == server_hello.session_id {
|
||||||
|
@ -187,7 +175,6 @@ mod server_hello {
|
||||||
suite,
|
suite,
|
||||||
may_send_cert_status,
|
may_send_cert_status,
|
||||||
must_issue_new_ticket,
|
must_issue_new_ticket,
|
||||||
server_cert_sct_list,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,7 +191,6 @@ struct ExpectCertificate {
|
||||||
pub(super) suite: &'static Tls12CipherSuite,
|
pub(super) suite: &'static Tls12CipherSuite,
|
||||||
may_send_cert_status: bool,
|
may_send_cert_status: bool,
|
||||||
must_issue_new_ticket: bool,
|
must_issue_new_ticket: bool,
|
||||||
server_cert_sct_list: Option<Vec<Sct>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State<ClientConnectionData> for ExpectCertificate {
|
impl State<ClientConnectionData> for ExpectCertificate {
|
||||||
|
@ -230,13 +216,11 @@ impl State<ClientConnectionData> for ExpectCertificate {
|
||||||
using_ems: self.using_ems,
|
using_ems: self.using_ems,
|
||||||
transcript: self.transcript,
|
transcript: self.transcript,
|
||||||
suite: self.suite,
|
suite: self.suite,
|
||||||
server_cert_sct_list: self.server_cert_sct_list,
|
|
||||||
server_cert_chain,
|
server_cert_chain,
|
||||||
must_issue_new_ticket: self.must_issue_new_ticket,
|
must_issue_new_ticket: self.must_issue_new_ticket,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
let server_cert =
|
let server_cert = ServerCertDetails::new(server_cert_chain, vec![]);
|
||||||
ServerCertDetails::new(server_cert_chain, vec![], self.server_cert_sct_list);
|
|
||||||
|
|
||||||
Ok(Box::new(ExpectServerKx {
|
Ok(Box::new(ExpectServerKx {
|
||||||
config: self.config,
|
config: self.config,
|
||||||
|
@ -263,7 +247,6 @@ struct ExpectCertificateStatusOrServerKx {
|
||||||
using_ems: bool,
|
using_ems: bool,
|
||||||
transcript: HandshakeHash,
|
transcript: HandshakeHash,
|
||||||
suite: &'static Tls12CipherSuite,
|
suite: &'static Tls12CipherSuite,
|
||||||
server_cert_sct_list: Option<Vec<Sct>>,
|
|
||||||
server_cert_chain: CertificatePayload,
|
server_cert_chain: CertificatePayload,
|
||||||
must_issue_new_ticket: bool,
|
must_issue_new_ticket: bool,
|
||||||
}
|
}
|
||||||
|
@ -287,11 +270,7 @@ impl State<ClientConnectionData> for ExpectCertificateStatusOrServerKx {
|
||||||
using_ems: self.using_ems,
|
using_ems: self.using_ems,
|
||||||
transcript: self.transcript,
|
transcript: self.transcript,
|
||||||
suite: self.suite,
|
suite: self.suite,
|
||||||
server_cert: ServerCertDetails::new(
|
server_cert: ServerCertDetails::new(self.server_cert_chain, vec![]),
|
||||||
self.server_cert_chain,
|
|
||||||
vec![],
|
|
||||||
self.server_cert_sct_list,
|
|
||||||
),
|
|
||||||
must_issue_new_ticket: self.must_issue_new_ticket,
|
must_issue_new_ticket: self.must_issue_new_ticket,
|
||||||
})
|
})
|
||||||
.handle(cx, m),
|
.handle(cx, m),
|
||||||
|
@ -311,7 +290,6 @@ impl State<ClientConnectionData> for ExpectCertificateStatusOrServerKx {
|
||||||
using_ems: self.using_ems,
|
using_ems: self.using_ems,
|
||||||
transcript: self.transcript,
|
transcript: self.transcript,
|
||||||
suite: self.suite,
|
suite: self.suite,
|
||||||
server_cert_sct_list: self.server_cert_sct_list,
|
|
||||||
server_cert_chain: self.server_cert_chain,
|
server_cert_chain: self.server_cert_chain,
|
||||||
must_issue_new_ticket: self.must_issue_new_ticket,
|
must_issue_new_ticket: self.must_issue_new_ticket,
|
||||||
})
|
})
|
||||||
|
@ -337,7 +315,6 @@ struct ExpectCertificateStatus {
|
||||||
using_ems: bool,
|
using_ems: bool,
|
||||||
transcript: HandshakeHash,
|
transcript: HandshakeHash,
|
||||||
suite: &'static Tls12CipherSuite,
|
suite: &'static Tls12CipherSuite,
|
||||||
server_cert_sct_list: Option<Vec<Sct>>,
|
|
||||||
server_cert_chain: CertificatePayload,
|
server_cert_chain: CertificatePayload,
|
||||||
must_issue_new_ticket: bool,
|
must_issue_new_ticket: bool,
|
||||||
}
|
}
|
||||||
|
@ -361,11 +338,7 @@ impl State<ClientConnectionData> for ExpectCertificateStatus {
|
||||||
&server_cert_ocsp_response
|
&server_cert_ocsp_response
|
||||||
);
|
);
|
||||||
|
|
||||||
let server_cert = ServerCertDetails::new(
|
let server_cert = ServerCertDetails::new(self.server_cert_chain, server_cert_ocsp_response);
|
||||||
self.server_cert_chain,
|
|
||||||
server_cert_ocsp_response,
|
|
||||||
self.server_cert_sct_list,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Box::new(ExpectServerKx {
|
Ok(Box::new(ExpectServerKx {
|
||||||
config: self.config,
|
config: self.config,
|
||||||
|
@ -741,7 +714,6 @@ impl State<ClientConnectionData> for ExpectServerDone {
|
||||||
end_entity,
|
end_entity,
|
||||||
intermediates,
|
intermediates,
|
||||||
&st.server_name,
|
&st.server_name,
|
||||||
&mut st.server_cert.scts(),
|
|
||||||
&st.server_cert.ocsp_response,
|
&st.server_cert.ocsp_response,
|
||||||
now,
|
now,
|
||||||
)
|
)
|
||||||
|
|
|
@ -448,7 +448,6 @@ impl State<ClientConnectionData> for ExpectEncryptedExtensions {
|
||||||
suite: self.suite,
|
suite: self.suite,
|
||||||
transcript: self.transcript,
|
transcript: self.transcript,
|
||||||
key_schedule: self.key_schedule,
|
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,
|
suite: &'static Tls13CipherSuite,
|
||||||
transcript: HandshakeHash,
|
transcript: HandshakeHash,
|
||||||
key_schedule: KeyScheduleHandshake,
|
key_schedule: KeyScheduleHandshake,
|
||||||
may_send_sct_list: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State<ClientConnectionData> for ExpectCertificateOrCertReq {
|
impl State<ClientConnectionData> for ExpectCertificateOrCertReq {
|
||||||
|
@ -481,7 +479,6 @@ impl State<ClientConnectionData> for ExpectCertificateOrCertReq {
|
||||||
suite: self.suite,
|
suite: self.suite,
|
||||||
transcript: self.transcript,
|
transcript: self.transcript,
|
||||||
key_schedule: self.key_schedule,
|
key_schedule: self.key_schedule,
|
||||||
may_send_sct_list: self.may_send_sct_list,
|
|
||||||
client_auth: None,
|
client_auth: None,
|
||||||
})
|
})
|
||||||
.handle(cx, m),
|
.handle(cx, m),
|
||||||
|
@ -499,7 +496,6 @@ impl State<ClientConnectionData> for ExpectCertificateOrCertReq {
|
||||||
suite: self.suite,
|
suite: self.suite,
|
||||||
transcript: self.transcript,
|
transcript: self.transcript,
|
||||||
key_schedule: self.key_schedule,
|
key_schedule: self.key_schedule,
|
||||||
may_send_sct_list: self.may_send_sct_list,
|
|
||||||
})
|
})
|
||||||
.handle(cx, m),
|
.handle(cx, m),
|
||||||
payload => Err(inappropriate_handshake_message(
|
payload => Err(inappropriate_handshake_message(
|
||||||
|
@ -524,7 +520,6 @@ struct ExpectCertificateRequest {
|
||||||
suite: &'static Tls13CipherSuite,
|
suite: &'static Tls13CipherSuite,
|
||||||
transcript: HandshakeHash,
|
transcript: HandshakeHash,
|
||||||
key_schedule: KeyScheduleHandshake,
|
key_schedule: KeyScheduleHandshake,
|
||||||
may_send_sct_list: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State<ClientConnectionData> for ExpectCertificateRequest {
|
impl State<ClientConnectionData> for ExpectCertificateRequest {
|
||||||
|
@ -582,7 +577,6 @@ impl State<ClientConnectionData> for ExpectCertificateRequest {
|
||||||
suite: self.suite,
|
suite: self.suite,
|
||||||
transcript: self.transcript,
|
transcript: self.transcript,
|
||||||
key_schedule: self.key_schedule,
|
key_schedule: self.key_schedule,
|
||||||
may_send_sct_list: self.may_send_sct_list,
|
|
||||||
client_auth: Some(client_auth),
|
client_auth: Some(client_auth),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -595,7 +589,6 @@ struct ExpectCertificate {
|
||||||
suite: &'static Tls13CipherSuite,
|
suite: &'static Tls13CipherSuite,
|
||||||
transcript: HandshakeHash,
|
transcript: HandshakeHash,
|
||||||
key_schedule: KeyScheduleHandshake,
|
key_schedule: KeyScheduleHandshake,
|
||||||
may_send_sct_list: bool,
|
|
||||||
client_auth: Option<ClientAuthDetails>,
|
client_auth: Option<ClientAuthDetails>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,23 +618,8 @@ impl State<ClientConnectionData> for ExpectCertificate {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_cert = ServerCertDetails::new(
|
let server_cert =
|
||||||
cert_chain.convert(),
|
ServerCertDetails::new(cert_chain.convert(), cert_chain.get_end_entity_ocsp());
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Box::new(ExpectCertificateVerify {
|
Ok(Box::new(ExpectCertificateVerify {
|
||||||
config: self.config,
|
config: self.config,
|
||||||
|
@ -692,7 +670,6 @@ impl State<ClientConnectionData> for ExpectCertificateVerify {
|
||||||
end_entity,
|
end_entity,
|
||||||
intermediates,
|
intermediates,
|
||||||
&self.server_name,
|
&self.server_name,
|
||||||
&mut self.server_cert.scts(),
|
|
||||||
&self.server_cert.ocsp_response,
|
&self.server_cert.ocsp_response,
|
||||||
now,
|
now,
|
||||||
)
|
)
|
||||||
|
|
|
@ -66,9 +66,6 @@ pub enum Error {
|
||||||
/// implementation.
|
/// implementation.
|
||||||
InvalidCertificate(CertificateError),
|
InvalidCertificate(CertificateError),
|
||||||
|
|
||||||
/// The presented SCT(s) were invalid.
|
|
||||||
InvalidSct(sct::Error),
|
|
||||||
|
|
||||||
/// A provided certificate revocation list (CRL) was invalid.
|
/// A provided certificate revocation list (CRL) was invalid.
|
||||||
InvalidCertRevocationList(CertRevocationListError),
|
InvalidCertRevocationList(CertRevocationListError),
|
||||||
|
|
||||||
|
@ -188,7 +185,6 @@ pub enum PeerMisbehaved {
|
||||||
IncorrectBinder,
|
IncorrectBinder,
|
||||||
InvalidMaxEarlyDataSize,
|
InvalidMaxEarlyDataSize,
|
||||||
InvalidKeyShare,
|
InvalidKeyShare,
|
||||||
InvalidSctList,
|
|
||||||
KeyEpochWithPendingFragment,
|
KeyEpochWithPendingFragment,
|
||||||
KeyUpdateReceivedInQuicConnection,
|
KeyUpdateReceivedInQuicConnection,
|
||||||
MessageInterleavedWithHandshakeMessage,
|
MessageInterleavedWithHandshakeMessage,
|
||||||
|
@ -525,7 +521,6 @@ impl fmt::Display for Error {
|
||||||
Self::PeerSentOversizedRecord => write!(f, "peer sent excess record size"),
|
Self::PeerSentOversizedRecord => write!(f, "peer sent excess record size"),
|
||||||
Self::HandshakeNotComplete => write!(f, "handshake not complete"),
|
Self::HandshakeNotComplete => write!(f, "handshake not complete"),
|
||||||
Self::NoApplicationProtocol => write!(f, "peer doesn't support any known protocol"),
|
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::FailedToGetCurrentTime => write!(f, "failed to get current time"),
|
||||||
Self::FailedToGetRandomBytes => write!(f, "failed to get random bytes"),
|
Self::FailedToGetRandomBytes => write!(f, "failed to get random bytes"),
|
||||||
Self::BadMaxFragmentSize => {
|
Self::BadMaxFragmentSize => {
|
||||||
|
@ -653,7 +648,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() {
|
fn smoke() {
|
||||||
use crate::enums::{AlertDescription, ContentType, HandshakeType};
|
use crate::enums::{AlertDescription, ContentType, HandshakeType};
|
||||||
use sct;
|
|
||||||
|
|
||||||
let all = vec![
|
let all = vec![
|
||||||
Error::InappropriateMessage {
|
Error::InappropriateMessage {
|
||||||
|
@ -671,7 +665,6 @@ mod tests {
|
||||||
super::PeerMisbehaved::UnsolicitedCertExtension.into(),
|
super::PeerMisbehaved::UnsolicitedCertExtension.into(),
|
||||||
Error::AlertReceived(AlertDescription::ExportRestriction),
|
Error::AlertReceived(AlertDescription::ExportRestriction),
|
||||||
super::CertificateError::Expired.into(),
|
super::CertificateError::Expired.into(),
|
||||||
Error::InvalidSct(sct::Error::MalformedSct),
|
|
||||||
Error::General("undocumented error".to_string()),
|
Error::General("undocumented error".to_string()),
|
||||||
Error::FailedToGetCurrentTime,
|
Error::FailedToGetCurrentTime,
|
||||||
Error::FailedToGetRandomBytes,
|
Error::FailedToGetRandomBytes,
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
//! * Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)).
|
//! * Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)).
|
||||||
//! * Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)).
|
//! * Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)).
|
||||||
//! * OCSP stapling by servers.
|
//! * OCSP stapling by servers.
|
||||||
//! * SCT stapling by servers.
|
|
||||||
//! * SCT verification by clients.
|
|
||||||
//!
|
//!
|
||||||
//! ## Possible future features
|
//! ## Possible future features
|
||||||
//!
|
//!
|
||||||
|
@ -417,7 +415,7 @@ pub mod client {
|
||||||
mod tls13;
|
mod tls13;
|
||||||
|
|
||||||
pub use crate::dns_name::InvalidDnsNameError;
|
pub use crate::dns_name::InvalidDnsNameError;
|
||||||
pub use builder::{WantsClientCert, WantsTransparencyPolicyOrClientCert};
|
pub use builder::WantsClientCert;
|
||||||
pub use client_conn::{
|
pub use client_conn::{
|
||||||
ClientConfig, ClientConnection, ClientConnectionData, ClientSessionStore,
|
ClientConfig, ClientConnection, ClientConnectionData, ClientSessionStore,
|
||||||
ResolvesClientCert, Resumption, ServerName, Tls12Resumption, WriteEarlyData,
|
ResolvesClientCert, Resumption, ServerName, Tls12Resumption, WriteEarlyData,
|
||||||
|
@ -426,9 +424,8 @@ pub mod client {
|
||||||
|
|
||||||
#[cfg(feature = "dangerous_configuration")]
|
#[cfg(feature = "dangerous_configuration")]
|
||||||
pub use crate::verify::{
|
pub use crate::verify::{
|
||||||
verify_server_cert_signed_by_trust_anchor, verify_server_name,
|
verify_server_cert_signed_by_trust_anchor, verify_server_name, HandshakeSignatureValid,
|
||||||
CertificateTransparencyPolicy, HandshakeSignatureValid, ServerCertVerified,
|
ServerCertVerified, ServerCertVerifier, WebPkiVerifier,
|
||||||
ServerCertVerifier, WebPkiVerifier,
|
|
||||||
};
|
};
|
||||||
#[cfg(feature = "dangerous_configuration")]
|
#[cfg(feature = "dangerous_configuration")]
|
||||||
pub use client_conn::danger::DangerousClientConfig;
|
pub use client_conn::danger::DangerousClientConfig;
|
||||||
|
|
|
@ -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 {
|
impl TlsListElement for PSKKeyExchangeMode {
|
||||||
|
@ -554,7 +545,6 @@ pub enum ClientExtension {
|
||||||
Cookie(PayloadU16),
|
Cookie(PayloadU16),
|
||||||
ExtendedMasterSecretRequest,
|
ExtendedMasterSecretRequest,
|
||||||
CertificateStatusRequest(CertificateStatusRequest),
|
CertificateStatusRequest(CertificateStatusRequest),
|
||||||
SignedCertificateTimestampRequest,
|
|
||||||
TransportParameters(Vec<u8>),
|
TransportParameters(Vec<u8>),
|
||||||
TransportParametersDraft(Vec<u8>),
|
TransportParametersDraft(Vec<u8>),
|
||||||
EarlyData,
|
EarlyData,
|
||||||
|
@ -577,7 +567,6 @@ impl ClientExtension {
|
||||||
Self::Cookie(_) => ExtensionType::Cookie,
|
Self::Cookie(_) => ExtensionType::Cookie,
|
||||||
Self::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret,
|
Self::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret,
|
||||||
Self::CertificateStatusRequest(_) => ExtensionType::StatusRequest,
|
Self::CertificateStatusRequest(_) => ExtensionType::StatusRequest,
|
||||||
Self::SignedCertificateTimestampRequest => ExtensionType::SCT,
|
|
||||||
Self::TransportParameters(_) => ExtensionType::TransportParameters,
|
Self::TransportParameters(_) => ExtensionType::TransportParameters,
|
||||||
Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft,
|
Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft,
|
||||||
Self::EarlyData => ExtensionType::EarlyData,
|
Self::EarlyData => ExtensionType::EarlyData,
|
||||||
|
@ -598,7 +587,6 @@ impl Codec for ClientExtension {
|
||||||
Self::ServerName(ref r) => r.encode(&mut sub),
|
Self::ServerName(ref r) => r.encode(&mut sub),
|
||||||
Self::SessionTicket(ClientSessionTicket::Request)
|
Self::SessionTicket(ClientSessionTicket::Request)
|
||||||
| Self::ExtendedMasterSecretRequest
|
| Self::ExtendedMasterSecretRequest
|
||||||
| Self::SignedCertificateTimestampRequest
|
|
||||||
| Self::EarlyData => {}
|
| Self::EarlyData => {}
|
||||||
Self::SessionTicket(ClientSessionTicket::Offer(ref r)) => r.encode(&mut sub),
|
Self::SessionTicket(ClientSessionTicket::Offer(ref r)) => r.encode(&mut sub),
|
||||||
Self::Protocols(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)?;
|
let csr = CertificateStatusRequest::read(&mut sub)?;
|
||||||
Self::CertificateStatusRequest(csr)
|
Self::CertificateStatusRequest(csr)
|
||||||
}
|
}
|
||||||
ExtensionType::SCT if !sub.any_left() => Self::SignedCertificateTimestampRequest,
|
|
||||||
ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()),
|
ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()),
|
||||||
ExtensionType::TransportParametersDraft => {
|
ExtensionType::TransportParametersDraft => {
|
||||||
Self::TransportParametersDraft(sub.rest().to_vec())
|
Self::TransportParametersDraft(sub.rest().to_vec())
|
||||||
|
@ -707,7 +694,6 @@ pub enum ServerExtension {
|
||||||
PresharedKey(u16),
|
PresharedKey(u16),
|
||||||
ExtendedMasterSecretAck,
|
ExtendedMasterSecretAck,
|
||||||
CertificateStatusAck,
|
CertificateStatusAck,
|
||||||
SignedCertificateTimestamp(Vec<Sct>),
|
|
||||||
SupportedVersions(ProtocolVersion),
|
SupportedVersions(ProtocolVersion),
|
||||||
TransportParameters(Vec<u8>),
|
TransportParameters(Vec<u8>),
|
||||||
TransportParametersDraft(Vec<u8>),
|
TransportParametersDraft(Vec<u8>),
|
||||||
|
@ -727,7 +713,6 @@ impl ServerExtension {
|
||||||
Self::PresharedKey(_) => ExtensionType::PreSharedKey,
|
Self::PresharedKey(_) => ExtensionType::PreSharedKey,
|
||||||
Self::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret,
|
Self::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret,
|
||||||
Self::CertificateStatusAck => ExtensionType::StatusRequest,
|
Self::CertificateStatusAck => ExtensionType::StatusRequest,
|
||||||
Self::SignedCertificateTimestamp(_) => ExtensionType::SCT,
|
|
||||||
Self::SupportedVersions(_) => ExtensionType::SupportedVersions,
|
Self::SupportedVersions(_) => ExtensionType::SupportedVersions,
|
||||||
Self::TransportParameters(_) => ExtensionType::TransportParameters,
|
Self::TransportParameters(_) => ExtensionType::TransportParameters,
|
||||||
Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft,
|
Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft,
|
||||||
|
@ -753,7 +738,6 @@ impl Codec for ServerExtension {
|
||||||
Self::Protocols(ref r) => r.encode(&mut sub),
|
Self::Protocols(ref r) => r.encode(&mut sub),
|
||||||
Self::KeyShare(ref r) => r.encode(&mut sub),
|
Self::KeyShare(ref r) => r.encode(&mut sub),
|
||||||
Self::PresharedKey(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::SupportedVersions(ref r) => r.encode(&mut sub),
|
||||||
Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => {
|
Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => {
|
||||||
sub.extend_from_slice(r);
|
sub.extend_from_slice(r);
|
||||||
|
@ -780,7 +764,6 @@ impl Codec for ServerExtension {
|
||||||
ExtensionType::KeyShare => Self::KeyShare(KeyShareEntry::read(&mut sub)?),
|
ExtensionType::KeyShare => Self::KeyShare(KeyShareEntry::read(&mut sub)?),
|
||||||
ExtensionType::PreSharedKey => Self::PresharedKey(u16::read(&mut sub)?),
|
ExtensionType::PreSharedKey => Self::PresharedKey(u16::read(&mut sub)?),
|
||||||
ExtensionType::ExtendedMasterSecret => Self::ExtendedMasterSecretAck,
|
ExtensionType::ExtendedMasterSecret => Self::ExtendedMasterSecretAck,
|
||||||
ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?),
|
|
||||||
ExtensionType::SupportedVersions => {
|
ExtensionType::SupportedVersions => {
|
||||||
Self::SupportedVersions(ProtocolVersion::read(&mut sub)?)
|
Self::SupportedVersions(ProtocolVersion::read(&mut sub)?)
|
||||||
}
|
}
|
||||||
|
@ -806,11 +789,6 @@ impl ServerExtension {
|
||||||
let empty = Vec::new();
|
let empty = Vec::new();
|
||||||
Self::RenegotiationInfo(PayloadU8::new(empty))
|
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)]
|
#[derive(Debug)]
|
||||||
|
@ -1264,14 +1242,6 @@ impl ServerHelloPayload {
|
||||||
.is_some()
|
.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> {
|
pub fn get_supported_versions(&self) -> Option<ProtocolVersion> {
|
||||||
let ext = self.find_extension(ExtensionType::SupportedVersions)?;
|
let ext = self.find_extension(ExtensionType::SupportedVersions)?;
|
||||||
match *ext {
|
match *ext {
|
||||||
|
@ -1294,7 +1264,6 @@ impl TlsListElement for key::Certificate {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CertificateExtension {
|
pub enum CertificateExtension {
|
||||||
CertificateStatus(CertificateStatus),
|
CertificateStatus(CertificateStatus),
|
||||||
SignedCertificateTimestamp(Vec<Sct>),
|
|
||||||
Unknown(UnknownExtension),
|
Unknown(UnknownExtension),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1302,29 +1271,16 @@ impl CertificateExtension {
|
||||||
pub fn get_type(&self) -> ExtensionType {
|
pub fn get_type(&self) -> ExtensionType {
|
||||||
match *self {
|
match *self {
|
||||||
Self::CertificateStatus(_) => ExtensionType::StatusRequest,
|
Self::CertificateStatus(_) => ExtensionType::StatusRequest,
|
||||||
Self::SignedCertificateTimestamp(_) => ExtensionType::SCT,
|
|
||||||
Self::Unknown(ref r) => r.typ,
|
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>> {
|
pub fn get_cert_status(&self) -> Option<&Vec<u8>> {
|
||||||
match *self {
|
match *self {
|
||||||
Self::CertificateStatus(ref cs) => Some(&cs.ocsp_response.0),
|
Self::CertificateStatus(ref cs) => Some(&cs.ocsp_response.0),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sct_list(&self) -> Option<&[Sct]> {
|
|
||||||
match *self {
|
|
||||||
Self::SignedCertificateTimestamp(ref sctl) => Some(sctl),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Codec for CertificateExtension {
|
impl Codec for CertificateExtension {
|
||||||
|
@ -1334,7 +1290,6 @@ impl Codec for CertificateExtension {
|
||||||
let mut sub: Vec<u8> = Vec::new();
|
let mut sub: Vec<u8> = Vec::new();
|
||||||
match *self {
|
match *self {
|
||||||
Self::CertificateStatus(ref r) => r.encode(&mut sub),
|
Self::CertificateStatus(ref r) => r.encode(&mut sub),
|
||||||
Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub),
|
|
||||||
Self::Unknown(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)?;
|
let st = CertificateStatus::read(&mut sub)?;
|
||||||
Self::CertificateStatus(st)
|
Self::CertificateStatus(st)
|
||||||
}
|
}
|
||||||
ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?),
|
|
||||||
_ => Self::Unknown(UnknownExtension::read(typ, &mut sub)),
|
_ => Self::Unknown(UnknownExtension::read(typ, &mut sub)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1409,9 +1363,9 @@ impl CertificateEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_unknown_extension(&self) -> bool {
|
pub fn has_unknown_extension(&self) -> bool {
|
||||||
self.exts.iter().any(|ext| {
|
self.exts
|
||||||
ext.get_type() != ExtensionType::StatusRequest && ext.get_type() != ExtensionType::SCT
|
.iter()
|
||||||
})
|
.any(|ext| ext.get_type() != ExtensionType::StatusRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ocsp_response(&self) -> Option<&Vec<u8>> {
|
pub fn get_ocsp_response(&self) -> Option<&Vec<u8>> {
|
||||||
|
@ -1420,13 +1374,6 @@ impl CertificateEntry {
|
||||||
.find(|ext| ext.get_type() == ExtensionType::StatusRequest)
|
.find(|ext| ext.get_type() == ExtensionType::StatusRequest)
|
||||||
.and_then(CertificateExtension::get_cert_status)
|
.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 {
|
impl TlsListElement for CertificateEntry {
|
||||||
|
@ -1499,12 +1446,6 @@ impl CertificatePayloadTLS13 {
|
||||||
.unwrap_or_default()
|
.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 {
|
pub fn convert(&self) -> CertificatePayload {
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
for entry in &self.entries {
|
for entry in &self.entries {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::msgs::handshake::{
|
||||||
ECParameters, HandshakeMessagePayload, HandshakePayload, HasServerExtensions,
|
ECParameters, HandshakeMessagePayload, HandshakePayload, HasServerExtensions,
|
||||||
HelloRetryExtension, HelloRetryRequest, KeyShareEntry, NewSessionTicketExtension,
|
HelloRetryExtension, HelloRetryRequest, KeyShareEntry, NewSessionTicketExtension,
|
||||||
NewSessionTicketPayload, NewSessionTicketPayloadTLS13, PresharedKeyBinder,
|
NewSessionTicketPayload, NewSessionTicketPayloadTLS13, PresharedKeyBinder,
|
||||||
PresharedKeyIdentity, PresharedKeyOffer, ProtocolName, Random, Sct, ServerECDHParams,
|
PresharedKeyIdentity, PresharedKeyOffer, ProtocolName, Random, ServerECDHParams,
|
||||||
ServerExtension, ServerHelloPayload, ServerKeyExchangePayload, SessionId, UnknownExtension,
|
ServerExtension, ServerHelloPayload, ServerKeyExchangePayload, SessionId, UnknownExtension,
|
||||||
};
|
};
|
||||||
use crate::verify::DigitallySignedStruct;
|
use crate::verify::DigitallySignedStruct;
|
||||||
|
@ -131,7 +131,7 @@ fn refuses_server_ext_with_unparsed_bytes() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn refuses_certificate_ext_with_unparsed_bytes() {
|
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);
|
let mut rd = Reader::init(&bytes);
|
||||||
assert!(CertificateExtension::read(&mut rd).is_err());
|
assert!(CertificateExtension::read(&mut rd).is_err());
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,6 @@ fn get_sample_clienthellopayload() -> ClientHelloPayload {
|
||||||
ClientExtension::Cookie(PayloadU16(vec![1, 2, 3])),
|
ClientExtension::Cookie(PayloadU16(vec![1, 2, 3])),
|
||||||
ClientExtension::ExtendedMasterSecretRequest,
|
ClientExtension::ExtendedMasterSecretRequest,
|
||||||
ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()),
|
ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()),
|
||||||
ClientExtension::SignedCertificateTimestampRequest,
|
|
||||||
ClientExtension::TransportParameters(vec![1, 2, 3]),
|
ClientExtension::TransportParameters(vec![1, 2, 3]),
|
||||||
ClientExtension::Unknown(UnknownExtension {
|
ClientExtension::Unknown(UnknownExtension {
|
||||||
typ: ExtensionType::Unknown(12345),
|
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]
|
#[test]
|
||||||
fn server_get_supported_versions() {
|
fn server_get_supported_versions() {
|
||||||
test_server_extension_getter(ExtensionType::SupportedVersions, |shp| {
|
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 {
|
fn get_sample_serverhellopayload() -> ServerHelloPayload {
|
||||||
ServerHelloPayload {
|
ServerHelloPayload {
|
||||||
legacy_version: ProtocolVersion::TLSv1_2,
|
legacy_version: ProtocolVersion::TLSv1_2,
|
||||||
|
@ -764,7 +753,6 @@ fn get_sample_serverhellopayload() -> ServerHelloPayload {
|
||||||
ServerExtension::PresharedKey(3),
|
ServerExtension::PresharedKey(3),
|
||||||
ServerExtension::ExtendedMasterSecretAck,
|
ServerExtension::ExtendedMasterSecretAck,
|
||||||
ServerExtension::CertificateStatusAck,
|
ServerExtension::CertificateStatusAck,
|
||||||
ServerExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]),
|
|
||||||
ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_2),
|
ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_2),
|
||||||
ServerExtension::TransportParameters(vec![1, 2, 3]),
|
ServerExtension::TransportParameters(vec![1, 2, 3]),
|
||||||
ServerExtension::Unknown(UnknownExtension {
|
ServerExtension::Unknown(UnknownExtension {
|
||||||
|
@ -811,7 +799,6 @@ fn get_sample_certificatepayloadtls13() -> CertificatePayloadTLS13 {
|
||||||
CertificateExtension::CertificateStatus(CertificateStatus {
|
CertificateExtension::CertificateStatus(CertificateStatus {
|
||||||
ocsp_response: PayloadU24(vec![1, 2, 3]),
|
ocsp_response: PayloadU24(vec![1, 2, 3]),
|
||||||
}),
|
}),
|
||||||
CertificateExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]),
|
|
||||||
CertificateExtension::Unknown(UnknownExtension {
|
CertificateExtension::Unknown(UnknownExtension {
|
||||||
typ: ExtensionType::Unknown(12345),
|
typ: ExtensionType::Unknown(12345),
|
||||||
payload: Payload(vec![1, 2, 3]),
|
payload: Payload(vec![1, 2, 3]),
|
||||||
|
|
|
@ -77,19 +77,15 @@ impl ConfigBuilder<ServerConfig, WantsServerCert> {
|
||||||
/// `cert_chain` is a vector of DER-encoded certificates.
|
/// `cert_chain` is a vector of DER-encoded certificates.
|
||||||
/// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key.
|
/// `key_der` is a DER-encoded RSA, ECDSA, or Ed25519 private key.
|
||||||
/// `ocsp` is a DER-encoded OCSP response. Ignored if zero length.
|
/// `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.
|
/// 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,
|
self,
|
||||||
cert_chain: Vec<key::Certificate>,
|
cert_chain: Vec<key::Certificate>,
|
||||||
key_der: key::PrivateKey,
|
key_der: key::PrivateKey,
|
||||||
ocsp: Vec<u8>,
|
ocsp: Vec<u8>,
|
||||||
scts: Vec<u8>,
|
|
||||||
) -> Result<ServerConfig, Error> {
|
) -> Result<ServerConfig, Error> {
|
||||||
let resolver =
|
let resolver = handy::AlwaysResolvesChain::new_with_extras(cert_chain, &key_der, ocsp)?;
|
||||||
handy::AlwaysResolvesChain::new_with_extras(cert_chain, &key_der, ocsp, scts)?;
|
|
||||||
Ok(self.with_cert_resolver(Arc::new(resolver)))
|
Ok(self.with_cert_resolver(Arc::new(resolver)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::{key, sign};
|
||||||
pub(super) struct ActiveCertifiedKey<'a> {
|
pub(super) struct ActiveCertifiedKey<'a> {
|
||||||
key: &'a sign::CertifiedKey,
|
key: &'a sign::CertifiedKey,
|
||||||
ocsp: Option<&'a [u8]>,
|
ocsp: Option<&'a [u8]>,
|
||||||
sct_list: Option<&'a [u8]>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ActiveCertifiedKey<'a> {
|
impl<'a> ActiveCertifiedKey<'a> {
|
||||||
|
@ -13,7 +12,6 @@ impl<'a> ActiveCertifiedKey<'a> {
|
||||||
ActiveCertifiedKey {
|
ActiveCertifiedKey {
|
||||||
key,
|
key,
|
||||||
ocsp: key.ocsp.as_deref(),
|
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]> {
|
pub(super) fn get_ocsp(&self) -> Option<&[u8]> {
|
||||||
self.ocsp
|
self.ocsp
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(super) fn get_sct_list(&self) -> Option<&[u8]> {
|
|
||||||
self.sct_list
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,6 @@ impl AlwaysResolvesChain {
|
||||||
chain: Vec<key::Certificate>,
|
chain: Vec<key::Certificate>,
|
||||||
priv_key: &key::PrivateKey,
|
priv_key: &key::PrivateKey,
|
||||||
ocsp: Vec<u8>,
|
ocsp: Vec<u8>,
|
||||||
scts: Vec<u8>,
|
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut r = Self::new(chain, priv_key)?;
|
let mut r = Self::new(chain, priv_key)?;
|
||||||
|
|
||||||
|
@ -121,9 +120,6 @@ impl AlwaysResolvesChain {
|
||||||
if !ocsp.is_empty() {
|
if !ocsp.is_empty() {
|
||||||
cert.ocsp = Some(ocsp);
|
cert.ocsp = Some(ocsp);
|
||||||
}
|
}
|
||||||
if !scts.is_empty() {
|
|
||||||
cert.sct_list = Some(scts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(r)
|
Ok(r)
|
||||||
|
|
|
@ -67,7 +67,6 @@ impl ExtensionProcessing {
|
||||||
config: &ServerConfig,
|
config: &ServerConfig,
|
||||||
cx: &mut ServerContext<'_>,
|
cx: &mut ServerContext<'_>,
|
||||||
ocsp_response: &mut Option<&[u8]>,
|
ocsp_response: &mut Option<&[u8]>,
|
||||||
sct_list: &mut Option<&[u8]>,
|
|
||||||
hello: &ClientHelloPayload,
|
hello: &ClientHelloPayload,
|
||||||
resumedata: Option<&persist::ServerSessionValue>,
|
resumedata: Option<&persist::ServerSessionValue>,
|
||||||
extra_exts: Vec<ServerExtension>,
|
extra_exts: Vec<ServerExtension>,
|
||||||
|
@ -156,24 +155,6 @@ impl ExtensionProcessing {
|
||||||
ocsp_response.take();
|
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);
|
self.exts.extend(extra_exts);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -193,8 +193,7 @@ mod client_hello {
|
||||||
|
|
||||||
debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed);
|
debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed);
|
||||||
|
|
||||||
let (mut ocsp_response, mut sct_list) =
|
let mut ocsp_response = server_key.get_ocsp();
|
||||||
(server_key.get_ocsp(), server_key.get_sct_list());
|
|
||||||
|
|
||||||
// If we're not offered a ticket or a potential session ID, allocate a session ID.
|
// If we're not offered a ticket or a potential session ID, allocate a session ID.
|
||||||
if !self.config.session_storage.can_cache() {
|
if !self.config.session_storage.can_cache() {
|
||||||
|
@ -211,7 +210,6 @@ mod client_hello {
|
||||||
self.suite,
|
self.suite,
|
||||||
self.using_ems,
|
self.using_ems,
|
||||||
&mut ocsp_response,
|
&mut ocsp_response,
|
||||||
&mut sct_list,
|
|
||||||
client_hello,
|
client_hello,
|
||||||
None,
|
None,
|
||||||
&self.randoms,
|
&self.randoms,
|
||||||
|
@ -283,7 +281,6 @@ mod client_hello {
|
||||||
self.suite,
|
self.suite,
|
||||||
self.using_ems,
|
self.using_ems,
|
||||||
&mut None,
|
&mut None,
|
||||||
&mut None,
|
|
||||||
client_hello,
|
client_hello,
|
||||||
Some(&resumedata),
|
Some(&resumedata),
|
||||||
&self.randoms,
|
&self.randoms,
|
||||||
|
@ -339,22 +336,13 @@ mod client_hello {
|
||||||
suite: &'static Tls12CipherSuite,
|
suite: &'static Tls12CipherSuite,
|
||||||
using_ems: bool,
|
using_ems: bool,
|
||||||
ocsp_response: &mut Option<&[u8]>,
|
ocsp_response: &mut Option<&[u8]>,
|
||||||
sct_list: &mut Option<&[u8]>,
|
|
||||||
hello: &ClientHelloPayload,
|
hello: &ClientHelloPayload,
|
||||||
resumedata: Option<&persist::ServerSessionValue>,
|
resumedata: Option<&persist::ServerSessionValue>,
|
||||||
randoms: &ConnectionRandoms,
|
randoms: &ConnectionRandoms,
|
||||||
extra_exts: Vec<ServerExtension>,
|
extra_exts: Vec<ServerExtension>,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
let mut ep = hs::ExtensionProcessing::new();
|
let mut ep = hs::ExtensionProcessing::new();
|
||||||
ep.process_common(
|
ep.process_common(config, cx, ocsp_response, hello, resumedata, extra_exts)?;
|
||||||
config,
|
|
||||||
cx,
|
|
||||||
ocsp_response,
|
|
||||||
sct_list,
|
|
||||||
hello,
|
|
||||||
resumedata,
|
|
||||||
extra_exts,
|
|
||||||
)?;
|
|
||||||
ep.process_tls12(config, hello, using_ems);
|
ep.process_tls12(config, hello, using_ems);
|
||||||
|
|
||||||
let sh = Message {
|
let sh = Message {
|
||||||
|
|
|
@ -372,14 +372,12 @@ mod client_hello {
|
||||||
emit_fake_ccs(cx.common);
|
emit_fake_ccs(cx.common);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut ocsp_response, mut sct_list) =
|
let mut ocsp_response = server_key.get_ocsp();
|
||||||
(server_key.get_ocsp(), server_key.get_sct_list());
|
|
||||||
let doing_early_data = emit_encrypted_extensions(
|
let doing_early_data = emit_encrypted_extensions(
|
||||||
&mut self.transcript,
|
&mut self.transcript,
|
||||||
self.suite,
|
self.suite,
|
||||||
cx,
|
cx,
|
||||||
&mut ocsp_response,
|
&mut ocsp_response,
|
||||||
&mut sct_list,
|
|
||||||
client_hello,
|
client_hello,
|
||||||
resumedata.as_ref(),
|
resumedata.as_ref(),
|
||||||
self.extra_exts,
|
self.extra_exts,
|
||||||
|
@ -394,7 +392,6 @@ mod client_hello {
|
||||||
cx.common,
|
cx.common,
|
||||||
server_key.get_cert(),
|
server_key.get_cert(),
|
||||||
ocsp_response,
|
ocsp_response,
|
||||||
sct_list,
|
|
||||||
);
|
);
|
||||||
emit_certificate_verify_tls13(
|
emit_certificate_verify_tls13(
|
||||||
&mut self.transcript,
|
&mut self.transcript,
|
||||||
|
@ -666,22 +663,13 @@ mod client_hello {
|
||||||
suite: &'static Tls13CipherSuite,
|
suite: &'static Tls13CipherSuite,
|
||||||
cx: &mut ServerContext<'_>,
|
cx: &mut ServerContext<'_>,
|
||||||
ocsp_response: &mut Option<&[u8]>,
|
ocsp_response: &mut Option<&[u8]>,
|
||||||
sct_list: &mut Option<&[u8]>,
|
|
||||||
hello: &ClientHelloPayload,
|
hello: &ClientHelloPayload,
|
||||||
resumedata: Option<&persist::ServerSessionValue>,
|
resumedata: Option<&persist::ServerSessionValue>,
|
||||||
extra_exts: Vec<ServerExtension>,
|
extra_exts: Vec<ServerExtension>,
|
||||||
config: &ServerConfig,
|
config: &ServerConfig,
|
||||||
) -> Result<EarlyDataDecision, Error> {
|
) -> Result<EarlyDataDecision, Error> {
|
||||||
let mut ep = hs::ExtensionProcessing::new();
|
let mut ep = hs::ExtensionProcessing::new();
|
||||||
ep.process_common(
|
ep.process_common(config, cx, ocsp_response, hello, resumedata, extra_exts)?;
|
||||||
config,
|
|
||||||
cx,
|
|
||||||
ocsp_response,
|
|
||||||
sct_list,
|
|
||||||
hello,
|
|
||||||
resumedata,
|
|
||||||
extra_exts,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let early_data = decide_if_early_data_allowed(cx, hello, resumedata, suite, config);
|
let early_data = decide_if_early_data_allowed(cx, hello, resumedata, suite, config);
|
||||||
if early_data == EarlyDataDecision::Accepted {
|
if early_data == EarlyDataDecision::Accepted {
|
||||||
|
@ -751,7 +739,6 @@ mod client_hello {
|
||||||
common: &mut CommonState,
|
common: &mut CommonState,
|
||||||
cert_chain: &[Certificate],
|
cert_chain: &[Certificate],
|
||||||
ocsp_response: Option<&[u8]>,
|
ocsp_response: Option<&[u8]>,
|
||||||
sct_list: Option<&[u8]>,
|
|
||||||
) {
|
) {
|
||||||
let mut cert_entries = vec![];
|
let mut cert_entries = vec![];
|
||||||
for cert in cert_chain {
|
for cert in cert_chain {
|
||||||
|
@ -772,13 +759,6 @@ mod client_hello {
|
||||||
.exts
|
.exts
|
||||||
.push(CertificateExtension::CertificateStatus(cst));
|
.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);
|
let cert_body = CertificatePayloadTLS13::new(cert_entries);
|
||||||
|
|
|
@ -44,11 +44,6 @@ pub struct CertifiedKey {
|
||||||
/// An optional OCSP response from the certificate issuer,
|
/// An optional OCSP response from the certificate issuer,
|
||||||
/// attesting to its continued validity.
|
/// attesting to its continued validity.
|
||||||
pub ocsp: Option<Vec<u8>>,
|
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 {
|
impl CertifiedKey {
|
||||||
|
@ -61,7 +56,6 @@ impl CertifiedKey {
|
||||||
cert,
|
cert,
|
||||||
key,
|
key,
|
||||||
ocsp: None,
|
ocsp: None,
|
||||||
sct_list: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::error::{
|
||||||
};
|
};
|
||||||
use crate::key::{Certificate, ParsedCertificate};
|
use crate::key::{Certificate, ParsedCertificate};
|
||||||
#[cfg(feature = "logging")]
|
#[cfg(feature = "logging")]
|
||||||
use crate::log::{debug, trace, warn};
|
use crate::log::trace;
|
||||||
use crate::msgs::base::PayloadU16;
|
use crate::msgs::base::PayloadU16;
|
||||||
use crate::msgs::codec::{Codec, Reader};
|
use crate::msgs::codec::{Codec, Reader};
|
||||||
use crate::msgs::handshake::DistinguishedName;
|
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
|
/// the implementor to handle invalid data. It is recommended that the implementor returns
|
||||||
/// [`Error::InvalidCertificate(CertificateError::BadEncoding)`] when these cases are encountered.
|
/// [`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
|
/// [Certificate]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2
|
||||||
fn verify_server_cert(
|
fn verify_server_cert(
|
||||||
&self,
|
&self,
|
||||||
end_entity: &Certificate,
|
end_entity: &Certificate,
|
||||||
intermediates: &[Certificate],
|
intermediates: &[Certificate],
|
||||||
server_name: &ServerName,
|
server_name: &ServerName,
|
||||||
scts: &mut dyn Iterator<Item = &[u8]>,
|
|
||||||
ocsp_response: &[u8],
|
ocsp_response: &[u8],
|
||||||
now: SystemTime,
|
now: SystemTime,
|
||||||
) -> Result<ServerCertVerified, Error>;
|
) -> Result<ServerCertVerified, Error>;
|
||||||
|
@ -187,16 +183,6 @@ pub trait ServerCertVerifier: Send + Sync {
|
||||||
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
||||||
WebPkiVerifier::verification_schemes()
|
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 {
|
impl fmt::Debug for dyn ServerCertVerifier {
|
||||||
|
@ -392,7 +378,6 @@ impl ServerCertVerifier for WebPkiVerifier {
|
||||||
end_entity: &Certificate,
|
end_entity: &Certificate,
|
||||||
intermediates: &[Certificate],
|
intermediates: &[Certificate],
|
||||||
server_name: &ServerName,
|
server_name: &ServerName,
|
||||||
scts: &mut dyn Iterator<Item = &[u8]>,
|
|
||||||
ocsp_response: &[u8],
|
ocsp_response: &[u8],
|
||||||
now: SystemTime,
|
now: SystemTime,
|
||||||
) -> Result<ServerCertVerified, Error> {
|
) -> Result<ServerCertVerified, Error> {
|
||||||
|
@ -400,10 +385,6 @@ impl ServerCertVerifier for WebPkiVerifier {
|
||||||
|
|
||||||
verify_server_cert_signed_by_trust_anchor(&cert, &self.roots, intermediates, now)?;
|
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() {
|
if !ocsp_response.is_empty() {
|
||||||
trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec());
|
trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec());
|
||||||
}
|
}
|
||||||
|
@ -418,7 +399,6 @@ impl ServerCertVerifier for WebPkiVerifier {
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))]
|
||||||
pub struct WebPkiVerifier {
|
pub struct WebPkiVerifier {
|
||||||
roots: RootCertStore,
|
roots: RootCertStore,
|
||||||
ct_policy: Option<CertificateTransparencyPolicy>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unreachable_pub)]
|
#[allow(unreachable_pub)]
|
||||||
|
@ -426,12 +406,8 @@ impl WebPkiVerifier {
|
||||||
/// Constructs a new `WebPkiVerifier`.
|
/// Constructs a new `WebPkiVerifier`.
|
||||||
///
|
///
|
||||||
/// `roots` is the set of trust anchors to trust for issuing server certs.
|
/// `roots` is the set of trust anchors to trust for issuing server certs.
|
||||||
///
|
pub fn new(roots: RootCertStore) -> Self {
|
||||||
/// `ct_logs` is the list of logs that are trusted for Certificate
|
Self { roots }
|
||||||
/// 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 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the signature verification methods supported by
|
/// 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]> {
|
fn intermediate_chain(intermediates: &[Certificate]) -> Vec<&[u8]> {
|
||||||
intermediates
|
intermediates
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -920,16 +819,6 @@ fn verify_tls13(
|
||||||
.map(|_| HandshakeSignatureValid::assertion())
|
.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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -213,8 +213,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bench(&self, count: usize) {
|
fn bench(&self, count: usize) {
|
||||||
let verifier = verify::WebPkiVerifier::new(self.roots.clone(), None);
|
let verifier = verify::WebPkiVerifier::new(self.roots.clone());
|
||||||
const SCTS: &[&[u8]] = &[];
|
|
||||||
const OCSP_RESPONSE: &[u8] = &[];
|
const OCSP_RESPONSE: &[u8] = &[];
|
||||||
let mut times = Vec::new();
|
let mut times = Vec::new();
|
||||||
|
|
||||||
|
@ -227,7 +226,6 @@ impl Context {
|
||||||
end_entity,
|
end_entity,
|
||||||
intermediates,
|
intermediates,
|
||||||
&server_name,
|
&server_name,
|
||||||
&mut SCTS.iter().copied(),
|
|
||||||
OCSP_RESPONSE,
|
OCSP_RESPONSE,
|
||||||
self.now,
|
self.now,
|
||||||
)
|
)
|
||||||
|
|
|
@ -157,7 +157,6 @@ pub struct MockServerVerifier {
|
||||||
cert_rejection_error: Option<Error>,
|
cert_rejection_error: Option<Error>,
|
||||||
tls12_signature_error: Option<Error>,
|
tls12_signature_error: Option<Error>,
|
||||||
tls13_signature_error: Option<Error>,
|
tls13_signature_error: Option<Error>,
|
||||||
wants_scts: bool,
|
|
||||||
signature_schemes: Vec<SignatureScheme>,
|
signature_schemes: Vec<SignatureScheme>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,14 +166,12 @@ impl ServerCertVerifier for MockServerVerifier {
|
||||||
end_entity: &rustls::Certificate,
|
end_entity: &rustls::Certificate,
|
||||||
intermediates: &[rustls::Certificate],
|
intermediates: &[rustls::Certificate],
|
||||||
server_name: &rustls::ServerName,
|
server_name: &rustls::ServerName,
|
||||||
scts: &mut dyn Iterator<Item = &[u8]>,
|
|
||||||
oscp_response: &[u8],
|
oscp_response: &[u8],
|
||||||
now: std::time::SystemTime,
|
now: std::time::SystemTime,
|
||||||
) -> Result<ServerCertVerified, Error> {
|
) -> Result<ServerCertVerified, Error> {
|
||||||
let scts: Vec<Vec<u8>> = scts.map(|x| x.to_owned()).collect();
|
|
||||||
println!(
|
println!(
|
||||||
"verify_server_cert({:?}, {:?}, {:?}, {:?}, {:?}, {:?})",
|
"verify_server_cert({:?}, {:?}, {:?}, {:?}, {:?})",
|
||||||
end_entity, intermediates, server_name, scts, oscp_response, now
|
end_entity, intermediates, server_name, oscp_response, now
|
||||||
);
|
);
|
||||||
if let Some(error) = &self.cert_rejection_error {
|
if let Some(error) = &self.cert_rejection_error {
|
||||||
Err(error.clone())
|
Err(error.clone())
|
||||||
|
@ -220,11 +217,6 @@ impl ServerCertVerifier for MockServerVerifier {
|
||||||
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
|
||||||
self.signature_schemes.clone()
|
self.signature_schemes.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_scts(&self) -> bool {
|
|
||||||
println!("request_scts? {:?}", self.wants_scts);
|
|
||||||
self.wants_scts
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockServerVerifier {
|
impl MockServerVerifier {
|
||||||
|
@ -270,7 +262,6 @@ impl Default for MockServerVerifier {
|
||||||
cert_rejection_error: None,
|
cert_rejection_error: None,
|
||||||
tls12_signature_error: None,
|
tls12_signature_error: None,
|
||||||
tls13_signature_error: None,
|
tls13_signature_error: None,
|
||||||
wants_scts: false,
|
|
||||||
signature_schemes: WebPkiVerifier::verification_schemes(),
|
signature_schemes: WebPkiVerifier::verification_schemes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue