From 8ad676f95ec1ee5cc0c689fdd289ccfa136a57ba Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 28 Apr 2026 08:10:43 +0100 Subject: [PATCH] certificate chain verification test --- Cargo.lock | 7 ++++++ labs/x509test/Cargo.toml | 11 +++++++++ labs/x509test/src/bundle.p12 | Bin 0 -> 4275 bytes labs/x509test/src/cacert.pem | 31 ++++++++++++++++++++++++++ labs/x509test/src/cert.pem | 25 +++++++++++++++++++++ labs/x509test/src/key.pem | 28 +++++++++++++++++++++++ labs/x509test/src/main.rs | 42 +++++++++++++++++++++++++++++++++++ 7 files changed, 144 insertions(+) create mode 100644 labs/x509test/Cargo.toml create mode 100644 labs/x509test/src/bundle.p12 create mode 100644 labs/x509test/src/cacert.pem create mode 100644 labs/x509test/src/cert.pem create mode 100644 labs/x509test/src/key.pem create mode 100644 labs/x509test/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3f7f7e8c3..b3ccba7be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7765,6 +7765,13 @@ dependencies = [ "zeroize", ] +[[package]] +name = "x509test" +version = "0.1.0" +dependencies = [ + "rustls", +] + [[package]] name = "xshell" version = "0.2.2" diff --git a/labs/x509test/Cargo.toml b/labs/x509test/Cargo.toml new file mode 100644 index 000000000..05c92e867 --- /dev/null +++ b/labs/x509test/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "x509test" +version = "0.1.0" +edition = "2024" +rust-version.workspace = true + +[dependencies] +rustls = "^0.23.4" + +[lints] +workspace = true diff --git a/labs/x509test/src/bundle.p12 b/labs/x509test/src/bundle.p12 new file mode 100644 index 0000000000000000000000000000000000000000..026a7bdc1ad5b05fa7be409a679cd2999a2955fd GIT binary patch literal 4275 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 K{5Jos+W!C$0qev7 literal 0 HcmV?d00001 diff --git a/labs/x509test/src/cacert.pem b/labs/x509test/src/cacert.pem new file mode 100644 index 000000000..66938937e --- /dev/null +++ b/labs/x509test/src/cacert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUcP2Ij9JBq8IQfZT5dhNLsbPXYwowDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCVUsxDzANBgNVBAgMBkxvbmRvbjETMBEGA1UECgwKZWxl +bWVudC5pbzEQMA4GA1UEAwwHdGVzdC1jYTAeFw0yNjA0MjcxMzIxMjdaFw0yNzA0 +MjcxMzIxMjdaMEUxCzAJBgNVBAYTAlVLMQ8wDQYDVQQIDAZMb25kb24xEzARBgNV +BAoMCmVsZW1lbnQuaW8xEDAOBgNVBAMMB3Rlc3QtY2EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQD3R1GuEpYIBXuZ47E4Cd6GNuaaUgF9ygRuy1dFgoqY +wRt564jkOYB6Ht5le4R/rb3u6fIeu9j4X2k7DNJPc4H5smHX3ih4BJ5Yli2pzG9S +iUj7dFY69bDA02c4DQP/gjVQddbBUEolPj5L5Ig3a++7zaPloegB/AQ+f9NTceI8 +eehVQ2dWZlI45ltVlXPxUI5MFm3iSJ889ogX+OQMSouARm6/4d3VMTHpSkPPKpH0 +vgFzn/96/C6yWKz7Fis8lM6MRqd8Ka5O5eZ0hAhVktPkUfgVZKpEsCYNVCBqJgOU +OU8FcMLinK9Zp0k8xZkTBXQbFXsKQNTa9/alX9wi2+c41O9d1MmhkYUwkdNh7OJO +//jbm7E5x//10bVgPB7eEqDUA/M/LzSZPmw/94lOcHRHBJyo0mcP74Bcg+tHydwD +xUe8gETLb7ctrlZ+HXMozoeZLeieR7knlHdFbUyufmpsrs/ONLzkPKqG4nqEjhCi +B+PZLFkRM08677FVDTmHWTN2ARAjhdOGWQBSkoD/0qlNJ3cmaqRl4uApPNRCnEKL +HDLwDNA1AH0Y5RmJX9vblfOdmGNEygpxLQmQ5IsQbJS47orupSNnDToP+IjGheOe +r5e8pWTzGO+ptO1a8GaSurrfWLk5D4wVNp+i0rCU1yBa/vCpaUjmSxEn2sG/SyKX +jQIDAQABo1MwUTAdBgNVHQ4EFgQU2F6Rmhfww1sT23VCfSE3mt8+lhEwHwYDVR0j +BBgwFoAU2F6Rmhfww1sT23VCfSE3mt8+lhEwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAJmUlRR7PrS5EXNy+fToAYkSt4xFlTfOeXN6JdQzCia+x +s5TFtqQe/giphQKLN/i9Mm3w0E0u8WA87TKlaWdrZrCivLEhwvieq0u3XwqY628z +8vlcqJuhM4Soe80AQiL51NeHp0WDhBTWnwCXF/e7GA4xryjg7zqhGZjY8+m61vSd +sLT/N05mSsW/m7ZAwxhe2XBVMXvHNTVuAbHX5+4mX9OXRAbnXg5Cexn1sKONsR1L +kN5VjSSvLmzX4AhV0oIRT23NfWBPJnq2s4S9DFDi2uYqE0BWUR1AZOagaVowFsJQ +q8ccwOQMdZZkAC3h2IIVNzYuFFeXkpZM6Bp7Js9IOJrDCL+A/UsndRkv9gX4SVgd +y9vQQBr5iaI5RTKkEiprnZhKOyBd3X/QpAoPRdhiGeImRpKt8vhF+JetGc2E1o+O +CSDpNjD6uI3SHSKt2mlOfeNoZms1pxY36gNYsytFGXf3qdb1I9cP4GRI6cz4JbmP +Y3eczjaqZMcOaPBBZlYz867C5sZi2tvqT75jlB+rVckKRIEl1bL4EZEpvRbK+nfJ +RFSPEY1fryCthLfa67ThB+IAonX4jU663sLoAQW1FEpJp3q08kKJOoCXlCMZ7g1P +eXmIj7ZEOIsufPdiYuKDp/aUdgUHmuCGyegfoCJze36SdFX5q6z8Aq5nKPtz+FM= +-----END CERTIFICATE----- diff --git a/labs/x509test/src/cert.pem b/labs/x509test/src/cert.pem new file mode 100644 index 000000000..99b23d586 --- /dev/null +++ b/labs/x509test/src/cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKjCCAhKgAwIBAgIBADANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJVSzEP +MA0GA1UECAwGTG9uZG9uMRMwEQYDVQQKDAplbGVtZW50LmlvMRAwDgYDVQQDDAd0 +ZXN0LWNhMB4XDTI2MDQyNzEzMzIzNVoXDTI3MDQyNzEzMzIzNVowKDEmMCQGCSqG +SIb3DQEJARYXdmRoLXg1MDl0ZXN0QG1hdHJpeC5vcmcwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCzMke0NO4fXtAnkvqqc9PHcf6tMAB7P7+xjWDTpKfJ +PHohC7IzTNR8u1+Oz76fCLq0bIWDbXS570YoA9hlj6UCH5a/+4NhsNYKTapbUVfq +LVk41oNKAFt7brKZ8tkvAG9GCSKztrc3xAG5+QmiEoVY1XSShz3WuD94LIp3me2R +doQcgSP3Gb6zIhpE8sI4MMRsyjU/k822SfiKOqrWKa+HuXTmNDC2UeCTj2++y0e4 +s2IRrniOjM84Ci2mMhv/L6cpwwhyI1PsL28tGAX1NhEdVdrQxcOyhh3T9Q2er8J1 +kJsfOEmLecNutiSi+mdYbY1pKc60St4KVBE89zAWIg/FAgMBAAGjQjBAMB0GA1Ud +DgQWBBQdCjaG9Xzjyxv9S7xlM1ryXhGyWTAfBgNVHSMEGDAWgBTYXpGaF/DDWxPb +dUJ9ITea3z6WETANBgkqhkiG9w0BAQsFAAOCAgEAhhIcWrFaAd4DuDlHHoqmL9rs +sLn3rx+v4Et+GRV0EjMIOX+tTPO3mUCUb8Ifvk8cC3fucoClKVG8snzIir4eUFOx +d6M7+GAoTLkh8V8XAre3Xo9O2vxB2V8m3IO8Sbnht9aWj9FeMB5Pb9yzTFr8GZPf +7jky+o9R9lrIrURprKBehStYTaNj5YIjYxDXwy+64yXyrckhA8vioFpUFz/CBQMz +B4DwEZRjtFNDxNKA/LcoSnTRfoTpclZIUtJ7YX/qC98QUleuNzpGHM3/59Tn7lzt +ykuWvCAFc3f1nELrEe2ffhCs5M9HNBtGJZ21iEK4LaIu4PBgRTuXDXfsZpC02VKi +s8S9G+er9IUyLpJ1dajY2jXhJuUvmcFLltlzUPYocWcQVVFFAkrrHnew5NzZUPOD ++LQYjNFszITmFc6V49Df23d/kDK+4QzpdtjEf+hjWdDtUDLsAvc48RylwoSIwxn+ +3poImhlL5uqHuyQfQqnEVo/DrV44qi3Qv+cBzC+DQ0SQQJ89keWNTGGAVRggY6lX +iQOKT/LtaDO8mtCwY9GT5ZqjynCnLygdG+GgE7sBaRhoj5FFIaXHD83Gcwpv/JI6 +giqgGwii4W8KvNkR/k1Z6C9+RvENbluqMRbQ3CXVNDbyU1MB6ZliRGTtbZvL0bd1 +/F4LixSyyHVXMUn4/1Q= +-----END CERTIFICATE----- diff --git a/labs/x509test/src/key.pem b/labs/x509test/src/key.pem new file mode 100644 index 000000000..02a4b6068 --- /dev/null +++ b/labs/x509test/src/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCzMke0NO4fXtAn +kvqqc9PHcf6tMAB7P7+xjWDTpKfJPHohC7IzTNR8u1+Oz76fCLq0bIWDbXS570Yo +A9hlj6UCH5a/+4NhsNYKTapbUVfqLVk41oNKAFt7brKZ8tkvAG9GCSKztrc3xAG5 ++QmiEoVY1XSShz3WuD94LIp3me2RdoQcgSP3Gb6zIhpE8sI4MMRsyjU/k822SfiK +OqrWKa+HuXTmNDC2UeCTj2++y0e4s2IRrniOjM84Ci2mMhv/L6cpwwhyI1PsL28t +GAX1NhEdVdrQxcOyhh3T9Q2er8J1kJsfOEmLecNutiSi+mdYbY1pKc60St4KVBE8 +9zAWIg/FAgMBAAECggEADkeBFpIVMONsRjWxyygPBdib87mx1XW/VRWv/o14tVIg +D/Fk/NjazH8IiVJynSz5O8FeDkVdmidqpBZSWx123P7JaM5Q/4Azk39G259VbcVj +/mHRn8b8LeTPT0czw/QOlI/LzR2lPJ4I3oSYHkBy5yDzThiAIVPDSFSRoCA1oclO +oD/PiXADtfa3vkHTswmnT8JTZP7Dpe1zl5AZALQSFVZyQJ4oFxKqJMWc6LsYpHQ3 +AqAAHk7VFyJQGsFZ+D1EgXv3Tzh8YB1nfhjvAucj8VPP9gbDzf4uHEp8FJEHCEAb +lJcEyWNNcpLhSl5T6oY9hjnIkDrxEITdUts+jMRHLQKBgQDrL9ivhSZMZbytU5sv +20JTBFYpgK4TFHeaWnsOwO53AsPTFsl2s6cQ18UNbWIdxn2E7AiTqPVO++E6etNc +HUo76gR9/0gNXILNysQAP0Wzkwtz4c0pXx6pa4zZTihvIcwO0Q6NRAB4sOk+XgDP +Pu79nUSaO8O+d8EUOb+9P2gAZwKBgQDDDfhq12ElgUmhDW92iuD2LwDGg22U4qNQ +0dMXju268TPwx1dYYi/f2yzp/Tn4xKlIo9NZNOzf6GW0+cnOjzyGKCzUglME6Pei +X2Hn8nSD4j60bRCIcf5VfFRAUm9j/y9F/hE5JX+XSM5DKrw09IqzMuu3+Z9TKxRg +dKNOTUQi8wKBgE+d8PLqVl7Cii77AKwgw8Eq1KhUIZnf8eVVABeshI3RZ82MB0Oh +6cqv4Mt83hxKV6+p3/Vs2y6T4llTvz2NxNWnkUG+K/wp9zYHkHas9MGn49ak+Dkr +NEwSVqox5UpJ3LSfXRfBj49MBInSdN+z5GAC33h/BvLxw3E/Y4ODdYe9AoGAaWju +XAbjOBqDiOay2vQ4mLJUD/PMz44fRjjuhCe4r7NUJ4YC3P/K8YYH4rf3kUnuVhQ6 +zlW8wVBdTo1DEz7zLWkeuQVpChlAYl57kZbEgtVMn8LlEWfRU69p9IzYJ8kraf7g +nep25nHxDflVVqTlI+yb2IOtJ4v7ahj+e/1jmiMCgYBX57KyNSGew08r2ezjuV6f +wy/qfzJlieWhESZIckJcrDurfzR3xCj4n4xyC4GMTt3bGYs/rGTdkJGxJ6Bq4Ld2 +foobh78qDEn1mFVwUuW2kzOJsIlN3FQFSKK3upVdRmzXTvaJN4MKRjwmu6KYIpxA +03GLFlPRHwxXrJAV+om1nQ== +-----END PRIVATE KEY----- diff --git a/labs/x509test/src/main.rs b/labs/x509test/src/main.rs new file mode 100644 index 000000000..141329d08 --- /dev/null +++ b/labs/x509test/src/main.rs @@ -0,0 +1,42 @@ +use std::sync::Arc; + +use rustls::{ + RootCertStore, + pki_types::{CertificateDer, UnixTime, pem::PemObject}, + server::WebPkiClientVerifier, +}; + +// TODO: how to load from a PKCS12 bundle? cms::encrypted_data, I think +const KEY_BUNDLE: &[u8] = include_bytes!("bundle.p12"); + +const CA_CERT: &[u8] = include_bytes!("cacert.pem"); +const CERT_BUNDLE_PEM: &[u8] = include_bytes!("cert.pem"); +const PRIVATE_KEY_PEM: &[u8] = include_bytes!("key.pem"); + +fn main() { + // Load the trusted root certificates into a verifier. These would come from + // local configuration. + let mut root_store = RootCertStore::empty(); + for result in CertificateDer::pem_slice_iter(CA_CERT) { + root_store + .add(result.expect("Unable to parse certificate in root store")) + .expect("Unable to add certificate to root store"); + } + let verifier = WebPkiClientVerifier::builder(Arc::new(root_store)) + //.with_crls(...) + .build() + .unwrap(); + + // Verify the certificate chain presented by the device + let mut cert_iter = CertificateDer::pem_slice_iter(CERT_BUNDLE_PEM) + .map(|r| r.expect("Unable to parse cert in cert chain")); + let end_cert = cert_iter.next().expect("Empty certificate chain"); + let intermediate_certs: Vec<_> = cert_iter.collect(); + + verifier + .verify_client_cert(&end_cert, intermediate_certs.as_ref(), UnixTime::now()) + .expect("Unable to verify client certificate"); + + // TODO: verify that the end cert is valid for the user id in question + // TODO: verify a signature from the end cert +}