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 + -
显示快捷键?