Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Enumerations | Functions | Variables
secasn1d.c File Reference
#include "secasn1.h"
#include "secerr.h"

Go to the source code of this file.

Classes

struct  subitem
struct  sec_asn1d_state_struct
struct  sec_DecoderContext_struct

Defines

#define IS_HIGH_TAG_NUMBER(n)   ((n) == SEC_ASN1_HIGH_TAG_NUMBER)
#define LAST_TAG_NUMBER_BYTE(b)   (((b) & 0x80) == 0)
#define TAG_NUMBER_BITS   7
#define TAG_NUMBER_MASK   0x7f
#define LENGTH_IS_SHORT_FORM(b)   (((b) & 0x80) == 0)
#define LONG_FORM_LENGTH(b)   ((b) & 0x7f)
#define HIGH_BITS(field, cnt)   ((field) >> ((sizeof(field) * 8) - (cnt)))

Typedefs

typedef struct
sec_asn1d_state_struct 
sec_asn1d_state

Enumerations

enum  sec_asn1d_parse_place {
  beforeIdentifier, duringIdentifier, afterIdentifier, beforeLength,
  duringLength, afterLength, beforeBitString, duringBitString,
  duringConstructedString, duringGroup, duringLeaf, duringSaveEncoding,
  duringSequence, afterConstructedString, afterGroup, afterExplicit,
  afterImplicit, afterInline, afterPointer, afterSaveEncoding,
  beforeEndOfContents, duringEndOfContents, afterEndOfContents, beforeChoice,
  duringChoice, afterChoice, notInUse, beforeIdentifier,
  duringIdentifier, afterIdentifier, beforeLength, duringLength,
  afterLength, beforeBitString, duringBitString, duringConstructedString,
  duringGroup, duringLeaf, duringSaveEncoding, duringSequence,
  afterConstructedString, afterGroup, afterExplicit, afterImplicit,
  afterInline, afterPointer, afterSaveEncoding, beforeEndOfContents,
  duringEndOfContents, afterEndOfContents, beforeChoice, duringChoice,
  afterChoice, notInUse
}
enum  sec_asn1d_parse_status {
  allDone, decodeError, keepGoing, needBytes,
  allDone, decodeError, keepGoing, needBytes
}

Functions

static voidsec_asn1d_alloc (PRArenaPool *poolp, unsigned long len)
static voidsec_asn1d_zalloc (PRArenaPool *poolp, unsigned long len)
static sec_asn1d_statesec_asn1d_push_state (SEC_ASN1DecoderContext *cx, const SEC_ASN1Template *theTemplate, void *dest, PRBool new_depth)
static void sec_asn1d_scrub_state (sec_asn1d_state *state)
static void sec_asn1d_notify_before (SEC_ASN1DecoderContext *cx, void *dest, int depth)
static void sec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth)
static sec_asn1d_statesec_asn1d_init_state_based_on_template (sec_asn1d_state *state)
static sec_asn1d_statesec_asn1d_get_enclosing_construct (sec_asn1d_state *state)
static PRBool sec_asn1d_parent_allows_EOC (sec_asn1d_state *state)
static unsigned long sec_asn1d_parse_identifier (sec_asn1d_state *state, const char *buf, unsigned long len)
static unsigned long sec_asn1d_parse_more_identifier (sec_asn1d_state *state, const char *buf, unsigned long len)
static void sec_asn1d_confirm_identifier (sec_asn1d_state *state)
static unsigned long sec_asn1d_parse_length (sec_asn1d_state *state, const char *buf, unsigned long len)
static unsigned long sec_asn1d_parse_more_length (sec_asn1d_state *state, const char *buf, unsigned long len)
static void sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
static void sec_asn1d_free_child (sec_asn1d_state *state, PRBool error)
static void sec_asn1d_reuse_encoding (sec_asn1d_state *state)
static unsigned long sec_asn1d_parse_leaf (sec_asn1d_state *state, const char *buf, unsigned long len)
static unsigned long sec_asn1d_parse_bit_string (sec_asn1d_state *state, const char *buf, unsigned long len)
static unsigned long sec_asn1d_parse_more_bit_string (sec_asn1d_state *state, const char *buf, unsigned long len)
static struct subitemsec_asn1d_add_to_subitems (sec_asn1d_state *state, const void *data, unsigned long len, PRBool copy_data)
static void sec_asn1d_record_any_header (sec_asn1d_state *state, const char *buf, unsigned long len)
static void sec_asn1d_next_substring (sec_asn1d_state *state)
static void sec_asn1d_next_in_group (sec_asn1d_state *state)
static void sec_asn1d_next_in_sequence (sec_asn1d_state *state)
static void sec_asn1d_concat_substrings (sec_asn1d_state *state)
static void sec_asn1d_concat_group (sec_asn1d_state *state)
static void sec_asn1d_absorb_child (sec_asn1d_state *state)
static void sec_asn1d_prepare_for_end_of_contents (sec_asn1d_state *state)
static unsigned long sec_asn1d_parse_end_of_contents (sec_asn1d_state *state, const char *buf, unsigned long len)
static void sec_asn1d_pop_state (sec_asn1d_state *state)
static sec_asn1d_statesec_asn1d_before_choice (sec_asn1d_state *state)
static sec_asn1d_statesec_asn1d_during_choice (sec_asn1d_state *state)
static void sec_asn1d_after_choice (sec_asn1d_state *state)
unsigned long sec_asn1d_uinteger (SECItem *src)
SECStatus SEC_ASN1DecodeInteger (SECItem *src, unsigned long *value)
SECStatus SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx, const char *buf, unsigned long len)
SECStatus SEC_ASN1DecoderFinish (SEC_ASN1DecoderContext *cx)
SEC_ASN1DecoderContext * SEC_ASN1DecoderStart (PRArenaPool *their_pool, void *dest, const SEC_ASN1Template *theTemplate)
void SEC_ASN1DecoderSetFilterProc (SEC_ASN1DecoderContext *cx, SEC_ASN1WriteProc fn, void *arg, PRBool only)
void SEC_ASN1DecoderClearFilterProc (SEC_ASN1DecoderContext *cx)
void SEC_ASN1DecoderSetNotifyProc (SEC_ASN1DecoderContext *cx, SEC_ASN1NotifyProc fn, void *arg)
void SEC_ASN1DecoderClearNotifyProc (SEC_ASN1DecoderContext *cx)
void SEC_ASN1DecoderAbort (SEC_ASN1DecoderContext *cx, int error)
SECStatus SEC_ASN1Decode (PRArenaPool *poolp, void *dest, const SEC_ASN1Template *theTemplate, const char *buf, long len)
SECStatus SEC_ASN1DecodeItem (PRArenaPool *poolp, void *dest, const SEC_ASN1Template *theTemplate, const SECItem *src)

Variables

const SEC_ASN1Template SEC_AnyTemplate []
const SEC_ASN1Template SEC_PointerToAnyTemplate []
const SEC_ASN1Template SEC_SequenceOfAnyTemplate []
const SEC_ASN1Template SEC_SetOfAnyTemplate []
const SEC_ASN1Template SEC_BitStringTemplate []
const SEC_ASN1Template SEC_PointerToBitStringTemplate []
const SEC_ASN1Template SEC_SequenceOfBitStringTemplate []
const SEC_ASN1Template SEC_SetOfBitStringTemplate []
const SEC_ASN1Template SEC_BMPStringTemplate []
const SEC_ASN1Template SEC_PointerToBMPStringTemplate []
const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate []
const SEC_ASN1Template SEC_SetOfBMPStringTemplate []
const SEC_ASN1Template SEC_BooleanTemplate []
const SEC_ASN1Template SEC_PointerToBooleanTemplate []
const SEC_ASN1Template SEC_SequenceOfBooleanTemplate []
const SEC_ASN1Template SEC_SetOfBooleanTemplate []
const SEC_ASN1Template SEC_EnumeratedTemplate []
const SEC_ASN1Template SEC_PointerToEnumeratedTemplate []
const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate []
const SEC_ASN1Template SEC_SetOfEnumeratedTemplate []
const SEC_ASN1Template SEC_GeneralizedTimeTemplate []
const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate []
const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate []
const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate []
const SEC_ASN1Template SEC_IA5StringTemplate []
const SEC_ASN1Template SEC_PointerToIA5StringTemplate []
const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate []
const SEC_ASN1Template SEC_SetOfIA5StringTemplate []
const SEC_ASN1Template SEC_IntegerTemplate []
const SEC_ASN1Template SEC_PointerToIntegerTemplate []
const SEC_ASN1Template SEC_SequenceOfIntegerTemplate []
const SEC_ASN1Template SEC_SetOfIntegerTemplate []
const SEC_ASN1Template SEC_NullTemplate []
const SEC_ASN1Template SEC_PointerToNullTemplate []
const SEC_ASN1Template SEC_SequenceOfNullTemplate []
const SEC_ASN1Template SEC_SetOfNullTemplate []
const SEC_ASN1Template SEC_ObjectIDTemplate []
const SEC_ASN1Template SEC_PointerToObjectIDTemplate []
const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate []
const SEC_ASN1Template SEC_SetOfObjectIDTemplate []
const SEC_ASN1Template SEC_OctetStringTemplate []
const SEC_ASN1Template SEC_PointerToOctetStringTemplate []
const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate []
const SEC_ASN1Template SEC_SetOfOctetStringTemplate []
const SEC_ASN1Template SEC_PrintableStringTemplate []
const SEC_ASN1Template SEC_PointerToPrintableStringTemplate []
const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate []
const SEC_ASN1Template SEC_SetOfPrintableStringTemplate []
const SEC_ASN1Template SEC_T61StringTemplate []
const SEC_ASN1Template SEC_PointerToT61StringTemplate []
const SEC_ASN1Template SEC_SequenceOfT61StringTemplate []
const SEC_ASN1Template SEC_SetOfT61StringTemplate []
const SEC_ASN1Template SEC_UniversalStringTemplate []
const SEC_ASN1Template SEC_PointerToUniversalStringTemplate []
const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate []
const SEC_ASN1Template SEC_SetOfUniversalStringTemplate []
const SEC_ASN1Template SEC_UTCTimeTemplate []
const SEC_ASN1Template SEC_PointerToUTCTimeTemplate []
const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate []
const SEC_ASN1Template SEC_SetOfUTCTimeTemplate []
const SEC_ASN1Template SEC_UTF8StringTemplate []
const SEC_ASN1Template SEC_PointerToUTF8StringTemplate []
const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate []
const SEC_ASN1Template SEC_SetOfUTF8StringTemplate []
const SEC_ASN1Template SEC_VisibleStringTemplate []
const SEC_ASN1Template SEC_PointerToVisibleStringTemplate []
const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate []
const SEC_ASN1Template SEC_SetOfVisibleStringTemplate []
const SEC_ASN1Template SEC_SkipTemplate []

Class Documentation

struct subitem

Definition at line 231 of file secasn1d.c.

Collaboration diagram for subitem:
Class Members
const void * data
unsigned long len
struct subitem * next
struct sec_asn1d_state_struct

Definition at line 237 of file secasn1d.c.

Collaboration diagram for sec_asn1d_state_struct:
Class Members
PRPackedBool allocate
unsigned int bit_string_unused_bits
unsigned long check_tag_mask
struct sec_asn1d_state_struct * child
unsigned long consumed
unsigned long contents_length
int depth
void * dest
PRPackedBool endofcontents
unsigned char expect_tag_modifiers
unsigned long expect_tag_number
PRPackedBool explicit
unsigned char found_tag_modifiers
unsigned long found_tag_number
PRPackedBool indefinite
PRPackedBool missing
PRPackedBool optional
void * our_mark
struct sec_asn1d_state_struct * parent
unsigned long pending
sec_asn1d_parse_place place
struct subitem * subitems_head
struct subitem * subitems_tail
PRPackedBool substring
const SEC_ASN1Template * theTemplate
SEC_ASN1DecoderContext * top
unsigned long underlying_kind
struct sec_DecoderContext_struct

Definition at line 308 of file secasn1d.c.

Collaboration diagram for sec_DecoderContext_struct:
Class Members
sec_asn1d_state * current
PRBool during_notify
void * filter_arg
PRBool filter_only
SEC_ASN1WriteProc filter_proc
void * notify_arg
SEC_ASN1NotifyProc notify_proc
PRArenaPool * our_pool
sec_asn1d_parse_status status
PRArenaPool * their_pool

Define Documentation

#define HIGH_BITS (   field,
  cnt 
)    ((field) >> ((sizeof(field) * 8) - (cnt)))

Definition at line 299 of file secasn1d.c.

Definition at line 291 of file secasn1d.c.

#define LAST_TAG_NUMBER_BYTE (   b)    (((b) & 0x80) == 0)

Definition at line 292 of file secasn1d.c.

#define LENGTH_IS_SHORT_FORM (   b)    (((b) & 0x80) == 0)

Definition at line 296 of file secasn1d.c.

#define LONG_FORM_LENGTH (   b)    ((b) & 0x7f)

Definition at line 297 of file secasn1d.c.

Definition at line 293 of file secasn1d.c.

#define TAG_NUMBER_MASK   0x7f

Definition at line 294 of file secasn1d.c.


Typedef Documentation


Enumeration Type Documentation

Enumerator:
beforeIdentifier 
duringIdentifier 
afterIdentifier 
beforeLength 
duringLength 
afterLength 
beforeBitString 
duringBitString 
duringConstructedString 
duringGroup 
duringLeaf 
duringSaveEncoding 
duringSequence 
afterConstructedString 
afterGroup 
afterExplicit 
afterImplicit 
afterInline 
afterPointer 
afterSaveEncoding 
beforeEndOfContents 
duringEndOfContents 
afterEndOfContents 
beforeChoice 
duringChoice 
afterChoice 
notInUse 
beforeIdentifier 
duringIdentifier 
afterIdentifier 
beforeLength 
duringLength 
afterLength 
beforeBitString 
duringBitString 
duringConstructedString 
duringGroup 
duringLeaf 
duringSaveEncoding 
duringSequence 
afterConstructedString 
afterGroup 
afterExplicit 
afterImplicit 
afterInline 
afterPointer 
afterSaveEncoding 
beforeEndOfContents 
duringEndOfContents 
afterEndOfContents 
beforeChoice 
duringChoice 
afterChoice 
notInUse 

Definition at line 54 of file secasn1d.c.

Enumerator:
allDone 
decodeError 
keepGoing 
needBytes 
allDone 
decodeError 
keepGoing 
needBytes 

Definition at line 224 of file secasn1d.c.


Function Documentation

static void sec_asn1d_absorb_child ( sec_asn1d_state state) [static]

Definition at line 2195 of file secasn1d.c.

{
    /*
     * There is absolutely supposed to be a child there.
     */
    PORT_Assert (state->child != NULL);

    /*
     * Inherit the missing status of our child, and do the ugly
     * backing-up if necessary.
     */
    state->missing = state->child->missing;
    if (state->missing) {
       state->found_tag_number = state->child->found_tag_number;
       state->found_tag_modifiers = state->child->found_tag_modifiers;
       state->endofcontents = state->child->endofcontents;
    }

    /*
     * Add in number of bytes consumed by child.
     * (Only EXPLICIT should have already consumed bytes itself.)
     */
    PORT_Assert (state->place == afterExplicit || state->consumed == 0);
    state->consumed += state->child->consumed;

    /*
     * Subtract from bytes pending; this only applies to a definite-length
     * EXPLICIT field.
     */
    if (state->pending) {
       PORT_Assert (!state->indefinite);
       PORT_Assert (state->place == afterExplicit);

       /*
        * If we had a definite-length explicit, then what the child
        * consumed should be what was left pending.
        */
       if (state->pending != state->child->consumed) {
           if (state->pending < state->child->consumed) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
              return;
           }
           /*
            * Okay, this is a hack.  It *should* be an error whether
            * pending is too big or too small, but it turns out that
            * we had a bug in our *old* DER encoder that ended up
            * counting an explicit header twice in the case where
            * the underlying type was an ANY.  So, because we cannot
            * prevent receiving these (our own certificate server can
            * send them to us), we need to be lenient and accept them.
            * To do so, we need to pretend as if we read all of the
            * bytes that the header said we would find, even though
            * we actually came up short.
            */
           state->consumed += (state->pending - state->child->consumed);
       }
       state->pending = 0;
    }

    /*
     * Indicate that we are done with child.
     */
    state->child->consumed = 0;

    /*
     * And move on to final state.
     * (Technically everybody could move to afterEndOfContents except
     * for an indefinite-length EXPLICIT; for simplicity though we assert
     * that but let the end-of-contents code do the real determination.)
     */
    PORT_Assert (state->place == afterExplicit || (! state->indefinite));
    state->place = beforeEndOfContents;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct subitem* sec_asn1d_add_to_subitems ( sec_asn1d_state state,
const void data,
unsigned long  len,
PRBool  copy_data 
) [static, read]

Definition at line 1655 of file secasn1d.c.

{
    struct subitem *thing;

    thing = (struct subitem*)sec_asn1d_zalloc (state->top->our_pool,
                            sizeof (struct subitem));
    if (thing == NULL) {
       state->top->status = decodeError;
       return NULL;
    }

    if (copy_data) {
       void *copy;
       copy = sec_asn1d_alloc (state->top->our_pool, len);
       if (copy == NULL) {
           state->top->status = decodeError;
           if (!state->top->our_pool)
              PORT_Free(thing);
           return NULL;
       }
       PORT_Memcpy (copy, data, len);
       thing->data = copy;
    } else {
       thing->data = data;
    }
    thing->len = len;
    thing->next = NULL;

    if (state->subitems_head == NULL) {
       PORT_Assert (state->subitems_tail == NULL);
       state->subitems_head = state->subitems_tail = thing;
    } else {
       state->subitems_tail->next = thing;
       state->subitems_tail = thing;
    }

    return thing;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_after_choice ( sec_asn1d_state state) [static]

Definition at line 2493 of file secasn1d.c.

{
    state->consumed += state->child->consumed;
    state->child->consumed = 0;
    state->place = afterEndOfContents;
    sec_asn1d_pop_state(state);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void* sec_asn1d_alloc ( PRArenaPool poolp,
unsigned long  len 
) [static]

Definition at line 341 of file secasn1d.c.

{
    void *thing;

    if (poolp != NULL) {
       /*
        * Allocate from the pool.
        */
       thing = PORT_ArenaAlloc (poolp, len);
    } else {
       /*
        * Allocate generically.
        */
       thing = PORT_Alloc (len);
    }

    return thing;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2359 of file secasn1d.c.

{
    sec_asn1d_state *child;

    if (state->allocate) {
       void *dest;

       dest = sec_asn1d_zalloc(state->top->their_pool, state->theTemplate->size);
       if ((void *)NULL == dest) {
           state->top->status = decodeError;
           return (sec_asn1d_state *)NULL;
       }

       state->dest = (char *)dest + state->theTemplate->offset;
    }

    child = sec_asn1d_push_state(state->top, state->theTemplate + 1, 
                             (char *)state->dest - state->theTemplate->offset, 
                             PR_FALSE);
    if ((sec_asn1d_state *)NULL == child) {
       return (sec_asn1d_state *)NULL;
    }

    sec_asn1d_scrub_state(child);
    child = sec_asn1d_init_state_based_on_template(child);
    if ((sec_asn1d_state *)NULL == child) {
       return (sec_asn1d_state *)NULL;
    }

    child->optional = PR_TRUE;

    state->place = duringChoice;

    return child;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_concat_group ( sec_asn1d_state state) [static]

Definition at line 2141 of file secasn1d.c.

{
    const void ***placep;

    PORT_Assert (state->place == afterGroup);

    placep = (const void***)state->dest;
    PORT_Assert(state->subitems_head == NULL || placep != NULL);
    if (placep != NULL) {
       struct subitem *item;
       const void **group;
       int count;

       count = 0;
       item = state->subitems_head;
       while (item != NULL) {
           PORT_Assert (item->next != NULL || item == state->subitems_tail);
           count++;
           item = item->next;
       }

       group = (const void**)sec_asn1d_zalloc (state->top->their_pool,
                              (count + 1) * (sizeof(void *)));
       if (group == NULL) {
           state->top->status = decodeError;
           return;
       }

       *placep = group;

       item = state->subitems_head;
       while (item != NULL) {
           *group++ = item->data;
           item = item->next;
       }
       *group = NULL;

       /*
        * Because we use arenas and have a mark set, we later free
        * everything we have allocated, so this does *not* present
        * a memory leak (it is just temporarily left dangling).
        */
       state->subitems_head = state->subitems_tail = NULL;
    }

    state->place = afterEndOfContents;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_concat_substrings ( sec_asn1d_state state) [static]

Definition at line 2057 of file secasn1d.c.

{
    PORT_Assert (state->place == afterConstructedString);

    if (state->subitems_head != NULL) {
       struct subitem *substring;
       unsigned long alloc_len, item_len;
       unsigned char *where;
       SECItem *item;
       PRBool is_bit_string;

       item_len = 0;
       is_bit_string = (state->underlying_kind == SEC_ASN1_BIT_STRING)
                     ? PR_TRUE : PR_FALSE;

       substring = state->subitems_head;
       while (substring != NULL) {
           /*
            * All bit-string substrings except the last one should be
            * a clean multiple of 8 bits.
            */
           if (is_bit_string && (substring->next == NULL)
                           && (substring->len & 0x7)) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
              return;
           }
           item_len += substring->len;
           substring = substring->next;
       }

       if (is_bit_string) {
#ifdef XP_WIN16             /* win16 compiler gets an internal error otherwise */
           alloc_len = (((long)item_len + 7) / 8);
#else
           alloc_len = ((item_len + 7) >> 3);
#endif
       } else {
           /*
            * Add 2 for the end-of-contents octets of an indefinite-length
            * ANY that is *not* also an INNER.  Because we zero-allocate
            * below, all we need to do is increase the length here.
            */
           if (state->underlying_kind == SEC_ASN1_ANY && state->indefinite)
              item_len += 2; 
           alloc_len = item_len;
       }

       item = (SECItem *)(state->dest);
       PORT_Assert (item != NULL);
       PORT_Assert (item->data == NULL);
       item->data = (unsigned char*)sec_asn1d_zalloc (state->top->their_pool, 
                                                 alloc_len);
       if (item->data == NULL) {
           state->top->status = decodeError;
           return;
       }
       item->len = item_len;

       where = item->data;
       substring = state->subitems_head;
       while (substring != NULL) {
           if (is_bit_string)
              item_len = (substring->len + 7) >> 3;
           else
              item_len = substring->len;
           PORT_Memcpy (where, substring->data, item_len);
           where += item_len;
           substring = substring->next;
       }

       /*
        * Because we use arenas and have a mark set, we later free
        * everything we have allocated, so this does *not* present
        * a memory leak (it is just temporarily left dangling).
        */
       state->subitems_head = state->subitems_tail = NULL;
    }

    state->place = afterEndOfContents;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_confirm_identifier ( sec_asn1d_state state) [static]

Definition at line 877 of file secasn1d.c.

{
    PRBool match;

    PORT_Assert (state->place == afterIdentifier);

    match = (PRBool)(((state->found_tag_modifiers & state->check_tag_mask)
            == state->expect_tag_modifiers)
           && ((state->found_tag_number & state->check_tag_mask)
              == state->expect_tag_number));
    if (match) {
       state->place = beforeLength;
    } else {
       if (state->optional) {
           state->missing = PR_TRUE;
           state->place = afterEndOfContents;
       } else {
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
       }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2396 of file secasn1d.c.

{
    sec_asn1d_state *child = state->child;
    
    PORT_Assert((sec_asn1d_state *)NULL != child);

    if (child->missing) {
       unsigned char child_found_tag_modifiers = 0;
       unsigned long child_found_tag_number = 0;
       void *        dest;

       state->consumed += child->consumed;

       if (child->endofcontents) {
           /* This choice is probably the first item in a GROUP
           ** (e.g. SET_OF) that was indefinite-length encoded.
           ** We're actually at the end of that GROUP.
           ** We look up the stack to be sure that we find
           ** a state with indefinite length encoding before we
           ** find a state (like a SEQUENCE) that is definite.
           */
           child->place = notInUse;
           state->place = afterChoice;
           state->endofcontents = PR_TRUE;  /* propagate this up */
           if (sec_asn1d_parent_allows_EOC(state))
              return state;
           PORT_SetError(SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return NULL;
       }

       dest = (char *)child->dest - child->theTemplate->offset;
       child->theTemplate++;

       if (0 == child->theTemplate->kind) {
           /* Ran out of choices */
           PORT_SetError(SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return (sec_asn1d_state *)NULL;
       }
       child->dest = (char *)dest + child->theTemplate->offset;

       /* cargo'd from next_in_sequence innards */
       if (state->pending) {
           PORT_Assert(!state->indefinite);
           if (child->consumed > state->pending) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
              return NULL;
           }
           state->pending -= child->consumed;
           if (0 == state->pending) {
              /* XXX uh.. not sure if I should have stopped this
               * from happening before. */
              PORT_Assert(0);
              PORT_SetError(SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
              return (sec_asn1d_state *)NULL;
           }
       }

       child->consumed = 0;
       sec_asn1d_scrub_state(child);

       /* move it on top again */
       state->top->current = child;

       child_found_tag_modifiers = child->found_tag_modifiers;
       child_found_tag_number = child->found_tag_number;

       child = sec_asn1d_init_state_based_on_template(child);
       if ((sec_asn1d_state *)NULL == child) {
           return (sec_asn1d_state *)NULL;
       }

       /* copy our findings to the new top */
       child->found_tag_modifiers = child_found_tag_modifiers;
       child->found_tag_number = child_found_tag_number;

       child->optional = PR_TRUE;
       child->place = afterIdentifier;

       return child;
    } 
    if ((void *)NULL != state->dest) {
       /* Store the enum */
       int *which = (int *)state->dest;
       *which = (int)child->theTemplate->size;
    }

    child->place = notInUse;

    state->place = afterChoice;
    return state;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_free_child ( sec_asn1d_state state,
PRBool  error 
) [static]

Definition at line 1412 of file secasn1d.c.

{
    if (state->child != NULL) {
       PORT_Assert (error || state->child->consumed == 0);
       PORT_Assert (state->our_mark != NULL);
       PORT_ArenaZRelease (state->top->our_pool, state->our_mark);
       if (error && state->top->their_pool == NULL) {
           /*
            * XXX We need to free anything allocated.
             * At this point, we failed in the middle of decoding. But we
             * can't free the data we previously allocated with PR_Malloc
             * unless we keep track of every pointer. So instead we have a
             * memory leak when decoding fails half-way, unless an arena is
             * used. See bug 95311 .
            */
       }
       state->child = NULL;
       state->our_mark = NULL;
    } else {
       /*
        * It is important that we do not leave a mark unreleased/unmarked.
        * But I do not think we should ever have one set in this case, only
        * if we had a child (handled above).  So check for that.  If this
        * assertion should ever get hit, then we probably need to add code
        * here to release back to our_mark (and then set our_mark to NULL).
        */
       PORT_Assert (state->our_mark == NULL);
    }
    state->place = beforeEndOfContents;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 729 of file secasn1d.c.

{
    for (state = state->parent; state; state = state->parent) {
       sec_asn1d_parse_place place = state->place;
       if (place != afterImplicit      &&
           place != afterPointer       &&
           place != afterInline        &&
           place != afterSaveEncoding  &&
           place != duringSaveEncoding &&
           place != duringChoice) {

            /* we've walked up the stack to a state that represents
            ** the enclosing construct.  
           */
            break;
       }
    }
    return state;
}

Here is the caller graph for this function:

Definition at line 469 of file secasn1d.c.

{
    PRBool explicit, optional, universal;
    unsigned char expect_tag_modifiers;
    unsigned long encode_kind, under_kind;
    unsigned long check_tag_mask, expect_tag_number;


    /* XXX Check that both of these tests are really needed/appropriate. */
    if (state == NULL || state->top->status == decodeError)
       return state;

    encode_kind = state->theTemplate->kind;

    if (encode_kind & SEC_ASN1_SAVE) {
       /*
        * This is a "magic" field that saves away all bytes, allowing
        * the immediately following field to still be decoded from this
        * same spot -- sort of a fork.
        */
       /* check that there are no extraneous bits */
       PORT_Assert (encode_kind == SEC_ASN1_SAVE);
       if (state->top->filter_only) {
           /*
            * If we are not storing, then we do not do the SAVE field
            * at all.  Just move ahead to the "real" field instead,
            * doing the appropriate notify calls before and after.
            */
           sec_asn1d_notify_after (state->top, state->dest, state->depth);
           /*
            * Since we are not storing, allow for our current dest value
            * to be NULL.  (This might not actually occur, but right now I
            * cannot convince myself one way or the other.)  If it is NULL,
            * assume that our parent dest can help us out.
            */
           if (state->dest == NULL)
              state->dest = state->parent->dest;
           else
              state->dest = (char *)state->dest - state->theTemplate->offset;
           state->theTemplate++;
           if (state->dest != NULL)
              state->dest = (char *)state->dest + state->theTemplate->offset;
           sec_asn1d_notify_before (state->top, state->dest, state->depth);
           encode_kind = state->theTemplate->kind;
           PORT_Assert ((encode_kind & SEC_ASN1_SAVE) == 0);
       } else {
           sec_asn1d_scrub_state (state);
           state->place = duringSaveEncoding;
           state = sec_asn1d_push_state (state->top, SEC_AnyTemplate,
                                     state->dest, PR_FALSE);
           if (state != NULL)
              state = sec_asn1d_init_state_based_on_template (state);
           return state;
       }
    }


    universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
              ? PR_TRUE : PR_FALSE;

    explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
    encode_kind &= ~SEC_ASN1_EXPLICIT;

    optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
    encode_kind &= ~SEC_ASN1_OPTIONAL;

    PORT_Assert (!(explicit && universal));      /* bad templates */

    encode_kind &= ~SEC_ASN1_DYNAMIC;
    encode_kind &= ~SEC_ASN1_MAY_STREAM;

    if (encode_kind & SEC_ASN1_CHOICE) {
#if 0  /* XXX remove? */
      sec_asn1d_state *child = sec_asn1d_push_state(state->top, state->theTemplate, state->dest, PR_FALSE);
      if ((sec_asn1d_state *)NULL == child) {
        return (sec_asn1d_state *)NULL;
      }

      child->allocate = state->allocate;
      child->place = beforeChoice;
      return child;
#else
      state->place = beforeChoice;
      return state;
#endif
    }

    if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
                                                       && !explicit)) {
       const SEC_ASN1Template *subt;
       void *dest;
       PRBool child_allocate;

       PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);

       sec_asn1d_scrub_state (state);
       child_allocate = PR_FALSE;

       if (encode_kind & SEC_ASN1_POINTER) {
           /*
            * A POINTER means we need to allocate the destination for
            * this field.  But, since it may also be an optional field,
            * we defer the allocation until later; we just record that
            * it needs to be done.
            *
            * There are two possible scenarios here -- one is just a
            * plain POINTER (kind of like INLINE, except with allocation)
            * and the other is an implicitly-tagged POINTER.  We don't
            * need to do anything special here for the two cases, but
            * since the template definition can be tricky, we do check
            * that there are no extraneous bits set in encode_kind.
            *
            * XXX The same conditions which assert should set an error.
            */
           if (universal) {
              /*
               * "universal" means this entry is a standalone POINTER;
               * there should be no other bits set in encode_kind.
               */
              PORT_Assert (encode_kind == SEC_ASN1_POINTER);
           } else {
              /*
               * If we get here we have an implicitly-tagged field
               * that needs to be put into a POINTER.  The subtemplate
               * will determine how to decode the field, but encode_kind
               * describes the (implicit) tag we are looking for.
               * The non-tag bits of encode_kind will be ignored by
               * the code below; none of them should be set, however,
               * except for the POINTER bit itself -- so check that.
               */
              PORT_Assert ((encode_kind & ~SEC_ASN1_TAG_MASK)
                          == SEC_ASN1_POINTER);
           }
           if (!state->top->filter_only)
              child_allocate = PR_TRUE;
           dest = NULL;
           state->place = afterPointer;
       } else {
           dest = state->dest;
           if (encode_kind & SEC_ASN1_INLINE) {
              /* check that there are no extraneous bits */
              PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
              state->place = afterInline;
           } else {
              state->place = afterImplicit;
           }
       }

       state->optional = optional;
       subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest, PR_FALSE);
       state = sec_asn1d_push_state (state->top, subt, dest, PR_FALSE);
       if (state == NULL)
           return NULL;

       state->allocate = child_allocate;

       if (universal) {
           state = sec_asn1d_init_state_based_on_template (state);
           if (state != NULL) {
              /*
               * If this field is optional, we need to record that on
               * the pushed child so it won't fail if the field isn't
               * found.  I can't think of a way that this new state
               * could already have optional set (which we would wipe
               * out below if our local optional is not set) -- but
               * just to be sure, assert that it isn't set.
               */
              PORT_Assert (!state->optional);
              state->optional = optional;
           }
           return state;
       }

       under_kind = state->theTemplate->kind;
       under_kind &= ~SEC_ASN1_MAY_STREAM;
    } else if (explicit) {
       /*
        * For explicit, we only need to match the encoding tag next,
        * then we will push another state to handle the entire inner
        * part.  In this case, there is no underlying kind which plays
        * any part in the determination of the outer, explicit tag.
        * So we just set under_kind to 0, which is not a valid tag,
        * and the rest of the tag matching stuff should be okay.
        */
       under_kind = 0;
    } else {
       /*
        * Nothing special; the underlying kind and the given encoding
        * information are the same.
        */
       under_kind = encode_kind;
    }

    /* XXX is this the right set of bits to test here? */
    PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
                            | SEC_ASN1_MAY_STREAM
                            | SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);

    if (encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) {
       PORT_Assert (encode_kind == under_kind);
       if (encode_kind & SEC_ASN1_SKIP) {
           PORT_Assert (!optional);
           PORT_Assert (encode_kind == SEC_ASN1_SKIP);
           state->dest = NULL;
       }
       check_tag_mask = 0;
       expect_tag_modifiers = 0;
       expect_tag_number = 0;
    } else {
       check_tag_mask = SEC_ASN1_TAG_MASK;
       expect_tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK
                            & ~SEC_ASN1_TAGNUM_MASK;
       /*
        * XXX This assumes only single-octet identifiers.  To handle
        * the HIGH TAG form we would need to do some more work, especially
        * in how to specify them in the template, because right now we
        * do not provide a way to specify more *tag* bits in encode_kind.
        */
       expect_tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;

       switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
         case SEC_ASN1_SET:
           /*
            * XXX A plain old SET (as opposed to a SET OF) is not implemented.
            * If it ever is, remove this assert...
            */
           PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
           /* fallthru */
         case SEC_ASN1_SEQUENCE:
           expect_tag_modifiers |= SEC_ASN1_CONSTRUCTED;
           break;
         case SEC_ASN1_BIT_STRING:
         case SEC_ASN1_BMP_STRING:
         case SEC_ASN1_GENERALIZED_TIME:
         case SEC_ASN1_IA5_STRING:
         case SEC_ASN1_OCTET_STRING:
         case SEC_ASN1_PRINTABLE_STRING:
         case SEC_ASN1_T61_STRING:
         case SEC_ASN1_UNIVERSAL_STRING:
         case SEC_ASN1_UTC_TIME:
         case SEC_ASN1_UTF8_STRING:
         case SEC_ASN1_VISIBLE_STRING:
           check_tag_mask &= ~SEC_ASN1_CONSTRUCTED;
           break;
       }
    }

    state->check_tag_mask = check_tag_mask;
    state->expect_tag_modifiers = expect_tag_modifiers;
    state->expect_tag_number = expect_tag_number;
    state->underlying_kind = under_kind;
    state->explicit = explicit;
    state->optional = optional;

    sec_asn1d_scrub_state (state);

    return state;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_next_in_group ( sec_asn1d_state state) [static]

Definition at line 1797 of file secasn1d.c.

{
    sec_asn1d_state *child;
    unsigned long child_consumed;

    PORT_Assert (state->place == duringGroup);
    PORT_Assert (state->child != NULL);

    child = state->child;

    child_consumed = child->consumed;
    child->consumed = 0;
    state->consumed += child_consumed;

    /*
     * If our child was just our end-of-contents octets, we are done.
     */
    if (child->endofcontents) {
       /* XXX I removed the PORT_Assert (child->dest == NULL) because there
        * was a bug in that a template that was a sequence of which also had
        * a child of a sequence of, in an indefinite group was not working 
        * properly.  This fix seems to work, (added the if statement below),
        * and nothing appears broken, but I am putting this note here just
        * in case. */
       /*
        * XXX No matter how many times I read that comment,
        * I cannot figure out what case he was fixing.  I believe what he
        * did was deliberate, so I am loathe to touch it.  I need to
        * understand how it could ever be that child->dest != NULL but
        * child->endofcontents is true, and why it is important to check
        * that state->subitems_head is NULL.  This really needs to be
        * figured out, as I am not sure if the following code should be
        * compensating for "offset", as is done a little farther below
        * in the more normal case.
        */
       PORT_Assert (state->indefinite);
       PORT_Assert (state->pending == 0);
       if(child->dest && !state->subitems_head) {
           sec_asn1d_add_to_subitems (state, child->dest, 0, PR_FALSE);
           child->dest = NULL;
       }

       child->place = notInUse;
       state->place = afterGroup;
       return;
    }

    /* 
     * Do the "after" field notification for next in group.
     */
    sec_asn1d_notify_after (state->top, child->dest, child->depth);

    /*
     * Save it away (unless we are not storing).
     */
    if (child->dest != NULL) {
       void *dest;

       dest = child->dest;
       dest = (char *)dest - child->theTemplate->offset;
       sec_asn1d_add_to_subitems (state, dest, 0, PR_FALSE);
       child->dest = NULL;
    }

    /*
     * Account for those bytes; see if we are done.
     */
    if (state->pending) {
       PORT_Assert (!state->indefinite);
       if (child_consumed > state->pending) {
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return;
       }

       state->pending -= child_consumed;
       if (state->pending == 0) {
           child->place = notInUse;
           state->place = afterGroup;
           return;
       }
    }

    /*
     * Do the "before" field notification for next item in group.
     */
    sec_asn1d_notify_before (state->top, child->dest, child->depth);

    /*
     * Now we do the next one.
     */
    sec_asn1d_scrub_state (child);

    /* Initialize child state from the template */
    sec_asn1d_init_state_based_on_template(child);

    state->top->current = child;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_next_in_sequence ( sec_asn1d_state state) [static]

Definition at line 1903 of file secasn1d.c.

{
    sec_asn1d_state *child;
    unsigned long child_consumed;
    PRBool child_missing;

    PORT_Assert (state->place == duringSequence);
    PORT_Assert (state->child != NULL);

    child = state->child;

    /*
     * Do the "after" field notification.
     */
    sec_asn1d_notify_after (state->top, child->dest, child->depth);

    child_missing = (PRBool) child->missing;
    child_consumed = child->consumed;
    child->consumed = 0;

    /*
     * Take care of accounting.
     */
    if (child_missing) {
       PORT_Assert (child->optional);
    } else {
       state->consumed += child_consumed;
       /*
        * Free any grandchild.
        */
       sec_asn1d_free_child (child, PR_FALSE);
       if (state->pending) {
           PORT_Assert (!state->indefinite);
           if (child_consumed > state->pending) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
              return;
           }
           state->pending -= child_consumed;
           if (state->pending == 0) {
              child->theTemplate++;
              while (child->theTemplate->kind != 0) {
                  if ((child->theTemplate->kind & SEC_ASN1_OPTIONAL) == 0) {
                     PORT_SetError (SEC_ERROR_BAD_DER);
                     state->top->status = decodeError;
                     return;
                  }
                  child->theTemplate++;
              }
              child->place = notInUse;
              state->place = afterEndOfContents;
              return;
           }
       }
    }

    /*
     * Move forward.
     */
    child->theTemplate++;
    if (child->theTemplate->kind == 0) {
       /*
        * We are done with this sequence.
        */
       child->place = notInUse;
       if (state->pending) {
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
       } else if (child_missing) {
           /*
            * We got to the end, but have a child that started parsing
            * and ended up "missing".  The only legitimate reason for
            * this is that we had one or more optional fields at the
            * end of our sequence, and we were encoded indefinite-length,
            * so when we went looking for those optional fields we
            * found our end-of-contents octets instead.
            * (Yes, this is ugly; dunno a better way to handle it.)
            * So, first confirm the situation, and then mark that we
            * are done.
            */
           if (state->indefinite && child->endofcontents) {
              PORT_Assert (child_consumed == 2);
              if (child_consumed != 2) {
                  PORT_SetError (SEC_ERROR_BAD_DER);
                  state->top->status = decodeError;
              } else {
                  state->consumed += child_consumed;
                  state->place = afterEndOfContents;
              }
           } else {
              PORT_SetError (SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
           }
       } else {
           /*
            * We have to finish out, maybe reading end-of-contents octets;
            * let the normal logic do the right thing.
            */
           state->place = beforeEndOfContents;
       }
    } else {
       unsigned char child_found_tag_modifiers = 0;
       unsigned long child_found_tag_number = 0;

       /*
        * Reset state and push.
        */
       if (state->dest != NULL)
           child->dest = (char *)state->dest + child->theTemplate->offset;

       /*
        * Do the "before" field notification.
        */
       sec_asn1d_notify_before (state->top, child->dest, child->depth);

       if (child_missing) { /* if previous child was missing, copy the tag data we already have */
           child_found_tag_modifiers = child->found_tag_modifiers;
           child_found_tag_number = child->found_tag_number;
       }
       state->top->current = child;
       child = sec_asn1d_init_state_based_on_template (child);
       if (child_missing) {
           child->place = afterIdentifier;
           child->found_tag_modifiers = child_found_tag_modifiers;
           child->found_tag_number = child_found_tag_number;
           child->consumed = child_consumed;
           if (child->underlying_kind == SEC_ASN1_ANY
              && !child->top->filter_only) {
              /*
               * If the new field is an ANY, and we are storing, then
               * we need to save the tag out.  We would have done this
               * already in the normal case, but since we were looking
               * for an optional field, and we did not find it, we only
               * now realize we need to save the tag.
               */
              unsigned char identifier;

              /*
               * Check that we did not end up with a high tag; for that
               * we need to re-encode the tag into multiple bytes in order
               * to store it back to look like what we parsed originally.
               * In practice this does not happen, but for completeness
               * sake it should probably be made to work at some point.
               */
              PORT_Assert (child_found_tag_number < SEC_ASN1_HIGH_TAG_NUMBER);
              identifier = (unsigned char)(child_found_tag_modifiers | child_found_tag_number);
              sec_asn1d_record_any_header (child, (char *) &identifier, 1);
           }
       }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_next_substring ( sec_asn1d_state state) [static]

Definition at line 1727 of file secasn1d.c.

{
    sec_asn1d_state *child;
    SECItem *item;
    unsigned long child_consumed;
    PRBool done;

    PORT_Assert (state->place == duringConstructedString);
    PORT_Assert (state->child != NULL);

    child = state->child;

    child_consumed = child->consumed;
    child->consumed = 0;
    state->consumed += child_consumed;

    done = PR_FALSE;

    if (state->pending) {
       PORT_Assert (!state->indefinite);
       if (child_consumed > state->pending) {
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return;
       }

       state->pending -= child_consumed;
       if (state->pending == 0)
           done = PR_TRUE;
    } else {
       PORT_Assert (state->indefinite);

       item = (SECItem *)(child->dest);
       if (item != NULL && item->data != NULL) {
           /*
            * Save the string away for later concatenation.
            */
           PORT_Assert (item->data != NULL);
           sec_asn1d_add_to_subitems (state, item->data, item->len, PR_FALSE);
           /*
            * Clear the child item for the next round.
            */
           item->data = NULL;
           item->len = 0;
       }

       /*
        * If our child was just our end-of-contents octets, we are done.
        */
       if (child->endofcontents)
           done = PR_TRUE;
    }

    /*
     * Stop or do the next one.
     */
    if (done) {
       child->place = notInUse;
       state->place = afterConstructedString;
    } else {
       sec_asn1d_scrub_state (child);
       state->top->current = child;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_notify_after ( SEC_ASN1DecoderContext *  cx,
void dest,
int  depth 
) [static]

Definition at line 457 of file secasn1d.c.

{
    if (cx->notify_proc == NULL)
       return;

    cx->during_notify = PR_TRUE;
    (* cx->notify_proc) (cx->notify_arg, PR_FALSE, dest, depth);
    cx->during_notify = PR_FALSE;
}

Here is the caller graph for this function:

static void sec_asn1d_notify_before ( SEC_ASN1DecoderContext *  cx,
void dest,
int  depth 
) [static]

Definition at line 445 of file secasn1d.c.

{
    if (cx->notify_proc == NULL)
       return;

    cx->during_notify = PR_TRUE;
    (* cx->notify_proc) (cx->notify_arg, PR_TRUE, dest, depth);
    cx->during_notify = PR_FALSE;
}

Here is the caller graph for this function:

static PRBool sec_asn1d_parent_allows_EOC ( sec_asn1d_state state) [static]

Definition at line 750 of file secasn1d.c.

{
    /* get state of enclosing construct. */
    state = sec_asn1d_get_enclosing_construct(state);
    if (state) {
       sec_asn1d_parse_place place = state->place;
        /* Is it one of the types that permits an unexpected EOC? */
       int eoc_permitted = 
           (place == duringGroup ||
            place == duringConstructedString ||
            state->child->optional);
       return (state->indefinite && eoc_permitted) ? PR_TRUE : PR_FALSE;
    }
    return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_bit_string ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 1582 of file secasn1d.c.

{
    unsigned char byte;

    /*PORT_Assert (state->pending > 0); */
    PORT_Assert (state->place == beforeBitString);

    if (state->pending == 0) {
       if (state->dest != NULL) {
           SECItem *item = (SECItem *)(state->dest);
           item->data = NULL;
           item->len = 0;
           state->place = beforeEndOfContents;
           return 0;
       }
    }

    if (len == 0) {
       state->top->status = needBytes;
       return 0;
    }

    byte = (unsigned char) *buf;
    if (byte > 7) {
       PORT_SetError (SEC_ERROR_BAD_DER);
       state->top->status = decodeError;
       return 0;
    }

    state->bit_string_unused_bits = byte;
    state->place = duringBitString;
    state->pending -= 1;

    return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_end_of_contents ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 2286 of file secasn1d.c.

{
    unsigned int i;

    PORT_Assert (state->pending <= 2);
    PORT_Assert (state->place == duringEndOfContents);

    if (len == 0) {
       state->top->status = needBytes;
       return 0;
    }

    if (state->pending < len)
       len = state->pending;

    for (i = 0; i < len; i++) {
       if (buf[i] != 0) {
           /*
            * We expect to find only zeros; if not, just give up.
            */
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return 0;
       }
    }

    state->pending -= len;

    if (state->pending == 0) {
       state->place = afterEndOfContents;
       state->endofcontents = PR_TRUE;
    }

    return len;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_identifier ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 767 of file secasn1d.c.

{
    unsigned char byte;
    unsigned char tag_number;

    PORT_Assert (state->place == beforeIdentifier);

    if (len == 0) {
       state->top->status = needBytes;
       return 0;
    }

    byte = (unsigned char) *buf;
#ifdef DEBUG_ASN1D_STATES
    {
        char kindBuf[256];
        formatKind(byte, kindBuf);
        printf("Found tag %02x %s\n", byte, kindBuf);
    }
#endif
    tag_number = byte & SEC_ASN1_TAGNUM_MASK;

    if (IS_HIGH_TAG_NUMBER (tag_number)) {
       state->place = duringIdentifier;
       state->found_tag_number = 0;
       /*
        * Actually, we have no idea how many bytes are pending, but we
        * do know that it is at least 1.  That is all we know; we have
        * to look at each byte to know if there is another, etc.
        */
       state->pending = 1;
    } else {
       if (byte == 0 && sec_asn1d_parent_allows_EOC(state)) {
           /*
            * Our parent has indefinite-length encoding, and the
            * entire tag found is 0, so it seems that we have hit the
            * end-of-contents octets.  To handle this, we just change
            * our state to that which expects to get the bytes of the
            * end-of-contents octets and let that code re-read this byte
            * so that our categorization of field types is correct.
            * After that, our parent will then deal with everything else.
            */
           state->place = duringEndOfContents;
           state->pending = 2;
           state->found_tag_number = 0;
           state->found_tag_modifiers = 0;
           /*
            * We might be an optional field that is, as we now find out,
            * missing.  Give our parent a clue that this happened.
            */
           if (state->optional)
              state->missing = PR_TRUE;
           return 0;
       }
       state->place = afterIdentifier;
       state->found_tag_number = tag_number;
    }
    state->found_tag_modifiers = byte & ~SEC_ASN1_TAGNUM_MASK;

    return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_leaf ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 1542 of file secasn1d.c.

{
    SECItem *item;
    unsigned long bufLen;

    if (len == 0) {
       state->top->status = needBytes;
       return 0;
    }

    if (state->pending < len)
       len = state->pending;

    bufLen = len;

    item = (SECItem *)(state->dest);
    if (item != NULL && item->data != NULL) {
       /* Strip leading zeroes when target is unsigned integer */
       if (state->underlying_kind == SEC_ASN1_INTEGER && /* INTEGER   */
           item->len == 0 &&                             /* MSB       */
           item->type == siUnsignedInteger)              /* unsigned  */
       {
           while (len > 1 && buf[0] == 0) {              /* leading 0 */
              buf++;
              len--;
           }
       }
       PORT_Memcpy (item->data + item->len, buf, len);
       item->len += len;
    }
    state->pending -= bufLen;
    if (state->pending == 0)
       state->place = beforeEndOfContents;

    return bufLen;
}

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_length ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 902 of file secasn1d.c.

{
    unsigned char byte;

    PORT_Assert (state->place == beforeLength);

    if (len == 0) {
       state->top->status = needBytes;
       return 0;
    }

    /*
     * The default/likely outcome.  It may get adjusted below.
     */
    state->place = afterLength;

    byte = (unsigned char) *buf;

    if (LENGTH_IS_SHORT_FORM (byte)) {
       state->contents_length = byte;
    } else {
       state->contents_length = 0;
       state->pending = LONG_FORM_LENGTH (byte);
       if (state->pending == 0) {
           state->indefinite = PR_TRUE;
       } else {
           state->place = duringLength;
       }
    }

    /* If we're parsing an ANY, SKIP, or SAVE template, and 
    ** the object being saved is definite length encoded and constructed, 
    ** there's no point in decoding that construct's members.
    ** So, just forget it's constructed and treat it as primitive.
    ** (SAVE appears as an ANY at this point)
    */
    if (!state->indefinite &&
       (state->underlying_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP))) {
       state->found_tag_modifiers &= ~SEC_ASN1_CONSTRUCTED;
    }

    return 1;
}

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_more_bit_string ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 1621 of file secasn1d.c.

{
    PORT_Assert (state->place == duringBitString);
    if (state->pending == 0) {
       /* An empty bit string with some unused bits is invalid. */
       if (state->bit_string_unused_bits) {
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
       } else {
           /* An empty bit string with no unused bits is OK. */
           state->place = beforeEndOfContents;
       }
       return 0;
    }

    len = sec_asn1d_parse_leaf (state, buf, len);
    if (state->place == beforeEndOfContents && state->dest != NULL) {
       SECItem *item;

       item = (SECItem *)(state->dest);
       if (item->len)
           item->len = (item->len << 3) - state->bit_string_unused_bits;
    }

    return len;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_more_identifier ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 832 of file secasn1d.c.

{
    unsigned char byte;
    int count;

    PORT_Assert (state->pending == 1);
    PORT_Assert (state->place == duringIdentifier);

    if (len == 0) {
       state->top->status = needBytes;
       return 0;
    }

    count = 0;

    while (len && state->pending) {
       if (HIGH_BITS (state->found_tag_number, TAG_NUMBER_BITS) != 0) {
           /*
            * The given high tag number overflows our container;
            * just give up.  This is not likely to *ever* happen.
            */
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return 0;
       }

       state->found_tag_number <<= TAG_NUMBER_BITS;

       byte = (unsigned char) buf[count++];
       state->found_tag_number |= (byte & TAG_NUMBER_MASK);

       len--;
       if (LAST_TAG_NUMBER_BYTE (byte))
           state->pending = 0;
    }

    if (state->pending == 0)
       state->place = afterIdentifier;

    return count;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static unsigned long sec_asn1d_parse_more_length ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 949 of file secasn1d.c.

{
    int count;

    PORT_Assert (state->pending > 0);
    PORT_Assert (state->place == duringLength);

    if (len == 0) {
       state->top->status = needBytes;
       return 0;
    }

    count = 0;

    while (len && state->pending) {
       if (HIGH_BITS (state->contents_length, 9) != 0) {
           /*
            * The given full content length overflows our container;
            * just give up.
            */
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return 0;
       }

       state->contents_length <<= 8;
       state->contents_length |= (unsigned char) buf[count++];

       len--;
       state->pending--;
    }

    if (state->pending == 0)
       state->place = afterLength;

    return count;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_pop_state ( sec_asn1d_state state) [static]

Definition at line 2325 of file secasn1d.c.

{
#if 0  /* XXX I think this should always be handled explicitly by parent? */
    /*
     * Account for our child.
     */
    if (state->child != NULL) {
       state->consumed += state->child->consumed;
       if (state->pending) {
           PORT_Assert (!state->indefinite);
           if (state->child->consumed > state->pending) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
           } else {
              state->pending -= state->child->consumed;
           }
       }
       state->child->consumed = 0;
    }
#endif /* XXX */

    /*
     * Free our child.
     */
    sec_asn1d_free_child (state, PR_FALSE);

    /*
     * Just make my parent be the current state.  It will then clean
     * up after me and free me (or reuse me).
     */
    state->top->current = state->parent;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_prepare_for_contents ( sec_asn1d_state state) [static]

Definition at line 990 of file secasn1d.c.

{
    SECItem *item;
    PRArenaPool *poolp;
    unsigned long alloc_len;

#ifdef DEBUG_ASN1D_STATES
    {
        printf("Found Length %d %s\n", state->contents_length,
               state->indefinite ? "indefinite" : "");
    }
#endif

    /*
     * XXX I cannot decide if this allocation should exclude the case
     *     where state->endofcontents is true -- figure it out!
     */
    if (state->allocate) {
       void *dest;

       PORT_Assert (state->dest == NULL);
       /*
        * We are handling a POINTER or a member of a GROUP, and need to
        * allocate for the data structure.
        */
       dest = sec_asn1d_zalloc (state->top->their_pool,
                             state->theTemplate->size);
       if (dest == NULL) {
           state->top->status = decodeError;
           return;
       }
       state->dest = (char *)dest + state->theTemplate->offset;

       /*
        * For a member of a GROUP, our parent will later put the
        * pointer wherever it belongs.  But for a POINTER, we need
        * to record the destination now, in case notify or filter
        * procs need access to it -- they cannot find it otherwise,
        * until it is too late (for one-pass processing).
        */
       if (state->parent->place == afterPointer) {
           void **placep;

           placep = state->parent->dest;
           *placep = dest;
       }
    }

    /*
     * Remember, length may be indefinite here!  In that case,
     * both contents_length and pending will be zero.
     */
    state->pending = state->contents_length;

    /* If this item has definite length encoding, and 
    ** is enclosed by a definite length constructed type,
    ** make sure it isn't longer than the remaining space in that 
    ** constructed type.  
    */
    if (state->contents_length > 0) {
       sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state);
       if (parent && !parent->indefinite && 
           state->consumed + state->contents_length > parent->pending) {
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           return;
       }
    }

    /*
     * An EXPLICIT is nothing but an outer header, which we have
     * already parsed and accepted.  Now we need to do the inner
     * header and its contents.
     */
    if (state->explicit) {
       state->place = afterExplicit;
       state = sec_asn1d_push_state (state->top,
                                  SEC_ASN1GetSubtemplate(state->theTemplate,
                                                      state->dest,
                                                      PR_FALSE),
                                  state->dest, PR_TRUE);
       if (state != NULL)
           state = sec_asn1d_init_state_based_on_template (state);
       return;
    }

    /*
     * For GROUP (SET OF, SEQUENCE OF), even if we know the length here
     * we cannot tell how many items we will end up with ... so push a
     * state that can keep track of "children" (the individual members
     * of the group; we will allocate as we go and put them all together
     * at the end.
     */
    if (state->underlying_kind & SEC_ASN1_GROUP) {
       /* XXX If this assertion holds (should be able to confirm it via
        * inspection, too) then move this code into the switch statement
        * below under cases SET_OF and SEQUENCE_OF; it will be cleaner.
        */
       PORT_Assert (state->underlying_kind == SEC_ASN1_SET_OF
          || state->underlying_kind == SEC_ASN1_SEQUENCE_OF
          || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
          || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
                   );
       if (state->contents_length != 0 || state->indefinite) {
           const SEC_ASN1Template *subt;

           state->place = duringGroup;
           subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest,
                                      PR_FALSE);
           state = sec_asn1d_push_state (state->top, subt, NULL, PR_TRUE);
           if (state != NULL) {
              if (!state->top->filter_only)
                  state->allocate = PR_TRUE;     /* XXX propogate this? */
              /*
               * Do the "before" field notification for next in group.
               */
              sec_asn1d_notify_before (state->top, state->dest, state->depth);
              state = sec_asn1d_init_state_based_on_template (state);
           }
       } else {
           /*
            * A group of zero; we are done.
            * Set state to afterGroup and let that code plant the NULL.
            */
           state->place = afterGroup;
       }
       return;
    }

    switch (state->underlying_kind) {
      case SEC_ASN1_SEQUENCE:
       /*
        * We need to push a child to handle the individual fields.
        */
       state->place = duringSequence;
       state = sec_asn1d_push_state (state->top, state->theTemplate + 1,
                                  state->dest, PR_TRUE);
       if (state != NULL) {
           /*
            * Do the "before" field notification.
            */
           sec_asn1d_notify_before (state->top, state->dest, state->depth);
           state = sec_asn1d_init_state_based_on_template (state);
       }
       break;

      case SEC_ASN1_SET:    /* XXX SET is not really implemented */
       /*
        * XXX A plain SET requires special handling; scanning of a
        * template to see where a field should go (because by definition,
        * they are not in any particular order, and you have to look at
        * each tag to disambiguate what the field is).  We may never
        * implement this because in practice, it seems to be unused.
        */
       PORT_Assert(0);
       PORT_SetError (SEC_ERROR_BAD_DER); /* XXX */
       state->top->status = decodeError;
       break;

      case SEC_ASN1_NULL:
       /*
        * The NULL type, by definition, is "nothing", content length of zero.
        * An indefinite-length encoding is not alloweed.
        */
       if (state->contents_length || state->indefinite) {
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
           break;
       }
       if (state->dest != NULL) {
           item = (SECItem *)(state->dest);
           item->data = NULL;
           item->len = 0;
       }
       state->place = afterEndOfContents;
       break;

      case SEC_ASN1_BMP_STRING:
       /* Error if length is not divisable by 2 */
       if (state->contents_length % 2) {
          PORT_SetError (SEC_ERROR_BAD_DER);
          state->top->status = decodeError;
          break;
       }   
       /* otherwise, handle as other string types */
       goto regular_string_type;

      case SEC_ASN1_UNIVERSAL_STRING:
       /* Error if length is not divisable by 4 */
       if (state->contents_length % 4) {
          PORT_SetError (SEC_ERROR_BAD_DER);
          state->top->status = decodeError;
          break;
       }   
       /* otherwise, handle as other string types */
       goto regular_string_type;

      case SEC_ASN1_SKIP:
      case SEC_ASN1_ANY:
      case SEC_ASN1_ANY_CONTENTS:
       /*
        * These are not (necessarily) strings, but they need nearly
        * identical handling (especially when we need to deal with
        * constructed sub-pieces), so we pretend they are.
        */
       /* fallthru */
regular_string_type:
      case SEC_ASN1_BIT_STRING:
      case SEC_ASN1_IA5_STRING:
      case SEC_ASN1_OCTET_STRING:
      case SEC_ASN1_PRINTABLE_STRING:
      case SEC_ASN1_T61_STRING:
      case SEC_ASN1_UTC_TIME:
      case SEC_ASN1_UTF8_STRING:
      case SEC_ASN1_VISIBLE_STRING:
       /*
        * We are allocating for a primitive or a constructed string.
        * If it is a constructed string, it may also be indefinite-length.
        * If it is primitive, the length can (legally) be zero.
        * Our first order of business is to allocate the memory for
        * the string, if we can (if we know the length).
        */
       item = (SECItem *)(state->dest);

       /*
        * If the item is a definite-length constructed string, then
        * the contents_length is actually larger than what we need
        * (because it also counts each intermediate header which we
        * will be throwing away as we go), but it is a perfectly good
        * upper bound that we just allocate anyway, and then concat
        * as we go; we end up wasting a few extra bytes but save a
        * whole other copy.
        */
       alloc_len = state->contents_length;
       poolp = NULL; /* quiet compiler warnings about unused... */

       if (item == NULL || state->top->filter_only) {
           if (item != NULL) {
              item->data = NULL;
              item->len = 0;
           }
           alloc_len = 0;
       } else if (state->substring) {
           /*
            * If we are a substring of a constructed string, then we may
            * not have to allocate anything (because our parent, the
            * actual constructed string, did it for us).  If we are a
            * substring and we *do* have to allocate, that means our
            * parent is an indefinite-length, so we allocate from our pool;
            * later our parent will copy our string into the aggregated
            * whole and free our pool allocation.
            */
           if (item->data == NULL) {
              PORT_Assert (item->len == 0);
              poolp = state->top->our_pool;
           } else {
              alloc_len = 0;
           }
       } else {
           item->len = 0;
           item->data = NULL;
           poolp = state->top->their_pool;
       }

       if (alloc_len || ((! state->indefinite)
                       && (state->subitems_head != NULL))) {
           struct subitem *subitem;
           int len;

           PORT_Assert (item);
           if (!item) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              state->top->status = decodeError;
              return;
           }
           PORT_Assert (item->len == 0 && item->data == NULL);
           /*
            * Check for and handle an ANY which has stashed aside the
            * header (identifier and length) bytes for us to include
            * in the saved contents.
            */
           if (state->subitems_head != NULL) {
              PORT_Assert (state->underlying_kind == SEC_ASN1_ANY);
              for (subitem = state->subitems_head;
                   subitem != NULL; subitem = subitem->next)
                  alloc_len += subitem->len;
           }

           item->data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len);
           if (item->data == NULL) {
              state->top->status = decodeError;
              break;
           }

           len = 0;
           for (subitem = state->subitems_head;
               subitem != NULL; subitem = subitem->next) {
              PORT_Memcpy (item->data + len, subitem->data, subitem->len);
              len += subitem->len;
           }
           item->len = len;

           /*
            * Because we use arenas and have a mark set, we later free
            * everything we have allocated, so this does *not* present
            * a memory leak (it is just temporarily left dangling).
            */
           state->subitems_head = state->subitems_tail = NULL;
       }

       if (state->contents_length == 0 && (! state->indefinite)) {
           /*
            * A zero-length simple or constructed string; we are done.
            */
           state->place = afterEndOfContents;
       } else if (state->found_tag_modifiers & SEC_ASN1_CONSTRUCTED) {
           const SEC_ASN1Template *sub;

           switch (state->underlying_kind) {
             case SEC_ASN1_ANY:
             case SEC_ASN1_ANY_CONTENTS:
              sub = SEC_AnyTemplate;
              break;
             case SEC_ASN1_BIT_STRING:
              sub = SEC_BitStringTemplate;
              break;
             case SEC_ASN1_BMP_STRING:
              sub = SEC_BMPStringTemplate;
              break;
             case SEC_ASN1_GENERALIZED_TIME:
              sub = SEC_GeneralizedTimeTemplate;
              break;
             case SEC_ASN1_IA5_STRING:
              sub = SEC_IA5StringTemplate;
              break;
             case SEC_ASN1_OCTET_STRING:
              sub = SEC_OctetStringTemplate;
              break;
             case SEC_ASN1_PRINTABLE_STRING:
              sub = SEC_PrintableStringTemplate;
              break;
             case SEC_ASN1_T61_STRING:
              sub = SEC_T61StringTemplate;
              break;
             case SEC_ASN1_UNIVERSAL_STRING:
              sub = SEC_UniversalStringTemplate;
              break;
             case SEC_ASN1_UTC_TIME:
              sub = SEC_UTCTimeTemplate;
              break;
             case SEC_ASN1_UTF8_STRING:
              sub = SEC_UTF8StringTemplate;
              break;
             case SEC_ASN1_VISIBLE_STRING:
              sub = SEC_VisibleStringTemplate;
              break;
             case SEC_ASN1_SKIP:
              sub = SEC_SkipTemplate;
              break;
             default:              /* redundant given outer switch cases, but */
              PORT_Assert(0);      /* the compiler does not seem to know that, */
              sub = NULL;   /* so just do enough to quiet it. */
              break;
           }

           state->place = duringConstructedString;
           state = sec_asn1d_push_state (state->top, sub, item, PR_TRUE);
           if (state != NULL) {
              state->substring = PR_TRUE; /* XXX propogate? */
              state = sec_asn1d_init_state_based_on_template (state);
           }
       } else if (state->indefinite) {
           /*
            * An indefinite-length string *must* be constructed!
            */
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
       } else {
           /*
            * A non-zero-length simple string.
            */
           if (state->underlying_kind == SEC_ASN1_BIT_STRING)
              state->place = beforeBitString;
           else
              state->place = duringLeaf;
       }
       break;

      default:
       /*
        * We are allocating for a simple leaf item.
        */
       if (state->contents_length) {
           if (state->dest != NULL) {
              item = (SECItem *)(state->dest);
              item->len = 0;
              if (state->top->filter_only) {
                  item->data = NULL;
              } else {
                  item->data = (unsigned char*)
                                sec_asn1d_zalloc (state->top->their_pool,
                                             state->contents_length);
                  if (item->data == NULL) {
                     state->top->status = decodeError;
                     return;
                  }
              }
           }
           state->place = duringLeaf;
       } else {
           /*
            * An indefinite-length or zero-length item is not allowed.
            * (All legal cases of such were handled above.)
            */
           PORT_SetError (SEC_ERROR_BAD_DER);
           state->top->status = decodeError;
       }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2272 of file secasn1d.c.

{
    PORT_Assert (state->place == beforeEndOfContents);

    if (state->indefinite) {
       state->place = duringEndOfContents;
       state->pending = 2;
    } else {
       state->place = afterEndOfContents;
    }
}

Here is the caller graph for this function:

static sec_asn1d_state* sec_asn1d_push_state ( SEC_ASN1DecoderContext *  cx,
const SEC_ASN1Template theTemplate,
void dest,
PRBool  new_depth 
) [static]

Definition at line 377 of file secasn1d.c.

{
    sec_asn1d_state *state, *new_state;

    state = cx->current;

    PORT_Assert (state == NULL || state->child == NULL);

    if (state != NULL) {
       PORT_Assert (state->our_mark == NULL);
       state->our_mark = PORT_ArenaMark (cx->our_pool);
    }

    new_state = (sec_asn1d_state*)sec_asn1d_zalloc (cx->our_pool, 
                                              sizeof(*new_state));
    if (new_state == NULL) {
       goto loser;
    }

    new_state->top         = cx;
    new_state->parent      = state;
    new_state->theTemplate = theTemplate;
    new_state->place       = notInUse;
    if (dest != NULL)
       new_state->dest = (char *)dest + theTemplate->offset;

    if (state != NULL) {
       new_state->depth = state->depth;
       if (new_depth) {
           if (++new_state->depth > SEC_ASN1D_MAX_DEPTH) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              goto loser;
           }
       }
       state->child = new_state;
    }

    cx->current = new_state;
    return new_state;

loser:
    cx->status = decodeError;
    if (state != NULL) {
       PORT_ArenaRelease(cx->our_pool, state->our_mark);
       state->our_mark = NULL;
    }
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_record_any_header ( sec_asn1d_state state,
const char *  buf,
unsigned long  len 
) [static]

Definition at line 1698 of file secasn1d.c.

{
    SECItem *item;

    item = (SECItem *)(state->dest);
    if (item != NULL && item->data != NULL) {
       PORT_Assert (state->substring);
       PORT_Memcpy (item->data + item->len, buf, len);
       item->len += len;
    } else {
       sec_asn1d_add_to_subitems (state, buf, len, PR_TRUE);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_reuse_encoding ( sec_asn1d_state state) [static]

Definition at line 1455 of file secasn1d.c.

{
    sec_asn1d_state *child;
    unsigned long consumed;
    SECItem *item;
    void *dest;


    child = state->child;
    PORT_Assert (child != NULL);

    consumed = child->consumed;
    child->consumed = 0;

    item = (SECItem *)(state->dest);
    PORT_Assert (item != NULL);

    PORT_Assert (item->len == consumed);

    /*
     * Free any grandchild.
     */
    sec_asn1d_free_child (child, PR_FALSE);

    /*
     * Notify after the SAVE field.
     */
    sec_asn1d_notify_after (state->top, state->dest, state->depth);

    /*
     * Adjust to get new dest and move forward.
     */
    dest = (char *)state->dest - state->theTemplate->offset;
    state->theTemplate++;
    child->dest = (char *)dest + state->theTemplate->offset;
    child->theTemplate = state->theTemplate;

    /*
     * Notify before the "real" field.
     */
    PORT_Assert (state->depth == child->depth);
    sec_asn1d_notify_before (state->top, child->dest, child->depth);

    /*
     * This will tell DecoderUpdate to return when it is done.
     */
    state->place = afterSaveEncoding;

    /*
     * We already have a child; "push" it by making it current.
     */
    state->top->current = child;

    /*
     * And initialize it so it is ready to parse.
     */
    (void) sec_asn1d_init_state_based_on_template(child);

    /*
     * Now parse that out of our data.
     */
    if (SEC_ASN1DecoderUpdate (state->top,
                            (char *) item->data, item->len) != SECSuccess)
       return;
    if (state->top->status == needBytes) {
       return;
    }

    PORT_Assert (state->top->current == state);
    PORT_Assert (state->child == child);

    /*
     * That should have consumed what we consumed before.
     */
    PORT_Assert (consumed == child->consumed);
    child->consumed = 0;

    /*
     * Done.
     */
    state->consumed += consumed;
    child->place = notInUse;
    state->place = afterEndOfContents;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sec_asn1d_scrub_state ( sec_asn1d_state state) [static]

Definition at line 430 of file secasn1d.c.

{
    /*
     * Some default "scrubbing".
     * XXX right set of initializations?
     */
    state->place = beforeIdentifier;
    state->endofcontents = PR_FALSE;
    state->indefinite = PR_FALSE;
    state->missing = PR_FALSE;
    PORT_Assert (state->consumed == 0);
}

Here is the caller graph for this function:

unsigned long sec_asn1d_uinteger ( SECItem *  src)

Definition at line 2502 of file secasn1d.c.

{
    unsigned long value;
    int len;

    if (src->len > 5 || (src->len > 4 && src->data[0] == 0))
       return 0;

    value = 0;
    len = src->len;
    while (len) {
       value <<= 8;
       value |= src->data[--len];
    }
    return value;
}
static void* sec_asn1d_zalloc ( PRArenaPool poolp,
unsigned long  len 
) [static]

Definition at line 365 of file secasn1d.c.

{
    void *thing;

    thing = sec_asn1d_alloc (poolp, len);
    if (thing != NULL)
       PORT_Memset (thing, 0, len);
    return thing;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus SEC_ASN1Decode ( PRArenaPool poolp,
void dest,
const SEC_ASN1Template theTemplate,
const char *  buf,
long  len 
)

Definition at line 2951 of file secasn1d.c.

{
    SEC_ASN1DecoderContext *dcx;
    SECStatus urv, frv;

    dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate);
    if (dcx == NULL)
       return SECFailure;

    urv = SEC_ASN1DecoderUpdate (dcx, buf, len);
    frv = SEC_ASN1DecoderFinish (dcx);

    if (urv != SECSuccess)
       return urv;

    return frv;
}
SECStatus SEC_ASN1DecodeInteger ( SECItem *  src,
unsigned long value 
)

Definition at line 2520 of file secasn1d.c.

{
    unsigned long v;
    unsigned int i;
    
    if (src == NULL) {
       PORT_SetError(SEC_ERROR_INVALID_ARGS);
       return SECFailure;
    }

    if (src->len > sizeof(unsigned long)) {
       PORT_SetError(SEC_ERROR_INVALID_ARGS);
       return SECFailure;
    }

    if (src->data == NULL) {
       PORT_SetError(SEC_ERROR_INVALID_ARGS);
       return SECFailure;
    }

    if (src->data[0] & 0x80)
       v = -1;              /* signed and negative - start with all 1's */
    else
       v = 0;

    for (i= 0; i < src->len; i++) {
       /* shift in next byte */
       v <<= 8;
       v |= src->data[i];
    }
    *value = v;
    return SECSuccess;
}
SECStatus SEC_ASN1DecodeItem ( PRArenaPool poolp,
void dest,
const SEC_ASN1Template theTemplate,
const SECItem *  src 
)

Definition at line 2973 of file secasn1d.c.

{
    return SEC_ASN1Decode (poolp, dest, theTemplate,
                        (const char *)src->data, src->len);
}
void SEC_ASN1DecoderAbort ( SEC_ASN1DecoderContext *  cx,
int  error 
)

Definition at line 2942 of file secasn1d.c.

void SEC_ASN1DecoderClearFilterProc ( SEC_ASN1DecoderContext *  cx)

Definition at line 2914 of file secasn1d.c.

{
    /* check that we are "between" fields here */
    PORT_Assert (cx->during_notify);

    cx->filter_proc = NULL;
    cx->filter_arg = NULL;
    cx->filter_only = PR_FALSE;
}
void SEC_ASN1DecoderClearNotifyProc ( SEC_ASN1DecoderContext *  cx)

Definition at line 2935 of file secasn1d.c.

{
    cx->notify_proc = NULL;
    cx->notify_arg = NULL;  /* not necessary; just being clean */
}
SECStatus SEC_ASN1DecoderFinish ( SEC_ASN1DecoderContext *  cx)

Definition at line 2837 of file secasn1d.c.

{
    SECStatus rv;

    if (cx->status == needBytes) {
       PORT_SetError (SEC_ERROR_BAD_DER);
       rv = SECFailure;
    } else {
       rv = SECSuccess;
    }

    /*
     * XXX anything else that needs to be finished?
     */

    PORT_FreeArena (cx->our_pool, PR_TRUE);

    return rv;
}
void SEC_ASN1DecoderSetFilterProc ( SEC_ASN1DecoderContext *  cx,
SEC_ASN1WriteProc  fn,
void arg,
PRBool  only 
)

Definition at line 2900 of file secasn1d.c.

{
    /* check that we are "between" fields here */
    PORT_Assert (cx->during_notify);

    cx->filter_proc = fn;
    cx->filter_arg = arg;
    cx->filter_only = only;
}
void SEC_ASN1DecoderSetNotifyProc ( SEC_ASN1DecoderContext *  cx,
SEC_ASN1NotifyProc  fn,
void arg 
)

Definition at line 2926 of file secasn1d.c.

{
    cx->notify_proc = fn;
    cx->notify_arg = arg;
}
SEC_ASN1DecoderContext* SEC_ASN1DecoderStart ( PRArenaPool their_pool,
void dest,
const SEC_ASN1Template theTemplate 
)

Definition at line 2859 of file secasn1d.c.

{
    PRArenaPool *our_pool;
    SEC_ASN1DecoderContext *cx;

    our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
    if (our_pool == NULL)
       return NULL;

    cx = (SEC_ASN1DecoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
    if (cx == NULL) {
       PORT_FreeArena (our_pool, PR_FALSE);
       return NULL;
    }

    cx->our_pool = our_pool;
    if (their_pool != NULL) {
       cx->their_pool = their_pool;
#ifdef SEC_ASN1D_FREE_ON_ERROR
       cx->their_mark = PORT_ArenaMark (their_pool);
#endif
    }

    cx->status = needBytes;

    if (sec_asn1d_push_state(cx, theTemplate, dest, PR_FALSE) == NULL
       || sec_asn1d_init_state_based_on_template (cx->current) == NULL) {
       /*
        * Trouble initializing (probably due to failed allocations)
        * requires that we just give up.
        */
       PORT_FreeArena (our_pool, PR_FALSE);
       return NULL;
    }

    return cx;
}
SECStatus SEC_ASN1DecoderUpdate ( SEC_ASN1DecoderContext *  cx,
const char *  buf,
unsigned long  len 
)

Definition at line 2596 of file secasn1d.c.

{
    sec_asn1d_state *state = NULL;
    unsigned long consumed;
    SEC_ASN1EncodingPart what;
    sec_asn1d_state *stateEnd = cx->current;

    if (cx->status == needBytes)
       cx->status = keepGoing;

    while (cx->status == keepGoing) {
       state = cx->current;
       what = SEC_ASN1_Contents;
       consumed = 0;
#ifdef DEBUG_ASN1D_STATES
        printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
               (state->place >= 0 && state->place <= notInUse) ?
               place_names[ state->place ] : "(undefined)",
               (unsigned int)((unsigned char *)buf)[ consumed ],
               buf, consumed);
        dump_states(cx);
#endif /* DEBUG_ASN1D_STATES */
       switch (state->place) {
         case beforeIdentifier:
           consumed = sec_asn1d_parse_identifier (state, buf, len);
           what = SEC_ASN1_Identifier;
           break;
         case duringIdentifier:
           consumed = sec_asn1d_parse_more_identifier (state, buf, len);
           what = SEC_ASN1_Identifier;
           break;
         case afterIdentifier:
           sec_asn1d_confirm_identifier (state);
           break;
         case beforeLength:
           consumed = sec_asn1d_parse_length (state, buf, len);
           what = SEC_ASN1_Length;
           break;
         case duringLength:
           consumed = sec_asn1d_parse_more_length (state, buf, len);
           what = SEC_ASN1_Length;
           break;
         case afterLength:
           sec_asn1d_prepare_for_contents (state);
           break;
         case beforeBitString:
           consumed = sec_asn1d_parse_bit_string (state, buf, len);
           break;
         case duringBitString:
           consumed = sec_asn1d_parse_more_bit_string (state, buf, len);
           break;
         case duringConstructedString:
           sec_asn1d_next_substring (state);
           break;
         case duringGroup:
           sec_asn1d_next_in_group (state);
           break;
         case duringLeaf:
           consumed = sec_asn1d_parse_leaf (state, buf, len);
           break;
         case duringSaveEncoding:
           sec_asn1d_reuse_encoding (state);
           if (cx->status == decodeError) {
              /* recursive call has already popped all states from stack.
              ** Bail out quickly.
              */
              return SECFailure;
           }
           if (cx->status == needBytes) {
              /* recursive call wanted more data. Fatal. Clean up below. */
              PORT_SetError (SEC_ERROR_BAD_DER);
              cx->status = decodeError;
           }
           break;
         case duringSequence:
           sec_asn1d_next_in_sequence (state);
           break;
         case afterConstructedString:
           sec_asn1d_concat_substrings (state);
           break;
         case afterExplicit:
         case afterImplicit:
         case afterInline:
         case afterPointer:
           sec_asn1d_absorb_child (state);
           break;
         case afterGroup:
           sec_asn1d_concat_group (state);
           break;
         case afterSaveEncoding:
           /* SEC_ASN1DecoderUpdate has called itself recursively to 
           ** decode SAVEd encoded data, and now is done decoding that.
           ** Return to the calling copy of SEC_ASN1DecoderUpdate.
           */
           return SECSuccess;
         case beforeEndOfContents:
           sec_asn1d_prepare_for_end_of_contents (state);
           break;
         case duringEndOfContents:
           consumed = sec_asn1d_parse_end_of_contents (state, buf, len);
           what = SEC_ASN1_EndOfContents;
           break;
         case afterEndOfContents:
           sec_asn1d_pop_state (state);
           break;
          case beforeChoice:
            state = sec_asn1d_before_choice(state);
            break;
          case duringChoice:
            state = sec_asn1d_during_choice(state);
            break;
          case afterChoice:
            sec_asn1d_after_choice(state);
            break;
         case notInUse:
         default:
           /* This is not an error, but rather a plain old BUG! */
           PORT_Assert (0);
           PORT_SetError (SEC_ERROR_BAD_DER);
           cx->status = decodeError;
           break;
       }

       if (cx->status == decodeError)
           break;

       /* We should not consume more than we have.  */
       PORT_Assert (consumed <= len);
       if (consumed > len) {
           PORT_SetError (SEC_ERROR_BAD_DER);
           cx->status = decodeError;
           break;
       }

       /* It might have changed, so we have to update our local copy.  */
       state = cx->current;

       /* If it is NULL, we have popped all the way to the top.  */
       if (state == NULL) {
           PORT_Assert (consumed == 0);
#if 0  /* XXX I want this here, but it seems that we have situations (like
        * downloading a pkcs7 cert chain from some issuers) that give us a
        * length which is greater than the entire encoding.  So, we cannot
        * have this be an error.
        */
           if (len > 0) {
              PORT_SetError (SEC_ERROR_BAD_DER);
              cx->status = decodeError;
           } else
#endif
              cx->status = allDone;
           break;
       }
       else if (state->theTemplate->kind == SEC_ASN1_SKIP_REST) {
           cx->status = allDone;
           break;
       }
         
       if (consumed == 0)
           continue;

       /*
        * The following check is specifically looking for an ANY
        * that is *not* also an INNER, because we need to save aside
        * all bytes in that case -- the contents parts will get
        * handled like all other contents, and the end-of-contents
        * bytes are added by the concat code, but the outer header
        * bytes need to get saved too, so we do them explicitly here.
        */
       if (state->underlying_kind == SEC_ASN1_ANY
           && !cx->filter_only && (what == SEC_ASN1_Identifier
                                || what == SEC_ASN1_Length)) {
           sec_asn1d_record_any_header (state, buf, consumed);
       }

       /*
        * We had some number of good, accepted bytes.  If the caller
        * has registered to see them, pass them along.
        */
       if (state->top->filter_proc != NULL) {
           int depth;

           depth = state->depth;
           if (what == SEC_ASN1_EndOfContents && !state->indefinite) {
              PORT_Assert (state->parent != NULL
                          && state->parent->indefinite);
              depth--;
              PORT_Assert (depth == state->parent->depth);
           }
           (* state->top->filter_proc) (state->top->filter_arg,
                                    buf, consumed, depth, what);
       }

       state->consumed += consumed;
       buf += consumed;
       len -= consumed;
    }

    if (cx->status == decodeError) {
       while (state != NULL && stateEnd->parent!=state) {
           sec_asn1d_free_child (state, PR_TRUE);
           state = state->parent;
       }
#ifdef SEC_ASN1D_FREE_ON_ERROR     /*
                             * XXX This does not work because we can
                             * end up leaving behind dangling pointers
                             * to stuff that was allocated.  In order
                             * to make this really work (which would
                             * be a good thing, I think), we need to
                             * keep track of every place/pointer that
                             * was allocated and make sure to NULL it
                             * out before we then free back to the mark.     
                             */
       if (cx->their_pool != NULL) {
           PORT_Assert (cx->their_mark != NULL);
           PORT_ArenaRelease (cx->their_pool, cx->their_mark);
       }
#endif
       return SECFailure;
    }

#if 0  /* XXX This is what I want, but cannot have because it seems we
        * have situations (like when downloading a pkcs7 cert chain from
        * some issuers) that give us a total length which is greater than
        * the entire encoding.  So, we have to allow allDone to have a
        * remaining length greater than zero.  I wanted to catch internal
        * bugs with this, noticing when we do not have the right length.
        * Oh well.
        */
    PORT_Assert (len == 0
               && (cx->status == needBytes || cx->status == allDone));
#else
    PORT_Assert ((len == 0 && cx->status == needBytes)
               || cx->status == allDone);
#endif
    return SECSuccess;
}

Variable Documentation

Initial value:
 {
    { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3005 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_BIT_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3021 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_BMP_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3037 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_BOOLEAN, 0, NULL, sizeof(SECItem) }
}

Definition at line 3053 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) }
}

Definition at line 3069 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
}

Definition at line 3085 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_IA5_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3101 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) }
}

Definition at line 3117 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) }
}

Definition at line 3133 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_OBJECT_ID, 0, NULL, sizeof(SECItem) }
}

Definition at line 3149 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_OCTET_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3165 of file secasn1d.c.

Initial value:

Definition at line 3009 of file secasn1d.c.

Initial value:

Definition at line 3025 of file secasn1d.c.

Initial value:

Definition at line 3041 of file secasn1d.c.

Initial value:

Definition at line 3057 of file secasn1d.c.

Initial value:

Definition at line 3073 of file secasn1d.c.

Initial value:

Definition at line 3089 of file secasn1d.c.

Initial value:

Definition at line 3105 of file secasn1d.c.

Initial value:

Definition at line 3121 of file secasn1d.c.

Initial value:

Definition at line 3137 of file secasn1d.c.

Initial value:

Definition at line 3153 of file secasn1d.c.

Initial value:

Definition at line 3169 of file secasn1d.c.

Initial value:

Definition at line 3185 of file secasn1d.c.

Initial value:

Definition at line 3201 of file secasn1d.c.

Initial value:

Definition at line 3217 of file secasn1d.c.

Initial value:

Definition at line 3233 of file secasn1d.c.

Initial value:

Definition at line 3249 of file secasn1d.c.

Initial value:

Definition at line 3265 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_PRINTABLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
}

Definition at line 3181 of file secasn1d.c.

Initial value:

Definition at line 3013 of file secasn1d.c.

Initial value:

Definition at line 3029 of file secasn1d.c.

Initial value:

Definition at line 3045 of file secasn1d.c.

Initial value:

Definition at line 3061 of file secasn1d.c.

Initial value:

Definition at line 3077 of file secasn1d.c.

Initial value:

Definition at line 3093 of file secasn1d.c.

Initial value:

Definition at line 3109 of file secasn1d.c.

Initial value:

Definition at line 3125 of file secasn1d.c.

Initial value:

Definition at line 3141 of file secasn1d.c.

Initial value:

Definition at line 3157 of file secasn1d.c.

Initial value:

Definition at line 3173 of file secasn1d.c.

Initial value:

Definition at line 3189 of file secasn1d.c.

Initial value:

Definition at line 3205 of file secasn1d.c.

Initial value:

Definition at line 3221 of file secasn1d.c.

Initial value:

Definition at line 3237 of file secasn1d.c.

Initial value:

Definition at line 3253 of file secasn1d.c.

Initial value:

Definition at line 3269 of file secasn1d.c.

Initial value:

Definition at line 3017 of file secasn1d.c.

Initial value:

Definition at line 3033 of file secasn1d.c.

Initial value:

Definition at line 3049 of file secasn1d.c.

Initial value:

Definition at line 3065 of file secasn1d.c.

Initial value:

Definition at line 3081 of file secasn1d.c.

Initial value:

Definition at line 3097 of file secasn1d.c.

Initial value:

Definition at line 3113 of file secasn1d.c.

Initial value:

Definition at line 3129 of file secasn1d.c.

Initial value:

Definition at line 3145 of file secasn1d.c.

Initial value:

Definition at line 3161 of file secasn1d.c.

Initial value:

Definition at line 3177 of file secasn1d.c.

Initial value:

Definition at line 3193 of file secasn1d.c.

Initial value:

Definition at line 3209 of file secasn1d.c.

Initial value:

Definition at line 3225 of file secasn1d.c.

Initial value:

Definition at line 3241 of file secasn1d.c.

Initial value:

Definition at line 3257 of file secasn1d.c.

Initial value:

Definition at line 3273 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_SKIP }
}

Definition at line 3285 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_T61_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3197 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_UNIVERSAL_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
}

Definition at line 3213 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_UTC_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3229 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_UTF8_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
}

Definition at line 3245 of file secasn1d.c.

Initial value:
 {
    { SEC_ASN1_VISIBLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
}

Definition at line 3261 of file secasn1d.c.