| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 57bc62c commit 1219622
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -126,10 +126,12 @@ fn check_presented_id_conforms_to_constraints( | |||
| 126 | 126 | Err(err) => return Some(Err(err)), | |
| 127 | 127 | }; | |
| 128 | 128 | ||
| 129 | + // Avoid having a catch-all branch here which might fail open on new variants | ||
| 129 | 130 | let matches = match (name, base) { | |
| 130 | 131 | (GeneralName::DnsName(name), GeneralName::DnsName(base)) => { | |
| 131 | 132 | dns_name::presented_id_matches_reference_id(name, IdRole::NameConstraint, base) | |
| 132 | 133 | } | |
| 134 | + (GeneralName::DnsName(_), _) => continue, | ||
| 133 | 135 | ||
| 134 | 136 | (GeneralName::DirectoryName, GeneralName::DirectoryName) => Ok( | |
| 135 | 137 | // Reject any uses of directory name constraints; we don't implement this. | |
@@ -150,10 +152,19 @@ fn check_presented_id_conforms_to_constraints( | |||
| 150 | 152 | Subtrees::ExcludedSubtrees => true, | |
| 151 | 153 | }, | |
| 152 | 154 | ), | |
| 155 | + (GeneralName::DirectoryName, _) => continue, | ||
| 153 | 156 | ||
| 154 | 157 | (GeneralName::IpAddress(name), GeneralName::IpAddress(base)) => { | |
| 155 | 158 | ip_address::presented_id_matches_constraint(name, base) | |
| 156 | 159 | } | |
| 160 | + (GeneralName::IpAddress(_), _) => continue, | ||
| 161 | + | ||
| 162 | + // We currently don't support URI constraints -- fail closed for now. | ||
| 163 | + ( | ||
| 164 | + GeneralName::UniformResourceIdentifier(_), | ||
| 165 | + GeneralName::UniformResourceIdentifier(_), | ||
| 166 | + ) => Ok(false), | ||
| 167 | + (GeneralName::UniformResourceIdentifier(_), _) => continue, | ||
| 157 | 168 | ||
| 158 | 169 | // RFC 4280 says "If a name constraints extension that is marked as | |
| 159 | 170 | // critical imposes constraints on a particular name form, and an | |
@@ -168,12 +179,7 @@ fn check_presented_id_conforms_to_constraints( | |||
| 168 | 179 | { | |
| 169 | 180 | Err(Error::NameConstraintViolation) | |
| 170 | 181 | } | |
| 171 | - | ||
| 172 | - _ => { | ||
| 173 | - // mismatch between constraint and name types; continue with current | ||
| 174 | - // name and next constraint | ||
| 175 | - continue; | ||
| 176 | - } | ||
| 182 | + (GeneralName::Unsupported(_), _) => continue, | ||
| 177 | 183 | }; | |
| 178 | 184 | ||
| 179 | 185 | match (subtrees, matches) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,3 +1,5 @@ | |||
| 1 | + #![allow(dead_code, unreachable_pub)] | ||
| 2 | + | ||
| 1 | 3 | use std::error::Error as StdError; | |
| 2 | 4 | ||
| 3 | 5 | use rcgen::{ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,8 +16,60 @@ | |||
| 16 | 16 | use core::time::Duration; | |
| 17 | 17 | ||
| 18 | 18 | use pki_types::{CertificateDer, ServerName, UnixTime}; | |
| 19 | + use rcgen::{ | ||
| 20 | + Certificate, CertificateParams, CertifiedIssuer, CustomExtension, DnType, IsCa, KeyPair, | ||
| 21 | + SanType, date_time_ymd, | ||
| 22 | + }; | ||
| 19 | 23 | use webpki::{InvalidNameContext, KeyUsage, anchor_from_trusted_cert}; | |
| 20 | 24 | ||
| 25 | + mod common; | ||
| 26 | + use common::issuer_params; | ||
| 27 | + | ||
| 28 | + /// Since we don't have real constraint matching implemented for URI names, fail closed. | ||
| 29 | + #[test] | ||
| 30 | + fn uri_san_rejected_against_uri_permitted_subtree() { | ||
| 31 | + let ca_key = KeyPair::generate().unwrap(); | ||
| 32 | + let mut ca_params = issuer_params("issuer.example.com").unwrap(); | ||
| 33 | + ca_params | ||
| 34 | + .custom_extensions | ||
| 35 | + .push(uri_permitted_name_constraints( | ||
| 36 | + b"https://allowed.example.com", | ||
| 37 | + )); | ||
| 38 | + let issuer = CertifiedIssuer::self_signed(ca_params, ca_key).expect("failed to generate CA"); | ||
| 39 | + | ||
| 40 | + let ee = generate_cert( | ||
| 41 | + vec![SanType::URI("https://evil.example.com".try_into().unwrap())], | ||
| 42 | + &issuer, | ||
| 43 | + ); | ||
| 44 | + assert_eq!( | ||
| 45 | + check_cert(ee.der(), issuer.der(), &[], &[], &[]), | ||
| 46 | + Err(webpki::Error::NameConstraintViolation), | ||
| 47 | + ); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + // Hand-encode a NameConstraints extension (OID 2.5.29.30) with a single | ||
| 51 | + // permittedSubtree containing a URI GeneralName. rcgen's GeneralSubtree enum | ||
| 52 | + // doesn't expose a URI variant, so we emit the DER directly. | ||
| 53 | + fn uri_permitted_name_constraints(uri: &[u8]) -> CustomExtension { | ||
| 54 | + assert!(uri.len() < 128); | ||
| 55 | + // URI GeneralName: [6] IMPLICIT IA5String | ||
| 56 | + let mut uri_gn = vec![0x86, uri.len() as u8]; | ||
| 57 | + uri_gn.extend_from_slice(uri); | ||
| 58 | + // GeneralSubtree SEQUENCE { base GeneralName, ... } | ||
| 59 | + let mut subtree = vec![0x30, uri_gn.len() as u8]; | ||
| 60 | + subtree.extend_from_slice(&uri_gn); | ||
| 61 | + // permittedSubtrees [0] IMPLICIT GeneralSubtrees | ||
| 62 | + let mut permitted = vec![0xa0, subtree.len() as u8]; | ||
| 63 | + permitted.extend_from_slice(&subtree); | ||
| 64 | + // NameConstraints SEQUENCE | ||
| 65 | + let mut nc = vec![0x30, permitted.len() as u8]; | ||
| 66 | + nc.extend_from_slice(&permitted); | ||
| 67 | + | ||
| 68 | + let mut ext = CustomExtension::from_oid_content(&[2, 5, 29, 30], nc); | ||
| 69 | + ext.set_criticality(true); | ||
| 70 | + ext | ||
| 71 | + } | ||
| 72 | + | ||
| 21 | 73 | #[track_caller] | |
| 22 | 74 | fn check_cert( | |
| 23 | 75 | ee: &[u8], | |
@@ -61,6 +113,45 @@ fn check_cert( | |||
| 61 | 113 | Ok(()) | |
| 62 | 114 | } | |
| 63 | 115 | ||
| 116 | + fn generate_cert(sans: Vec<SanType>, issuer: &CertifiedIssuer<'_, KeyPair>) -> Certificate { | ||
| 117 | + generate_cert_with_names(None, None, sans, issuer) | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + fn generate_cert_with_names( | ||
| 121 | + subject_cn: Option<&str>, | ||
| 122 | + subject_email: Option<&str>, | ||
| 123 | + sans: Vec<SanType>, | ||
| 124 | + issuer: &CertifiedIssuer<'_, KeyPair>, | ||
| 125 | + ) -> Certificate { | ||
| 126 | + let (not_before, not_after) = (date_time_ymd(1970, 1, 1), date_time_ymd(2050, 1, 1)); | ||
| 127 | + | ||
| 128 | + // Generate end entity certificate | ||
| 129 | + let ee_key = KeyPair::generate().unwrap(); | ||
| 130 | + let mut ee_params = CertificateParams::new([]).expect("failed to create EE params"); | ||
| 131 | + ee_params.subject_alt_names = sans; | ||
| 132 | + if let Some(cn) = subject_cn { | ||
| 133 | + ee_params.distinguished_name.push(DnType::CommonName, cn); | ||
| 134 | + } | ||
| 135 | + if let Some(email) = subject_email { | ||
| 136 | + ee_params | ||
| 137 | + .distinguished_name | ||
| 138 | + .push(DnType::from_oid(OID_EMAIL_ADDRESS), email); | ||
| 139 | + } | ||
| 140 | + ee_params | ||
| 141 | + .distinguished_name | ||
| 142 | + .push(DnType::OrganizationName, "test"); | ||
| 143 | + ee_params.is_ca = IsCa::ExplicitNoCa; | ||
| 144 | + ee_params.not_before = not_before; | ||
| 145 | + ee_params.not_after = not_after; | ||
| 146 | + | ||
| 147 | + ee_params | ||
| 148 | + .signed_by(&ee_key, issuer) | ||
| 149 | + .expect("failed to generate EE cert") | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + // OID for emailAddress in subject DN (pkcs9-emailAddress) | ||
| 153 | + const OID_EMAIL_ADDRESS: &[u64] = &[1, 2, 840, 113549, 1, 9, 1]; | ||
| 154 | + | ||
| 64 | 155 | // DO NOT EDIT BELOW: generated by tests/generate.py | |
| 65 | 156 | ||
| 66 | 157 | #[test] | |
| Back | FazBrowse Home | New Git URL |
0 commit comments