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,404 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::UTF8String do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::UTF8String }
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::UTF8String
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
+ def _A(str)
34
+ str.force_encoding("ASCII-8BIT")
35
+ end
36
+
37
+ describe '#new' do
38
+ context 'gets value for construct' do
39
+ subject { klass.new(value) }
40
+
41
+ context 'accepts Japanese UTF-8 string' do
42
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
43
+ its(:tag) { should == Krypt::ASN1::UTF8_STRING }
44
+ its(:tag_class) { should == :UNIVERSAL }
45
+ its(:value) { should == value }
46
+ its(:infinite_length) { should == false }
47
+ end
48
+
49
+ context 'accepts Japanese EUC-JP string' do
50
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B'.encode("EUC-JP") }
51
+ its(:value) { should == value } # TODO: auto convert to UTF-8? raise?
52
+ end
53
+
54
+ context 'accepts empty String' do
55
+ let(:value) { '' }
56
+ its(:value) { should == value }
57
+ end
58
+ end
59
+
60
+ context 'gets explicit tag number as the 2nd argument' do
61
+ subject { klass.new('$B$3$s$K$A$O!"@$3&!*(B', tag, :PRIVATE) }
62
+
63
+ context 'accepts default tag' do
64
+ let(:tag) { Krypt::ASN1::UTF8_STRING }
65
+ its(:tag) { should == tag }
66
+ end
67
+
68
+ context 'accepts custom tag' do
69
+ let(:tag) { 14 }
70
+ its(:tag) { should == tag }
71
+ end
72
+ end
73
+
74
+ context 'gets tag class symbol as the 3rd argument' do
75
+ subject { klass.new('$B$3$s$K$A$O!"@$3&!*(B', Krypt::ASN1::UTF8_STRING, tag_class) }
76
+
77
+ context 'accepts :UNIVERSAL' do
78
+ let(:tag_class) { :UNIVERSAL }
79
+ its(:tag_class) { should == tag_class }
80
+ end
81
+
82
+ context 'accepts :APPLICATION' do
83
+ let(:tag_class) { :APPLICATION }
84
+ its(:tag_class) { should == tag_class }
85
+ end
86
+
87
+ context 'accepts :CONTEXT_SPECIFIC' do
88
+ let(:tag_class) { :CONTEXT_SPECIFIC }
89
+ its(:tag_class) { should == tag_class }
90
+ end
91
+
92
+ context 'accepts :PRIVATE' do
93
+ let(:tag_class) { :PRIVATE }
94
+ its(:tag_class) { should == tag_class }
95
+ end
96
+
97
+ context 'accepts :IMPLICIT' do
98
+ let(:tag_class) { :IMPLICIT }
99
+ its(:tag_class) { should == tag_class }
100
+ end
101
+
102
+ context 'accepts :EXPLICIT' do
103
+ let(:tag_class) { :EXPLICIT }
104
+ its(:tag_class) { should == tag_class }
105
+ end
106
+ end
107
+
108
+ context 'when the 2nd argument is given but 3rd argument is omitted' do
109
+ subject { klass.new('$B$3$s$K$A$O!"@$3&!*(B', Krypt::ASN1::UTF8_STRING) }
110
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
111
+ end
112
+ end
113
+
114
+ describe 'accessors' do
115
+ describe '#value' do
116
+ subject { o = klass.new(nil); o.value = value; o }
117
+
118
+ context 'accepts Japanese UTF-8 string' do
119
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
120
+ its(:tag) { should == Krypt::ASN1::UTF8_STRING }
121
+ its(:tag_class) { should == :UNIVERSAL }
122
+ its(:value) { should == value }
123
+ its(:infinite_length) { should == false }
124
+ end
125
+
126
+ context 'accepts Japanese EUC-JP string' do
127
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B'.encode("EUC-JP") }
128
+ its(:value) { should == value } # TODO: auto convert to UTF-8? raise?
129
+ end
130
+
131
+ context 'accepts empty String' do
132
+ let(:value) { '' }
133
+ its(:value) { should == value }
134
+ end
135
+ end
136
+
137
+ describe '#tag' do
138
+ subject { o = klass.new(nil); o.tag = tag; o }
139
+
140
+ context 'accepts default tag' do
141
+ let(:tag) { Krypt::ASN1::UTF8_STRING }
142
+ its(:tag) { should == tag }
143
+ end
144
+
145
+ context 'accepts custom tag' do
146
+ let(:tag) { 14 }
147
+ its(:tag) { should == tag }
148
+ end
149
+ end
150
+
151
+ describe '#tag_class' do
152
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
153
+
154
+ context 'accepts :UNIVERSAL' do
155
+ let(:tag_class) { :UNIVERSAL }
156
+ its(:tag_class) { should == tag_class }
157
+ end
158
+
159
+ context 'accepts :APPLICATION' do
160
+ let(:tag_class) { :APPLICATION }
161
+ its(:tag_class) { should == tag_class }
162
+ end
163
+
164
+ context 'accepts :CONTEXT_SPECIFIC' do
165
+ let(:tag_class) { :CONTEXT_SPECIFIC }
166
+ its(:tag_class) { should == tag_class }
167
+ end
168
+
169
+ context 'accepts :PRIVATE' do
170
+ let(:tag_class) { :PRIVATE }
171
+ its(:tag_class) { should == tag_class }
172
+ end
173
+
174
+ context 'accepts :IMPLICIT' do
175
+ let(:tag_class) { :IMPLICIT }
176
+ its(:tag_class) { should == tag_class }
177
+ end
178
+
179
+ context 'accepts :EXPLICIT' do
180
+ let(:tag_class) { :EXPLICIT }
181
+ its(:tag_class) { should == tag_class }
182
+ end
183
+ end
184
+ end
185
+
186
+ describe '#to_der' do
187
+ context 'encodes a given value' do
188
+ subject { klass.new(value).to_der }
189
+
190
+ context '$B$3$s$K$A$O!"@$3&!*(B' do
191
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
192
+ it { should == _A("\x0C\x18" + value) }
193
+ end
194
+
195
+ context '(empty)' do
196
+ let(:value) { '' }
197
+ it { should == "\x0C\x00" }
198
+ end
199
+
200
+ context '1000 octets' do
201
+ let(:value) { '$B$"(B' * 1000 }
202
+ it { should == _A("\x0C\x82\x1F\x40" + value) }
203
+ end
204
+
205
+ context 'nil' do
206
+ let(:value) { nil }
207
+ it { should == "\x0C\x00" }
208
+ end
209
+ end
210
+
211
+ context 'encodes tag number' do
212
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
213
+ subject { klass.new(value, tag, :PRIVATE).to_der }
214
+
215
+ context 'default tag' do
216
+ let(:tag) { Krypt::ASN1::UTF8_STRING }
217
+ it { should == _A("\xCC\x18" + value) }
218
+ end
219
+
220
+ context 'custom tag' do
221
+ let(:tag) { 14 }
222
+ it { should == _A("\xCE\x18" + value) }
223
+ end
224
+
225
+ context 'nil' do
226
+ let(:tag) { nil }
227
+ it { -> { subject }.should raise_error asn1error }
228
+ end
229
+ end
230
+
231
+ context 'encodes tag class' do
232
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
233
+ subject { klass.new(value, Krypt::ASN1::UTF8_STRING, tag_class).to_der }
234
+
235
+ context 'UNIVERSAL' do
236
+ let(:tag_class) { :UNIVERSAL }
237
+ it { should == _A("\x0C\x18" + value) }
238
+ end
239
+
240
+ context 'APPLICATION' do
241
+ let(:tag_class) { :APPLICATION }
242
+ it { should == _A("\x4C\x18" + value) }
243
+ end
244
+
245
+ context 'CONTEXT_SPECIFIC' do
246
+ let(:tag_class) { :CONTEXT_SPECIFIC }
247
+ it { should == _A("\x8C\x18" + value) }
248
+ end
249
+
250
+ context 'PRIVATE' do
251
+ let(:tag_class) { :PRIVATE }
252
+ it { should == _A("\xCC\x18" + value) }
253
+ end
254
+
255
+ context 'IMPLICIT' do
256
+ let(:tag_class) { :IMPLICIT }
257
+ it { should == _A("\x8C\x18" + value) }
258
+ end
259
+
260
+ context 'EXPLICIT' do
261
+ let(:tag_class) { :EXPLICIT }
262
+ it { should == _A("\xAC\x1A\x0C\x18" + value) }
263
+ end
264
+
265
+ context nil do
266
+ let(:tag_class) { nil }
267
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
268
+ end
269
+
270
+ context :no_such_class do
271
+ let(:tag_class) { :no_such_class }
272
+ it { -> { subject }.should raise_error asn1error }
273
+ end
274
+ end
275
+
276
+ context 'encodes values set via accessors' do
277
+ subject {
278
+ o = klass.new(nil)
279
+ o.value = value if defined? value
280
+ o.tag = tag if defined? tag
281
+ o.tag_class = tag_class if defined? tag_class
282
+ o.to_der
283
+ }
284
+
285
+ context 'value: 01010101' do
286
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
287
+ it { should == _A("\x0C\x18" + value) }
288
+ end
289
+
290
+ context 'custom tag' do
291
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
292
+ let(:tag) { 14 }
293
+ let(:tag_class) { :PRIVATE }
294
+ it { should == _A("\xCE\x18" + value) }
295
+ end
296
+
297
+ context 'tag_class' do
298
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
299
+ let(:tag_class) { :APPLICATION }
300
+ it { should == _A("\x4C\x18" + value) }
301
+ end
302
+ end
303
+ end
304
+
305
+ describe '#encode_to' do
306
+ context 'encodes to an IO' do
307
+ subject { klass.new(value).encode_to(io); io }
308
+
309
+ context "StringIO" do
310
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
311
+ let(:io) { string_io_object }
312
+ its(:written_bytes) { should == _A("\x0C\x18" + value) }
313
+ end
314
+
315
+ context "Object responds to :write" do
316
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
317
+ let(:io) { writable_object }
318
+ its(:written_bytes) { should == _A("\x0C\x18" + value) }
319
+ end
320
+
321
+ context "raise IO error transparently" do
322
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
323
+ let(:io) { io_error_object }
324
+ it { -> { subject }.should raise_error asn1error }
325
+ end
326
+ end
327
+
328
+ it 'returns self' do
329
+ obj = klass.new('$B$3$s$K$A$O!"@$3&!*(B')
330
+ obj.encode_to(string_io_object).should == obj
331
+ end
332
+ end
333
+
334
+ describe 'extracted from ASN1.decode' do
335
+ subject { decoder.decode(der) }
336
+
337
+ context 'extracted value' do
338
+ context '$B$3$s$K$A$O!"@$3&!*(B' do
339
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
340
+ let(:der) { _A("\x0C\x18" + value) }
341
+ its(:class) { should == klass }
342
+ its(:tag) { should == Krypt::ASN1::UTF8_STRING }
343
+ its(:value) { should == value }
344
+ end
345
+
346
+ context '(empty)' do
347
+ let(:der) { "\x0C\x00" }
348
+ its(:class) { should == klass }
349
+ its(:tag) { should == Krypt::ASN1::UTF8_STRING }
350
+ its(:value) { should == '' }
351
+ end
352
+
353
+ context '1000 octets' do
354
+ let(:value) { '$B$"(B' * 1000 }
355
+ let(:der) { _A("\x0C\x82\x1F\x40" + value) }
356
+ its(:class) { should == klass }
357
+ its(:tag) { should == Krypt::ASN1::UTF8_STRING }
358
+ its(:value) { should == value }
359
+ end
360
+ end
361
+
362
+ context 'extracted tag class' do
363
+ let(:value) { '$B$3$s$K$A$O!"@$3&!*(B' }
364
+
365
+ context 'UNIVERSAL' do
366
+ let(:der) { _A("\x0C\x18" + value) }
367
+ its(:tag_class) { should == :UNIVERSAL }
368
+ end
369
+
370
+ context 'APPLICATION' do
371
+ let(:der) { _A("\x4C\x18" + value) }
372
+ its(:tag_class) { should == :APPLICATION }
373
+ end
374
+
375
+ context 'CONTEXT_SPECIFIC' do
376
+ let(:der) { _A("\x8C\x18" + value) }
377
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
378
+ end
379
+
380
+ context 'PRIVATE' do
381
+ let(:der) { _A("\xCC\x18" + value) }
382
+ its(:tag_class) { should == :PRIVATE }
383
+ end
384
+
385
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
386
+ let(:der) { _A("\x0C\x18" + value) }
387
+ it do
388
+ subject.tag_class = :IMPLICIT
389
+ subject.to_der.should == _A("\x8C\x18" + value)
390
+ end
391
+ end
392
+
393
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
394
+ let(:der) { _A("\x0C\x18" + value) }
395
+ it do
396
+ subject.tag_class = :EXPLICIT
397
+ subject.tag = 0
398
+ subject.to_der.should == _A("\xA0\x1A\x0C\x18" + value)
399
+ end
400
+ end
401
+
402
+ end
403
+ end
404
+ end
@@ -0,0 +1,53 @@
1
+ require 'stringio'
2
+
3
+ module Krypt
4
+ module ASN1
5
+ module Resources
6
+ def string_io_object
7
+ obj = StringIO.new("".encode("BINARY"))
8
+ def obj.written_bytes
9
+ string
10
+ end
11
+ obj
12
+ end
13
+
14
+ def writable_object
15
+ obj = Object.new
16
+ def obj.write(str)
17
+ (@buf ||= "") << str
18
+ str.size
19
+ end
20
+ def obj.written_bytes; @buf; end
21
+ obj
22
+ end
23
+
24
+ def io_error_object
25
+ obj = Object.new
26
+ def obj.write(str)
27
+ raise EOFError, 'bark'
28
+ end
29
+ obj
30
+ end
31
+
32
+ def s(str)
33
+ Krypt::ASN1::OctetString.new(str)
34
+ end
35
+
36
+ def i(num)
37
+ Krypt::ASN1::Integer.new(num)
38
+ end
39
+
40
+ def eoc
41
+ Krypt::ASN1::EndOfContents.new
42
+ end
43
+
44
+ def yielded_value_from_each(obj)
45
+ all = []
46
+ obj.each do |element|
47
+ all << element
48
+ end
49
+ all
50
+ end
51
+ end
52
+ end
53
+ end