secasn1d.c

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

C
2,402
字号
    /*     * Inherit the missing status of our child, and do the ugly     * backing-up if necessary.     * (Only IMPLICIT or POINTER should encounter such; all other cases     * should have confirmed a tag *before* pushing a child.)     */    state->missing = state->child->missing;    if (state->missing) {	PORT_Assert (state->place == afterImplicit		     || state->place == afterPointer);	state->found_tag_number = state->child->found_tag_number;	state->found_tag_modifiers = state->child->found_tag_modifiers;	state->endofcontents = state->child->endofcontents;    }    /*     * Add in number of bytes consumed by child.     * (Only EXPLICIT should have already consumed bytes itself.)     */    PORT_Assert (state->place == afterExplicit || state->consumed == 0);    state->consumed += state->child->consumed;    /*     * Subtract from bytes pending; this only applies to a definite-length     * EXPLICIT field.     */    if (state->pending) {	PORT_Assert (!state->indefinite);	PORT_Assert (state->place == afterExplicit);	/*	 * If we had a definite-length explicit, then what the child	 * consumed should be what was left pending.	 */	if (state->pending != state->child->consumed) {	    if (state->pending < state->child->consumed) {		PORT_SetError (SEC_ERROR_BAD_DER);		state->top->status = decodeError;		return;	    }	    /*	     * Okay, this is a hack.  It *should* be an error whether	     * pending is too big or too small, but it turns out that	     * we had a bug in our *old* DER encoder that ended up	     * counting an explicit header twice in the case where	     * the underlying type was an ANY.  So, because we cannot	     * prevent receiving these (our own certificate server can	     * send them to us), we need to be lenient and accept them.	     * To do so, we need to pretend as if we read all of the	     * bytes that the header said we would find, even though	     * we actually came up short.	     */	    state->consumed += (state->pending - state->child->consumed);	}	state->pending = 0;    }    /*     * Indicate that we are done with child.     */    state->child->consumed = 0;    /*     * And move on to final state.     * (Technically everybody could move to afterEndOfContents except     * for an indefinite-length EXPLICIT; for simplicity though we assert     * that but let the end-of-contents code do the real determination.)     */    PORT_Assert (state->place == afterExplicit || (! state->indefinite));    state->place = beforeEndOfContents;}static voidsec_asn1d_prepare_for_end_of_contents (sec_asn1d_state *state){    PORT_Assert (state->place == beforeEndOfContents);    if (state->indefinite) {	state->place = duringEndOfContents;	state->pending = 2;    } else {	state->place = afterEndOfContents;    }}static unsigned longsec_asn1d_parse_end_of_contents (sec_asn1d_state *state,				 const char *buf, unsigned long len){    int i;    PORT_Assert (state->pending <= 2);    PORT_Assert (state->place == duringEndOfContents);    if (len == 0) {	state->top->status = needBytes;	return 0;    }    if (state->pending < len)	len = state->pending;    for (i = 0; i < len; i++) {	if (buf[i] != 0) {	    /*	     * We expect to find only zeros; if not, just give up.	     */	    PORT_SetError (SEC_ERROR_BAD_DER);	    state->top->status = decodeError;	    return 0;	}    }    state->pending -= len;    if (state->pending == 0) {	state->place = afterEndOfContents;	state->endofcontents = PR_TRUE;    }    return len;}static voidsec_asn1d_pop_state (sec_asn1d_state *state){#if 0	/* XXX I think this should always be handled explicitly by parent? */    /*     * Account for our child.     */    if (state->child != NULL) {	state->consumed += state->child->consumed;	if (state->pending) {	    PORT_Assert (!state->indefinite);	    PORT_Assert (state->child->consumed <= state->pending);	    state->pending -= state->child->consumed;	}	state->child->consumed = 0;    }#endif	/* XXX */    /*     * Free our child.     */    sec_asn1d_free_child (state, PR_FALSE);    /*     * 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;}static sec_asn1d_state *sec_asn1d_before_choice(  sec_asn1d_state *state){  sec_asn1d_state *child;  if( state->allocate ) {    void *dest;    dest = sec_asn1d_zalloc(state->top->their_pool, state->theTemplate->size);    if( (void *)NULL == dest ) {      state->top->status = decodeError;      return (sec_asn1d_state *)NULL;    }    state->dest = (char *)dest + state->theTemplate->offset;  }  child = sec_asn1d_push_state(state->top, state->theTemplate + 1,                                state->dest, PR_FALSE);  if( (sec_asn1d_state *)NULL == child ) {    return (sec_asn1d_state *)NULL;  }  sec_asn1d_scrub_state(child);  child = sec_asn1d_init_state_based_on_template(child);  if( (sec_asn1d_state *)NULL == child ) {    return (sec_asn1d_state *)NULL;  }  child->optional = PR_TRUE;  state->place = duringChoice;  return child;}static sec_asn1d_state *sec_asn1d_during_choice(  sec_asn1d_state *state){  sec_asn1d_state *child = state->child;    PORT_Assert((sec_asn1d_state *)NULL != child);  if( child->missing ) {    unsigned char child_found_tag_modifiers = 0;    unsigned long child_found_tag_number = 0;    child->theTemplate++;    if( 0 == child->theTemplate->kind ) {      /* Ran out of choices */      PORT_SetError(SEC_ERROR_BAD_DER);      state->top->status = decodeError;      return (sec_asn1d_state *)NULL;    }    state->consumed += child->consumed;    /* cargo'd from next_in_sequence innards */    if( state->pending ) {      PORT_Assert(!state->indefinite);      PORT_Assert(child->consumed <= state->pending);      state->pending -= child->consumed;      if( 0 == state->pending ) {        /* XXX uh.. not sure if I should have stopped this         * from happening before. */        PORT_Assert(0);        PORT_SetError(SEC_ERROR_BAD_DER);        state->top->status = decodeError;        return (sec_asn1d_state *)NULL;      }    }    child->consumed = 0;    sec_asn1d_scrub_state(child);    /* move it on top again */    state->top->current = child;    child_found_tag_modifiers = child->found_tag_modifiers;    child_found_tag_number = child->found_tag_number;    child = sec_asn1d_init_state_based_on_template(child);    if( (sec_asn1d_state *)NULL == child ) {      return (sec_asn1d_state *)NULL;    }    /* copy our findings to the new top */    child->found_tag_modifiers = child_found_tag_modifiers;    child->found_tag_number = child_found_tag_number;    child->optional = PR_TRUE;    child->place = afterIdentifier;    return child;  } else {    if( (void *)NULL != state->dest ) {      /* Store the enum */      int *which = (int *)((char *)state->dest + state->theTemplate->offset);      *which = (int)child->theTemplate->size;    }    child->place = notInUse;    state->place = afterChoice;    return state;  }}static voidsec_asn1d_after_choice(  sec_asn1d_state *state){  state->consumed += state->child->consumed;  state->child->consumed = 0;  state->place = afterEndOfContents;  sec_asn1d_pop_state(state);}unsigned longsec_asn1d_uinteger(SECItem *src){    unsigned long value;    int len;    if (src->len > 5 || (src->len > 4 && src->data[0] == 0))	return 0;    value = 0;    len = src->len;    while (len) {	value <<= 8;	value |= src->data[--len];    }    return value;}SECStatusSEC_ASN1DecodeInteger(SECItem *src, unsigned long *value){    unsigned long v;    int i;        if (src->len > sizeof(unsigned long))	return SECFailure;    if (src->data[0] & 0x80)	v = -1;		/* signed and negative - start with all 1's */    else	v = 0;    for (i= 0; i < src->len; i++) {	/* shift in next byte */	v <<= 8;	v |= src->data[i];    }    *value = v;    return SECSuccess;}#ifdef DEBUG_ASN1D_STATESstatic voiddump_states(  SEC_ASN1DecoderContext *cx){  sec_asn1d_state *state;  for( state = cx->current; state->parent; state = state->parent ) {    ;  }  for( ; state; state = state->child ) {    int i;    for( i = 0; i < state->depth; i++ ) {      printf("  ");    }    printf("%s: template[0]->kind = 0x%02x, expect tag number = 0x%02x\n",           (state == cx->current) ? "STATE" : "State",           state->theTemplate->kind, state->expect_tag_number);  }  return;}#endif /* DEBUG_ASN1D_STATES */SECStatusSEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx,		       const char *buf, unsigned long len){    sec_asn1d_state *state = NULL;    unsigned long consumed;    SEC_ASN1EncodingPart what;    if (cx->status == needBytes)	cx->status = keepGoing;    while (cx->status == keepGoing) {	state = cx->current;	what = SEC_ASN1_Contents;	consumed = 0;#ifdef DEBUG_ASN1D_STATES        printf("\nPLACE = %s, next byte = 0x%02x\n",               (state->place >= 0 && state->place <= notInUse) ?               place_names[ state->place ] : "(undefined)",               (unsigned int)((unsigned char *)buf)[ consumed ]);        dump_states(cx);#endif /* DEBUG_ASN1D_STATES */	switch (state->place) {	  case beforeIdentifier:	    consumed = sec_asn1d_parse_identifier (state, buf, len);	    what = SEC_ASN1_Identifier;	    break;	  case duringIdentifier:	    consumed = sec_asn1d_parse_more_identifier (state, buf, len);	    what = SEC_ASN1_Identifier;	    break;	  case afterIdentifier:	    sec_asn1d_confirm_identifier (state);	    break;	  case beforeLength:	    consumed = sec_asn1d_parse_length (state, buf, len);	    what = SEC_ASN1_Length;	    break;	  case duringLength:	    consumed = sec_asn1d_parse_more_length (state, buf, len);	    what = SEC_ASN1_Length;	    break;	  case afterLength:	    sec_asn1d_prepare_for_contents (state);	    break;	  case beforeBitString:	    consumed = sec_asn1d_parse_bit_string (state, buf, len);	    break;	  case duringBitString:	    consumed = sec_asn1d_parse_more_bit_string (state, buf, len);	    break;	  case duringConstructedString:	    sec_asn1d_next_substring (state);	    break;	  case duringGroup:	    sec_asn1d_next_in_group (state);	    break;	  case duringLeaf:	    consumed = sec_asn1d_parse_leaf (state, buf, len);	    break;	  case duringSaveEncoding:	    sec_asn1d_reuse_encoding (state);	    break;	  case duringSequence:	    sec_asn1d_next_in_sequence (state);	    break;	  case afterConstructedString:	    sec_asn1d_concat_substrings (state);	    break;	  case afterExplicit:	  case afterImplicit:	  case afterInline:	  case afterPointer:	    sec_asn1d_absorb_child (state);	    break;	  case afterGroup:	    sec_asn1d_concat_group (state);	    break;	  case afterSaveEncoding:	    /* XXX comment! */	    return SECSuccess;	  case beforeEndOfContents:	    sec_asn1d_prepare_for_end_of_contents (state);	    break;	  case duringEndOfContents:	    consumed = sec_asn1d_parse_end_of_contents (state, buf, len);	    what = SEC_ASN1_EndOfContents;	    break;	  case afterEndOfContents:	    sec_asn1d_pop_state (state);	    break;          case beforeChoice:            state = sec_asn1d_before_choice(state);            break;          case duringChoice:            state = sec_asn1d_during_choice(state);            break;          case afterChoice:            sec_asn1d_after_choice(state);            break;	  case notInUse:	  default:	    /* This is not an error, but rather a plain old BUG! */	    PORT_Assert (0);	    PORT_SetError (SEC_ERROR_BAD_DER);	    cx->status = decodeError;	    break;	}	if (cx->status == decodeError)	    break;	/* We should not consume more than we have.  */	PORT_Assert (consumed <= len);	/* 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) {	    PORT_Assert (consumed == 0);#if 0	/* XXX I want this here, but it seems that we have situations (like	 * downloading a pkcs7 cert chain from some issuers) that give us a	 * length which is greater than the entire encoding.  So

⌨️ 快捷键说明

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