secasn1d.c

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

C
2,402
字号
{    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);    }}/* * We are moving along through the substrings of a constructed string, * and have just finished parsing one -- we need to save our child data * (if the child was not already writing directly into the destination) * and then move forward by one. * * We also have to detect when we are done: *	- a definite-length encoding stops when our pending value hits 0 *	- an indefinite-length encoding stops when our child is empty *	  (which means it was the end-of-contents octets) */static voidsec_asn1d_next_substring (sec_asn1d_state *state){    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);	PORT_Assert (child_consumed <= state->pending);	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;    }}/* * We are doing a SET OF or SEQUENCE OF, and have just finished an item. */static voidsec_asn1d_next_in_group (sec_asn1d_state *state){    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);	PORT_Assert (child_consumed <= state->pending);	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);    state->top->current = child;}/* * We are moving along through a sequence; move forward by one, * (detecting end-of-sequence when it happens). * XXX The handling of "missing" is ugly.  Fix it. */static voidsec_asn1d_next_in_sequence (sec_asn1d_state *state){    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);	    PORT_Assert (child_consumed <= state->pending);	    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);		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 = child_found_tag_modifiers | child_found_tag_number;		sec_asn1d_record_any_header (child, (char *) &identifier, 1);	    }	}    }}static voidsec_asn1d_concat_substrings (sec_asn1d_state *state){    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;}static voidsec_asn1d_concat_group (sec_asn1d_state *state){    const void ***placep;    PORT_Assert (state->place == afterGroup);    placep = (const void***)state->dest;    if (state->subitems_head != 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;	}	PORT_Assert (placep != NULL);	*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;    } else if (placep != NULL) {	*placep = NULL;    }    state->place = afterEndOfContents;}/* * For those states that push a child to handle a subtemplate, * "absorb" that child (transfer necessary information). */static voidsec_asn1d_absorb_child (sec_asn1d_state *state){    /*     * There is absolutely supposed to be a child there.     */    PORT_Assert (state->child != NULL);

⌨️ 快捷键说明

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