@@ -12,14 +12,15 @@ use asn1::{Asn1IntegerRef, Asn1ObjectRef};
12
12
use error:: ErrorStack ;
13
13
use ffi;
14
14
use hash:: MessageDigest ;
15
- use x509:: X509Algorithm ;
15
+ use pkey:: { HasPrivate , PKeyRef } ;
16
+ use x509:: { X509Algorithm , X509Ref } ;
16
17
use { cvt, cvt_p} ;
17
18
18
19
foreign_type_and_impl_send_sync ! {
19
20
type CType = ffi:: TS_MSG_IMPRINT ;
20
21
fn drop = ffi:: TS_MSG_IMPRINT_free ;
21
22
22
- /// A message imprint contains the has of the data to be timestamped.
23
+ /// A message imprint contains the hash of the data to be timestamped.
23
24
pub struct TsMsgImprint ;
24
25
25
26
/// Reference to `TsMsgImprint`.
@@ -271,13 +272,125 @@ impl TsVerifyContext {
271
272
}
272
273
}
273
274
275
+ foreign_type_and_impl_send_sync ! {
276
+ type CType = ffi:: TS_RESP_CTX ;
277
+ fn drop = ffi:: TS_RESP_CTX_free ;
278
+
279
+ /// A context object used to sign timestamp requests.
280
+ pub struct TsRespContext ;
281
+
282
+ /// Reference to `TsRespContext`.
283
+ pub struct TsRespContextRef ;
284
+ }
285
+
286
+ impl TsRespContextRef {
287
+ /// Creates a signed timestamp response for the request.
288
+ ///
289
+ /// This corresponds to `TS_RESP_create_response`.
290
+ pub fn create_response ( & mut self , request : & TsReqRef ) -> Result < TsResp , ErrorStack > {
291
+ unsafe {
292
+ let der = request. to_der ( ) ?;
293
+ let bio = :: bio:: MemBioSlice :: new ( & der) ?;
294
+ let response = cvt_p ( ffi:: TS_RESP_create_response ( self . as_ptr ( ) , bio. as_ptr ( ) ) ) ?;
295
+ Ok ( TsResp :: from_ptr ( response) )
296
+ }
297
+ }
298
+ }
299
+
300
+ pub struct TsRespContextBuilder ( TsRespContext ) ;
301
+
302
+ impl TsRespContextBuilder {
303
+ /// Creates a new builder.
304
+ pub fn new ( ) -> Result < TsRespContextBuilder , ErrorStack > {
305
+ unsafe {
306
+ ffi:: init ( ) ;
307
+ let resp_context: * mut ffi:: TS_RESP_CTX = cvt_p ( ffi:: TS_RESP_CTX_new ( ) ) ?;
308
+ Ok ( TsRespContextBuilder ( TsRespContext :: from_ptr ( resp_context) ) )
309
+ }
310
+ }
311
+
312
+ /// Sets the OID of the default policy used by the TSA.
313
+ ///
314
+ /// This corresponds to `TS_RESP_CTX_set_def_policy`.
315
+ pub fn set_default_policy ( & mut self , policy : & Asn1ObjectRef ) -> Result < ( ) , ErrorStack > {
316
+ unsafe {
317
+ cvt ( ffi:: TS_RESP_CTX_set_def_policy (
318
+ self . 0 . as_ptr ( ) ,
319
+ policy. as_ptr ( ) ,
320
+ ) )
321
+ . map ( |_| ( ) )
322
+ }
323
+ }
324
+
325
+ /// Sets the certificate the TSA uses to sign the request.
326
+ ///
327
+ /// This corresponds to `TS_RESP_CTX_set_signer_cert`.
328
+ pub fn set_signer_cert ( & mut self , cert : & X509Ref ) -> Result < ( ) , ErrorStack > {
329
+ unsafe {
330
+ cvt ( ffi:: TS_RESP_CTX_set_signer_cert (
331
+ self . 0 . as_ptr ( ) ,
332
+ cert. as_ptr ( ) ,
333
+ ) )
334
+ . map ( |_| ( ) )
335
+ }
336
+ }
337
+
338
+ /// Sets the private key the TSA uses to sign the request.
339
+ ///
340
+ /// The private key match the X.509 certificate set by `set_signer_cert`.
341
+ ///
342
+ /// This corresponds to `TS_RESP_CTX_set_signer_key`.
343
+ pub fn set_signer_key < T > ( & mut self , pkey : & PKeyRef < T > ) -> Result < ( ) , ErrorStack >
344
+ where
345
+ T : HasPrivate ,
346
+ {
347
+ unsafe {
348
+ cvt ( ffi:: TS_RESP_CTX_set_signer_key (
349
+ self . 0 . as_ptr ( ) ,
350
+ pkey. as_ptr ( ) ,
351
+ ) )
352
+ . map ( |_| ( ) )
353
+ }
354
+ }
355
+
356
+ /// Sets the message digest algorithm to use for the signature.
357
+ ///
358
+ /// This corresponds to `TS_RESP_CTX_set_signer_digest`.
359
+ pub fn set_signer_digest ( & mut self , md : MessageDigest ) -> Result < ( ) , ErrorStack > {
360
+ unsafe {
361
+ cvt ( ffi:: TS_RESP_CTX_set_signer_digest (
362
+ self . 0 . as_ptr ( ) ,
363
+ md. as_ptr ( ) ,
364
+ ) )
365
+ . map ( |_| ( ) )
366
+ }
367
+ }
368
+
369
+ /// Add an accepted message digest algorithm.
370
+ ///
371
+ /// At least one accepted digest algorithm should be added to the context.
372
+ ///
373
+ /// This corresponds to `TS_RESP_CTX_add_md`.
374
+ pub fn add_md ( & mut self , md : MessageDigest ) -> Result < ( ) , ErrorStack > {
375
+ unsafe { cvt ( ffi:: TS_RESP_CTX_add_md ( self . 0 . as_ptr ( ) , md. as_ptr ( ) ) ) . map ( |_| ( ) ) }
376
+ }
377
+
378
+ /// Consume the builder and return the response context.
379
+ pub fn build ( self ) -> TsRespContext {
380
+ self . 0
381
+ }
382
+ }
383
+
274
384
#[ cfg( test) ]
275
385
mod tests {
276
386
use super :: * ;
277
387
278
- use asn1:: Asn1Integer ;
388
+ use asn1:: { Asn1Integer , Asn1Object } ;
279
389
use bn:: BigNum ;
390
+ use hash:: MessageDigest ;
391
+ use pkey:: PKey ;
280
392
use sha:: sha512;
393
+ use x509:: X509 ;
281
394
282
395
#[ test]
283
396
fn test_request ( ) {
@@ -317,4 +430,28 @@ mod tests {
317
430
let context = TsVerifyContext :: from_req ( & request) . unwrap ( ) ;
318
431
response. verify ( & context) . unwrap ( ) ;
319
432
}
433
+
434
+ #[ test]
435
+ fn test_response_context ( ) {
436
+ let mut response_context = TsRespContextBuilder :: new ( ) . unwrap ( ) ;
437
+ response_context
438
+ . set_default_policy ( & Asn1Object :: from_str ( "1.2.3.4" ) . unwrap ( ) )
439
+ . unwrap ( ) ;
440
+ let cert = X509 :: from_pem ( include_bytes ! ( "../test/ts-cert.pem" ) ) . unwrap ( ) ;
441
+ response_context. set_signer_cert ( & cert) . unwrap ( ) ;
442
+ let key = PKey :: private_key_from_pem ( include_bytes ! ( "../test/ts-key.pem" ) ) . unwrap ( ) ;
443
+ response_context. set_signer_key ( & key) . unwrap ( ) ;
444
+
445
+ response_context
446
+ . set_signer_digest ( MessageDigest :: sha256 ( ) )
447
+ . unwrap ( ) ;
448
+ response_context. add_md ( MessageDigest :: sha512 ( ) ) . unwrap ( ) ;
449
+ let mut response_context = response_context. build ( ) ;
450
+
451
+ let request = TsReq :: from_der ( include_bytes ! ( "../test/ts-request.der" ) ) . unwrap ( ) ;
452
+ let response = response_context. create_response ( & request) . unwrap ( ) ;
453
+
454
+ let context = TsVerifyContext :: from_req ( & request) . unwrap ( ) ;
455
+ response. verify ( & context) . unwrap ( ) ;
456
+ }
320
457
}
0 commit comments