guardtime 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/ChangeLog +5 -2
  2. data/README.rdoc +55 -0
  3. data/ext/guardtime.c +165 -171
  4. data/test/tc_guardtime.rb +91 -91
  5. metadata +10 -6
data/ChangeLog CHANGED
@@ -1,8 +1,11 @@
1
- Release 0.0.2 (2013-01-02 by risto):
1
+ Release 0.0.3 (2013-01-07 by risto):
2
+ - Documentation improvements, supports both RDoc and yard.
3
+
4
+ Release 0.0.2 (2013-01-05 by risto):
2
5
  - added RDoc
3
6
  - new function 'extend'
4
7
  - minor bug: double free when 'extended' signature is verified
5
8
  - GT library init done at 'require' time instead of instantiation time.
6
9
 
7
- Release 0.0.1 (2013-01-05 by risto):
10
+ Release 0.0.1 (2013-01-02 by risto):
8
11
  - initial verion
data/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ == About
2
+
3
+ Ruby API for accessing GuardTime Keyless Signature services.
4
+
5
+ == Links
6
+
7
+ API docs: http://rubydoc.info/gems/guardtime/
8
+
9
+ Information about the service: http://www.guardtime.com/signatures/technology-overview/
10
+
11
+ Installation: see INSTALL
12
+
13
+ == Background
14
+
15
+ The two main operations are signing and verification. Signing involves cryptographically binding the data whose integrity is to be protected to the audited time value and server component's identity in a way that neither the data, the time value nor identity could later be changed undetectably. Verification means checking that the binding is still intact.
16
+
17
+ To get a sigature token from a GuardTime service, the client application computes a hash value of the data to be signed and submits the hash value to the signing service. The service returns a signature token binding the hash value to the current time. The interaction follows the standard cryptographic time-stamping protocol defined in the RFC 3161.
18
+
19
+ Every month, GuardTime creates an Integrity Code and publishes it in several newspapers across the world. The Integrity Code is a summary of all signatures issued by the GuardTime data integrity services. Any signature issued prior to the creation of the Integrity Code can be traced to it to unambiguously prove the signature’s issuing time, issuer ID and link to signed data, effectively proving the data integrity.
20
+
21
+ The proof connecting the signature to the Integrity Code can be inserted back into the token in a process we call extending. An extended signature token is completely independent of GuardTime. Only the original data, the signature and any copy of the newspaper where the Integrity Code is published will be necessary to prove the intgerity of the document.
22
+
23
+ For convenience, GuardTime publishes an electronic archive containing all Integrity Codes since the launch of the service and all valid signing keys. This electronic archive can be used to automate mass verification of thousands of timestamps (whether extended or not) per second in a large archive.
24
+
25
+ == Usage
26
+
27
+ Sign:
28
+
29
+ require 'guardtime'
30
+ require 'digest/sha2'
31
+
32
+ h = Digest::SHA2.new << 'This text shall be signed!'
33
+ gt = GuardTime.new
34
+ sig = gt.sign(h)
35
+ # ...and verify right away
36
+ puts 'OK!' if gt.verify(sig, h)
37
+
38
+ Verify:
39
+
40
+ def slurpfile (fn)
41
+ File.open(fn, 'rb') {|f| f.read}
42
+ end
43
+
44
+ token = slurpfile('importantdata.txt.gtts')
45
+ hasher = GuardTime.getnewdigester(token)
46
+ hasher << slurpfile('importantdata.txt')
47
+ gt = GuardTime.new
48
+ signedAt = nil
49
+ okay = gt.verify(token, hasher) do |r|
50
+ signedAt = r[:time]
51
+ /company$/ =~ r[:location_name] and
52
+ r[:verification_errors] == GuardTime::NO_FAILURES
53
+ end
54
+ puts "data signed at #{signedAt.utc.to_s}" if okay
55
+
data/ext/guardtime.c CHANGED
@@ -36,7 +36,7 @@ typedef struct _GuardTimeData {
36
36
  char * loadpubs;
37
37
  time_t pubdataupdated;
38
38
  GT_Time_t64 lastpublicationtime;
39
- GTPublicationsFile *pub;
39
+ GTPublicationsFile *pub;
40
40
  } GuardTimeData;
41
41
 
42
42
 
@@ -180,7 +180,6 @@ cleanup:
180
180
  return res;
181
181
  }
182
182
 
183
-
184
183
  static void get_gtdatahash(VALUE digest, GTDataHash *dh)
185
184
  {
186
185
  int gtalgoid;
@@ -189,17 +188,17 @@ static void get_gtdatahash(VALUE digest, GTDataHash *dh)
189
188
  int bitlen = 8 * NUM2INT(rb_funcall(digest, rb_intern("digest_length"), 0));
190
189
 
191
190
  gtalgoid = (
192
- strcasecmp(cn, "Digest::SHA1") == 0 ? GT_HASHALG_SHA1 :
193
- strcasecmp(cn, "Digest::SHA2") == 0 ?
194
- (bitlen == 224 ? GT_HASHALG_SHA224 :
195
- bitlen == 256 ? GT_HASHALG_SHA256 :
196
- bitlen == 384 ? GT_HASHALG_SHA384 :
197
- bitlen == 512 ? GT_HASHALG_SHA512 : -1
198
- ) :
199
- strcasecmp(cn, "Digest::RMD160") == 0 ? GT_HASHALG_RIPEMD160 :
200
- -1);
191
+ strcasecmp(cn, "Digest::SHA1") == 0 ? GT_HASHALG_SHA1 :
192
+ strcasecmp(cn, "Digest::SHA2") == 0 ?
193
+ (bitlen == 224 ? GT_HASHALG_SHA224 :
194
+ bitlen == 256 ? GT_HASHALG_SHA256 :
195
+ bitlen == 384 ? GT_HASHALG_SHA384 :
196
+ bitlen == 512 ? GT_HASHALG_SHA512 : -1
197
+ ):
198
+ strcasecmp(cn, "Digest::RMD160") == 0 ? GT_HASHALG_RIPEMD160 : -1
199
+ );
201
200
  if (gtalgoid < 0)
202
- rb_raise(rb_eRuntimeError, "Argument must be supported Digest::... instance.");
201
+ rb_raise(rb_eArgError, "Argument must be supported Digest::... instance.");
203
202
 
204
203
  dh->context = NULL;
205
204
  dh->algorithm = gtalgoid;
@@ -213,15 +212,15 @@ static void get_gtdatahash2(VALUE algo, VALUE digest, GTDataHash *dh)
213
212
  StringValue(algo);
214
213
  StringValue(digest);
215
214
  gtalgoid = (
216
- strcasecmp(RSTRING_PTR(algo), "sha1") == 0 ? GT_HASHALG_SHA1 :
217
- strcasecmp(RSTRING_PTR(algo), "sha224") == 0 ? GT_HASHALG_SHA224 :
218
- strcasecmp(RSTRING_PTR(algo), "sha256") == 0 ? GT_HASHALG_SHA256 :
219
- strcasecmp(RSTRING_PTR(algo), "sha384") == 0 ? GT_HASHALG_SHA384 :
220
- strcasecmp(RSTRING_PTR(algo), "sha512") == 0 ? GT_HASHALG_SHA512 :
221
- strcasecmp(RSTRING_PTR(algo), "ripemd160") == 0 ? GT_HASHALG_RIPEMD160 :
222
- -1);
215
+ strcasecmp(RSTRING_PTR(algo), "sha1") == 0 ? GT_HASHALG_SHA1 :
216
+ strcasecmp(RSTRING_PTR(algo), "sha224") == 0 ? GT_HASHALG_SHA224 :
217
+ strcasecmp(RSTRING_PTR(algo), "sha256") == 0 ? GT_HASHALG_SHA256 :
218
+ strcasecmp(RSTRING_PTR(algo), "sha384") == 0 ? GT_HASHALG_SHA384 :
219
+ strcasecmp(RSTRING_PTR(algo), "sha512") == 0 ? GT_HASHALG_SHA512 :
220
+ strcasecmp(RSTRING_PTR(algo), "ripemd160") == 0 ? GT_HASHALG_RIPEMD160 :
221
+ -1);
223
222
  if (gtalgoid < 0)
224
- rb_raise(rb_eRuntimeError, "Argument must be supported Digest::... instance.");
223
+ rb_raise(rb_eArgError, "Argument must be supported Digest::... instance.");
225
224
 
226
225
  dh->context = NULL;
227
226
  dh->algorithm = gtalgoid;
@@ -252,8 +251,8 @@ guardtime_sign(int argc, VALUE *argv, VALUE obj)
252
251
  GTDataHash dh;
253
252
  GTTimestamp *ts;
254
253
  unsigned char *data;
255
- size_t data_length;
256
- GuardTimeData *gt;
254
+ size_t data_length;
255
+ GuardTimeData *gt;
257
256
  VALUE hash, hash2, result;
258
257
 
259
258
  switch (rb_scan_args(argc, argv, "11", &hash, &hash2)) {
@@ -268,14 +267,13 @@ guardtime_sign(int argc, VALUE *argv, VALUE obj)
268
267
  res = GTHTTP_createTimestampHash(&dh, gt->signeruri, &ts);
269
268
  if (res != GT_OK)
270
269
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
271
- // todo - return here? or does it use longjmp etc?
272
270
 
273
- res = GTTimestamp_getDEREncoded(ts, &data, &data_length);
271
+ res = GTTimestamp_getDEREncoded(ts, &data, &data_length);
274
272
  if (res != GT_OK)
275
273
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
276
- GTTimestamp_free(ts);
277
- result = rb_str_new((char*)data, data_length);
278
- GT_free(data);
274
+ GTTimestamp_free(ts);
275
+ result = rb_str_new((char*)data, data_length);
276
+ GT_free(data);
279
277
  return result;
280
278
  }
281
279
 
@@ -291,7 +289,7 @@ guardtime_sign(int argc, VALUE *argv, VALUE obj)
291
289
  * - +ArgumentError+ -> if any value is nil or wrong type.
292
290
  * - +RuntimeError+ -> other errors, including network, hash value, token too new or old etc. Proper description is in the error message.
293
291
  * Extended signature token may be used for 'independent' verification without any keys or services. Just data, token and newspaper with published value.
294
- * There is no point in extending the signature before next newspaper publication is performed. Good rule of thumb is to wait for 35 days, or until 15th date plus 5 more days.
292
+ * There is no point in extending new signature before next newspaper publication is performed. Good rule of thumb is to wait for 35 days (after signing), or until 15th date plus 5 more days.
295
293
  */
296
294
  static VALUE
297
295
  guardtime_extend(VALUE obj, VALUE in)
@@ -300,28 +298,28 @@ guardtime_extend(VALUE obj, VALUE in)
300
298
  GTDataHash dh;
301
299
  GTTimestamp *ts, *ts2;
302
300
  unsigned char *data;
303
- size_t data_length;
304
- GuardTimeData *gt;
301
+ size_t data_length;
302
+ GuardTimeData *gt;
305
303
  VALUE result;
306
304
 
307
305
  StringValue(in);
308
306
  Data_Get_Struct(obj, GuardTimeData, gt);
309
307
  res = GTTimestamp_DERDecode(RSTRING_PTR(in),
310
- RSTRING_LEN(in), &ts);
311
- if (res != GT_OK)
312
- rb_raise(rb_eArgError, GT_getErrorString(res));
308
+ RSTRING_LEN(in), &ts);
309
+ if (res != GT_OK)
310
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
313
311
 
314
312
  res = GTHTTP_extendTimestamp(ts, gt->verifieruri, &ts2);
315
313
  GTTimestamp_free(ts);
316
314
  if (res != GT_OK)
317
315
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
318
316
 
319
- res = GTTimestamp_getDEREncoded(ts2, &data, &data_length);
317
+ res = GTTimestamp_getDEREncoded(ts2, &data, &data_length);
320
318
  if (res != GT_OK)
321
319
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
322
320
 
323
- result = rb_str_new((char*)data, data_length);
324
- GT_free(data);
321
+ result = rb_str_new((char*)data, data_length);
322
+ GT_free(data);
325
323
  return result;
326
324
  }
327
325
 
@@ -331,7 +329,7 @@ int loadpubs_helper(GuardTimeData *gt) {
331
329
  GTPubFileVerificationInfo *pub_ver;
332
330
 
333
331
  if (gt->pub != NULL)
334
- GTPublicationsFile_free(gt->pub);
332
+ GTPublicationsFile_free(gt->pub);
335
333
  res = GTHTTP_getPublicationsFile(gt->pubfileuri, &(gt->pub));
336
334
  if (res == GT_OK)
337
335
  res = GTPublicationsFile_verify(gt->pub, &pub_ver);
@@ -403,20 +401,20 @@ format_location_id(GT_UInt64 l)
403
401
  static VALUE
404
402
  format_hash_algorithm(int alg)
405
403
  {
406
- switch(alg) {
407
- case GT_HASHALG_SHA256:
408
- return rb_str_new2("SHA256");
409
- case GT_HASHALG_SHA1:
410
- return rb_str_new2("SHA1");
411
- case GT_HASHALG_RIPEMD160:
412
- return rb_str_new2("RIPEMD160");
413
- case GT_HASHALG_SHA224:
414
- return rb_str_new2("SHA224");
415
- case GT_HASHALG_SHA384:
416
- return rb_str_new2("SHA384");
417
- case GT_HASHALG_SHA512:
418
- return rb_str_new2("SHA512");
419
- default:
404
+ switch(alg) {
405
+ case GT_HASHALG_SHA256:
406
+ return rb_str_new2("SHA256");
407
+ case GT_HASHALG_SHA1:
408
+ return rb_str_new2("SHA1");
409
+ case GT_HASHALG_RIPEMD160:
410
+ return rb_str_new2("RIPEMD160");
411
+ case GT_HASHALG_SHA224:
412
+ return rb_str_new2("SHA224");
413
+ case GT_HASHALG_SHA384:
414
+ return rb_str_new2("SHA384");
415
+ case GT_HASHALG_SHA512:
416
+ return rb_str_new2("SHA512");
417
+ default:
420
418
  return Qnil;
421
419
  }
422
420
  }
@@ -440,7 +438,7 @@ format_hash_algorithm(int alg)
440
438
  * - +ArgumentError+ -> if any value is nil or wrong type, or signature token is corrupted.
441
439
  * - +RuntimeError+ -> other errors, including network, hash value etc.
442
440
  *
443
- * Code block receives parameter +resulthash+ which is populated with signature properties. There are following keys:
441
+ * Code block receives parameter +resulthash+ which is populated with verified signature properties. There are following keys:
444
442
  * *verification_errors*:: bitfield containing verification errors. See class constants. Verification is successful only if value equals to <tt>GuardTime::NO_FAILURES</tt>
445
443
  * *verification_status*:: Numeric bitfield -- flags identifying successful verification checks. See class constants.
446
444
  * *time*:: Time object containing signing (time-stamp) datum.
@@ -491,29 +489,29 @@ guardtime_verify(int argc, VALUE *argv, VALUE obj)
491
489
  argcount = rb_scan_args(argc, argv, "12&", &tsdata, &hash, &hash2, &block);
492
490
  StringValue(tsdata);
493
491
 
494
- res = GTTimestamp_DERDecode(RSTRING_PTR(tsdata),
495
- RSTRING_LEN(tsdata), &ts);
496
- if (res != GT_OK)
492
+ res = GTTimestamp_DERDecode(RSTRING_PTR(tsdata),
493
+ RSTRING_LEN(tsdata), &ts);
494
+ if (res != GT_OK)
497
495
  rb_raise(rb_eArgError, GT_getErrorString(res));
498
496
 
499
497
  loadpubs(obj);
500
- GTVerificationInfo *verification_info = NULL;
501
- switch (argcount) {
502
- case 1:
503
- res = verifyTimestamp(ts, NULL, gt, RTEST(block)? 1:0, &verification_info);
504
- break;
505
- case 2:
498
+ GTVerificationInfo *verification_info = NULL;
499
+ switch (argcount) {
500
+ case 1:
501
+ res = verifyTimestamp(ts, NULL, gt, RTEST(block)? 1:0, &verification_info);
502
+ break;
503
+ case 2:
506
504
  get_gtdatahash(hash, &dh);
507
- res = verifyTimestamp(ts, &dh, gt, RTEST(block)? 1:0, &verification_info);
508
- break;
509
- case 3:
505
+ res = verifyTimestamp(ts, &dh, gt, RTEST(block)? 1:0, &verification_info);
506
+ break;
507
+ case 3:
510
508
  get_gtdatahash2(hash, hash2, &dh);
511
- res = verifyTimestamp(ts, &dh, gt, RTEST(block)? 1:0, &verification_info);
512
- break;
513
- }
509
+ res = verifyTimestamp(ts, &dh, gt, RTEST(block)? 1:0, &verification_info);
510
+ break;
511
+ }
514
512
 
515
513
  if (res != GT_OK) {
516
- GTTimestamp_free(ts);
514
+ GTTimestamp_free(ts);
517
515
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
518
516
  }
519
517
 
@@ -522,7 +520,7 @@ guardtime_verify(int argc, VALUE *argv, VALUE obj)
522
520
  #define RBSET(n, v) \
523
521
  ( rb_hash_aset(retval, ID2SYM(rb_intern(n)), (v)) )
524
522
 
525
- if (RTEST(block)) {
523
+ if (RTEST(block)) {
526
524
  retval = rb_hash_new();
527
525
  RBSET("verification_status", INT2FIX( verification_info->verification_status ));
528
526
  RBSET("verification_errors", INT2FIX( verification_info->verification_errors ));
@@ -549,11 +547,11 @@ guardtime_verify(int argc, VALUE *argv, VALUE obj)
549
547
 
550
548
  RBSET("time", time_t_to_Time( verification_info->implicit_data->registered_time ));
551
549
  RBSET("publication_time", time_t_to_Time( verification_info->explicit_data->publication_identifier ));
552
- } else
553
- retval = verification_info->verification_errors == GT_NO_FAILURES ? Qtrue : Qfalse;
550
+ } else
551
+ retval = verification_info->verification_errors == GT_NO_FAILURES ? Qtrue : Qfalse;
554
552
 
555
- GTTimestamp_free(ts);
556
- GTVerificationInfo_free(verification_info);
553
+ GTTimestamp_free(ts);
554
+ GTVerificationInfo_free(verification_info);
557
555
 
558
556
  if (RTEST(block))
559
557
  return rb_funcall(block, rb_intern("call"), 1, retval);
@@ -577,48 +575,48 @@ static VALUE
577
575
  guardtime_getnewdigester(VALUE self, VALUE tsdata)
578
576
  {
579
577
  int res;
580
- int alg;
578
+ int alg;
581
579
  GTTimestamp *ts;
582
580
  VALUE module_klass, args[1];
583
581
 
584
582
  StringValue(tsdata);
585
583
 
586
584
  res = GTTimestamp_DERDecode(RSTRING_PTR(tsdata), RSTRING_LEN(tsdata), &ts);
587
- if (res != GT_OK)
585
+ if (res != GT_OK)
588
586
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
589
587
 
590
- res = GTTimestamp_getAlgorithm(ts, &alg);
591
- GTTimestamp_free(ts);
592
- if (res != GT_OK)
588
+ res = GTTimestamp_getAlgorithm(ts, &alg);
589
+ GTTimestamp_free(ts);
590
+ if (res != GT_OK)
593
591
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
594
592
 
595
593
  // checkifnecessary: rb_requre('digest');
596
594
  module_klass = rb_const_get(rb_cObject, rb_intern("Digest"));
597
595
 
598
596
  switch(alg) {
599
- case GT_HASHALG_SHA256:
600
- args[0] = INT2FIX(256);
601
- return rb_class_new_instance(1, args,
602
- rb_const_get(module_klass, rb_intern("SHA2")));
603
- case GT_HASHALG_SHA1:
604
- return rb_class_new_instance(0, NULL,
605
- rb_const_get(module_klass, rb_intern("SHA1")));
606
- case GT_HASHALG_RIPEMD160:
607
- return rb_class_new_instance(0, NULL,
608
- rb_const_get(module_klass, rb_intern("RMD160")));
597
+ case GT_HASHALG_SHA256:
598
+ args[0] = INT2FIX(256);
599
+ return rb_class_new_instance(1, args,
600
+ rb_const_get(module_klass, rb_intern("SHA2")));
601
+ case GT_HASHALG_SHA1:
602
+ return rb_class_new_instance(0, NULL,
603
+ rb_const_get(module_klass, rb_intern("SHA1")));
604
+ case GT_HASHALG_RIPEMD160:
605
+ return rb_class_new_instance(0, NULL,
606
+ rb_const_get(module_klass, rb_intern("RMD160")));
609
607
  case GT_HASHALG_SHA224:
610
- args[0] = INT2FIX(224);
611
- return rb_class_new_instance(1, args,
612
- rb_const_get(module_klass, rb_intern("SHA2")));
613
- case GT_HASHALG_SHA384:
614
- args[0] = INT2FIX(384);
615
- return rb_class_new_instance(1, args,
616
- rb_const_get(module_klass, rb_intern("SHA2")));
617
- case GT_HASHALG_SHA512:
618
- args[0] = INT2FIX(512);
619
- return rb_class_new_instance(1, args,
620
- rb_const_get(module_klass, rb_intern("SHA2")));
621
- default:
608
+ args[0] = INT2FIX(224);
609
+ return rb_class_new_instance(1, args,
610
+ rb_const_get(module_klass, rb_intern("SHA2")));
611
+ case GT_HASHALG_SHA384:
612
+ args[0] = INT2FIX(384);
613
+ return rb_class_new_instance(1, args,
614
+ rb_const_get(module_klass, rb_intern("SHA2")));
615
+ case GT_HASHALG_SHA512:
616
+ args[0] = INT2FIX(512);
617
+ return rb_class_new_instance(1, args,
618
+ rb_const_get(module_klass, rb_intern("SHA2")));
619
+ default:
622
620
  rb_raise(rb_eRuntimeError, "Unknown hash algorithm ID");
623
621
  }
624
622
  return Qnil;
@@ -640,34 +638,34 @@ static VALUE
640
638
  guardtime_gethashalg(VALUE self, VALUE tsdata)
641
639
  {
642
640
  int res;
643
- int alg;
641
+ int alg;
644
642
  GTTimestamp *ts;
645
643
 
646
644
  StringValue(tsdata);
647
645
 
648
646
  res = GTTimestamp_DERDecode(RSTRING_PTR(tsdata), RSTRING_LEN(tsdata), &ts);
649
- if (res != GT_OK)
647
+ if (res != GT_OK)
650
648
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
651
649
 
652
- res = GTTimestamp_getAlgorithm(ts, &alg);
653
- GTTimestamp_free(ts);
654
- if (res != GT_OK)
650
+ res = GTTimestamp_getAlgorithm(ts, &alg);
651
+ GTTimestamp_free(ts);
652
+ if (res != GT_OK)
655
653
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
656
654
 
657
- switch(alg) {
658
- case GT_HASHALG_SHA256:
659
- return rb_str_new2("SHA256");
660
- case GT_HASHALG_SHA1:
661
- return rb_str_new2("SHA1");
662
- case GT_HASHALG_RIPEMD160:
663
- return rb_str_new2("RIPEMD160");
664
- case GT_HASHALG_SHA224:
665
- return rb_str_new2("SHA224");
666
- case GT_HASHALG_SHA384:
667
- return rb_str_new2("SHA384");
668
- case GT_HASHALG_SHA512:
669
- return rb_str_new2("SHA512");
670
- default:
655
+ switch(alg) {
656
+ case GT_HASHALG_SHA256:
657
+ return rb_str_new2("SHA256");
658
+ case GT_HASHALG_SHA1:
659
+ return rb_str_new2("SHA1");
660
+ case GT_HASHALG_RIPEMD160:
661
+ return rb_str_new2("RIPEMD160");
662
+ case GT_HASHALG_SHA224:
663
+ return rb_str_new2("SHA224");
664
+ case GT_HASHALG_SHA384:
665
+ return rb_str_new2("SHA384");
666
+ case GT_HASHALG_SHA512:
667
+ return rb_str_new2("SHA512");
668
+ default:
671
669
  rb_raise(rb_eRuntimeError, "Unknown hash algorithm ID");
672
670
  }
673
671
  return Qnil;
@@ -683,49 +681,46 @@ each_conf_param(VALUE key, VALUE value, VALUE klass)
683
681
 
684
682
  if (key == Qundef) return ST_CONTINUE;
685
683
  switch(TYPE(key)) {
686
- case T_STRING:
687
- key_id = rb_intern(RSTRING_PTR(key));
688
- break;
689
- case T_SYMBOL:
690
- key_id = SYM2ID(key);
691
- break;
692
- default:
693
- rb_raise(rb_eArgError,
694
- "config hash includes invalid key");
695
- }
696
- if (TYPE(value) != T_STRING)
697
- rb_raise(rb_eArgError,
698
- "config hash value for '%s' must be a String", rb_id2name(key_id));
699
-
700
- if (strcasecmp(rb_id2name(key_id), "signeruri") == 0)
701
- gt->signeruri = RSTRING_PTR(value); // strdup() perhaps?
702
- else if (strcasecmp(rb_id2name(key_id), "verifieruri") == 0) {
703
- if (strlen(gt->verifieruri) > 0)
704
- gt->verifieruri = RSTRING_PTR(value);
705
- else
706
- gt->verifieruri = NULL; // no extending
684
+ case T_STRING:
685
+ key_id = rb_intern(RSTRING_PTR(key));
686
+ break;
687
+ case T_SYMBOL:
688
+ key_id = SYM2ID(key);
689
+ break;
690
+ default:
691
+ rb_raise(rb_eArgError,
692
+ "config hash includes invalid key");
693
+ }
694
+ if (TYPE(value) != T_STRING)
695
+ rb_raise(rb_eArgError,
696
+ "config hash value for '%s' must be a String", rb_id2name(key_id));
697
+
698
+ if (strcasecmp(rb_id2name(key_id), "signeruri") == 0)
699
+ gt->signeruri = RSTRING_PTR(value); // strdup() perhaps?
700
+ else if (strcasecmp(rb_id2name(key_id), "verifieruri") == 0) {
701
+ if (strlen(gt->verifieruri) > 0)
702
+ gt->verifieruri = RSTRING_PTR(value);
703
+ else
704
+ gt->verifieruri = NULL; // no extending
707
705
  }
708
- else if (strcasecmp(rb_id2name(key_id), "publicationsuri") == 0)
709
- gt->pubfileuri = RSTRING_PTR(value);
710
- else if (strcasecmp(rb_id2name(key_id), "loadpubs") == 0)
711
- gt->loadpubs = RSTRING_PTR(value);
712
- else
713
- rb_raise(rb_eArgError,
714
- "config hash has unknown key '%s'", rb_id2name(key_id));
715
-
716
- return ST_CONTINUE;
706
+ else if (strcasecmp(rb_id2name(key_id), "publicationsuri") == 0)
707
+ gt->pubfileuri = RSTRING_PTR(value);
708
+ else if (strcasecmp(rb_id2name(key_id), "loadpubs") == 0)
709
+ gt->loadpubs = RSTRING_PTR(value);
710
+ else
711
+ rb_raise(rb_eArgError,
712
+ "config hash has unknown key '%s'", rb_id2name(key_id));
713
+
714
+ return ST_CONTINUE;
717
715
  }
718
716
 
719
717
  static void
720
718
  guardtime_free(GuardTimeData *gt)
721
719
  {
722
720
  if (gt) {
723
- if (gt->pub != NULL)
724
- GTPublicationsFile_free(gt->pub);
725
- // we'll initialize gt libs when module is 'required' to keep singletons happy; thus free at end of time.
726
- // GTHTTP_finalize();
727
- // GT_finalize();
728
- free(gt);
721
+ if (gt->pub != NULL)
722
+ GTPublicationsFile_free(gt->pub);
723
+ free(gt);
729
724
  }
730
725
 
731
726
  }
@@ -754,11 +749,21 @@ guardtime_allocate(VALUE self)
754
749
  * * *Args* :
755
750
  * - +confighash+ -> Optional Hash containing configuration parameters. Defaults:
756
751
  * { :signeruri => 'http://verifier.guardtime.net/gt-extendingservice',
757
- * :verifieruri => 'http://verifier.guardtime.net/gt-extendingservice', # if blank String then online verification is not used
752
+ * :verifieruri => 'http://verifier.guardtime.net/gt-extendingservice',
758
753
  * :publicationsuri => 'http://verify.guardtime.com/gt-controlpublications.bin',
759
- * :loadpubs => 'auto' ## or once, always, no, auto (update every 8 hours)
754
+ * :loadpubs => 'auto'
760
755
  * }
761
- * Please use env. parameters to specify proxy ({syntax}[http://curl.haxx.se/docs/manpage.html#ENVIRONMENT]), Internet Explorer settints will be used on Windows. Specify url as <em>http://name:pass@site/url</em> for basic auth.
756
+ *
757
+ * * *Notes* :
758
+ * - If <tt>:verifieruri</tt> is blank String then online verification is not used.
759
+ *
760
+ * - <tt>:loadpubs</tt> may be either
761
+ * +once+:: Publications file is loaded once.
762
+ * +always+:: Publications file is reloaded at each verification call
763
+ * +no+:: Publications file is not used for verification. May be good as token consistency check, or with extra verification (e.g. manual publication string check)
764
+ * +auto+:: Publications file is automatically reloaded if older than 8 hours. Default.
765
+ *
766
+ * - Please use environment to specify proxy ({syntax}[http://curl.haxx.se/docs/manpage.html#ENVIRONMENT]), Internet Explorer settints will be used on Windows. Specify url as <em>http://name:pass@site/url</em> for basic auth.
762
767
  */
763
768
  static VALUE
764
769
  guardtime_initialize(int argc, VALUE *argv, VALUE obj)
@@ -771,18 +776,7 @@ guardtime_initialize(int argc, VALUE *argv, VALUE obj)
771
776
  }
772
777
 
773
778
  /*
774
- * This API provides access to GuardTime keyless signature service.
775
- * Please refer to http://www.guardtime.com/signatures/technology-overview/ for technology overview.
776
- *
777
- * The two main operations are signing and verification. Signing involves cryptographically binding the data whose integrity is to be protected to the audited time value and server component's identity in a way that neither the data, the time value nor identity could later be changed undetectably. Verification means checking that the binding is still intact.
778
- *
779
- * To get a sigature token from a GuardTime service, the client application computes a hash value of the data to be signed and submits the hash value to the signing service. The service returns a signature token binding the hash value to the current time. The interaction follows the standard cryptographic time-stamping protocol defined in the RFC 3161.
780
- *
781
- * Every month, GuardTime creates an Integrity Code and publishes it in several newspapers across the world. The Integrity Code is a summary of all signatures issued by the GuardTime data integrity services. Any signature issued prior to the creation of the Integrity Code can be traced to it to unambiguously prove the signature’s issuing time, issuer ID and link to signed data, effectively proving the data integrity.
782
- *
783
- * The proof connecting the signature to the Integrity Code can be inserted back into the token in a process we call extending. An extended signature token is completely independent of GuardTime. Only the original data, the signature and any copy of the newspaper where the Integrity Code is published will be necessary to prove the intgerity of the document.
784
- *
785
- * For convenience, GuardTime publishes an electronic archive containing all Integrity Codes since the launch of the service and all valid signing keys. This electronic archive can be used to automate mass verification of thousands of timestamps (whether extended or not) per second in a large archive.
779
+ * This API provides access to the GuardTime keyless signature service.
786
780
  */
787
781
  void Init_guardtime()
788
782
  {
@@ -794,7 +788,7 @@ void Init_guardtime()
794
788
  if (res != GT_OK)
795
789
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
796
790
 
797
- rb_cGuardTime = rb_define_class("GuardTime", rb_cObject);
791
+ rb_cGuardTime = rb_define_class("GuardTime", rb_cObject);
798
792
  rb_define_alloc_func(rb_cGuardTime, guardtime_allocate);
799
793
  rb_define_method(rb_cGuardTime, "initialize", guardtime_initialize, -1);
800
794
  rb_define_method(rb_cGuardTime, "sign", guardtime_sign, -1);
data/test/tc_guardtime.rb CHANGED
@@ -5,48 +5,48 @@ require 'test/unit'
5
5
  class TestGuardTime < Test::Unit::TestCase
6
6
 
7
7
  def test_old
8
- ts = File.open( File.dirname(__FILE__) + File::SEPARATOR + 'cat.gif.gtts', 'rb' ) do |f|
9
- f.read
10
- end
11
- gt3 = GuardTime.new
12
- assert( gt3.verify(ts) )
13
- assert_raise ArgumentError do
14
- gt3.verify("corrupted signature token")
15
- end
16
- assert_block do
17
- gt3.verify(ts) do |r|
18
- assert_instance_of(Time, r[:time])
19
- assert(Time.now - r[:time] > 60*60*24*45, 'must be old sig')
20
- assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT,
21
- r[:verification_status])
22
- assert_equal( GuardTime::NO_FAILURES, r[:verification_errors])
23
- assert_instance_of( Array, r[:pub_reference_list])
24
- assert_instance_of( String, r[:publication_string])
25
- assert_instance_of(Time, r[:publication_time])
26
- r[:verification_errors] == GuardTime::NO_FAILURES
27
- end
28
- end
29
- h3 = Digest::SHA2.new << File.read(File.dirname(__FILE__) + File::SEPARATOR + 'cat.gif')
30
- assert( gt3.verify(ts, h3) )
31
- assert( gt3.verify(ts, h3) do |r|
32
- assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT |
33
- GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
8
+ ts = File.open( File.dirname(__FILE__) + File::SEPARATOR + 'cat.gif.gtts', 'rb' ) do |f|
9
+ f.read
10
+ end
11
+ gt3 = GuardTime.new
12
+ assert( gt3.verify(ts) )
13
+ assert_raise ArgumentError do
14
+ gt3.verify("corrupted signature token")
15
+ end
16
+ assert_block do
17
+ gt3.verify(ts) do |r|
18
+ assert_instance_of(Time, r[:time])
19
+ assert(Time.now - r[:time] > 60*60*24*45, 'must be old sig')
20
+ assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT,
21
+ r[:verification_status])
22
+ assert_equal( GuardTime::NO_FAILURES, r[:verification_errors])
23
+ assert_instance_of( Array, r[:pub_reference_list])
24
+ assert_instance_of( String, r[:publication_string])
25
+ assert_instance_of(Time, r[:publication_time])
26
+ r[:verification_errors] == GuardTime::NO_FAILURES
27
+ end
28
+ end
29
+ h3 = Digest::SHA2.new << File.read(File.dirname(__FILE__) + File::SEPARATOR + 'cat.gif')
30
+ assert( gt3.verify(ts, h3) )
31
+ assert( gt3.verify(ts, h3) do |r|
32
+ assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT |
33
+ GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
34
34
  assert_equal(h3.hexdigest, r[:hash_value].delete(':'))
35
- r[:verification_errors] == GuardTime::NO_FAILURES
36
- end
37
- )
38
- # extending token first, then verifying
39
- assert( tsext = gt3.extend(ts) )
40
- gt4 = GuardTime.new({:loadpubs => 'once', :verifieruri => ''})
41
- gt4.verify(tsext, h3) do |r|
42
- assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT |
43
- GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
44
- end
45
- # verification without extending
46
- gt4.verify(ts, h3) do |r|
47
- assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT |
48
- GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
49
- end
35
+ r[:verification_errors] == GuardTime::NO_FAILURES
36
+ end
37
+ )
38
+ # extending token first, then verifying
39
+ assert( tsext = gt3.extend(ts) )
40
+ gt4 = GuardTime.new({:loadpubs => 'once', :verifieruri => ''})
41
+ gt4.verify(tsext, h3) do |r|
42
+ assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT |
43
+ GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
44
+ end
45
+ # verification without extending
46
+ gt4.verify(ts, h3) do |r|
47
+ assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT |
48
+ GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
49
+ end
50
50
 
51
51
 
52
52
  end
@@ -56,23 +56,23 @@ class TestGuardTime < Test::Unit::TestCase
56
56
  gt = GuardTime.new
57
57
  assert_instance_of(GuardTime, gt)
58
58
  ts = gt.sign(h)
59
- assert_equal('SHA256', GuardTime.gethashalg(ts).upcase, 'GuardTime.gethashalg() works')
59
+ assert_equal('SHA256', GuardTime.gethashalg(ts).upcase, 'GuardTime.gethashalg() works')
60
60
 
61
- assert_raise TypeError do
62
- GuardTime.gethashalg(123)
63
- end
64
- assert_raise RuntimeError do
65
- GuardTime.gethashalg("corrupted signature token")
66
- end
67
- assert_raise RuntimeError do
68
- GuardTime.getnewdigester("corrupted signature token")
69
- end
70
- h2 = GuardTime.getnewdigester(ts) << 'bla bla blah'
71
- assert_equal(h.inspect, h2.inspect, 'GuardTime.getnewdigester()')
72
- assert( gt.verify(ts) do |r|
73
- assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::PUBLICATION_CHECKED,
74
- r[:verification_status])
75
- assert_equal( GuardTime::NO_FAILURES, r[:verification_errors])
61
+ assert_raise TypeError do
62
+ GuardTime.gethashalg(123)
63
+ end
64
+ assert_raise RuntimeError do
65
+ GuardTime.gethashalg("corrupted signature token")
66
+ end
67
+ assert_raise RuntimeError do
68
+ GuardTime.getnewdigester("corrupted signature token")
69
+ end
70
+ h2 = GuardTime.getnewdigester(ts) << 'bla bla blah'
71
+ assert_equal(h.inspect, h2.inspect, 'GuardTime.getnewdigester()')
72
+ assert( gt.verify(ts) do |r|
73
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::PUBLICATION_CHECKED,
74
+ r[:verification_status])
75
+ assert_equal( GuardTime::NO_FAILURES, r[:verification_errors])
76
76
  assert_equal( nil, r[:pub_reference_list])
77
77
  assert_equal( nil, r[:publication_string])
78
78
  assert_instance_of(Time, r[:time])
@@ -80,43 +80,43 @@ class TestGuardTime < Test::Unit::TestCase
80
80
  assert_instance_of(Time, r[:publication_time])
81
81
  assert_equal(h.hexdigest, r[:hash_value].delete(':'))
82
82
  assert_equal('GT : GT : public', r[:location_name])
83
- r[:verification_errors] == GuardTime::NO_FAILURES
84
- end
85
- )
86
- assert( gt.verify(ts, h2))
87
- assert( gt.verify(ts, h2) do |r|
88
- assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::PUBLICATION_CHECKED |
89
- GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
90
- r[:verification_errors] == GuardTime::NO_FAILURES
91
- end
92
- )
83
+ r[:verification_errors] == GuardTime::NO_FAILURES
84
+ end
85
+ )
86
+ assert( gt.verify(ts, h2))
87
+ assert( gt.verify(ts, h2) do |r|
88
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::PUBLICATION_CHECKED |
89
+ GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
90
+ r[:verification_errors] == GuardTime::NO_FAILURES
91
+ end
92
+ )
93
93
 
94
- assert(gt.verify(ts, 'SHA256', h2.digest))
94
+ assert(gt.verify(ts, 'SHA256', h2.digest))
95
95
 
96
- gt2 = GuardTime.new({:loadpubs => 'no', :verifieruri => ''})
97
- assert( gt2.verify(ts) do |r|
98
- assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT, r[:verification_status])
99
- r[:verification_errors] == GuardTime::NO_FAILURES
100
- end
101
- )
102
- assert( gt2.verify(ts, h2) do |r|
103
- assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
104
- r[:verification_errors] == GuardTime::NO_FAILURES
105
- end
106
- )
96
+ gt2 = GuardTime.new({:loadpubs => 'no', :verifieruri => ''})
97
+ assert( gt2.verify(ts) do |r|
98
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT, r[:verification_status])
99
+ r[:verification_errors] == GuardTime::NO_FAILURES
100
+ end
101
+ )
102
+ assert( gt2.verify(ts, h2) do |r|
103
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
104
+ r[:verification_errors] == GuardTime::NO_FAILURES
105
+ end
106
+ )
107
107
 
108
- wrongh = Digest::SHA2.new << 'whateverelse'
109
- assert_equal( false, gt2.verify(ts, wrongh) )
110
- assert_equal( false, gt2.verify(ts, wrongh) do |r|
111
- assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
112
- assert_equal( GuardTime::WRONG_DOCUMENT_FAILURE, r[:verification_errors])
113
- r[:verification_errors] == GuardTime::NO_FAILURES
114
- end
115
- )
116
- exception = assert_raise RuntimeError do
117
- ext = gt.extend(ts)
118
- end
119
- assert_match /not yet available/, exception.message
108
+ wrongh = Digest::SHA2.new << 'whateverelse'
109
+ assert_equal( false, gt2.verify(ts, wrongh) )
110
+ assert_equal( false, gt2.verify(ts, wrongh) do |r|
111
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
112
+ assert_equal( GuardTime::WRONG_DOCUMENT_FAILURE, r[:verification_errors])
113
+ r[:verification_errors] == GuardTime::NO_FAILURES
114
+ end
115
+ )
116
+ exception = assert_raise RuntimeError do
117
+ ext = gt.extend(ts)
118
+ end
119
+ assert_match /not yet available/, exception.message
120
120
  end
121
121
 
122
122
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - GuardTime AS
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2013-01-05 00:00:00 +02:00
17
+ date: 2013-01-07 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -32,6 +32,7 @@ extra_rdoc_files: []
32
32
  files:
33
33
  - COPYING
34
34
  - INSTALL
35
+ - README.rdoc
35
36
  - ChangeLog
36
37
  - ext/guardtime.c
37
38
  - ext/extconf.rb
@@ -39,12 +40,15 @@ files:
39
40
  - test/cat.gif.gtts
40
41
  - test/tc_guardtime.rb
41
42
  has_rdoc: true
42
- homepage: http://www.guardtime.com/
43
+ homepage: https://github.com/ristik/ruby-guardtime
43
44
  licenses:
44
45
  - apache-2.0
45
46
  post_install_message:
46
- rdoc_options: []
47
-
47
+ rdoc_options:
48
+ - --main
49
+ - README.rdoc
50
+ - README.rdoc
51
+ - ext/guardtime.c
48
52
  require_paths:
49
53
  - lib
50
54
  required_ruby_version: !ruby/object:Gem::Requirement