guardtime 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/COPYING +202 -0
  2. data/INSTALL +22 -0
  3. data/ext/extconf.rb +9 -0
  4. data/ext/guardtime.c +651 -0
  5. data/test/tc_guardtime.rb +107 -0
  6. metadata +69 -0
data/COPYING ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/INSTALL ADDED
@@ -0,0 +1,22 @@
1
+ Dependencies:
2
+
3
+ - libcurl
4
+ - openssl 0.9.8+
5
+ - GuardTime C API
6
+
7
+ installation on Debian:
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
21
+
22
+ Adjust at other platforms.
data/ext/extconf.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("guardtime")
4
+ have_library("gtbase")
5
+ have_library("gthttp")
6
+ have_library("crypto")
7
+ have_library("curl")
8
+
9
+ create_makefile("guardtime")
data/ext/guardtime.c ADDED
@@ -0,0 +1,651 @@
1
+ /*
2
+ * Copyright 2013 GuardTime AS
3
+ *
4
+ * This file is part of the GuardTime Ruby SDK.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
+ * implied. See the License for the specific language governing
14
+ * permissions and limitations under the License.
15
+ */
16
+
17
+ #include "ruby.h"
18
+ #include <st.h>
19
+ #include <time.h>
20
+ #include <gt_base.h>
21
+ #include <gt_http.h>
22
+
23
+ static VALUE rb_cGuardTime;
24
+
25
+ #define DEFAULT_SIGNERURI "http://stamper.guardtime.net/gt-signingservice"
26
+ #define DEFAULT_VERIFIERURI "http://verifier.guardtime.net/gt-extendingservice"
27
+ #define DEFAULT_PUBFILEURI "http://verify.guardtime.com/gt-controlpublications.bin"
28
+ #define DEFAULT_LOADPUBS "auto"
29
+ #define PUBDATA_UPDATE_SECONDS (8 * 60 * 60)
30
+
31
+ // object instance state
32
+ typedef struct _GuardTimeData {
33
+ char * signeruri;
34
+ char * verifieruri;
35
+ char * pubfileuri;
36
+ char * loadpubs;
37
+ time_t pubdataupdated;
38
+ GT_Time_t64 lastpublicationtime;
39
+ GTPublicationsFile *pub;
40
+ } GuardTimeData;
41
+
42
+
43
+ // based on GTHTTP_verifyTimestampHash from gt_http.c, modified to support more
44
+ // combinations of arguments and externalized pub. file processing
45
+ static int verifyTimestamp(const GTTimestamp *ts,
46
+ const GTDataHash *hash, GuardTimeData *gt,
47
+ int parse, GTVerificationInfo **ver)
48
+ {
49
+ int res = GT_UNKNOWN_ERROR;
50
+ GTVerificationInfo *ver_tmp = NULL;
51
+ GTTimestamp *ext = NULL;
52
+ int is_ext = 0, is_new = 0;
53
+
54
+ if (ts == NULL || ver == NULL) {
55
+ res = GT_INVALID_ARGUMENT;
56
+ goto cleanup;
57
+ }
58
+
59
+ /* Check internal consistency of the timestamp. */
60
+ res = GTTimestamp_verify(ts, parse, &ver_tmp);
61
+ if (res != GT_OK) {
62
+ goto cleanup;
63
+ }
64
+ if (ver_tmp == NULL || ver_tmp->implicit_data == NULL) {
65
+ res = GT_UNKNOWN_ERROR;
66
+ goto cleanup;
67
+ }
68
+ if (ver_tmp->verification_errors != GT_NO_FAILURES) {
69
+ goto cleanup;
70
+ }
71
+
72
+ /* Check document hash.
73
+ * GT_WRONG_DOCUMENT means the hash did not match.
74
+ * Everything else is some sort of system error. */
75
+ if (hash != NULL) {
76
+ res = GTTimestamp_checkDocumentHash(ts, hash);
77
+ if (res == GT_OK) {
78
+ ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED;
79
+ } else if (res == GT_WRONG_DOCUMENT) {
80
+ ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED;
81
+ ver_tmp->verification_errors |= GT_WRONG_DOCUMENT_FAILURE;
82
+ res = GT_OK;
83
+ goto cleanup;
84
+ } else {
85
+ goto cleanup;
86
+ }
87
+ }
88
+
89
+ /* Whether the timestamp is extended. */
90
+ is_ext = ((ver_tmp->verification_status & GT_PUBLIC_KEY_SIGNATURE_PRESENT) == 0);
91
+ /* Whether it is too new to be extended. */
92
+ is_new = (ver_tmp->implicit_data->registered_time > gt->lastpublicationtime);
93
+
94
+ /* If the timestamp is already extended, "promote" it.
95
+ * If it is not extended, but is old enough, attempt to extend it. */
96
+ if (is_ext) {
97
+ ext = (GTTimestamp *) ts;
98
+ } else if (!is_new && gt->verifieruri != NULL) {
99
+ res = GTHTTP_extendTimestamp(ts, gt->verifieruri, &ext);
100
+ /* If extending fails because of infrastructure failure, fall
101
+ * back to signing key check. Else report errors. */
102
+ if (res == GT_NONSTD_EXTEND_LATER || res == GT_NONSTD_EXTENSION_OVERDUE ||
103
+ (res >= GTHTTP_IMPL_BASE && res <= GTHTTP_HIGHEST)) {
104
+ res = GT_OK;
105
+ }
106
+ if (res != GT_OK) {
107
+ goto cleanup;
108
+ }
109
+ }
110
+
111
+ /* If we now have a new timestamp, check internal consistency and document hash. */
112
+ if (ext != NULL && ext != ts) {
113
+ /* Release the old verification info. */
114
+ GTVerificationInfo_free(ver_tmp);
115
+ ver_tmp = NULL;
116
+ /* Re-check consistency. */
117
+ res = GTTimestamp_verify(ext, parse, &ver_tmp);
118
+ if (res != GT_OK) {
119
+ goto cleanup;
120
+ }
121
+ if (ver_tmp == NULL || ver_tmp->implicit_data == NULL) {
122
+ res = GT_UNKNOWN_ERROR;
123
+ goto cleanup;
124
+ }
125
+ if (ver_tmp->verification_errors != GT_NO_FAILURES) {
126
+ goto cleanup;
127
+ }
128
+ /* Re-check document hash. */
129
+ if (hash != NULL) {
130
+ res = GTTimestamp_checkDocumentHash(ts, hash);
131
+ if (res == GT_OK) {
132
+ ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED;
133
+ } else if (res == GT_WRONG_DOCUMENT) {
134
+ ver_tmp->verification_status |= GT_DOCUMENT_HASH_CHECKED;
135
+ ver_tmp->verification_errors |= GT_WRONG_DOCUMENT_FAILURE;
136
+ res = GT_OK;
137
+ goto cleanup;
138
+ } else {
139
+ goto cleanup;
140
+ }
141
+ }
142
+ }
143
+ if (gt->pub != NULL) {
144
+ if (ext != NULL) {
145
+ /* If we now have an extended timestamp, check publication.
146
+ * GT_TRUST_POINT_NOT_FOUND and GT_INVALID_TRUST_POINT mean it did not match.
147
+ * Everything else is some sort of system error. */
148
+ res = GTTimestamp_checkPublication(ext, gt->pub);
149
+ if (res == GT_OK) {
150
+ ver_tmp->verification_status |= GT_PUBLICATION_CHECKED;
151
+ } else if (res == GT_TRUST_POINT_NOT_FOUND || res == GT_INVALID_TRUST_POINT) {
152
+ ver_tmp->verification_status |= GT_PUBLICATION_CHECKED;
153
+ ver_tmp->verification_errors |= GT_NOT_VALID_PUBLICATION;
154
+ res = GT_OK;
155
+ }
156
+ } else {
157
+ /* Otherwise, check signing key.
158
+ * GT_KEY_NOT_PUBLISHED and GT_CERT_TICKET_TOO_OLD mean key not valid.
159
+ * Everything else is some sort of system error. */
160
+ res = GTTimestamp_checkPublicKey(ts, ver_tmp->implicit_data->registered_time, gt->pub);
161
+ if (res == GT_OK) {
162
+ ver_tmp->verification_status |= GT_PUBLICATION_CHECKED;
163
+ } else if (res == GT_KEY_NOT_PUBLISHED || res == GT_CERT_TICKET_TOO_OLD) {
164
+ ver_tmp->verification_status |= GT_PUBLICATION_CHECKED;
165
+ ver_tmp->verification_errors |= GT_NOT_VALID_PUBLIC_KEY_FAILURE;
166
+ res = GT_OK;
167
+ }
168
+ }
169
+ }
170
+
171
+ cleanup:
172
+ if (res == GT_OK) {
173
+ *ver = ver_tmp;
174
+ ver_tmp = NULL;
175
+ }
176
+
177
+ GTTimestamp_free(ext);
178
+ GTVerificationInfo_free(ver_tmp);
179
+
180
+ return res;
181
+ }
182
+
183
+
184
+ static void get_gtdatahash(VALUE digest, GTDataHash *dh)
185
+ {
186
+ int gtalgoid;
187
+ const char * cn = rb_obj_classname(digest); // Digest::SHA2
188
+ VALUE rb_digest = rb_funcall(digest, rb_intern("digest"), 0);
189
+ int bitlen = 8 * NUM2INT(rb_funcall(digest, rb_intern("digest_length"), 0));
190
+
191
+ 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);
201
+ if (gtalgoid < 0)
202
+ rb_raise(rb_eRuntimeError, "Argument must be supported Digest::... instance.");
203
+
204
+ dh->context = NULL;
205
+ dh->algorithm = gtalgoid;
206
+ dh->digest = (unsigned char *)RSTRING_PTR(rb_digest);
207
+ dh->digest_length = RSTRING_LEN(rb_digest);
208
+ }
209
+
210
+ static void get_gtdatahash2(VALUE algo, VALUE digest, GTDataHash *dh)
211
+ {
212
+ int gtalgoid;
213
+ StringValue(algo);
214
+ StringValue(digest);
215
+ 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);
223
+ if (gtalgoid < 0)
224
+ rb_raise(rb_eRuntimeError, "Argument must be supported Digest::... instance.");
225
+
226
+ dh->context = NULL;
227
+ dh->algorithm = gtalgoid;
228
+ dh->digest = (unsigned char *)RSTRING_PTR(digest);
229
+ dh->digest_length = RSTRING_LEN(digest);
230
+ }
231
+
232
+ static VALUE
233
+ guardtime_sign(int argc, VALUE *argv, VALUE obj)
234
+ {
235
+ int res;
236
+ GTDataHash dh;
237
+ GTTimestamp *ts;
238
+ unsigned char *data;
239
+ size_t data_length;
240
+ GuardTimeData *gt;
241
+ VALUE hash, hash2, result;
242
+
243
+ switch (rb_scan_args(argc, argv, "11", &hash, &hash2)) {
244
+ case 1:
245
+ get_gtdatahash(hash, &dh);
246
+ break;
247
+ case 2:
248
+ get_gtdatahash2(hash, hash2, &dh);
249
+ break;
250
+ }
251
+ Data_Get_Struct(obj, GuardTimeData, gt);
252
+ res = GTHTTP_createTimestampHash(&dh, gt->signeruri, &ts);
253
+ if (res != GT_OK)
254
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
255
+ // todo - return here? or does it use longjmp etc?
256
+
257
+ res = GTTimestamp_getDEREncoded(ts, &data, &data_length);
258
+ if (res != GT_OK)
259
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
260
+ GTTimestamp_free(ts);
261
+ result = rb_str_new((char*)data, data_length);
262
+ GT_free(data);
263
+ return result;
264
+ }
265
+
266
+ // load and parse/verify pub. file, populate state.
267
+ int loadpubs_helper(GuardTimeData *gt) {
268
+ int res = GT_OK;
269
+ GTPubFileVerificationInfo *pub_ver;
270
+
271
+ if (gt->pub != NULL)
272
+ GTPublicationsFile_free(gt->pub);
273
+ res = GTHTTP_getPublicationsFile(gt->pubfileuri, &(gt->pub));
274
+ if (res == GT_OK)
275
+ res = GTPublicationsFile_verify(gt->pub, &pub_ver);
276
+ if (res == GT_OK) {
277
+ gt->lastpublicationtime = pub_ver->last_publication_time;
278
+ GTPubFileVerificationInfo_free(pub_ver);
279
+ }
280
+ return res;
281
+ }
282
+
283
+ static void loadpubs(VALUE self)
284
+ {
285
+ int res = GT_OK;
286
+ time_t now;
287
+ GuardTimeData *gt;
288
+ Data_Get_Struct(self, GuardTimeData, gt);
289
+
290
+ if (strcasecmp(gt->loadpubs, "auto") == 0) {
291
+ time(&now);
292
+ if (now <= gt->pubdataupdated + PUBDATA_UPDATE_SECONDS)
293
+ return;
294
+ res = loadpubs_helper(gt);
295
+ if (res == GT_OK)
296
+ gt->pubdataupdated = now;
297
+ }
298
+ else if (strcasecmp(gt->loadpubs, "once") == 0) {
299
+ if (gt->pub != NULL)
300
+ return;
301
+ res = loadpubs_helper(gt);
302
+ }
303
+ else if (strcasecmp(gt->loadpubs, "always") == 0) {
304
+ res = loadpubs_helper(gt);
305
+ }
306
+ else if (strcasecmp(gt->loadpubs, "no") == 0) {
307
+ return;
308
+ }
309
+ else
310
+ rb_raise(rb_eArgError, "'loadpubs' parameter must be either 'auto', 'once', 'no', or 'always'");
311
+
312
+ if (res != GT_OK)
313
+ rb_raise(rb_eRuntimeError, "Error downloading/validating publishing data: %s", GT_getErrorString(res));
314
+ }
315
+
316
+ static VALUE
317
+ time_t_to_Time(GT_Time_t64 t)
318
+ {
319
+ VALUE rb_cTime, rubytime;
320
+ if (t == 0)
321
+ return Qnil;
322
+ rb_cTime = rb_const_get(rb_cObject, rb_intern("Time"));
323
+ rubytime = rb_funcall(rb_cTime, rb_intern("at"), 1, ULL2NUM(t));
324
+ return rubytime;
325
+ }
326
+
327
+ static VALUE
328
+ format_location_id(GT_UInt64 l)
329
+ {
330
+ char buf[32];
331
+ if (l == 0)
332
+ return Qnil;
333
+ snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
334
+ (unsigned) (l >> 48 & 0xffff),
335
+ (unsigned) (l >> 32 & 0xffff),
336
+ (unsigned) (l >> 16 & 0xffff),
337
+ (unsigned) (l & 0xffff));
338
+ return rb_str_new2(buf); //yes, makes copy.
339
+ }
340
+
341
+ static VALUE
342
+ format_hash_algorithm(int alg)
343
+ {
344
+ switch(alg) {
345
+ case GT_HASHALG_SHA256:
346
+ return rb_str_new2("SHA256");
347
+ case GT_HASHALG_SHA1:
348
+ return rb_str_new2("SHA1");
349
+ case GT_HASHALG_RIPEMD160:
350
+ return rb_str_new2("RIPEMD160");
351
+ case GT_HASHALG_SHA224:
352
+ return rb_str_new2("SHA224");
353
+ case GT_HASHALG_SHA384:
354
+ return rb_str_new2("SHA384");
355
+ case GT_HASHALG_SHA512:
356
+ return rb_str_new2("SHA512");
357
+ default:
358
+ return Qnil;
359
+ }
360
+ }
361
+
362
+ static VALUE
363
+ guardtime_verify(int argc, VALUE *argv, VALUE obj)
364
+ {
365
+ int res, argcount;
366
+ GTTimestamp *ts;
367
+ GTDataHash dh;
368
+ GuardTimeData *gt;
369
+ VALUE tsdata, hash, hash2, block, retval;
370
+ Data_Get_Struct(obj, GuardTimeData, gt);
371
+
372
+ argcount = rb_scan_args(argc, argv, "12&", &tsdata, &hash, &hash2, &block);
373
+ StringValue(tsdata);
374
+
375
+ res = GTTimestamp_DERDecode(RSTRING_PTR(tsdata),
376
+ RSTRING_LEN(tsdata), &ts);
377
+ if (res != GT_OK)
378
+ rb_raise(rb_eArgError, GT_getErrorString(res));
379
+
380
+ loadpubs(obj);
381
+ GTVerificationInfo *verification_info = NULL;
382
+ switch (argcount) {
383
+ case 1:
384
+ res = verifyTimestamp(ts, NULL, gt, RTEST(block)? 1:0, &verification_info);
385
+ break;
386
+ case 2:
387
+ get_gtdatahash(hash, &dh);
388
+ res = verifyTimestamp(ts, &dh, gt, RTEST(block)? 1:0, &verification_info);
389
+ break;
390
+ case 3:
391
+ get_gtdatahash2(hash, hash2, &dh);
392
+ res = verifyTimestamp(ts, &dh, gt, RTEST(block)? 1:0, &verification_info);
393
+ break;
394
+ }
395
+
396
+ if (res != GT_OK) {
397
+ GTTimestamp_free(ts);
398
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
399
+ }
400
+
401
+ #define RBNILSTR(n, i) \
402
+ ( rb_hash_aset(retval, ID2SYM(rb_intern(n)), (i) == NULL ? Qnil : rb_str_new2(i)) )
403
+ #define RBSET(n, v) \
404
+ ( rb_hash_aset(retval, ID2SYM(rb_intern(n)), (v)) )
405
+
406
+ if (RTEST(block)) {
407
+ retval = rb_hash_new();
408
+ RBSET("verification_status", INT2FIX( verification_info->verification_status ));
409
+ RBSET("verification_errors", INT2FIX( verification_info->verification_errors ));
410
+ // impl
411
+ RBSET("registered_time", ULL2NUM( verification_info->implicit_data->registered_time ));
412
+ RBSET("location_id", format_location_id( verification_info->implicit_data->location_id ));
413
+ RBNILSTR("location_name", verification_info->implicit_data->location_name );
414
+ RBNILSTR("public_key_fingerprint", verification_info->implicit_data->public_key_fingerprint );
415
+ RBNILSTR("publication_string", verification_info->implicit_data->publication_string );
416
+ // expl
417
+ RBNILSTR("policy", verification_info->explicit_data->policy);
418
+ RBSET("hash_algorithm", format_hash_algorithm( verification_info->explicit_data->hash_algorithm ));
419
+ RBNILSTR("hash_value", verification_info->explicit_data->hash_value );
420
+ RBSET("publication_identifier", ULL2NUM( verification_info->explicit_data->publication_identifier ));
421
+
422
+ if (verification_info->explicit_data->pub_reference_count > 0) {
423
+ int i;
424
+ VALUE pubrefs = rb_ary_new2(verification_info->explicit_data->pub_reference_count);
425
+ for (i = 0; i < verification_info->explicit_data->pub_reference_count; i++)
426
+ rb_ary_push(pubrefs, rb_str_new2( verification_info->explicit_data->pub_reference_list[i] ));
427
+ RBSET("pub_reference_list", pubrefs);
428
+ } else
429
+ RBSET("pub_reference_list", Qnil);
430
+
431
+ RBSET("time", time_t_to_Time( verification_info->implicit_data->registered_time ));
432
+ RBSET("publication_time", time_t_to_Time( verification_info->explicit_data->publication_identifier ));
433
+
434
+ } else
435
+ retval = verification_info->verification_errors == GT_NO_FAILURES ? Qtrue : Qfalse;
436
+
437
+ GTTimestamp_free(ts);
438
+ GTVerificationInfo_free(verification_info);
439
+
440
+ if (RTEST(block))
441
+ return rb_funcall(block, rb_intern("call"), 1, retval);
442
+ else
443
+ return retval;
444
+ }
445
+
446
+
447
+ // returns instance of Digester::... with same hashalg.
448
+ static VALUE
449
+ guardtime_getnewdigester(VALUE self, VALUE tsdata)
450
+ {
451
+ int res;
452
+ int alg;
453
+ GTTimestamp *ts;
454
+ VALUE module_klass, args[1];
455
+
456
+ StringValue(tsdata);
457
+
458
+ res = GTTimestamp_DERDecode(RSTRING_PTR(tsdata), RSTRING_LEN(tsdata), &ts);
459
+ if (res != GT_OK)
460
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
461
+
462
+ res = GTTimestamp_getAlgorithm(ts, &alg);
463
+ GTTimestamp_free(ts);
464
+ if (res != GT_OK)
465
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
466
+
467
+ // checkifnecessary: rb_requre('digest');
468
+ module_klass = rb_const_get(rb_cObject, rb_intern("Digest"));
469
+
470
+ switch(alg) {
471
+ case GT_HASHALG_SHA256:
472
+ args[0] = INT2FIX(256);
473
+ return rb_class_new_instance(1, args,
474
+ rb_const_get(module_klass, rb_intern("SHA2")));
475
+ case GT_HASHALG_SHA1:
476
+ return rb_class_new_instance(0, NULL,
477
+ rb_const_get(module_klass, rb_intern("SHA1")));
478
+ case GT_HASHALG_RIPEMD160:
479
+ return rb_class_new_instance(0, NULL,
480
+ rb_const_get(module_klass, rb_intern("RMD160")));
481
+ case GT_HASHALG_SHA224:
482
+ args[0] = INT2FIX(224);
483
+ return rb_class_new_instance(1, args,
484
+ rb_const_get(module_klass, rb_intern("SHA2")));
485
+ case GT_HASHALG_SHA384:
486
+ args[0] = INT2FIX(384);
487
+ return rb_class_new_instance(1, args,
488
+ rb_const_get(module_klass, rb_intern("SHA2")));
489
+ case GT_HASHALG_SHA512:
490
+ args[0] = INT2FIX(512);
491
+ return rb_class_new_instance(1, args,
492
+ rb_const_get(module_klass, rb_intern("SHA2")));
493
+ default:
494
+ rb_raise(rb_eRuntimeError, "Unknown hash algorithm ID");
495
+ }
496
+ return Qnil;
497
+ }
498
+
499
+
500
+ static VALUE
501
+ guardtime_gethashalg(VALUE self, VALUE tsdata)
502
+ {
503
+ int res;
504
+ int alg;
505
+ GTTimestamp *ts;
506
+
507
+ StringValue(tsdata);
508
+
509
+ res = GTTimestamp_DERDecode(RSTRING_PTR(tsdata), RSTRING_LEN(tsdata), &ts);
510
+ if (res != GT_OK)
511
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
512
+
513
+ res = GTTimestamp_getAlgorithm(ts, &alg);
514
+ GTTimestamp_free(ts);
515
+ if (res != GT_OK)
516
+ rb_raise(rb_eRuntimeError, GT_getErrorString(res));
517
+
518
+ switch(alg) {
519
+ case GT_HASHALG_SHA256:
520
+ return rb_str_new2("SHA256");
521
+ case GT_HASHALG_SHA1:
522
+ return rb_str_new2("SHA1");
523
+ case GT_HASHALG_RIPEMD160:
524
+ return rb_str_new2("RIPEMD160");
525
+ case GT_HASHALG_SHA224:
526
+ return rb_str_new2("SHA224");
527
+ case GT_HASHALG_SHA384:
528
+ return rb_str_new2("SHA384");
529
+ case GT_HASHALG_SHA512:
530
+ return rb_str_new2("SHA512");
531
+ default:
532
+ rb_raise(rb_eRuntimeError, "Unknown hash algorithm ID");
533
+ }
534
+ return Qnil;
535
+ }
536
+
537
+
538
+ static int
539
+ each_conf_param(VALUE key, VALUE value, VALUE klass)
540
+ {
541
+ ID key_id;
542
+ GuardTimeData *gt; // = DATA_PTR(klass);
543
+ Data_Get_Struct(klass, GuardTimeData, gt); // typesafe macro
544
+
545
+ if (key == Qundef) return ST_CONTINUE;
546
+ switch(TYPE(key)) {
547
+ case T_STRING:
548
+ key_id = rb_intern(RSTRING_PTR(key));
549
+ break;
550
+ case T_SYMBOL:
551
+ key_id = SYM2ID(key);
552
+ break;
553
+ default:
554
+ rb_raise(rb_eArgError,
555
+ "config hash includes invalid key");
556
+ }
557
+ if (TYPE(value) != T_STRING)
558
+ rb_raise(rb_eArgError,
559
+ "config hash value for '%s' must be a String", rb_id2name(key_id));
560
+
561
+ if (strcasecmp(rb_id2name(key_id), "signeruri") == 0)
562
+ gt->signeruri = RSTRING_PTR(value); // strdup() perhaps?
563
+ else if (strcasecmp(rb_id2name(key_id), "verifieruri") == 0) {
564
+ if (strlen(gt->verifieruri) > 0)
565
+ gt->verifieruri = RSTRING_PTR(value);
566
+ else
567
+ gt->verifieruri = NULL; // no extending
568
+ }
569
+ else if (strcasecmp(rb_id2name(key_id), "publicationsuri") == 0)
570
+ gt->pubfileuri = RSTRING_PTR(value);
571
+ else if (strcasecmp(rb_id2name(key_id), "loadpubs") == 0)
572
+ gt->loadpubs = RSTRING_PTR(value);
573
+ else
574
+ rb_raise(rb_eArgError,
575
+ "config hash has unknown key '%s'", rb_id2name(key_id));
576
+
577
+ return ST_CONTINUE;
578
+ }
579
+
580
+ static void
581
+ guardtime_free(GuardTimeData *gt)
582
+ {
583
+ if (gt) {
584
+ if (gt->pub != NULL)
585
+ GTPublicationsFile_free(gt->pub);
586
+ GTHTTP_finalize();
587
+ GT_finalize();
588
+ free(gt);
589
+ }
590
+
591
+ }
592
+
593
+ static VALUE
594
+ guardtime_allocate(VALUE self)
595
+ {
596
+ int res;
597
+ GuardTimeData *gt;
598
+
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
+ gt = ALLOC(GuardTimeData);
607
+ // DATA_PTR(self) = gt;
608
+ gt->signeruri = DEFAULT_SIGNERURI;
609
+ gt->verifieruri = DEFAULT_VERIFIERURI;
610
+ gt->pubfileuri = DEFAULT_PUBFILEURI;
611
+ gt->loadpubs = DEFAULT_LOADPUBS;
612
+ gt->pub = NULL;
613
+ gt->pubdataupdated = 0;
614
+ return Data_Wrap_Struct(self, 0, guardtime_free, gt);
615
+ }
616
+
617
+
618
+ // GuardTime.new(blaah)
619
+ static VALUE
620
+ guardtime_initialize(int argc, VALUE *argv, VALUE obj)
621
+ {
622
+ VALUE arghash;
623
+
624
+ if (rb_scan_args(argc, argv, "01", &arghash) == 1)
625
+ rb_hash_foreach(arghash, each_conf_param, obj);
626
+ return obj;
627
+ }
628
+
629
+
630
+ void Init_guardtime()
631
+ {
632
+ rb_cGuardTime = rb_define_class("GuardTime", rb_cObject);
633
+ rb_define_alloc_func(rb_cGuardTime, guardtime_allocate);
634
+ rb_define_method(rb_cGuardTime, "initialize", guardtime_initialize, -1);
635
+ rb_define_method(rb_cGuardTime, "sign", guardtime_sign, -1);
636
+ rb_define_method(rb_cGuardTime, "verify", guardtime_verify, -1);
637
+ rb_define_singleton_method(rb_cGuardTime, "gethashalg", guardtime_gethashalg, 1);
638
+ rb_define_singleton_method(rb_cGuardTime, "getnewdigester", guardtime_getnewdigester, 1);
639
+
640
+ rb_define_const(rb_cGuardTime, "NO_FAILURES", INT2NUM(GT_NO_FAILURES));
641
+ rb_define_const(rb_cGuardTime, "SYNTACTIC_CHECK_FAILURE", INT2NUM(GT_SYNTACTIC_CHECK_FAILURE));
642
+ rb_define_const(rb_cGuardTime, "HASHCHAIN_VERIFICATION_FAILURE", INT2NUM(GT_HASHCHAIN_VERIFICATION_FAILURE));
643
+ rb_define_const(rb_cGuardTime, "PUBLIC_KEY_SIGNATURE_FAILURE", INT2NUM(GT_PUBLIC_KEY_SIGNATURE_FAILURE));
644
+ rb_define_const(rb_cGuardTime, "NOT_VALID_PUBLIC_KEY_FAILURE", INT2NUM(GT_NOT_VALID_PUBLIC_KEY_FAILURE));
645
+ rb_define_const(rb_cGuardTime, "WRONG_DOCUMENT_FAILURE", INT2NUM(GT_WRONG_DOCUMENT_FAILURE));
646
+ 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
+ }
@@ -0,0 +1,107 @@
1
+ require './guardtime'
2
+ require 'digest/sha2'
3
+ require 'test/unit'
4
+
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
+
12
+ gt3 = GuardTime.new
13
+ assert( gt3.verify(ts) )
14
+ assert_raise ArgumentError do
15
+ gt3.verify("corrupted signature token")
16
+ end
17
+ assert_block do
18
+ gt3.verify(ts) do |r|
19
+ assert_instance_of(Time, r[:time])
20
+ assert(Time.now - r[:time] > 60*60*24*45, 'must be old sig')
21
+ assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT,
22
+ r[:verification_status])
23
+ assert_equal( GuardTime::NO_FAILURES, r[:verification_errors])
24
+ assert_instance_of( Array, r[:pub_reference_list])
25
+ assert_instance_of( String, r[:publication_string])
26
+ assert_instance_of(Time, r[:publication_time])
27
+ r[:verification_errors] == GuardTime::NO_FAILURES
28
+ end
29
+ end
30
+ h3 = Digest::SHA2.new << File.read(File.dirname(__FILE__) + File::SEPARATOR + 'cat.gif')
31
+ assert( gt3.verify(ts, h3) )
32
+ assert( gt3.verify(ts, h3) do |r|
33
+ assert_equal( GuardTime::PUBLICATION_CHECKED | GuardTime::PUBLICATION_REFERENCE_PRESENT |
34
+ GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
35
+ assert_equal(h3.hexdigest, r[:hash_value].delete(':'))
36
+ r[:verification_errors] == GuardTime::NO_FAILURES
37
+ end
38
+ )
39
+
40
+ end
41
+
42
+ def test_fresh
43
+ h = Digest::SHA2.new(256) << 'bla bla blah'
44
+ gt = GuardTime.new
45
+ assert_instance_of(GuardTime, gt)
46
+ ts = gt.sign(h)
47
+ assert_equal('SHA256', GuardTime.gethashalg(ts).upcase, 'GuardTime.gethashalg() works')
48
+
49
+ assert_raise TypeError do
50
+ GuardTime.gethashalg(123)
51
+ end
52
+ assert_raise RuntimeError do
53
+ GuardTime.gethashalg("corrupted signature token")
54
+ end
55
+ assert_raise RuntimeError do
56
+ GuardTime.getnewdigester("corrupted signature token")
57
+ end
58
+ h2 = GuardTime.getnewdigester(ts) << 'bla bla blah'
59
+ assert_equal(h.inspect, h2.inspect, 'GuardTime.getnewdigester()')
60
+ assert( gt.verify(ts) do |r|
61
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::PUBLICATION_CHECKED,
62
+ r[:verification_status])
63
+ assert_equal( GuardTime::NO_FAILURES, r[:verification_errors])
64
+ assert_equal( nil, r[:pub_reference_list])
65
+ assert_equal( nil, r[:publication_string])
66
+ assert_instance_of(Time, r[:time])
67
+ assert(Time.now - r[:time] < 60, 'local wall clock may be out of sync?')
68
+ assert_instance_of(Time, r[:publication_time])
69
+ assert_equal(h.hexdigest, r[:hash_value].delete(':'))
70
+ assert_equal('GT : GT : public', r[:location_name])
71
+ r[:verification_errors] == GuardTime::NO_FAILURES
72
+ end
73
+ )
74
+ assert( gt.verify(ts, h2))
75
+ assert( gt.verify(ts, h2) do |r|
76
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::PUBLICATION_CHECKED |
77
+ GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
78
+ r[:verification_errors] == GuardTime::NO_FAILURES
79
+ end
80
+ )
81
+
82
+ assert(gt.verify(ts, 'SHA256', h2.digest))
83
+
84
+ gt2 = GuardTime.new({:loadpubs => 'no', :verifieruri => ''})
85
+ assert( gt2.verify(ts) do |r|
86
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT, r[:verification_status])
87
+ r[:verification_errors] == GuardTime::NO_FAILURES
88
+ end
89
+ )
90
+ assert( gt2.verify(ts, h2) do |r|
91
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
92
+ r[:verification_errors] == GuardTime::NO_FAILURES
93
+ end
94
+ )
95
+
96
+ wrongh = Digest::SHA2.new << 'whateverelse'
97
+ assert_equal( false, gt2.verify(ts, wrongh) )
98
+ assert_equal( false, gt2.verify(ts, wrongh) do |r|
99
+ assert_equal( GuardTime::PUBLIC_KEY_SIGNATURE_PRESENT | GuardTime::DOCUMENT_HASH_CHECKED, r[:verification_status])
100
+ assert_equal( GuardTime::WRONG_DOCUMENT_FAILURE, r[:verification_errors])
101
+ r[:verification_errors] == GuardTime::NO_FAILURES
102
+ end
103
+ )
104
+ end
105
+
106
+ end
107
+
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: guardtime
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - GuardTime AS
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2013-01-03 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: |
22
+ Keyless Signatures are a combination of hash function based server-side signatures and hash-linking based digital timestamping delivered using a distributed and hierarchical infrastructure.
23
+ This extension provides high-level API to access KSI.
24
+
25
+ email: info@guardtime.com
26
+ executables: []
27
+
28
+ extensions:
29
+ - ext/extconf.rb
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - COPYING
34
+ - INSTALL
35
+ - ext/guardtime.c
36
+ - ext/extconf.rb
37
+ - test/tc_guardtime.rb
38
+ has_rdoc: true
39
+ homepage: http://www.guardtime.com/
40
+ licenses:
41
+ - apache-2.0
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.6
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: GuardTime service access extension for Ruby
68
+ test_files:
69
+ - test/tc_guardtime.rb