Home | History | Annotate | Download | only in sequence
      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