Skip to content

Add OCSP nonce functionality #1046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions openssl-sys/src/ocsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;

Expand Down Expand Up @@ -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;
}
126 changes: 126 additions & 0 deletions openssl/src/ocsp.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -28,6 +30,51 @@ bitflags! {
}
}

#[derive(Debug)]
Copy link
Author

@scolby33 scolby33 Jan 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ought I derive Copy, Clone, PartialEq, Eq as well?

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)]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: should Copy, Clone, PartialEq, Eq be added?

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);

Expand Down Expand Up @@ -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! {
Expand Down Expand Up @@ -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! {
Expand All @@ -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<OcspNonceCheckSuccessResult, OcspNonceCheckErrorResult> {
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());
}
}
Binary file added openssl/test/ocsp-req-nonce.der
Binary file not shown.
Binary file added openssl/test/ocsp-req.der
Binary file not shown.