Skip to main content

Crate x509_validator

Crate x509_validator 

Source
Expand description

X509-validator

§X509Validator

Build+test Documentation Crates.io Coverage

X.509 certificate chain validator.

§Overview

This library validates an X.509 certificate chain against a set of root certificates and a policy. This is an essential building block for a wide range of PKI applications. It ships with a default verifier and a number of built-in verifier policies.

This library is heavily inspired by, and follows the design of, the verifier from the swift-certificates library. Some pragmatic ideas and project structure have been taken from rustls.

§Requirements

  • Rust 1.88 or newer, edition 2024.

§Installation

Add the dependency and pick a crypto backend:

x509-validator = { version = "0.3.0", features = ["aws_lc"] }
FeatureBackendNotes
aws_lcaws-lc-rsFastest.
ringringClose to aws_lc.
rust_cryptoRustCryptoPure Rust. Slowest.

There is no default backend: without one of these features enabled, the crate compiles but verifies nothing. You can also provide your own by implementing SignatureVerifier — see the custom_crypto_backend example.

§Example code

use x509_validator::rfc5280::RFC5280Policy;
use x509_validator::store::CertificateStore;
use x509_validator::Validator;
use x509_validator::rfc5280::Timestamp;
use x509_validator::{Certificate, FromDer};

fn example(root_der: &[u8], intermediate_der: &[u8], leaf_der: &[u8], now: Timestamp) {
    let parse = |der| Certificate::from_der(der).expect("parse").1;
    let (root, intermediate, leaf) = (parse(root_der), parse(intermediate_der), parse(leaf_der));

    // Roots are trusted a priori. Intermediates are only available to build
    // through — each still has to be signed by something leading back to a root.
    let roots = CertificateStore::from_iter([root]);
    let intermediates = CertificateStore::from_iter([intermediate]);

    let policy = RFC5280Policy::new(now);
    let validator = Validator::with_policy(roots, policy);

    match validator.validate_with_diagnostics(&leaf, &intermediates, &mut |_| {}) {
        Ok(chain) => {
            // Leaf first, root last.
            for cert in chain.iter() {
                println!("{}", cert.tbs_certificate.subject);
            }
        }
        Err(reasons) => {
            // Empty means no candidate chain reached a root, so the policy was
            // never asked.
            for reason in reasons {
                println!("rejected: {reason}");
            }
        }
    }
}

The closure is the diagnostic channel: chain building reports every issuer it considers and every candidate it discards through it. If you don’t need any of that, call validate(&leaf, &intermediates) instead.

More are in examples:

ExampleShows
webpkiWhat a TLS client checks: platform trust store, serverAuth, hostname
apple_x5cValidating the x5c chain from an App Store JWS
client_certificateThe mutual-TLS server side
pinned_rootTrusting one private CA instead of the public web PKI
diagnosticsReading the diagnostic callback to find out why a chain failed
custom_crypto_backendImplementing SignatureVerifier over OpenSSL
cargo run -p x509-validator-examples --example webpki

§Approach

Parsing is done by x509-parser.

Crypto is swappable via the feature flags above, or you can supply your own SignatureVerifier.

Policy is where the actual rules live. A ValidationPolicy receives each candidate chain and accepts or rejects it. The built-in ones:

PolicyChecks
RFC5280PolicyValidity period, version, basic constraints, name constraints
EkuPolicyExtended key usage: serverAuth, clientAuth, or any purpose OID you name
ServerIdentityPolicyHostname or IP against the subject alternative names, RFC 6125 style

Policies compose with the policy! macro, so a TLS client’s checks read as one list:

use x509_validator::rfc5280::{EkuPolicy, RFC5280Policy, Timestamp};
use x509_validator::{ServerIdentityPolicy, policy};

fn tls_client_policy(now: Timestamp, hostname: &str) -> impl x509_validator::ValidationPolicy {
    policy! {
        RFC5280Policy::new(now);
        EkuPolicy::server_auth();
        ServerIdentityPolicy::new(Some(hostname), None)
    }
}

§Benchmarks

Two crates, in x509-validator-bench:

  • measure — Regression benchmarks.
  • compare — Compare backends, parsers, other verifiers, and the Swift original across four groups (index).

§Fuzzing

Four cargo-fuzz targets live in fuzz, covering parsing, chain validation, server identity matching and name constraints. They run on every pull request and nightly; see the fuzzing README to run them locally.

§Contributing

Thanks for your help improving the project! We are so happy to have you! We have a contributing guide to help you get involved in the X509Validator project, and everyone taking part is expected to follow our Code of Conduct.

§License

X509Validator is distributed under the following two licenses:

  • Apache License version 2.0.
  • MIT license.

These are included as LICENSE-APACHE and LICENSE-MIT respectively.
You may use this software under the terms of any of these licenses, at your option.

Re-exports§

pub use validator::Validator;
pub use certificate::Certificate;
pub use certificate::CertificateExt;
pub use all_of_policies::AllOfPolicies;
pub use any_policy::AnyPolicy;
pub use one_of_policies::OneOfPolicies;
pub use policy_builder::Either;
pub use policy_builder::OneOfTuple2;
pub use policy_builder::OneOfWrappedOptional;
pub use policy_builder::Tuple2;
pub use policy_builder::WrappedOptional;
pub use server_identity_policy::ServerIdentityPolicy;
pub use crypto::*;
pub use diagnostic::*;
pub use policy::*;
pub use rfc5280::*;

Modules§

all_of_policies
any_policy
asn1_rs
certificate
crypto
der_parser
diagnostic
extensions
objects
oid_registry
one_of_policies
policy
policy_builder
prelude
rfc5280
server_identity_policy
signature_algorithm
store
unverified_chain
validated_chain
validator
x509

Macros§

one_of
A DSL for constructing a ValidationPolicy out of alternatives, without type erasure.
policy
A DSL for constructing a ValidationPolicy out of other ValidationPolicy values, without type erasure.

Structs§

X509Version
The version of the encoded certificate.

Traits§

FromDer
Base trait for DER object parsers

Type Aliases§

AlgorithmIdentifier
Any
GeneralName
GeneralSubtree
Oid
ParsedExtension
RsaSsaPssParams
SubjectPublicKeyInfo