1 /**
2 * DER Encoder
3 * 
4 * Copyright:
5 * (C) 1999-2007 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.asn1.der_enc;
12 
13 import botan.constants;
14 import botan.asn1.asn1_obj;
15 import botan.asn1.der_enc;
16 import botan.math.bigint.bigint;
17 import botan.utils.get_byte;
18 import botan.utils.parsing;
19 import botan.utils.bit_ops;
20 import botan.utils.types;
21 import std.algorithm;
22 
23 import botan.utils.types;
24 
25 
26 /**
27 * General DER Encoding Object
28 */
29 struct DEREncoder
30 {
31 public:
32     Vector!ubyte getContentsUnlocked()
33     {
34         //logTrace("DEREncoder.getContentsUnlocked");
35         return unlock(getContents()); 
36     }
37 
38     /*
39     * Return the encoded m_contents
40     */
41     SecureVector!ubyte getContents()
42     {
43         if (m_subsequences.length != 0)
44             throw new InvalidState("DEREncoder: Sequence hasn't been marked done");
45         
46         return m_contents.dup;
47     }  
48 
49     /*
50     * Return the encoded m_contents
51     */
52     SecureArray!ubyte getContentsRef()
53     {
54         if (m_subsequences.length != 0)
55             throw new InvalidState("DEREncoder: Sequence hasn't been marked done");
56         
57         return m_contents.dupr;
58     }
59     
60     /*
61     * Start a new ASN.1 ASN1Tag.SEQUENCE/SET/EXPLICIT
62     */
63     ref DEREncoder startCons(ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.UNIVERSAL)
64     {
65         m_subsequences.pushBack(DERSequence(m_type_tag, m_class_tag));
66         return this;
67     }
68     
69     /*
70     * Finish the current ASN.1 ASN1Tag.SEQUENCE/SET/EXPLICIT
71     */
72     ref DEREncoder endCons()
73     {
74         if (m_subsequences.empty)
75             throw new InvalidState("endCons: No such sequence");
76         
77         SecureVector!ubyte seq = m_subsequences[m_subsequences.length-1].getContents();
78         m_subsequences.removeBack();
79         rawBytes(seq);
80         return this;
81     }
82     
83     /*
84     * Start a new ASN.1 EXPLICIT encoding
85     */
86     ref DEREncoder startExplicit(ushort type_no)
87     {
88         ASN1Tag m_type_tag = cast(ASN1Tag)(type_no);
89         
90         if (m_type_tag == ASN1Tag.SET)
91             throw new InternalError("DEREncoder.startExplicit(SET); cannot perform");
92         
93         return startCons(m_type_tag, ASN1Tag.CONTEXT_SPECIFIC);
94     }
95     
96     /*
97     * Finish the current ASN.1 EXPLICIT encoding
98     */
99     ref DEREncoder endExplicit()
100     {
101         return endCons();
102     }
103     
104     /*
105     * Write raw bytes into the stream
106     */
107     ref DEREncoder rawBytes(ALLOC)(auto const ref Vector!(ubyte, ALLOC) val)
108     {
109         return rawBytes(val.ptr, val.length);
110     }
111 
112     ref DEREncoder rawBytes(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) val)
113     {
114         return rawBytes(val.ptr, val.length);
115     }
116        
117     /*
118     * Write raw bytes into the stream
119     */
120     ref DEREncoder rawBytes(const(ubyte)* bytes, size_t length)
121     {
122 
123         if (m_subsequences.length)
124             m_subsequences[m_subsequences.length-1].addBytes(bytes, length);
125         else
126             m_contents ~= bytes[0 .. length];
127         //logTrace("Contents appended: ", m_contents.length);
128         return this;
129     }
130     
131     /*
132     * Encode a NULL object
133     */
134     ref DEREncoder encodeNull()
135     {
136         return addObject(ASN1Tag.NULL_TAG, ASN1Tag.UNIVERSAL, null, 0);
137     }
138     
139     /*
140     * DER encode a BOOLEAN
141     */
142     ref DEREncoder encode(bool is_true)
143     {
144         return encode(is_true, ASN1Tag.BOOLEAN, ASN1Tag.UNIVERSAL);
145     }
146     
147     /*
148     * DER encode a small INTEGER
149     */
150     ref DEREncoder encode(size_t n)
151     {
152         return encode(BigInt(n), ASN1Tag.INTEGER, ASN1Tag.UNIVERSAL);
153     }
154     
155     /*
156     * DER encode a small INTEGER
157     */
158     ref DEREncoder encode()(auto const ref BigInt n)
159     {
160         return encode(n, ASN1Tag.INTEGER, ASN1Tag.UNIVERSAL);
161     }
162     
163     /*
164     * DER encode an OCTET STRING or BIT STRING
165     */
166     ref DEREncoder encode(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) bytes, ASN1Tag real_type)
167     {
168         return encode(bytes.ptr, bytes.length, real_type, real_type, ASN1Tag.UNIVERSAL);
169     }
170     
171     /*
172     * DER encode an OCTET STRING or BIT STRING
173     */
174     ref DEREncoder encode(ALLOC)(auto const ref Vector!(ubyte, ALLOC) bytes, ASN1Tag real_type)
175     {
176         return encode(bytes.ptr, bytes.length, real_type, real_type, ASN1Tag.UNIVERSAL);
177     }
178     
179     /*
180     * Encode this object
181     */
182     ref DEREncoder encode(const(ubyte)* bytes, size_t length, ASN1Tag real_type)
183     {
184         return encode(bytes, length, real_type, real_type, ASN1Tag.UNIVERSAL);
185     }
186     
187     /*
188     * DER encode a BOOLEAN
189     */
190     ref DEREncoder encode(bool is_true, ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC)
191     {
192         ubyte val = is_true ? 0xFF : 0x00;
193         return addObject(m_type_tag, m_class_tag, &val, 1);
194     }
195     
196     /*
197     * DER encode a small INTEGER
198     */
199     ref DEREncoder encode(size_t n, ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC)
200     {
201         return encode(BigInt(n), m_type_tag, m_class_tag);
202     }
203     
204     /*
205     * DER encode an INTEGER
206     */
207     ref DEREncoder encode()(auto const ref BigInt n, ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC)
208     {
209         //logTrace("Encode BigInt: ", n.toString());
210         if (n == 0)
211             return addObject(m_type_tag, m_class_tag, 0);
212         
213         bool extra_zero = (n.bits() % 8 == 0);
214         SecureVector!ubyte m_contents = SecureVector!ubyte(extra_zero + n.bytes());
215         BigInt.encode(m_contents.ptr + extra_zero, n);
216         if (n < 0)
217         {
218             foreach (size_t i; 0 .. m_contents.length)
219                 m_contents[i] = ~m_contents[i];
220             for (size_t i = m_contents.length; i > 0; --i)
221                 if (++(m_contents[i-1]))
222                     break;
223         }
224         
225         return addObject(m_type_tag, m_class_tag, m_contents);
226     }
227     
228     /*
229     * DER encode an OCTET STRING or BIT STRING
230     */
231     ref DEREncoder encode(ALLOC)(auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) bytes,
232                                        ASN1Tag real_type,
233                                       ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC)
234     {
235         return encode(bytes.ptr, bytes.length, real_type, m_type_tag, m_class_tag);
236     }
237     
238     /*
239     * DER encode an OCTET STRING or BIT STRING
240     */
241     ref DEREncoder encode(ALLOC)(auto const ref Vector!(ubyte, ALLOC) bytes,
242                                       ASN1Tag real_type,
243                                       ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC)
244     {
245         return encode(bytes.ptr, bytes.length, real_type, m_type_tag, m_class_tag);
246     }
247 
248     /*
249     * DER encode an OCTET STRING or BIT STRING
250     */
251     ref DEREncoder encode(const(ubyte)* bytes, size_t length,
252                           ASN1Tag real_type,
253                           ASN1Tag m_type_tag, ASN1Tag m_class_tag = ASN1Tag.CONTEXT_SPECIFIC)
254     {
255         if (real_type != ASN1Tag.OCTET_STRING && real_type != ASN1Tag.BIT_STRING)
256             throw new InvalidArgument("DEREncoder: Invalid tag for ubyte/bit string");
257         
258         if (real_type == ASN1Tag.BIT_STRING)
259         {
260             SecureVector!ubyte encoded;
261             encoded.pushBack(0);
262             encoded ~= bytes[0 .. length];
263             return addObject(m_type_tag, m_class_tag, encoded);
264         }
265         else
266             return addObject(m_type_tag, m_class_tag, bytes, length);
267     }
268 
269     /*
270     * Request for an object to encode itself
271     */
272     ref DEREncoder encode(T)(auto const ref T obj)
273     {
274         obj.encodeInto(this);
275         return this;
276     }
277 
278     /*
279     * Conditionally write some values to the stream
280     */
281     ref DEREncoder encodeIf (bool cond, ref DEREncoder codec)
282     {
283         if (cond)
284             return rawBytes(codec.getContents());
285         return this;
286     }
287     
288     ref DEREncoder encodeIf(T)(bool cond, auto const ref T obj)
289     {
290         if (cond)
291             encode(obj);
292         return this;
293     }
294 
295     ref DEREncoder encodeOptional(T)(in T value, in T default_value = T.init)
296     {
297         if (value != default_value)
298             encode(value);
299         return this;
300     }
301 
302     ref DEREncoder encodeList(T, Alloc)(const ref Vector!(T, Alloc) values)
303     {
304         foreach (const ref value; values[])
305             encode(value);
306         return this;
307     }
308 
309     /*
310     * Write the encoding of the ubyte(s)
311     */
312     ref DEREncoder addObject(ASN1Tag m_type_tag, ASN1Tag m_class_tag, in string rep_str)
313     {
314         const(ubyte)* rep = cast(const(ubyte)*)(rep_str.ptr);
315         const size_t rep_len = rep_str.length;
316         return addObject(m_type_tag, m_class_tag, rep, rep_len);
317     }
318 
319     /*
320     * Write the encoding of the ubyte(s)
321     */
322     ref DEREncoder addObject(ASN1Tag m_type_tag, ASN1Tag m_class_tag, const(ubyte)* rep, size_t length)
323     {
324         //logTrace("AddObject: ", m_type_tag);
325         SecureVector!ubyte buffer;
326 		auto enc_tag = encodeTag(m_type_tag, m_class_tag);
327 		auto enc_len = encodeLength(length);
328         buffer ~= enc_tag[];
329         buffer ~= enc_len[];
330         buffer ~= rep[0 .. length];
331         //logTrace("Finish Add object");
332 
333         return rawBytes(buffer);
334     }
335 
336     /*
337     * Write the encoding of the ubyte
338     */
339     ref DEREncoder addObject(ASN1Tag m_type_tag, ASN1Tag m_class_tag, ubyte rep)
340     {
341         return addObject(m_type_tag, m_class_tag, &rep, 1);
342     }
343 
344 
345     ref DEREncoder addObject(ALLOC)(ASN1Tag m_type_tag, ASN1Tag m_class_tag, 
346                                     auto const ref RefCounted!(Vector!(ubyte, ALLOC), ALLOC) rep)
347     {
348         return addObject(m_type_tag, m_class_tag, rep.ptr, rep.length);
349     }
350 
351     ref DEREncoder addObject(ALLOC)(ASN1Tag m_type_tag, ASN1Tag m_class_tag, 
352                                         auto const ref Vector!(ubyte, ALLOC) rep)
353     {
354         return addObject(m_type_tag, m_class_tag, rep.ptr, rep.length);
355     }
356 private:
357     alias DERSequence = RefCounted!DERSequenceImpl;
358     class DERSequenceImpl
359     {
360     public:
361         /*
362         * Return the type and class taggings
363         */
364         const(ASN1Tag) tagOf() const
365         {
366             return m_type_tag | m_class_tag;
367         }
368 
369         /*
370         * Return the encoded ASN1Tag.SEQUENCE/SET
371         */
372         SecureVector!ubyte getContents()
373         {
374             //logTrace("Get Contents real class tag: ", m_class_tag);
375             const ASN1Tag real_class_tag = m_class_tag | ASN1Tag.CONSTRUCTED;
376             
377             if (m_type_tag == ASN1Tag.SET)
378             {    // TODO: check if sort works
379                 auto set_contents = m_set_contents[];
380                 //logTrace("set contents before: ", set_contents[]);
381                 sort!("a < b", SwapStrategy.stable)(set_contents);
382                 //logTrace("set contents after: ", set_contents[]);
383                 foreach (SecureArray!ubyte data; set_contents)
384                     m_contents ~= data[];
385 
386                 m_set_contents.clear();
387             }
388             
389             SecureVector!ubyte result;
390 			auto enc_tag = encodeTag(m_type_tag, real_class_tag);
391 			auto enc_len = encodeLength(m_contents.length);
392             result ~= enc_tag[];
393 			result ~= enc_len[];
394             result ~= m_contents[];
395             m_contents.clear();
396             
397             return result.move();
398         }
399 
400         /*
401         * Add an encoded value to the ASN1Tag.SEQUENCE/SET
402         */
403         void addBytes(const(ubyte)* data, size_t length)
404         {
405             if (m_type_tag == ASN1Tag.SET)
406                 m_set_contents.pushBack(SecureArray!ubyte(data[0 .. length]));
407             else
408                 m_contents ~= data[0 .. length];
409         }
410 
411         /*
412         * DERSequence Constructor
413         */
414         this(ASN1Tag t1, ASN1Tag t2)
415         {
416             m_type_tag = t1;
417             m_class_tag = t2;
418         }
419 
420     private:
421 
422         ASN1Tag m_type_tag;
423         ASN1Tag m_class_tag;
424         SecureVector!ubyte m_contents;
425         Vector!( SecureArray!ubyte ) m_set_contents;
426     }
427 
428     SecureArray!ubyte m_contents;
429     Array!DERSequence m_subsequences;
430 }
431 
432 /*
433 * DER encode an ASN.1 type tag
434 */
435 SecureArray!ubyte encodeTag(ASN1Tag m_type_tag, ASN1Tag m_class_tag)
436 {
437     //logTrace("Encode type: ", m_type_tag);
438     //logTrace("Encode class: ", m_class_tag);
439     //assert(m_type_tag != 33 || m_class_tag != cast(ASN1Tag)96);
440     if ((m_class_tag | 0xE0) != 0xE0)
441         throw new EncodingError("DEREncoder: Invalid class tag " ~ to!string(m_class_tag));
442 
443     SecureArray!ubyte encoded_tag;
444     if (m_type_tag <= 30)
445         encoded_tag.pushBack(cast(ubyte) (m_type_tag | m_class_tag));
446     else
447     {
448         size_t blocks = highBit(m_type_tag) + 6;
449         blocks = (blocks - (blocks % 7)) / 7;
450         auto blocks_tag = cast(ubyte) (m_class_tag | 0x1F);
451         encoded_tag.pushBack(blocks_tag);
452         foreach (size_t i; 0 .. (blocks - 1)) {
453             auto blocks_i_tag = cast(ubyte) (0x80 | ((m_type_tag >> 7*(blocks-i-1)) & 0x7F));
454             encoded_tag.pushBack(blocks_i_tag);
455         }
456         auto blocks_end_tag = cast(ubyte) (m_type_tag & 0x7F);
457         encoded_tag.pushBack(blocks_end_tag);
458     }
459     //logTrace("Encoded tag: ", cast(ubyte[]) encoded_tag[]);
460     return encoded_tag;
461 }
462 
463 /*
464 * DER encode an ASN.1 length field
465 */
466 SecureArray!ubyte encodeLength(size_t length)
467 {
468     //logTrace("Encode length: ", length);
469     SecureArray!ubyte encoded_length;
470     if (length <= 127)
471         encoded_length.pushBack(cast(ubyte)(length));
472     else
473     {
474         const size_t top_byte = significantBytes(length);
475         
476         encoded_length.pushBack(cast(ubyte)(0x80 | top_byte));
477         
478         for (size_t i = (length).sizeof - top_byte; i != (length).sizeof; ++i)
479             encoded_length.pushBack(get_byte(i, length));
480     }
481     return encoded_length;
482 }