10
10
11
11
module OpenSSL
12
12
module ASN1
13
+ INT_MAX = begin
14
+ n_bytes = [ 42 ] . pack ( 'i' ) . size
15
+ n_bits = n_bytes * 16
16
+ 2 ** ( n_bits - 2 ) - 1
17
+ end
18
+
19
+ V_ASN1_UNIVERSAL = 0x00
20
+ V_ASN1_APPLICATION = 0x40
21
+ V_ASN1_CONTEXT_SPECIFIC = 0x80
22
+ V_ASN1_PRIVATE = 0xc0
23
+ V_ASN1_CONSTRUCTED = 0x20
24
+ V_ASN1_PRIMITIVE_TAG = 0x1f
25
+
26
+
13
27
class ASN1Data
14
28
#
15
29
# Carries the value of a ASN.1 type.
@@ -71,6 +85,101 @@ def initialize(value, tag, tag_class)
71
85
@tag_class = tag_class
72
86
@indefinite_length = false
73
87
end
88
+
89
+ def to_der
90
+ if @value . is_a? ( Array )
91
+ cons_to_der
92
+ elsif @indefinite_length
93
+ raise ASN1Error , "indefinite length form cannot be used " \
94
+ "with primitive encoding"
95
+ else
96
+ prim_to_der
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def cons_to_der
103
+ ary = @value . to_a
104
+ str = "" . b
105
+
106
+ @value . each_with_index do |item , idx |
107
+ if @indefinite_length && item . is_a? ( EndOfContent )
108
+ if idx != ary . size - 1
109
+ raise ASN1Error , "illegal EOC octets in value"
110
+ end
111
+
112
+ break
113
+ end
114
+
115
+ item = item . to_der if item . respond_to? ( :to_der )
116
+
117
+ str << item
118
+ end
119
+
120
+ to_der_internal ( str , true )
121
+ end
122
+
123
+ def prim_to_der
124
+ return to_der_internal ( @value ) unless ASN1 . take_default_tag ( self . class )
125
+
126
+ # TODO: how to translate this?
127
+ asn1 = ossl_asn1_get_asn1type ( self )
128
+ alllen = i2d_ASN1_TYPE ( asn1 , NULL )
129
+
130
+ if ( alllen < 0 )
131
+ ASN1_TYPE_free ( asn1 )
132
+ raise ASN1Error , "i2d_ASN1_TYPE"
133
+ end
134
+
135
+ str = String . new ( capacity : alllen )
136
+
137
+ p0 = p1 = str ;
138
+ if ( i2d_ASN1_TYPE ( asn1 , &p0 ) < 0 )
139
+ ASN1_TYPE_free ( asn1 ) ;
140
+ ossl_raise ( eASN1Error , "i2d_ASN1_TYPE" ) ;
141
+ end
142
+ ASN1_TYPE_free ( asn1 ) ;
143
+ ossl_str_adjust ( str , p0 ) ;
144
+
145
+ j = ASN1_get_object ( p1 , bodylen , tag , tc , alllen )
146
+ if j & 0x80
147
+ ossl_raise ( eASN1Error , "ASN1_get_object" ) ; # should not happen
148
+ end
149
+
150
+ to_der_internal ( str [ ( alllen - bodylen ) ..-1 ] )
151
+ end
152
+
153
+ def to_der_internal ( body , constructed = false )
154
+ default_tag = ASN1 . take_default_tag ( self . class )
155
+ body_len = body . size
156
+
157
+ if @tagging == :EXPLICIT
158
+ raise ASN1Error , "explicit tagging of unknown tag" unless default_tag
159
+
160
+ inner_len = ASN1 . object_size ( constructed && @indefinite_length , body_len , default_tag )
161
+ total_len = ASN1 . object_size ( @indefinite_length , inner_len , @tag )
162
+
163
+ # Put explicit tag
164
+ str = ASN1 . put_object ( constructed , @indefinite_length , inner_len , @tag , @tag_class ) <<
165
+ # Append inner object
166
+ ASN1 . put_object ( constructed , @indefinite_length , body_len , default_tag , :UNIVERSAL )
167
+
168
+ str << body
169
+ if @indefinite_length
170
+ str << "\x00 \x00 \x00 \x00 "
171
+ end
172
+ else
173
+ total_length = ASN1 . object_size ( constructed && @indefinite_length , body_len , @tag )
174
+ str = ASN1 . put_object ( constructed , @indefinite_length , body_len , @tag , @tag_class )
175
+ str << body
176
+ if @indefinite_length
177
+ str << "\x00 \x00 "
178
+ end
179
+ end
180
+
181
+ str
182
+ end
74
183
end
75
184
76
185
module TaggedASN1Data
@@ -172,8 +281,110 @@ def initialize
172
281
end
173
282
end
174
283
284
+ module_function
285
+
286
+ # ruby port of ASN1_object_size
287
+ def object_size ( indefinite_length , length , tag )
288
+ ret = 1
289
+
290
+ return -1 if length < 0
291
+
292
+ if tag >= 31
293
+ while tag > 0
294
+ tag >>= 7
295
+ ret += 1
296
+ end
297
+ end
298
+ if indefinite_length
299
+ ret += 3
300
+ else
301
+ ret += 1
302
+ if length > 127
303
+ tmplen = length
304
+ while tmplen > 0
305
+ tmplen >>= 8
306
+ ret +=1
307
+ end
308
+ end
309
+ end
310
+
311
+ return -1 if ( ret >= INT_MAX - length )
312
+
313
+
314
+ ret + length
315
+ end
316
+
317
+ # ruby port of openssl ASN1_put_object
318
+ def put_object ( constructed , indefinite_length , length , tag , tag_class )
319
+ str = "" . b
320
+ xclass = take_asn1_tag_class ( tag_class )
321
+
322
+ i = constructed ? V_ASN1_CONSTRUCTED : 0
323
+ i |= ( xclass & V_ASN1_PRIVATE )
324
+
325
+ if tag < 31
326
+ str << ( i | ( tag & V_ASN1_PRIMITIVE_TAG ) ) . chr
327
+
328
+ else
329
+ str << ( i | V_ASN1_PRIMITIVE_TAG ) . chr
330
+
331
+ i = 0
332
+ ttag = tag
333
+
334
+ while ttag > 0
335
+ i += 1
336
+ ttag >>= 7
337
+ end
338
+
339
+ ttag = i
340
+
341
+ while i > 0
342
+ i -= 1
343
+ tag_str = tag & 0x7f
344
+ if ( i != ( ttag - 1 ) )
345
+ tag_str |= 0x80
346
+ end
347
+ str . insert ( 1 , tag_str . chr )
348
+ tag >>= 7
349
+ end
350
+ end
351
+
352
+ if constructed && indefinite_length
353
+ str << 0x80 . chr
354
+ else
355
+ str << put_length ( length )
356
+ end
357
+ str
358
+ end
359
+
360
+
361
+ def put_length ( length )
362
+ raise ASN1Error , "invalid length" if length < 0
363
+
364
+ if length < 0x80
365
+ length . chr
366
+ else
367
+ i = length
368
+
369
+ if i >= 0
370
+ done = 0
371
+ else
372
+ done = -1
373
+ end
374
+
375
+ octets = "" . b
376
+ begin
377
+ octets = ( i & 0xff ) . chr << octets
378
+ i = i >> 8
379
+ end until i == done
380
+ octets
381
+
382
+ ( octets . size | 0x80 ) . chr << octets
383
+ end
384
+ end
385
+
175
386
# :nodoc:
176
- def self . take_default_tag ( klass )
387
+ def take_default_tag ( klass )
177
388
tag = CLASS_TAG_MAP [ klass ]
178
389
179
390
return tag if tag
@@ -184,5 +395,17 @@ def self.take_default_tag(klass)
184
395
185
396
take_default_tag ( sklass )
186
397
end
398
+
399
+ # from ossl_asn1.c : ossl_asn1_tag_class
400
+ def take_asn1_tag_class ( tag_class )
401
+ case tag_class
402
+ when :UNIVERSAL , nil then V_ASN1_UNIVERSAL
403
+ when :APPLICATION then V_ASN1_APPLICATION
404
+ when :CONTEXT_SPECIFIC then V_ASN1_CONTEXT_SPECIFIC
405
+ when :PRIVATE then V_ASN1_PRIVATE
406
+ else
407
+ raise ASN1Error , "invalid tag class"
408
+ end
409
+ end
187
410
end
188
411
end
0 commit comments