Skip to content

Commit

Permalink
feat: include trust anchors in found reports
Browse files Browse the repository at this point in the history
- `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`.
  • Loading branch information
kikuomax committed Nov 23, 2023
1 parent 8d4a86b commit 33f278a
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 16 deletions.
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
8 changes: 4 additions & 4 deletions src/find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ 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 +150,9 @@ 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
2 changes: 1 addition & 1 deletion src/provided/validator/default/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ 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
22 changes: 19 additions & 3 deletions src/provided/validator/openssl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,30 @@ 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 +80,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::{Certificate, der::Encode as _};

#[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 33f278a

Please sign in to comment.