Skip to content

Commit 4e98937

Browse files
krisztian-kovacsJonas Maier
authored andcommitted
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.
1 parent 5b12bd1 commit 4e98937

File tree

4 files changed

+217
-3
lines changed

4 files changed

+217
-3
lines changed

openssl-sys/src/ts.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use *;
66
pub enum TS_MSG_IMPRINT {}
77
pub enum TS_REQ {}
88
pub enum TS_RESP {}
9+
pub enum TS_RESP_CTX {}
910

1011
cfg_if! {
1112
if #[cfg(ossl110)] {
@@ -51,6 +52,13 @@ pub const TS_VFY_ALL_DATA: c_uint = TS_VFY_SIGNATURE
5152
| TS_VFY_SIGNER
5253
| TS_VFY_TSA_NAME;
5354

55+
pub const TS_STATUS_GRANTED: c_uint = 0;
56+
pub const TS_STATUS_GRANTED_WITH_MODS: c_uint = 1;
57+
pub const TS_STATUS_REJECTION: c_uint = 2;
58+
pub const TS_STATUS_WAITING: c_uint = 3;
59+
pub const TS_STATUS_REVOCATION_WARNING: c_uint = 4;
60+
pub const TS_STATUS_REVOCATION_NOTIFICATION: c_uint = 5;
61+
5462
extern "C" {
5563
pub fn TS_MSG_IMPRINT_new() -> *mut TS_MSG_IMPRINT;
5664
pub fn TS_MSG_IMPRINT_free(a: *mut TS_MSG_IMPRINT);
@@ -87,6 +95,14 @@ extern "C" {
8795

8896
pub fn TS_REQ_to_TS_VERIFY_CTX(req: *mut TS_REQ, ctx: *mut TS_VERIFY_CTX)
8997
-> *mut TS_VERIFY_CTX;
98+
99+
pub fn TS_RESP_CTX_new() -> *mut TS_RESP_CTX;
100+
pub fn TS_RESP_CTX_free(ctx: *mut TS_RESP_CTX);
101+
pub fn TS_RESP_CTX_set_signer_cert(ctx: *mut TS_RESP_CTX, signer: *mut X509) -> c_int;
102+
pub fn TS_RESP_CTX_set_signer_key(ctx: *mut TS_RESP_CTX, key: *mut EVP_PKEY) -> c_int;
103+
pub fn TS_RESP_CTX_add_md(ctx: *mut TS_RESP_CTX, md: *const EVP_MD) -> c_int;
104+
105+
pub fn TS_RESP_create_response(ctx: *mut TS_RESP_CTX, req_bio: *mut BIO) -> *mut TS_RESP;
90106
}
91107

92108
cfg_if! {
@@ -96,13 +112,32 @@ cfg_if! {
96112
a: *mut TS_REQ,
97113
policy: *const ASN1_OBJECT
98114
) -> c_int;
115+
pub fn TS_RESP_CTX_set_def_policy(
116+
ctx: *mut TS_RESP_CTX,
117+
def_policy: *const ASN1_OBJECT
118+
) -> c_int;
99119
}
100120
} else {
101121
extern "C" {
102122
pub fn TS_REQ_set_policy_id(
103123
a: *mut TS_REQ,
104124
policy: *mut ASN1_OBJECT
105125
) -> c_int;
126+
pub fn TS_RESP_CTX_set_def_policy(
127+
ctx: *mut TS_RESP_CTX,
128+
def_policy: *mut ASN1_OBJECT
129+
) -> c_int;
130+
}
131+
}
132+
}
133+
134+
cfg_if! {
135+
if #[cfg(ossl110)] {
136+
extern "C" {
137+
pub fn TS_RESP_CTX_set_signer_digest(
138+
ctx: *mut TS_RESP_CTX,
139+
signer_digest: *const EVP_MD,
140+
) -> c_int;
106141
}
107142
}
108143
}

openssl/src/ts.rs

Lines changed: 135 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ use libc::{c_int, c_long, c_uint};
1010
use std::ptr;
1111

1212
use crate::asn1::{Asn1IntegerRef, Asn1ObjectRef};
13+
use crate::bio::MemBioSlice;
1314
use crate::error::ErrorStack;
1415
use crate::hash::MessageDigest;
15-
use crate::x509::X509Algorithm;
16+
use crate::pkey::{HasPrivate, PKeyRef};
17+
use crate::x509::{X509Algorithm, X509Ref};
1618
use crate::{cvt, cvt_p};
1719

1820
foreign_type_and_impl_send_sync! {
1921
type CType = ffi::TS_MSG_IMPRINT;
2022
fn drop = ffi::TS_MSG_IMPRINT_free;
2123

22-
/// A message imprint contains the has of the data to be timestamped.
24+
/// A message imprint contains the hash of the data to be timestamped.
2325
pub struct TsMsgImprint;
2426

2527
/// Reference to `TsMsgImprint`.
@@ -255,13 +257,123 @@ impl TsVerifyContext {
255257
}
256258
}
257259

260+
foreign_type_and_impl_send_sync! {
261+
type CType = ffi::TS_RESP_CTX;
262+
fn drop = ffi::TS_RESP_CTX_free;
263+
264+
/// A context object used to sign timestamp requests.
265+
pub struct TsRespContext;
266+
267+
/// Reference to `TsRespContext`.
268+
pub struct TsRespContextRef;
269+
}
270+
271+
impl TsRespContextRef {
272+
/// Creates a signed timestamp response for the request.
273+
///
274+
/// This corresponds to `TS_RESP_create_response`.
275+
pub fn create_response(&mut self, request: &TsReqRef) -> Result<TsResp, ErrorStack> {
276+
unsafe {
277+
let der = request.to_der()?;
278+
let bio = MemBioSlice::new(&der)?;
279+
let response = cvt_p(ffi::TS_RESP_create_response(self.as_ptr(), bio.as_ptr()))?;
280+
Ok(TsResp::from_ptr(response))
281+
}
282+
}
283+
}
284+
285+
impl TsRespContext {
286+
/// Creates a new response context.
287+
///
288+
/// This corresponds to `TS_RESP_CTX_new`.
289+
pub fn new() -> Result<TsRespContext, ErrorStack> {
290+
unsafe {
291+
ffi::init();
292+
let resp_context: *mut ffi::TS_RESP_CTX = cvt_p(ffi::TS_RESP_CTX_new())?;
293+
Ok(TsRespContext::from_ptr(resp_context))
294+
}
295+
}
296+
297+
/// Sets the OID of the default policy used by the TSA.
298+
///
299+
/// This corresponds to `TS_RESP_CTX_set_def_policy`.
300+
pub fn set_default_policy(&mut self, policy: &Asn1ObjectRef) -> Result<(), ErrorStack> {
301+
unsafe {
302+
cvt(ffi::TS_RESP_CTX_set_def_policy(
303+
self.as_ptr(),
304+
policy.as_ptr(),
305+
))
306+
.map(|_| ())
307+
}
308+
}
309+
310+
/// Sets the certificate the TSA uses to sign the request.
311+
///
312+
/// This corresponds to `TS_RESP_CTX_set_signer_cert`.
313+
pub fn set_signer_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
314+
unsafe {
315+
cvt(ffi::TS_RESP_CTX_set_signer_cert(
316+
self.as_ptr(),
317+
cert.as_ptr(),
318+
))
319+
.map(|_| ())
320+
}
321+
}
322+
323+
/// Sets the private key the TSA uses to sign the request.
324+
///
325+
/// The private key match the X.509 certificate set by `set_signer_cert`.
326+
///
327+
/// This corresponds to `TS_RESP_CTX_set_signer_key`.
328+
pub fn set_signer_key<T>(&mut self, pkey: &PKeyRef<T>) -> Result<(), ErrorStack>
329+
where
330+
T: HasPrivate,
331+
{
332+
unsafe {
333+
cvt(ffi::TS_RESP_CTX_set_signer_key(
334+
self.as_ptr(),
335+
pkey.as_ptr(),
336+
))
337+
.map(|_| ())
338+
}
339+
}
340+
341+
/// Sets the message digest algorithm to use for the signature.
342+
///
343+
///
344+
/// Requires OpenSSL 1.1.0 or newer.
345+
/// This corresponds to `TS_RESP_CTX_set_signer_digest`.
346+
#[cfg(ossl110)]
347+
pub fn set_signer_digest(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
348+
unsafe {
349+
cvt(ffi::TS_RESP_CTX_set_signer_digest(
350+
self.as_ptr(),
351+
md.as_ptr(),
352+
))
353+
.map(|_| ())
354+
}
355+
}
356+
357+
/// Add an accepted message digest algorithm.
358+
///
359+
/// At least one accepted digest algorithm should be added to the context.
360+
///
361+
/// This corresponds to `TS_RESP_CTX_add_md`.
362+
pub fn add_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
363+
unsafe { cvt(ffi::TS_RESP_CTX_add_md(self.as_ptr(), md.as_ptr())).map(|_| ()) }
364+
}
365+
}
366+
258367
#[cfg(test)]
259368
mod tests {
260369
use super::*;
261370

262-
use crate::asn1::Asn1Integer;
371+
use crate::asn1::{Asn1Integer, Asn1Object};
263372
use crate::bn::BigNum;
373+
use crate::hash::MessageDigest;
374+
use crate::pkey::PKey;
264375
use crate::sha::sha512;
376+
use crate::x509::X509;
265377

266378
#[test]
267379
fn test_request() {
@@ -299,4 +411,24 @@ mod tests {
299411
let context = TsVerifyContext::from_req(&request).unwrap();
300412
response.verify(&context).unwrap();
301413
}
414+
415+
#[test]
416+
fn test_response_context() {
417+
let mut response_context = TsRespContext::new().unwrap();
418+
response_context
419+
.set_default_policy(&Asn1Object::from_str("1.2.3.4").unwrap())
420+
.unwrap();
421+
let cert = X509::from_pem(include_bytes!("../test/ts-cert.pem")).unwrap();
422+
response_context.set_signer_cert(&cert).unwrap();
423+
let key = PKey::private_key_from_pem(include_bytes!("../test/ts-key.pem")).unwrap();
424+
response_context.set_signer_key(&key).unwrap();
425+
426+
response_context.add_md(MessageDigest::sha512()).unwrap();
427+
428+
let request = TsReq::from_der(include_bytes!("../test/ts-request.der")).unwrap();
429+
let response = response_context.create_response(&request).unwrap();
430+
431+
let context = TsVerifyContext::from_req(&request).unwrap();
432+
response.verify(&context).unwrap();
433+
}
302434
}

openssl/test/ts-cert.pem

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDOjCCAiKgAwIBAgIFN8DNd/kwDQYJKoZIhvcNAQELBQAwRTELMAkGA1UEBhMC
3+
QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp
4+
dHMgUHR5IEx0ZDAeFw0yMDEwMjcwODQwMTBaFw0zMTEwMTAwODQwMTBaMFwxCzAJ
5+
BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l
6+
dCBXaWRnaXRzIFB0eSBMdGQxFTATBgNVBAMTDFRpbWVzdGFtcGluZzCCASIwDQYJ
7+
KoZIhvcNAQEBBQADggEPADCCAQoCggEBANUTsyhUuzou06s/XXelCLSF7sd8xtFO
8+
4OJFEWAulg5K4m7w/GG/VIaelvqgNxdSHdzheT1l1UrMP6na2tAcAS5tBv+X0Q0C
9+
T3+FqlqcgV2HSUNKJy3CJ1CoNQCuN6eaqO7y3O9yfdze8jCpHcrYrx4BFNISw8/T
10+
KaAKQRHjrVbAOlIA+nCc7MGYXJS9ZVwfXNASrhRBoswLoesSf4mX1PPXwjnhGJMq
11+
nVhVI+1G1gD9t4l7CrdOhx5vONffOoSjmqDVfRmcyYNT33V8zlynUoKwLF985TKo
12+
hJAfA8qQDczLkPv6shssNWk8BJ+mYRz3sU9QHM4dkX1oql3oWlOx+o0CAwEAAaMa
13+
MBgwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggEBAC1D
14+
6A5FrPsYV4Q2Zar/MdYsuA2XM2j8SA/H2m4uGz8Sg52/V1VWBouB4JVz1EHytAlG
15+
BD2A+71Bk/Y6JpxdU51O/ZgGlrOaCs+1L4+WLe1cgXGcgC65fP7eMCF3ajuOYZid
16+
q5cJxpbBEspecus7ArqEQ9+ahAVZXcSuKfHOcW+3DxqP3/GPvbt4vLdxjPbe1Dbx
17+
Le+UkPPIQoKNk7yOILMuZrR+O4E4O0cn7E2qodUoYIxSOWIg9euvfntFyR66NzXL
18+
+pDtbVzWPKNiqgvhx5n5GjdyQGHA0X2gEpepT3p3S9dHMcdjJfDixVKp8F5f9mbx
19+
6wgs4XG7rb8sRDsAmAc=
20+
-----END CERTIFICATE-----

openssl/test/ts-key.pem

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpAIBAAKCAQEA1ROzKFS7Oi7Tqz9dd6UItIXux3zG0U7g4kURYC6WDkribvD8
3+
Yb9Uhp6W+qA3F1Id3OF5PWXVSsw/qdra0BwBLm0G/5fRDQJPf4WqWpyBXYdJQ0on
4+
LcInUKg1AK43p5qo7vLc73J93N7yMKkdytivHgEU0hLDz9MpoApBEeOtVsA6UgD6
5+
cJzswZhclL1lXB9c0BKuFEGizAuh6xJ/iZfU89fCOeEYkyqdWFUj7UbWAP23iXsK
6+
t06HHm841986hKOaoNV9GZzJg1PfdXzOXKdSgrAsX3zlMqiEkB8DypANzMuQ+/qy
7+
Gyw1aTwEn6ZhHPexT1Aczh2RfWiqXehaU7H6jQIDAQABAoIBAQDCoR76DQOELvfL
8+
qbKfshDUjK5Ca9hTokBKjppDh+orHf3dJqTySElWOhBg1+3akHiUpSQQkC8XBqB0
9+
b2OFyr7NgGtvFmavAlhJfHfSErkcDJJAM8C7zGgLBcp8V6agouYCdbaXxbXwBXmm
10+
NyPugKTcvFIfXWKdOB4CgLtVMunHnVz97+2O6HwN3nPfnsUTBNlImyO9UFO+2utB
11+
kk8vx9qvxhVo6bRmL85+CmuPAN0XiYaXqKRyF55b37c69A1mrMsGimRCO9fxuhhW
12+
JW7UwbXM/RHEDKRfD2P8dWMWyw+jQEBzQKrGZ/2dbjuXOVsTT6h/UVnLdFR7ntrk
13+
HljlNsXhAoGBAPwOyAIPBe9MZPmItO4Ssw2hr62MglmXYQITT+i6uuun2LMr6X/E
14+
zTlMNZGTOXPt8mDuPmELXX4rpKu1lBTuhM9/csbYG32kQK2I6j0QuY1fQ+NHnzcA
15+
4e9SkctZSx0auSo4u3+8SaoRpFfbxs6+tv7xJCcmvxkJZrKnTS7Z0SOJAoGBANho
16+
17fBqN63ogcf8y74D15KyxJi/spr7ZAZY1mH212TGf2xOC2gWpLyl+mENjj9L0+j
17+
qRh0J7y0wcnX9ZuuZHmU647/9bM3q21ZLpoP/gbUdZEBU9CnurCk+tTlGZ49iiN0
18+
KqX86JuynNlou/gcNFJS1v62TCnTr+aWGH6vOmnlAoGBALbTQd+8ZeGc1+Dnd9T3
19+
W0iX7oVDVYkGdCa9O0jjqJElvdi4ETXL2c+lp3VgBFxCS3xjUnuxcq8BmP+zRSWp
20+
nEuldesk9Uu8x+0XUk/Ywb35S5SfbqzGxxqAGaAVtJX3vDcTz2xndkcVZM8Vaq6r
21+
RrDE2CRNxm6ykvsivqks9LWBAoGAfuqF0KPHyM5DPRB0y0/5m2Ab1m2uZcKEMWVi
22+
SaiOc0OJE6pyeve3BsU1aGL8ddGuhHNEAS5l+5q6qAh6Z1IQZOl8eIIOc4urgtax
23+
qPLGFPVW+bKgmBc2OtCWtnKh4pbOw9omBPDc7isDJ9HvoyPPX5RruDfrVQBsAbx3
24+
IxzbEi0CgYAXZDdGCX1GiW1qBOGzgN/omrEKuXVQ9QEQYfAy+EWYw6EfWYSzgi3d
25+
QRV2x5q/T4IdPlrFM5fNilQGH2F9fGLX/CSJLWqnvPEKaB6e89y2ncFFZFIaP0YT
26+
UxDNUSmAmdP+GBYZCl3cYAUtVBKrjjyHRkCy8to62ldbSV7jsngX0A==
27+
-----END RSA PRIVATE KEY-----

0 commit comments

Comments
 (0)