1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 * LibTomCrypt is a library that provides various cryptographic
4 * algorithms in a highly modular and flexible manner.
6 * The library is free for all purposes without any express
12 @file der_decode_sequence_flexi.c
13 ASN.1 DER, decode an array of ASN.1 types with a flexi parser, Tom St Denis
18 static unsigned long _fetch_length(const unsigned char *in, unsigned long inlen, unsigned long *data_offset)
24 /* skip type and read len */
28 ++in; ++(*data_offset);
31 x = *in++; ++(*data_offset);
33 /* <128 means literal */
35 return x+*data_offset;
37 x &= 0x7F; /* the lower 7 bits are the length of the length */
40 /* len means len of len! */
41 if (x == 0 || x > 4 || x > inlen) {
48 z = (z<<8) | ((unsigned long)*in);
51 return z+*data_offset;
54 static int _new_element(ltc_asn1_list **l)
58 *l = XCALLOC(1, sizeof(ltc_asn1_list));
63 (*l)->next = XCALLOC(1, sizeof(ltc_asn1_list));
64 if ((*l)->next == NULL) {
67 (*l)->next->prev = *l;
74 ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
75 @param in The input buffer
76 @param inlen [in/out] The length of the input buffer and on output the amount of decoded data
77 @param out [out] A pointer to the linked list
78 @return CRYPT_OK on success.
80 int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
83 unsigned long err, type, len, totlen, data_offset, len_len;
86 LTC_ARGCHK(in != NULL);
87 LTC_ARGCHK(inlen != NULL);
88 LTC_ARGCHK(out != NULL);
95 if ((err = _new_element(&l)) != CRYPT_OK) {
100 /* scan the input and and get lengths and what not */
102 /* read the type byte */
106 len = _fetch_length(in, *inlen, &data_offset);
108 err = CRYPT_INVALID_PACKET;
113 if ((err = _new_element(&l)) != CRYPT_OK) {
117 if ((type & 0x20) && (type != 0x30) && (type != 0x31)) {
118 /* constructed, use the 'used' field to store the original identifier */
120 /* treat constructed elements like SETs */
123 else if ((type & 0xC0) == 0x80) {
124 /* context-specific, use the 'used' field to store the original identifier */
126 /* context-specific elements are treated as opaque data */
130 /* now switch on type */
132 case 0x01: /* BOOLEAN */
133 l->type = LTC_ASN1_BOOLEAN;
135 l->data = XCALLOC(1, sizeof(int));
137 if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) {
141 if ((err = der_length_boolean(&len)) != CRYPT_OK) {
146 case 0x02: /* INTEGER */
148 l->type = LTC_ASN1_INTEGER;
150 if ((err = mp_init(&l->data)) != CRYPT_OK) {
155 if ((err = der_decode_integer(in, *inlen, l->data)) != CRYPT_OK) {
159 /* calc length of object */
160 if ((err = der_length_integer(l->data, &len)) != CRYPT_OK) {
167 l->type = LTC_ASN1_BIT_STRING;
168 l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char. */
170 if ((l->data = XCALLOC(1, l->size)) == NULL) {
175 if ((err = der_decode_bit_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
179 if ((err = der_length_bit_string(l->size, &len)) != CRYPT_OK) {
184 case 0x04: /* OCTET */
187 l->type = LTC_ASN1_OCTET_STRING;
190 if ((l->data = XCALLOC(1, l->size)) == NULL) {
195 if ((err = der_decode_octet_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
199 if ((err = der_length_octet_string(l->size, &len)) != CRYPT_OK) {
204 case 0x05: /* NULL */
206 /* valid NULL is 0x05 0x00 */
207 if (in[0] != 0x05 || in[1] != 0x00) {
208 err = CRYPT_INVALID_PACKET;
212 /* simple to store ;-) */
213 l->type = LTC_ASN1_NULL;
223 l->type = LTC_ASN1_OBJECT_IDENTIFIER;
226 if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
231 if ((err = der_decode_object_identifier(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
235 if ((err = der_length_object_identifier(l->data, l->size, &len)) != CRYPT_OK) {
239 /* resize it to save a bunch of mem */
240 if ((realloc_tmp = XREALLOC(l->data, l->size * sizeof(unsigned long))) == NULL) {
241 /* out of heap but this is not an error */
244 l->data = realloc_tmp;
247 case 0x0C: /* UTF8 */
250 l->type = LTC_ASN1_UTF8_STRING;
253 if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
258 if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
262 if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
267 case 0x13: /* PRINTABLE */
270 l->type = LTC_ASN1_PRINTABLE_STRING;
273 if ((l->data = XCALLOC(1, l->size)) == NULL) {
278 if ((err = der_decode_printable_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
282 if ((err = der_length_printable_string(l->data, l->size, &len)) != CRYPT_OK) {
287 case 0x14: /* TELETEXT */
290 l->type = LTC_ASN1_TELETEX_STRING;
293 if ((l->data = XCALLOC(1, l->size)) == NULL) {
298 if ((err = der_decode_teletex_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
302 if ((err = der_length_teletex_string(l->data, l->size, &len)) != CRYPT_OK) {
310 l->type = LTC_ASN1_IA5_STRING;
313 if ((l->data = XCALLOC(1, l->size)) == NULL) {
318 if ((err = der_decode_ia5_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
322 if ((err = der_length_ia5_string(l->data, l->size, &len)) != CRYPT_OK) {
327 case 0x17: /* UTC TIME */
330 l->type = LTC_ASN1_UTCTIME;
333 if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
339 if ((err = der_decode_utctime(in, &len, l->data)) != CRYPT_OK) {
343 if ((err = der_length_utctime(l->data, &len)) != CRYPT_OK) {
349 l->type = LTC_ASN1_GENERALIZEDTIME;
352 if ((l->data = XCALLOC(1, sizeof(ltc_generalizedtime))) == NULL) {
357 if ((err = der_decode_generalizedtime(in, &len, l->data)) != CRYPT_OK) {
361 if ((err = der_length_generalizedtime(l->data, &len)) != CRYPT_OK) {
367 case 0x20: /* Any CONSTRUCTED element that is neither SEQUENCE nor SET */
368 case 0x30: /* SEQUENCE */
373 l->type = LTC_ASN1_CONSTRUCTED;
375 else if (type == 0x30) {
376 l->type = LTC_ASN1_SEQUENCE;
379 l->type = LTC_ASN1_SET;
382 if ((l->data = XMALLOC(len)) == NULL) {
387 XMEMCPY(l->data, in, len);
391 /* jump to the start of the data */
393 *inlen -= data_offset;
394 len = len - data_offset;
396 /* Sequence elements go as child */
397 if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
402 totlen += data_offset;
404 /* the flexi decoder can also do nothing, so make sure a child has been allocated */
406 /* link them up y0 */
407 l->child->parent = l;
412 while((t != NULL) && (t->child != NULL)) {
416 if (len_len > LTC_DER_MAX_RECURSION) {
423 case 0x80: /* Context-specific */
424 l->type = LTC_ASN1_CONTEXT_SPECIFIC;
426 if ((l->data = XCALLOC(1, len - data_offset)) == NULL) {
431 XMEMCPY(l->data, in + data_offset, len - data_offset);
432 l->size = len - data_offset;
437 /* invalid byte ... this is a soft error */
447 /* advance pointers */
455 /* in case we processed anything */
457 /* rewind l please */
458 while (l->prev != NULL || l->parent != NULL) {
459 if (l->parent != NULL) {
474 der_sequence_free(l);
482 /* ref: $Format:%D$ */
483 /* git commit: $Format:%H$ */
484 /* commit time: $Format:%ai$ */