@@ -10,16 +10,18 @@ use libc::{c_int, c_long, c_uint};
10
10
use std:: ptr;
11
11
12
12
use crate :: asn1:: { Asn1IntegerRef , Asn1ObjectRef } ;
13
+ use crate :: bio:: MemBioSlice ;
13
14
use crate :: error:: ErrorStack ;
14
15
use crate :: hash:: MessageDigest ;
15
- use crate :: x509:: X509Algorithm ;
16
+ use crate :: pkey:: { HasPrivate , PKeyRef } ;
17
+ use crate :: x509:: { X509Algorithm , X509Ref } ;
16
18
use crate :: { cvt, cvt_p} ;
17
19
18
20
foreign_type_and_impl_send_sync ! {
19
21
type CType = ffi:: TS_MSG_IMPRINT ;
20
22
fn drop = ffi:: TS_MSG_IMPRINT_free ;
21
23
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.
23
25
pub struct TsMsgImprint ;
24
26
25
27
/// Reference to `TsMsgImprint`.
@@ -255,13 +257,123 @@ impl TsVerifyContext {
255
257
}
256
258
}
257
259
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
+
258
367
#[ cfg( test) ]
259
368
mod tests {
260
369
use super :: * ;
261
370
262
- use crate :: asn1:: Asn1Integer ;
371
+ use crate :: asn1:: { Asn1Integer , Asn1Object } ;
263
372
use crate :: bn:: BigNum ;
373
+ use crate :: hash:: MessageDigest ;
374
+ use crate :: pkey:: PKey ;
264
375
use crate :: sha:: sha512;
376
+ use crate :: x509:: X509 ;
265
377
266
378
#[ test]
267
379
fn test_request ( ) {
@@ -299,4 +411,24 @@ mod tests {
299
411
let context = TsVerifyContext :: from_req ( & request) . unwrap ( ) ;
300
412
response. verify ( & context) . unwrap ( ) ;
301
413
}
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
+ }
302
434
}
0 commit comments