Skip to main content

pkix_path_builder/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![forbid(unsafe_code)]
4#![warn(missing_docs, rust_2018_idioms)]
5
6//! RFC 4158 certification path building for [`pkix_path`].
7//!
8//! Accepts an unordered collection of certificates ([`CertPool`]) and
9//! constructs a valid ordered chain suitable for [`pkix_path::validate_path`].
10//!
11//! # Relationship to `pkix-path`
12//!
13//! `pkix-path` validates a caller-ordered `&[Certificate]`. This crate
14//! handles the prior step: discovering and ordering that chain from a bag
15//! of certificates when the caller does not know the chain order in advance.
16//! Cross-certificates and bridge CA topologies are handled here, not in
17//! `pkix-path`.
18//!
19//! # Spec references
20//!
21//! - RFC 4158 — Internet X.509 PKI: Certification Path Building
22//! - RFC 5280 §6.1 — the validation algorithm this crate feeds into
23//!
24//! # Limitations
25//!
26//! Not yet implemented. See PKIX-y2j.
27
28extern crate alloc;
29
30use alloc::vec::Vec;
31use x509_cert::Certificate;
32
33/// An unordered collection of certificates used as input to path building.
34///
35/// Certificates are stored by DER bytes and decoded on demand. Add all
36/// candidate intermediate certificates here; the path builder will select
37/// and order the subset that forms a valid path to a trust anchor.
38#[derive(Debug, Default)]
39pub struct CertPool {
40    certs: Vec<Certificate>,
41}
42
43impl CertPool {
44    /// Create an empty pool.
45    pub fn new() -> Self {
46        Self::default()
47    }
48
49    /// Add a certificate to the pool.
50    pub fn add(&mut self, cert: Certificate) {
51        self.certs.push(cert);
52    }
53
54    /// Return the number of certificates in the pool.
55    pub fn len(&self) -> usize {
56        self.certs.len()
57    }
58
59    /// Return `true` if the pool contains no certificates.
60    pub fn is_empty(&self) -> bool {
61        self.certs.is_empty()
62    }
63}
64
65/// Errors returned by path building.
66#[derive(Debug)]
67#[non_exhaustive]
68pub enum Error {
69    /// No valid path from the target certificate to any trust anchor was found.
70    NoPathFound,
71    /// Path building exceeded the configured maximum candidate depth.
72    DepthExceeded,
73}
74
75impl core::fmt::Display for Error {
76    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77        match self {
78            Error::NoPathFound => f.write_str("no certification path found to a trust anchor"),
79            Error::DepthExceeded => f.write_str("path building exceeded maximum candidate depth"),
80        }
81    }
82}
83
84#[cfg(feature = "std")]
85impl std::error::Error for Error {}
86
87/// Result alias for this crate.
88pub type Result<T> = core::result::Result<T, Error>;
89
90/// Build a certification path from `target` through certificates in `pool`
91/// to one of the provided trust anchors.
92///
93/// Returns the ordered chain `[target, intermediate..., issuer]` ready for
94/// [`pkix_path::validate_path`].
95///
96/// # Errors
97///
98/// Returns [`Error::NoPathFound`] if no valid path exists in `pool`.
99///
100/// # Limitations
101///
102/// Not yet implemented (PKIX-y2j).
103pub fn build_path(
104    _target: &Certificate,
105    _pool: &CertPool,
106    _anchors: &[pkix_path::TrustAnchor],
107) -> Result<Vec<Certificate>> {
108    Err(Error::NoPathFound)
109}