krypt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,282 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'base64'
6
+ require_relative './resources'
7
+ require_relative '../resources'
8
+
9
+ describe Krypt::ASN1 do
10
+ include Krypt::ASN1::Resources
11
+
12
+ let(:mod) { Krypt::ASN1 }
13
+ let(:decoder) { mod }
14
+ let(:asn1error) { mod::ASN1Error }
15
+
16
+ def create_pem_b64(b64, name)
17
+ "-----BEGIN #{name}-----\n#{b64}-----END #{name}-----\n"
18
+ end
19
+
20
+ describe "#decode" do
21
+ subject { decoder.decode(value) }
22
+
23
+ context "accepts regular DER-encoded values" do
24
+ let(:value) { "\x02\x01\x01" }
25
+ its(:tag) { should == Krypt::ASN1::INTEGER }
26
+ its(:tag_class) { should == :UNIVERSAL }
27
+ its(:value) { should == 1 }
28
+ its(:infinite_length) { should == false }
29
+ end
30
+
31
+ context "also accepts PEM-encoded values" do
32
+ let(:value) { create_pem_b64(Base64.encode64("\x02\x01\x01"), "INTEGER") }
33
+ its(:tag) { should == Krypt::ASN1::INTEGER }
34
+ its(:tag_class) { should == :UNIVERSAL }
35
+ its(:value) { should == 1 }
36
+ its(:infinite_length) { should == false }
37
+ end
38
+
39
+ context "accepts IO" do
40
+ subject do
41
+ begin
42
+ decoder.decode(io)
43
+ ensure
44
+ io.close
45
+ end
46
+ end
47
+
48
+ context "regular DER-encoded IO" do
49
+ let(:io) { Resources.certificate_io }
50
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
51
+ its(:tag_class) { should == :UNIVERSAL }
52
+ its(:infinite_length) { should == false }
53
+ its(:value) { should be_an_instance_of Array }
54
+ its(:to_der) { should == Resources.certificate }
55
+ end
56
+
57
+ context "regular PEM-encoded IO" do
58
+ let(:io) { Resources.certificate_pem_io }
59
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
60
+ its(:tag_class) { should == :UNIVERSAL }
61
+ its(:infinite_length) { should == false }
62
+ its(:value) { should be_an_instance_of Array }
63
+ its(:to_der) { should == Resources.certificate }
64
+ end
65
+
66
+ context "regular DER-encoded StringIO" do
67
+ let(:io) { StringIO.new(Resources.certificate) }
68
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
69
+ its(:tag_class) { should == :UNIVERSAL }
70
+ its(:infinite_length) { should == false }
71
+ its(:value) { should be_an_instance_of Array }
72
+ its(:to_der) { should == Resources.certificate }
73
+ end
74
+
75
+ context "regular PEM-encoded StringIO" do
76
+ let(:io) { StringIO.new(Resources.certificate_pem) }
77
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
78
+ its(:tag_class) { should == :UNIVERSAL }
79
+ its(:infinite_length) { should == false }
80
+ its(:value) { should be_an_instance_of Array }
81
+ its(:to_der) { should == Resources.certificate }
82
+ end
83
+
84
+ context "DER-encoded IO-like value that does not support rewinding" do
85
+ let(:io) do
86
+ c = Class.new do
87
+ def initialize
88
+ @io = Resources.certificate_io
89
+ end
90
+
91
+ def read(len=nil, buf=nil)
92
+ @io.read(len, buf)
93
+ end
94
+
95
+ def seek(amount, whence=IO::SEEK_SET)
96
+ raise RuntimeError.new
97
+ end
98
+
99
+ def close
100
+ @io.close
101
+ end
102
+ end
103
+ c.new
104
+ end
105
+
106
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
107
+ its(:tag_class) { should == :UNIVERSAL }
108
+ its(:infinite_length) { should == false }
109
+ its(:value) { should be_an_instance_of Array }
110
+ its(:to_der) { should == Resources.certificate }
111
+ end
112
+
113
+ context "PEM-encoded IO-like value that does not support rewinding" do
114
+ let(:io) do
115
+ c = Class.new do
116
+ def initialize
117
+ @io = Resources.certificate_pem_io
118
+ end
119
+
120
+ def read(len=nil, buf=nil)
121
+ @io.read(len, buf)
122
+ end
123
+
124
+ def seek(amount, whence=IO::SEEK_SET)
125
+ raise RuntimeError.new
126
+ end
127
+
128
+ def close
129
+ @io.close
130
+ end
131
+ end
132
+ c.new
133
+ end
134
+
135
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
136
+ its(:tag_class) { should == :UNIVERSAL }
137
+ its(:infinite_length) { should == false }
138
+ its(:value) { should be_an_instance_of Array }
139
+ its(:to_der) { should == Resources.certificate }
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "#decode_der" do
145
+ subject { decoder.decode_der(value) }
146
+
147
+ context "accepts regular DER-encoded values" do
148
+ let(:value) { "\x02\x01\x01" }
149
+ its(:tag) { should == Krypt::ASN1::INTEGER }
150
+ its(:tag_class) { should == :UNIVERSAL }
151
+ its(:value) { should == 1 }
152
+ its(:infinite_length) { should == false }
153
+ end
154
+
155
+ context "accepts IO" do
156
+ subject do
157
+ begin
158
+ decoder.decode_der(io)
159
+ ensure
160
+ io.close
161
+ end
162
+ end
163
+
164
+ context "regular DER-encoded IO" do
165
+ let(:io) { Resources.certificate_io }
166
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
167
+ its(:tag_class) { should == :UNIVERSAL }
168
+ its(:infinite_length) { should == false }
169
+ its(:value) { should be_an_instance_of Array }
170
+ its(:to_der) { should == Resources.certificate }
171
+ end
172
+
173
+ context "regular DER-encoded StringIO" do
174
+ let(:io) { StringIO.new(Resources.certificate) }
175
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
176
+ its(:tag_class) { should == :UNIVERSAL }
177
+ its(:infinite_length) { should == false }
178
+ its(:value) { should be_an_instance_of Array }
179
+ its(:to_der) { should == Resources.certificate }
180
+ end
181
+
182
+ context "DER-encoded IO-like value that does not support rewinding" do
183
+ let(:io) do
184
+ c = Class.new do
185
+ def initialize
186
+ @io = Resources.certificate_io
187
+ end
188
+
189
+ def read(len=nil, buf=nil)
190
+ @io.read(len, buf)
191
+ end
192
+
193
+ def seek(amount, whence=IO::SEEK_SET)
194
+ raise RuntimeError.new
195
+ end
196
+
197
+ def close
198
+ @io.close
199
+ end
200
+ end
201
+ c.new
202
+ end
203
+
204
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
205
+ its(:tag_class) { should == :UNIVERSAL }
206
+ its(:infinite_length) { should == false }
207
+ its(:value) { should be_an_instance_of Array }
208
+ its(:to_der) { should == Resources.certificate }
209
+ end
210
+ end
211
+ end
212
+
213
+ describe "#decode_pem" do
214
+ subject { decoder.decode_pem(value) }
215
+
216
+ context "accepts regular PEM-encoded values" do
217
+ let(:value) { create_pem_b64(Base64.encode64("\x02\x01\x01"), "INTEGER") }
218
+ its(:tag) { should == Krypt::ASN1::INTEGER }
219
+ its(:tag_class) { should == :UNIVERSAL }
220
+ its(:value) { should == 1 }
221
+ its(:infinite_length) { should == false }
222
+ end
223
+
224
+ context "accepts IO" do
225
+ subject do
226
+ begin
227
+ decoder.decode_pem(io)
228
+ ensure
229
+ io.close
230
+ end
231
+ end
232
+
233
+ context "regular PEM-encoded IO" do
234
+ let(:io) { Resources.certificate_pem_io }
235
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
236
+ its(:tag_class) { should == :UNIVERSAL }
237
+ its(:infinite_length) { should == false }
238
+ its(:value) { should be_an_instance_of Array }
239
+ its(:to_der) { should == Resources.certificate }
240
+ end
241
+
242
+ context "regular PEM-encoded StringIO" do
243
+ let(:io) { StringIO.new(Resources.certificate_pem) }
244
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
245
+ its(:tag_class) { should == :UNIVERSAL }
246
+ its(:infinite_length) { should == false }
247
+ its(:value) { should be_an_instance_of Array }
248
+ its(:to_der) { should == Resources.certificate }
249
+ end
250
+
251
+ context "PEM-encoded IO-like value that does not support rewinding" do
252
+ let(:io) do
253
+ c = Class.new do
254
+ def initialize
255
+ @io = Resources.certificate_pem_io
256
+ end
257
+
258
+ def read(len=nil, buf=nil)
259
+ @io.read(len, buf)
260
+ end
261
+
262
+ def seek(amount, whence=IO::SEEK_SET)
263
+ raise RuntimeError.new
264
+ end
265
+
266
+ def close
267
+ @io.close
268
+ end
269
+ end
270
+ c.new
271
+ end
272
+
273
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
274
+ its(:tag_class) { should == :UNIVERSAL }
275
+ its(:infinite_length) { should == false }
276
+ its(:value) { should be_an_instance_of Array }
277
+ its(:to_der) { should == Resources.certificate }
278
+ end
279
+ end
280
+ end
281
+ end
282
+
@@ -0,0 +1,637 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::Sequence do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::Sequence }
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::Sequence
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 SEQUENCE as Array' do
38
+ let(:value) { [s('hello'), i(42), s('world')] }
39
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
40
+ its(:tag_class) { should == :UNIVERSAL }
41
+ its(:value) { should == value }
42
+ its(:infinite_length) { should == false }
43
+ end
44
+
45
+ context 'accepts SEQUENCE OF as Array' do
46
+ let(:value) { [s('hello'), s(','), s('world')] }
47
+ its(:value) { should == value }
48
+ end
49
+
50
+ context 'accepts empty Array' do
51
+ let(:value) { [] }
52
+ its(:value) { should == [] }
53
+ end
54
+ end
55
+
56
+ context 'gets explicit tag number as the 2nd argument' do
57
+ let(:value) { [s('hello')] }
58
+ subject { klass.new(value, tag, :PRIVATE) }
59
+
60
+ context 'accepts default tag' do
61
+ let(:tag) { Krypt::ASN1::SEQUENCE }
62
+ its(:tag) { should == tag }
63
+ end
64
+
65
+ context 'accepts custom tag' do
66
+ let(:tag) { 14 }
67
+ its(:tag) { should == tag }
68
+ end
69
+ end
70
+
71
+ context 'gets tag class symbol as the 3rd argument' do
72
+ let(:value) { [s('hello')] }
73
+ subject { klass.new(value, Krypt::ASN1::SEQUENCE, tag_class) }
74
+
75
+ context 'accepts :UNIVERSAL' do
76
+ let(:tag_class) { :UNIVERSAL }
77
+ its(:tag_class) { should == tag_class }
78
+ end
79
+
80
+ context 'accepts :APPLICATION' do
81
+ let(:tag_class) { :APPLICATION }
82
+ its(:tag_class) { should == tag_class }
83
+ end
84
+
85
+ context 'accepts :CONTEXT_SPECIFIC' do
86
+ let(:tag_class) { :CONTEXT_SPECIFIC }
87
+ its(:tag_class) { should == tag_class }
88
+ end
89
+
90
+ context 'accepts :PRIVATE' do
91
+ let(:tag_class) { :PRIVATE }
92
+ its(:tag_class) { should == tag_class }
93
+ end
94
+
95
+ context 'accepts :IMPLICIT' do
96
+ let(:tag_class) { :IMPLICIT }
97
+ its(:tag_class) { should == tag_class }
98
+ end
99
+
100
+ context 'accepts :EXPLICIT' do
101
+ let(:tag_class) { :EXPLICIT }
102
+ its(:tag_class) { should == tag_class }
103
+ end
104
+ end
105
+
106
+ context 'when the 2nd argument is given but 3rd argument is omitted' do
107
+ subject { klass.new([s('hello')], Krypt::ASN1::SEQUENCE) }
108
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
109
+ end
110
+ end
111
+
112
+ describe 'accessors' do
113
+ describe '#value' do
114
+ subject { o = klass.new(nil); o.value = value; o }
115
+
116
+ context 'accepts SEQUENCE as Array' do
117
+ let(:value) { [s('hello'), i(42), s('world')] }
118
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
119
+ its(:tag_class) { should == :UNIVERSAL }
120
+ its(:value) { should == value }
121
+ its(:infinite_length) { should == false }
122
+ end
123
+
124
+ context 'accepts SEQUENCE OF as Array' do
125
+ let(:value) { [s('hello'), s(','), s('world')] }
126
+ its(:value) { should == value }
127
+ end
128
+
129
+ context 'accepts empty Array' do
130
+ let(:value) { [] }
131
+ its(:value) { should == [] }
132
+ end
133
+ end
134
+
135
+ describe '#tag' do
136
+ subject { o = klass.new(nil); o.tag = tag; o }
137
+
138
+ context 'accepts default tag' do
139
+ let(:tag) { Krypt::ASN1::SEQUENCE }
140
+ its(:tag) { should == tag }
141
+ end
142
+
143
+ context 'accepts custom tag' do
144
+ let(:tag) { 14 }
145
+ its(:tag) { should == tag }
146
+ end
147
+ end
148
+
149
+ describe '#tag_class' do
150
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
151
+
152
+ context 'accepts :UNIVERSAL' do
153
+ let(:tag_class) { :UNIVERSAL }
154
+ its(:tag_class) { should == tag_class }
155
+ end
156
+
157
+ context 'accepts :APPLICATION' do
158
+ let(:tag_class) { :APPLICATION }
159
+ its(:tag_class) { should == tag_class }
160
+ end
161
+
162
+ context 'accepts :CONTEXT_SPECIFIC' do
163
+ let(:tag_class) { :CONTEXT_SPECIFIC }
164
+ its(:tag_class) { should == tag_class }
165
+ end
166
+
167
+ context 'accepts :PRIVATE' do
168
+ let(:tag_class) { :PRIVATE }
169
+ its(:tag_class) { should == tag_class }
170
+ end
171
+
172
+ context 'accepts :IMPLICIT' do
173
+ let(:tag_class) { :IMPLICIT }
174
+ its(:tag_class) { should == tag_class }
175
+ end
176
+
177
+ context 'accepts :EXPLICIT' do
178
+ let(:tag_class) { :EXPLICIT }
179
+ its(:tag_class) { should == tag_class }
180
+ end
181
+ end
182
+
183
+ describe '#infinite_length' do
184
+ subject { o = klass.new(nil); o.infinite_length = infinite_length; o }
185
+
186
+ context 'accepts true' do
187
+ let(:infinite_length) { true }
188
+ its(:infinite_length) { should == true }
189
+ end
190
+
191
+ context 'accepts false' do
192
+ let(:infinite_length) { false }
193
+ its(:infinite_length) { should == false }
194
+ end
195
+
196
+ context 'accepts nil as false' do
197
+ let(:infinite_length) { nil }
198
+ its(:infinite_length) { should == false }
199
+ end
200
+
201
+ context 'accepts non boolean as true' do
202
+ let(:infinite_length) { Object.new }
203
+ its(:infinite_length) { should == true }
204
+ end
205
+ end
206
+ end
207
+
208
+ describe '#to_der' do
209
+ context 'encodes a given value' do
210
+ subject { klass.new(value).to_der }
211
+
212
+ context 'SEQUENCE' do
213
+ let(:value) { [s('hello'), i(42), s('world')] }
214
+ it { should == "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
215
+ end
216
+
217
+ context 'SEQUENCE OF OctetString' do
218
+ let(:value) { [s(''), s(''), s('')] }
219
+ it { should == "\x30\x06\x04\x00\x04\x00\x04\x00" }
220
+ end
221
+
222
+ context 'SEQUENCE OF Integer' do
223
+ let(:value) { [i(-1), i(0), i(1)] }
224
+ it { should == "\x30\x09\x02\x01\xFF\x02\x01\x00\x02\x01\x01" }
225
+ end
226
+
227
+ context '(empty)' do
228
+ let(:value) { [] }
229
+ it { should == "\x30\x00" }
230
+ end
231
+
232
+ context '1000 elements' do
233
+ let(:value) { [i(0)] * 1000 }
234
+ it { should == "\x30\x82\x0B\xB8" + "\x02\x01\x00" * 1000 }
235
+ end
236
+
237
+ context 'responds to :each' do
238
+ let(:value) {
239
+ o = Object.new # TODO: Discuss - BasicObject does not support respond_to?
240
+ def o.each
241
+ yield Krypt::ASN1::OctetString.new('hello')
242
+ yield Krypt::ASN1::Integer.new(42)
243
+ yield Krypt::ASN1::OctetString.new('world')
244
+ end
245
+ o
246
+ }
247
+ it { should == "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
248
+ end
249
+
250
+ context "keeps the ordering of the value in the encoding" do
251
+ context "definite length Array" do
252
+ let(:value) { [i(1), s("a"), Krypt::ASN1::Boolean.new(true)] }
253
+ it { should == "\x30\x09\x02\x01\x01\x04\x01a\x01\x01\xFF" }
254
+ end
255
+
256
+ context "definite length Enumerable" do
257
+ let(:value) {
258
+ o = Object.new
259
+ def o.each
260
+ yield Krypt::ASN1::Integer.new(1)
261
+ yield Krypt::ASN1::OctetString.new("a")
262
+ yield Krypt::ASN1::Boolean.new(true)
263
+ end
264
+ o
265
+ }
266
+ it { should == "\x30\x09\x02\x01\x01\x04\x01a\x01\x01\xFF" }
267
+ end
268
+
269
+ context "infinite length" do
270
+ subject { o = klass.new(value); o.infinite_length = true; o.to_der }
271
+
272
+ context "infinite length Array" do
273
+ let(:value) { [i(1), s("a"), Krypt::ASN1::Boolean.new(true)] }
274
+ it { should == "\x30\x80\x02\x01\x01\x04\x01a\x01\x01\xFF\x00\x00" }
275
+ end
276
+
277
+ context "infinite length Enumerable" do
278
+ let(:value) {
279
+ o = Object.new
280
+ def o.each
281
+ yield Krypt::ASN1::Integer.new(1)
282
+ yield Krypt::ASN1::OctetString.new("a")
283
+ yield Krypt::ASN1::Boolean.new(true)
284
+ end
285
+ o
286
+ }
287
+ it { should == "\x30\x80\x02\x01\x01\x04\x01a\x01\x01\xFF\x00\x00" }
288
+ end
289
+ end
290
+ end
291
+
292
+ context 'nil' do
293
+ let(:value) { nil }
294
+ it { -> { subject }.should raise_error asn1error }
295
+ end
296
+
297
+ context 'does not respond to :each' do
298
+ let(:value) { '123' }
299
+ it { -> { subject }.should raise_error asn1error }
300
+ end
301
+ end
302
+
303
+ context 'encodes tag number' do
304
+ let(:value) { [s(''), s(''), s('')] }
305
+ subject { klass.new(value, tag, :PRIVATE).to_der }
306
+
307
+ context 'default tag' do
308
+ let(:tag) { Krypt::ASN1::SEQUENCE }
309
+ it { should == "\xF0\x06\x04\x00\x04\x00\x04\x00" }
310
+ end
311
+
312
+ context 'custom tag' do
313
+ let(:tag) { 14 }
314
+ it { should == "\xEE\x06\x04\x00\x04\x00\x04\x00" }
315
+ end
316
+
317
+ context 'nil' do
318
+ let(:tag) { nil }
319
+ it { -> { subject }.should raise_error asn1error }
320
+ end
321
+ end
322
+
323
+ context 'encodes tag class' do
324
+ let(:value) { [s(''), s(''), s('')] }
325
+ subject { klass.new(value, Krypt::ASN1::SEQUENCE, tag_class).to_der }
326
+
327
+ context 'UNIVERSAL' do
328
+ let(:tag_class) { :UNIVERSAL }
329
+ it { should == "\x30\x06\x04\x00\x04\x00\x04\x00" }
330
+ end
331
+
332
+ context 'APPLICATION' do
333
+ let(:tag_class) { :APPLICATION }
334
+ it { should == "\x70\x06\x04\x00\x04\x00\x04\x00" }
335
+ end
336
+
337
+ context 'CONTEXT_SPECIFIC' do
338
+ let(:tag_class) { :CONTEXT_SPECIFIC }
339
+ it { should == "\xB0\x06\x04\x00\x04\x00\x04\x00" }
340
+ end
341
+
342
+ context 'PRIVATE' do
343
+ let(:tag_class) { :PRIVATE }
344
+ it { should == "\xF0\x06\x04\x00\x04\x00\x04\x00" }
345
+ end
346
+
347
+ context 'IMPLICIT' do
348
+ let(:tag_class) { :IMPLICIT }
349
+ it { should == "\xB0\x06\x04\x00\x04\x00\x04\x00" }
350
+ end
351
+
352
+ context 'EXPLICIT' do
353
+ let(:tag_class) { :EXPLICIT }
354
+ it { should == "\xB0\x08\x30\x06\x04\x00\x04\x00\x04\x00" }
355
+ end
356
+
357
+ context nil do
358
+ let(:tag_class) { nil }
359
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
360
+ end
361
+
362
+ context :no_such_class do
363
+ let(:tag_class) { :no_such_class }
364
+ it { -> { subject }.should raise_error asn1error }
365
+ end
366
+ end
367
+
368
+ context 'encodes indefinite length packets' do
369
+ subject {
370
+ o = klass.new(nil, Krypt::ASN1::SEQUENCE, :UNIVERSAL)
371
+ o.value = value if defined? value
372
+ o.infinite_length = true
373
+ o
374
+ }
375
+
376
+ context 'with EndOfContents' do
377
+ let(:value) { [s('hello'), i(42), s('world'), eoc] }
378
+ let(:infinite_length) { true }
379
+ its(:to_der) { should == "\x30\x80\x04\x05hello\x02\x01\x2A\x04\x05world\x00\x00" }
380
+ end
381
+ end
382
+
383
+ context 'encodes values set via accessors' do
384
+ subject {
385
+ o = klass.new(nil)
386
+ o.value = value if defined? value
387
+ o.tag = tag if defined? tag
388
+ o.tag_class = tag_class if defined? tag_class
389
+ o.to_der
390
+ }
391
+
392
+ context 'value: SEQUENCE' do
393
+ let(:value) { [s('hello'), i(42), s('world')] }
394
+ it { should == "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
395
+ end
396
+
397
+ context 'custom tag' do
398
+ let(:value) { [s('hello'), i(42), s('world')] }
399
+ let(:tag) { 14 }
400
+ let(:tag_class) { :PRIVATE }
401
+ it { should == "\xEE\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
402
+ end
403
+
404
+ context 'tag_class' do
405
+ let(:value) { [s('hello'), i(42), s('world')] }
406
+ let(:tag_class) { :APPLICATION }
407
+ it { should == "\x70\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
408
+ end
409
+ end
410
+
411
+ context "encodes infinite length values" do
412
+ subject do
413
+ asn1 = klass.new(value)
414
+ asn1.infinite_length = true
415
+ asn1.to_der
416
+ end
417
+
418
+ context "with explicit EOC" do
419
+ let(:value) { [
420
+ mod::Integer.new(1),
421
+ mod::Boolean.new(true),
422
+ mod::EndOfContents.new
423
+ ] }
424
+ it { subject.should == "\x30\x80\x02\x01\x01\x01\x01\xFF\x00\x00" }
425
+ end
426
+
427
+ context "without explicit EOC" do
428
+ let(:value) { [
429
+ mod::Integer.new(1),
430
+ mod::Boolean.new(true),
431
+ ] }
432
+ it { subject.should == "\x30\x80\x02\x01\x01\x01\x01\xFF\x00\x00" }
433
+ end
434
+ end
435
+ end
436
+
437
+ describe '#encode_to' do
438
+ context 'encodes to an IO' do
439
+ subject { klass.new(value).encode_to(io); io }
440
+
441
+ context "StringIO" do
442
+ let(:value) { [s(''), s(''), s('')] }
443
+ let(:io) { string_io_object }
444
+ its(:written_bytes) { should == "\x30\x06\x04\x00\x04\x00\x04\x00" }
445
+ end
446
+
447
+ context "Object responds to :write" do
448
+ let(:value) { [s(''), s(''), s('')] }
449
+ let(:io) { writable_object }
450
+ its(:written_bytes) { should == "\x30\x06\x04\x00\x04\x00\x04\x00" }
451
+ end
452
+
453
+ context "raise IO error transparently" do
454
+ let(:value) { [s(''), s(''), s('')] }
455
+ let(:io) { io_error_object }
456
+ it { -> { subject }.should raise_error asn1error }
457
+ end
458
+ end
459
+
460
+ it 'returns self' do
461
+ obj = klass.new([s(''), s(''), s('')])
462
+ obj.encode_to(string_io_object).should == obj
463
+ end
464
+ end
465
+
466
+ describe '#each' do
467
+ subject { yielded_value_from_each(klass.new(value)) }
468
+
469
+ context "yields each value in its order" do
470
+ let(:value) { [s('hello'), i(42), s('world')] }
471
+ it { should == value }
472
+ end
473
+
474
+ context "yields nothing for empty value" do
475
+ let(:value) { [] }
476
+ it { should == value }
477
+ end
478
+
479
+ it "is Enumerable via each" do
480
+ value = [s('hello'), i(42), s('world')]
481
+ klass.new(value).map { |e| e.value }.should == ['hello', 42, 'world']
482
+ end
483
+
484
+ it "returns Enumerator for blockless call" do
485
+ value = [s('hello'), i(42), s('world')]
486
+ klass.new(value).each.next.value.should == 'hello'
487
+ end
488
+
489
+ it "yields each value for an Enumerable" do
490
+ o = Object.new
491
+ def o.each
492
+ yield Krypt::ASN1::Integer.new(1)
493
+ yield Krypt::ASN1::Integer.new(2)
494
+ yield Krypt::ASN1::Integer.new(3)
495
+ end
496
+ klass.new(o).map { |e| e.value }.should == [1, 2, 3]
497
+ end
498
+ end
499
+
500
+ describe 'extracted from ASN1.decode' do
501
+ subject { decoder.decode(der) }
502
+
503
+ context 'extracted value' do
504
+ context 'SEQUENCE' do
505
+ let(:der) { "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
506
+ its(:class) { should == klass }
507
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
508
+ it 'contains decoded value' do
509
+ value = subject.value
510
+ value.size.should == 3
511
+ value[0].value == 'hello'
512
+ value[1].value == 42
513
+ value[2].value == 'world'
514
+ end
515
+ end
516
+
517
+ context 'SEQUENCE OF Integer' do
518
+ let(:der) { "\x30\x0C\x02\x04\xFF\xFF\xFF\xFF\x02\x01\x00\x02\x01\x01" }
519
+ its(:class) { should == klass }
520
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
521
+ it 'contains decoded value' do
522
+ value = subject.value
523
+ value.size.should == 3
524
+ value[0].value == -1
525
+ value[1].value == 0
526
+ value[2].value == 1
527
+ end
528
+ end
529
+
530
+ context '(empty)' do
531
+ let(:der) { "\x30\x00" }
532
+ its(:class) { should == klass }
533
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
534
+ its(:value) { should == [] }
535
+ end
536
+
537
+ context '1000 elements' do
538
+ let(:der) { "\x30\x82\x0B\xB8" + "\x02\x01\x00" * 1000 }
539
+ its(:class) { should == klass }
540
+ its(:tag) { should == Krypt::ASN1::SEQUENCE }
541
+ it 'contains decoded value' do
542
+ value = subject.value
543
+ value.size == 1000
544
+ value.all? { |v| v.value == 0 }.should be_true
545
+ end
546
+ end
547
+ end
548
+
549
+ context 'extracted tag class' do
550
+ context 'UNIVERSAL' do
551
+ let(:der) { "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
552
+ its(:tag_class) { should == :UNIVERSAL }
553
+ end
554
+
555
+ context 'APPLICATION' do
556
+ let(:der) { "\x70\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
557
+ its(:tag_class) { should == :APPLICATION }
558
+ end
559
+
560
+ context 'CONTEXT_SPECIFIC' do
561
+ let(:der) { "\xB0\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
562
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
563
+ end
564
+
565
+ context 'PRIVATE' do
566
+ let(:der) { "\xF0\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
567
+ its(:tag_class) { should == :PRIVATE }
568
+ end
569
+
570
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
571
+ let(:der) { "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
572
+ it do
573
+ subject.tag_class = :IMPLICIT
574
+ subject.to_der.should == "\xB0\x11\x04\x05hello\x02\x01\x2A\x04\x05world"
575
+ end
576
+ end
577
+
578
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
579
+ let(:der) { "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
580
+ it do
581
+ subject.tag_class = :EXPLICIT
582
+ subject.tag = 0
583
+ subject.to_der.should == "\xA0\x13\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world"
584
+ end
585
+ end
586
+ end
587
+
588
+ context 'extracted infinite_length' do
589
+ context 'definite encoding' do
590
+ let(:der) { "\x30\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
591
+ its(:infinite_length) { should be_false }
592
+ end
593
+
594
+ context 'indefinite encoding' do
595
+ let(:der) { "\x30\x80\x04\x05hello\x02\x01\x2A\x04\x05world\x00\x00" }
596
+ its(:infinite_length) { should be_true }
597
+ it "drops EndOfContents as last value" do
598
+ subject.value.size.should == 3
599
+ subject.value.any? { |o| o.instance_of? Krypt::ASN1::EndOfContents }.should be_false
600
+ end
601
+ end
602
+ end
603
+
604
+ context "preserves the ordering present in the encoding" do
605
+ context "definite length" do
606
+ context "when immediately re-encoding" do
607
+ let(:der) { "\x30\x08\x05\x00\x04\x01a\x02\x01\x01" }
608
+ its(:to_der) { should == der }
609
+ end
610
+
611
+ context "when changing one of the values" do
612
+ let(:der) { "\x30\x08\x05\x00\x04\x01a\x02\x01\x01" }
613
+ it do
614
+ subject.value[2].value = 5
615
+ subject.to_der.should == "\x30\x08\x05\x00\x04\x01a\x02\x01\x05"
616
+ end
617
+ end
618
+ end
619
+
620
+ context "infinite length" do
621
+ context "when immediately re-encoding" do
622
+ let(:der) { "\x30\x80\x05\x00\x04\x01a\x02\x01\x01\x00\x00" }
623
+ its(:to_der) { should == der }
624
+ end
625
+
626
+ context "when changing one of the values" do
627
+ let(:der) { "\x30\x80\x05\x00\x04\x01a\x02\x01\x01\x00\x00" }
628
+ it do
629
+ subject.value[2].value = 5
630
+ subject.to_der.should == "\x30\x80\x05\x00\x04\x01a\x02\x01\x05\x00\x00"
631
+ end
632
+ end
633
+ end
634
+ end
635
+ end
636
+ end
637
+