diff options
| author | Steven Fackler <[email protected]> | 2018-03-11 13:37:21 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2018-03-11 13:37:21 -0700 |
| commit | 00359a1a55898629eb4b068ae68e9bc4e38740f9 (patch) | |
| tree | 2dea94c87e87dfd062debcb0fcc777319d6b87c9 /openssl/src | |
| parent | Merge pull request #870 from sfackler/tweaks (diff) | |
| parent | Changes `init` to take a closure which is called with the initialized context (diff) | |
| download | rust-openssl-00359a1a55898629eb4b068ae68e9bc4e38740f9.tar.xz rust-openssl-00359a1a55898629eb4b068ae68e9bc4e38740f9.zip | |
Merge pull request #861 from bkchr/verify_certificate
Implements `X509_verify_cert`
Diffstat (limited to 'openssl/src')
| -rw-r--r-- | openssl/src/x509/mod.rs | 76 | ||||
| -rw-r--r-- | openssl/src/x509/tests.rs | 36 |
2 files changed, 111 insertions, 1 deletions
diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 9638e6a3..146a77b0 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -67,6 +67,18 @@ impl X509StoreContext { pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> { unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } } + + /// Creates a new `X509StoreContext` instance. + /// + /// This corresponds to [`X509_STORE_CTX_new`]. + /// + /// [`X509_STORE_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_new.html + pub fn new() -> Result<X509StoreContext, ErrorStack> { + unsafe { + ffi::init(); + cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext(p)) + } + } } impl X509StoreContextRef { @@ -95,6 +107,70 @@ impl X509StoreContextRef { unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } } + /// Initializes this context with the given certificate, certificates chain and certificate + /// store. After initializing the context, the `with_context` closure is called with the prepared + /// context. As long as the closure is running, the context stays initialized and can be used + /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished. + /// + /// * `trust` - The certificate store with the trusted certificates. + /// * `cert` - The certificate that should be verified. + /// * `cert_chain` - The certificates chain. + /// * `with_context` - The closure that is called with the initialized context. + /// + /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to + /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. + /// + /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html + /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html + pub fn init<F, T>(&mut self, trust: &store::X509StoreRef, cert: &X509Ref, + cert_chain: &StackRef<X509>, with_context: F) -> Result<T, ErrorStack> + where + F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack> + { + struct Cleanup<'a>(&'a mut X509StoreContextRef); + + impl<'a> Drop for Cleanup<'a> { + fn drop(&mut self) { + self.0.cleanup(); + } + } + + unsafe { + cvt(ffi::X509_STORE_CTX_init(self.as_ptr(), trust.as_ptr(), + cert.as_ptr(), cert_chain.as_ptr()))?; + + let cleanup = Cleanup(self); + with_context(cleanup.0) + } + } + + /// Verifies the stored certificate. + /// It is required to call `init` in beforehand, to initialize the required values. + /// + /// This corresponds to [`X509_verify_cert`]. + /// + /// [`X509_verify_cert`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html + /// + /// # Result + /// + /// The Result must be `Ok(())` to be a valid certificate, otherwise the cert is not valid. + pub fn verify_cert(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_verify_cert(self.as_ptr())).map(|_| ()) + } + } + + /// Cleans-up the context. + /// + /// This corresponds to [`X509_STORE_CTX_cleanup`]. + /// + /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html + fn cleanup(&mut self) { + unsafe { + ffi::X509_STORE_CTX_cleanup(self.as_ptr()); + } + } + /// Set the error code of the context. /// /// This corresponds to [`X509_STORE_CTX_set_error`]. diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 6f6b430a..e3c726ae 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -7,9 +7,10 @@ use nid::Nid; use pkey::{PKey, Private}; use rsa::Rsa; use stack::Stack; -use x509::{X509, X509Name, X509Req, X509VerifyResult}; +use x509::{X509, X509Name, X509Req, X509VerifyResult, X509StoreContext}; use x509::extension::{AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier}; +use x509::store::X509StoreBuilder; fn pkey() -> PKey<Private> { let rsa = Rsa::generate(2048).unwrap(); @@ -291,3 +292,36 @@ fn clone_x509() { let cert = X509::from_pem(cert).unwrap(); cert.clone(); } + +#[test] +fn test_verify_cert() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + let chain = Stack::new().unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + store_bldr.add_cert(ca).unwrap(); + let store = store_bldr.build(); + + let mut context = X509StoreContext::new().unwrap(); + assert!(context.init(&store, &cert, &chain, |c| c.verify_cert()).is_ok()); + assert!(context.init(&store, &cert, &chain, |c| c.verify_cert()).is_ok()); +} + +#[test] +fn test_verify_fails() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/alt_name_cert.pem"); + let ca = X509::from_pem(ca).unwrap(); + let chain = Stack::new().unwrap(); + + let mut store_bldr = X509StoreBuilder::new().unwrap(); + store_bldr.add_cert(ca).unwrap(); + let store = store_bldr.build(); + + let mut context = X509StoreContext::new().unwrap(); + assert!(context.init(&store, &cert, &chain, |c| c.verify_cert()).is_err()); +} |