From 8d4a86b1efb97fd33a6cb87f2e3e374ef6ba5146 Mon Sep 17 00:00:00 2001 From: Kikuo Emoto Date: Thu, 23 Nov 2023 16:48:16 +0900 Subject: [PATCH 1/3] chore: bump rustls-webpki to v0.101.7-ext.1 - To obtain the trust anchor of the verified path. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 259ea28..9d40bc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -785,8 +785,8 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.7-ext.0" -source = "git+https://github.com/codemonger-io/webpki.git?tag=v0.101.7-ext.0#557fa010e6419f0f242e4c4f077852548e4f3a85" +version = "0.101.7-ext.1" +source = "git+https://github.com/codemonger-io/webpki.git?tag=v0.101.7-ext.1#2cc268f0e67e2e99f9a96687e38fbe0ea5bb8c72" dependencies = [ "ring", "untrusted", diff --git a/Cargo.toml b/Cargo.toml index 96a289e..2b4a26d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 } From 33f278abcf6da0fd7630924c63b2af812d22bd64 Mon Sep 17 00:00:00 2001 From: Kikuo Emoto Date: Thu, 23 Nov 2023 16:52:08 +0900 Subject: [PATCH 2/3] 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`. --- src/api.rs | 4 +++- src/find.rs | 8 ++++---- src/provided/validator/default/mod.rs | 2 +- src/provided/validator/openssl/mod.rs | 22 +++++++++++++++++++--- src/report.rs | 2 ++ src/tests/test_validator.rs | 4 ++-- tests/default/validator.rs | 6 +++--- tests/openssl/validator.rs | 5 +++-- 8 files changed, 37 insertions(+), 16 deletions(-) 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); } From 8e8ba3d762a1504ba7cfb51c77678a024e99db8c Mon Sep 17 00:00:00 2001 From: Kikuo Emoto Date: Thu, 23 Nov 2023 17:08:45 +0900 Subject: [PATCH 3/3] style: apply cargo fmt --- src/find.rs | 12 ++++++++++-- src/provided/validator/default/mod.rs | 4 +++- src/provided/validator/openssl/mod.rs | 4 +++- src/tests/test_validator.rs | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/find.rs b/src/find.rs index a213f95..aa44a10 100644 --- a/src/find.rs +++ b/src/find.rs @@ -100,7 +100,11 @@ where { CertificatePathValidation::Found(trust_anchor) => { return Ok(Report { - found: Some(Found { path, origin, trust_anchor }), + found: Some(Found { + path, + origin, + trust_anchor, + }), duration: Instant::now() - start, failures, }); @@ -152,7 +156,11 @@ where { CertificatePathValidation::Found(trust_anchor) => { return Ok(Report { - found: Some(Found { path, origin, trust_anchor }), + 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 74b6610..c45bfd1 100644 --- a/src/provided/validator/default/mod.rs +++ b/src/provided/validator/default/mod.rs @@ -86,7 +86,9 @@ impl<'a> PathValidator for DefaultPathValidator<'a> { self.usage, self.crls, ) { - Ok(trust_anchor) => Ok(CertificatePathValidation::Found(trust_anchor.as_der().to_vec())), + 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 7741c3d..0a71653 100644 --- a/src/provided/validator/openssl/mod.rs +++ b/src/provided/validator/openssl/mod.rs @@ -67,7 +67,9 @@ impl PathValidator for OpenSSLPathValidator { )?; match verified { - VerifyResult::Success(Ok(trust_anchor)) => Ok(CertificatePathValidation::Found(trust_anchor)), + VerifyResult::Success(Ok(trust_anchor)) => { + Ok(CertificatePathValidation::Found(trust_anchor)) + } VerifyResult::Success(Err(e)) => Ok(CertificatePathValidation::NotFound(e)), VerifyResult::Failure(f) => Ok(CertificatePathValidation::NotFound( diff --git a/src/tests/test_validator.rs b/src/tests/test_validator.rs index df1f8ba..eef02d6 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, der::Encode as _}; +use x509_cert::{der::Encode as _, Certificate}; #[derive(Clone)] pub struct TestPathValidator {