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