diff --git a/openssl-sys/src/ocsp.rs b/openssl-sys/src/ocsp.rs index 82157f32ff..0ef77dc097 100644 --- a/openssl-sys/src/ocsp.rs +++ b/openssl-sys/src/ocsp.rs @@ -66,6 +66,7 @@ cfg_if! { extern "C" { pub fn OCSP_request_add0_id(r: *mut OCSP_REQUEST, id: *mut OCSP_CERTID) -> *mut OCSP_ONEREQ; + pub fn OCSP_request_add1_nonce(req: *mut OCSP_REQUEST, val: *mut c_uchar, len: c_int) -> c_int; pub fn OCSP_resp_find_status( bs: *mut OCSP_BASICRESP, @@ -85,6 +86,9 @@ extern "C" { pub fn OCSP_response_status(resp: *mut OCSP_RESPONSE) -> c_int; pub fn OCSP_response_get1_basic(resp: *mut OCSP_RESPONSE) -> *mut OCSP_BASICRESP; + pub fn OCSP_basic_add1_nonce(resp: *mut OCSP_BASICRESP, val: *mut c_uchar, len: c_int) + -> c_int; + pub fn OCSP_copy_nonce(resp: *mut OCSP_BASICRESP, req: *mut OCSP_REQUEST) -> c_int; pub fn OCSP_response_create(status: c_int, bs: *mut OCSP_BASICRESP) -> *mut OCSP_RESPONSE; @@ -115,4 +119,6 @@ extern "C" { st: *mut X509_STORE, flags: c_ulong, ) -> c_int; + + pub fn OCSP_check_nonce(req: *mut OCSP_REQUEST, bs: *mut OCSP_BASICRESP) -> c_int; } diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs index fbe02993cd..dba8fb0556 100644 --- a/openssl/src/ocsp.rs +++ b/openssl/src/ocsp.rs @@ -1,6 +1,8 @@ use ffi; use foreign_types::ForeignTypeRef; use libc::{c_int, c_long, c_ulong}; +use std::error::Error; +use std::fmt; use std::mem; use std::ptr; @@ -28,6 +30,51 @@ bitflags! { } } +#[derive(Debug)] +pub enum OcspNonceCheckSuccessResult { + PresentAndEqual, // 1 + Absent, // 2 + PresentInResponseOnly, // 3 +} + +impl fmt::Display for OcspNonceCheckSuccessResult { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let message = match *self { + OcspNonceCheckSuccessResult::PresentAndEqual => "Nonces Present and Equal", + OcspNonceCheckSuccessResult::Absent => "Nonces Absent from Request and Response", + OcspNonceCheckSuccessResult::PresentInResponseOnly => "Nonce Present in Response Only", + }; + write!(f, "{}", message) + } +} + +#[derive(Debug)] +pub enum OcspNonceCheckErrorResult { + PresentAndUnequal, // 0 + PresentInRequestOnly, // -1 + Unknown(ErrorStack), // any other return value +} + +impl fmt::Display for OcspNonceCheckErrorResult { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + OcspNonceCheckErrorResult::PresentAndUnequal => { + write!(f, "Nonces Present and Unequal!") + } + OcspNonceCheckErrorResult::PresentInRequestOnly => { + write!(f, "Nonce Present in Request Only!") + } + OcspNonceCheckErrorResult::Unknown(ref err) => err.fmt(f), + } + } +} + +impl Error for OcspNonceCheckErrorResult { + fn description(&self) -> &str { + "an error in OCSP nonce checking" + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OcspResponseStatus(c_int); @@ -206,6 +253,24 @@ impl OcspBasicResponseRef { } } } + + pub fn add_nonce(&mut self, val: Option<&[u8]>) -> Result<(), ErrorStack> { + unsafe { + let (ptr, len) = match val { + Some(slice) => (slice.as_ptr() as *mut _, slice.len() as c_int), + None => (ptr::null_mut(), 0), + }; + cvt(ffi::OCSP_basic_add1_nonce(self.as_ptr(), ptr, len))?; + Ok(()) + } + } + + pub fn copy_nonce(&mut self, req: &OcspRequestRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::OCSP_copy_nonce(self.as_ptr(), req.as_ptr()))?; + Ok(()) + } + } } foreign_type_and_impl_send_sync! { @@ -344,6 +409,17 @@ impl OcspRequestRef { Ok(OcspOneReqRef::from_ptr_mut(ptr)) } } + + pub fn add_nonce(&mut self, val: Option<&[u8]>) -> Result<(), ErrorStack> { + unsafe { + let (ptr, len) = match val { + Some(slice) => (slice.as_ptr() as *mut _, slice.len() as c_int), + None => (ptr::null_mut(), 0), + }; + cvt(ffi::OCSP_request_add1_nonce(self.as_ptr(), ptr, len))?; + Ok(()) + } + } } foreign_type_and_impl_send_sync! { @@ -353,3 +429,53 @@ foreign_type_and_impl_send_sync! { pub struct OcspOneReq; pub struct OcspOneReqRef; } + +pub fn check_nonce( + req: &OcspRequestRef, + bs: &OcspBasicResponseRef, +) -> Result { + unsafe { + match ffi::OCSP_check_nonce(req.as_ptr(), bs.as_ptr()) { + // good cases + 1 => Ok(OcspNonceCheckSuccessResult::PresentAndEqual), + 2 => Ok(OcspNonceCheckSuccessResult::Absent), + 3 => Ok(OcspNonceCheckSuccessResult::PresentInResponseOnly), + // bad cases + 0 => Err(OcspNonceCheckErrorResult::PresentAndUnequal), + -1 => Err(OcspNonceCheckErrorResult::PresentInRequestOnly), + _ => Err(OcspNonceCheckErrorResult::Unknown(ErrorStack::get())), //something else! + } + } +} + +#[cfg(test)] +mod tests { + use hex::FromHex; + + use super::*; + use hash::MessageDigest; + use x509::X509; + + #[test] + fn test_create_ocsp_request() { + let subject = include_bytes!("../test/cert.pem"); + let subject = X509::from_pem(subject).unwrap(); + let issuer = include_bytes!("../test/root-ca.pem"); + let issuer = X509::from_pem(issuer).unwrap(); + + let req_der = include_bytes!("../test/ocsp-req.der"); + let req_nonce_der = include_bytes!("../test/ocsp-req-nonce.der"); + + let cert_id = OcspCertId::from_cert(MessageDigest::sha1(), &subject, &issuer).unwrap(); + + let mut req = OcspRequest::new().unwrap(); + req.add_id(cert_id).unwrap(); + + assert_eq!(&*req.to_der().unwrap(), req_der.as_ref()); + + let nonce = Vec::from_hex("4413A2C5019A7C3A384CDD8AB30E3816").unwrap(); + req.add_nonce(Some(&nonce)).unwrap(); + + assert_eq!(&*req.to_der().unwrap(), req_nonce_der.as_ref()); + } +} diff --git a/openssl/test/ocsp-req-nonce.der b/openssl/test/ocsp-req-nonce.der new file mode 100644 index 0000000000..98ddb9ae65 Binary files /dev/null and b/openssl/test/ocsp-req-nonce.der differ diff --git a/openssl/test/ocsp-req.der b/openssl/test/ocsp-req.der new file mode 100644 index 0000000000..bcd2c8ce00 Binary files /dev/null and b/openssl/test/ocsp-req.der differ