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,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
+