aboutsummaryrefslogtreecommitdiff
path: root/openssl/src
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2018-03-11 13:37:21 -0700
committerGitHub <[email protected]>2018-03-11 13:37:21 -0700
commit00359a1a55898629eb4b068ae68e9bc4e38740f9 (patch)
tree2dea94c87e87dfd062debcb0fcc777319d6b87c9 /openssl/src
parentMerge pull request #870 from sfackler/tweaks (diff)
parentChanges `init` to take a closure which is called with the initialized context (diff)
downloadrust-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.rs76
-rw-r--r--openssl/src/x509/tests.rs36
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());
+}