Skip to content

Commit

Permalink
src: docs
Browse files Browse the repository at this point in the history
Signed-off-by: William Woodruff <[email protected]>
  • Loading branch information
woodruffw committed Jun 15, 2023
1 parent a32edd6 commit 4902b87
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 14 deletions.
13 changes: 10 additions & 3 deletions src/rust/cryptography-x509-validation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl<'a, B: Backend, P: policy::Profile<B>> Validator<'a, B, P> {

// 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.
Expand Down Expand Up @@ -84,14 +85,20 @@ impl<'a, B: Backend, P: policy::Profile<B>> Validator<'a, B, P> {
Err(PolicyError::Other("chain construction exhausted all candidates").into())
}

pub fn validate(&self, ee: &'a Certificate) -> Result<Chain<'_>, ValidationError> {
pub fn validate(&self, leaf: &'a Certificate) -> Result<Chain<'_>, ValidationError> {
// Before anything else, check whether the given EE cert
// is well-formed according to our policy (and its underlying
// certificate profile).
//
// This includes a check against the EE cert's SANs.
self.policy.permits_ee(ee)?;
//
// NOTE: This is correct when the certificate passed in is an EE,
// but there's no reason why a user shouldn't be able to pass in an
// intermediate instead and construct a chain from there. Maybe
// check whether `leaf` is actually an EE and, if not, validate
// it against the policy's CA checks instead?
self.policy.permits_ee(leaf)?;

self.build_chain(ee, 0)
self.build_chain(leaf, 0)
}
}
57 changes: 46 additions & 11 deletions src/rust/cryptography-x509-validation/src/policy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,16 @@ pub struct Policy<B: Backend, P: Profile<B>> {
/// this policy.
pub max_chain_depth: u8,

/// A DNS name (e.g. `example.com`) that any EE certificates validated
/// by this policy must match.
pub name: DNSString,
pub validation_time: asn1::DateTime,

// NOTE: Conceptually this belongs in the underlying profile instead,
// but doing so introduces another configuration point when virtually
// every profile should have the same validation time semantics.
// So we raise it to the profile instead.
pub validation_time: Option<asn1::DateTime>,

// TODO: Real types here, as these get filled in.
pub extended_key_usage: (),
pub algorithms: (),
Expand All @@ -73,15 +81,17 @@ impl<B: Backend> Policy<B, RFC5280> {
// anyways, so we panic rather than pushing the failure states
// through.
let now = Utc::now();
let validation_time = asn1::DateTime::new(
now.year() as u16,
now.month() as u8,
now.day() as u8,
now.hour() as u8,
now.minute() as u8,
now.second() as u8,
)
.expect("unrepresentable system time: malarkey detected");
let validation_time = Some(
asn1::DateTime::new(
now.year() as u16,
now.month() as u8,
now.day() as u8,
now.hour() as u8,
now.minute() as u8,
now.second() as u8,
)
.expect("unrepresentable system time: malarkey detected"),
);

Self {
profile: RFC5280::default(),
Expand All @@ -96,11 +106,23 @@ impl<B: Backend> Policy<B, RFC5280> {
}

impl<B: Backend, P: Profile<B>> Policy<B, P> {
pub fn with_time(mut self, time: asn1::DateTime) -> Self {
/// Configure this policy's validation time, i.e. the time referenced
/// for certificate validity period checks.
///
/// Passing `None` will disable validity period checks, meaning that
/// no certificates will be considered expired.
pub fn with_validation_time(mut self, time: Option<asn1::DateTime>) -> Self {
self.validation_time = time;
self
}

/// Configure this policy's maximum chain building depth, i.e. the
/// longest chain that path construction will attempt before giving up.
pub fn with_max_chain_depth(mut self, depth: u8) -> Self {
self.max_chain_depth = depth;
self
}

fn permits_san(&self, cert: &Certificate) -> Result<(), PolicyError> {
// Check that the supplied name matches a DNSName SAN in our EE cert.
// TODO: Does this belong under the profile instead?
Expand All @@ -123,6 +145,7 @@ impl<B: Backend, P: Profile<B>> Policy<B, P> {
}
}

/// Checks whether the given CA certificate is compatible with this policy.
pub(crate) fn permits_ca(&self, cert: &Certificate) -> Result<(), PolicyError> {
self.profile.permits_basic(cert)?;
self.profile.permits_ca(cert)?;
Expand All @@ -132,6 +155,7 @@ impl<B: Backend, P: Profile<B>> Policy<B, P> {
Ok(())
}

/// Checks whether the given EE certificate is compatible with this policy.
pub(crate) fn permits_ee(&self, cert: &Certificate) -> Result<(), PolicyError> {
// An end entity cert is considered "permitted" under a policy if:
// 1. It satisfies the basic (EE and CA) requirements of the underlying profile;
Expand All @@ -147,6 +171,16 @@ impl<B: Backend, P: Profile<B>> Policy<B, P> {
Ok(())
}

/// Checks whether `issuer` is a valid issuing CA for `child` at a
/// path-building depth of `current_depth`.
///
/// This checks that `issuer` is permitted under this policy and that
/// it was used to sign for `child`.
///
/// On success, this function returns the new path-building depth. This
/// may or may not be a higher number than the original depth, depending
/// on the kind of validation performed (e.g., whether the issuer was
/// self-issued).
pub(crate) fn valid_issuer(
&self,
issuer: &Certificate,
Expand All @@ -164,6 +198,7 @@ impl<B: Backend, P: Profile<B>> Policy<B, P> {
}

// Self-issued issuers don't increase the working depth.
// NOTE: This is technically part of the profile's semantics.
match issuer.is_self_issued() {
true => Ok(current_depth),
false => Ok(current_depth + 1),
Expand Down

0 comments on commit 4902b87

Please sign in to comment.