Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
8 changes: 8 additions & 0 deletions openssl-sys/src/handwritten/ocsp.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::super::*;
use libc::*;
use std::os::raw::c_int;

pub enum OCSP_CERTID {}

Expand All @@ -21,6 +22,7 @@ const_ptr_api! {

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 @@ -47,6 +49,10 @@ extern "C" {
pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP);
pub fn OCSP_RESPONSE_new() -> *mut OCSP_RESPONSE;
pub fn OCSP_RESPONSE_free(r: *mut OCSP_RESPONSE);

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

const_ptr_api! {
Expand Down Expand Up @@ -86,4 +92,6 @@ extern "C" {
st: *mut X509_STORE,
flags: c_ulong,
) -> c_int;

pub fn OCSP_check_nonce(req: *mut OCSP_REQUEST, resp: *mut OCSP_BASICRESP) -> c_int;
}
176 changes: 176 additions & 0 deletions openssl/src/ocsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,26 @@ impl OcspRevokedStatus {
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct OcspCheckNonceStatus(c_int);

impl OcspCheckNonceStatus {
pub const REQUEST_ONLY: OcspCheckNonceStatus = OcspCheckNonceStatus(-1);
pub const NOT_EQUAL: OcspCheckNonceStatus = OcspCheckNonceStatus(0);
pub const EQUAL: OcspCheckNonceStatus = OcspCheckNonceStatus(1);
pub const ABSENT: OcspCheckNonceStatus = OcspCheckNonceStatus(2);
pub const RESPONSE_ONLY: OcspCheckNonceStatus = OcspCheckNonceStatus(3);

pub fn from_raw(raw: c_int) -> OcspResponseStatus {
OcspResponseStatus(raw)
}

#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn as_raw(&self) -> c_int {
self.0
}
}

pub struct OcspStatus<'a> {
/// The overall status of the response.
pub status: OcspCertStatus,
Expand Down Expand Up @@ -209,6 +229,30 @@ impl OcspBasicResponseRef {
}
}
}

/// Add a nonce value to the response.
///
/// If `val` is `None`, a random nonce is used.
#[corresponds(OCSP_basic_add1_nonce)]
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(())
}
}

/// Copy the nonce value from `req` to the response.
#[corresponds(OCSP_copy_nonce)]
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 @@ -341,6 +385,21 @@ impl OcspRequestRef {
Ok(OcspOneReqRef::from_ptr_mut(ptr))
}
}

/// Add a nonce value to the request.
///
/// If `val` is `None`, a random nonce is used.
#[corresponds(OCSP_request_add1_nonce)]
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 @@ -350,3 +409,120 @@ foreign_type_and_impl_send_sync! {
pub struct OcspOneReq;
pub struct OcspOneReqRef;
}

/// Compares the nonce value in `req` and `resp`.
#[corresponds(OCSP_check_nonce)]
pub fn check_nonce(req: &OcspRequestRef, resp: &OcspBasicResponseRef) -> OcspCheckNonceStatus {
unsafe {
let r = ffi::OCSP_check_nonce(req.as_ptr(), resp.as_ptr());
OcspCheckNonceStatus(r)
}
}

#[cfg(test)]
mod tests {
use hex::FromHex;

use super::*;

const TEST_NONCE_HEX_1: &str = "2AE3D741A4112D3A0FD345FE89134AD1"; // nonce in test request
const TEST_NONCE_HEX_2: &str = "5E18AA1A113648F054A2F5A396F1636F";

#[test]
fn test_ocsp_create_request_with_nonce() {
let req_der = include_bytes!("../test/ocsp_req.der");
let req_nonce_der = include_bytes!("../test/ocsp_req_nonce.der");
let mut req = OcspRequest::from_der(req_der.as_slice()).unwrap();

assert_hex_eq(req.to_der().unwrap(), req_der);

let nonce = Vec::from_hex(TEST_NONCE_HEX_1).unwrap();
req.add_nonce(Some(&nonce)).unwrap();

assert_hex_eq(req.to_der().unwrap(), req_nonce_der);
}

#[test]
fn test_ocsp_check_nonce() {
let req_der = include_bytes!("../test/ocsp_req.der");
let resp_der = include_bytes!("../test/ocsp_resp.der");
let mut req = OcspRequest::from_der(req_der.as_slice()).unwrap();
let mut resp = OcspResponse::from_der(resp_der.as_slice())
.unwrap()
.basic()
.unwrap();
let nonce1 = Vec::from_hex(TEST_NONCE_HEX_1).unwrap();
let nonce2 = Vec::from_hex(TEST_NONCE_HEX_2).unwrap();

assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::ABSENT
);

req.add_nonce(Some(&nonce1)).unwrap();
assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::REQUEST_ONLY
);

resp.add_nonce(Some(&nonce1)).unwrap();
assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::EQUAL
);

resp.add_nonce(Some(&nonce2)).unwrap();
assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::NOT_EQUAL
);
}

#[test]
fn test_ocsp_copy_nonce() {
let req_der = include_bytes!("../test/ocsp_req_nonce.der");
let resp_der = include_bytes!("../test/ocsp_resp.der");
let req = OcspRequest::from_der(req_der.as_slice()).unwrap();
let mut resp = OcspResponse::from_der(resp_der.as_slice())
.unwrap()
.basic()
.unwrap();

assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::REQUEST_ONLY
);

resp.copy_nonce(req.as_ref()).unwrap();
assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::EQUAL
);
}

#[test]
fn test_ocsp_copy_no_nonce() {
let req_der = include_bytes!("../test/ocsp_req.der");
let resp_der = include_bytes!("../test/ocsp_resp.der");
let req = OcspRequest::from_der(req_der.as_slice()).unwrap();
let mut resp = OcspResponse::from_der(resp_der.as_slice())
.unwrap()
.basic()
.unwrap();

assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::ABSENT
);

resp.copy_nonce(req.as_ref()).unwrap();
assert_eq!(
check_nonce(req.as_ref(), resp.as_ref()),
OcspCheckNonceStatus::ABSENT
);
}

fn assert_hex_eq(left: impl AsRef<[u8]>, right: impl AsRef<[u8]>) {
assert_eq!(hex::encode(left.as_ref()), hex::encode(right.as_ref()))
}
}
Binary file added openssl/test/ocsp_req.der
Binary file not shown.
Binary file added openssl/test/ocsp_req_nonce.der
Binary file not shown.
Binary file added openssl/test/ocsp_resp.der
Binary file not shown.