guardtime 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog ADDED
@@ -0,0 +1,8 @@
1
+ Release 0.0.2 (2013-01-02 by risto):
2
+ - added RDoc
3
+ - new function 'extend'
4
+ - minor bug: double free when 'extended' signature is verified
5
+ - GT library init done at 'require' time instead of instantiation time.
6
+
7
+ Release 0.0.1 (2013-01-05 by risto):
8
+ - initial verion
data/INSTALL CHANGED
@@ -1,22 +1,27 @@
1
- Dependencies:
1
+ = Dependencies:
2
2
 
3
3
  - libcurl
4
4
  - openssl 0.9.8+
5
5
  - GuardTime C API
6
6
 
7
- installation on Debian:
7
+ == installation on Debian:
8
8
 
9
- apt-get install ruby ruby-dev rubygems
10
- apt-get install libcurl-dev openssl-dev
11
- wget http://download.guardtime.com/libgt-0.3.11-src.tgz
12
- tar xfz libgt-0.3.11-src.tgz
13
- cd libgt-0.3.11
14
- ./configure --disable-shared
15
- make
16
- sudo make install
17
- cd ..
18
- sudo gem install guardtime-x.y.z.gem
19
- or
20
- sudo gem install guardtime
9
+ apt-get install ruby ruby-dev rubygems
10
+ apt-get install libcurl-dev openssl-dev
11
+ wget http://download.guardtime.com/libgt-0.3.11-src.tgz
12
+ tar xfz libgt-0.3.11-src.tgz
13
+ cd libgt-0.3.11
14
+ ./configure --disable-shared
15
+ make
16
+ sudo make install
17
+ cd ..
18
+ sudo gem install guardtime-x.y.z.gem
19
+ or
20
+ sudo gem install guardtime
21
21
 
22
- Adjust at other platforms.
22
+
23
+ == installation on OpenSolaris / OpenIndiana / Illumous / SmartOS
24
+
25
+ Please use
26
+ CPPFLAGS="-I/opt/local/include -fPIC" LDFLAGS="-L/opt/local/lib -R/opt/local/lib" ./configure --prefix=/opt/local --disable-shared
27
+ for configuring the GuardTime C API. Adjust dependency install commands etc.
data/ext/guardtime.c CHANGED
@@ -173,8 +173,8 @@ cleanup:
173
173
  *ver = ver_tmp;
174
174
  ver_tmp = NULL;
175
175
  }
176
-
177
- GTTimestamp_free(ext);
176
+ if (ext != ts)
177
+ GTTimestamp_free(ext);
178
178
  GTVerificationInfo_free(ver_tmp);
179
179
 
180
180
  return res;
@@ -229,6 +229,22 @@ static void get_gtdatahash2(VALUE algo, VALUE digest, GTDataHash *dh)
229
229
  dh->digest_length = RSTRING_LEN(digest);
230
230
  }
231
231
 
232
+ /*
233
+ * call-seq:
234
+ * sign(Digest) -> signature_token
235
+ * sign(hashalgname, binarydigest) -> signature_token
236
+ *
237
+ * * *Args* :
238
+ * - +Digest+ -> Digest object, implementing supported hahs algorithm, encapsulating already calculated hash value.
239
+ * example: guardtime.sign(Digest.SHA2.new(256).update('this string shall be signed'))
240
+ * - +hashalgname+ -> String with OpenSSL style hash algorithm name, either SHA256, SHA224, SHA384, SHA512, SHA1 or RIPEMD160.
241
+ * - +binarydigest+ -> String with binary hash value.
242
+ * * *Returns* :
243
+ * - String containing binary data with Guardime signature token. May be directly saved etc.
244
+ * * *Raises* :
245
+ * - +ArgumentError+ -> if any value is nil or wrong type.
246
+ * - +RuntimeError+ -> other errors, including network, hash value etc.
247
+ */
232
248
  static VALUE
233
249
  guardtime_sign(int argc, VALUE *argv, VALUE obj)
234
250
  {
@@ -263,6 +279,52 @@ guardtime_sign(int argc, VALUE *argv, VALUE obj)
263
279
  return result;
264
280
  }
265
281
 
282
+ /*
283
+ * call-seq:
284
+ * extend(sig) -> extended_signature_token
285
+ *
286
+ * * *Args* :
287
+ * - +sig+ -> String containing binary data with Guardime signature token. May be directly loaded from file.
288
+ * * *Returns* :
289
+ * - String containing binary data with Guardime signature token. May be directly saved etc.
290
+ * * *Raises* :
291
+ * - +ArgumentError+ -> if any value is nil or wrong type.
292
+ * - +RuntimeError+ -> other errors, including network, hash value, token too new or old etc. Proper description is in the error message.
293
+ * 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.
295
+ */
296
+ static VALUE
297
+ guardtime_extend(VALUE obj, VALUE in)
298
+ {
299
+ int res;
300
+ GTDataHash dh;
301
+ GTTimestamp *ts, *ts2;
302
+ unsigned char *data;
303
+ size_t data_length;
304
+ GuardTimeData *gt;
305
+ VALUE result;
306
+
307
+ StringValue(in);
308
+ Data_Get_Struct(obj, GuardTimeData, gt);
309
+ res = GTTimestamp_DERDecode(RSTRING_PTR(in),
310
+ RSTRING_LEN(in), &ts);
311
+ if (res != GT_OK)
312
+ rb_raise(rb_eArgError, GT_getErrorString(res));
313
+
314
+ res = GTHTTP_extendTimestamp(ts, gt->verifieruri, &ts2);
315
+ GTTimestamp_free(ts);
316
+ if (res != GT_OK)
317
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
318
+
319
+ res = GTTimestamp_getDEREncoded(ts2, &data, &data_length);
320
+ if (res != GT_OK)
321
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
322
+
323
+ result = rb_str_new((char*)data, data_length);
324
+ GT_free(data);
325
+ return result;
326
+ }
327
+
266
328
  // load and parse/verify pub. file, populate state.
267
329
  int loadpubs_helper(GuardTimeData *gt) {
268
330
  int res = GT_OK;
@@ -359,6 +421,63 @@ format_hash_algorithm(int alg)
359
421
  }
360
422
  }
361
423
 
424
+ /*
425
+ * call-seq:
426
+ * verify(sig) -> true/false
427
+ * verify(sig, Digest) -> true/false
428
+ * verify(sig, hashalgname, binarydigest) -> true/false
429
+ * verify(sig, ...) {|resulthash| ... statement } -> value_of_last_cb_statement
430
+ *
431
+ * * *Args* :
432
+ * - +sig+ -> String containing binary data with Guardime signature token. May be directly loaded from file.
433
+ * - +Digest+ -> Digest object, implementing supported hash algorithm, encapsulating already calculated hash value.
434
+ * - +hashalgname+ -> String with OpenSSL style hash algorithm name, either SHA256, SHA224, SHA384, SHA512, SHA1 or RIPEMD160.
435
+ * - +binarydigest+ -> String with binary hash value. Obtain with +Digest.digest+ for example.
436
+ * - +code_block+ -> Optional code block serves two purposes: 1) Allows to implement _verification_policies_, i.e. add additional checks to the signature verification, and 2) Gives access to signature properties present in code block argument +resulthash+.
437
+ * * *Returns* :
438
+ * - either +true+ or +false+, depending on the result of verification. If code block is used then the value returned by last statement of code block is passed through.
439
+ * * *Raises* :
440
+ * - +ArgumentError+ -> if any value is nil or wrong type, or signature token is corrupted.
441
+ * - +RuntimeError+ -> other errors, including network, hash value etc.
442
+ *
443
+ * Code block receives parameter +resulthash+ which is populated with signature properties. There are following keys:
444
+ * *verification_errors*:: bitfield containing verification errors. See class constants. Verification is successful only if value equals to <tt>GuardTime::NO_FAILURES</tt>
445
+ * *verification_status*:: Numeric bitfield -- flags identifying successful verification checks. See class constants.
446
+ * *time*:: Time object containing signing (time-stamp) datum.
447
+ * *registered_time*:: Numeric containing 'time_t' representation (seconds since Epoch) of the signing datum.
448
+ * *hash_algorithm*:: String with OpenSSL style hash algorithm name; this algorithm was used for hashing the original data.
449
+ * *hash_value*:: Hash of the signed data, formatted as String of ':'-separated hex octets.
450
+ * *location_name*:: String containing signature issuer name within the GuardTime network. Example: 'GT : GT : Customer'
451
+ * *location_id*:: String containing '.' separated customer address hierarchy.
452
+ * *policy*:: String with signing/time-stamping policy OID.
453
+ * *publication_identifier*:: Publication ID, Numeric.
454
+ * *publication_string*:: Control string for verifying the timestamp using a hardcopy publication, the value is base32(time+alg+hash+crc32)
455
+ * *pub_reference_list*:: Array of UTF-8 encoded Strings containing list of newspaper issues or other media used for publishing verification values.
456
+ * *publication_time*:: Time object containing datum of publishing time which could be used for intependent 'newspaper based' verification.
457
+ * *public_key_fingerprint*:: String with PKI key fingerprint which could be used for extra verification until newspaper hash-link publication becomes available. List of trusted keys is published with publications file.
458
+ *
459
+ * * *Notes*
460
+ * - hash algorithm must match one used for hashing the original data during signing. See example below.
461
+ * - finish the code block with <tt>resulthash[:verification_errors] == GuardTime::NO_FAILURES</tt> if You care of the return value!
462
+ *
463
+ * * *Examples*
464
+ * - Default behaviour (without code block) is acheved with following code:
465
+ * result = guardtime_obj.verify(token) do |resulthash|
466
+ * resulthash[:verification_errors] == GuardTime::NO_FAILURES
467
+ * end
468
+ * - Verification flow with loading token, determining hash alg., hashing file, verifying with signer ID check.
469
+ * token = slurpbinaryfile('importantdata.txt.gtts')
470
+ * hasher = GuardTime.getnewdigester(token)
471
+ * hasher << slurpbinaryfile('importantdata.txt')
472
+ * gt = GuardTime.new
473
+ * signedAt = nil
474
+ * okay = gt.verify(token, hasher) do |r|
475
+ * signedAt = r[:time]
476
+ * /companyname$/ =~ r[:location_name] and
477
+ * r[:verification_errors] == GuardTime::NO_FAILURES
478
+ * end
479
+ * puts "data signed at #{signedAt.utc.to_s}" if okay
480
+ */
362
481
  static VALUE
363
482
  guardtime_verify(int argc, VALUE *argv, VALUE obj)
364
483
  {
@@ -393,7 +512,7 @@ guardtime_verify(int argc, VALUE *argv, VALUE obj)
393
512
  break;
394
513
  }
395
514
 
396
- if (res != GT_OK) {
515
+ if (res != GT_OK) {
397
516
  GTTimestamp_free(ts);
398
517
  rb_raise(rb_eRuntimeError, GT_getErrorString(res));
399
518
  }
@@ -430,7 +549,6 @@ guardtime_verify(int argc, VALUE *argv, VALUE obj)
430
549
 
431
550
  RBSET("time", time_t_to_Time( verification_info->implicit_data->registered_time ));
432
551
  RBSET("publication_time", time_t_to_Time( verification_info->explicit_data->publication_identifier ));
433
-
434
552
  } else
435
553
  retval = verification_info->verification_errors == GT_NO_FAILURES ? Qtrue : Qfalse;
436
554
 
@@ -443,8 +561,18 @@ guardtime_verify(int argc, VALUE *argv, VALUE obj)
443
561
  return retval;
444
562
  }
445
563
 
446
-
447
- // returns instance of Digester::... with same hashalg.
564
+ /*
565
+ * call-seq:
566
+ * GuardTime.getnewdigester(signature) -> instance_of_Digest
567
+ *
568
+ * * *Args* :
569
+ * - +signature+ -> String containing Guardtime signature token
570
+ * * *Returns* :
571
+ * - instantiated object of Digest::... implementing exactly same hashing algorithm used for hashing the original signed data.
572
+ * * *Raises* :
573
+ * - +TypeError+ -> wrong argument datatype.
574
+ * - +RuntimeError+ -> other errors like corrupted token etc.
575
+ */
448
576
  static VALUE
449
577
  guardtime_getnewdigester(VALUE self, VALUE tsdata)
450
578
  {
@@ -496,7 +624,18 @@ guardtime_getnewdigester(VALUE self, VALUE tsdata)
496
624
  return Qnil;
497
625
  }
498
626
 
499
-
627
+ /*
628
+ * call-seq:
629
+ * GuardTime.gethashalg(signature) -> algorithm_name
630
+ *
631
+ * * *Args* :
632
+ * - +signature+ -> String containing Guardtime signature token
633
+ * * *Returns* :
634
+ * - String with OpenSSL style hash algorithm name used for hashing the signed data.
635
+ * * *Raises* :
636
+ * - +TypeError+ -> wrong argument datatype.
637
+ * - +RuntimeError+ -> other errors like corrupted token etc.
638
+ */
500
639
  static VALUE
501
640
  guardtime_gethashalg(VALUE self, VALUE tsdata)
502
641
  {
@@ -583,8 +722,9 @@ guardtime_free(GuardTimeData *gt)
583
722
  if (gt) {
584
723
  if (gt->pub != NULL)
585
724
  GTPublicationsFile_free(gt->pub);
586
- GTHTTP_finalize();
587
- GT_finalize();
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();
588
728
  free(gt);
589
729
  }
590
730
 
@@ -593,16 +733,8 @@ guardtime_free(GuardTimeData *gt)
593
733
  static VALUE
594
734
  guardtime_allocate(VALUE self)
595
735
  {
596
- int res;
597
736
  GuardTimeData *gt;
598
737
 
599
- res = GT_init();
600
- if (res != GT_OK)
601
- rb_raise(rb_eRuntimeError, GT_getErrorString(res));
602
- res = GTHTTP_init("ruby api 0.0", 1);
603
- if (res != GT_OK)
604
- rb_raise(rb_eRuntimeError, GT_getErrorString(res));
605
-
606
738
  gt = ALLOC(GuardTimeData);
607
739
  // DATA_PTR(self) = gt;
608
740
  gt->signeruri = DEFAULT_SIGNERURI;
@@ -614,8 +746,20 @@ guardtime_allocate(VALUE self)
614
746
  return Data_Wrap_Struct(self, 0, guardtime_free, gt);
615
747
  }
616
748
 
617
-
618
- // GuardTime.new(blaah)
749
+ /*
750
+ * call-seq:
751
+ * GuardTime.new -> obj
752
+ * GuardTime.new(confighash) -> obj
753
+ *
754
+ * * *Args* :
755
+ * - +confighash+ -> Optional Hash containing configuration parameters. Defaults:
756
+ * { :signeruri => 'http://verifier.guardtime.net/gt-extendingservice',
757
+ * :verifieruri => 'http://verifier.guardtime.net/gt-extendingservice', # if blank String then online verification is not used
758
+ * :publicationsuri => 'http://verify.guardtime.com/gt-controlpublications.bin',
759
+ * :loadpubs => 'auto' ## or once, always, no, auto (update every 8 hours)
760
+ * }
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.
762
+ */
619
763
  static VALUE
620
764
  guardtime_initialize(int argc, VALUE *argv, VALUE obj)
621
765
  {
@@ -626,26 +770,79 @@ guardtime_initialize(int argc, VALUE *argv, VALUE obj)
626
770
  return obj;
627
771
  }
628
772
 
629
-
773
+ /*
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.
786
+ */
630
787
  void Init_guardtime()
631
788
  {
789
+ int res;
790
+ res = GT_init();
791
+ if (res != GT_OK)
792
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
793
+ res = GTHTTP_init("ruby api 0.0.1", 1);
794
+ if (res != GT_OK)
795
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
796
+
632
797
  rb_cGuardTime = rb_define_class("GuardTime", rb_cObject);
633
798
  rb_define_alloc_func(rb_cGuardTime, guardtime_allocate);
634
799
  rb_define_method(rb_cGuardTime, "initialize", guardtime_initialize, -1);
635
800
  rb_define_method(rb_cGuardTime, "sign", guardtime_sign, -1);
801
+ rb_define_method(rb_cGuardTime, "extend", guardtime_extend, 1);
636
802
  rb_define_method(rb_cGuardTime, "verify", guardtime_verify, -1);
637
803
  rb_define_singleton_method(rb_cGuardTime, "gethashalg", guardtime_gethashalg, 1);
638
804
  rb_define_singleton_method(rb_cGuardTime, "getnewdigester", guardtime_getnewdigester, 1);
639
805
 
806
+ /**
807
+ * \ingroup verification
808
+ *
809
+ * Timestamp verification status codes.
810
+ *
811
+ * \note The values are bit flags so that a single +int+ can contain any combination of them.
812
+ */
813
+ /* The PKI signature was present in the signature. */
814
+ rb_define_const(rb_cGuardTime, "PUBLIC_KEY_SIGNATURE_PRESENT", INT2NUM(GT_PUBLIC_KEY_SIGNATURE_PRESENT));
815
+ /* Publication references (list of newspaper etc sources to verify publication value) are present in the signature. */
816
+ rb_define_const(rb_cGuardTime, "PUBLICATION_REFERENCE_PRESENT", INT2NUM(GT_PUBLICATION_REFERENCE_PRESENT));
817
+ /* The signature was checked against the document hash. */
818
+ rb_define_const(rb_cGuardTime, "DOCUMENT_HASH_CHECKED", INT2NUM(GT_DOCUMENT_HASH_CHECKED));
819
+ /* The signature was checked against the publication data. */
820
+ rb_define_const(rb_cGuardTime, "PUBLICATION_CHECKED", INT2NUM(GT_PUBLICATION_CHECKED));
821
+
822
+ /**
823
+ * \ingroup verification
824
+ *
825
+ * Signature verification error codes.
826
+ *
827
+ * \note Values other than +GT_NO_FAILURES+ are bit flags so that
828
+ * a single +int+ can contain any combination of them.
829
+ */
830
+ /* The verification completed successfully. */
640
831
  rb_define_const(rb_cGuardTime, "NO_FAILURES", INT2NUM(GT_NO_FAILURES));
832
+ /* The level bytes inside the hash chains are improperly ordered. */
641
833
  rb_define_const(rb_cGuardTime, "SYNTACTIC_CHECK_FAILURE", INT2NUM(GT_SYNTACTIC_CHECK_FAILURE));
834
+ /* The hash chain computation result does not match the publication imprint. */
642
835
  rb_define_const(rb_cGuardTime, "HASHCHAIN_VERIFICATION_FAILURE", INT2NUM(GT_HASHCHAIN_VERIFICATION_FAILURE));
836
+ /* The +signed_data+ structure is incorrectly composed, i.e. wrong data
837
+ * is signed or the signature does not match with the public key in the
838
+ * timestamp. */
643
839
  rb_define_const(rb_cGuardTime, "PUBLIC_KEY_SIGNATURE_FAILURE", INT2NUM(GT_PUBLIC_KEY_SIGNATURE_FAILURE));
840
+ /* Public key of signature token is not found among trusted ones in publications file. */
644
841
  rb_define_const(rb_cGuardTime, "NOT_VALID_PUBLIC_KEY_FAILURE", INT2NUM(GT_NOT_VALID_PUBLIC_KEY_FAILURE));
842
+ /* Timestamp does not match with the document it is claimed to belong to. */
645
843
  rb_define_const(rb_cGuardTime, "WRONG_DOCUMENT_FAILURE", INT2NUM(GT_WRONG_DOCUMENT_FAILURE));
844
+ /* The publications file is inconsistent with the corresponding data in
845
+ * timestamp - publication identifiers do not match or published hash
846
+ * values do not match. */
646
847
  rb_define_const(rb_cGuardTime, "NOT_VALID_PUBLICATION", INT2NUM(GT_NOT_VALID_PUBLICATION));
647
- rb_define_const(rb_cGuardTime, "PUBLIC_KEY_SIGNATURE_PRESENT", INT2NUM(GT_PUBLIC_KEY_SIGNATURE_PRESENT));
648
- rb_define_const(rb_cGuardTime, "PUBLICATION_REFERENCE_PRESENT", INT2NUM(GT_PUBLICATION_REFERENCE_PRESENT));
649
- rb_define_const(rb_cGuardTime, "DOCUMENT_HASH_CHECKED", INT2NUM(GT_DOCUMENT_HASH_CHECKED));
650
- rb_define_const(rb_cGuardTime, "PUBLICATION_CHECKED", INT2NUM(GT_PUBLICATION_CHECKED));
651
848
  }
data/test/cat.gif ADDED
Binary file
data/test/cat.gif.gtts ADDED
Binary file
data/test/tc_guardtime.rb CHANGED
@@ -3,12 +3,11 @@ require 'digest/sha2'
3
3
  require 'test/unit'
4
4
 
5
5
  class TestGuardTime < Test::Unit::TestCase
6
-
7
- def test_old
8
- file = File.open(File.dirname(__FILE__) + File::SEPARATOR + 'cat.gif.gtts', 'rb')
9
- ts = file.read
10
- file.close
11
6
 
7
+ def test_old
8
+ ts = File.open( File.dirname(__FILE__) + File::SEPARATOR + 'cat.gif.gtts', 'rb' ) do |f|
9
+ f.read
10
+ end
12
11
  gt3 = GuardTime.new
13
12
  assert( gt3.verify(ts) )
14
13
  assert_raise ArgumentError do
@@ -36,6 +35,19 @@ class TestGuardTime < Test::Unit::TestCase
36
35
  r[:verification_errors] == GuardTime::NO_FAILURES
37
36
  end
38
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
+
39
51
 
40
52
  end
41
53
 
@@ -101,6 +113,10 @@ class TestGuardTime < Test::Unit::TestCase
101
113
  r[:verification_errors] == GuardTime::NO_FAILURES
102
114
  end
103
115
  )
116
+ exception = assert_raise RuntimeError do
117
+ ext = gt.extend(ts)
118
+ end
119
+ assert_match /not yet available/, exception.message
104
120
  end
105
121
 
106
122
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
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-03 00:00:00 +02:00
17
+ date: 2013-01-05 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -32,8 +32,11 @@ extra_rdoc_files: []
32
32
  files:
33
33
  - COPYING
34
34
  - INSTALL
35
+ - ChangeLog
35
36
  - ext/guardtime.c
36
37
  - ext/extconf.rb
38
+ - test/cat.gif
39
+ - test/cat.gif.gtts
37
40
  - test/tc_guardtime.rb
38
41
  has_rdoc: true
39
42
  homepage: http://www.guardtime.com/