diff --git a/src/api.rs b/src/api.rs index 8a27c1f..6860f6c 100644 --- a/src/api.rs +++ b/src/api.rs @@ -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), /// Valid path not found NotFound(String), } diff --git a/src/find.rs b/src/find.rs index 2664796..a213f95 100644 --- a/src/find.rs +++ b/src/find.rs @@ -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, }); @@ -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, }); diff --git a/src/provided/validator/default/mod.rs b/src/provided/validator/default/mod.rs index 0cb499a..74b6610 100644 --- a/src/provided/validator/default/mod.rs +++ b/src/provided/validator/default/mod.rs @@ -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())), } diff --git a/src/provided/validator/openssl/mod.rs b/src/provided/validator/openssl/mod.rs index e1ab4e5..7741c3d 100644 --- a/src/provided/validator/openssl/mod.rs +++ b/src/provided/validator/openssl/mod.rs @@ -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(), @@ -64,6 +80,6 @@ impl PathValidator for OpenSSLPathValidator { impl PathValidatorError for OpenSSLPathValidatorError {} enum VerifyResult { - Success, + Success(Result, String>), Failure(X509VerifyResult), } diff --git a/src/report.rs b/src/report.rs index 027c445..3edbba4 100644 --- a/src/report.rs +++ b/src/report.rs @@ -40,6 +40,8 @@ pub struct Found { pub path: Vec>, /// Certificate path origins pub origin: Vec, + /// DER representation of the trust anchor. + pub trust_anchor: Vec, } impl<'r> IntoIterator for &'r Found { diff --git a/src/tests/test_validator.rs b/src/tests/test_validator.rs index 171437b..df1f8ba 100644 --- a/src/tests/test_validator.rs +++ b/src/tests/test_validator.rs @@ -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 { @@ -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())); } } diff --git a/tests/default/validator.rs b/tests/default/validator.rs index 4babddd..d71e9ba 100644 --- a/tests/default/validator.rs +++ b/tests/default/validator.rs @@ -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); } diff --git a/tests/openssl/validator.rs b/tests/openssl/validator.rs index d984b5a..9eef9ae 100644 --- a/tests/openssl/validator.rs +++ b/tests/openssl/validator.rs @@ -10,7 +10,8 @@ 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(); @@ -18,5 +19,5 @@ fn test_validator() { 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); }