From 84fa6fff18414b10b8c23b8d70cbc38f12a10f77 Mon Sep 17 00:00:00 2001 From: Spencer Gilson Date: Sun, 4 Aug 2024 14:22:33 -0700 Subject: [PATCH 1/3] Add support for OCSP nonce --- openssl-sys/src/handwritten/ocsp.rs | 8 ++ openssl/src/ocsp.rs | 176 ++++++++++++++++++++++++++++ openssl/test/ocsp_req.der | Bin 0 -> 83 bytes openssl/test/ocsp_req_nonce.der | Bin 0 -> 120 bytes openssl/test/ocsp_resp.der | Bin 0 -> 471 bytes 5 files changed, 184 insertions(+) create mode 100644 openssl/test/ocsp_req.der create mode 100644 openssl/test/ocsp_req_nonce.der create mode 100644 openssl/test/ocsp_resp.der diff --git a/openssl-sys/src/handwritten/ocsp.rs b/openssl-sys/src/handwritten/ocsp.rs index c194a831b9..d69eae284a 100644 --- a/openssl-sys/src/handwritten/ocsp.rs +++ b/openssl-sys/src/handwritten/ocsp.rs @@ -1,5 +1,6 @@ use super::super::*; use libc::*; +use std::os::raw::c_int; pub enum OCSP_CERTID {} @@ -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, @@ -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! { @@ -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; } diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs index 93a5d36b7e..9f171bb643 100644 --- a/openssl/src/ocsp.rs +++ b/openssl/src/ocsp.rs @@ -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, @@ -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! { @@ -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! { @@ -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: &'static str = "2AE3D741A4112D3A0FD345FE89134AD1"; // nonce in test request + const TEST_NONCE_HEX_2: &'static 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())) + } +} diff --git a/openssl/test/ocsp_req.der b/openssl/test/ocsp_req.der new file mode 100644 index 0000000000000000000000000000000000000000..82b5c87cd7367bda54fcacff1fb1f416ba2a97dc GIT binary patch literal 83 zcmV-Z0IdHoQ7}(1O)yI^NiYcp1uG5%0vZJX1Qcd%3vir?=Q*tO)yI^NiYcp1uG5%0vZJX1Qcd%3vir?=Q*t1_>($0R;sI aFaZJt5(E$`zwz zrlj!P>6deUR=sX|B*AZFU}R!oVPIltU}|D)7-djwP-x(3z{$p{&Bx3n#mc}Ul9tO| zFsJj$KJV9Wgk9aAY@2Gv--F#WCIJ?q^+F6`;*2Jp`kkHEuC8lfK(@iy(!eNcfgnuC z(9pmVEM&mT#;Mij(e|B}k&&B~fw_s1k->h+)TtX5%Kv6J+0V9RXTyf8?0c=Z*R_kv z>aFAQcz=w2%>ucHH_tcxT$I>mp~}=*7RB+lZi>Op`~#I0CmY|oHiWRMDk^F?$IP_* ze`d{w>l}}^x?fZNde}yj`N^VU)-%bVs2^ zW54od3q1?__Js5Mv-UhTuWvuaJ#S9>$zrV){lr(Uc2Z~VcELsJYqL@sGcO8=K4(yz nP|$W{y>4>ZrOzE4kuNfr2ivq<*qfc#8+Ds&axLewTkEU=zLLN3 literal 0 HcmV?d00001 From f41518d20aa32e5c688d0aa5268bc42306d1dc6c Mon Sep 17 00:00:00 2001 From: Spencer Gilson Date: Sun, 4 Aug 2024 14:33:53 -0700 Subject: [PATCH 2/3] Fix clippy errors --- openssl/src/ocsp.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs index 9f171bb643..28d1d73136 100644 --- a/openssl/src/ocsp.rs +++ b/openssl/src/ocsp.rs @@ -425,14 +425,14 @@ mod tests { use super::*; - const TEST_NONCE_HEX_1: &'static str = "2AE3D741A4112D3A0FD345FE89134AD1"; // nonce in test request - const TEST_NONCE_HEX_2: &'static str = "5E18AA1A113648F054A2F5A396F1636F"; + 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(); + let mut req = OcspRequest::from_der(req_der.as_slice()).unwrap(); assert_hex_eq(req.to_der().unwrap(), req_der); @@ -446,8 +446,8 @@ mod tests { 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()) + let mut req = OcspRequest::from_der(req_der.as_slice()).unwrap(); + let mut resp = OcspResponse::from_der(resp_der.as_slice()) .unwrap() .basic() .unwrap(); @@ -482,8 +482,8 @@ mod tests { 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()) + let req = OcspRequest::from_der(req_der.as_slice()).unwrap(); + let mut resp = OcspResponse::from_der(resp_der.as_slice()) .unwrap() .basic() .unwrap(); @@ -504,8 +504,8 @@ mod tests { 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()) + let req = OcspRequest::from_der(req_der.as_slice()).unwrap(); + let mut resp = OcspResponse::from_der(resp_der.as_slice()) .unwrap() .basic() .unwrap(); From 08597e4f1826283b649a0788f9c48c2d0b74fa02 Mon Sep 17 00:00:00 2001 From: Spencer Gilson Date: Mon, 5 Aug 2024 09:16:26 -0700 Subject: [PATCH 3/3] Remove redundant import --- openssl-sys/src/handwritten/ocsp.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/openssl-sys/src/handwritten/ocsp.rs b/openssl-sys/src/handwritten/ocsp.rs index d69eae284a..1df00372e6 100644 --- a/openssl-sys/src/handwritten/ocsp.rs +++ b/openssl-sys/src/handwritten/ocsp.rs @@ -1,6 +1,5 @@ use super::super::*; use libc::*; -use std::os::raw::c_int; pub enum OCSP_CERTID {}