• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2  *
3  * LibTomCrypt is a library that provides various cryptographic
4  * algorithms in a highly modular and flexible manner.
5  *
6  * The library is free for all purposes without any express
7  * guarantee it works.
8  *
9  * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
10  */
11 #include "tomcrypt.h"
12 
13 /**
14   @file der_decode_sequence_flexi.c
15   ASN.1 DER, decode an array of ASN.1 types with a flexi parser, Tom St Denis
16 */
17 
18 #ifdef LTC_DER
19 
fetch_length(const unsigned char * in,unsigned long inlen)20 static unsigned long fetch_length(const unsigned char *in, unsigned long inlen)
21 {
22    unsigned long x, y, z;
23 
24    y = 0;
25 
26    /* skip type and read len */
27    if (inlen < 2) {
28       return 0xFFFFFFFF;
29    }
30    ++in; ++y;
31 
32    /* read len */
33    x = *in++; ++y;
34 
35    /* <128 means literal */
36    if (x < 128) {
37       return x+y;
38    }
39    x     &= 0x7F; /* the lower 7 bits are the length of the length */
40    inlen -= 2;
41 
42    /* len means len of len! */
43    if (x == 0 || x > 4 || x > inlen) {
44       return 0xFFFFFFFF;
45    }
46 
47    y += x;
48    z = 0;
49    while (x--) {
50       z = (z<<8) | ((unsigned long)*in);
51       ++in;
52    }
53    return z+y;
54 }
55 
56 /**
57    ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
58    @param in      The input buffer
59    @param inlen   [in/out] The length of the input buffer and on output the amount of decoded data
60    @param out     [out] A pointer to the linked list
61    @return CRYPT_OK on success.
62 */
der_decode_sequence_flexi(const unsigned char * in,unsigned long * inlen,ltc_asn1_list ** out)63 int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
64 {
65    ltc_asn1_list *l;
66    unsigned long err, type, len, totlen, x, y;
67    void          *realloc_tmp;
68 
69    LTC_ARGCHK(in    != NULL);
70    LTC_ARGCHK(inlen != NULL);
71    LTC_ARGCHK(out   != NULL);
72 
73    l = NULL;
74    totlen = 0;
75 
76    /* scan the input and and get lengths and what not */
77    while (*inlen) {
78       /* read the type byte */
79       type = *in;
80 
81       /* fetch length */
82       len = fetch_length(in, *inlen);
83       if (len > *inlen) {
84          err = CRYPT_INVALID_PACKET;
85          goto error;
86       }
87 
88       /* alloc new link */
89       if (l == NULL) {
90          l = XCALLOC(1, sizeof(*l));
91          if (l == NULL) {
92             err = CRYPT_MEM;
93             goto error;
94          }
95       } else {
96          l->next = XCALLOC(1, sizeof(*l));
97          if (l->next == NULL) {
98             err = CRYPT_MEM;
99             goto error;
100          }
101          l->next->prev = l;
102          l = l->next;
103       }
104 
105       /* now switch on type */
106       switch (type) {
107          case 0x01: /* BOOLEAN */
108             l->type = LTC_ASN1_BOOLEAN;
109             l->size = 1;
110             l->data = XCALLOC(1, sizeof(int));
111 
112             if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) {
113                goto error;
114             }
115 
116             if ((err = der_length_boolean(&len)) != CRYPT_OK) {
117                goto error;
118             }
119             break;
120 
121          case 0x02: /* INTEGER */
122              /* init field */
123              l->type = LTC_ASN1_INTEGER;
124              l->size = 1;
125              if ((err = mp_init(&l->data)) != CRYPT_OK) {
126                  goto error;
127              }
128 
129              /* decode field */
130              if ((err = der_decode_integer(in, *inlen, l->data)) != CRYPT_OK) {
131                  goto error;
132              }
133 
134              /* calc length of object */
135              if ((err = der_length_integer(l->data, &len)) != CRYPT_OK) {
136                  goto error;
137              }
138              break;
139 
140          case 0x03: /* BIT */
141             /* init field */
142             l->type = LTC_ASN1_BIT_STRING;
143             l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char.  */
144 
145             if ((l->data = XCALLOC(1, l->size)) == NULL) {
146                err = CRYPT_MEM;
147                goto error;
148             }
149 
150             if ((err = der_decode_bit_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
151                goto error;
152             }
153 
154             if ((err = der_length_bit_string(l->size, &len)) != CRYPT_OK) {
155                goto error;
156             }
157             break;
158 
159          case 0x04: /* OCTET */
160 
161             /* init field */
162             l->type = LTC_ASN1_OCTET_STRING;
163             l->size = len;
164 
165             if ((l->data = XCALLOC(1, l->size)) == NULL) {
166                err = CRYPT_MEM;
167                goto error;
168             }
169 
170             if ((err = der_decode_octet_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
171                goto error;
172             }
173 
174             if ((err = der_length_octet_string(l->size, &len)) != CRYPT_OK) {
175                goto error;
176             }
177             break;
178 
179          case 0x05: /* NULL */
180 
181             /* valid NULL is 0x05 0x00 */
182             if (in[0] != 0x05 || in[1] != 0x00) {
183                err = CRYPT_INVALID_PACKET;
184                goto error;
185             }
186 
187             /* simple to store ;-) */
188             l->type = LTC_ASN1_NULL;
189             l->data = NULL;
190             l->size = 0;
191             len     = 2;
192 
193             break;
194 
195          case 0x06: /* OID */
196 
197             /* init field */
198             l->type = LTC_ASN1_OBJECT_IDENTIFIER;
199             l->size = len;
200 
201             if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
202                err = CRYPT_MEM;
203                goto error;
204             }
205 
206             if ((err = der_decode_object_identifier(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
207                goto error;
208             }
209 
210             if ((err = der_length_object_identifier(l->data, l->size, &len)) != CRYPT_OK) {
211                goto error;
212             }
213 
214             /* resize it to save a bunch of mem */
215             if ((realloc_tmp = XREALLOC(l->data, l->size * sizeof(unsigned long))) == NULL) {
216                /* out of heap but this is not an error */
217                break;
218             }
219             l->data = realloc_tmp;
220             break;
221 
222          case 0x0C: /* UTF8 */
223 
224             /* init field */
225             l->type = LTC_ASN1_UTF8_STRING;
226             l->size = len;
227 
228             if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
229                err = CRYPT_MEM;
230                goto error;
231             }
232 
233             if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
234                goto error;
235             }
236 
237             if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
238                goto error;
239             }
240             break;
241 
242          case 0x13: /* PRINTABLE */
243 
244             /* init field */
245             l->type = LTC_ASN1_PRINTABLE_STRING;
246             l->size = len;
247 
248             if ((l->data = XCALLOC(1, l->size)) == NULL) {
249                err = CRYPT_MEM;
250                goto error;
251             }
252 
253             if ((err = der_decode_printable_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
254                goto error;
255             }
256 
257             if ((err = der_length_printable_string(l->data, l->size, &len)) != CRYPT_OK) {
258                goto error;
259             }
260             break;
261 
262          case 0x16: /* IA5 */
263 
264             /* init field */
265             l->type = LTC_ASN1_IA5_STRING;
266             l->size = len;
267 
268             if ((l->data = XCALLOC(1, l->size)) == NULL) {
269                err = CRYPT_MEM;
270                goto error;
271             }
272 
273             if ((err = der_decode_ia5_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
274                goto error;
275             }
276 
277             if ((err = der_length_ia5_string(l->data, l->size, &len)) != CRYPT_OK) {
278                goto error;
279             }
280             break;
281 
282          case 0x17: /* UTC TIME */
283 
284             /* init field */
285             l->type = LTC_ASN1_UTCTIME;
286             l->size = 1;
287 
288             if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
289                err = CRYPT_MEM;
290                goto error;
291             }
292 
293             len = *inlen;
294             if ((err = der_decode_utctime(in, &len, l->data)) != CRYPT_OK) {
295                goto error;
296             }
297 
298             if ((err = der_length_utctime(l->data, &len)) != CRYPT_OK) {
299                goto error;
300             }
301             break;
302 
303          case 0x30: /* SEQUENCE */
304          case 0x31: /* SET */
305 
306              /* init field */
307              l->type = (type == 0x30) ? LTC_ASN1_SEQUENCE : LTC_ASN1_SET;
308 
309              /* we have to decode the SEQUENCE header and get it's length */
310 
311                 /* move past type */
312                 ++in; --(*inlen);
313 
314                 /* read length byte */
315                 x = *in++; --(*inlen);
316 
317                 /* smallest SEQUENCE/SET header */
318                 y = 2;
319 
320                 /* now if it's > 127 the next bytes are the length of the length */
321                 if (x > 128) {
322                    x      &= 0x7F;
323                    in     += x;
324                    *inlen -= x;
325 
326                    /* update sequence header len */
327                    y      += x;
328                 }
329 
330              /* Sequence elements go as child */
331              len = len - y;
332              if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
333                 goto error;
334              }
335 
336              /* len update */
337              totlen += y;
338 
339              /* link them up y0 */
340              l->child->parent = l;
341 
342              break;
343          default:
344            /* invalid byte ... this is a soft error */
345            /* remove link */
346            l       = l->prev;
347            XFREE(l->next);
348            l->next = NULL;
349            goto outside;
350       }
351 
352       /* advance pointers */
353       totlen  += len;
354       in      += len;
355       *inlen  -= len;
356    }
357 
358 outside:
359 
360    /* rewind l please */
361    while (l->prev != NULL || l->parent != NULL) {
362       if (l->parent != NULL) {
363          l = l->parent;
364       } else {
365          l = l->prev;
366       }
367    }
368 
369    /* return */
370    *out   = l;
371    *inlen = totlen;
372    return CRYPT_OK;
373 
374 error:
375    /* free list */
376    der_sequence_free(l);
377 
378    return err;
379 }
380 
381 #endif
382 
383 
384 /* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c,v $ */
385 /* $Revision: 1.25 $ */
386 /* $Date: 2006/11/26 02:25:18 $ */
387