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,69 @@
1
+ module Krypt
2
+ class HMAC
3
+ include Krypt::Helper::XOR
4
+
5
+ def initialize(digest, key)
6
+ @digest = digest
7
+ @key = process_key(key)
8
+
9
+ # hash ipad
10
+ hash_pad(0x36)
11
+ end
12
+
13
+ def update(data)
14
+ @digest << data
15
+ end
16
+ alias << update
17
+
18
+ def digest
19
+ inner_digest = @digest.digest
20
+ # hash opad
21
+ hash_pad(0x5c)
22
+ @digest << inner_digest
23
+ @digest.digest
24
+ end
25
+
26
+ def hexdigest
27
+ Krypt::Hex.encode(digest)
28
+ end
29
+
30
+ class << self
31
+
32
+ def digest(md, key, data)
33
+ hmac = self.new(md, key)
34
+ hmac << data
35
+ hmac.digest
36
+ end
37
+
38
+ def hexdigest(md, key, data)
39
+ Krypt::Hex.encode(digest(md, key, data))
40
+ end
41
+
42
+ end
43
+
44
+ private
45
+
46
+ def process_key(key)
47
+ block_len = @digest.block_length
48
+
49
+ if key.size > block_len
50
+ key = @digest.digest(key)
51
+ end
52
+
53
+ if key.size < block_len
54
+ new_key = key.dup.tap do |new_key|
55
+ (block_len - key.size).times { new_key << 0 }
56
+ end
57
+ else
58
+ key
59
+ end
60
+ end
61
+
62
+ def hash_pad(pad_char)
63
+ @digest << String.new.tap do |s|
64
+ @key.each_byte { |b| s << (pad_char ^ b) }
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1 @@
1
+ require_relative 'pkcs5/pbkdf2'
@@ -0,0 +1,41 @@
1
+ module Krypt
2
+ class PBKDF2
3
+ include Krypt::Helper::XOR
4
+
5
+ MAX_FACTOR = (2 ** 32) - 1
6
+
7
+ def initialize(digest)
8
+ @digest = digest
9
+ @block_size = digest.digest_length
10
+ end
11
+
12
+ def generate(pwd, salt, iter, outlen)
13
+ raise "outlen too large" if outlen > MAX_FACTOR * @block_size
14
+
15
+ @digest.reset
16
+ num_blocks = (outlen.to_f / @block_size).ceil
17
+ # enforces ASCII-8BIT
18
+ String.new.tap do |result|
19
+ 1.upto(num_blocks) { |i| result << f(pwd, salt, iter, i) }
20
+ end.slice(0, outlen)
21
+ end
22
+
23
+ def generate_hex(pwd, salt, iter, outlen)
24
+ Krypt::Hex.encode(generate(pwd, salt, iter, outlen))
25
+ end
26
+
27
+ private
28
+
29
+ def f(pwd, salt, iter, i)
30
+ u = salt + [i].pack("L>")
31
+ ("\0" * @block_size).force_encoding(Encoding::BINARY).tap do |result|
32
+ 1.upto(iter) do
33
+ u = Krypt::HMAC.digest(@digest, pwd, u)
34
+ xor!(result, u)
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+
@@ -0,0 +1,35 @@
1
+ module Krypt::Provider
2
+
3
+ PROVIDERS = {}
4
+ PROVIDER_LIST = []
5
+
6
+ class AlreadyExistsError < Krypt::Error; end
7
+
8
+ class ServiceNotAvailableError < Krypt::Error; end
9
+
10
+ module_function
11
+
12
+ def register(name, provider)
13
+ raise AlreadyExistsError.new("There already is a Provider named #{name}") if PROVIDERS.has_key?(name)
14
+ PROVIDERS[name] = provider
15
+ PROVIDER_LIST << name
16
+ end
17
+
18
+ def by_name(name)
19
+ PROVIDERS[name]
20
+ end
21
+
22
+ def remove(name)
23
+ PROVIDERS.delete(name)
24
+ PROVIDER_LIST.delete(name)
25
+ end
26
+
27
+ def new_service(klass, *args)
28
+ PROVIDER_LIST.reverse.each do |name|
29
+ service = PROVIDERS[name].new_service(klass, *args)
30
+ return service if service
31
+ end
32
+ raise ServiceNotAvailableError.new("The requested service is not available")
33
+ end
34
+
35
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'x509/common'
2
+ require_relative 'x509/certificate'
3
+ require_relative 'x509/crl'
@@ -0,0 +1,36 @@
1
+ module Krypt
2
+ module X509
3
+
4
+ class Certificate
5
+ include ASN1::Template::Sequence
6
+
7
+ class SubjectPublicKeyInfo
8
+ include ASN1::Template::Sequence
9
+
10
+ asn1_template :algorithm, ASN1::AlgorithmIdentifier
11
+ asn1_bit_string :subject_pkey
12
+ end
13
+
14
+ class TBSCertificate
15
+ include ASN1::Template::Sequence
16
+
17
+ asn1_integer :version, tag: 0, tagging: :EXPLICIT, default: 0
18
+ asn1_integer :serial
19
+ asn1_template :algorithm, ASN1::AlgorithmIdentifier
20
+ asn1_template :issuer, ASN1::DistinguishedName
21
+ asn1_template :validity, X509::Validity
22
+ asn1_template :subject, ASN1::DistinguishedName
23
+ asn1_template :subject_pkey, SubjectPublicKeyInfo
24
+ asn1_bit_string :issuer_id, tag: 1, tagging: :IMPLICIT, optional: true
25
+ asn1_bit_string :subject_id, tag: 2, tagging: :IMPLICIT, optional: true
26
+ asn1_sequence_of :extensions, X509::Extension, tag: 3, tagging: :EXPLICIT, optional: true
27
+ end
28
+
29
+ asn1_template :tbs_cert, TBSCertificate
30
+ asn1_template :algorithm, ASN1::AlgorithmIdentifier
31
+ asn1_bit_string :signature
32
+ end
33
+
34
+ end
35
+ end
36
+
@@ -0,0 +1,41 @@
1
+ module Krypt
2
+ module X509
3
+
4
+ class Extension
5
+ include ASN1::Template::Sequence
6
+
7
+ asn1_object_id :id
8
+ asn1_boolean :critical, default: false
9
+ asn1_octet_string :value
10
+ end
11
+
12
+ class Attribute
13
+ include ASN1::Template::Sequence
14
+
15
+ asn1_object_id :type
16
+ asn1_set_of :value, ASN1::ASN1Data
17
+ end
18
+
19
+ class IssuerSerialNumber
20
+ include Krypt::ASN1::Template::Sequence
21
+
22
+ asn1_template :issuer, ASN1::DistinguishedName
23
+ asn1_integer :serial
24
+ end
25
+
26
+ class Time
27
+ include ASN1::Template::Choice
28
+
29
+ asn1_utc_time
30
+ asn1_generalized_time
31
+ end
32
+
33
+ class Validity
34
+ include ASN1::Template::Sequence
35
+
36
+ asn1_template :not_before, X509::Time
37
+ asn1_template :not_after, X509::Time
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ module Krypt
2
+ module X509
3
+
4
+ class CRL
5
+ include ASN1::Template::Sequence
6
+
7
+ class RevokedCertificates
8
+ include ASN1::Template::Sequence
9
+
10
+ asn1_integer :serial_number
11
+ asn1_template :revocation_date, X509::Time
12
+ asn1_template :crl_entry_extensions, X509::Extension
13
+ end
14
+
15
+ class TBSCertList
16
+ include ASN1::Template::Sequence
17
+
18
+ asn1_integer :version, default: 1
19
+ asn1_template :signature_algorithm, ASN1::AlgorithmIdentifier
20
+ asn1_template :issuer, ASN1::DistinguishedName
21
+ asn1_template :this_update, X509::Time
22
+ asn1_template :next_update, X509::Time
23
+ asn1_sequence_of :revoked_certificates, RevokedCertificates, optional: true
24
+ asn1_template :extensions, X509::Extension, tag: 0, tagging: :EXPLICIT, optional: true
25
+ end
26
+
27
+ asn1_template :tbs_cert_list, TBSCertList
28
+ asn1_template :signature_algorithm, ASN1::AlgorithmIdentifier
29
+ asn1_bit_string :signature
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ unless Kernel.respond_to? :private_constant
2
+ module Kernel
3
+ def private_constant(*)
4
+ # TODO delete when sufficiently supported
5
+ nil
6
+ end
7
+ end
8
+ end
9
+
10
+ module Krypt
11
+ module Helper
12
+
13
+ module XOR
14
+ def xor(s1, s2)
15
+ String.new.tap do |result|
16
+ s1.bytes.each_with_index do |b, i|
17
+ result << (b ^ s2.getbyte(i))
18
+ end
19
+ end
20
+ end
21
+
22
+ def xor!(recv, other)
23
+ recv.bytes.each_with_index do |b, i|
24
+ recv.setbyte(i, b ^ other.getbyte(i))
25
+ end
26
+ recv
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+
@@ -0,0 +1,85 @@
1
+ module Krypt
2
+ class KryptError < StandardError; end
3
+
4
+ module ASN1
5
+ class ASN1Error < KryptError; end
6
+ class ParseError < ASN1Error; end
7
+ class SerializeError < ASN1Error; end
8
+
9
+ END_OF_CONTENTS = 0
10
+ BOOLEAN = 1
11
+ ...
12
+ BMP_STRING = 30
13
+
14
+ UNIVERSAL_TAG_NAME = ["END_OF_CONTENTS", "BOOLEAN", ... ]
15
+
16
+ def self.decode(str_or_file_or_readable)
17
+ end
18
+
19
+ class ASN1Data
20
+ attr_accessor :tag, :tag_class, :value
21
+ attr_reader :infinite_length
22
+
23
+ def initialize(value, tag, tag_class); end
24
+ def to_der; end
25
+ def encode_to(io); end #=> self
26
+ end
27
+
28
+ class Primitive < ASN1Data
29
+ end
30
+
31
+ class Constructive < ASN1Data
32
+ attr_writer :infinite_length # ?
33
+ def each; end
34
+ end
35
+
36
+ class EndOfContents < Primitive; end
37
+ class Boolean < Primitive; end
38
+ class Integer < Primitive; end
39
+ class Enumerated < Primitive; end
40
+ class BitString < Primitive; end
41
+ class OctetString < Primitive; end
42
+ class UTF8String < Primitive; end
43
+ class NumericString < Primitive; end
44
+ class PrintableString < Primitive; end
45
+ class T61String < Primitive; end
46
+ class VideotexString < Primitive; end
47
+ class IA5String < Primitive; end
48
+ class GraphicString < Primitive; end
49
+ class ISO64String < Primitive; end
50
+ class GeneralString < Primitive; end
51
+ class UniversalString < Primitive; end
52
+ class BMPString < Primitive; end
53
+ class Null < Primitive; end
54
+ class ObjectId < Primitive; end
55
+ class UTCTime < Primitive; end
56
+ class GeneralizedTime < Primitive; end
57
+
58
+ class Sequence < Constructive; end
59
+ class Set < Constructive; end
60
+
61
+ class Parser
62
+ def next(io); end #=> Header
63
+ end
64
+
65
+ class Header
66
+ attr_reader :tag, :tag_class, :length, :header_length
67
+ def constructed?; end
68
+ def infinite?; end
69
+
70
+ def bytes; end #=> String
71
+ def encode_to(io); end #=> self
72
+
73
+ def skip_value; end
74
+ def value; end
75
+ def value_io; end # get value (V of TLV) stream
76
+
77
+ def to_s; end
78
+ end
79
+
80
+ class Instream
81
+ def read(len = nil, buf = nil); end
82
+ def seek(offset, whence = SEEK_SET); end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,475 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::BitString do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::BitString }
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::BitString
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 _B(bin_encode)
34
+ [bin_encode.reverse].pack('b*').reverse
35
+ end
36
+
37
+ describe '#new' do
38
+ context 'gets value for construct' do
39
+ subject { klass.new(value) }
40
+
41
+ context 'accepts binary packed 01010101 := "\x55"' do
42
+ let(:value) { _B('01010101') }
43
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
44
+ its(:tag_class) { should == :UNIVERSAL }
45
+ its(:value) { should == value }
46
+ its(:infinite_length) { should == false }
47
+ end
48
+
49
+ context 'accepts (empty)' do
50
+ let(:value) { '' }
51
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
52
+ its(:tag_class) { should == :UNIVERSAL }
53
+ its(:value) { should == '' }
54
+ its(:infinite_length) { should == false }
55
+ end
56
+ end
57
+
58
+ context 'gets explicit tag number as the 2nd argument' do
59
+ subject { klass.new(_B('01010101'), tag, :PRIVATE) }
60
+
61
+ context 'accepts default tag' do
62
+ let(:tag) { Krypt::ASN1::BIT_STRING }
63
+ its(:tag) { should == tag }
64
+ end
65
+
66
+ context 'accepts custom tag' do
67
+ let(:tag) { 14 }
68
+ its(:tag) { should == tag }
69
+ end
70
+ end
71
+
72
+ context 'gets tag class symbol as the 3rd argument' do
73
+ subject { klass.new(_B('01010101'), Krypt::ASN1::BIT_STRING, 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(_B('01010101'), Krypt::ASN1::BIT_STRING) }
108
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
109
+ end
110
+
111
+ context 'sets unused_bits to 0' do
112
+ subject { klass.new(nil) }
113
+ its(:unused_bits) { should == 0 }
114
+ end
115
+ end
116
+
117
+ describe 'accessors' do
118
+ describe '#value' do
119
+ subject { o = klass.new(nil); o.value = value; o }
120
+
121
+ context 'accepts binary packed 01010101 := "\x55"' do
122
+ let(:value) { _B('01010101') }
123
+ its(:value) { should == value }
124
+ end
125
+
126
+ context 'accepts (empty)' do
127
+ let(:value) { '' }
128
+ its(:value) { should == '' }
129
+ end
130
+ end
131
+
132
+ describe '#tag' do
133
+ subject { o = klass.new(nil); o.tag = tag; o }
134
+
135
+ context 'accepts default tag' do
136
+ let(:tag) { Krypt::ASN1::BIT_STRING }
137
+ its(:tag) { should == tag }
138
+ end
139
+
140
+ context 'accepts custom tag' do
141
+ let(:tag) { 14 }
142
+ its(:tag) { should == tag }
143
+ end
144
+ end
145
+
146
+ describe '#tag_class' do
147
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
148
+
149
+ context 'accepts :UNIVERSAL' do
150
+ let(:tag_class) { :UNIVERSAL }
151
+ its(:tag_class) { should == tag_class }
152
+ end
153
+
154
+ context 'accepts :APPLICATION' do
155
+ let(:tag_class) { :APPLICATION }
156
+ its(:tag_class) { should == tag_class }
157
+ end
158
+
159
+ context 'accepts :CONTEXT_SPECIFIC' do
160
+ let(:tag_class) { :CONTEXT_SPECIFIC }
161
+ its(:tag_class) { should == tag_class }
162
+ end
163
+
164
+ context 'accepts :PRIVATE' do
165
+ let(:tag_class) { :PRIVATE }
166
+ its(:tag_class) { should == tag_class }
167
+ end
168
+
169
+ context 'accepts :IMPLICIT' do
170
+ let(:tag_class) { :IMPLICIT }
171
+ its(:tag_class) { should == tag_class }
172
+ end
173
+
174
+ context 'accepts :EXPLICIT' do
175
+ let(:tag_class) { :EXPLICIT }
176
+ its(:tag_class) { should == tag_class }
177
+ end
178
+ end
179
+ end
180
+
181
+ describe '#to_der' do
182
+ context 'encodes a given value' do
183
+ subject { klass.new(value).to_der }
184
+
185
+ context '01010101' do
186
+ let(:value) { _B('01010101') }
187
+ it { should == "\x03\x02\x00\x55" }
188
+ end
189
+
190
+ context '010101010' do
191
+ let(:value) { _B('010101010') }
192
+ it { should == "\x03\x03\x00\x00\xAA" }
193
+ end
194
+
195
+ context '(empty)' do
196
+ let(:value) { '' }
197
+ it { should == "\x03\x01\x00" }
198
+ end
199
+
200
+ context '999 octets' do
201
+ let(:value) { _B('1' * 8 * 999) }
202
+ it { should == "\x03\x82\x03\xE8\x00" + "\xFF" * 999 }
203
+ end
204
+
205
+ context '1000 octets' do
206
+ let(:value) { _B('0' * 8 * 1000) }
207
+ it { should == "\x03\x82\x03\xE9\x00" + "\x00" * 1000 }
208
+ end
209
+
210
+ context '1001 octets' do
211
+ let(:value) { _B('1' * 8 * 1001) }
212
+ it { should == "\x03\x82\x03\xEA\x00" + "\xFF" * 1001 }
213
+ end
214
+
215
+ context 'nil' do
216
+ let(:value) { nil }
217
+ it { -> { subject }.should raise_error asn1error }
218
+ end
219
+ end
220
+
221
+ context 'encodes tag number' do
222
+ subject { klass.new(_B('01010101'), tag, :PRIVATE).to_der }
223
+
224
+ context 'default tag' do
225
+ let(:tag) { Krypt::ASN1::BIT_STRING }
226
+ it { should == "\xC3\x02\x00\x55" }
227
+ end
228
+
229
+ context 'custom tag' do
230
+ let(:tag) { 14 }
231
+ it { should == "\xCE\x02\x00\x55" }
232
+ end
233
+
234
+ context 'nil' do
235
+ let(:tag) { nil }
236
+ it { -> { subject }.should raise_error asn1error }
237
+ end
238
+ end
239
+
240
+ context 'encodes tag class' do
241
+ subject { klass.new(_B('01010101'), Krypt::ASN1::BIT_STRING, tag_class).to_der }
242
+
243
+ context 'UNIVERSAL' do
244
+ let(:tag_class) { :UNIVERSAL }
245
+ it { should == "\x03\x02\x00\x55" }
246
+ end
247
+
248
+ context 'APPLICATION' do
249
+ let(:tag_class) { :APPLICATION }
250
+ it { should == "\x43\x02\x00\x55" }
251
+ end
252
+
253
+ context 'CONTEXT_SPECIFIC' do
254
+ let(:tag_class) { :CONTEXT_SPECIFIC }
255
+ it { should == "\x83\x02\x00\x55" }
256
+ end
257
+
258
+ context 'PRIVATE' do
259
+ let(:tag_class) { :PRIVATE }
260
+ it { should == "\xC3\x02\x00\x55" }
261
+ end
262
+
263
+ context "IMPLICIT" do
264
+ let(:tag_class) { :IMPLICIT }
265
+ it { should == "\x83\x02\x00\x55" }
266
+ end
267
+
268
+ context "EXPLICIT" do
269
+ let(:tag_class) { :EXPLICIT }
270
+ it { should == "\xA3\x04\x03\x02\x00\x55" }
271
+ end
272
+
273
+ context nil do
274
+ let(:tag_class) { nil }
275
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
276
+ end
277
+
278
+ context :no_such_class do
279
+ let(:tag_class) { :no_such_class }
280
+ it { -> { subject }.should raise_error asn1error }
281
+ end
282
+ end
283
+
284
+ context 'encodes values set via accessors' do
285
+ subject {
286
+ o = klass.new(nil)
287
+ o.value = value if defined? value
288
+ o.tag = tag if defined? tag
289
+ o.tag_class = tag_class if defined? tag_class
290
+ o.unused_bits = unused_bits if defined? unused_bits
291
+ o.to_der
292
+ }
293
+
294
+ context 'value: 01010101' do
295
+ let(:value) { _B('01010101') }
296
+ it { should == "\x03\x02\x00\x55" }
297
+ end
298
+
299
+ context 'custom tag' do
300
+ let(:value) { _B('01010101') }
301
+ let(:tag) { 14 }
302
+ let(:tag_class) { :PRIVATE }
303
+ it { should == "\xCE\x02\x00\x55" }
304
+ end
305
+
306
+ context 'tag_class' do
307
+ let(:value) { _B('01010101') }
308
+ let(:tag_class) { :APPLICATION }
309
+ it { should == "\x43\x02\x00\x55" }
310
+ end
311
+
312
+ context 'unused_bits' do
313
+ let(:value) { _B('01010100') }
314
+ let(:unused_bits) { 2 }
315
+ it { should == "\x03\x02\x02\x54" }
316
+ end
317
+
318
+ context 'rejects unused_bits' do
319
+ let (:value) { _B('01010100') }
320
+
321
+ context '< 0' do
322
+ let(:unused_bits) { -1 }
323
+ it { -> { subject }.should raise_error asn1error }
324
+ end
325
+
326
+ context '> 7' do
327
+ let(:unused_bits) { 8 }
328
+ it { -> { subject }.should raise_error asn1error }
329
+ end
330
+ end
331
+ end
332
+ end
333
+
334
+ describe '#encode_to' do
335
+ context 'encodes to an IO' do
336
+ subject { klass.new(value).encode_to(io); io }
337
+
338
+ context "StringIO" do
339
+ let(:value) { _B('01010101') }
340
+ let(:io) { string_io_object }
341
+ its(:written_bytes) { should == "\x03\x02\x00\x55" }
342
+ end
343
+
344
+ context "Object responds to :write" do
345
+ let(:value) { _B('01010101') }
346
+ let(:io) { writable_object }
347
+ its(:written_bytes) { should == "\x03\x02\x00\x55" }
348
+ end
349
+
350
+ context "raise IO error transparently" do
351
+ let(:value) { _B('01010101') }
352
+ let(:io) { io_error_object }
353
+ it { -> { subject }.should raise_error asn1error }
354
+ end
355
+ end
356
+
357
+ it 'returns self' do
358
+ obj = klass.new(_B('01010101'))
359
+ obj.encode_to(string_io_object).should == obj
360
+ end
361
+ end
362
+
363
+ describe 'extracted from ASN1.decode' do
364
+ subject { decoder.decode(der) }
365
+
366
+ context 'extracted value' do
367
+ context '01010101' do
368
+ let(:der) { "\x03\x02\x00\x55" }
369
+ its(:class) { should == klass }
370
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
371
+ its(:value) { should == _B('01010101') }
372
+ end
373
+
374
+ context '010101010' do
375
+ let(:der) { "\x03\x03\x00\x00\xAA" }
376
+ its(:class) { should == klass }
377
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
378
+ its(:value) { should == "\x00\xAA" }
379
+ end
380
+
381
+ context '(empty)' do
382
+ let(:der) { "\x03\x01\x00" }
383
+ its(:class) { should == klass }
384
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
385
+ its(:value) { should == '' }
386
+ end
387
+
388
+ context '999 octets' do
389
+ let(:der) { "\x03\x82\x03\xE8\x00" + "\xFF" * 999 }
390
+ its(:class) { should == klass }
391
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
392
+ its(:value) { should == "\xFF" * 999 }
393
+ end
394
+
395
+ context '1000 octets' do
396
+ let(:der) { "\x03\x82\x03\xE9\x00" + "\x00" * 1000 }
397
+ its(:class) { should == klass }
398
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
399
+ its(:value) { should == "\x00" * 1000 }
400
+ end
401
+
402
+ context '1001 octets' do
403
+ let(:der) { "\x03\x82\x03\xEA\x00" + "\xFF" * 1001 }
404
+ its(:class) { should == klass }
405
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
406
+ its(:value) { should == "\xFF" * 1001 }
407
+ end
408
+
409
+ it 'rejects incomplete value' do
410
+ asn1 = decoder.decode("\x03\x00")
411
+ -> { asn1.value }.should raise_error asn1error
412
+ end
413
+
414
+ context 'unused_bits is 0 for empty value' do
415
+ let(:der) { "\x03\x01\x00" }
416
+ its(:class) { should == klass }
417
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
418
+ its(:value) { should == '' }
419
+ its(:unused_bits) { should == 0 }
420
+ end
421
+
422
+ context 'unused_bits non-zero' do
423
+ let(:der) { "\x03\x02\x02\x01" }
424
+ its(:class) { should == klass }
425
+ its(:tag) { should == Krypt::ASN1::BIT_STRING }
426
+ its(:value) { should == "\x01" }
427
+ its(:unused_bits) { should == 2 }
428
+ end
429
+
430
+ context 'rejects unused_bits larger than 7' do
431
+ let(:der) { "\x03\x02\x08\x01" }
432
+ it { -> { subject.value }.should raise_error asn1error }
433
+ end
434
+ end
435
+
436
+ context 'extracted tag class' do
437
+ context 'UNIVERSAL' do
438
+ let(:der) { "\x03\x03\x00\x00\xAA" }
439
+ its(:tag_class) { should == :UNIVERSAL }
440
+ end
441
+
442
+ context 'APPLICATION' do
443
+ let(:der) { "\x43\x03\x00\x00\xAA" }
444
+ its(:tag_class) { should == :APPLICATION }
445
+ end
446
+
447
+ context 'CONTEXT_SPECIFIC' do
448
+ let(:der) { "\x83\x03\x00\x00\xAA" }
449
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
450
+ end
451
+
452
+ context 'PRIVATE' do
453
+ let(:der) { "\xC3\x03\x00\x00\xAA" }
454
+ its(:tag_class) { should == :PRIVATE }
455
+ end
456
+
457
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
458
+ let(:der) { "\x03\x03\x00\x00\xAA" }
459
+ it do
460
+ subject.tag_class = :IMPLICIT
461
+ subject.to_der.should == "\x83\x03\x00\x00\xAA"
462
+ end
463
+ end
464
+
465
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
466
+ let(:der) { "\x03\x03\x00\x00\xAA" }
467
+ it do
468
+ subject.tag_class = :EXPLICIT
469
+ subject.tag = 0
470
+ subject.to_der.should == "\xA0\x05\x03\x03\x00\x00\xAA"
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end