Changes `init` to take a closure which is called with the initialized context

After calling the closure, we automatically cleanup the context. This is
required, because otherwise we could have dangling references in the context.
This commit is contained in:
Bastian Köcher 2018-03-11 11:29:45 +01:00
parent a5d7f8a718
commit d7a7c379a8
2 changed files with 28 additions and 14 deletions

View File

@ -108,21 +108,39 @@ impl X509StoreContextRef {
} }
/// Initializes this context with the given certificate, certificates chain and certificate /// Initializes this context with the given certificate, certificates chain and certificate
/// store. /// store. After initializing the context, the `with_context` closure is called with the prepared
/// For successive calls to this function, it is required to call `cleanup` in beforehand. /// 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. /// * `trust` - The certificate store with the trusted certificates.
/// * `cert` - The certificate that should be verified. /// * `cert` - The certificate that should be verified.
/// * `cert_chain` - The certificates chain. /// * `cert_chain` - The certificates chain.
/// * `with_context` - The closure that is called with the initialized context.
/// ///
/// This corresponds to [`X509_STORE_CTX_init`]. /// 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_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html
pub fn init(&mut self, trust: &store::X509StoreRef, cert: &X509Ref, /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html
cert_chain: &StackRef<X509>) -> Result<(), ErrorStack> { 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 { unsafe {
cvt(ffi::X509_STORE_CTX_init(self.as_ptr(), trust.as_ptr(), cvt(ffi::X509_STORE_CTX_init(self.as_ptr(), trust.as_ptr(),
cert.as_ptr(), cert_chain.as_ptr())).map(|_| ()) cert.as_ptr(), cert_chain.as_ptr()))?;
let cleanup = Cleanup(self);
with_context(cleanup.0)
} }
} }
@ -147,7 +165,7 @@ impl X509StoreContextRef {
/// This corresponds to [`X509_STORE_CTX_cleanup`]. /// 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 /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html
pub fn cleanup(&mut self) { fn cleanup(&mut self) {
unsafe { unsafe {
ffi::X509_STORE_CTX_cleanup(self.as_ptr()); ffi::X509_STORE_CTX_cleanup(self.as_ptr());
} }

View File

@ -306,11 +306,8 @@ fn test_verify_cert() {
let store = store_bldr.build(); let store = store_bldr.build();
let mut context = X509StoreContext::new().unwrap(); let mut context = X509StoreContext::new().unwrap();
assert!(context.init(&store, &cert, &chain).is_ok()); assert!(context.init(&store, &cert, &chain, |c| c.verify_cert()).is_ok());
assert!(context.verify_cert().is_ok()); assert!(context.init(&store, &cert, &chain, |c| c.verify_cert()).is_ok());
context.cleanup();
assert!(context.init(&store, &cert, &chain).is_ok());
assert!(context.verify_cert().is_ok());
} }
#[test] #[test]
@ -326,6 +323,5 @@ fn test_verify_fails() {
let store = store_bldr.build(); let store = store_bldr.build();
let mut context = X509StoreContext::new().unwrap(); let mut context = X509StoreContext::new().unwrap();
assert!(context.init(&store, &cert, &chain).is_ok()); assert!(context.init(&store, &cert, &chain, |c| c.verify_cert()).is_err());
assert!(context.verify_cert().is_err());
} }