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#include <stdarg.h>
13
14
15/**
16  @file der_decode_sequence_ex.c
17  ASN.1 DER, decode a SEQUENCE, Tom St Denis
18*/
19
20#ifdef LTC_DER
21
22/**
23   Decode a SEQUENCE
24   @param in       The DER encoded input
25   @param inlen    The size of the input
26   @param list     The list of items to decode
27   @param outlen   The number of items in the list
28   @param ordered  Search an unordeded or ordered list
29   @return CRYPT_OK on success
30*/
31int der_decode_sequence_ex(const unsigned char *in, unsigned long  inlen,
32                           ltc_asn1_list *list,     unsigned long  outlen, int ordered)
33{
34   int           err, type;
35   unsigned long size, x, y, z, i, blksize;
36   void          *data;
37
38   LTC_ARGCHK(in   != NULL);
39   LTC_ARGCHK(list != NULL);
40
41   /* get blk size */
42   if (inlen < 2) {
43      return CRYPT_INVALID_PACKET;
44   }
45
46   /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
47   x = 0;
48   if (in[x] != 0x30 && in[x] != 0x31) {
49      return CRYPT_INVALID_PACKET;
50   }
51   ++x;
52
53   if (in[x] < 128) {
54      blksize = in[x++];
55   } else if (in[x] & 0x80) {
56      if (in[x] < 0x81 || in[x] > 0x83) {
57         return CRYPT_INVALID_PACKET;
58      }
59      y = in[x++] & 0x7F;
60
61      /* would reading the len bytes overrun? */
62      if (x + y > inlen) {
63         return CRYPT_INVALID_PACKET;
64      }
65
66      /* read len */
67      blksize = 0;
68      while (y--) {
69          blksize = (blksize << 8) | (unsigned long)in[x++];
70      }
71  }
72
73  /* would this blksize overflow? */
74  if (x + blksize > inlen) {
75     return CRYPT_INVALID_PACKET;
76  }
77
78   /* mark all as unused */
79   for (i = 0; i < outlen; i++) {
80       list[i].used = 0;
81   }
82
83  /* ok read data */
84   inlen = blksize;
85   for (i = 0; i < outlen; i++) {
86       z    = 0;
87       type = list[i].type;
88       size = list[i].size;
89       data = list[i].data;
90       if (!ordered && list[i].used == 1) { continue; }
91
92       if (type == LTC_ASN1_EOL) {
93          break;
94       }
95
96       switch (type) {
97           case LTC_ASN1_BOOLEAN:
98               z = inlen;
99               if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
100                   goto LBL_ERR;
101               }
102               if ((err = der_length_boolean(&z)) != CRYPT_OK) {
103                   goto LBL_ERR;
104                }
105                break;
106
107           case LTC_ASN1_INTEGER:
108               z = inlen;
109               if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
110                  if (!ordered) {  continue; }
111                  goto LBL_ERR;
112               }
113               if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
114                  goto LBL_ERR;
115               }
116               break;
117
118           case LTC_ASN1_SHORT_INTEGER:
119               z = inlen;
120               if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
121                  if (!ordered) { continue; }
122                  goto LBL_ERR;
123               }
124               if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
125                  goto LBL_ERR;
126               }
127
128               break;
129
130           case LTC_ASN1_BIT_STRING:
131               z = inlen;
132               if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
133                  if (!ordered) { continue; }
134                  goto LBL_ERR;
135               }
136               list[i].size = size;
137               if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
138                  goto LBL_ERR;
139               }
140               break;
141
142           case LTC_ASN1_OCTET_STRING:
143               z = inlen;
144               if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
145                  if (!ordered) { continue; }
146                  goto LBL_ERR;
147               }
148               list[i].size = size;
149               if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
150                  goto LBL_ERR;
151               }
152               break;
153
154           case LTC_ASN1_NULL:
155               if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
156                  if (!ordered) { continue; }
157                  err = CRYPT_INVALID_PACKET;
158                  goto LBL_ERR;
159               }
160               z = 2;
161               break;
162
163           case LTC_ASN1_OBJECT_IDENTIFIER:
164               z = inlen;
165               if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
166                  if (!ordered) { continue; }
167                  goto LBL_ERR;
168               }
169               list[i].size = size;
170               if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
171                  goto LBL_ERR;
172               }
173               break;
174
175           case LTC_ASN1_IA5_STRING:
176               z = inlen;
177               if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
178                  if (!ordered) { continue; }
179                  goto LBL_ERR;
180               }
181               list[i].size = size;
182               if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
183                  goto LBL_ERR;
184               }
185               break;
186
187
188           case LTC_ASN1_PRINTABLE_STRING:
189               z = inlen;
190               if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
191                  if (!ordered) { continue; }
192                  goto LBL_ERR;
193               }
194               list[i].size = size;
195               if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
196                  goto LBL_ERR;
197               }
198               break;
199
200           case LTC_ASN1_UTF8_STRING:
201               z = inlen;
202               if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
203                  if (!ordered) { continue; }
204                  goto LBL_ERR;
205               }
206               list[i].size = size;
207               if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
208                  goto LBL_ERR;
209               }
210               break;
211
212           case LTC_ASN1_UTCTIME:
213               z = inlen;
214               if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
215                  if (!ordered) { continue; }
216                  goto LBL_ERR;
217               }
218               break;
219
220           case LTC_ASN1_SET:
221               z = inlen;
222               if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
223                  if (!ordered) { continue; }
224                  goto LBL_ERR;
225               }
226               if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
227                  goto LBL_ERR;
228               }
229               break;
230
231           case LTC_ASN1_SETOF:
232           case LTC_ASN1_SEQUENCE:
233               /* detect if we have the right type */
234               if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
235                  err = CRYPT_INVALID_PACKET;
236                  goto LBL_ERR;
237               }
238
239               z = inlen;
240               if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) {
241                  if (!ordered) { continue; }
242                  goto LBL_ERR;
243               }
244               if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
245                  goto LBL_ERR;
246               }
247               break;
248
249
250           case LTC_ASN1_CHOICE:
251               z = inlen;
252               if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
253                  if (!ordered) { continue; }
254                  goto LBL_ERR;
255               }
256               break;
257
258           default:
259               err = CRYPT_INVALID_ARG;
260               goto LBL_ERR;
261       }
262       x           += z;
263       inlen       -= z;
264       list[i].used = 1;
265       if (!ordered) {
266          /* restart the decoder */
267          i = -1;
268       }
269   }
270
271   for (i = 0; i < outlen; i++) {
272      if (list[i].used == 0) {
273          err = CRYPT_INVALID_PACKET;
274          goto LBL_ERR;
275      }
276   }
277   err = CRYPT_OK;
278
279LBL_ERR:
280   return err;
281}
282
283#endif
284
285/* $Source: /cvs/libtom/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_ex.c,v $ */
286/* $Revision: 1.15 $ */
287/* $Date: 2006/11/26 02:25:18 $ */
288