From 43fab3b46448c9bb57f18f4b7728be98ad448741 Mon Sep 17 00:00:00 2001 From: KOVACS Krisztian Date: Thu, 25 Jun 2020 10:39:10 +0200 Subject: [PATCH 01/14] openssl-sys: add wrappers for timestamping functions --- openssl-sys/src/lib.rs | 2 + openssl-sys/src/ts.rs | 107 +++++++++++++++++++++++++++++++++++++++++ systest/build.rs | 3 +- 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 openssl-sys/src/ts.rs diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0e23386fd3..ce91e6d95f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -62,6 +62,7 @@ mod openssl { pub use self::ssl::*; pub use self::ssl3::*; pub use self::tls1::*; + pub use self::ts::*; pub use self::types::*; pub use self::x509::*; pub use self::x509_vfy::*; @@ -92,6 +93,7 @@ mod openssl { mod ssl; mod ssl3; mod tls1; + mod ts; mod types; mod x509; mod x509_vfy; diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs new file mode 100644 index 0000000000..6f65058ee0 --- /dev/null +++ b/openssl-sys/src/ts.rs @@ -0,0 +1,107 @@ +use libc::*; + +#[allow(unused_imports)] +use *; + +pub enum TS_MSG_IMPRINT {} +pub enum TS_REQ {} +pub enum TS_RESP {} + +cfg_if! { + if #[cfg(ossl110)] { + pub enum TS_VERIFY_CTX {} + } else { + #[repr(C)] + pub struct TS_VERIFY_CTX { + flags: c_uint, + store: *mut X509_STORE, + certs: *mut stack_st_X509, + policy: *mut ASN1_OBJECT, + md_alg: *mut X509_ALGOR, + imprint: *mut c_uchar, + imprint_len: c_uint, + data: *mut BIO, + nonce: *mut ASN1_INTEGER, + tsa_name: *mut GENERAL_NAME, + } + } +} + +pub const TS_VFY_SIGNATURE: c_uint = 0x1; +pub const TS_VFY_VERSION: c_uint = 0x2; +pub const TS_VFY_POLICY: c_uint = 0x4; +pub const TS_VFY_IMPRINT: c_uint = 0x8; +pub const TS_VFY_DATA: c_uint = 0x10; +pub const TS_VFY_NONCE: c_uint = 0x20; +pub const TS_VFY_SIGNER: c_uint = 0x40; +pub const TS_VFY_TSA_NAME: c_uint = 0x80; + +pub const TS_VFY_ALL_IMPRINT: c_uint = TS_VFY_SIGNATURE + | TS_VFY_VERSION + | TS_VFY_POLICY + | TS_VFY_IMPRINT + | TS_VFY_NONCE + | TS_VFY_SIGNER + | TS_VFY_TSA_NAME; +pub const TS_VFY_ALL_DATA: c_uint = TS_VFY_SIGNATURE + | TS_VFY_VERSION + | TS_VFY_POLICY + | TS_VFY_DATA + | TS_VFY_NONCE + | TS_VFY_SIGNER + | TS_VFY_TSA_NAME; + +extern "C" { + pub fn TS_MSG_IMPRINT_new() -> *mut TS_MSG_IMPRINT; + pub fn TS_MSG_IMPRINT_free(a: *mut TS_MSG_IMPRINT); + pub fn TS_MSG_IMPRINT_set_algo(a: *mut TS_MSG_IMPRINT, alg: *mut X509_ALGOR) -> c_int; + pub fn TS_MSG_IMPRINT_set_msg(a: *mut TS_MSG_IMPRINT, d: *mut c_uchar, length: c_int) -> c_int; + + pub fn TS_REQ_new() -> *mut TS_REQ; + pub fn TS_REQ_free(a: *mut TS_REQ); + pub fn d2i_TS_REQ(a: *mut *mut TS_REQ, pp: *mut *const c_uchar, length: c_long) -> *mut TS_REQ; + pub fn i2d_TS_REQ(a: *const TS_REQ, pp: *mut *mut c_uchar) -> c_int; + pub fn TS_REQ_set_msg_imprint(a: *mut TS_REQ, msg_imprint: *mut TS_MSG_IMPRINT) -> c_int; + pub fn TS_REQ_set_nonce(a: *mut TS_REQ, nonce: *const ASN1_INTEGER) -> c_int; + pub fn TS_REQ_set_cert_req(a: *mut TS_REQ, cert_req: c_int) -> c_int; + + pub fn TS_RESP_new() -> *mut TS_RESP; + pub fn TS_RESP_free(a: *mut TS_RESP); + pub fn d2i_TS_RESP( + a: *mut *mut TS_RESP, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut TS_RESP; + pub fn i2d_TS_RESP(a: *const TS_RESP, pp: *mut *mut c_uchar) -> c_int; + + pub fn TS_VERIFY_CTX_new() -> *mut TS_VERIFY_CTX; + pub fn TS_VERIFY_CTX_free(ctx: *mut TS_VERIFY_CTX); + #[cfg(ossl110)] + pub fn TS_VERIFY_CTX_set_imprint( + ctx: *mut TS_VERIFY_CTX, + hexstr: *mut c_uchar, + length: c_long, + ) -> *mut c_uchar; + pub fn TS_RESP_verify_response(ctx: *mut TS_VERIFY_CTX, response: *mut TS_RESP) -> c_int; + + pub fn TS_REQ_to_TS_VERIFY_CTX(req: *mut TS_REQ, ctx: *mut TS_VERIFY_CTX) + -> *mut TS_VERIFY_CTX; +} + +cfg_if! { + if #[cfg(any(ossl110, libressl280))] { + extern "C" { + pub fn TS_REQ_set_policy_id( + a: *mut TS_REQ, + policy: *const ASN1_OBJECT + ) -> c_int; + } + } else { + extern "C" { + pub fn TS_REQ_set_policy_id( + a: *mut TS_REQ, + policy: *mut ASN1_OBJECT + ) -> c_int; + } + } +} diff --git a/systest/build.rs b/systest/build.rs index 56230ada60..f359077d25 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -67,7 +67,8 @@ fn main() { .header("openssl/aes.h") .header("openssl/ocsp.h") .header("openssl/evp.h") - .header("openssl/x509_vfy.h"); + .header("openssl/x509_vfy.h") + .header("openssl/ts.h"); if let Some(version) = libressl_version { cfg.header("openssl/poly1305.h"); From 5b12bd181af5ff0debccf065d0cf38b906312c1c Mon Sep 17 00:00:00 2001 From: KOVACS Krisztian Date: Tue, 1 Sep 2020 10:28:09 +0200 Subject: [PATCH 02/14] openssl/ts: add timestamping functionality This change adds a partial wrapper for the Time-Stamp Protocol (RFC 3161) implementation in OpenSSL. The aim is to have enough coverage to create a client that can interact with a Time Stamp Authority by creating time-stamp requests and verifying responses returned by the authority. --- openssl-sys/src/ts.rs | 1 + openssl/src/lib.rs | 1 + openssl/src/ts.rs | 302 +++++++++++++++++++++++++++++++++++ openssl/test/ts-request.der | Bin 0 -> 102 bytes openssl/test/ts-response.der | Bin 0 -> 4276 bytes 5 files changed, 304 insertions(+) create mode 100644 openssl/src/ts.rs create mode 100644 openssl/test/ts-request.der create mode 100644 openssl/test/ts-response.der diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs index 6f65058ee0..e16cdad924 100644 --- a/openssl-sys/src/ts.rs +++ b/openssl-sys/src/ts.rs @@ -61,6 +61,7 @@ extern "C" { pub fn TS_REQ_free(a: *mut TS_REQ); pub fn d2i_TS_REQ(a: *mut *mut TS_REQ, pp: *mut *const c_uchar, length: c_long) -> *mut TS_REQ; pub fn i2d_TS_REQ(a: *const TS_REQ, pp: *mut *mut c_uchar) -> c_int; + pub fn TS_REQ_set_version(a: *mut TS_REQ, version: c_long) -> c_int; pub fn TS_REQ_set_msg_imprint(a: *mut TS_REQ, msg_imprint: *mut TS_MSG_IMPRINT) -> c_int; pub fn TS_REQ_set_nonce(a: *mut TS_REQ, nonce: *const ASN1_INTEGER) -> c_int; pub fn TS_REQ_set_cert_req(a: *mut TS_REQ, cert_req: c_int) -> c_int; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 555eda9720..df8b87dc5c 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -193,6 +193,7 @@ pub mod ssl; pub mod stack; pub mod string; pub mod symm; +pub mod ts; pub mod version; pub mod x509; diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs new file mode 100644 index 0000000000..48636736b3 --- /dev/null +++ b/openssl/src/ts.rs @@ -0,0 +1,302 @@ +//! Partial interface to OpenSSL Time-Stamp Protocol (RFC 3161) implementation. +//! +//! This module provides a partial interface to OpenSSL's TSP implementation. +//! The aim is to provide enough functionality for a client to request and +//! verify timestamps returned by a Time Stamp Authority. +use bitflags::bitflags; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::{c_int, c_long, c_uint}; + +use std::ptr; + +use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef}; +use crate::error::ErrorStack; +use crate::hash::MessageDigest; +use crate::x509::X509Algorithm; +use crate::{cvt, cvt_p}; + +foreign_type_and_impl_send_sync! { + type CType = ffi::TS_MSG_IMPRINT; + fn drop = ffi::TS_MSG_IMPRINT_free; + + /// A message imprint contains the has of the data to be timestamped. + pub struct TsMsgImprint; + + /// Reference to `TsMsgImprint`. + pub struct TsMsgImprintRef; +} + +impl TsMsgImprint { + /// Creates a new message imprint. + /// + /// This corresponds to `TS_MSG_IMPRINT_new`. + pub fn new() -> Result { + unsafe { + ffi::init(); + let imprint: *mut ffi::TS_MSG_IMPRINT = cvt_p(ffi::TS_MSG_IMPRINT_new())?; + Ok(TsMsgImprint::from_ptr(imprint)) + } + } + + /// Sets the algorithm identifier of the message digest algorithm. + /// + /// This corresponds to `TS_MSG_IMPRINT_set_algo`. + pub fn set_algo(&mut self, digest: &MessageDigest) -> Result<(), ErrorStack> { + unsafe { + let algorithm = X509Algorithm::from_ptr(cvt_p(ffi::X509_ALGOR_new())?); + ffi::X509_ALGOR_set_md(algorithm.as_ptr(), digest.as_ptr()); + cvt(ffi::TS_MSG_IMPRINT_set_algo( + self.as_ptr(), + algorithm.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the message digest of the data to be timestamped. + /// + /// This corresponds to `TS_MSG_IMPRINT_set_msg`. + pub fn set_msg(&mut self, digest: &[u8]) -> Result<(), ErrorStack> { + let length = convert_digest_length_to_int(digest.len()); + unsafe { + cvt(ffi::TS_MSG_IMPRINT_set_msg( + self.as_ptr(), + digest.as_ptr() as *mut _, + length, + )) + .map(|_| ()) + } + } +} + +fn convert_digest_length_to_int(len: usize) -> c_int { + if len > std::i32::MAX as usize { + panic!("Digest length is too large"); + } else { + len as i32 + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::TS_REQ; + fn drop = ffi::TS_REQ_free; + + /// A timestamp request. + pub struct TsReq; + + /// Reference to `TsReq`. + pub struct TsReqRef; +} + +impl TsReq { + from_der! { + /// Deserializes a DER-encoded TimeStampReq structure. + /// + /// This corresponds to [`d2i_TS_REQ`]. + /// + /// [`d2i_TS_REQ`]: https://www.openssl.org/docs/man1.1.0/man3/d2i_TS_REQ.html + from_der, + TsReq, + ffi::d2i_TS_REQ + } +} + +impl TsReqRef { + to_der! { + /// Serializes the timestamp request into a DER-encoded TimeStampReq structure. + /// + /// This corresponds to [`i2d_TS_REQ`]. + /// + /// [`i2d_TS_REQ`]: https://www.openssl.org/docs/man1.1.0/man3/i2d_TS_REQ.html + to_der, + ffi::i2d_TS_REQ + } +} + +impl TsReq { + /// Creates a new timestamp request. + /// + /// This corresponds to `TS_REQ_new`. + pub fn new() -> Result { + unsafe { + ffi::init(); + let req: *mut ffi::TS_REQ = cvt_p(ffi::TS_REQ_new())?; + Ok(TsReq::from_ptr(req)) + } + } + + /// Set the version of the timestamp request. + /// + /// RFC 3161 requires this to be 1. + /// + /// This corresponds to `TS_REQ_set_version`. + pub fn set_version(&mut self, version: c_long) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::TS_REQ_set_version(self.as_ptr(), version)).map(|_| ()) } + } + + /// Set the message imprint. + /// + /// This corresponds to `TS_REQ_set_msg_imprint`. + pub fn set_msg_imprint(&mut self, imprint: &TsMsgImprintRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::TS_REQ_set_msg_imprint(self.as_ptr(), imprint.as_ptr())).map(|_| ()) } + } + + /// Sets the OID of the policy under which we're requesting the timestamp. + /// + /// This corresponds to `TS_REQ_set_policy_id`. + pub fn set_policy_id(&mut self, policy: &Asn1ObjectRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::TS_REQ_set_policy_id(self.as_ptr(), policy.as_ptr())).map(|_| ()) } + } + + /// Sets the nonce. + /// + /// This corresopnds to `TS_REQ_set_nonce`. + pub fn set_nonce(&mut self, nonce: &Asn1IntegerRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::TS_REQ_set_nonce(self.as_ptr(), nonce.as_ptr())).map(|_| ()) } + } + + /// Sets whether to request the public key certificate in the response. + /// + /// This corresponds to `TS_REQ_set_cert_req`. + pub fn set_cert_req(&mut self, cert_req: bool) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::TS_REQ_set_cert_req(self.as_ptr(), cert_req as c_int)).map(|_| ()) } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::TS_RESP; + fn drop = ffi::TS_RESP_free; + + /// A time-stamping response. + pub struct TsResp; + + /// Reference to `TsResp`. + pub struct TsRespRef; +} + +impl TsResp { + from_der! { + /// Deserializes a DER-encoded TimeStampResp structure. + /// + /// This corresponds to [`d2i_TS_RESP`]. + /// + /// [`d2i_TS_RESP`]: https://www.openssl.org/docs/man1.1.0/man3/d2i_TS_RESP.html + from_der, + TsResp, + ffi::d2i_TS_RESP + } +} + +impl TsRespRef { + to_der! { + /// Serializes the timestamp request into a DER-encoded TimeStampResp structure. + /// + /// This corresponds to [`i2d_TS_RESP`]. + /// + /// [`i2d_TS_RESP`]: https://www.openssl.org/docs/man1.1.0/man3/i2d_TS_RESP.html + to_der, + ffi::i2d_TS_RESP + } + + /// Verifies a timestamp response. + /// + /// This corresponds to `TS_RESP_verify_response`. + pub fn verify(&self, context: &TsVerifyContext) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::TS_RESP_verify_response( + context.as_ptr(), + self.as_ptr(), + )) + .map(|_| ()) + } + } +} + +bitflags! { + /// Flags controlling timestamp verification behaviour. + pub struct VerifyFlags: c_uint { + const SIGNATURE = ffi::TS_VFY_SIGNATURE; + const VERSION = ffi::TS_VFY_VERSION; + const POLICY = ffi::TS_VFY_POLICY; + const IMPRINT = ffi::TS_VFY_IMPRINT; + const DATA = ffi::TS_VFY_DATA; + const NONCE = ffi::TS_VFY_NONCE; + const SIGNER = ffi::TS_VFY_SIGNER; + const TSA_NAME = ffi::TS_VFY_TSA_NAME; + + const ALL_IMPRINT = ffi::TS_VFY_ALL_IMPRINT; + const ALL_DATA = ffi::TS_VFY_ALL_DATA; + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::TS_VERIFY_CTX; + fn drop = ffi::TS_VERIFY_CTX_free; + + /// A context object specifying time-stamping response verification parameters. + pub struct TsVerifyContext; + + /// Reference to `TsVerifyContext`. + pub struct TsVerifyContextRef; +} + +impl TsVerifyContext { + /// Construct a verify context from a timestamping request. + /// + /// Corresponds to `TS_REQ_to_TS_VERIFY_CTX`. + pub fn from_req(request: &TsReqRef) -> Result { + unsafe { + let ctx = cvt_p(ffi::TS_REQ_to_TS_VERIFY_CTX( + request.as_ptr(), + ptr::null_mut(), + ))?; + Ok(TsVerifyContext::from_ptr(ctx)) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::asn1::Asn1Integer; + use crate::bn::BigNum; + use crate::sha::sha512; + + #[test] + fn test_request() { + let mut imprint = TsMsgImprint::new().unwrap(); + imprint.set_algo(&MessageDigest::sha512()).unwrap(); + imprint.set_msg(&sha512(b"BLAHBLAHBLAH\n")).unwrap(); + + let mut request = TsReq::new().unwrap(); + request.set_version(1).unwrap(); + request.set_msg_imprint(&imprint).unwrap(); + request.set_cert_req(true).unwrap(); + let nonce = + Asn1Integer::from_bn(&BigNum::from_hex_str("F3AA393032C93DC1").unwrap()).unwrap(); + request.set_nonce(&nonce).unwrap(); + + let der = request.to_der().unwrap(); + + let request = TsReq::from_der(&der).unwrap(); + assert_eq!(request.to_der().unwrap(), der); + } + + #[test] + fn test_response_der_serialization() { + let original_der = include_bytes!("../test/ts-response.der").to_vec(); + let response = TsResp::from_der(&original_der).unwrap(); + let der = response.to_der().unwrap(); + assert_eq!(der, original_der); + } + + #[test] + fn test_verify() { + let request = TsReq::from_der(include_bytes!("../test/ts-request.der")).unwrap(); + let response = TsResp::from_der(include_bytes!("../test/ts-response.der")).unwrap(); + + let context = TsVerifyContext::from_req(&request).unwrap(); + response.verify(&context).unwrap(); + } +} diff --git a/openssl/test/ts-request.der b/openssl/test/ts-request.der new file mode 100644 index 0000000000000000000000000000000000000000..fcaf129327066096ca0f0147c29fa5501a7b0e99 GIT binary patch literal 102 zcmV-s0GaNC9O71OfvE00cl*jiCZFchv1ct&e)a7C_=At6kBS zv*@AoQ=+#7$Kek4sR)z2?<3gMlHZE14OG)mn54Sng3OC?q}#*^44j|>2>|n|IWRKG IJ;4D1|FB0Z{Qv*} literal 0 HcmV?d00001 diff --git a/openssl/test/ts-response.der b/openssl/test/ts-response.der new file mode 100644 index 0000000000000000000000000000000000000000..771e203d435646ede88728a80c4a0862f57dddbc GIT binary patch literal 4276 zcmd50XRZbyU=S66XD)`(Nkr*H zZ6QE3;9NX&24yM*41%DU00fNAE=mXF1c8D<)Kma21xEinla3h#&BaAPaX26h3g* zssLb~D|P1L83+KLIt{=>Zst;s1g7L4BL9sPM1P1p9!(F>!60T(7#mo}49y0x91dvN z;3i%kPRC8K_E;x03&3n~Z@cnnV|086)0M9RE$p4Rw0tycn{PVj}{x}2= zW};LG7!Jl$N`(Z=yN=3VS+p)IncsFgkhPp?iOjM-si_XS$!|6Fj9H_Vc=YbvLMObZ zvgb*InBt(DlH?VUa@J70&%0@PKfr0{oi(q=({WkjDdqxwir|m^#H802M|d!n zTQ78j;8)IM6lAFD#{l;xHIuWy=DJW@SfXeBs%`H*LdkxaeBDXx|DnPAO~q_qgb>Jil|2H zd=yA=AuLD{YtlNcUHp$YmGy4vD$>=$9rJ6&1Q;mnU}&z3g~ zEALnr==kY8OP;;<>6mlJ_pA%l@IDJVjw4I@pBD*lM(snDW&1m5h0k{ATN*VErfItUO1^^DDrQCgLY8nXbpVdRTb(HD>QE@&(>54C2 z?)2@Q>}z!PIzJQ4*lk6#<^~n!AM(wRI4fA`oj;&Kp5qo`bN*5xYPYhUEj%AIhKv6E ztj~*x{c-$jLuOOEtJULP5>`T8q3;X_xrEo`()@kpvM|((v7OOz9fZnB zl+3tVjYr-(L1bj+`KSHB%aac|INm>}`s%=W!V;c)bZ%Iwf&4hv_tRrW>|T2ec3|>J z*}6F547IBfJ|5xP(=kEtP8pm9?PvutQ_s_DT%o4#snyuH!X3_+zJT7Hy!}H%U^AFM zzrE>bh12+Y^R2Yg(Z&_oo8? zoExz0TNk!g;Zkfz1<`4A5?obD{NDD+VXNnj`+Y8HK;ind;#QA2FSXfjX{`fOWTvBM zgP~OD4@_g}ai^<%jId1k={a^E7w4|J@IFWHIH$0pR_4+aA8kH)B-uV)%Eg0S+kRMS zQW2SOcipsh=iqDu1}p8}Y7yY6a4O0V=W!9CR{!av-A%HP0b37gicMTf@QE8SF)d?2 zu49u1cCz>sp3|0B#o*b8mJc?@)Jqx?^AC)Qz;;UT#g-UR`%w=74_g56(9vJajPwx! z9%T|9`V$QJiaVt$_X6Wtoc}Bv#6O#?W#usnzsZ_H*z!Mz|G3BHzwvl=)owH3_MWh? zZ?xPHk&M~uil^bXX~+imUoI`liD&;*|8<3EkOI)uxjS*D69VyfnO=iA`%5ec^a!<o)inM#kRw#p8I85`YIO0KA7>&Isjz zB5^@eClk!QIqu7B8c2!QJI*U@CIGmh!?+L>*9+jfZvDrcJX~@iF6p0k4eL3slO3{z7pF)wB6$%EZesx)Xb{P*>G99k`mGy_jq_Eb{ z#}1_WUXZwBrnX1J8dy+f=YmSY_&K{}(UNNP@Mfci8V-fVEV!kP?V4m6hBcAuwmN7V z#`7lANOirz$TU$He51sq=eF|H=7qvGFw%&(VhpooG-sutKE!mhj5^7ZZy-H=xSz)$kSHVh!AS2Xrm(-7(Ly`+Jl&l02M_#ygh27J@}TVw%7C^>_QdVH(R{0gFKlYb8Vw5>;90 z!>0_IvdEpXT9H*J=)8%WtY(*l)ulgig^cqYOkj1MRu;K4rF26Rxz&P-)T)o57_d_r zt9rddjmD;pon|=#A)}lR5L$^t@e^8O{0u8Ry_u0(H4*#sQ#=e4xd|kh{9`m|Jj9Y> zL(C5y2rl`bb|ZfKqCXs6E-nK&@-L@E2SFqL&ENs3zhl&Brhj>sUlt6I{3996fJOm7 zr6Ck~i)Y>ym9e-`&t$6z#wtizklEpY^xs=S(SlHc@{W#klZB_UjQqnnOISddi9qpSDuZ4c+I)+U$FA{hE@S)gTqmSOvIFx)9;}{K)*?Wq8?|Mx=N;1oMGfYM}2*hnDRn%V@nO(_=;OUM(w;1qIO1 Date: Tue, 27 Oct 2020 14:45:45 +0100 Subject: [PATCH 03/14] openssl/ts: add functionality for a basic Time Stamp Authority This change adds the missing wrappers to be able to generate a minimally functional Time Stamp Authority, signing time stamp requests and generating time stamp responses. --- openssl-sys/src/ts.rs | 35 ++++++++++ openssl/src/ts.rs | 138 ++++++++++++++++++++++++++++++++++++++- openssl/test/ts-cert.pem | 20 ++++++ openssl/test/ts-key.pem | 27 ++++++++ 4 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 openssl/test/ts-cert.pem create mode 100644 openssl/test/ts-key.pem diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs index e16cdad924..9a1cb1b2dd 100644 --- a/openssl-sys/src/ts.rs +++ b/openssl-sys/src/ts.rs @@ -6,6 +6,7 @@ use *; pub enum TS_MSG_IMPRINT {} pub enum TS_REQ {} pub enum TS_RESP {} +pub enum TS_RESP_CTX {} cfg_if! { if #[cfg(ossl110)] { @@ -51,6 +52,13 @@ pub const TS_VFY_ALL_DATA: c_uint = TS_VFY_SIGNATURE | TS_VFY_SIGNER | TS_VFY_TSA_NAME; +pub const TS_STATUS_GRANTED: c_uint = 0; +pub const TS_STATUS_GRANTED_WITH_MODS: c_uint = 1; +pub const TS_STATUS_REJECTION: c_uint = 2; +pub const TS_STATUS_WAITING: c_uint = 3; +pub const TS_STATUS_REVOCATION_WARNING: c_uint = 4; +pub const TS_STATUS_REVOCATION_NOTIFICATION: c_uint = 5; + extern "C" { pub fn TS_MSG_IMPRINT_new() -> *mut TS_MSG_IMPRINT; pub fn TS_MSG_IMPRINT_free(a: *mut TS_MSG_IMPRINT); @@ -87,6 +95,14 @@ extern "C" { pub fn TS_REQ_to_TS_VERIFY_CTX(req: *mut TS_REQ, ctx: *mut TS_VERIFY_CTX) -> *mut TS_VERIFY_CTX; + + pub fn TS_RESP_CTX_new() -> *mut TS_RESP_CTX; + pub fn TS_RESP_CTX_free(ctx: *mut TS_RESP_CTX); + pub fn TS_RESP_CTX_set_signer_cert(ctx: *mut TS_RESP_CTX, signer: *mut X509) -> c_int; + pub fn TS_RESP_CTX_set_signer_key(ctx: *mut TS_RESP_CTX, key: *mut EVP_PKEY) -> c_int; + pub fn TS_RESP_CTX_add_md(ctx: *mut TS_RESP_CTX, md: *const EVP_MD) -> c_int; + + pub fn TS_RESP_create_response(ctx: *mut TS_RESP_CTX, req_bio: *mut BIO) -> *mut TS_RESP; } cfg_if! { @@ -96,6 +112,10 @@ cfg_if! { a: *mut TS_REQ, policy: *const ASN1_OBJECT ) -> c_int; + pub fn TS_RESP_CTX_set_def_policy( + ctx: *mut TS_RESP_CTX, + def_policy: *const ASN1_OBJECT + ) -> c_int; } } else { extern "C" { @@ -103,6 +123,21 @@ cfg_if! { a: *mut TS_REQ, policy: *mut ASN1_OBJECT ) -> c_int; + pub fn TS_RESP_CTX_set_def_policy( + ctx: *mut TS_RESP_CTX, + def_policy: *mut ASN1_OBJECT + ) -> c_int; + } + } +} + +cfg_if! { + if #[cfg(ossl110)] { + extern "C" { + pub fn TS_RESP_CTX_set_signer_digest( + ctx: *mut TS_RESP_CTX, + signer_digest: *const EVP_MD, + ) -> c_int; } } } diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 48636736b3..f9f6659432 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -10,16 +10,18 @@ use libc::{c_int, c_long, c_uint}; use std::ptr; use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef}; +use crate::bio::MemBioSlice; use crate::error::ErrorStack; use crate::hash::MessageDigest; -use crate::x509::X509Algorithm; +use crate::pkey::{HasPrivate, PKeyRef}; +use crate::x509::{X509Algorithm, X509Ref}; use crate::{cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::TS_MSG_IMPRINT; fn drop = ffi::TS_MSG_IMPRINT_free; - /// A message imprint contains the has of the data to be timestamped. + /// A message imprint contains the hash of the data to be timestamped. pub struct TsMsgImprint; /// Reference to `TsMsgImprint`. @@ -255,13 +257,123 @@ impl TsVerifyContext { } } +foreign_type_and_impl_send_sync! { + type CType = ffi::TS_RESP_CTX; + fn drop = ffi::TS_RESP_CTX_free; + + /// A context object used to sign timestamp requests. + pub struct TsRespContext; + + /// Reference to `TsRespContext`. + pub struct TsRespContextRef; +} + +impl TsRespContextRef { + /// Creates a signed timestamp response for the request. + /// + /// This corresponds to `TS_RESP_create_response`. + pub fn create_response(&mut self, request: &TsReqRef) -> Result { + unsafe { + let der = request.to_der()?; + let bio = MemBioSlice::new(&der)?; + let response = cvt_p(ffi::TS_RESP_create_response(self.as_ptr(), bio.as_ptr()))?; + Ok(TsResp::from_ptr(response)) + } + } +} + +impl TsRespContext { + /// Creates a new response context. + /// + /// This corresponds to `TS_RESP_CTX_new`. + pub fn new() -> Result { + unsafe { + ffi::init(); + let resp_context: *mut ffi::TS_RESP_CTX = cvt_p(ffi::TS_RESP_CTX_new())?; + Ok(TsRespContext::from_ptr(resp_context)) + } + } + + /// Sets the OID of the default policy used by the TSA. + /// + /// This corresponds to `TS_RESP_CTX_set_def_policy`. + pub fn set_default_policy(&mut self, policy: &Asn1ObjectRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::TS_RESP_CTX_set_def_policy( + self.as_ptr(), + policy.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the certificate the TSA uses to sign the request. + /// + /// This corresponds to `TS_RESP_CTX_set_signer_cert`. + pub fn set_signer_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::TS_RESP_CTX_set_signer_cert( + self.as_ptr(), + cert.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the private key the TSA uses to sign the request. + /// + /// The private key match the X.509 certificate set by `set_signer_cert`. + /// + /// This corresponds to `TS_RESP_CTX_set_signer_key`. + pub fn set_signer_key(&mut self, pkey: &PKeyRef) -> Result<(), ErrorStack> + where + T: HasPrivate, + { + unsafe { + cvt(ffi::TS_RESP_CTX_set_signer_key( + self.as_ptr(), + pkey.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Sets the message digest algorithm to use for the signature. + /// + /// + /// Requires OpenSSL 1.1.0 or newer. + /// This corresponds to `TS_RESP_CTX_set_signer_digest`. + #[cfg(ossl110)] + pub fn set_signer_digest(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::TS_RESP_CTX_set_signer_digest( + self.as_ptr(), + md.as_ptr(), + )) + .map(|_| ()) + } + } + + /// Add an accepted message digest algorithm. + /// + /// At least one accepted digest algorithm should be added to the context. + /// + /// This corresponds to `TS_RESP_CTX_add_md`. + pub fn add_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::TS_RESP_CTX_add_md(self.as_ptr(), md.as_ptr())).map(|_| ()) } + } +} + #[cfg(test)] mod tests { use super::*; - use crate::asn1::Asn1Integer; + use crate::asn1::{Asn1Integer, Asn1Object}; use crate::bn::BigNum; + use crate::hash::MessageDigest; + use crate::pkey::PKey; use crate::sha::sha512; + use crate::x509::X509; #[test] fn test_request() { @@ -299,4 +411,24 @@ mod tests { let context = TsVerifyContext::from_req(&request).unwrap(); response.verify(&context).unwrap(); } + + #[test] + fn test_response_context() { + let mut response_context = TsRespContext::new().unwrap(); + response_context + .set_default_policy(&Asn1Object::from_str("1.2.3.4").unwrap()) + .unwrap(); + let cert = X509::from_pem(include_bytes!("../test/ts-cert.pem")).unwrap(); + response_context.set_signer_cert(&cert).unwrap(); + let key = PKey::private_key_from_pem(include_bytes!("../test/ts-key.pem")).unwrap(); + response_context.set_signer_key(&key).unwrap(); + + response_context.add_md(MessageDigest::sha512()).unwrap(); + + let request = TsReq::from_der(include_bytes!("../test/ts-request.der")).unwrap(); + let response = response_context.create_response(&request).unwrap(); + + let context = TsVerifyContext::from_req(&request).unwrap(); + response.verify(&context).unwrap(); + } } diff --git a/openssl/test/ts-cert.pem b/openssl/test/ts-cert.pem new file mode 100644 index 0000000000..e13bd4d217 --- /dev/null +++ b/openssl/test/ts-cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDOjCCAiKgAwIBAgIFN8DNd/kwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMC +QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp +dHMgUHR5IEx0ZDAeFw0yMDEwMjcwODQwMTBaFw0zMTEwMTAwODQwMTBaMFwxCzAJ +BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l +dCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMTDFRpbWVzdGFtcGluZzCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBANUTsyhUuzou06s/XXelCLSF7sd8xtFO +4OJFEWAulg5K4m7w/GG/VIaelvqgNxdSHdzheT1l1UrMP6na2tAcAS5tBv+X0Q0C +T3+FqlqcgV2HSUNKJy3CJ1CoNQCuN6eaqO7y3O9yfdze8jCpHcrYrx4BFNISw8/T +KaAKQRHjrVbAOlIA+nCc7MGYXJS9ZVwfXNASrhRBoswLoesSf4mX1PPXwjnhGJMq +nVhVI+1G1gD9t4l7CrdOhx5vONffOoSjmqDVfRmcyYNT33V8zlynUoKwLF985TKo +hJAfA8qQDczLkPv6shssNWk8BJ+mYRz3sU9QHM4dkX1oql3oWlOx+o0CAwEAAaMa +MBgwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggEBAC1D +6A5FrPsYV4Q2Zar/MdYsuA2XM2j8SA/H2m4uGz8Sg52/V1VWBouB4JVz1EHytAlG +BD2A+71Bk/Y6JpxdU51O/ZgGlrOaCs+1L4+WLe1cgXGcgC65fP7eMCF3ajuOYZid +q5cJxpbBEspecus7ArqEQ9+ahAVZXcSuKfHOcW+3DxqP3/GPvbt4vLdxjPbe1Dbx +Le+UkPPIQoKNk7yOILMuZrR+O4E4O0cn7E2qodUoYIxSOWIg9euvfntFyR66NzXL ++pDtbVzWPKNiqgvhx5n5GjdyQGHA0X2gEpepT3p3S9dHMcdjJfDixVKp8F5f9mbx +6wgs4XG7rb8sRDsAmAc= +-----END CERTIFICATE----- diff --git a/openssl/test/ts-key.pem b/openssl/test/ts-key.pem new file mode 100644 index 0000000000..9a3cf9d640 --- /dev/null +++ b/openssl/test/ts-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA1ROzKFS7Oi7Tqz9dd6UItIXux3zG0U7g4kURYC6WDkribvD8 +Yb9Uhp6W+qA3F1Id3OF5PWXVSsw/qdra0BwBLm0G/5fRDQJPf4WqWpyBXYdJQ0on +LcInUKg1AK43p5qo7vLc73J93N7yMKkdytivHgEU0hLDz9MpoApBEeOtVsA6UgD6 +cJzswZhclL1lXB9c0BKuFEGizAuh6xJ/iZfU89fCOeEYkyqdWFUj7UbWAP23iXsK +t06HHm841986hKOaoNV9GZzJg1PfdXzOXKdSgrAsX3zlMqiEkB8DypANzMuQ+/qy +Gyw1aTwEn6ZhHPexT1Aczh2RfWiqXehaU7H6jQIDAQABAoIBAQDCoR76DQOELvfL +qbKfshDUjK5Ca9hTokBKjppDh+orHf3dJqTySElWOhBg1+3akHiUpSQQkC8XBqB0 +b2OFyr7NgGtvFmavAlhJfHfSErkcDJJAM8C7zGgLBcp8V6agouYCdbaXxbXwBXmm +NyPugKTcvFIfXWKdOB4CgLtVMunHnVz97+2O6HwN3nPfnsUTBNlImyO9UFO+2utB +kk8vx9qvxhVo6bRmL85+CmuPAN0XiYaXqKRyF55b37c69A1mrMsGimRCO9fxuhhW +JW7UwbXM/RHEDKRfD2P8dWMWyw+jQEBzQKrGZ/2dbjuXOVsTT6h/UVnLdFR7ntrk +HljlNsXhAoGBAPwOyAIPBe9MZPmItO4Ssw2hr62MglmXYQITT+i6uuun2LMr6X/E +zTlMNZGTOXPt8mDuPmELXX4rpKu1lBTuhM9/csbYG32kQK2I6j0QuY1fQ+NHnzcA +4e9SkctZSx0auSo4u3+8SaoRpFfbxs6+tv7xJCcmvxkJZrKnTS7Z0SOJAoGBANho +17fBqN63ogcf8y74D15KyxJi/spr7ZAZY1mH212TGf2xOC2gWpLyl+mENjj9L0+j +qRh0J7y0wcnX9ZuuZHmU647/9bM3q21ZLpoP/gbUdZEBU9CnurCk+tTlGZ49iiN0 +KqX86JuynNlou/gcNFJS1v62TCnTr+aWGH6vOmnlAoGBALbTQd+8ZeGc1+Dnd9T3 +W0iX7oVDVYkGdCa9O0jjqJElvdi4ETXL2c+lp3VgBFxCS3xjUnuxcq8BmP+zRSWp +nEuldesk9Uu8x+0XUk/Ywb35S5SfbqzGxxqAGaAVtJX3vDcTz2xndkcVZM8Vaq6r +RrDE2CRNxm6ykvsivqks9LWBAoGAfuqF0KPHyM5DPRB0y0/5m2Ab1m2uZcKEMWVi +SaiOc0OJE6pyeve3BsU1aGL8ddGuhHNEAS5l+5q6qAh6Z1IQZOl8eIIOc4urgtax +qPLGFPVW+bKgmBc2OtCWtnKh4pbOw9omBPDc7isDJ9HvoyPPX5RruDfrVQBsAbx3 +IxzbEi0CgYAXZDdGCX1GiW1qBOGzgN/omrEKuXVQ9QEQYfAy+EWYw6EfWYSzgi3d +QRV2x5q/T4IdPlrFM5fNilQGH2F9fGLX/CSJLWqnvPEKaB6e89y2ncFFZFIaP0YT +UxDNUSmAmdP+GBYZCl3cYAUtVBKrjjyHRkCy8to62ldbSV7jsngX0A== +-----END RSA PRIVATE KEY----- From a48269f8094127d566b0c3f69be91f36ec16b4a0 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Sat, 3 Aug 2024 11:47:41 +0200 Subject: [PATCH 04/14] change interface to match original openssl, add helper functions for convenience --- openssl-sys/src/handwritten/x509.rs | 2 ++ openssl-sys/src/ts.rs | 3 +- openssl/src/ts.rs | 51 +++++++++++++++++++---------- openssl/src/x509/mod.rs | 16 +++++++++ 4 files changed, 53 insertions(+), 19 deletions(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 0bb682764c..a9d4176c55 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -210,7 +210,9 @@ extern "C" { pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ; + pub fn X509_ALGOR_new() -> *mut X509_ALGOR; pub fn X509_ALGOR_free(x: *mut X509_ALGOR); + pub fn X509_ALGOR_set_md(alg: *mut X509_ALGOR, md: *const EVP_MD); pub fn X509_REVOKED_new() -> *mut X509_REVOKED; pub fn X509_REVOKED_free(x: *mut X509_REVOKED); diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs index 9a1cb1b2dd..52cac7c620 100644 --- a/openssl-sys/src/ts.rs +++ b/openssl-sys/src/ts.rs @@ -1,7 +1,6 @@ use libc::*; -#[allow(unused_imports)] -use *; +use crate::{ASN1_INTEGER, ASN1_OBJECT, BIO, EVP_MD, EVP_PKEY, X509, X509_ALGOR}; pub enum TS_MSG_IMPRINT {} pub enum TS_REQ {} diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index f9f6659432..7e2197ed92 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -6,15 +6,16 @@ use bitflags::bitflags; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long, c_uint}; +use openssl_macros::corresponds; use std::ptr; use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef}; use crate::bio::MemBioSlice; use crate::error::ErrorStack; -use crate::hash::MessageDigest; +use crate::hash::{Hasher, MessageDigest}; use crate::pkey::{HasPrivate, PKeyRef}; -use crate::x509::{X509Algorithm, X509Ref}; +use crate::x509::{X509Algorithm, X509AlgorithmRef, X509Ref}; use crate::{cvt, cvt_p}; foreign_type_and_impl_send_sync! { @@ -33,31 +34,28 @@ impl TsMsgImprint { /// /// This corresponds to `TS_MSG_IMPRINT_new`. pub fn new() -> Result { + ffi::init(); unsafe { - ffi::init(); - let imprint: *mut ffi::TS_MSG_IMPRINT = cvt_p(ffi::TS_MSG_IMPRINT_new())?; + let imprint = cvt_p(ffi::TS_MSG_IMPRINT_new())?; Ok(TsMsgImprint::from_ptr(imprint)) } } /// Sets the algorithm identifier of the message digest algorithm. - /// - /// This corresponds to `TS_MSG_IMPRINT_set_algo`. - pub fn set_algo(&mut self, digest: &MessageDigest) -> Result<(), ErrorStack> { + #[corresponds(TS_MSG_IMPRINT_set_algo)] + pub fn set_algo(&mut self, algo: &X509AlgorithmRef) -> Result<(), ErrorStack> { unsafe { - let algorithm = X509Algorithm::from_ptr(cvt_p(ffi::X509_ALGOR_new())?); - ffi::X509_ALGOR_set_md(algorithm.as_ptr(), digest.as_ptr()); cvt(ffi::TS_MSG_IMPRINT_set_algo( self.as_ptr(), - algorithm.as_ptr(), + algo.as_ptr(), )) .map(|_| ()) } } - /// Sets the message digest of the data to be timestamped. - /// - /// This corresponds to `TS_MSG_IMPRINT_set_msg`. + /// Sets the message **digest** of the data to be timestamped. + /// It is named this way to match the name in openssl itself + #[corresponds(TS_MSG_IMPRINT_set_msg)] pub fn set_msg(&mut self, digest: &[u8]) -> Result<(), ErrorStack> { let length = convert_digest_length_to_int(digest.len()); unsafe { @@ -69,6 +67,28 @@ impl TsMsgImprint { .map(|_| ()) } } + + /// Creates a ready-to-use message imprint from a message and a specified hash algorithm. + pub fn from_message_with_algo(msg: &[u8], md: MessageDigest) -> Result { + let mut h = Hasher::new(md)?; + h.update(msg)?; + let hash = h.finish()?; + Self::from_prehash_with_algo(&hash, md) + } + + /// Creates a ready-to-use message imprint from the hash of a message and a specified hash algorithm. + /// + /// `hash` must have originated from the hash function specified by `md`. + pub fn from_prehash_with_algo(hash: &[u8], md: MessageDigest) -> Result { + let mut algo = X509Algorithm::new()?; + algo.set_md(md); + + let mut imprint = Self::new()?; + imprint.set_algo(&algo)?; + imprint.set_msg(hash)?; + + Ok(imprint) + } } fn convert_digest_length_to_int(len: usize) -> c_int { @@ -372,14 +392,11 @@ mod tests { use crate::bn::BigNum; use crate::hash::MessageDigest; use crate::pkey::PKey; - use crate::sha::sha512; use crate::x509::X509; #[test] fn test_request() { - let mut imprint = TsMsgImprint::new().unwrap(); - imprint.set_algo(&MessageDigest::sha512()).unwrap(); - imprint.set_msg(&sha512(b"BLAHBLAHBLAH\n")).unwrap(); + let imprint = TsMsgImprint::from_message_with_algo(b"BLAHBLAHBLAH\n", MessageDigest::sha512()).unwrap(); let mut request = TsReq::new().unwrap(); request.set_version(1).unwrap(); diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index e583518dae..41315f25c7 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -2320,6 +2320,16 @@ foreign_type_and_impl_send_sync! { pub struct X509AlgorithmRef; } +impl X509Algorithm { + pub fn new() -> Result { + ffi::init(); + unsafe { + let ptr = cvt_p(ffi::X509_ALGOR_new())?; + Ok(Self::from_ptr(ptr)) + } + } +} + impl X509AlgorithmRef { /// Returns the ASN.1 OID of this algorithm. pub fn object(&self) -> &Asn1ObjectRef { @@ -2329,6 +2339,12 @@ impl X509AlgorithmRef { Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null") } } + + pub fn set_md(&mut self, md: MessageDigest) { + unsafe { + ffi::X509_ALGOR_set_md(self.as_ptr(), md.as_ptr()); + } + } } foreign_type_and_impl_send_sync! { From ea3182d38656c9681624ef81499a3d3d3594a091 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Sat, 3 Aug 2024 13:09:40 +0200 Subject: [PATCH 05/14] add tryfrom --- openssl/src/ts.rs | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 7e2197ed92..43972cdd34 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -8,6 +8,7 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long, c_uint}; use openssl_macros::corresponds; +use std::convert::TryFrom; use std::ptr; use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef}; @@ -44,25 +45,24 @@ impl TsMsgImprint { /// Sets the algorithm identifier of the message digest algorithm. #[corresponds(TS_MSG_IMPRINT_set_algo)] pub fn set_algo(&mut self, algo: &X509AlgorithmRef) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::TS_MSG_IMPRINT_set_algo( - self.as_ptr(), - algo.as_ptr(), - )) - .map(|_| ()) - } + unsafe { cvt(ffi::TS_MSG_IMPRINT_set_algo(self.as_ptr(), algo.as_ptr())).map(|_| ()) } } /// Sets the message **digest** of the data to be timestamped. /// It is named this way to match the name in openssl itself #[corresponds(TS_MSG_IMPRINT_set_msg)] pub fn set_msg(&mut self, digest: &[u8]) -> Result<(), ErrorStack> { - let length = convert_digest_length_to_int(digest.len()); + let len = if digest.len() > c_int::MAX as usize { + panic!("digest length is too large"); + } else { + digest.len() as c_int + }; + unsafe { cvt(ffi::TS_MSG_IMPRINT_set_msg( self.as_ptr(), digest.as_ptr() as *mut _, - length, + len, )) .map(|_| ()) } @@ -77,7 +77,7 @@ impl TsMsgImprint { } /// Creates a ready-to-use message imprint from the hash of a message and a specified hash algorithm. - /// + /// /// `hash` must have originated from the hash function specified by `md`. pub fn from_prehash_with_algo(hash: &[u8], md: MessageDigest) -> Result { let mut algo = X509Algorithm::new()?; @@ -91,14 +91,6 @@ impl TsMsgImprint { } } -fn convert_digest_length_to_int(len: usize) -> c_int { - if len > std::i32::MAX as usize { - panic!("Digest length is too large"); - } else { - len as i32 - } -} - foreign_type_and_impl_send_sync! { type CType = ffi::TS_REQ; fn drop = ffi::TS_REQ_free; @@ -277,6 +269,14 @@ impl TsVerifyContext { } } +impl TryFrom<&TsReqRef> for TsVerifyContext { + type Error = ErrorStack; + + fn try_from(value: &TsReqRef) -> Result { + Self::from_req(value) + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::TS_RESP_CTX; fn drop = ffi::TS_RESP_CTX_free; @@ -396,7 +396,9 @@ mod tests { #[test] fn test_request() { - let imprint = TsMsgImprint::from_message_with_algo(b"BLAHBLAHBLAH\n", MessageDigest::sha512()).unwrap(); + let imprint = + TsMsgImprint::from_message_with_algo(b"BLAHBLAHBLAH\n", MessageDigest::sha512()) + .unwrap(); let mut request = TsReq::new().unwrap(); request.set_version(1).unwrap(); From 151b5dcd8ba4428eb470e0753aa91fc52ef6d057 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Sat, 3 Aug 2024 13:17:23 +0200 Subject: [PATCH 06/14] add TS_REQ_get_msg_imprint --- openssl-sys/src/ts.rs | 1 + openssl/src/ts.rs | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs index 52cac7c620..4595fc10da 100644 --- a/openssl-sys/src/ts.rs +++ b/openssl-sys/src/ts.rs @@ -70,6 +70,7 @@ extern "C" { pub fn i2d_TS_REQ(a: *const TS_REQ, pp: *mut *mut c_uchar) -> c_int; pub fn TS_REQ_set_version(a: *mut TS_REQ, version: c_long) -> c_int; pub fn TS_REQ_set_msg_imprint(a: *mut TS_REQ, msg_imprint: *mut TS_MSG_IMPRINT) -> c_int; + pub fn TS_REQ_get_msg_imprint(a: *mut TS_REQ) -> *mut TS_MSG_IMPRINT; pub fn TS_REQ_set_nonce(a: *mut TS_REQ, nonce: *const ASN1_INTEGER) -> c_int; pub fn TS_REQ_set_cert_req(a: *mut TS_REQ, cert_req: c_int) -> c_int; diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 43972cdd34..8bb292a4b2 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -16,6 +16,7 @@ use crate::bio::MemBioSlice; use crate::error::ErrorStack; use crate::hash::{Hasher, MessageDigest}; use crate::pkey::{HasPrivate, PKeyRef}; +use crate::util::ForeignTypeExt; use crate::x509::{X509Algorithm, X509AlgorithmRef, X509Ref}; use crate::{cvt, cvt_p}; @@ -155,6 +156,15 @@ impl TsReq { unsafe { cvt(ffi::TS_REQ_set_msg_imprint(self.as_ptr(), imprint.as_ptr())).map(|_| ()) } } + /// Get the message imprint + #[corresponds(TS_REQ_get_msg_imprint)] + pub fn get_msg_imprint(&mut self) -> Option { + unsafe { + let imprint = ffi::TS_REQ_get_msg_imprint(self.as_ptr()); + TsMsgImprint::from_ptr_opt(imprint) + } + } + /// Sets the OID of the policy under which we're requesting the timestamp. /// /// This corresponds to `TS_REQ_set_policy_id`. From b32fc0a6b3e616110af332510d460cb3382678af Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Sat, 3 Aug 2024 13:21:54 +0200 Subject: [PATCH 07/14] corresponds --- openssl/src/ts.rs | 53 ++++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 8bb292a4b2..8a6d5956c7 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -33,8 +33,7 @@ foreign_type_and_impl_send_sync! { impl TsMsgImprint { /// Creates a new message imprint. - /// - /// This corresponds to `TS_MSG_IMPRINT_new`. + #[corresponds(TS_MSG_IMPRINT_new)] pub fn new() -> Result { ffi::init(); unsafe { @@ -106,10 +105,7 @@ foreign_type_and_impl_send_sync! { impl TsReq { from_der! { /// Deserializes a DER-encoded TimeStampReq structure. - /// - /// This corresponds to [`d2i_TS_REQ`]. - /// - /// [`d2i_TS_REQ`]: https://www.openssl.org/docs/man1.1.0/man3/d2i_TS_REQ.html + #[corresponds(d2i_TS_REQ)] from_der, TsReq, ffi::d2i_TS_REQ @@ -119,10 +115,7 @@ impl TsReq { impl TsReqRef { to_der! { /// Serializes the timestamp request into a DER-encoded TimeStampReq structure. - /// - /// This corresponds to [`i2d_TS_REQ`]. - /// - /// [`i2d_TS_REQ`]: https://www.openssl.org/docs/man1.1.0/man3/i2d_TS_REQ.html + #[corresponds(i2d_TS_REQ)] to_der, ffi::i2d_TS_REQ } @@ -130,8 +123,7 @@ impl TsReqRef { impl TsReq { /// Creates a new timestamp request. - /// - /// This corresponds to `TS_REQ_new`. + #[corresponds(TS_REQ_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -143,15 +135,13 @@ impl TsReq { /// Set the version of the timestamp request. /// /// RFC 3161 requires this to be 1. - /// - /// This corresponds to `TS_REQ_set_version`. + #[corresponds(TS_REQ_set_version)] pub fn set_version(&mut self, version: c_long) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_REQ_set_version(self.as_ptr(), version)).map(|_| ()) } } /// Set the message imprint. - /// - /// This corresponds to `TS_REQ_set_msg_imprint`. + #[corresponds(TS_REQ_set_msg_imprint)] pub fn set_msg_imprint(&mut self, imprint: &TsMsgImprintRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_REQ_set_msg_imprint(self.as_ptr(), imprint.as_ptr())).map(|_| ()) } } @@ -166,22 +156,19 @@ impl TsReq { } /// Sets the OID of the policy under which we're requesting the timestamp. - /// - /// This corresponds to `TS_REQ_set_policy_id`. + #[corresponds(TS_REQ_set_policy_id)] pub fn set_policy_id(&mut self, policy: &Asn1ObjectRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_REQ_set_policy_id(self.as_ptr(), policy.as_ptr())).map(|_| ()) } } /// Sets the nonce. - /// - /// This corresopnds to `TS_REQ_set_nonce`. + #[corresponds(TS_REQ_set_nonce)] pub fn set_nonce(&mut self, nonce: &Asn1IntegerRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_REQ_set_nonce(self.as_ptr(), nonce.as_ptr())).map(|_| ()) } } /// Sets whether to request the public key certificate in the response. - /// - /// This corresponds to `TS_REQ_set_cert_req`. + #[corresponds(TS_REQ_set_cert_req)] pub fn set_cert_req(&mut self, cert_req: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_REQ_set_cert_req(self.as_ptr(), cert_req as c_int)).map(|_| ()) } } @@ -201,10 +188,7 @@ foreign_type_and_impl_send_sync! { impl TsResp { from_der! { /// Deserializes a DER-encoded TimeStampResp structure. - /// - /// This corresponds to [`d2i_TS_RESP`]. - /// - /// [`d2i_TS_RESP`]: https://www.openssl.org/docs/man1.1.0/man3/d2i_TS_RESP.html + #[corresponds(d2i_TS_RESP)] from_der, TsResp, ffi::d2i_TS_RESP @@ -214,17 +198,13 @@ impl TsResp { impl TsRespRef { to_der! { /// Serializes the timestamp request into a DER-encoded TimeStampResp structure. - /// - /// This corresponds to [`i2d_TS_RESP`]. - /// - /// [`i2d_TS_RESP`]: https://www.openssl.org/docs/man1.1.0/man3/i2d_TS_RESP.html + #[corresponds(i2d_TS_RESP)] to_der, ffi::i2d_TS_RESP } /// Verifies a timestamp response. - /// - /// This corresponds to `TS_RESP_verify_response`. + #[corresponds(TS_RESP_verify_response)] pub fn verify(&self, context: &TsVerifyContext) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_RESP_verify_response( @@ -300,8 +280,7 @@ foreign_type_and_impl_send_sync! { impl TsRespContextRef { /// Creates a signed timestamp response for the request. - /// - /// This corresponds to `TS_RESP_create_response`. + #[corresponds(TS_RESP_create_response)] pub fn create_response(&mut self, request: &TsReqRef) -> Result { unsafe { let der = request.to_der()?; @@ -314,8 +293,7 @@ impl TsRespContextRef { impl TsRespContext { /// Creates a new response context. - /// - /// This corresponds to `TS_RESP_CTX_new`. + #[corresponds(TS_RESP_CTX_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -325,8 +303,7 @@ impl TsRespContext { } /// Sets the OID of the default policy used by the TSA. - /// - /// This corresponds to `TS_RESP_CTX_set_def_policy`. + #[corresponds(TS_RESP_CTX_set_def_policy)] pub fn set_default_policy(&mut self, policy: &Asn1ObjectRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_RESP_CTX_set_def_policy( From 343c3b448436818d200c4c1827b771ef1f366000 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Sat, 3 Aug 2024 14:33:09 +0200 Subject: [PATCH 08/14] corresponds --- openssl/src/ts.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 8a6d5956c7..ecf7ea3bdd 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -315,8 +315,7 @@ impl TsRespContext { } /// Sets the certificate the TSA uses to sign the request. - /// - /// This corresponds to `TS_RESP_CTX_set_signer_cert`. + #[corresponds(TS_RESP_CTX_set_signer_cert)] pub fn set_signer_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_RESP_CTX_set_signer_cert( @@ -330,8 +329,7 @@ impl TsRespContext { /// Sets the private key the TSA uses to sign the request. /// /// The private key match the X.509 certificate set by `set_signer_cert`. - /// - /// This corresponds to `TS_RESP_CTX_set_signer_key`. + #[corresponds(TS_RESP_CTX_set_signer_key)] pub fn set_signer_key(&mut self, pkey: &PKeyRef) -> Result<(), ErrorStack> where T: HasPrivate, @@ -349,8 +347,8 @@ impl TsRespContext { /// /// /// Requires OpenSSL 1.1.0 or newer. - /// This corresponds to `TS_RESP_CTX_set_signer_digest`. #[cfg(ossl110)] + #[corresponds(TS_RESP_CTX_set_signer_digest)] pub fn set_signer_digest(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_RESP_CTX_set_signer_digest( @@ -364,8 +362,7 @@ impl TsRespContext { /// Add an accepted message digest algorithm. /// /// At least one accepted digest algorithm should be added to the context. - /// - /// This corresponds to `TS_RESP_CTX_add_md`. + #[corresponds(TS_RESP_CTX_add_md)] pub fn add_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::TS_RESP_CTX_add_md(self.as_ptr(), md.as_ptr())).map(|_| ()) } } From e7b45657c6c4ae0d221a0fe59dec8ffb33b07ad3 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Sat, 3 Aug 2024 15:08:31 +0200 Subject: [PATCH 09/14] add getters & equality functionality s.t. one can extract digest+algo from a TsReq to confirm it matches the data it supposedly signs --- openssl-sys/src/handwritten/x509.rs | 2 ++ openssl-sys/src/ts.rs | 6 +++++- openssl/src/asn1.rs | 12 +++++++++++ openssl/src/ts.rs | 31 ++++++++++++++++++++++++++++- openssl/src/x509/mod.rs | 15 ++++++++++++++ 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index a9d4176c55..aba33d8fad 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -214,6 +214,8 @@ extern "C" { pub fn X509_ALGOR_free(x: *mut X509_ALGOR); pub fn X509_ALGOR_set_md(alg: *mut X509_ALGOR, md: *const EVP_MD); + pub fn X509_ALGOR_cmp(alg0: *const X509_ALGOR, alg1: *const X509_ALGOR) -> c_int; + pub fn X509_REVOKED_new() -> *mut X509_REVOKED; pub fn X509_REVOKED_free(x: *mut X509_REVOKED); } diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs index 4595fc10da..2fb1f7b52a 100644 --- a/openssl-sys/src/ts.rs +++ b/openssl-sys/src/ts.rs @@ -1,6 +1,8 @@ use libc::*; -use crate::{ASN1_INTEGER, ASN1_OBJECT, BIO, EVP_MD, EVP_PKEY, X509, X509_ALGOR}; +use crate::{ + ASN1_INTEGER, ASN1_OBJECT, ASN1_OCTET_STRING, BIO, EVP_MD, EVP_PKEY, X509, X509_ALGOR, +}; pub enum TS_MSG_IMPRINT {} pub enum TS_REQ {} @@ -62,7 +64,9 @@ extern "C" { pub fn TS_MSG_IMPRINT_new() -> *mut TS_MSG_IMPRINT; pub fn TS_MSG_IMPRINT_free(a: *mut TS_MSG_IMPRINT); pub fn TS_MSG_IMPRINT_set_algo(a: *mut TS_MSG_IMPRINT, alg: *mut X509_ALGOR) -> c_int; + pub fn TS_MSG_IMPRINT_get_algo(a: *mut TS_MSG_IMPRINT) -> *mut X509_ALGOR; pub fn TS_MSG_IMPRINT_set_msg(a: *mut TS_MSG_IMPRINT, d: *mut c_uchar, length: c_int) -> c_int; + pub fn TS_MSG_IMPRINT_get_msg(a: *mut TS_MSG_IMPRINT) -> *mut ASN1_OCTET_STRING; pub fn TS_REQ_new() -> *mut TS_REQ; pub fn TS_REQ_free(a: *mut TS_REQ); diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 03340820d0..20d5b54ebf 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -651,6 +651,18 @@ impl Asn1OctetStringRef { } } +impl PartialEq for Asn1OctetStringRef { + fn eq(&self, other: &Self) -> bool { + self.as_slice() == other.as_slice() + } +} + +impl PartialEq for Asn1OctetString { + fn eq(&self, other: &Self) -> bool { + Asn1OctetStringRef::eq(self, other) + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_OBJECT; fn drop = ffi::ASN1_OBJECT_free; diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index ecf7ea3bdd..068d966000 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -11,7 +11,7 @@ use openssl_macros::corresponds; use std::convert::TryFrom; use std::ptr; -use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef}; +use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef, Asn1OctetString}; use crate::bio::MemBioSlice; use crate::error::ErrorStack; use crate::hash::{Hasher, MessageDigest}; @@ -31,6 +31,17 @@ foreign_type_and_impl_send_sync! { pub struct TsMsgImprintRef; } +impl PartialEq for TsMsgImprintRef { + fn eq(&self, other: &Self) -> bool { + self.get_msg() == other.get_msg() && self.get_algo() == other.get_algo() + } +} +impl PartialEq for TsMsgImprint { + fn eq(&self, other: &Self) -> bool { + TsMsgImprintRef::eq(self, other) + } +} + impl TsMsgImprint { /// Creates a new message imprint. #[corresponds(TS_MSG_IMPRINT_new)] @@ -91,6 +102,24 @@ impl TsMsgImprint { } } +impl TsMsgImprintRef { + #[corresponds(TS_MSG_IMPRINT_get_msg)] + pub fn get_msg(&self) -> Option { + unsafe { + let octet = ffi::TS_MSG_IMPRINT_get_msg(self.as_ptr()); + Asn1OctetString::from_ptr_opt(octet) + } + } + + #[corresponds(TS_MSG_IMPRINT_get_algo)] + pub fn get_algo(&self) -> Option { + unsafe { + let algo = ffi::TS_MSG_IMPRINT_get_algo(self.as_ptr()); + X509Algorithm::from_ptr_opt(algo) + } + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::TS_REQ; fn drop = ffi::TS_REQ_free; diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 41315f25c7..d55479f63e 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -2340,6 +2340,7 @@ impl X509AlgorithmRef { } } + #[corresponds(X509_ALGOR_set_md)] pub fn set_md(&mut self, md: MessageDigest) { unsafe { ffi::X509_ALGOR_set_md(self.as_ptr(), md.as_ptr()); @@ -2347,6 +2348,20 @@ impl X509AlgorithmRef { } } +impl PartialEq for X509AlgorithmRef { + fn eq(&self, other: &Self) -> bool { + unsafe { + ffi::X509_ALGOR_cmp(self.as_ptr(), other.as_ptr()) == 0 + } + } +} + +impl PartialEq for X509Algorithm { + fn eq(&self, other: &Self) -> bool { + X509AlgorithmRef::eq(self, other) + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::X509_OBJECT; fn drop = X509_OBJECT_free; From 00ba4b7e02eef62bf82dba9854804c94ac5918c5 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Sat, 3 Aug 2024 16:52:06 +0200 Subject: [PATCH 10/14] methods to fetch timestamp from timestamp response object --- openssl-sys/src/ts.rs | 7 +++++++ openssl/src/ts.rs | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs index 2fb1f7b52a..618a07b6bd 100644 --- a/openssl-sys/src/ts.rs +++ b/openssl-sys/src/ts.rs @@ -4,9 +4,12 @@ use crate::{ ASN1_INTEGER, ASN1_OBJECT, ASN1_OCTET_STRING, BIO, EVP_MD, EVP_PKEY, X509, X509_ALGOR, }; +use super::ASN1_STRING; + pub enum TS_MSG_IMPRINT {} pub enum TS_REQ {} pub enum TS_RESP {} +pub enum TS_TST_INFO {} pub enum TS_RESP_CTX {} cfg_if! { @@ -107,6 +110,10 @@ extern "C" { pub fn TS_RESP_CTX_add_md(ctx: *mut TS_RESP_CTX, md: *const EVP_MD) -> c_int; pub fn TS_RESP_create_response(ctx: *mut TS_RESP_CTX, req_bio: *mut BIO) -> *mut TS_RESP; + + pub fn TS_RESP_get_tst_info(a: *mut TS_RESP) -> *mut TS_TST_INFO; + pub fn TS_TST_INFO_get_time(a: *const TS_TST_INFO) -> *const ASN1_STRING; + pub fn TS_TST_INFO_free(a: *mut TS_TST_INFO); } cfg_if! { diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 068d966000..cc7192c080 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -11,12 +11,12 @@ use openssl_macros::corresponds; use std::convert::TryFrom; use std::ptr; -use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef, Asn1OctetString}; +use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef, Asn1OctetString, Asn1StringRef}; use crate::bio::MemBioSlice; use crate::error::ErrorStack; use crate::hash::{Hasher, MessageDigest}; use crate::pkey::{HasPrivate, PKeyRef}; -use crate::util::ForeignTypeExt; +use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; use crate::x509::{X509Algorithm, X509AlgorithmRef, X509Ref}; use crate::{cvt, cvt_p}; @@ -243,6 +243,19 @@ impl TsRespRef { .map(|_| ()) } } + + // idk what the null-ness guarantees of this function is as it's not documented in openssl + #[corresponds(TS_RESP_get_tst_info)] + pub fn get_tst(&self) -> Option<&TsTstInfoRef> { + unsafe { + let info = ffi::TS_RESP_get_tst_info(self.as_ptr()); + if info.is_null() { + None + } else { + Some(TsTstInfoRef::from_const_ptr(info)) + } + } + } } bitflags! { @@ -397,6 +410,28 @@ impl TsRespContext { } } +foreign_type_and_impl_send_sync!{ + type CType = ffi::TS_TST_INFO; + fn drop = ffi::TS_TST_INFO_free; + pub struct TsTstInfo; + pub struct TsTstInfoRef; +} + +impl TsTstInfoRef { + // idk what the null-ness guarantees of this function is as it's not documented in openssl + #[corresponds(TS_TST_INFO_get_time)] + pub fn get_time(&self) -> Option<&Asn1StringRef> { + unsafe { + let ptr = ffi::TS_TST_INFO_get_time(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(Asn1StringRef::from_const_ptr(ptr)) + } + } + } +} + #[cfg(test)] mod tests { use super::*; From cdab526568f9814d859e917e4f59980dbac6152b Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Thu, 29 Aug 2024 21:59:43 +0200 Subject: [PATCH 11/14] pipeline fixes --- openssl-sys/src/handwritten/x509.rs | 2 ++ openssl-sys/src/ts.rs | 27 ++------------------------- openssl/src/lib.rs | 1 + openssl/src/ts.rs | 2 +- openssl/src/x509/mod.rs | 5 ++--- 5 files changed, 8 insertions(+), 29 deletions(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index aba33d8fad..2e6ecaef64 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -212,6 +212,8 @@ extern "C" { pub fn X509_ALGOR_new() -> *mut X509_ALGOR; pub fn X509_ALGOR_free(x: *mut X509_ALGOR); + + #[cfg(ossl101)] pub fn X509_ALGOR_set_md(alg: *mut X509_ALGOR, md: *const EVP_MD); pub fn X509_ALGOR_cmp(alg0: *const X509_ALGOR, alg1: *const X509_ALGOR) -> c_int; diff --git a/openssl-sys/src/ts.rs b/openssl-sys/src/ts.rs index 618a07b6bd..31075afc24 100644 --- a/openssl-sys/src/ts.rs +++ b/openssl-sys/src/ts.rs @@ -1,36 +1,13 @@ use libc::*; -use crate::{ - ASN1_INTEGER, ASN1_OBJECT, ASN1_OCTET_STRING, BIO, EVP_MD, EVP_PKEY, X509, X509_ALGOR, -}; - -use super::ASN1_STRING; +use super::*; pub enum TS_MSG_IMPRINT {} pub enum TS_REQ {} pub enum TS_RESP {} pub enum TS_TST_INFO {} pub enum TS_RESP_CTX {} - -cfg_if! { - if #[cfg(ossl110)] { - pub enum TS_VERIFY_CTX {} - } else { - #[repr(C)] - pub struct TS_VERIFY_CTX { - flags: c_uint, - store: *mut X509_STORE, - certs: *mut stack_st_X509, - policy: *mut ASN1_OBJECT, - md_alg: *mut X509_ALGOR, - imprint: *mut c_uchar, - imprint_len: c_uint, - data: *mut BIO, - nonce: *mut ASN1_INTEGER, - tsa_name: *mut GENERAL_NAME, - } - } -} +pub enum TS_VERIFY_CTX {} pub const TS_VFY_SIGNATURE: c_uint = 0x1; pub const TS_VFY_VERSION: c_uint = 0x2; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index df8b87dc5c..6d74569c51 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -193,6 +193,7 @@ pub mod ssl; pub mod stack; pub mod string; pub mod symm; +#[cfg(all(not(boringssl), not(libressl)))] pub mod ts; pub mod version; pub mod x509; diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index cc7192c080..6d525dc7cb 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -410,7 +410,7 @@ impl TsRespContext { } } -foreign_type_and_impl_send_sync!{ +foreign_type_and_impl_send_sync! { type CType = ffi::TS_TST_INFO; fn drop = ffi::TS_TST_INFO_free; pub struct TsTstInfo; diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 716a853998..4dd969db7c 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -2291,6 +2291,7 @@ impl X509AlgorithmRef { } } + #[cfg(ossl101)] #[corresponds(X509_ALGOR_set_md)] pub fn set_md(&mut self, md: MessageDigest) { unsafe { @@ -2301,9 +2302,7 @@ impl X509AlgorithmRef { impl PartialEq for X509AlgorithmRef { fn eq(&self, other: &Self) -> bool { - unsafe { - ffi::X509_ALGOR_cmp(self.as_ptr(), other.as_ptr()) == 0 - } + unsafe { ffi::X509_ALGOR_cmp(self.as_ptr(), other.as_ptr()) == 0 } } } From 870e0e4ec7e9f1f857c558e52baa6c419bc379f4 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Fri, 30 Aug 2024 16:14:36 +0200 Subject: [PATCH 12/14] adjust TsMsgImprint to not use X509_ALGOR_set_md --- openssl-sys/src/handwritten/x509.rs | 3 +-- openssl/src/ts.rs | 10 ++++++++-- openssl/src/x509/mod.rs | 8 -------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 2e6ecaef64..26c2888fce 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -213,8 +213,7 @@ extern "C" { pub fn X509_ALGOR_new() -> *mut X509_ALGOR; pub fn X509_ALGOR_free(x: *mut X509_ALGOR); - #[cfg(ossl101)] - pub fn X509_ALGOR_set_md(alg: *mut X509_ALGOR, md: *const EVP_MD); + pub fn X509_ALGOR_set0(alg: *mut X509_ALGOR, aobj: *mut ASN1_OBJECT, ptype: c_int, pval: *mut c_void) -> c_int; pub fn X509_ALGOR_cmp(alg0: *const X509_ALGOR, alg1: *const X509_ALGOR) -> c_int; diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 6d525dc7cb..7725677ccb 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -4,6 +4,7 @@ //! The aim is to provide enough functionality for a client to request and //! verify timestamps returned by a Time Stamp Authority. use bitflags::bitflags; +use ffi::{ASN1_OBJECT_free, EVP_MD_get_type, OBJ_nid2obj, X509_ALGOR_set0}; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long, c_uint}; use openssl_macros::corresponds; @@ -91,8 +92,13 @@ impl TsMsgImprint { /// /// `hash` must have originated from the hash function specified by `md`. pub fn from_prehash_with_algo(hash: &[u8], md: MessageDigest) -> Result { - let mut algo = X509Algorithm::new()?; - algo.set_md(md); + let algo = X509Algorithm::new()?; + + let aobj = unsafe { cvt_p(OBJ_nid2obj(EVP_MD_get_type(md.as_ptr())))? }; + let res = unsafe { X509_ALGOR_set0(algo.as_ptr(), aobj, ffi::V_ASN1_NULL, ptr::null_mut()) }; + cvt(res).inspect_err(|_| unsafe { + ASN1_OBJECT_free(aobj); + })?; let mut imprint = Self::new()?; imprint.set_algo(&algo)?; diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 4dd969db7c..13e5489958 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -2290,14 +2290,6 @@ impl X509AlgorithmRef { Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null") } } - - #[cfg(ossl101)] - #[corresponds(X509_ALGOR_set_md)] - pub fn set_md(&mut self, md: MessageDigest) { - unsafe { - ffi::X509_ALGOR_set_md(self.as_ptr(), md.as_ptr()); - } - } } impl PartialEq for X509AlgorithmRef { From 17acb84dacf1b5e983e85b161d1037bf837cc7c0 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Fri, 30 Aug 2024 16:17:44 +0200 Subject: [PATCH 13/14] cargo clippy && cargo fmt --- openssl-sys/src/handwritten/x509.rs | 7 ++++++- openssl/src/ts.rs | 14 +++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 26c2888fce..2b33a6593e 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -213,7 +213,12 @@ extern "C" { pub fn X509_ALGOR_new() -> *mut X509_ALGOR; pub fn X509_ALGOR_free(x: *mut X509_ALGOR); - pub fn X509_ALGOR_set0(alg: *mut X509_ALGOR, aobj: *mut ASN1_OBJECT, ptype: c_int, pval: *mut c_void) -> c_int; + pub fn X509_ALGOR_set0( + alg: *mut X509_ALGOR, + aobj: *mut ASN1_OBJECT, + ptype: c_int, + pval: *mut c_void, + ) -> c_int; pub fn X509_ALGOR_cmp(alg0: *const X509_ALGOR, alg1: *const X509_ALGOR) -> c_int; diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 7725677ccb..8e270276c0 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -94,11 +94,15 @@ impl TsMsgImprint { pub fn from_prehash_with_algo(hash: &[u8], md: MessageDigest) -> Result { let algo = X509Algorithm::new()?; - let aobj = unsafe { cvt_p(OBJ_nid2obj(EVP_MD_get_type(md.as_ptr())))? }; - let res = unsafe { X509_ALGOR_set0(algo.as_ptr(), aobj, ffi::V_ASN1_NULL, ptr::null_mut()) }; - cvt(res).inspect_err(|_| unsafe { - ASN1_OBJECT_free(aobj); - })?; + unsafe { + let aobj = cvt_p(OBJ_nid2obj(EVP_MD_get_type(md.as_ptr())))?; + let res = X509_ALGOR_set0(algo.as_ptr(), aobj, ffi::V_ASN1_NULL, ptr::null_mut()); + + if let Err(e) = cvt(res) { + ASN1_OBJECT_free(aobj); + return Err(e); + } + }; let mut imprint = Self::new()?; imprint.set_algo(&algo)?; From fef401170b019988472056304af06078c7ef6ee3 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Fri, 30 Aug 2024 16:27:28 +0200 Subject: [PATCH 14/14] EVP_MD_type instead of EVP_MD_get_type --- openssl/src/ts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/ts.rs b/openssl/src/ts.rs index 8e270276c0..297529236a 100644 --- a/openssl/src/ts.rs +++ b/openssl/src/ts.rs @@ -4,7 +4,7 @@ //! The aim is to provide enough functionality for a client to request and //! verify timestamps returned by a Time Stamp Authority. use bitflags::bitflags; -use ffi::{ASN1_OBJECT_free, EVP_MD_get_type, OBJ_nid2obj, X509_ALGOR_set0}; +use ffi::{ASN1_OBJECT_free, EVP_MD_type, OBJ_nid2obj, X509_ALGOR_set0}; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long, c_uint}; use openssl_macros::corresponds; @@ -95,7 +95,7 @@ impl TsMsgImprint { let algo = X509Algorithm::new()?; unsafe { - let aobj = cvt_p(OBJ_nid2obj(EVP_MD_get_type(md.as_ptr())))?; + let aobj = cvt_p(OBJ_nid2obj(EVP_MD_type(md.as_ptr())))?; let res = X509_ALGOR_set0(algo.as_ptr(), aobj, ffi::V_ASN1_NULL, ptr::null_mut()); if let Err(e) = cvt(res) {