Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rust: add crate skeleton for X.509 path validation #8873

Merged
merged 193 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from 123 commits
Commits
Show all changes
193 commits
Select commit Hold shift + click to select a range
69eb9a1
src, tests: flatten all changes
woodruffw Sep 7, 2023
cb8a316
Merge remote-tracking branch 'origin/main' into tob-x509-cv-skeleton
woodruffw Oct 2, 2023
7e1f72a
make `cargo doc` happy
woodruffw Oct 3, 2023
ade49a1
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 5, 2023
30509a8
verify: move API to ServerVerifier.verify
woodruffw Oct 5, 2023
4658f70
fix tests
woodruffw Oct 5, 2023
1420533
extensions: derive Eq
woodruffw Oct 5, 2023
43999ac
policy: another Eq derive
woodruffw Oct 5, 2023
c220117
[DEMO] declarative extension policies
woodruffw Oct 5, 2023
25655ad
more extension policy refactoring
woodruffw Oct 5, 2023
7c77155
fixup tests
woodruffw Oct 6, 2023
352d9cf
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 6, 2023
b7205be
rust: support name constraints (#4)
tetsuo-cpp Oct 6, 2023
d663c07
types: clippage
woodruffw Oct 6, 2023
0af2218
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Oct 7, 2023
5285a9a
rust: check for malformed `AuthorityInformationAccess` extension (#5)
tetsuo-cpp Oct 16, 2023
9713022
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 16, 2023
4de63fc
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 18, 2023
2adf177
validation: refactor maybe_present extn handling
woodruffw Oct 19, 2023
7f550db
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 19, 2023
71bd69d
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Oct 22, 2023
625fa41
tests: Add `x509-limbo` test (#1)
tetsuo-cpp Oct 24, 2023
4745642
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 24, 2023
ba37c80
rust: Use extension policy mechanism to check for unaccounted critica…
tetsuo-cpp Oct 24, 2023
21b8026
clippy fixes
woodruffw Oct 24, 2023
2232868
derive Eq
woodruffw Oct 24, 2023
d91f976
policy: clippage
woodruffw Oct 24, 2023
9e04a6a
remove double negative
woodruffw Oct 24, 2023
0f21360
test_verification: move asserts
woodruffw Oct 24, 2023
9ff4070
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 26, 2023
8d9d223
drop unused From impl
woodruffw Oct 26, 2023
5ef5ecb
Revert "drop unused From impl"
woodruffw Oct 26, 2023
9d46d04
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Oct 28, 2023
f02458e
fixup AKI handling, update limbo
woodruffw Oct 28, 2023
95ac2e7
bump limbo
woodruffw Oct 28, 2023
5153a69
bump limbo suite
woodruffw Oct 29, 2023
f54ce64
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Oct 30, 2023
8a702a9
validation/policy: clean up TODOs and NOTEs a bit
woodruffw Oct 30, 2023
f59cbed
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 30, 2023
a356e05
validation/policy: drop unreachable check
woodruffw Oct 30, 2023
9d5a313
vectors: bump limbo
woodruffw Oct 31, 2023
457df90
policy: check for 0 SN explicitly
woodruffw Oct 31, 2023
c54bced
vectors: bump limbo
woodruffw Oct 31, 2023
5e72f8b
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Oct 31, 2023
c91e13f
WIP docs
woodruffw Oct 31, 2023
7b8f5a3
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Oct 31, 2023
e8b4fbc
verification: fixup docs
woodruffw Oct 31, 2023
7aefd2a
validation: make subject non-optional (#7)
woodruffw Nov 2, 2023
504dd59
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 2, 2023
34202c4
vectors: bump limbo
woodruffw Nov 2, 2023
fb362bd
vectors: bump limbo
woodruffw Nov 2, 2023
ce4e907
validation/policies: turn permits_san into an extension validator (#8)
woodruffw Nov 2, 2023
daa512d
vectors: bump limbo
woodruffw Nov 2, 2023
53e6761
validation: move v3 check to permits_basic
woodruffw Nov 2, 2023
0259030
vectors: bump limbo
woodruffw Nov 2, 2023
a9a380f
validation: put EKU handling under ext handling
woodruffw Nov 2, 2023
a9d8dc9
tests, vectors: bump limbo
woodruffw Nov 2, 2023
199ba0d
fixup isort
woodruffw Nov 2, 2023
956c1b8
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 3, 2023
52977bd
vectors: bump limbo
woodruffw Nov 3, 2023
a163676
validation: refactor depth checks
woodruffw Nov 3, 2023
b0d8477
mod: comment
woodruffw Nov 3, 2023
a4f4ea9
vectors: bump limbo
woodruffw Nov 3, 2023
58261a2
vectors: bump limbo
woodruffw Nov 3, 2023
0282239
[WIP] vectors: bump limbo
woodruffw Nov 3, 2023
c086393
vectors: bump limbo
woodruffw Nov 3, 2023
107c082
lib: Convert duplicate extension errors explicitly (#10)
facutuesca Nov 3, 2023
be6d3d8
vectors: bump limbo
woodruffw Nov 3, 2023
36654c1
lib: remove another From impl
woodruffw Nov 3, 2023
6bed9db
vectors: bump limbo
woodruffw Nov 3, 2023
6d3714c
vectors: bump limbo
facutuesca Nov 6, 2023
5afa0a7
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 6, 2023
7546674
validation: Add `max_chain_depth` parameter to `ServerVerifier` (#9)
tetsuo-cpp Nov 9, 2023
af0d43b
test_verification: add already-set test for max_chain_depth
woodruffw Nov 9, 2023
acdf068
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 9, 2023
e5d62a3
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 9, 2023
06e1be5
verification: fix bad merge
woodruffw Nov 9, 2023
fe39fb9
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 9, 2023
329eed5
remove commented code, redundant tests
woodruffw Nov 9, 2023
4017871
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 9, 2023
c0ec72f
actions: add a fetch-limbo action
woodruffw Nov 9, 2023
c270e4a
tests: prep limbo a la wycheproof
woodruffw Nov 9, 2023
7434373
tests: migrate limbo
woodruffw Nov 9, 2023
363dee3
Merge branch 'tob-generic-fetch-vectors' into tob-x509-cv-skeleton
woodruffw Nov 9, 2023
efc8f29
ci: use fetch-limbo
woodruffw Nov 9, 2023
3e838c7
remove hardcopied limbo
woodruffw Nov 9, 2023
79fe0b4
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 10, 2023
f7fdeaf
tests: remove test_verify_basic
woodruffw Nov 10, 2023
913f723
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 10, 2023
ab7de49
validation/certificate: remove dead_code attrs
woodruffw Nov 10, 2023
421594a
validation/extension: remove more dead_code attrs
woodruffw Nov 10, 2023
8fd2684
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 13, 2023
ef9061f
verify: simplify types
woodruffw Nov 13, 2023
bf3b3cb
document, enforce chain order
woodruffw Nov 13, 2023
ea88d53
lib: simplify is_match
woodruffw Nov 13, 2023
7bfab59
Update src/rust/cryptography-x509-validation/src/lib.rs
woodruffw Nov 13, 2023
97c551f
validation/lib: return impl iterator
woodruffw Nov 13, 2023
db05265
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 13, 2023
669bb22
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 13, 2023
af14ec4
validation/ops: remove old coverage stub
woodruffw Nov 13, 2023
eac3a07
test_limbo: remove assert messages
woodruffw Nov 13, 2023
af29fec
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 13, 2023
4168322
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 13, 2023
062a64b
drastically simplify lifetimes
woodruffw Nov 13, 2023
ace8142
test_verification: remove unused import
woodruffw Nov 13, 2023
9793bb2
validation/lib: Remove unnecessary `AccumulatedNameConstraints` type
tetsuo-cpp Nov 14, 2023
d498f67
validation/lib: Use `cert_is_self_issued` for potential issuers
tetsuo-cpp Nov 14, 2023
2f52dd0
validation/lib: Flip condition
tetsuo-cpp Nov 14, 2023
c40761f
validation/lib: Use `cert_is_self_signed`
tetsuo-cpp Nov 14, 2023
e0c377d
validation/lib: Reduce calls to `Certificate::extensions`
tetsuo-cpp Nov 14, 2023
269ef79
validation/lib: Remove more calls to `extensions`
tetsuo-cpp Nov 14, 2023
90162e4
validation/policy: Check for overflow of current depth
tetsuo-cpp Nov 14, 2023
adc7333
validation/policy: Check validity dates for generalized date cutoff
tetsuo-cpp Nov 14, 2023
0c5ff83
validation/policy: Check for negative serial numbers
tetsuo-cpp Nov 14, 2023
2ce7a34
validation: only check spki and signature_alg when verifying sigs
woodruffw Nov 14, 2023
0f6214f
validation: add API TODO
woodruffw Nov 15, 2023
55e82f7
test_limbo: more features
woodruffw Nov 15, 2023
bf12b48
policy/extension: allow missing AKI on CAs
woodruffw Nov 15, 2023
e665d3b
tests/limbo: skip webpki::aki::root-with-aki-ski-mismatch
woodruffw Nov 15, 2023
a14634d
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 16, 2023
ba7dbf3
tests: Remove `pedantic-webpki` from unsupported list
tetsuo-cpp Nov 17, 2023
8d06d26
validation/policy: Remove unused conversion
tetsuo-cpp Nov 17, 2023
0d98eaf
validation/policy: Add unit tests for validity dates
tetsuo-cpp Nov 17, 2023
6be1f50
ci: remove a line
woodruffw Nov 17, 2023
76abe1f
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 17, 2023
09377a5
validation: flatten error types
woodruffw Nov 17, 2023
1a4cf74
validation: remove unnecessary From impls
woodruffw Nov 17, 2023
e93bc07
validation: render OIDs in a few errors
woodruffw Nov 17, 2023
0cf2e52
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 17, 2023
c9642e9
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 17, 2023
6c577be
validation/policy: free coverage
woodruffw Nov 17, 2023
a860232
validation/policy: ok_or_else (no escaping the coverage gods)
woodruffw Nov 18, 2023
d231e1e
validation/policy: remove no-op branch
woodruffw Nov 20, 2023
7b4c2c0
validation: add EKU note
woodruffw Nov 20, 2023
5ee09e5
validation: add invariant-preserving Intermediates type
woodruffw Nov 20, 2023
bd1553f
validation: better error message
woodruffw Nov 20, 2023
89067e2
invert conditions
woodruffw Nov 20, 2023
adeb62d
validation: rewrite error handling
woodruffw Nov 20, 2023
518da01
lib: misleading comment
woodruffw Nov 20, 2023
f964ce7
test_limbo: handle IPv6 addresses correctly
woodruffw Nov 21, 2023
48af1c5
test_limbo: add another feature flag
woodruffw Nov 22, 2023
c79f40b
validation/extensions: add some NC checks
woodruffw Nov 22, 2023
a29c73e
lintage
woodruffw Nov 22, 2023
bab3d2a
validation/extension: fix subtree check
woodruffw Nov 22, 2023
8135121
validation/extension: remove pedantic check
woodruffw Nov 22, 2023
b3ae108
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 23, 2023
31d7d81
validation: avoid an intermediate vector
woodruffw Nov 23, 2023
d294958
validation: `&Vec<_>` -> `&[_]`
woodruffw Nov 23, 2023
d1b0a33
validation: search the store first
woodruffw Nov 23, 2023
6c2eafe
validation: simplify match
woodruffw Nov 23, 2023
f591c12
validation: rename IntermediateChain -> PartialChainState
woodruffw Nov 23, 2023
1adf14f
policy/extension: add a NOTE about pathLength validation
woodruffw Nov 23, 2023
9ce06d0
tests/x509: restructure verification tests
woodruffw Nov 23, 2023
030b79f
test_limbo: update ID
woodruffw Nov 24, 2023
b6de1f9
validation: expand NC skip comment
woodruffw Nov 24, 2023
6e6d7c7
validation: fixup NC handling, expose NC errors
woodruffw Nov 24, 2023
120daf5
Merge branch 'main' into tob-x509-cv-skeleton
woodruffw Nov 24, 2023
6607e75
validation: remove unreachable error case
woodruffw Nov 24, 2023
24ecf76
validation: remove unnecessary clone
woodruffw Nov 24, 2023
3060a70
validation: handle malformed SANs in NC checking
woodruffw Nov 25, 2023
e1ee967
validation: allow SN==0
woodruffw Nov 25, 2023
642e72e
validation: remove redundant branch
woodruffw Nov 26, 2023
c6d502e
validation: relax SKI check on CA certs
woodruffw Nov 26, 2023
e26feb8
validation: document BC handling
woodruffw Nov 26, 2023
b1e8d2a
validation: document precondition on valid_issuer
woodruffw Nov 26, 2023
91c30d5
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Nov 30, 2023
dcc7069
validation: make EKU in EEs optional
woodruffw Nov 30, 2023
1ed7c2b
validation: make EKU handling common
woodruffw Dec 1, 2023
e4c33bb
[WIP] validation: refactor name constraints handling
woodruffw Dec 1, 2023
98d5502
Merge remote-tracking branch 'upstream/main' into tob-x509-cv-skeleton
woodruffw Dec 18, 2023
baaeeb2
src, tests: remove self-issued special-casing
woodruffw Dec 18, 2023
6c886b5
lintage
woodruffw Dec 18, 2023
a167fd2
validation: remove NullOps
woodruffw Dec 19, 2023
9926b98
validation: feedback
woodruffw Dec 19, 2023
d4a876f
validation: remove unnecessary second loop
woodruffw Dec 19, 2023
474a925
tests/limbo: fixup schema assertions
woodruffw Dec 20, 2023
8152578
validation: remove no-op match
woodruffw Dec 20, 2023
5244884
Update src/rust/cryptography-x509-validation/src/policy/mod.rs
woodruffw Dec 20, 2023
be84030
policy: u64::from
woodruffw Dec 20, 2023
27b2b0d
test_limbo: assert that intermediates come from untrusted_intermediates
woodruffw Dec 20, 2023
0220e93
validation: simplify match exprs
woodruffw Dec 20, 2023
35de5fd
lib: apply_inner -> apply_single_constraint
woodruffw Dec 20, 2023
07f2445
test_limbo: open limbo.json in binary mode
woodruffw Dec 20, 2023
d5b8a45
validation: simplify, fix NC validation
woodruffw Dec 21, 2023
c52b597
lib: remove unused default derive
woodruffw Dec 21, 2023
6e7379a
policy: add NOTE, relax EKU check
woodruffw Dec 21, 2023
7830bad
validation: move SAN matching to permits_leaf
woodruffw Dec 21, 2023
e16a347
break apart EKU handling by EE/CA
woodruffw Dec 21, 2023
1e00199
validation: reorder permits_leaf for coverage
woodruffw Dec 21, 2023
fee2aa3
src, tests: remove CA-in-leaf-position support
woodruffw Dec 21, 2023
b65d12f
validation: unwrap and explain why
woodruffw Dec 21, 2023
6aa642c
validation: remove permits_leaf entirely
woodruffw Dec 22, 2023
0fc7327
validation/policy: fix validity_date GeneralizedTime check
woodruffw Dec 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ jobs:
timeout-minutes: 2
uses: ./.github/actions/fetch-vectors
if: matrix.PYTHON.NOXSESSION != 'flake' && matrix.PYTHON.NOXSESSION != 'docs' && matrix.PYTHON.NOXSESSION != 'rust'

- name: Compute config hash and set config vars
run: |
DEFAULT_CONFIG_FLAGS="shared no-ssl2 no-ssl3"
Expand Down
3 changes: 0 additions & 3 deletions src/rust/cryptography-x509-validation/src/certificate.rs
alex marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@ use cryptography_x509::certificate::Certificate;

use crate::ops::CryptoOps;

// TODO: Remove these attributes once we start using these helpers.
#[allow(dead_code)]
pub(crate) fn cert_is_self_issued(cert: &Certificate<'_>) -> bool {
cert.issuer() == cert.subject()
}

#[allow(dead_code)]
pub(crate) fn cert_is_self_signed<B: CryptoOps>(cert: &Certificate<'_>, ops: &B) -> bool {
match ops.public_key(cert) {
Ok(pk) => cert_is_self_issued(cert) && ops.verify_signed_by(cert, pk).is_ok(),
Expand Down
277 changes: 277 additions & 0 deletions src/rust/cryptography-x509-validation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,280 @@ pub mod ops;
pub mod policy;
pub mod trust_store;
pub mod types;

use std::collections::HashSet;

use crate::certificate::{cert_is_self_issued, cert_is_self_signed};
use crate::types::{DNSConstraint, IPAddress, IPConstraint};
use crate::ApplyNameConstraintStatus::{Applied, Skipped};
use cryptography_x509::extensions::Extensions;
use cryptography_x509::{
certificate::Certificate,
extensions::{NameConstraints, SubjectAlternativeName},
name::GeneralName,
oid::{NAME_CONSTRAINTS_OID, SUBJECT_ALTERNATIVE_NAME_OID},
};
use ops::CryptoOps;
use policy::{Policy, PolicyError};
use trust_store::Store;
use types::DNSName;

#[derive(Debug, PartialEq, Eq)]
pub enum ValidationError {
Policy(PolicyError),
}

impl From<PolicyError> for ValidationError {
fn from(value: PolicyError) -> Self {
ValidationError::Policy(value)
}
}

pub type Chain<'c> = Vec<Certificate<'c>>;
type IntermediateChain<'c> = (Chain<'c>, Vec<NameConstraints<'c>>);
woodruffw marked this conversation as resolved.
Show resolved Hide resolved

pub fn verify<'a, 'chain, B: CryptoOps>(
leaf: &'a Certificate<'chain>,
intermediates: impl IntoIterator<Item = Certificate<'chain>>,
policy: &Policy<'_, B>,
store: &'a Store<'chain>,
) -> Result<Chain<'chain>, ValidationError> {
let builder = ChainBuilder::new(HashSet::from_iter(intermediates), policy, store);

builder.build_chain(leaf)
}

struct ChainBuilder<'a, 'chain, B: CryptoOps> {
intermediates: HashSet<Certificate<'chain>>,
policy: &'a Policy<'a, B>,
store: &'a Store<'chain>,
}

// When applying a name constraint, we need to distinguish between a few different scenarios:
// * `Applied(true)`: The name constraint is the same type as the SAN and matches.
// * `Applied(false)`: The name constraint is the same type as the SAN and does not match.
// * `Skipped`: The name constraint is a different type to the SAN.
enum ApplyNameConstraintStatus {
Applied(bool),
Skipped,
}

impl ApplyNameConstraintStatus {
fn is_applied(&self) -> bool {
matches!(self, Applied(_))
}

fn is_match(&self) -> bool {
matches!(self, Applied(true))
}
}

impl<'a, 'chain, B: CryptoOps> ChainBuilder<'a, 'chain, B> {
fn new(
intermediates: HashSet<Certificate<'chain>>,
policy: &'a Policy<'a, B>,
store: &'a Store<'chain>,
) -> Self {
Self {
intermediates,
policy,
store,
}
}

fn potential_issuers(
&'a self,
cert: &'a Certificate<'chain>,
) -> impl Iterator<Item = &'a Certificate<'chain>> + '_ {
// TODO: Optimizations:
// * Use a backing structure that allows us to search by name
// rather than doing a linear scan
// * Search by AKI and other identifiers?
self.intermediates
.iter()
// NOTE: The intermediate set isn't allowed to offer a self-signed
// certificate as a candidate, since self-signed certs can only
// be roots.
.filter(|&candidate| !cert_is_self_signed(candidate, &self.policy.ops))
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
.chain(self.store.iter())
.filter(|&candidate| candidate.subject() == cert.issuer())
}

fn build_name_constraints(
&self,
constraints: &mut Vec<NameConstraints<'chain>>,
extensions: &Extensions<'chain>,
) -> Result<(), ValidationError> {
if let Some(nc) = extensions.get_extension(&NAME_CONSTRAINTS_OID) {
let nc: NameConstraints<'chain> = nc.value().map_err(PolicyError::Malformed)?;
constraints.push(nc);
}
Ok(())
}

fn apply_name_constraint(
&self,
constraint: &GeneralName<'chain>,
san: &GeneralName<'_>,
) -> Result<ApplyNameConstraintStatus, ValidationError> {
match (constraint, san) {
(GeneralName::DNSName(pattern), GeneralName::DNSName(name)) => {
if let Some(pattern) = DNSConstraint::new(pattern.0) {
let name = DNSName::new(name.0).unwrap();
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
Ok(Applied(pattern.matches(&name)))
} else {
Err(PolicyError::Other("malformed DNS name constraint").into())
}
}
(GeneralName::IPAddress(pattern), GeneralName::IPAddress(name)) => {
if let Some(pattern) = IPConstraint::from_bytes(pattern) {
let name = IPAddress::from_bytes(name).unwrap();
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
Ok(Applied(pattern.matches(&name)))
} else {
Err(PolicyError::Other("malformed IP name constraint").into())
}
}
_ => Ok(Skipped),
}
}

fn apply_name_constraints(
&self,
constraints: &Vec<NameConstraints<'chain>>,
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
extensions: &Extensions<'chain>,
) -> Result<(), ValidationError> {
if let Some(sans) = extensions.get_extension(&SUBJECT_ALTERNATIVE_NAME_OID) {
let sans: SubjectAlternativeName<'_> = sans.value().map_err(PolicyError::Malformed)?;
for san in sans.clone() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct that all sans need to be allowed by NCs, or only for the name we're validating?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't seem to find where that's detailed in the RFC. However, I can confirm that the Go implementation works that way.

Perhaps I can follow up with a Limbo test to make sure that this behaviour is consistent with other implementations.

// If there are no applicable constraints, the SAN is considered valid so the default is true.
let mut permit = true;
for nc in constraints {
if let Some(permitted_subtrees) = &nc.permitted_subtrees {
for p in permitted_subtrees.unwrap_read().clone() {
let status = self.apply_name_constraint(&p.base, &san)?;
if status.is_applied() {
permit = status.is_match();
if permit {
break;
}
}
}
}
}
if !permit {
return Err(
PolicyError::Other("no permitted name constraints matched SAN").into(),
);
}
for nc in constraints {
if let Some(excluded_subtrees) = &nc.excluded_subtrees {
for e in excluded_subtrees.unwrap_read().clone() {
let status = self.apply_name_constraint(&e.base, &san)?;
if status.is_match() {
return Err(PolicyError::Other(
"excluded name constraint matched SAN",
)
.into());
}
}
}
}
}
}
Ok(())
}

fn build_chain_inner(
&self,
working_cert: &'a Certificate<'chain>,
current_depth: u8,
is_leaf: bool,
extensions: &'a Extensions<'chain>,
) -> Result<IntermediateChain<'chain>, ValidationError> {
if current_depth > self.policy.max_chain_depth {
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
return Err(PolicyError::Other("chain construction exceeds max depth").into());
}

// Look in the store's root set to see if the working cert is listed.
// If it is, we've reached the end.
//
// Observe that no issuer connection or signature verification happens
// here: inclusion in the root set implies a trust relationship,
// even if the working certificate is an EE or intermediate CA.
if self.store.contains(working_cert) {
let mut constraints = vec![];
self.build_name_constraints(&mut constraints, extensions)?;
return Ok((vec![working_cert.clone()], constraints));
}

// Otherwise, we collect a list of potential issuers for this cert,
// and continue with the first that verifies.
for issuing_cert_candidate in self.potential_issuers(working_cert) {
// A candidate issuer is said to verify if it both
// signs for the working certificate and conforms to the
// policy.
let issuer_extensions = issuing_cert_candidate
.extensions()
.map_err(|e| ValidationError::Policy(PolicyError::DuplicateExtension(e)))?;
if let Ok(next_depth) = self.policy.valid_issuer(
issuing_cert_candidate,
working_cert,
current_depth,
&issuer_extensions,
) {
let result = self.build_chain_inner(
issuing_cert_candidate,
next_depth,
false,
&issuer_extensions,
);
if let Ok(result) = result {
let (remaining, mut constraints) = result;
// Name constraints are not applied to self-issued certificates unless they're
// the leaf certificate in the chain.
//
// NOTE: We can't simply check the `current_depth` since self-issued
// certificates don't increase the working depth.
let skip_name_constraints = cert_is_self_issued(working_cert) && !is_leaf;
if skip_name_constraints
|| self
.apply_name_constraints(&constraints, extensions)
.is_ok()
{
let mut chain: Vec<Certificate<'chain>> = vec![working_cert.clone()];
chain.extend(remaining);
self.build_name_constraints(&mut constraints, extensions)?;
return Ok((chain, constraints));
}
}
}
}

// We only reach this if we fail to hit our base case above, or if
// a chain building step fails to find a next valid certificate.
Err(PolicyError::Other("chain construction exhausted all candidates").into())
}

fn build_chain(&self, leaf: &'a Certificate<'chain>) -> Result<Chain<'chain>, ValidationError> {
alex marked this conversation as resolved.
Show resolved Hide resolved
// Before anything else, check whether the given leaf cert
// is well-formed according to our policy (and its underlying
// certificate profile).
//
// In the case that the leaf is an EE, this includes a check
// against the EE cert's SANs.
let extensions = leaf
.extensions()
.map_err(|e| ValidationError::Policy(PolicyError::DuplicateExtension(e)))?;

self.policy.permits_leaf(leaf, &extensions)?;

let result = self.build_chain_inner(leaf, 0, true, &extensions);
match result {
Ok(result) => {
let (chain, _) = result;
woodruffw marked this conversation as resolved.
Show resolved Hide resolved
Ok(chain)
}
Err(error) => Err(error),
}
}
}
12 changes: 0 additions & 12 deletions src/rust/cryptography-x509-validation/src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,4 @@ zl9HYIMxATFyqSiD9jsx
pub(crate) fn cert(cert_pem: &pem::Pem) -> Certificate<'_> {
asn1::parse_single(cert_pem.contents()).unwrap()
}

#[test]
fn test_nullops() {
let cert_pem = v1_cert_pem();
let cert = cert(&cert_pem);

let ops = NullOps {};
assert_eq!(ops.public_key(&cert), Ok(()));
assert!(ops
.verify_signed_by(&cert, ops.public_key(&cert).unwrap())
.is_ok());
}
}
Loading
Loading