X509 Path Finder is a depth-first search certificate path validator for Rust.
X509 Path Finder rejects the notion of a single "certificate chain." Instead, it searches for the first match out of infinity. Once it finds a path it can validate, the search halts and the path is returned to the caller.
The complexity of the path search is constrained by three factors:
When evaluating a path candidate for validation, X509 Path Finder is implementation-agnostic. Once it finds a path that has terminated, it presents it to be validated by a backend authority. If the authority validates the path, the search halts.
Validators can be implemented with one method. To get users started, X509 Path Finder ships with an OpenSSL validator.
By default, you'll need to implement your own PathValidator.
text
[dependencies]
x509_path_finder = { version = "0.3"] }
Or, enable the openssl
feature for access to the provided OpenSSLPathValidator validator.
text
[dependencies]
x509_path_finder = { version = "0.3", features = ["openssl"] }
```` rust no_run
use x509pathfinder::api::CertificateStore; use x509pathfinder::provided::certificate::openssl::OpenSSLCertificateIterator; use x509pathfinder::provided::store::DefaultCertificateStore; use x509pathfinder::provided::validator::openssl::OpenSSLPathValidator; use x509pathfinder::{X509PathFinder, X509PathFinderConfiguration, X509PathFinderResult, AIA, NoAIA}; use openssl::x509::store::{X509Store, X509StoreBuilder}; use openssl::x509::verify::X509VerifyFlags; use openssl::x509::X509; use std::marker::PhantomData; use std::time::Duration;
async fn test() -> X509PathFinderResult<()> { // load certificates let (root, certificates) = load_certificates().unwrap();
// create store, load in certificates
let store = DefaultCertificateStore::from_iter(&certificates);
// build openssl store for validator
let openssl_store = build_openssl_store(root).unwrap();
// Instantiate validator with OpenSSL store
let validator = OpenSSLPathValidator::new(openssl_store);
// Instantiate finder with store and validator
let mut finder = X509PathFinder::new(X509PathFinderConfiguration {
limit: Duration::default(),
aia: AIA::None(NoAIA::default()),
store,
validator,
});
// Find a path, starting with first certificate
let report = finder.find(certificates[0].as_ref()).await?;
let path = report.path.unwrap().into_iter().collect::<Vec<X509>>();
assert_eq!(2, path.len());
// Find a path, starting with second certificate
let report = finder.find(certificates[1].as_ref()).await?;
let path = report.path.unwrap().into_iter().collect::<Vec<X509>>();
assert_eq!(1, path.len());
Ok(())
}
// load certificates with OpenSSL
fn loadcertificates() -> Result<(X509, Vec
// create OpenSSL store
fn buildopensslstore(root: X509) -> Result
````
The X509PathFinderConfiguration
struct has the following fields.
limit
: limit runtime of path search. Actual limit will be N * HTTP timeout. See reqwest::ClientBuilder::timeout
for setting HTTP connection timeout.aia
: AIA
enum to configure Authority Information Access extensions.To enable AIA:
text
AIA::Client(MyX509Client::new())
To disable AIA:
text
AIA::None(NoAIA::default())
* store
- CertificateStore
implementation
* validator
: PathValidator
implementation
Because X509 Path Builder can consume AIA URLs from the web, a call to X509PathFinder::find
could in theory run forever, or be coerced into downloading vast amounts of data. Configuration options for managing X509 Path Finder resources:
limit
duration to non-zero for X509PathFinderConfiguration::limit
reqwest::ClientBuilder::timeout
to a more aggressive valuex509_client::X509ClientConfiguration::limit
to a non-zero valueCall X509PathFinder::find
to start the search.
The returning Report
contains the following fields:
path
: on validate success, Option::Some
holds CertificatePath
iterator.origin
: on validate success, Option::Some
holds a list of CertificateOrigin
valuesduration
: duration of path search failures
: any validation failures reported by PathValidator
implementation are held in ValidateFailure
CertificatePath
is an iterator over a list of certificates.
CertificateOrigin
is an enum that describes the origin of each certificate. Can be one of:
Find
: the initial certificate when calling X509PathFinder::find
.Store
: certificate was found in the storeUrl
: certificate was downloaded from a URL (AIA)ValidateFailure
stores any validation failures. Validation failures can occur even though a valid certificate path was eventually found. ValidateFailure
contains the following fields:
path
: the CertificatePath
of where the validation error occurredreason
: human-readable reason for the failureX509 Path Finder can be extended with three traits:
Certificate
- model-agnostic representation of an X509 certificate. Implement this trait to add more certificates modelsCertificateStore
- certificate store API. Implement this trait to make stores with different persistence strategies PathValidator
- path validator API. Implement this trait to use different backend authorities to validate certificate paths.The following API implementations are provided with the X509 Path Finder crate:
Certificate
and PathValidator