secasn1e.c

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

C
1,469
字号
/* * 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 ENcoding ASN.1 data based on BER/DER (Basic/Distinguished * Encoding Rules). * * $Id: secasn1e.c,v 1.2 2000/06/13 21:56:37 chrisk%netscape.com Exp $ */#include "secasn1.h"typedef enum {    beforeHeader,    duringContents,    duringGroup,    duringSequence,    afterContents,    afterImplicit,    afterInline,    afterPointer,    afterChoice,    notInUse} sec_asn1e_parse_place;typedef enum {    allDone,    encodeError,    keepGoing,    needBytes} sec_asn1e_parse_status;typedef struct sec_asn1e_state_struct {    SEC_ASN1EncoderContext *top;    const SEC_ASN1Template *theTemplate;    void *src;    struct sec_asn1e_state_struct *parent;	/* aka prev */    struct sec_asn1e_state_struct *child;	/* aka next */    sec_asn1e_parse_place place;	/* where we are in encoding process */    /*     * XXX explain the next fields as clearly as possible...     */    unsigned char tag_modifiers;    unsigned char tag_number;    unsigned long underlying_kind;    int depth;    PRBool explicit,		/* we are handling an explicit header */	   indefinite,		/* need end-of-contents */	   is_string,		/* encoding a simple string or an ANY */	   may_stream,		/* when streaming, do indefinite encoding */	   optional;		/* omit field if it has no contents */} sec_asn1e_state;/* * An "outsider" will have an opaque pointer to this, created by calling * SEC_ASN1EncoderStart().  It will be passed back in to all subsequent * calls to SEC_ASN1EncoderUpdate() and related routines, and when done * it is passed to SEC_ASN1EncoderFinish(). */struct sec_EncoderContext_struct {    PRArenaPool *our_pool;		/* for our internal allocs */    sec_asn1e_state *current;    sec_asn1e_parse_status status;    PRBool streaming;    PRBool from_buf;    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 output_proc;	/* pass encoded bytes to this  */    void *output_arg;			/* argument to that function */};static sec_asn1e_state *sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,		      const SEC_ASN1Template *theTemplate,		      void *src, PRBool new_depth){    sec_asn1e_state *state, *new_state;    state = cx->current;    new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool, 						    sizeof(*new_state));    if (new_state == NULL) {	cx->status = encodeError;	return NULL;    }    new_state->top = cx;    new_state->parent = state;    new_state->theTemplate = theTemplate;    new_state->place = notInUse;    if (src != NULL)	new_state->src = (char *)src + 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_asn1e_scrub_state (sec_asn1e_state *state){    /*     * Some default "scrubbing".     * XXX right set of initializations?     */    state->place = beforeHeader;    state->indefinite = PR_FALSE;}static voidsec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth){    if (cx->notify_proc == NULL)	return;    cx->during_notify = PR_TRUE;    (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);    cx->during_notify = PR_FALSE;}static voidsec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth){    if (cx->notify_proc == NULL)	return;    cx->during_notify = PR_TRUE;    (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);    cx->during_notify = PR_FALSE;}static sec_asn1e_state *sec_asn1e_init_state_based_on_template (sec_asn1e_state *state){    PRBool explicit, is_string, may_stream, optional, universal;    unsigned char tag_modifiers;    unsigned long encode_kind, under_kind;    unsigned long tag_number;    encode_kind = state->theTemplate->kind;    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 */    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 ) {      under_kind = SEC_ASN1_CHOICE;    } else    if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal							      && !explicit)) {	const SEC_ASN1Template *subt;	void *src;	PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);	sec_asn1e_scrub_state (state);	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.	     */	    src = *(void **)state->src;	    state->place = afterPointer;	    if (src == NULL) {		/*		 * If this is optional, but NULL, then the field does		 * not need to be encoded.  In this case we are done;		 * we do not want to push a subtemplate.		 */		if (optional)		    return state;		/*		 * XXX this is an error; need to figure out		 * how to handle this		 */	    }	} else {	    src = state->src;	    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 {		/*		 * Save the tag modifiers and tag number here before moving		 * on to the next state in case this is a member of a		 * SEQUENCE OF		 */		state->tag_modifiers = encode_kind & SEC_ASN1_TAG_MASK					& ~SEC_ASN1_TAGNUM_MASK;		state->tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;				state->place = afterImplicit;		state->optional = optional;	    }	}	subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE);	state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);	if (state == NULL)	    return NULL;	if (universal) {	    /*	     * This is a POINTER or INLINE; just init based on that	     * and we are done.	     */	    return sec_asn1e_init_state_based_on_template (state);	}	/*	 * This is an implicit, non-universal (meaning, application-private	 * or context-specific) field.  This results in a "magic" tag but	 * encoding based on the underlying type.  We pushed a new state	 * that is based on the subtemplate (the underlying type), but	 * now we will sort of alias it to give it some of our properties	 * (tag, optional status, etc.).	 */	under_kind = state->theTemplate->kind;	if (under_kind & SEC_ASN1_MAY_STREAM) {	    may_stream = PR_TRUE;	    under_kind &= ~SEC_ASN1_MAY_STREAM;	}    } else {	under_kind = encode_kind;    }    /*     * Sanity check that there are no unwanted bits marked in under_kind.     * These bits were either removed above (after we recorded them) or     * they simply should not be found (signalling a bad/broken template).     * XXX is this the right set of bits to test here? (i.e. need to add     * or remove any?)     */    PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL				| SEC_ASN1_SKIP | SEC_ASN1_INNER				| SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM				| SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);    if (encode_kind & SEC_ASN1_ANY) {	PORT_Assert (encode_kind == under_kind);	tag_modifiers = 0;	tag_number = 0;	is_string = PR_TRUE;    } else {	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.	 */	tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;	is_string = PR_FALSE;	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:	    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: 	    /*	     * We do not yet know if we will be constructing the string,	     * so we have to wait to do this final tag modification.	     */	    is_string = PR_TRUE;	    break;	}    }    state->tag_modifiers = tag_modifiers;    state->tag_number = tag_number;    state->underlying_kind = under_kind;    state->explicit = explicit;    state->may_stream = may_stream;    state->is_string = is_string;    state->optional = optional;    sec_asn1e_scrub_state (state);    return state;}static voidsec_asn1e_write_part (sec_asn1e_state *state,		      const char *buf, unsigned long len,		      SEC_ASN1EncodingPart part){    SEC_ASN1EncoderContext *cx;    cx = state->top;    (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);}/* * XXX This assumes only single-octet identifiers.  To handle * the HIGH TAG form we would need to modify this interface and * teach it to properly encode the special form. */static voidsec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value){    char byte;    byte = (char) value;    sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);}intSEC_ASN1EncodeLength(unsigned char *buf,int value) {    int lenlen;    lenlen = SEC_ASN1LengthLength (value);    if (lenlen == 1) {	buf[0] = value;    } else {	int i;	i = lenlen - 1;	buf[0] = 0x80 | i;	while (i) {	    buf[i--] = value;	    value >>= 8;	}        PORT_Assert (value == 0);    }    return lenlen;}static voidsec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,			      PRBool indefinite){    int lenlen;    unsigned char buf[sizeof(unsigned long) + 1];    if (indefinite) {	PORT_Assert (value == 0);	buf[0] = 0x80;	lenlen = 1;    } else {	lenlen = SEC_ASN1EncodeLength(buf,value);    }    sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);}static voidsec_asn1e_write_contents_bytes (sec_asn1e_state *state,				const char *buf, unsigned long len){    sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);}static voidsec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state){    const char eoc[2] = {0, 0};    sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);}static intsec_asn1e_which_choice(  void *src,  const SEC_ASN1Template *theTemplate){  int rv;  int which = *(int *)((char *)src + theTemplate->offset);  for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {    if( which == theTemplate->size ) {      return rv;    }  }  return 0;}static unsigned longsec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src,			   PRBool *noheaderp){    unsigned long encode_kind, underlying_kind;    PRBool explicit, optional, universal, may_stream;    unsigned long len;    encode_kind = theTemplate->kind;    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;

⌨️ 快捷键说明

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