tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

quickder.c (29918B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6    Optimized ASN.1 DER decoder
      7 */
      8 
      9 #include "secerr.h"
     10 #include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
     11 #include "secitem.h"
     12 
     13 /*
     14 * simple definite-length ASN.1 decoder
     15 */
     16 
     17 static unsigned char*
     18 definite_length_decoder(const unsigned char* buf,
     19                        const unsigned int buf_length,
     20                        unsigned int* out_data_length,
     21                        PRBool includeTag)
     22 {
     23    unsigned char tag;
     24    unsigned int used_length = 0;
     25    unsigned int data_length = 0;
     26    unsigned char length_field_len = 0;
     27    unsigned char byte;
     28    unsigned int i;
     29 
     30    if (used_length >= buf_length) {
     31        /* Tag field was not found! */
     32        return NULL;
     33    }
     34    tag = buf[used_length++];
     35 
     36    if (tag == 0) {
     37        /* End-of-contents octects should not be present in DER because
     38           DER doesn't use the indefinite length form. */
     39        return NULL;
     40    }
     41 
     42    if ((tag & 0x1F) == 0x1F) {
     43        /* High tag number (a tag number > 30) is not supported */
     44        return NULL;
     45    }
     46 
     47    if (used_length >= buf_length) {
     48        /* Length field was not found! */
     49        return NULL;
     50    }
     51    byte = buf[used_length++];
     52 
     53    if (!(byte & 0x80)) {
     54        /* Short form: The high bit is not set. */
     55        data_length = byte; /* clarity; we're returning a 32-bit int. */
     56    } else {
     57        /* Long form. Extract the field length */
     58        length_field_len = byte & 0x7F;
     59        if (length_field_len == 0) {
     60            /* DER doesn't use the indefinite length form. */
     61            return NULL;
     62        }
     63 
     64        if (length_field_len > sizeof(data_length)) {
     65            /* We don't support an extended length field  longer than
     66               4 bytes (2^32) */
     67            return NULL;
     68        }
     69 
     70        if (length_field_len > (buf_length - used_length)) {
     71            /* Extended length field was not found */
     72            return NULL;
     73        }
     74 
     75        /* Iterate across the extended length field */
     76        for (i = 0; i < length_field_len; i++) {
     77            byte = buf[used_length++];
     78            data_length = (data_length << 8) | byte;
     79 
     80            if (i == 0) {
     81                PRBool too_long = PR_FALSE;
     82                if (length_field_len == 1) {
     83                    too_long = ((byte & 0x80) == 0); /* Short form suffices */
     84                } else {
     85                    too_long = (byte == 0); /* This zero byte can be omitted */
     86                }
     87                if (too_long) {
     88                    /* The length is longer than needed. */
     89                    return NULL;
     90                }
     91            }
     92        }
     93    }
     94 
     95    if ((tag & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_NULL && data_length != 0) {
     96        /* The DER encoding of NULL has no contents octets */
     97        return NULL;
     98    }
     99 
    100    if (data_length > (buf_length - used_length)) {
    101        /* The decoded length exceeds the available buffer */
    102        return NULL;
    103    }
    104 
    105    if (includeTag) {
    106        data_length += used_length;
    107    }
    108 
    109    *out_data_length = data_length;
    110    return ((unsigned char*)buf + (includeTag ? 0 : used_length));
    111 }
    112 
    113 static SECStatus
    114 GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
    115 {
    116    if ((!src) || (!dest) || (!src->data && src->len)) {
    117        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    118        return SECFailure;
    119    }
    120 
    121    if (!src->len) {
    122        /* reaching the end of the buffer is not an error */
    123        dest->data = NULL;
    124        dest->len = 0;
    125        return SECSuccess;
    126    }
    127 
    128    dest->data = definite_length_decoder(src->data, src->len, &dest->len,
    129                                         includeTag);
    130    if (dest->data == NULL) {
    131        PORT_SetError(SEC_ERROR_BAD_DER);
    132        return SECFailure;
    133    }
    134    src->len -= (int)(dest->data - src->data) + dest->len;
    135    src->data = dest->data + dest->len;
    136    return SECSuccess;
    137 }
    138 
    139 /* check if the actual component's type matches the type in the template */
    140 
    141 static SECStatus
    142 MatchComponentType(const SEC_ASN1Template* templateEntry,
    143                   SECItem* item, PRBool* match, void* dest)
    144 {
    145    unsigned long kind = 0;
    146    unsigned char tag = 0;
    147 
    148    if ((!item) || (!item->data && item->len) || (!templateEntry) || (!match)) {
    149        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    150        return SECFailure;
    151    }
    152 
    153    if (!item->len) {
    154        *match = PR_FALSE;
    155        return SECSuccess;
    156    }
    157 
    158    kind = templateEntry->kind;
    159    tag = *(unsigned char*)item->data;
    160 
    161    if (((kind & SEC_ASN1_INLINE) ||
    162         (kind & SEC_ASN1_POINTER)) &&
    163        (0 == (kind & SEC_ASN1_TAG_MASK))) {
    164        /* These cases are special because the template's "kind" does not
    165           give us the information for the ASN.1 tag of the next item. It can
    166           only be figured out from the subtemplate. */
    167        if (!(kind & SEC_ASN1_OPTIONAL)) {
    168            /* This is a required component. If there is a type mismatch,
    169               the decoding of the subtemplate will fail, so assume this
    170               is a match at the parent level and let it fail later. This
    171               avoids a redundant check in matching cases */
    172            *match = PR_TRUE;
    173            return SECSuccess;
    174        } else {
    175            /* optional component. This is the hard case. Now we need to
    176               look at the subtemplate to get the expected kind */
    177            const SEC_ASN1Template* subTemplate =
    178                SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
    179            if (!subTemplate) {
    180                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
    181                return SECFailure;
    182            }
    183            if ((subTemplate->kind & SEC_ASN1_INLINE) ||
    184                (subTemplate->kind & SEC_ASN1_POINTER)) {
    185                /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
    186                   otherwise you may get a false positive due to the recursion
    187                   optimization above that always matches the type if the
    188                   component is required . Nesting these should never be
    189                   required, so that no one should miss this ability */
    190                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
    191                return SECFailure;
    192            }
    193            return MatchComponentType(subTemplate, item, match,
    194                                      (void*)((char*)dest + templateEntry->offset));
    195        }
    196    }
    197 
    198    if (kind & SEC_ASN1_CHOICE) {
    199        /* we need to check the component's tag against each choice's tag */
    200        /* XXX it would be nice to save the index of the choice here so that
    201           DecodeChoice wouldn't have to do this again. However, due to the
    202           recursivity of MatchComponentType, we don't know if we are in a
    203           required or optional component, so we can't write anywhere in
    204           the destination within this function */
    205        unsigned choiceIndex = 1;
    206        const SEC_ASN1Template* choiceEntry;
    207        while ((choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind)) {
    208            if ((SECSuccess == MatchComponentType(choiceEntry, item, match,
    209                                                  (void*)((char*)dest + choiceEntry->offset))) &&
    210                (PR_TRUE == *match)) {
    211                return SECSuccess;
    212            }
    213        }
    214        /* no match, caller must decide if this is BAD DER, or not. */
    215        *match = PR_FALSE;
    216        return SECSuccess;
    217    }
    218 
    219    if (kind & SEC_ASN1_ANY) {
    220        /* SEC_ASN1_ANY always matches */
    221        *match = PR_TRUE;
    222        return SECSuccess;
    223    }
    224 
    225    if ((0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
    226        (!(kind & SEC_ASN1_EXPLICIT)) &&
    227        (((kind & SEC_ASN1_SAVE) ||
    228          (kind & SEC_ASN1_SKIP)) &&
    229         (!(kind & SEC_ASN1_OPTIONAL)))) {
    230        /* when saving or skipping a required component,  a type is not
    231           required in the template. This is for legacy support of
    232           SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
    233           deprecate these usages and always require a type, as this
    234           disables type checking, and effectively forbids us from
    235           transparently ignoring optional components we aren't aware of */
    236        *match = PR_TRUE;
    237        return SECSuccess;
    238    }
    239 
    240    /* first, do a class check */
    241    if ((tag & SEC_ASN1_CLASS_MASK) !=
    242        (((unsigned char)kind) & SEC_ASN1_CLASS_MASK)) {
    243        /* this is only to help debugging of the decoder in case of problems */
    244        /* unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK; */
    245        /* unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK; */
    246        *match = PR_FALSE;
    247        return SECSuccess;
    248    }
    249 
    250    /* now do a tag check */
    251    if (((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
    252        (tag & SEC_ASN1_TAGNUM_MASK)) {
    253        *match = PR_FALSE;
    254        return SECSuccess;
    255    }
    256 
    257    /* now, do a method check. This depends on the class */
    258    switch (tag & SEC_ASN1_CLASS_MASK) {
    259        case SEC_ASN1_UNIVERSAL:
    260            /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
    261               primitive or constructed based on the tag */
    262            switch (tag & SEC_ASN1_TAGNUM_MASK) {
    263                case SEC_ASN1_SEQUENCE:
    264                case SEC_ASN1_SET:
    265                case SEC_ASN1_EMBEDDED_PDV:
    266                    /* this component must be a constructed type */
    267                    /* XXX add any new universal constructed type here */
    268                    if (tag & SEC_ASN1_CONSTRUCTED) {
    269                        *match = PR_TRUE;
    270                        return SECSuccess;
    271                    }
    272                    break;
    273 
    274                default:
    275                    /* this component must be a primitive type */
    276                    if (!(tag & SEC_ASN1_CONSTRUCTED)) {
    277                        *match = PR_TRUE;
    278                        return SECSuccess;
    279                    }
    280                    break;
    281            }
    282            break;
    283 
    284        default:
    285            /* for all other classes, we check the method based on the template */
    286            if ((unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
    287                (tag & SEC_ASN1_METHOD_MASK)) {
    288                *match = PR_TRUE;
    289                return SECSuccess;
    290            }
    291            /* method does not match between template and component */
    292            break;
    293    }
    294 
    295    *match = PR_FALSE;
    296    return SECSuccess;
    297 }
    298 
    299 #ifdef DEBUG
    300 
    301 static SECStatus
    302 CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
    303 {
    304    SECStatus rv = SECSuccess;
    305    const SEC_ASN1Template* sequenceEntry = NULL;
    306    unsigned long seqIndex = 0;
    307    unsigned long lastEntryIndex = 0;
    308    unsigned long ambiguityIndex = 0;
    309    PRBool foundAmbiguity = PR_FALSE;
    310 
    311    do {
    312        sequenceEntry = &sequenceTemplate[seqIndex++];
    313        if (sequenceEntry->kind) {
    314            /* ensure that we don't have an optional component of SEC_ASN1_ANY
    315               in the middle of the sequence, since we could not handle it */
    316            /* XXX this function needs to dig into the subtemplates to find
    317               the next tag */
    318            if ((PR_FALSE == foundAmbiguity) &&
    319                (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
    320                (sequenceEntry->kind & SEC_ASN1_ANY)) {
    321                foundAmbiguity = PR_TRUE;
    322                ambiguityIndex = seqIndex - 1;
    323            }
    324        }
    325    } while (sequenceEntry->kind);
    326 
    327    lastEntryIndex = seqIndex - 2;
    328 
    329    if (PR_FALSE != foundAmbiguity) {
    330        if (ambiguityIndex < lastEntryIndex) {
    331            /* ambiguity can only be tolerated on the last entry */
    332            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
    333            rv = SECFailure;
    334        }
    335    }
    336 
    337    /* XXX also enforce ASN.1 requirement that tags be
    338       distinct for consecutive optional components */
    339 
    340    return rv;
    341 }
    342 
    343 #endif
    344 
    345 static SECStatus DecodeItem(void* dest,
    346                            const SEC_ASN1Template* templateEntry,
    347                            SECItem* src, PLArenaPool* arena, PRBool checkTag);
    348 
    349 static SECStatus
    350 DecodeSequence(void* dest,
    351               const SEC_ASN1Template* templateEntry,
    352               SECItem* src, PLArenaPool* arena)
    353 {
    354    SECStatus rv = SECSuccess;
    355    SECItem source;
    356    SECItem sequence;
    357    const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
    358    const SEC_ASN1Template* sequenceEntry = NULL;
    359    unsigned long seqindex = 0;
    360 
    361 #ifdef DEBUG
    362    /* for a sequence, we need to validate the template. */
    363    rv = CheckSequenceTemplate(sequenceTemplate);
    364 #endif
    365 
    366    source = *src;
    367 
    368    /* get the sequence */
    369    if (SECSuccess == rv) {
    370        rv = GetItem(&source, &sequence, PR_FALSE);
    371    }
    372 
    373    /* process it */
    374    if (SECSuccess == rv)
    375        do {
    376            sequenceEntry = &sequenceTemplate[seqindex++];
    377            if ((sequenceEntry && sequenceEntry->kind) &&
    378                (sequenceEntry->kind != SEC_ASN1_SKIP_REST)) {
    379                rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
    380            }
    381        } while ((SECSuccess == rv) &&
    382                 (sequenceEntry->kind &&
    383                  sequenceEntry->kind != SEC_ASN1_SKIP_REST));
    384    /* we should have consumed all the bytes in the sequence by now
    385       unless the caller doesn't care about the rest of the sequence */
    386    if (SECSuccess == rv && sequence.len &&
    387        sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST) {
    388        /* it isn't 100% clear whether this is a bad DER or a bad template.
    389           The problem is that logically, they don't match - there is extra
    390           data in the DER that the template doesn't know about */
    391        PORT_SetError(SEC_ERROR_BAD_DER);
    392        rv = SECFailure;
    393    }
    394 
    395    return rv;
    396 }
    397 
    398 static SECStatus
    399 DecodeInline(void* dest,
    400             const SEC_ASN1Template* templateEntry,
    401             SECItem* src, PLArenaPool* arena, PRBool checkTag)
    402 {
    403    const SEC_ASN1Template* inlineTemplate =
    404        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
    405    return DecodeItem((void*)((char*)dest + templateEntry->offset),
    406                      inlineTemplate, src, arena, checkTag);
    407 }
    408 
    409 static SECStatus
    410 DecodePointer(void* dest,
    411              const SEC_ASN1Template* templateEntry,
    412              SECItem* src, PLArenaPool* arena, PRBool checkTag)
    413 {
    414    const SEC_ASN1Template* ptrTemplate =
    415        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
    416    if (!ptrTemplate) {
    417        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    418        return SECFailure;
    419    }
    420    void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
    421    *(void**)((char*)dest + templateEntry->offset) = subdata;
    422    if (subdata) {
    423        return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
    424    } else {
    425        PORT_SetError(SEC_ERROR_NO_MEMORY);
    426        return SECFailure;
    427    }
    428 }
    429 
    430 static SECStatus
    431 DecodeImplicit(void* dest,
    432               const SEC_ASN1Template* templateEntry,
    433               SECItem* src, PLArenaPool* arena)
    434 {
    435    if (templateEntry->kind & SEC_ASN1_POINTER) {
    436        return DecodePointer((void*)((char*)dest),
    437                             templateEntry, src, arena, PR_FALSE);
    438    } else {
    439        return DecodeInline((void*)((char*)dest),
    440                            templateEntry, src, arena, PR_FALSE);
    441    }
    442 }
    443 
    444 static SECStatus
    445 DecodeChoice(void* dest,
    446             const SEC_ASN1Template* templateEntry,
    447             SECItem* src, PLArenaPool* arena)
    448 {
    449    SECStatus rv = SECSuccess;
    450    SECItem choice;
    451    const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
    452    const SEC_ASN1Template* choiceEntry = NULL;
    453    unsigned long choiceindex = 0;
    454 
    455    /* XXX for a choice component, we should validate the template to make
    456       sure the tags are distinct, in debug builds. This hasn't been
    457       implemented yet */
    458    /* rv = CheckChoiceTemplate(sequenceTemplate); */
    459 
    460    /* process it */
    461    do {
    462        choice = *src;
    463        choiceEntry = &choiceTemplate[choiceindex++];
    464        if (choiceEntry->kind) {
    465            rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
    466        }
    467    } while ((SECFailure == rv) && (choiceEntry->kind));
    468 
    469    if (SECFailure == rv) {
    470        /* the component didn't match any of the choices */
    471        PORT_SetError(SEC_ERROR_BAD_DER);
    472    } else {
    473        /* set the type in the union here */
    474        int* which = (int*)((char*)dest + templateEntry->offset);
    475        *which = (int)choiceEntry->size;
    476    }
    477 
    478    /* we should have consumed all the bytes by now */
    479    /* fail if we have not */
    480    if (SECSuccess == rv && choice.len) {
    481        /* there is extra data that isn't listed in the template */
    482        PORT_SetError(SEC_ERROR_BAD_DER);
    483        rv = SECFailure;
    484    }
    485    return rv;
    486 }
    487 
    488 static SECStatus
    489 DecodeGroup(void* dest,
    490            const SEC_ASN1Template* templateEntry,
    491            SECItem* src, PLArenaPool* arena)
    492 {
    493    SECStatus rv = SECSuccess;
    494    SECItem source;
    495    SECItem group;
    496    PRUint32 totalEntries = 0;
    497    PRUint32 entryIndex = 0;
    498    void** entries = NULL;
    499 
    500    const SEC_ASN1Template* subTemplate =
    501        SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE);
    502 
    503    source = *src;
    504 
    505    /* get the group */
    506    if (SECSuccess == rv) {
    507        rv = GetItem(&source, &group, PR_FALSE);
    508    }
    509 
    510    /* XXX we should check the subtemplate in debug builds */
    511    if (SECSuccess == rv) {
    512        /* first, count the number of entries. Benchmarking showed that this
    513           counting pass is more efficient than trying to allocate entries as
    514           we read the DER, even if allocating many entries at a time
    515        */
    516        SECItem counter = group;
    517        do {
    518            SECItem anitem;
    519            rv = GetItem(&counter, &anitem, PR_TRUE);
    520            if (SECSuccess == rv && (anitem.len)) {
    521                totalEntries++;
    522            }
    523        } while ((SECSuccess == rv) && (counter.len));
    524 
    525        if (SECSuccess == rv) {
    526            /* allocate room for pointer array and entries */
    527            /* we want to allocate the array even if there is 0 entry */
    528            entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*) * (totalEntries + 1) + /* the extra one is for NULL termination */
    529                                                          subTemplate->size * totalEntries);
    530 
    531            if (entries) {
    532                entries[totalEntries] = NULL; /* terminate the array */
    533            } else {
    534                PORT_SetError(SEC_ERROR_NO_MEMORY);
    535                rv = SECFailure;
    536            }
    537            if (SECSuccess == rv) {
    538                void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*) * (totalEntries + 1));
    539                /* and fix the pointers in the array */
    540                PRUint32 entriesIndex = 0;
    541                for (entriesIndex = 0; entriesIndex < totalEntries; entriesIndex++) {
    542                    entries[entriesIndex] =
    543                        (char*)entriesData + (subTemplate->size * entriesIndex);
    544                }
    545            }
    546        }
    547    }
    548 
    549    if (SECSuccess == rv && totalEntries)
    550        do {
    551            if (!(entryIndex < totalEntries)) {
    552                rv = SECFailure;
    553                break;
    554            }
    555            rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
    556        } while ((SECSuccess == rv) && (group.len));
    557    /* we should be at the end of the set by now */
    558    /* save the entries where requested */
    559    memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
    560 
    561    return rv;
    562 }
    563 
    564 static SECStatus
    565 DecodeExplicit(void* dest,
    566               const SEC_ASN1Template* templateEntry,
    567               SECItem* src, PLArenaPool* arena)
    568 {
    569    SECStatus rv = SECSuccess;
    570    SECItem subItem;
    571    SECItem constructed = *src;
    572 
    573    rv = GetItem(&constructed, &subItem, PR_FALSE);
    574 
    575    if (SECSuccess == rv) {
    576        if (templateEntry->kind & SEC_ASN1_POINTER) {
    577            rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
    578        } else {
    579            rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
    580        }
    581    }
    582 
    583    return rv;
    584 }
    585 
    586 /* new decoder implementation. This is a recursive function */
    587 
    588 static SECStatus
    589 DecodeItem(void* dest,
    590           const SEC_ASN1Template* templateEntry,
    591           SECItem* src, PLArenaPool* arena, PRBool checkTag)
    592 {
    593    SECStatus rv = SECSuccess;
    594    SECItem temp;
    595    SECItem mark = { siBuffer, NULL, 0 };
    596    PRBool pop = PR_FALSE;
    597    PRBool decode = PR_TRUE;
    598    PRBool save = PR_FALSE;
    599    unsigned long kind;
    600    PRBool match = PR_TRUE;
    601 
    602    PR_ASSERT(src && dest && templateEntry && arena);
    603 #if 0
    604    if (!src || !dest || !templateEntry || !arena)
    605    {
    606        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    607        rv = SECFailure;
    608    }
    609 #endif
    610 
    611    if (SECSuccess == rv) {
    612        /* do the template validation */
    613        kind = templateEntry->kind;
    614        if (!kind) {
    615            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
    616            rv = SECFailure;
    617        }
    618    }
    619 
    620    if (SECSuccess == rv) {
    621 #ifdef DEBUG
    622        if (kind & SEC_ASN1_DEBUG_BREAK) {
    623            /* when debugging the decoder or a template that fails to
    624            decode, put SEC_ASN1_DEBUG in the component that gives you
    625            trouble. The decoder will then get to this block and assert.
    626            If you want to debug the rest of the code, you can set a
    627            breakpoint and set dontassert to PR_TRUE, which will let
    628            you skip over the assert and continue the debugging session
    629            past it. */
    630            PRBool dontassert = PR_FALSE;
    631            PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
    632        }
    633 #endif
    634 
    635        if ((kind & SEC_ASN1_SKIP) ||
    636            (kind & SEC_ASN1_SAVE)) {
    637            /* if skipping or saving this component, don't decode it */
    638            decode = PR_FALSE;
    639        }
    640 
    641        if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL)) {
    642            /* if saving this component, or if it is optional, we may not want to
    643               move past it, so save the position in case we have to rewind */
    644            mark = *src;
    645            if (kind & SEC_ASN1_SAVE) {
    646                save = PR_TRUE;
    647                if (0 == (kind & SEC_ASN1_SKIP)) {
    648                    /* we will for sure have to rewind when saving this
    649                       component and not skipping it. This is true for all
    650                       legacy uses of SEC_ASN1_SAVE where the following entry
    651                       in the template would causes the same component to be
    652                       processed again */
    653                    pop = PR_TRUE;
    654                }
    655            }
    656        }
    657 
    658        rv = GetItem(src, &temp, PR_TRUE);
    659    }
    660 
    661    if (SECSuccess == rv) {
    662        /* now check if the component matches what we expect in the template */
    663 
    664        if (PR_TRUE == checkTag)
    665 
    666        {
    667            rv = MatchComponentType(templateEntry, &temp, &match, dest);
    668        }
    669 
    670        if ((SECSuccess == rv) && (PR_TRUE != match)) {
    671            if (kind & SEC_ASN1_OPTIONAL) {
    672 
    673                /* the optional component is missing. This is not fatal. */
    674                /* Rewind, don't decode, and don't save */
    675                pop = PR_TRUE;
    676                decode = PR_FALSE;
    677                save = PR_FALSE;
    678            } else {
    679                /* a required component is missing. abort */
    680                PORT_SetError(SEC_ERROR_BAD_DER);
    681                rv = SECFailure;
    682            }
    683        }
    684    }
    685 
    686    if ((SECSuccess == rv) && (PR_TRUE == decode)) {
    687        /* the order of processing here is is the tricky part */
    688        /* we start with our special cases */
    689        /* first, check the component class */
    690        if (kind & SEC_ASN1_INLINE) {
    691            /* decode inline template */
    692            rv = DecodeInline(dest, templateEntry, &temp, arena, PR_TRUE);
    693        }
    694 
    695        else if (kind & SEC_ASN1_EXPLICIT) {
    696            rv = DecodeExplicit(dest, templateEntry, &temp, arena);
    697        } else if ((SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
    698 
    699                   (!(kind & SEC_ASN1_EXPLICIT))) {
    700 
    701            /* decode implicitly tagged components */
    702            rv = DecodeImplicit(dest, templateEntry, &temp, arena);
    703        } else if (kind & SEC_ASN1_POINTER) {
    704            rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
    705        } else if (kind & SEC_ASN1_CHOICE) {
    706            rv = DecodeChoice(dest, templateEntry, &temp, arena);
    707        } else if (kind & SEC_ASN1_ANY) {
    708            /* catch-all ANY type, don't decode */
    709            save = PR_TRUE;
    710            if (kind & SEC_ASN1_INNER) {
    711                /* skip the tag and length */
    712                SECItem newtemp = temp;
    713                rv = GetItem(&newtemp, &temp, PR_FALSE);
    714            }
    715        } else if (kind & SEC_ASN1_GROUP) {
    716            if ((SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
    717                (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK))) {
    718                rv = DecodeGroup(dest, templateEntry, &temp, arena);
    719            } else {
    720                /* a group can only be a SET OF or SEQUENCE OF */
    721                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
    722                rv = SECFailure;
    723            }
    724        } else if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) {
    725            /* plain SEQUENCE */
    726            rv = DecodeSequence(dest, templateEntry, &temp, arena);
    727        } else {
    728            /* handle all other types as "save" */
    729            /* we should only get here for primitive universal types */
    730            SECItem newtemp = temp;
    731            rv = GetItem(&newtemp, &temp, PR_FALSE);
    732            save = PR_TRUE;
    733            if ((SECSuccess == rv) &&
    734                SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK)) {
    735                unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
    736                if (temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
    737                                      tagnum == SEC_ASN1_INTEGER ||
    738                                      tagnum == SEC_ASN1_BIT_STRING ||
    739                                      tagnum == SEC_ASN1_OBJECT_ID ||
    740                                      tagnum == SEC_ASN1_ENUMERATED ||
    741                                      tagnum == SEC_ASN1_UTC_TIME ||
    742                                      tagnum == SEC_ASN1_GENERALIZED_TIME)) {
    743                    /* these types MUST have at least one content octet */
    744                    PORT_SetError(SEC_ERROR_BAD_DER);
    745                    rv = SECFailure;
    746                } else
    747                    switch (tagnum) {
    748                        /* special cases of primitive types */
    749                        case SEC_ASN1_INTEGER: {
    750                            SECItem* destItem = (SECItem*)((char*)dest +
    751                                                           templateEntry->offset);
    752                            if (destItem && (siUnsignedInteger == destItem->type)) {
    753                                /* A leading 0 is only allowed when a value
    754                                 * would otherwise be interpreted as negative. */
    755                                if (temp.len > 1 && temp.data[0] == 0) {
    756                                    temp.data++;
    757                                    temp.len--;
    758                                    if (!(temp.data[0] & 0x80)) {
    759                                        PORT_SetError(SEC_ERROR_BAD_DER);
    760                                        rv = SECFailure;
    761                                    }
    762                                }
    763                            }
    764                            break;
    765                        }
    766 
    767                        case SEC_ASN1_BIT_STRING: {
    768                            /* Can't be 8 or more spare bits, or any spare bits
    769                             * if there are no octets. */
    770                            if (temp.data[0] >= 8 || (temp.data[0] > 0 && temp.len == 1)) {
    771                                PORT_SetError(SEC_ERROR_BAD_DER);
    772                                rv = SECFailure;
    773                                break;
    774                            }
    775                            /* change the length in the SECItem to be the number
    776                               of bits */
    777                            temp.len = (temp.len - 1) * 8 - (temp.data[0] & 0x7);
    778                            temp.data++;
    779                            break;
    780                        }
    781 
    782                        default: {
    783                            break;
    784                        }
    785                    }
    786            }
    787        }
    788    }
    789 
    790    if ((SECSuccess == rv) && (PR_TRUE == save)) {
    791        SECItem* destItem = (SECItem*)((char*)dest + templateEntry->offset);
    792        if (destItem) {
    793            /* we leave the type alone in the destination SECItem.
    794               If part of the destination was allocated by the decoder, in
    795               cases of POINTER, SET OF and SEQUENCE OF, then type is set to
    796               siBuffer due to the use of PORT_ArenaZAlloc*/
    797            destItem->data = temp.len ? temp.data : NULL;
    798            destItem->len = temp.len;
    799        } else {
    800            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    801            rv = SECFailure;
    802        }
    803    }
    804 
    805    if (PR_TRUE == pop) {
    806        /* we don't want to move ahead, so restore the position */
    807        *src = mark;
    808    }
    809    return rv;
    810 }
    811 
    812 /* the function below is the public one */
    813 
    814 SECStatus
    815 SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
    816                       const SEC_ASN1Template* templateEntry,
    817                       const SECItem* src)
    818 {
    819    SECStatus rv = SECSuccess;
    820    SECItem newsrc;
    821 
    822    if (!arena || !templateEntry || !src) {
    823        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    824        rv = SECFailure;
    825    }
    826 
    827    if (SECSuccess == rv) {
    828        newsrc = *src;
    829        rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
    830        if (SECSuccess == rv && newsrc.len) {
    831            rv = SECFailure;
    832            PORT_SetError(SEC_ERROR_EXTRA_INPUT);
    833        }
    834    }
    835 
    836    return rv;
    837 }