krypt 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +82 -0
  3. data/lib/krypt.rb +49 -0
  4. data/lib/krypt/asn1.rb +3 -0
  5. data/lib/krypt/asn1/common.rb +96 -0
  6. data/lib/krypt/asn1/template.rb +257 -0
  7. data/lib/krypt/codec.rb +57 -0
  8. data/lib/krypt/codec/base64.rb +140 -0
  9. data/lib/krypt/codec/base_codec.rb +36 -0
  10. data/lib/krypt/codec/hex.rb +122 -0
  11. data/lib/krypt/digest.rb +112 -0
  12. data/lib/krypt/hmac.rb +69 -0
  13. data/lib/krypt/pkcs5.rb +1 -0
  14. data/lib/krypt/pkcs5/pbkdf2.rb +41 -0
  15. data/lib/krypt/provider.rb +35 -0
  16. data/lib/krypt/x509.rb +3 -0
  17. data/lib/krypt/x509/certificate.rb +36 -0
  18. data/lib/krypt/x509/common.rb +41 -0
  19. data/lib/krypt/x509/crl.rb +33 -0
  20. data/lib/krypt_missing.rb +32 -0
  21. data/spec/krypt-core/MEMO.txt +85 -0
  22. data/spec/krypt-core/asn1/asn1_bit_string_spec.rb +475 -0
  23. data/spec/krypt-core/asn1/asn1_boolean_spec.rb +392 -0
  24. data/spec/krypt-core/asn1/asn1_constants_spec.rb +71 -0
  25. data/spec/krypt-core/asn1/asn1_data_spec.rb +1153 -0
  26. data/spec/krypt-core/asn1/asn1_end_of_contents_spec.rb +133 -0
  27. data/spec/krypt-core/asn1/asn1_enumerated_spec.rb +458 -0
  28. data/spec/krypt-core/asn1/asn1_generalized_time_spec.rb +492 -0
  29. data/spec/krypt-core/asn1/asn1_integer_spec.rb +557 -0
  30. data/spec/krypt-core/asn1/asn1_null_spec.rb +360 -0
  31. data/spec/krypt-core/asn1/asn1_object_id_spec.rb +495 -0
  32. data/spec/krypt-core/asn1/asn1_octet_string_spec.rb +456 -0
  33. data/spec/krypt-core/asn1/asn1_parser_spec.rb +503 -0
  34. data/spec/krypt-core/asn1/asn1_pem_spec.rb +282 -0
  35. data/spec/krypt-core/asn1/asn1_sequence_spec.rb +637 -0
  36. data/spec/krypt-core/asn1/asn1_set_spec.rb +795 -0
  37. data/spec/krypt-core/asn1/asn1_utc_time_spec.rb +495 -0
  38. data/spec/krypt-core/asn1/asn1_utf8_string_spec.rb +404 -0
  39. data/spec/krypt-core/asn1/resources.rb +53 -0
  40. data/spec/krypt-core/base64/base64_spec.rb +97 -0
  41. data/spec/krypt-core/digest/digest_spec.rb +707 -0
  42. data/spec/krypt-core/hex/hex_spec.rb +102 -0
  43. data/spec/krypt-core/pem/pem_decode_spec.rb +235 -0
  44. data/spec/krypt-core/resources.rb +1 -0
  45. data/spec/krypt-core/template/template_choice_parse_spec.rb +289 -0
  46. data/spec/krypt-core/template/template_dsl_spec.rb +351 -0
  47. data/spec/krypt-core/template/template_seq_of_parse_spec.rb +64 -0
  48. data/spec/krypt-core/template/template_seq_parse_spec.rb +1241 -0
  49. data/spec/krypt/codec/base64_decoder_spec.rb +94 -0
  50. data/spec/krypt/codec/base64_encoder_spec.rb +94 -0
  51. data/spec/krypt/codec/base64_mixed_spec.rb +16 -0
  52. data/spec/krypt/codec/hex_decoder_spec.rb +94 -0
  53. data/spec/krypt/codec/hex_encoder_spec.rb +94 -0
  54. data/spec/krypt/codec/hex_mixed_spec.rb +17 -0
  55. data/spec/krypt/codec/identity_shared.rb +119 -0
  56. data/spec/krypt/hmac/hmac_spec.rb +311 -0
  57. data/spec/krypt/pkcs5/pbkdf2_spec.rb +79 -0
  58. data/spec/krypt/provider/provider_spec.rb +83 -0
  59. data/spec/res/ca-bundle.crt +11758 -0
  60. data/spec/res/certificate.cer +0 -0
  61. data/spec/res/certificate.pem +20 -0
  62. data/spec/res/multiple_certs.pem +60 -0
  63. data/spec/resources.rb +66 -0
  64. data/test/helper.rb +8 -0
  65. data/test/res/certificate.cer +0 -0
  66. data/test/resources.rb +48 -0
  67. data/test/scratch.rb +28 -0
  68. data/test/test_krypt_asn1.rb +119 -0
  69. data/test/test_krypt_parser.rb +331 -0
  70. metadata +134 -0
@@ -0,0 +1,392 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::Boolean do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::Boolean }
13
+ let(:decoder) { mod }
14
+ let(:asn1error) { mod::ASN1Error }
15
+
16
+ # For test against OpenSSL
17
+ #
18
+ #let(:mod) { OpenSSL::ASN1 }
19
+ #
20
+ # OpenSSL stub for signature mismatch
21
+ class OpenSSL::ASN1::Boolean
22
+ class << self
23
+ alias old_new new
24
+ def new(*args)
25
+ if args.size > 1
26
+ args = [args[0], args[1], :IMPLICIT, args[2]]
27
+ end
28
+ old_new(*args)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe '#new' do
34
+ context 'gets value for construct' do
35
+ subject { klass.new(value) }
36
+
37
+ context 'accepts true' do
38
+ let(:value) { true }
39
+ its(:tag) { should == Krypt::ASN1::BOOLEAN }
40
+ its(:tag_class) { should == :UNIVERSAL }
41
+ its(:value) { should == true }
42
+ its(:infinite_length) { should == false }
43
+ end
44
+
45
+ context 'accepts false' do
46
+ let(:value) { false }
47
+ its(:tag) { should == Krypt::ASN1::BOOLEAN }
48
+ its(:tag_class) { should == :UNIVERSAL }
49
+ its(:value) { should == false }
50
+ its(:infinite_length) { should == false }
51
+ end
52
+ end
53
+
54
+ context 'gets explicit tag number as the 2nd argument' do
55
+ subject { klass.new(true, tag, :PRIVATE) }
56
+
57
+ context 'accepts default tag' do
58
+ let(:tag) { Krypt::ASN1::BOOLEAN }
59
+ its(:tag) { should == tag }
60
+ end
61
+
62
+ context 'accepts custom tag' do
63
+ let(:tag) { 14 }
64
+ its(:tag) { should == tag }
65
+ end
66
+ end
67
+
68
+ context 'gets tag class symbol as the 3rd argument' do
69
+ subject { klass.new(true, Krypt::ASN1::BOOLEAN, tag_class) }
70
+
71
+ context 'accepts :UNIVERSAL' do
72
+ let(:tag_class) { :UNIVERSAL }
73
+ its(:tag_class) { should == tag_class }
74
+ end
75
+
76
+ context 'accepts :APPLICATION' do
77
+ let(:tag_class) { :APPLICATION }
78
+ its(:tag_class) { should == tag_class }
79
+ end
80
+
81
+ context 'accepts :CONTEXT_SPECIFIC' do
82
+ let(:tag_class) { :CONTEXT_SPECIFIC }
83
+ its(:tag_class) { should == tag_class }
84
+ end
85
+
86
+ context 'accepts :PRIVATE' do
87
+ let(:tag_class) { :PRIVATE }
88
+ its(:tag_class) { should == tag_class }
89
+ end
90
+
91
+ context 'accepts :IMPLICIT' do
92
+ let(:tag_class) { :IMPLICIT }
93
+ its(:tag_class) { should == tag_class }
94
+ end
95
+
96
+ context 'accepts :EXPLICIT' do
97
+ let(:tag_class) { :EXPLICIT }
98
+ its(:tag_class) { should == tag_class }
99
+ end
100
+ end
101
+
102
+ context 'when the 2nd argument is given but 3rd argument is omitted' do
103
+ subject { klass.new(true, Krypt::ASN1::BOOLEAN) }
104
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
105
+ end
106
+ end
107
+
108
+ describe 'accessors' do
109
+ describe '#value' do
110
+ subject { o = klass.new(nil); o.value = value; o }
111
+
112
+ context 'accepts true' do
113
+ let(:value) { true }
114
+ its(:value) { should == true }
115
+ end
116
+
117
+ context 'accepts false' do
118
+ let(:value) { false }
119
+ its(:value) { should == false }
120
+ end
121
+ end
122
+
123
+ describe '#tag' do
124
+ subject { o = klass.new(nil); o.tag = tag; o }
125
+
126
+ context 'accepts default tag' do
127
+ let(:tag) { Krypt::ASN1::BOOLEAN }
128
+ its(:tag) { should == tag }
129
+ end
130
+
131
+ context 'accepts custom tag' do
132
+ let(:tag) { 14 }
133
+ its(:tag) { should == tag }
134
+ end
135
+ end
136
+
137
+ describe '#tag_class' do
138
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
139
+
140
+ context 'accepts :UNIVERSAL' do
141
+ let(:tag_class) { :UNIVERSAL }
142
+ its(:tag_class) { should == tag_class }
143
+ end
144
+
145
+ context 'accepts :APPLICATION' do
146
+ let(:tag_class) { :APPLICATION }
147
+ its(:tag_class) { should == tag_class }
148
+ end
149
+
150
+ context 'accepts :CONTEXT_SPECIFIC' do
151
+ let(:tag_class) { :CONTEXT_SPECIFIC }
152
+ its(:tag_class) { should == tag_class }
153
+ end
154
+
155
+ context 'accepts :PRIVATE' do
156
+ let(:tag_class) { :PRIVATE }
157
+ its(:tag_class) { should == tag_class }
158
+ end
159
+
160
+ context 'accepts :IMPLICIT' do
161
+ let(:tag_class) { :IMPLICIT }
162
+ its(:tag_class) { should == tag_class }
163
+ end
164
+
165
+ context 'accepts :EXPLICIT' do
166
+ let(:tag_class) { :EXPLICIT }
167
+ its(:tag_class) { should == tag_class }
168
+ end
169
+ end
170
+ end
171
+
172
+ describe '#to_der' do
173
+ context 'encodes a given value' do
174
+ subject { klass.new(value).to_der }
175
+
176
+ context 'true' do
177
+ let(:value) { true }
178
+ it { should == "\x01\x01\xFF" }
179
+ end
180
+
181
+ context 'false' do
182
+ let(:value) { false }
183
+ it { should == "\x01\x01\x00" }
184
+ end
185
+
186
+ context 'nil' do
187
+ let(:value) { nil }
188
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
189
+ end
190
+
191
+ context 'non true/false e.g. String' do
192
+ let(:value) { 'hi!' }
193
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check true/false
194
+ end
195
+ end
196
+
197
+ context 'encodes tag number' do
198
+ subject { klass.new(true, tag, :PRIVATE).to_der }
199
+
200
+ context 'default tag' do
201
+ let(:tag) { Krypt::ASN1::BOOLEAN }
202
+ it { should == "\xC1\x01\xFF" }
203
+ end
204
+
205
+ context 'custom tag' do
206
+ let(:tag) { 14 }
207
+ it { should == "\xCE\x01\xFF" }
208
+ end
209
+
210
+ context 'nil' do
211
+ let(:tag) { nil }
212
+ it { -> { subject }.should raise_error asn1error }
213
+ end
214
+ end
215
+
216
+ context 'encodes tag class' do
217
+ subject { klass.new(true, Krypt::ASN1::BOOLEAN, tag_class).to_der }
218
+
219
+ context 'UNIVERSAL' do
220
+ let(:tag_class) { :UNIVERSAL }
221
+ it { should == "\x01\x01\xFF" }
222
+ end
223
+
224
+ context 'APPLICATION' do
225
+ let(:tag_class) { :APPLICATION }
226
+ it { should == "\x41\x01\xFF" }
227
+ end
228
+
229
+ context 'CONTEXT_SPECIFIC' do
230
+ let(:tag_class) { :CONTEXT_SPECIFIC }
231
+ it { should == "\x81\x01\xFF" }
232
+ end
233
+
234
+ context 'PRIVATE' do
235
+ let(:tag_class) { :PRIVATE }
236
+ it { should == "\xC1\x01\xFF" }
237
+ end
238
+
239
+ context "IMPLICIT" do
240
+ let(:tag_class) { :IMPLICIT }
241
+ it { should == "\x81\x01\xFF" }
242
+ end
243
+
244
+ context "EXPLICIT" do
245
+ let(:tag_class) { :EXPLICIT }
246
+ it { should == "\xA1\x03\x01\x01\xFF" }
247
+ end
248
+
249
+ context nil do
250
+ let(:tag_class) { nil }
251
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
252
+ end
253
+
254
+ context :no_such_class do
255
+ let(:tag_class) { :no_such_class }
256
+ it { -> { subject }.should raise_error asn1error }
257
+ end
258
+ end
259
+
260
+ context 'encodes values set via accessors' do
261
+ subject {
262
+ o = klass.new(nil)
263
+ o.value = value if defined? value
264
+ o.tag = tag if defined? tag
265
+ o.tag_class = tag_class if defined? tag_class
266
+ o.to_der
267
+ }
268
+
269
+ context 'value: true' do
270
+ let(:value) { true }
271
+ it { should == "\x01\x01\xFF" }
272
+ end
273
+
274
+ context 'custom tag' do
275
+ let(:value) { true }
276
+ let(:tag) { 14 }
277
+ let(:tag_class) { :PRIVATE }
278
+ it { should == "\xCE\x01\xFF" }
279
+ end
280
+
281
+ context 'tag_class' do
282
+ let(:value) { true }
283
+ let(:tag_class) { :APPLICATION }
284
+ it { should == "\x41\x01\xFF" }
285
+ end
286
+ end
287
+
288
+ it "preserves a BER-encoded value when encoding it again" do
289
+ ber = "\x01\x01\x01"
290
+ decoder.decode(ber).to_der.should == ber
291
+ end
292
+ end
293
+
294
+ describe '#encode_to' do
295
+ context 'encodes to an IO' do
296
+ subject { klass.new(value).encode_to(io); io }
297
+
298
+ context "StringIO" do
299
+ let(:value) { true }
300
+ let(:io) { string_io_object }
301
+ its(:written_bytes) { should == "\x01\x01\xFF" }
302
+ end
303
+
304
+ context "Object responds to :write" do
305
+ let(:value) { true }
306
+ let(:io) { writable_object }
307
+ its(:written_bytes) { should == "\x01\x01\xFF" }
308
+ end
309
+
310
+ context "raise IO error transparently" do
311
+ let(:value) { true }
312
+ let(:io) { io_error_object }
313
+ it { -> { subject }.should raise_error asn1error }
314
+ end
315
+ end
316
+
317
+ it 'returns self' do
318
+ obj = klass.new(true)
319
+ obj.encode_to(string_io_object).should == obj
320
+ end
321
+ end
322
+
323
+ describe 'extracted from ASN1.decode' do
324
+ subject { decoder.decode(der) }
325
+
326
+ context 'extracted value' do
327
+ context 'true' do
328
+ let(:der) { "\x01\x01\xFF" }
329
+ its(:class) { should == klass }
330
+ its(:tag) { should == Krypt::ASN1::BOOLEAN }
331
+ its(:value) { should == true }
332
+ end
333
+
334
+ context 'false' do
335
+ let(:der) { "\x01\x01\x00" }
336
+ its(:class) { should == klass }
337
+ its(:tag) { should == Krypt::ASN1::BOOLEAN }
338
+ its(:value) { should == false }
339
+ end
340
+
341
+ context 'allow to decode non-DER true' do
342
+ let(:der) { "\x01\x01\x01" } # non 0xFF is true in BER
343
+ its(:class) { should == klass }
344
+ its(:value) { should == true }
345
+ end
346
+
347
+ context 'rejects values whose length is > 1' do
348
+ let(:der) { "\x01\x02\x01\x01" }
349
+ it { -> { subject.value }.should raise_error asn1error }
350
+ end
351
+ end
352
+
353
+ context 'extracted tag class' do
354
+ context 'UNIVERSAL' do
355
+ let(:der) { "\x01\x01\xFF" }
356
+ its(:tag_class) { should == :UNIVERSAL }
357
+ end
358
+
359
+ context 'APPLICATION' do
360
+ let(:der) { "\x41\x01\xFF" }
361
+ its(:tag_class) { should == :APPLICATION }
362
+ end
363
+
364
+ context 'CONTEXT_SPECIFIC' do
365
+ let(:der) { "\x81\x01\xFF" }
366
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
367
+ end
368
+
369
+ context 'PRIVATE' do
370
+ let(:der) { "\xC1\x01\xFF" }
371
+ its(:tag_class) { should == :PRIVATE }
372
+ end
373
+
374
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
375
+ let(:der) { "\x01\x01\xFF" }
376
+ it do
377
+ subject.tag_class = :IMPLICIT
378
+ subject.to_der.should == "\x81\x01\xFF"
379
+ end
380
+ end
381
+
382
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
383
+ let(:der) { "\x01\x01\xFF" }
384
+ it do
385
+ subject.tag_class = :EXPLICIT
386
+ subject.tag = 0
387
+ subject.to_der.should == "\xA0\x03\x01\x01\xFF"
388
+ end
389
+ end
390
+ end
391
+ end
392
+ end
@@ -0,0 +1,71 @@
1
+ require 'rspec'
2
+ require 'krypt'
3
+
4
+ describe Krypt::ASN1 do
5
+ let(:mod) { Krypt::ASN1 }
6
+
7
+ it "defines constants for UNIVERSAL tags" do
8
+ mod::END_OF_CONTENTS.should == 0
9
+ mod::BOOLEAN.should == 1
10
+ mod::INTEGER.should == 2
11
+ mod::BIT_STRING.should == 3
12
+ mod::OCTET_STRING.should == 4
13
+ mod::NULL.should == 5
14
+ mod::OBJECT_ID.should == 6
15
+
16
+ mod::ENUMERATED.should == 10
17
+
18
+ mod::UTF8_STRING.should == 12
19
+
20
+ mod::SEQUENCE.should == 16
21
+ mod::SET.should == 17
22
+ mod::NUMERIC_STRING.should == 18
23
+ mod::PRINTABLE_STRING.should == 19
24
+ mod::T61_STRING.should == 20
25
+ mod::VIDEOTEX_STRING.should == 21
26
+ mod::IA5_STRING.should == 22
27
+ mod::UTC_TIME.should == 23
28
+ mod::GENERALIZED_TIME.should == 24
29
+ mod::GRAPHIC_STRING.should == 25
30
+ mod::ISO64_STRING.should == 26
31
+ mod::GENERAL_STRING.should == 27
32
+ mod::UNIVERSAL_STRING.should == 28
33
+
34
+ mod::BMP_STRING.should == 30
35
+ end
36
+
37
+ describe '::UNIVERSAL_TAG_NAME' do
38
+
39
+ let(:ary) { Krypt::ASN1::UNIVERSAL_TAG_NAME }
40
+
41
+ it "UNIVERSAL_TAG_NAME defines name of the constants
42
+ corresponding to a given tag. If a class is not
43
+ supported, the value at the corresponding index is nil" do
44
+ ary[mod::END_OF_CONTENTS].should == "END_OF_CONTENTS"
45
+ ary[mod::BOOLEAN].should == "BOOLEAN"
46
+ ary[mod::INTEGER].should == "INTEGER"
47
+ ary[mod::BIT_STRING].should == "BIT_STRING"
48
+ ary[mod::OCTET_STRING].should == "OCTET_STRING"
49
+ ary[mod::NULL].should == "NULL"
50
+ ary[mod::OBJECT_ID].should == "OBJECT_ID"
51
+ ary[mod::ENUMERATED].should == "ENUMERATED"
52
+ ary[mod::UTF8_STRING].should == "UTF8_STRING"
53
+ ary[mod::SEQUENCE].should == "SEQUENCE"
54
+ ary[mod::SET].should == "SET"
55
+ ary[mod::NUMERIC_STRING].should == "NUMERIC_STRING"
56
+ ary[mod::PRINTABLE_STRING].should == "PRINTABLE_STRING"
57
+ ary[mod::T61_STRING].should == "T61_STRING"
58
+ ary[mod::VIDEOTEX_STRING].should == "VIDEOTEX_STRING"
59
+ ary[mod::IA5_STRING].should == "IA5_STRING"
60
+ ary[mod::UTC_TIME].should == "UTC_TIME"
61
+ ary[mod::GENERALIZED_TIME].should == "GENERALIZED_TIME"
62
+ ary[mod::GRAPHIC_STRING].should == "GRAPHIC_STRING"
63
+ ary[mod::ISO64_STRING].should == "ISO64_STRING"
64
+ ary[mod::GENERAL_STRING].should == "GENERAL_STRING"
65
+ ary[mod::UNIVERSAL_STRING].should == "UNIVERSAL_STRING"
66
+ ary[mod::BMP_STRING].should == "BMP_STRING"
67
+ end
68
+
69
+ end
70
+
71
+ end