From 04caecad6b6fd510ce135a0da3f29edf009d7fa5 Mon Sep 17 00:00:00 2001 From: Joe Hirschfeld Date: Sat, 9 Jan 2021 14:03:08 -0800 Subject: [PATCH] Permit trusted self-signed certificates Self-signed certificates are both an end-entity as well as a certificate authority in the eyes of webpki - since we have ultimate trust in the supplied trust anchors, a certificate supplied with the same subject as a trust anchor and is directly signed by the same trust anchor should also be valid, even though the certificate supplied might still be a CA. --- Cargo.toml | 1 + src/verify_cert.rs | 16 ++++++++++++++-- tests/integration.rs | 17 +++++++++++++++++ tests/misc/selfsigned.der | Bin 0 -> 322 bytes 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/misc/selfsigned.der diff --git a/Cargo.toml b/Cargo.toml index 98bdd949..5d3bc3f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ include = [ "tests/dns_name_tests.rs", "tests/integration.rs", + "tests/misc/selfsigned.der", "tests/misc/serial_neg.der", "tests/misc/serial_zero.der", "tests/netflix/ca.der", diff --git a/src/verify_cert.rs b/src/verify_cert.rs index 1a52b7b1..17906046 100644 --- a/src/verify_cert.rs +++ b/src/verify_cert.rs @@ -28,13 +28,17 @@ pub fn build_chain( ) -> Result<(), Error> { let used_as_ca = used_as_ca(&cert.ee_or_ca); - check_issuer_independent_properties( + let must_be_self_signed = match check_issuer_independent_properties( cert, time, used_as_ca, sub_ca_count, required_eku_if_present, - )?; + ) { + Ok(()) => false, + Err(Error::CAUsedAsEndEntity) => true, + Err(e) => return Err(e), + }; // TODO: HPKP checks. @@ -71,6 +75,10 @@ pub fn build_chain( check_signatures(supported_sig_algs, cert, trust_anchor_spki)?; + if must_be_self_signed && trust_anchor_subject != cert.subject { + return Err(Error::CAUsedAsEndEntity); + } + Ok(()) }) { Ok(()) => { @@ -81,6 +89,10 @@ pub fn build_chain( } } + if must_be_self_signed { + return Err(Error::CAUsedAsEndEntity); + } + loop_while_non_fatal_error(intermediate_certs, |cert_der| { let potential_issuer = cert::parse_cert(untrusted::Input::from(*cert_der), EndEntityOrCA::CA(&cert))?; diff --git a/tests/integration.rs b/tests/integration.rs index 8e7abddc..f0053b68 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -84,6 +84,23 @@ fn read_root_with_neg_serial() { .expect("idcat cert should parse as anchor"); } +#[test] +fn selfsigned() { + let cert = include_bytes!("misc/selfsigned.der"); + + let anchors = vec![webpki::trust_anchor_util::cert_der_as_trust_anchor(cert).unwrap()]; + let anchors = webpki::TLSServerTrustAnchors(&anchors); + + #[allow(clippy::unreadable_literal)] // TODO: Make this clear. + let time = webpki::Time::from_seconds_since_unix_epoch(1610233207); + + let cert = webpki::EndEntityCert::from(cert).unwrap(); + assert_eq!( + Ok(()), + cert.verify_is_valid_tls_server_cert(ALL_SIGALGS, &anchors, &[], time) + ); +} + #[cfg(feature = "std")] #[test] fn time_constructor() { diff --git a/tests/misc/selfsigned.der b/tests/misc/selfsigned.der new file mode 100644 index 0000000000000000000000000000000000000000..1e0a50233f55096c15e06a44deb90d1b42c141cc GIT binary patch literal 322 zcmXqLVze`8{J4ObiIIs(L^qIg>e)2mLk*Vye%tnKUnDK`xYmG`jafUjz(CYc*g%kt zIh2K&hpRX>C#^U$JufxIKu(<3$k4#hz|zRb)WXy(3d}V!uz+%LY14ul%dE(7cHf$o z6ZP4(ExfiNTEe->5)W*`N#-jN~K`%qi`)y0cX zy${VWN?5lkS+-F7;i^VK9-%bH6oF+uyXr!OtL85_=veXj*@pPgjk|?ZZ8l!l-r-%l K*xA}9jvWAnrg5zR literal 0 HcmV?d00001