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 (at) 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 $ */ 387