secasn1d.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,402 行 · 第 1/5 页

C
2,402
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished * Encoding Rules). * * $Id: secasn1d.c,v 1.4 2000/06/20 13:24:01 chrisk%netscape.com Exp $ */#include "secasn1.h"#include "secerr.h"typedef enum {    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} sec_asn1d_parse_place;#ifdef DEBUG_ASN1D_STATESstatic const char *place_names[] = {    "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"};#endif /* DEBUG_ASN1D_STATES */typedef enum {    allDone,    decodeError,    keepGoing,    needBytes} sec_asn1d_parse_status;struct subitem {    const void *data;    unsigned long len;		/* only used for substrings */    struct subitem *next;};typedef struct sec_asn1d_state_struct {    SEC_ASN1DecoderContext *top;    const SEC_ASN1Template *theTemplate;    void *dest;    void *our_mark;	/* free on completion */    struct sec_asn1d_state_struct *parent;	/* aka prev */    struct sec_asn1d_state_struct *child;	/* aka next */    sec_asn1d_parse_place place;    /*     * XXX explain the next fields as clearly as possible...     */    unsigned char found_tag_modifiers;    unsigned char expect_tag_modifiers;    unsigned long check_tag_mask;    unsigned long found_tag_number;    unsigned long expect_tag_number;    unsigned long underlying_kind;    unsigned long contents_length;    unsigned long pending;    unsigned long consumed;    int depth;    /*     * Bit strings have their length adjusted -- the first octet of the     * contents contains a value between 0 and 7 which says how many bits     * at the end of the octets are not actually part of the bit string;     * when parsing bit strings we put that value here because we need it     * later, for adjustment of the length (when the whole string is done).     */    unsigned int bit_string_unused_bits;    /*     * The following are used for indefinite-length constructed strings.     */    struct subitem *subitems_head;    struct subitem *subitems_tail;    PRPackedBool	allocate,	/* when true, need to allocate the destination */	endofcontents,	/* this state ended up parsing end-of-contents octets */	explicit,	/* we are handling an explicit header */	indefinite,	/* the current item has indefinite-length encoding */	missing,	/* an optional field that was not present */	optional,	/* the template says this field may be omitted */	substring;	/* this is a substring of a constructed string */} sec_asn1d_state;#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)))/* * An "outsider" will have an opaque pointer to this, created by calling * SEC_ASN1DecoderStart().  It will be passed back in to all subsequent * calls to SEC_ASN1DecoderUpdate(), and when done it is passed to * SEC_ASN1DecoderFinish(). */struct sec_DecoderContext_struct {    PRArenaPool *our_pool;		/* for our internal allocs */    PRArenaPool *their_pool;		/* for destination structure allocs */#ifdef SEC_ASN1D_FREE_ON_ERROR		/*					 * XXX see comment below (by same					 * ifdef) that explains why this					 * does not work (need more smarts					 * in order to free back to mark)					 */    /*     * XXX how to make their_mark work in the case where they do NOT     * give us a pool pointer?     */    void *their_mark;			/* free on error */#endif    sec_asn1d_state *current;    sec_asn1d_parse_status status;    SEC_ASN1NotifyProc notify_proc;	/* call before/after handling field */    void *notify_arg;			/* argument to notify_proc */    PRBool during_notify;		/* true during call to notify_proc */    SEC_ASN1WriteProc filter_proc;	/* pass field bytes to this  */    void *filter_arg;			/* argument to that function */    PRBool filter_only;			/* do not allocate/store fields */};/* * XXX this is a fairly generic function that may belong elsewhere */static void *sec_asn1d_alloc (PRArenaPool *poolp, unsigned long len){    void *thing;    if (poolp != NULL) {	/*	 * Allocate from the pool.	 */	thing = PORT_ArenaAlloc (poolp, len);    } else {	/*	 * Allocate generically.	 */	thing = PORT_Alloc (len);    }    return thing;}/* * XXX this is a fairly generic function that may belong elsewhere */static void *sec_asn1d_zalloc (PRArenaPool *poolp, unsigned long len){    void *thing;    thing = sec_asn1d_alloc (poolp, len);    if (thing != NULL)	PORT_Memset (thing, 0, len);    return thing;}static sec_asn1d_state *sec_asn1d_push_state (SEC_ASN1DecoderContext *cx,		      const SEC_ASN1Template *theTemplate,		      void *dest, PRBool new_depth){    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) {	cx->status = decodeError;	if (state != NULL) {	    PORT_ArenaRelease(cx->our_pool, state->our_mark);	    state->our_mark = NULL;	}	return NULL;    }    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)	    new_state->depth++;	state->child = new_state;    }    cx->current = new_state;    return new_state;}static voidsec_asn1d_scrub_state (sec_asn1d_state *state){    /*     * 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);}static voidsec_asn1d_notify_before (SEC_ASN1DecoderContext *cx, void *dest, int depth){    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;}static voidsec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth){    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;}static sec_asn1d_state *sec_asn1d_init_state_based_on_template (sec_asn1d_state *state){    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 {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?