secasn1d.c

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

C
2,402
字号
	    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) {	   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) {	   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->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;	}    }}static voidsec_asn1d_free_child (sec_asn1d_state *state, PRBool error){    if (state->child != NULL) {	PORT_Assert (error || state->child->consumed == 0);	PORT_Assert (state->our_mark != NULL);	PORT_ArenaRelease (state->top->our_pool, state->our_mark);	if (error && state->top->their_pool == NULL) {	    /*	     * XXX We need to free anything allocated.	     */	    PORT_Assert (0);	}	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;}static voidsec_asn1d_reuse_encoding (sec_asn1d_state *state){    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;    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;}static unsigned longsec_asn1d_parse_leaf (sec_asn1d_state *state,		      const char *buf, unsigned long len){    SECItem *item;    if (len == 0) {	state->top->status = needBytes;	return 0;    }    if (state->pending < len)	len = state->pending;    item = (SECItem *)(state->dest);    if (item != NULL && item->data != NULL) {	PORT_Memcpy (item->data + item->len, buf, len);	item->len += len;    }    state->pending -= len;    if (state->pending == 0)	state->place = beforeEndOfContents;    return len;}static unsigned longsec_asn1d_parse_bit_string (sec_asn1d_state *state,			    const char *buf, unsigned long len){    unsigned char byte;    PORT_Assert (state->pending > 0);    PORT_Assert (state->place == beforeBitString);    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;}static unsigned longsec_asn1d_parse_more_bit_string (sec_asn1d_state *state,				 const char *buf, unsigned long len){    PORT_Assert (state->pending > 0);    PORT_Assert (state->place == duringBitString);    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;}/* * XXX All callers should be looking at return value to detect * out-of-memory errors (and stop!). */static struct subitem *sec_asn1d_add_to_subitems (sec_asn1d_state *state,			   const void *data, unsigned long len,			   PRBool copy_data){    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;	    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;}static voidsec_asn1d_record_any_header (sec_asn1d_state *state,			     const char *buf,			     unsigned long len)

⌨️ 快捷键说明

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