secasn1e.c

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

C
1,469
字号
    child = state->child;    group = *(void ***)state->src;    /*     * Find placement of current item.     */    member = (char *)(state->child->src) - child->theTemplate->offset;    while (*group != member)	group++;    /*     * Move forward to next item.     */    group++;    if (*group == NULL) {	/*	 * That was our last one; we are done now.	 */	child->place = notInUse;	state->place = afterContents;	return;    }    child->src = (char *)(*group) + child->theTemplate->offset;    /*     * Re-"push" child.     */    sec_asn1e_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). */static voidsec_asn1e_next_in_sequence (sec_asn1e_state *state){    sec_asn1e_state *child;    PORT_Assert (state->place == duringSequence);    PORT_Assert (state->child != NULL);    child = state->child;    /*     * Do the "after" field notification.     */    sec_asn1e_notify_after (state->top, child->src, child->depth);    /*     * Move forward.     */    child->theTemplate++;    if (child->theTemplate->kind == 0) {	/*	 * We are done with this sequence.	 */	child->place = notInUse;	state->place = afterContents;	return;    }    /*     * Reset state and push.     */    child->src = (char *)state->src + child->theTemplate->offset;    /*     * Do the "before" field notification.     */    sec_asn1e_notify_before (state->top, child->src, child->depth);    state->top->current = child;    (void) sec_asn1e_init_state_based_on_template (child);}static voidsec_asn1e_after_contents (sec_asn1e_state *state){    PORT_Assert (state->place == afterContents);    if (state->indefinite)	sec_asn1e_write_end_of_contents_bytes (state);    /*     * Just make my parent be the current state.  It will then clean     * up after me and free me (or reuse me).     */    state->top->current = state->parent;}/* * This function is called whether or not we are streaming; if we * *are* streaming, our caller can also instruct us to take bytes * from the passed-in buffer (at buf, for length len, which is likely * bytes but could even mean bits if the current field is a bit string). * If we have been so instructed, we will gobble up bytes from there * (rather than from our src structure) and output them, and then * we will just return, expecting to be called again -- either with * more bytes or after our caller has instructed us that we are done * (for now) with the buffer. */SECStatusSEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,		       const char *buf, unsigned long len){    sec_asn1e_state *state;    if (cx->status == needBytes) {	PORT_Assert (buf != NULL && len != 0);	cx->status = keepGoing;    }    while (cx->status == keepGoing) {	state = cx->current;	switch (state->place) {	  case beforeHeader:	    sec_asn1e_write_header (state);	    break;	  case duringContents:	    sec_asn1e_write_contents (state, buf, len);	    break;	  case duringGroup:	    sec_asn1e_next_in_group (state);	    break;	  case duringSequence:	    sec_asn1e_next_in_sequence (state);	    break;	  case afterContents:	    sec_asn1e_after_contents (state);	    break;	  case afterImplicit:	  case afterInline:	  case afterPointer:	  case afterChoice:	    /*	     * These states are more documentation than anything.	     * They just need to force a pop.	     */	    PORT_Assert (!state->indefinite);	    state->place = afterContents;	    break;	  case notInUse:	  default:	    /* This is not an error, but rather a plain old BUG! */	    PORT_Assert (0);	    cx->status = encodeError;	    break;	}	if (cx->status == encodeError)	    break;	/* It might have changed, so we have to update our local copy.  */	state = cx->current;	/* If it is NULL, we have popped all the way to the top.  */	if (state == NULL) {	    cx->status = allDone;	    break;	}    }    if (cx->status == encodeError) {	return SECFailure;    }    return SECSuccess;}voidSEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx){    /*     * XXX anything else that needs to be finished?     */    PORT_FreeArena (cx->our_pool, PR_FALSE);}SEC_ASN1EncoderContext *SEC_ASN1EncoderStart (void *src, const SEC_ASN1Template *theTemplate,		      SEC_ASN1WriteProc output_proc, void *output_arg){    PRArenaPool *our_pool;    SEC_ASN1EncoderContext *cx;    our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);    if (our_pool == NULL)	return NULL;    cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));    if (cx == NULL) {	PORT_FreeArena (our_pool, PR_FALSE);	return NULL;    }    cx->our_pool = our_pool;    cx->output_proc = output_proc;    cx->output_arg = output_arg;    cx->status = keepGoing;    if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL	|| sec_asn1e_init_state_based_on_template (cx->current) == NULL) {	/*	 * Trouble initializing (probably due to failed allocations)	 * requires that we just give up.	 */	PORT_FreeArena (our_pool, PR_FALSE);	return NULL;    }    return cx;}/* * XXX Do we need a FilterProc, too? */voidSEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,			      SEC_ASN1NotifyProc fn, void *arg){    cx->notify_proc = fn;    cx->notify_arg = arg;}voidSEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx){    cx->notify_proc = NULL;    cx->notify_arg = NULL;	/* not necessary; just being clean */}voidSEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx){    /* XXX is there a way to check that we are "between" fields here? */    cx->streaming = PR_TRUE;}voidSEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx){    /* XXX is there a way to check that we are "between" fields here? */    cx->streaming = PR_FALSE;}voidSEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx){    /*      * XXX is there a way to check that we are "between" fields here?  this     * needs to include a check for being in between groups of items in     * a SET_OF or SEQUENCE_OF.     */    PORT_Assert (cx->streaming);    cx->from_buf = PR_TRUE;}voidSEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx){    /* we should actually be taking from buf *now* */    PORT_Assert (cx->from_buf);    if (! cx->from_buf)		/* if not, just do nothing */	return;    cx->from_buf = PR_FALSE;    if (cx->status == needBytes) {	cx->status = keepGoing;	cx->current->place = afterContents;    }}SECStatusSEC_ASN1Encode (void *src, const SEC_ASN1Template *theTemplate,		SEC_ASN1WriteProc output_proc, void *output_arg){    SEC_ASN1EncoderContext *ecx;    SECStatus rv;    ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);    if (ecx == NULL)	return SECFailure;    rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);    SEC_ASN1EncoderFinish (ecx);    return rv;}/* * XXX depth and data_kind are unused; is there a PC way to silence warnings? * (I mean "politically correct", not anything to do with intel/win platform)  */static voidsec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len,			     int depth, SEC_ASN1EncodingPart data_kind){    unsigned long *count;    count = (unsigned long*)arg;    PORT_Assert (count != NULL);    *count += len;}/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */static voidsec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len,			     int depth, SEC_ASN1EncodingPart data_kind){    SECItem *dest;    dest = (SECItem*)arg;    PORT_Assert (dest != NULL);    PORT_Memcpy (dest->data + dest->len, buf, len);    dest->len += len;}/* * Allocate an entire SECItem, or just the data part of it, to hold * "len" bytes of stuff.  Allocate from the given pool, if specified, * otherwise just do a vanilla PORT_Alloc. * * XXX This seems like a reasonable general-purpose function (for SECITEM_)? */static SECItem *sec_asn1e_allocate_item (PRArenaPool *poolp, SECItem *dest, unsigned long len){    if (poolp != NULL) {	void *release;	release = PORT_ArenaMark (poolp);	if (dest == NULL)	    dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));	if (dest != NULL) {	    dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len);	    if (dest->data == NULL) {		dest = NULL;	    }	}	if (dest == NULL) {	    /* one or both allocations failed; release everything */	    PORT_ArenaRelease (poolp, release);	} else {	    /* everything okay; unmark the arena */	    PORT_ArenaUnmark (poolp, release);	}    } else {	SECItem *indest;	indest = dest;	if (dest == NULL)	    dest = (SECItem*)PORT_Alloc (sizeof(SECItem));	if (dest != NULL) {	    dest->data = (unsigned char*)PORT_Alloc (len);	    if (dest->data == NULL) {		if (indest == NULL)		    PORT_Free (dest);		dest = NULL;	    }	}    }    return dest;}SECItem *SEC_ASN1EncodeItem (PRArenaPool *poolp, SECItem *dest, void *src,		    const SEC_ASN1Template *theTemplate){    unsigned long encoding_length;    SECStatus rv;    PORT_Assert (dest == NULL || dest->data == NULL);    encoding_length = 0;    rv = SEC_ASN1Encode (src, theTemplate,			 sec_asn1e_encode_item_count, &encoding_length);    if (rv != SECSuccess)	return NULL;    dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);    if (dest == NULL)	return NULL;    /* XXX necessary?  This really just checks for a bug in the allocate fn */    PORT_Assert (dest->data != NULL);    if (dest->data == NULL)	return NULL;    dest->len = 0;    (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);    PORT_Assert (encoding_length == dest->len);    return dest;}static SECItem *sec_asn1e_integer(PRArenaPool *poolp, SECItem *dest, unsigned long value,		  PRBool make_unsigned){    unsigned long copy;    unsigned char sign;    int len = 0;    /*     * Determine the length of the encoded value (minimum of 1).     */    copy = value;    do {	len++;	sign = copy & 0x80;	copy >>= 8;    } while (copy);    /*     * If this is an unsigned encoding, and the high bit of the last     * byte we counted was set, we need to add one to the length so     * we put a high-order zero byte in the encoding.     */    if (sign && make_unsigned)	len++;    /*     * Allocate the item (if necessary) and the data pointer within.     */    dest = sec_asn1e_allocate_item (poolp, dest, len);    if (dest == NULL)	return NULL;    /*     * Store the value, byte by byte, in the item.     */    dest->len = len;    while (len) {	dest->data[--len] = value;	value >>= 8;    }    PORT_Assert (value == 0);    return dest;}SECItem *SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value){    return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);}extern SECItem *SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,			      SECItem *dest, unsigned long value){    return sec_asn1e_integer (poolp, dest, value, PR_TRUE);}

⌨️ 快捷键说明

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