Skip to content

Commit 265bfec

Browse files
scolby33mvertescher
authored andcommitted
Add implementation of OCSP nonce functions.
- References sfackler#1045. - Add test for creation of OCSP request. - With and without a nonce. - Add custom return/error type for ocsp::check_nonce. - Fix signature of ocsp::BasicResponseRef::copy_nonce. - Add Error::description implementation as required by older versions of Rust.
1 parent 21f9b42 commit 265bfec

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed

openssl-sys/src/ocsp.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ cfg_if! {
6666

6767
extern "C" {
6868
pub fn OCSP_request_add0_id(r: *mut OCSP_REQUEST, id: *mut OCSP_CERTID) -> *mut OCSP_ONEREQ;
69+
pub fn OCSP_request_add1_nonce(req: *mut OCSP_REQUEST, val: *mut c_uchar, len: c_int) -> c_int;
6970

7071
pub fn OCSP_resp_find_status(
7172
bs: *mut OCSP_BASICRESP,
@@ -85,6 +86,9 @@ extern "C" {
8586

8687
pub fn OCSP_response_status(resp: *mut OCSP_RESPONSE) -> c_int;
8788
pub fn OCSP_response_get1_basic(resp: *mut OCSP_RESPONSE) -> *mut OCSP_BASICRESP;
89+
pub fn OCSP_basic_add1_nonce(resp: *mut OCSP_BASICRESP, val: *mut c_uchar, len: c_int)
90+
-> c_int;
91+
pub fn OCSP_copy_nonce(resp: *mut OCSP_BASICRESP, req: *mut OCSP_REQUEST) -> c_int;
8892

8993
pub fn OCSP_response_create(status: c_int, bs: *mut OCSP_BASICRESP) -> *mut OCSP_RESPONSE;
9094

@@ -115,4 +119,6 @@ extern "C" {
115119
st: *mut X509_STORE,
116120
flags: c_ulong,
117121
) -> c_int;
122+
123+
pub fn OCSP_check_nonce(req: *mut OCSP_REQUEST, bs: *mut OCSP_BASICRESP) -> c_int;
118124
}

openssl/src/ocsp.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use ffi;
22
use foreign_types::ForeignTypeRef;
33
use libc::{c_int, c_long, c_ulong};
4+
5+
use std::error::Error;
6+
use std::fmt;
47
use std::mem;
58
use std::ptr;
69

@@ -28,6 +31,47 @@ bitflags! {
2831
}
2932
}
3033

34+
#[derive(Debug)]
35+
pub enum OcspNonceCheckSuccessResult {
36+
PresentAndEqual, // 1
37+
Absent, // 2
38+
PresentInResponseOnly, // 3
39+
}
40+
41+
impl fmt::Display for OcspNonceCheckSuccessResult {
42+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43+
let message = match *self {
44+
OcspNonceCheckSuccessResult::PresentAndEqual => "Nonces Present and Equal",
45+
OcspNonceCheckSuccessResult::Absent => "Nonces Absent from Request and Response",
46+
OcspNonceCheckSuccessResult::PresentInResponseOnly => "Nonce Present in Response Only",
47+
};
48+
write!(f, "{}", message)
49+
}
50+
}
51+
52+
#[derive(Debug)]
53+
pub enum OcspNonceCheckErrorResult {
54+
PresentAndUnequal, // 0
55+
PresentInRequestOnly, // -1
56+
Unknown(ErrorStack), // any other return value
57+
}
58+
59+
impl fmt::Display for OcspNonceCheckErrorResult {
60+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61+
match *self {
62+
OcspNonceCheckErrorResult::PresentAndUnequal => write!(f, "Nonces Present and Unequal!"),
63+
OcspNonceCheckErrorResult::PresentInRequestOnly => write!(f, "Nonce Present in Request Only!"),
64+
OcspNonceCheckErrorResult::Unknown(ref err) => err.fmt(f),
65+
}
66+
}
67+
}
68+
69+
impl Error for OcspNonceCheckErrorResult {
70+
fn description(&self) -> &str {
71+
"an error in OCSP nonce checking"
72+
}
73+
}
74+
3175
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
3276
pub struct OcspResponseStatus(c_int);
3377

@@ -202,6 +246,24 @@ impl OcspBasicResponseRef {
202246
}
203247
}
204248
}
249+
250+
pub fn add_nonce(&mut self, val: Option<&[u8]>) -> Result<(), ErrorStack> {
251+
unsafe {
252+
let (ptr, len) = match val {
253+
Some(slice) => (slice.as_ptr() as *mut _, slice.len() as c_int),
254+
None => (ptr::null_mut(), 0),
255+
};
256+
cvt(ffi::OCSP_basic_add1_nonce(self.as_ptr(), ptr, len))?;
257+
Ok(())
258+
}
259+
}
260+
261+
pub fn copy_nonce(&mut self, req: &OcspRequestRef) -> Result<(), ErrorStack> {
262+
unsafe {
263+
cvt(ffi::OCSP_copy_nonce(self.as_ptr(), req.as_ptr()))?;
264+
Ok(())
265+
}
266+
}
205267
}
206268

207269
foreign_type_and_impl_send_sync! {
@@ -340,6 +402,17 @@ impl OcspRequestRef {
340402
Ok(OcspOneReqRef::from_ptr_mut(ptr))
341403
}
342404
}
405+
406+
pub fn add_nonce(&mut self, val: Option<&[u8]>) -> Result<(), ErrorStack> {
407+
unsafe {
408+
let (ptr, len) = match val {
409+
Some(slice) => (slice.as_ptr() as *mut _, slice.len() as c_int),
410+
None => (ptr::null_mut(), 0),
411+
};
412+
cvt(ffi::OCSP_request_add1_nonce(self.as_ptr(), ptr, len))?;
413+
Ok(())
414+
}
415+
}
343416
}
344417

345418
foreign_type_and_impl_send_sync! {
@@ -349,3 +422,56 @@ foreign_type_and_impl_send_sync! {
349422
pub struct OcspOneReq;
350423
pub struct OcspOneReqRef;
351424
}
425+
426+
pub fn check_nonce(req: &OcspRequestRef, bs: &OcspBasicResponseRef) -> Result<OcspNonceCheckSuccessResult, OcspNonceCheckErrorResult> {
427+
unsafe {
428+
match ffi::OCSP_check_nonce(req.as_ptr(), bs.as_ptr()) {
429+
// good cases
430+
1 => Ok(OcspNonceCheckSuccessResult::PresentAndEqual),
431+
2 => Ok(OcspNonceCheckSuccessResult::Absent),
432+
3 => Ok(OcspNonceCheckSuccessResult::PresentInResponseOnly),
433+
// bad cases
434+
0 => Err(OcspNonceCheckErrorResult::PresentAndUnequal),
435+
-1 => Err(OcspNonceCheckErrorResult::PresentInRequestOnly),
436+
_ => Err(OcspNonceCheckErrorResult::Unknown(ErrorStack::get())), //something else!
437+
}
438+
}
439+
}
440+
441+
#[cfg(test)]
442+
mod tests {
443+
use hex::FromHex;
444+
445+
use super::*;
446+
use hash::MessageDigest;
447+
use x509::X509;
448+
449+
#[test]
450+
fn test_create_ocsp_request() {
451+
let subject = include_bytes!("../test/cert.pem");
452+
let subject = X509::from_pem(subject).unwrap();
453+
let issuer = include_bytes!("../test/root-ca.pem");
454+
let issuer = X509::from_pem(issuer).unwrap();
455+
456+
let req_der = include_bytes!("../test/ocsp-req.der");
457+
let req_nonce_der = include_bytes!("../test/ocsp-req-nonce.der");
458+
459+
let cert_id = OcspCertId::from_cert(
460+
MessageDigest::sha1(),
461+
&subject,
462+
&issuer
463+
).unwrap();
464+
465+
let mut req = OcspRequest::new().unwrap();
466+
req.add_id(cert_id).unwrap();
467+
468+
assert_eq!(&*req.to_der().unwrap(), req_der.as_ref());
469+
470+
471+
let nonce = Vec::from_hex("4413A2C5019A7C3A384CDD8AB30E3816").unwrap();
472+
req.add_nonce(Some(&nonce)).unwrap();
473+
474+
assert_eq!(&*req.to_der().unwrap(), req_nonce_der.as_ref());
475+
}
476+
477+
}

openssl/test/ocsp-req-nonce.der

113 Bytes
Binary file not shown.

openssl/test/ocsp-req.der

76 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)