secasn1e.c

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

C
1,469
字号
    encode_kind &= ~SEC_ASN1_OPTIONAL;    PORT_Assert (!(explicit && universal));	/* bad templates */    may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;    encode_kind &= ~SEC_ASN1_MAY_STREAM;    /* Just clear this to get it out of the way; we do not need it here */    encode_kind &= ~SEC_ASN1_DYNAMIC;    if( encode_kind & SEC_ASN1_CHOICE ) {      void *src2;      int indx = sec_asn1e_which_choice(src, theTemplate);      if( 0 == indx ) {        /* XXX set an error? "choice not found" */        /* state->top->status = encodeError; */        return 0;      }      src2 = (void *)((char *)src + theTemplate[indx].offset);      return sec_asn1e_contents_length(&theTemplate[indx], src2, noheaderp);    }    if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {	/* XXX any bits we want to disallow (PORT_Assert against) here? */	theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);	if (encode_kind & SEC_ASN1_POINTER) {	    /*	     * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER);	     * but that was too restrictive.  This needs to be fixed,	     * probably copying what the decoder now checks for, and	     * adding a big comment here to explain what the checks mean.	     * Alternatively, the check here could be omitted altogether	     * just letting sec_asn1e_init_state_based_on_template	     * do it, since that routine can do better error handling, too.	     */	    src = *(void **)src;	    if (src == NULL) {		if (optional)		    *noheaderp = PR_TRUE;		else 		    *noheaderp = PR_FALSE;		return 0;	    }	} else if (encode_kind & SEC_ASN1_INLINE) {	    /* check that there are no extraneous bits */	    PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);	}	src = (char *)src + theTemplate->offset;	if (explicit) {	    len = sec_asn1e_contents_length (theTemplate, src, noheaderp);	    if (len == 0 && optional) {		*noheaderp = PR_TRUE;	    } else if (*noheaderp) {		/* Okay, *we* do not want to add in a header, but our caller still does. */		*noheaderp = PR_FALSE;	    } else {		/* if the inner content exists, our length is		 * len(identifier) + len(length) + len(innercontent)		 * XXX we currently assume len(identifier) == 1;		 * to support a high-tag-number this would need to be smarter.		 */		len += 1 + SEC_ASN1LengthLength (len);	    }	    return len;	}	underlying_kind = theTemplate->kind;	underlying_kind &= ~SEC_ASN1_MAY_STREAM;	/* XXX Should we recurse here? */    } else {	underlying_kind = encode_kind;    }    /* This is only used in decoding; it plays no part in encoding.  */    if (underlying_kind & SEC_ASN1_SAVE) {	/* check that there are no extraneous bits */	PORT_Assert (underlying_kind == SEC_ASN1_SAVE);	*noheaderp = PR_TRUE;	return 0;    }    /* Having any of these bits is not expected here...  */    PORT_Assert ((underlying_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL				     | SEC_ASN1_INLINE | SEC_ASN1_POINTER				     | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM				     | SEC_ASN1_SAVE | SEC_ASN1_SKIP)) == 0);    if( underlying_kind & SEC_ASN1_CHOICE ) {      void *src2;      int indx = sec_asn1e_which_choice(src, theTemplate);      if( 0 == indx ) {        /* XXX set an error? "choice not found" */        /* state->top->status = encodeError; */        return 0;      }      src2 = (void *)((char *)src - theTemplate->offset + theTemplate[indx].offset);      len = sec_asn1e_contents_length(&theTemplate[indx], src2, noheaderp);    } else    switch (underlying_kind) {      case SEC_ASN1_SEQUENCE_OF:      case SEC_ASN1_SET_OF:	{	    const SEC_ASN1Template *tmpt;	    void *sub_src;	    unsigned long sub_len;	    void **group;	    len = 0;	    group = *(void ***)src;	    if (group == NULL)		break;	    tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);	    for (; *group != NULL; group++) {		sub_src = (char *)(*group) + tmpt->offset;		sub_len = sec_asn1e_contents_length (tmpt, sub_src, noheaderp);		len += sub_len;		/*		 * XXX The 1 below is the presumed length of the identifier;		 * to support a high-tag-number this would need to be smarter.		 */		if (!*noheaderp)		    len += 1 + SEC_ASN1LengthLength (sub_len);	    }	}	break;      case SEC_ASN1_SEQUENCE:      case SEC_ASN1_SET:	{	    const SEC_ASN1Template *tmpt;	    void *sub_src;	    unsigned long sub_len;	    len = 0;	    for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {		sub_src = (char *)src + tmpt->offset;		sub_len = sec_asn1e_contents_length (tmpt, sub_src, noheaderp);		len += sub_len;		/*		 * XXX The 1 below is the presumed length of the identifier;		 * to support a high-tag-number this would need to be smarter.		 */		if (!*noheaderp)		    len += 1 + SEC_ASN1LengthLength (sub_len);	    }	}	break;      case SEC_ASN1_BIT_STRING:	/* convert bit length to byte */	len = (((SECItem *)src)->len + 7) >> 3;	/* bit string contents involve an extra octet */	if (len)	    len++;	break;      default:	len = ((SECItem *)src)->len;	if (may_stream && len == 0)	    len = 1;	/* if we're streaming, we may have a secitem w/len 0 as placeholder */	break;    }    if ((len == 0 && optional) || underlying_kind == SEC_ASN1_ANY)	*noheaderp = PR_TRUE;    else 	*noheaderp = PR_FALSE;    return len;}static voidsec_asn1e_write_header (sec_asn1e_state *state){    unsigned long contents_length;    unsigned char tag_number, tag_modifiers;    PRBool noheader;    PORT_Assert (state->place == beforeHeader);    tag_number = state->tag_number;    tag_modifiers = state->tag_modifiers;    if (state->underlying_kind == SEC_ASN1_ANY) {	state->place = duringContents;	return;    }    if( state->underlying_kind & SEC_ASN1_CHOICE ) {      void *src2;      int indx = sec_asn1e_which_choice(state->src, state->theTemplate);      if( 0 == indx ) {        /* XXX set an error? "choice not found" */        state->top->status = encodeError;        return;      }      state->place = afterChoice;      state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],                                   state->src, PR_TRUE);      if( (sec_asn1e_state *)NULL != state ) {        /*         * Do the "before" field notification.         */        sec_asn1e_notify_before (state->top, state->src, state->depth);        state = sec_asn1e_init_state_based_on_template (state);      }            return;    }    /*     * We are doing a definite-length encoding.  First we have to     * walk the data structure to calculate the entire contents length.     */    contents_length = sec_asn1e_contents_length (state->theTemplate,						 state->src, &noheader);    /*     * We might be told explicitly not to put out a header.     * But it can also be the case, via a pushed subtemplate, that     * sec_asn1e_contents_length could not know that this field is     * really optional.  So check for that explicitly, too.     */    if (noheader || (contents_length == 0 && state->optional)) {	state->place = afterContents;	if (state->top->streaming && state->may_stream && state->top->from_buf)	    /* we did not find an optional indefinite string, so we don't encode it.	     * However, if TakeFromBuf is on, we stop here anyway to give our caller	     * a chance to intercept at the same point where we would stop if the	     * field were present. */	    state->top->status = needBytes;	return;    }    if (state->top->streaming && state->may_stream			      && (state->top->from_buf || !state->is_string)) {	/*	 * We need to put out an indefinite-length encoding.	 */	state->indefinite = PR_TRUE;	/*	 * The only universal types that can be constructed are SETs,	 * SEQUENCEs, and strings; so check that it is one of those,	 * or that it is not universal (e.g. context-specific).	 */	PORT_Assert ((tag_number == SEC_ASN1_SET)		     || (tag_number == SEC_ASN1_SEQUENCE)		     || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)		     || state->is_string);	tag_modifiers |= SEC_ASN1_CONSTRUCTED;	contents_length = 0;    }    sec_asn1e_write_identifier_bytes (state, tag_number | tag_modifiers);    sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);    if (contents_length == 0 && !state->indefinite) {	/*	 * If no real contents to encode, then we are done with this field.	 */	state->place = afterContents;	return;    }    /*     * An EXPLICIT is nothing but an outer header, which we have already     * written.  Now we need to do the inner header and contents.     */    if (state->explicit) {	state->place = afterContents;	state = sec_asn1e_push_state (state->top,				      SEC_ASN1GetSubtemplate(state->theTemplate,							     state->src,							     PR_TRUE),				      state->src, PR_TRUE);	if (state != NULL)	    state = sec_asn1e_init_state_based_on_template (state);	return;    }    switch (state->underlying_kind) {      case SEC_ASN1_SET_OF:      case SEC_ASN1_SEQUENCE_OF:	/*	 * We need to push a child to handle each member.	 */	{	    void **group;	    const SEC_ASN1Template *subt;	    group = *(void ***)state->src;	    if (group == NULL || *group == NULL) {		/*		 * Group is empty; we are done.		 */		state->place = afterContents;		return;	    }	    state->place = duringGroup;	    subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,					   PR_TRUE);	    state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);	    if (state != NULL)		state = sec_asn1e_init_state_based_on_template (state);	}	break;      case SEC_ASN1_SEQUENCE:      case SEC_ASN1_SET:	/*	 * We need to push a child to handle the individual fields.	 */	state->place = duringSequence;	state = sec_asn1e_push_state (state->top, state->theTemplate + 1,				      state->src, PR_TRUE);	if (state != NULL) {	    /*	     * Do the "before" field notification.	     */	    sec_asn1e_notify_before (state->top, state->src, state->depth);	    state = sec_asn1e_init_state_based_on_template (state);	}	break;      default:	/*	 * I think we do not need to do anything else.	 * XXX Correct?	 */	state->place = duringContents;	break;    }}static voidsec_asn1e_write_contents (sec_asn1e_state *state,			  const char *buf, unsigned long len){    PORT_Assert (state->place == duringContents);    if (state->top->from_buf) {	/*	 * Probably they just turned on "take from buf", but have not	 * yet given us any bytes.  If there is nothing in the buffer	 * then we have nothing to do but return and wait.	 */	if (buf == NULL || len == 0) {	    state->top->status = needBytes;	    return;	}	/*	 * We are streaming, reading from a passed-in buffer.	 * This means we are encoding a simple string or an ANY.	 * For the former, we need to put out a substring, with its	 * own identifier and length.  For an ANY, we just write it	 * out as is (our caller is required to ensure that it	 * is a properly encoded entity).	 */	PORT_Assert (state->is_string);		/* includes ANY */	if (state->underlying_kind != SEC_ASN1_ANY) {	    unsigned char identifier;	    /*	     * Create the identifier based on underlying_kind.  We cannot	     * use tag_number and tag_modifiers because this can be an	     * implicitly encoded field.  In that case, the underlying	     * substrings *are* encoded with their real tag.	     */	    identifier = state->underlying_kind & SEC_ASN1_TAG_MASK;	    /*	     * The underlying kind should just be a simple string; there	     * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.	     */	    PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);	    /*	     * Write out the tag and length for the substring.	     */	    sec_asn1e_write_identifier_bytes (state, identifier);	    if (state->underlying_kind == SEC_ASN1_BIT_STRING) {		char byte;		/*		 * Assume we have a length in bytes but we need to output		 * a proper bit string.  This interface only works for bit		 * strings that are full multiples of 8.  If support for		 * real, variable length bit strings is needed then the		 * caller will have to know to pass in a bit length instead		 * of a byte length and then this code will have to		 * perform the encoding necessary (length written is length		 * in bytes plus 1, and the first octet of string is the		 * number of bits remaining between the end of the bit		 * string and the next byte boundary).		 */		sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);		byte = 0;		sec_asn1e_write_contents_bytes (state, &byte, 1);	    } else {		sec_asn1e_write_length_bytes (state, len, PR_FALSE);	    }	}	sec_asn1e_write_contents_bytes (state, buf, len);	state->top->status = needBytes;    } else {	switch (state->underlying_kind) {	  case SEC_ASN1_SET:	  case SEC_ASN1_SEQUENCE:	    PORT_Assert (0);	    break;	  case SEC_ASN1_BIT_STRING:	    {		SECItem *item;		char rem;		item = (SECItem *)state->src;		len = (item->len + 7) >> 3;		rem = (len << 3) - item->len;	/* remaining bits */		sec_asn1e_write_contents_bytes (state, &rem, 1);		sec_asn1e_write_contents_bytes (state, (char *) item->data,						len);	    }	    break;	  case SEC_ASN1_BMP_STRING:	    /* The number of bytes must be divisable by 2 */	    if ((((SECItem *)state->src)->len) % 2) {		SEC_ASN1EncoderContext *cx;		cx = state->top;		cx->status = encodeError;		break;	    }	    /* otherwise, fall through to write the content */	    goto process_string;	  case SEC_ASN1_UNIVERSAL_STRING:	    /* The number of bytes must be divisable by 4 */	    if ((((SECItem *)state->src)->len) % 4) {		SEC_ASN1EncoderContext *cx;		cx = state->top;		cx->status = encodeError;		break;	    }	    /* otherwise, fall through to write the content */	    goto process_string;			process_string:				  default:	    {		SECItem *item;		item = (SECItem *)state->src;		sec_asn1e_write_contents_bytes (state, (char *) item->data,						item->len);	    }	    break;	}	state->place = afterContents;    }}/* * We are doing a SET OF or SEQUENCE OF, and have just finished an item. */static voidsec_asn1e_next_in_group (sec_asn1e_state *state){    sec_asn1e_state *child;    void **group;    void *member;    PORT_Assert (state->place == duringGroup);    PORT_Assert (state->child != NULL);

⌨️ 快捷键说明

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