diff nss/lib/util/quickder.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/util/quickder.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,897 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+    Optimized ASN.1 DER decoder
+    
+*/
+
+#include "secerr.h"
+#include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
+#include "secitem.h"
+
+/*
+ * simple definite-length ASN.1 decoder
+ */
+
+static unsigned char* definite_length_decoder(const unsigned char *buf,
+                                              const unsigned int length,
+                                              unsigned int *data_length,
+                                              PRBool includeTag)
+{
+    unsigned char tag;
+    unsigned int used_length= 0;
+    unsigned int data_len;
+
+    if (used_length >= length)
+    {
+        return NULL;
+    }
+    tag = buf[used_length++];
+
+    /* blow out when we come to the end */
+    if (tag == 0)
+    {
+        return NULL;
+    }
+
+    if (used_length >= length)
+    {
+        return NULL;
+    }
+    data_len = buf[used_length++];
+
+    if (data_len&0x80)
+    {
+        int  len_count = data_len & 0x7f;
+
+        data_len = 0;
+
+        while (len_count-- > 0)
+        {
+            if (used_length >= length)
+            {
+                return NULL;
+            }
+            data_len = (data_len << 8) | buf[used_length++];
+        }
+    }
+
+    if (data_len > (length-used_length) )
+    {
+        return NULL;
+    }
+    if (includeTag) data_len += used_length;
+
+    *data_length = data_len;
+    return ((unsigned char*)buf + (includeTag ? 0 : used_length));
+}
+
+static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
+{
+    if ( (!src) || (!dest) || (!src->data && src->len) )
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (!src->len)
+    {
+        /* reaching the end of the buffer is not an error */
+        dest->data = NULL;
+        dest->len = 0;
+        return SECSuccess;
+    }
+
+    dest->data = definite_length_decoder(src->data,  src->len, &dest->len,
+        includeTag);
+    if (dest->data == NULL)
+    {
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        return SECFailure;
+    }
+    src->len -= (dest->data - src->data) + dest->len;
+    src->data = dest->data + dest->len;
+    return SECSuccess;
+}
+
+/* check if the actual component's type matches the type in the template */
+
+static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
+                                    SECItem* item, PRBool* match, void* dest)
+{
+    unsigned long kind = 0;
+    unsigned char tag = 0;
+
+    if ( (!item) || (!item->data && item->len) || (!templateEntry) || (!match) )
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    if (!item->len)
+    {
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    kind = templateEntry->kind;
+    tag = *(unsigned char*) item->data;
+
+    if ( ( (kind & SEC_ASN1_INLINE) ||
+           (kind & SEC_ASN1_POINTER) ) &&
+           (0 == (kind & SEC_ASN1_TAG_MASK) ) )
+    {
+        /* These cases are special because the template's "kind" does not
+           give us the information for the ASN.1 tag of the next item. It can
+           only be figured out from the subtemplate. */
+        if (!(kind & SEC_ASN1_OPTIONAL))
+        {
+            /* This is a required component. If there is a type mismatch,
+               the decoding of the subtemplate will fail, so assume this
+               is a match at the parent level and let it fail later. This
+               avoids a redundant check in matching cases */
+            *match = PR_TRUE;
+            return SECSuccess;
+        }
+        else
+        {
+            /* optional component. This is the hard case. Now we need to
+               look at the subtemplate to get the expected kind */
+            const SEC_ASN1Template* subTemplate = 
+                SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+            if (!subTemplate)
+            {
+                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+                return SECFailure;
+            }
+            if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
+                 (subTemplate->kind & SEC_ASN1_POINTER) )
+            {
+                /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
+                   otherwise you may get a false positive due to the recursion
+                   optimization above that always matches the type if the
+                   component is required . Nesting these should never be
+                   required, so that no one should miss this ability */
+                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+                return SECFailure;
+            }
+            return MatchComponentType(subTemplate, item, match,
+                                      (void*)((char*)dest + templateEntry->offset));
+        }
+    }
+
+    if (kind & SEC_ASN1_CHOICE)
+    {
+        /* we need to check the component's tag against each choice's tag */
+        /* XXX it would be nice to save the index of the choice here so that
+           DecodeChoice wouldn't have to do this again. However, due to the
+           recursivity of MatchComponentType, we don't know if we are in a
+           required or optional component, so we can't write anywhere in
+           the destination within this function */
+        unsigned choiceIndex = 1;
+        const SEC_ASN1Template* choiceEntry;
+        while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
+        {
+            if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
+                                (void*)((char*)dest + choiceEntry->offset))) &&
+                 (PR_TRUE == *match) )
+            {
+                return SECSuccess;
+            }
+        }
+	/* no match, caller must decide if this is BAD DER, or not. */
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    if (kind & SEC_ASN1_ANY)
+    {
+        /* SEC_ASN1_ANY always matches */
+        *match = PR_TRUE;
+        return SECSuccess;
+    }
+
+    if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
+         (!(kind & SEC_ASN1_EXPLICIT)) &&
+         ( ( (kind & SEC_ASN1_SAVE) ||
+             (kind & SEC_ASN1_SKIP) ) &&
+           (!(kind & SEC_ASN1_OPTIONAL)) 
+         )
+       )
+    {
+        /* when saving or skipping a required component,  a type is not
+           required in the template. This is for legacy support of
+           SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
+           deprecate these usages and always require a type, as this
+           disables type checking, and effectively forbids us from
+           transparently ignoring optional components we aren't aware of */
+        *match = PR_TRUE;
+        return SECSuccess;
+    }
+
+    /* first, do a class check */
+    if ( (tag & SEC_ASN1_CLASS_MASK) !=
+         (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
+    {
+#ifdef DEBUG
+        /* this is only to help debugging of the decoder in case of problems */
+        unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
+        unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
+        tagclass = tagclass;
+        expectedclass = expectedclass;
+#endif
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    /* now do a tag check */
+    if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
+         (tag & SEC_ASN1_TAGNUM_MASK))
+    {
+        *match = PR_FALSE;
+        return SECSuccess;
+    }
+
+    /* now, do a method check. This depends on the class */
+    switch (tag & SEC_ASN1_CLASS_MASK)
+    {
+    case SEC_ASN1_UNIVERSAL:
+        /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
+           primitive or constructed based on the tag */
+        switch (tag & SEC_ASN1_TAGNUM_MASK)
+        {
+        case SEC_ASN1_SEQUENCE:
+        case SEC_ASN1_SET:
+        case SEC_ASN1_EMBEDDED_PDV:
+            /* this component must be a constructed type */
+            /* XXX add any new universal constructed type here */
+            if (tag & SEC_ASN1_CONSTRUCTED)
+            {
+                *match = PR_TRUE;
+                return SECSuccess;
+            }
+            break;
+
+        default:
+            /* this component must be a primitive type */
+            if (! (tag & SEC_ASN1_CONSTRUCTED))
+            {
+                *match = PR_TRUE;
+                return SECSuccess;
+            }
+            break;
+        }
+        break;
+
+    default:
+        /* for all other classes, we check the method based on the template */
+        if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
+             (tag & SEC_ASN1_METHOD_MASK) )
+        {
+            *match = PR_TRUE;
+            return SECSuccess;
+        }
+        /* method does not match between template and component */
+        break;
+    }
+
+    *match = PR_FALSE;
+    return SECSuccess;
+}
+
+#ifdef DEBUG
+
+static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
+{
+    SECStatus rv = SECSuccess;
+    const SEC_ASN1Template* sequenceEntry = NULL;
+    unsigned long seqIndex = 0;
+    unsigned long lastEntryIndex = 0;
+    unsigned long ambiguityIndex = 0;
+    PRBool foundAmbiguity = PR_FALSE;
+
+    do
+    {
+        sequenceEntry = &sequenceTemplate[seqIndex++];
+        if (sequenceEntry->kind)
+        {
+            /* ensure that we don't have an optional component of SEC_ASN1_ANY
+               in the middle of the sequence, since we could not handle it */
+            /* XXX this function needs to dig into the subtemplates to find
+               the next tag */
+            if ( (PR_FALSE == foundAmbiguity) &&
+                 (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
+                 (sequenceEntry->kind & SEC_ASN1_ANY) )
+            {
+                foundAmbiguity = PR_TRUE;
+                ambiguityIndex = seqIndex - 1;
+            }
+        }
+    } while (sequenceEntry->kind);
+
+    lastEntryIndex = seqIndex - 2;
+
+    if (PR_FALSE != foundAmbiguity)
+    {
+        if (ambiguityIndex < lastEntryIndex)
+        {
+            /* ambiguity can only be tolerated on the last entry */
+            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+            rv = SECFailure;
+        }
+    }
+
+    /* XXX also enforce ASN.1 requirement that tags be
+       distinct for consecutive optional components */
+
+    return rv;
+}
+
+#endif
+
+static SECStatus DecodeItem(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena, PRBool checkTag);
+
+static SECStatus DecodeSequence(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem source;
+    SECItem sequence;
+    const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
+    const SEC_ASN1Template* sequenceEntry = NULL;
+    unsigned long seqindex = 0;
+
+#ifdef DEBUG
+    /* for a sequence, we need to validate the template. */
+    rv = CheckSequenceTemplate(sequenceTemplate);
+#endif
+
+    source = *src;
+
+    /* get the sequence */
+    if (SECSuccess == rv)
+    {
+        rv = GetItem(&source, &sequence, PR_FALSE);
+    }
+
+    /* process it */
+    if (SECSuccess == rv)
+    do
+    {
+        sequenceEntry = &sequenceTemplate[seqindex++];
+        if ( (sequenceEntry && sequenceEntry->kind) &&
+             (sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
+        {
+            rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
+        }
+    } while ( (SECSuccess == rv) &&
+              (sequenceEntry->kind &&
+               sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
+    /* we should have consumed all the bytes in the sequence by now
+       unless the caller doesn't care about the rest of the sequence */
+    if (SECSuccess == rv && sequence.len &&
+        sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
+    {
+        /* it isn't 100% clear whether this is a bad DER or a bad template.
+           The problem is that logically, they don't match - there is extra
+           data in the DER that the template doesn't know about */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        rv = SECFailure;
+    }
+
+    return rv;
+}
+
+static SECStatus DecodeInline(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena, PRBool checkTag)
+{
+    const SEC_ASN1Template* inlineTemplate = 
+        SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+    return DecodeItem((void*)((char*)dest + templateEntry->offset),
+                            inlineTemplate, src, arena, checkTag);
+}
+
+static SECStatus DecodePointer(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena, PRBool checkTag)
+{
+    const SEC_ASN1Template* ptrTemplate = 
+        SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+    void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
+    *(void**)((char*)dest + templateEntry->offset) = subdata;
+    if (subdata)
+    {
+        return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
+    }
+    else
+    {
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
+        return SECFailure;
+    }
+}
+
+static SECStatus DecodeImplicit(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena)
+{
+    if (templateEntry->kind & SEC_ASN1_POINTER)
+    {
+        return DecodePointer((void*)((char*)dest ),
+                             templateEntry, src, arena, PR_FALSE);
+    }
+    else
+    {
+        return DecodeInline((void*)((char*)dest ),
+                             templateEntry, src, arena, PR_FALSE);
+    }
+}
+
+static SECStatus DecodeChoice(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem choice;
+    const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
+    const SEC_ASN1Template* choiceEntry = NULL;
+    unsigned long choiceindex = 0;
+
+    /* XXX for a choice component, we should validate the template to make
+       sure the tags are distinct, in debug builds. This hasn't been
+       implemented yet */
+    /* rv = CheckChoiceTemplate(sequenceTemplate); */
+
+    /* process it */
+    do
+    {
+        choice = *src;
+        choiceEntry = &choiceTemplate[choiceindex++];
+        if (choiceEntry->kind)
+        {
+            rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
+        }
+    } while ( (SECFailure == rv) && (choiceEntry->kind));
+
+    if (SECFailure == rv)
+    {
+        /* the component didn't match any of the choices */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+    }
+    else
+    {
+        /* set the type in the union here */
+        int *which = (int *)((char *)dest + templateEntry->offset);
+        *which = (int)choiceEntry->size;
+    }
+
+    /* we should have consumed all the bytes by now */
+    /* fail if we have not */
+    if (SECSuccess == rv && choice.len)
+    {
+        /* there is extra data that isn't listed in the template */
+        PORT_SetError(SEC_ERROR_BAD_DER);
+        rv = SECFailure;
+    }
+    return rv;
+}
+
+static SECStatus DecodeGroup(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem source;
+    SECItem group;
+    PRUint32 totalEntries = 0;
+    PRUint32 entryIndex = 0;
+    void** entries = NULL;
+
+    const SEC_ASN1Template* subTemplate =
+        SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+
+    source = *src;
+
+    /* get the group */
+    if (SECSuccess == rv)
+    {
+        rv = GetItem(&source, &group, PR_FALSE);
+    }
+
+    /* XXX we should check the subtemplate in debug builds */
+    if (SECSuccess == rv)
+    {
+        /* first, count the number of entries. Benchmarking showed that this
+           counting pass is more efficient than trying to allocate entries as
+           we read the DER, even if allocating many entries at a time
+        */
+        SECItem counter = group;
+        do
+        {
+            SECItem anitem;
+            rv = GetItem(&counter, &anitem, PR_TRUE);
+            if (SECSuccess == rv && (anitem.len) )
+            {
+                totalEntries++;
+            }
+        }  while ( (SECSuccess == rv) && (counter.len) );
+
+        if (SECSuccess == rv)
+        {
+            /* allocate room for pointer array and entries */
+            /* we want to allocate the array even if there is 0 entry */
+            entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
+                                          (totalEntries + 1 ) + /* the extra one is for NULL termination */
+                                          subTemplate->size*totalEntries); 
+
+            if (entries)
+            {
+                entries[totalEntries] = NULL; /* terminate the array */
+            }
+            else
+            {
+                PORT_SetError(SEC_ERROR_NO_MEMORY);
+                rv = SECFailure;
+            }
+            if (SECSuccess == rv)
+            {
+                void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
+                /* and fix the pointers in the array */
+                PRUint32 entriesIndex = 0;
+                for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
+                {
+                    entries[entriesIndex] =
+                        (char*)entriesData + (subTemplate->size*entriesIndex);
+                }
+            }
+        }
+    }
+
+    if (SECSuccess == rv && totalEntries)
+    do
+    {
+        if (!(entryIndex<totalEntries))
+        {
+            rv = SECFailure;
+            break;
+        }
+        rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
+    } while ( (SECSuccess == rv) && (group.len) );
+    /* we should be at the end of the set by now */    
+    /* save the entries where requested */
+    memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
+
+    return rv;
+}
+
+static SECStatus DecodeExplicit(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena)
+{
+    SECStatus rv = SECSuccess;
+    SECItem subItem;
+    SECItem constructed = *src;
+
+    rv = GetItem(&constructed, &subItem, PR_FALSE);
+
+    if (SECSuccess == rv)
+    {
+        if (templateEntry->kind & SEC_ASN1_POINTER)
+        {
+            rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
+        }
+        else
+        {
+            rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
+        }
+    }
+
+    return rv;
+}
+
+/* new decoder implementation. This is a recursive function */
+
+static SECStatus DecodeItem(void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     SECItem* src, PLArenaPool* arena, PRBool checkTag)
+{
+    SECStatus rv = SECSuccess;
+    SECItem temp;
+    SECItem mark;
+    PRBool pop = PR_FALSE;
+    PRBool decode = PR_TRUE;
+    PRBool save = PR_FALSE;
+    unsigned long kind;
+    PRBool match = PR_TRUE;
+    PRBool optional = PR_FALSE;
+
+    PR_ASSERT(src && dest && templateEntry && arena);
+#if 0
+    if (!src || !dest || !templateEntry || !arena)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        rv = SECFailure;
+    }
+#endif
+
+    if (SECSuccess == rv)
+    {
+        /* do the template validation */
+        kind = templateEntry->kind;
+        optional = (0 != (kind & SEC_ASN1_OPTIONAL));
+        if (!kind)
+        {
+            PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+            rv = SECFailure;
+        }
+    }
+
+    if (SECSuccess == rv)
+    {
+#ifdef DEBUG
+        if (kind & SEC_ASN1_DEBUG_BREAK)
+        {
+            /* when debugging the decoder or a template that fails to
+            decode, put SEC_ASN1_DEBUG in the component that gives you
+            trouble. The decoder will then get to this block and assert.
+            If you want to debug the rest of the code, you can set a
+            breakpoint and set dontassert to PR_TRUE, which will let
+            you skip over the assert and continue the debugging session
+            past it. */
+            PRBool dontassert = PR_FALSE;
+            PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
+        }
+#endif
+
+        if ((kind & SEC_ASN1_SKIP) ||
+            (kind & SEC_ASN1_SAVE))
+        {
+            /* if skipping or saving this component, don't decode it */
+            decode = PR_FALSE;
+        }
+    
+        if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
+        {
+            /* if saving this component, or if it is optional, we may not want to
+               move past it, so save the position in case we have to rewind */
+            mark = *src;
+            if (kind & SEC_ASN1_SAVE)
+            {
+                save = PR_TRUE;
+                if (0 == (kind & SEC_ASN1_SKIP))
+                {
+                    /* we will for sure have to rewind when saving this
+                       component and not skipping it. This is true for all
+                       legacy uses of SEC_ASN1_SAVE where the following entry
+                       in the template would causes the same component to be
+                       processed again */
+                    pop = PR_TRUE;
+                }
+            }
+        }
+
+        rv = GetItem(src, &temp, PR_TRUE);
+    }
+
+    if (SECSuccess == rv)
+    {
+        /* now check if the component matches what we expect in the template */
+
+        if (PR_TRUE == checkTag)
+
+        {
+            rv = MatchComponentType(templateEntry, &temp, &match, dest);
+        }
+
+        if ( (SECSuccess == rv) && (PR_TRUE != match) )
+        {
+            if (kind & SEC_ASN1_OPTIONAL)
+            {
+
+                /* the optional component is missing. This is not fatal. */
+                /* Rewind, don't decode, and don't save */
+                pop = PR_TRUE;
+                decode = PR_FALSE;
+                save = PR_FALSE;
+            }
+            else
+            {
+                /* a required component is missing. abort */
+                PORT_SetError(SEC_ERROR_BAD_DER);
+                rv = SECFailure;
+            }
+        }
+    }
+
+    if ((SECSuccess == rv) && (PR_TRUE == decode))
+    {
+        /* the order of processing here is is the tricky part */
+        /* we start with our special cases */
+        /* first, check the component class */
+        if (kind & SEC_ASN1_INLINE)
+        {
+            /* decode inline template */
+            rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
+        }
+
+        else
+        if (kind & SEC_ASN1_EXPLICIT)
+        {
+            rv = DecodeExplicit(dest, templateEntry, &temp, arena);
+        }
+        else
+        if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
+
+              (!(kind & SEC_ASN1_EXPLICIT)))
+        {
+
+            /* decode implicitly tagged components */
+            rv = DecodeImplicit(dest, templateEntry, &temp , arena);
+        }
+        else
+        if (kind & SEC_ASN1_POINTER)
+        {
+            rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
+        }
+        else
+        if (kind & SEC_ASN1_CHOICE)
+        {
+            rv = DecodeChoice(dest, templateEntry, &temp, arena);
+        }
+        else
+        if (kind & SEC_ASN1_ANY)
+        {
+            /* catch-all ANY type, don't decode */
+            save = PR_TRUE;
+            if (kind & SEC_ASN1_INNER)
+            {
+                /* skip the tag and length */
+                SECItem newtemp = temp;
+                rv = GetItem(&newtemp, &temp, PR_FALSE);
+            }
+        }
+        else
+        if (kind & SEC_ASN1_GROUP)
+        {
+            if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
+                 (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
+            {
+                rv = DecodeGroup(dest, templateEntry, &temp , arena);
+            }
+            else
+            {
+                /* a group can only be a SET OF or SEQUENCE OF */
+                PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+                rv = SECFailure;
+            }
+        }
+        else
+        if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
+        {
+            /* plain SEQUENCE */
+            rv = DecodeSequence(dest, templateEntry, &temp , arena);
+        }
+        else
+        {
+            /* handle all other types as "save" */
+            /* we should only get here for primitive universal types */
+            SECItem newtemp = temp;
+            rv = GetItem(&newtemp, &temp, PR_FALSE);
+            save = PR_TRUE;
+            if ((SECSuccess == rv) &&
+                SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
+            {
+                unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
+                if ( temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
+                                       tagnum == SEC_ASN1_INTEGER ||
+                                       tagnum == SEC_ASN1_BIT_STRING ||
+                                       tagnum == SEC_ASN1_OBJECT_ID ||
+                                       tagnum == SEC_ASN1_ENUMERATED ||
+                                       tagnum == SEC_ASN1_UTC_TIME ||
+                                       tagnum == SEC_ASN1_GENERALIZED_TIME) )
+                {
+                    /* these types MUST have at least one content octet */
+                    PORT_SetError(SEC_ERROR_BAD_DER);
+                    rv = SECFailure;
+                }
+                else
+                switch (tagnum)
+                {
+                /* special cases of primitive types */
+                case SEC_ASN1_INTEGER:
+                    {
+                        /* remove leading zeroes if the caller requested
+                           siUnsignedInteger
+                           This is to allow RSA key operations to work */
+                        SECItem* destItem = (SECItem*) ((char*)dest +
+                                            templateEntry->offset);
+                        if (destItem && (siUnsignedInteger == destItem->type))
+                        {
+                            while (temp.len > 1 && temp.data[0] == 0)
+                            {              /* leading 0 */
+                                temp.data++;
+                                temp.len--;
+                            }
+                        }
+                        break;
+                    }
+
+                case SEC_ASN1_BIT_STRING:
+                    {
+                        /* change the length in the SECItem to be the number
+                           of bits */
+                        temp.len = (temp.len-1)*8 - (temp.data[0] & 0x7);
+                        temp.data++;
+                        break;
+                    }
+
+                default:
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    if ((SECSuccess == rv) && (PR_TRUE == save))
+    {
+        SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
+        if (destItem)
+        {
+            /* we leave the type alone in the destination SECItem.
+               If part of the destination was allocated by the decoder, in
+               cases of POINTER, SET OF and SEQUENCE OF, then type is set to
+               siBuffer due to the use of PORT_ArenaZAlloc*/
+            destItem->data = temp.len ? temp.data : NULL;
+            destItem->len = temp.len;
+        }
+        else
+        {
+            PORT_SetError(SEC_ERROR_INVALID_ARGS);
+            rv = SECFailure;
+        }
+    }
+
+    if (PR_TRUE == pop)
+    {
+        /* we don't want to move ahead, so restore the position */
+        *src = mark;
+    }
+    return rv;
+}
+
+/* the function below is the public one */
+
+SECStatus SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
+                     const SEC_ASN1Template* templateEntry,
+                     const SECItem* src)
+{
+    SECStatus rv = SECSuccess;
+    SECItem newsrc;
+
+    if (!arena || !templateEntry || !src)
+    {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        rv = SECFailure;
+    }
+
+    if (SECSuccess == rv)
+    {
+        newsrc = *src;
+        rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
+        if (SECSuccess == rv && newsrc.len)
+        {
+            rv = SECFailure;
+            PORT_SetError(SEC_ERROR_EXTRA_INPUT);
+        }
+    }
+
+    return rv;
+}
+
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)