version 0.3.33
[fms.git] / libs / libtomcrypt / pk / asn1 / der / sequence / der_decode_sequence_flexi.c
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
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 */   
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 $ */