Skip to content

Commit

Permalink
Report the trust anchors of the verified paths (#1)
Browse files Browse the repository at this point in the history
* feat: include trust anchors in found reports

- `report::Found` includes the DER representation of the trust anchor of
  the verified path. Applies some tweaks to extract the trust anchors
  from `rustls-webpki` or `openssl`.

- Bumps `rustls-webpki` to v0.101.7-ext.1 to obtain the trust anchors of
  the verified paths.
  • Loading branch information
kikuomax authored Nov 23, 2023
1 parent cb148ca commit c362c18
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 19 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ bytes = { version = "1" }
url = { version = "2.4.0" }
sha2 = { version = "0.10.7" }
openssl = { version = "0.10.56", features = ["vendored"], optional = true }
rustls-webpki = { git = "https://github.com/codemonger-io/webpki.git", tag = "v0.101.7-ext.0", optional = true }
rustls-webpki = { git = "https://github.com/codemonger-io/webpki.git", tag = "v0.101.7-ext.1", optional = true }
x509-cert = { version = "0.2.4", features = ["pem"] }
der = { version = "0.7.6", features = ["alloc", "derive", "flagset", "oid"] }
x509-client = { version = "2.0.1", optional = true }
Expand Down
4 changes: 3 additions & 1 deletion src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ pub trait PathValidator {
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum CertificatePathValidation {
/// Valid path found
Found,
///
/// The parameter is a DER representation of the trust anchor.
Found(Vec<u8>),
/// Valid path not found
NotFound(String),
}
Expand Down
16 changes: 12 additions & 4 deletions src/find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,13 @@ where
.validator
.validate(path.iter().map(|c| c.as_ref()).collect())?
{
CertificatePathValidation::Found => {
CertificatePathValidation::Found(trust_anchor) => {
return Ok(Report {
found: Some(Found { path, origin }),
found: Some(Found {
path,
origin,
trust_anchor,
}),
duration: Instant::now() - start,
failures,
});
Expand Down Expand Up @@ -150,9 +154,13 @@ where
.validator
.validate(path.iter().map(|c| c.as_ref()).collect())?
{
CertificatePathValidation::Found => {
CertificatePathValidation::Found(trust_anchor) => {
return Ok(Report {
found: Some(Found { path, origin }),
found: Some(Found {
path,
origin,
trust_anchor,
}),
duration: Instant::now() - start,
failures,
});
Expand Down
4 changes: 3 additions & 1 deletion src/provided/validator/default/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ impl<'a> PathValidator for DefaultPathValidator<'a> {
self.usage,
self.crls,
) {
Ok(_) => Ok(CertificatePathValidation::Found),
Ok(trust_anchor) => Ok(CertificatePathValidation::Found(
trust_anchor.as_der().to_vec(),
)),

Err(f) => Ok(CertificatePathValidation::NotFound(f.to_string())),
}
Expand Down
24 changes: 21 additions & 3 deletions src/provided/validator/openssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,32 @@ impl PathValidator for OpenSSLPathValidator {
openssl_path.as_ref(),
|context| {
Ok(match context.verify_cert()? {
true => VerifyResult::Success,
true => {
let trust_anchor = context
.chain()
.and_then(|chain| {
println!("chain.len(): {}", chain.len());
let last = chain.len() - 1;
chain.get(last)
})
.ok_or("no trust anchor in chain".to_string())
.and_then(|trust_anchor| {
trust_anchor
.to_der()
.map_err(|e| format!("failed to serialize trust anchor: {}", e))
});
VerifyResult::Success(trust_anchor)
}
false => VerifyResult::Failure(context.error()),
})
},
)?;

match verified {
VerifyResult::Success => Ok(CertificatePathValidation::Found),
VerifyResult::Success(Ok(trust_anchor)) => {
Ok(CertificatePathValidation::Found(trust_anchor))
}
VerifyResult::Success(Err(e)) => Ok(CertificatePathValidation::NotFound(e)),

VerifyResult::Failure(f) => Ok(CertificatePathValidation::NotFound(
f.error_string().to_string(),
Expand All @@ -64,6 +82,6 @@ impl PathValidator for OpenSSLPathValidator {
impl PathValidatorError for OpenSSLPathValidatorError {}

enum VerifyResult {
Success,
Success(Result<Vec<u8>, String>),
Failure(X509VerifyResult),
}
2 changes: 2 additions & 0 deletions src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub struct Found {
pub path: Vec<Arc<crate::Certificate>>,
/// Certificate path origins
pub origin: Vec<CertificateOrigin>,
/// DER representation of the trust anchor.
pub trust_anchor: Vec<u8>,
}

impl<'r> IntoIterator for &'r Found {
Expand Down
4 changes: 2 additions & 2 deletions src/tests/test_validator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::api::{CertificatePathValidation, PathValidator};
use crate::provided::validator::default::result::DefaultPathValidatorError;
use x509_cert::Certificate;
use x509_cert::{der::Encode as _, Certificate};

#[derive(Clone)]
pub struct TestPathValidator {
Expand Down Expand Up @@ -29,7 +29,7 @@ impl PathValidator for TestPathValidator {

for root in self.store.iter() {
if root.tbs_certificate.subject == ic.tbs_certificate.issuer {
return Ok(CertificatePathValidation::Found);
return Ok(CertificatePathValidation::Found(root.to_der().unwrap()));
}
}

Expand Down
6 changes: 3 additions & 3 deletions tests/default/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use x509_path_finder_material::generate::CertificatePathGenerator;
#[test]
fn test_validator() {
let mut certificates = CertificatePathGenerator::generate(8, "0").unwrap();
let root = certificates.pop().unwrap().to_der().unwrap();
let root = TrustAnchor::try_from_cert_der(root.as_slice()).unwrap();
let root_der = certificates.pop().unwrap().to_der().unwrap();
let root = TrustAnchor::try_from_cert_der(root_der.as_slice()).unwrap();

let algorithms = &[&webpki::ECDSA_P256_SHA256];

let validator =
DefaultPathValidator::new(algorithms, vec![root], KeyUsage::client_auth(), &[], true);
let validate = validator.validate(certificates.iter().collect()).unwrap();
assert_eq!(CertificatePathValidation::Found, validate);
assert_eq!(CertificatePathValidation::Found(root_der), validate);
}
5 changes: 3 additions & 2 deletions tests/openssl/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ use x509_path_finder_material::generate::CertificatePathGenerator;
fn test_validator() {
let mut certificates = CertificatePathGenerator::generate(8, "0").unwrap();
let root = certificates.pop().unwrap();
let root = X509::from_der(root.to_der().unwrap().as_slice()).unwrap();
let root_der = root.to_der().unwrap();
let root = X509::from_der(root_der.as_slice()).unwrap();

let mut builder = X509StoreBuilder::new().unwrap();
builder.add_cert(root).unwrap();
builder.set_flags(X509VerifyFlags::X509_STRICT).unwrap();

let validator = OpenSSLPathValidator::new(builder.build());
let validate = validator.validate(certificates.iter().collect()).unwrap();
assert_eq!(CertificatePathValidation::Found, validate);
assert_eq!(CertificatePathValidation::Found(root_der), validate);
}

0 comments on commit c362c18

Please sign in to comment.