secasn1d.c

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

C
2,402
字号
	    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_DYNAMIC | 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 = 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;}static unsigned longsec_asn1d_parse_identifier (sec_asn1d_state *state,			    const char *buf, unsigned long len){    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;    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 && state->parent != NULL &&		    (state->parent->indefinite ||			(			    (state->parent->place == afterImplicit ||			     state->parent->place == afterPointer)			    && state->parent->parent != NULL && state->parent->parent->indefinite			)		    )	    ) {	    /*	     * 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;}static unsigned longsec_asn1d_parse_more_identifier (sec_asn1d_state *state,				 const char *buf, unsigned long len){    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;}static voidsec_asn1d_confirm_identifier (sec_asn1d_state *state){    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;	}    }}static unsigned longsec_asn1d_parse_length (sec_asn1d_state *state,			const char *buf, unsigned long len){    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;	}    }    return 1;}static unsigned longsec_asn1d_parse_more_length (sec_asn1d_state *state,			     const char *buf, unsigned long len){    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, 8) != 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;}static voidsec_asn1d_prepare_for_contents (sec_asn1d_state *state){    SECItem *item;    PRArenaPool *poolp;    unsigned long alloc_len;    /*     * 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;    /*     * 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);	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.	     * XXX Should we store a NULL here?  Or set state to	     * afterGroup and let that code do it?	     */	    state->place = afterEndOfContents;	}	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);	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) {	    state->top->status = decodeError;	    break;	}	if (state->dest != NULL) {

⌨️ 快捷键说明

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