secasn1d.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,402 行 · 第 1/5 页
C
2,402 行
{ SECItem *item; item = (SECItem *)(state->dest); if (item != NULL && item->data != NULL) { PORT_Assert (state->substring); PORT_Memcpy (item->data + item->len, buf, len); item->len += len; } else { sec_asn1d_add_to_subitems (state, buf, len, PR_TRUE); }}/* * We are moving along through the substrings of a constructed string, * and have just finished parsing one -- we need to save our child data * (if the child was not already writing directly into the destination) * and then move forward by one. * * We also have to detect when we are done: * - a definite-length encoding stops when our pending value hits 0 * - an indefinite-length encoding stops when our child is empty * (which means it was the end-of-contents octets) */static voidsec_asn1d_next_substring (sec_asn1d_state *state){ sec_asn1d_state *child; SECItem *item; unsigned long child_consumed; PRBool done; PORT_Assert (state->place == duringConstructedString); PORT_Assert (state->child != NULL); child = state->child; child_consumed = child->consumed; child->consumed = 0; state->consumed += child_consumed; done = PR_FALSE; if (state->pending) { PORT_Assert (!state->indefinite); PORT_Assert (child_consumed <= state->pending); state->pending -= child_consumed; if (state->pending == 0) done = PR_TRUE; } else { PORT_Assert (state->indefinite); item = (SECItem *)(child->dest); if (item != NULL && item->data != NULL) { /* * Save the string away for later concatenation. */ PORT_Assert (item->data != NULL); sec_asn1d_add_to_subitems (state, item->data, item->len, PR_FALSE); /* * Clear the child item for the next round. */ item->data = NULL; item->len = 0; } /* * If our child was just our end-of-contents octets, we are done. */ if (child->endofcontents) done = PR_TRUE; } /* * Stop or do the next one. */ if (done) { child->place = notInUse; state->place = afterConstructedString; } else { sec_asn1d_scrub_state (child); state->top->current = child; }}/* * We are doing a SET OF or SEQUENCE OF, and have just finished an item. */static voidsec_asn1d_next_in_group (sec_asn1d_state *state){ sec_asn1d_state *child; unsigned long child_consumed; PORT_Assert (state->place == duringGroup); PORT_Assert (state->child != NULL); child = state->child; child_consumed = child->consumed; child->consumed = 0; state->consumed += child_consumed; /* * If our child was just our end-of-contents octets, we are done. */ if (child->endofcontents) { /* XXX I removed the PORT_Assert (child->dest == NULL) because there * was a bug in that a template that was a sequence of which also had * a child of a sequence of, in an indefinite group was not working * properly. This fix seems to work, (added the if statement below), * and nothing appears broken, but I am putting this note here just * in case. */ /* * XXX No matter how many times I read that comment, * I cannot figure out what case he was fixing. I believe what he * did was deliberate, so I am loathe to touch it. I need to * understand how it could ever be that child->dest != NULL but * child->endofcontents is true, and why it is important to check * that state->subitems_head is NULL. This really needs to be * figured out, as I am not sure if the following code should be * compensating for "offset", as is done a little farther below * in the more normal case. */ PORT_Assert (state->indefinite); PORT_Assert (state->pending == 0); if(child->dest && !state->subitems_head) { sec_asn1d_add_to_subitems (state, child->dest, 0, PR_FALSE); child->dest = NULL; } child->place = notInUse; state->place = afterGroup; return; } /* * Do the "after" field notification for next in group. */ sec_asn1d_notify_after (state->top, child->dest, child->depth); /* * Save it away (unless we are not storing). */ if (child->dest != NULL) { void *dest; dest = child->dest; dest = (char *)dest - child->theTemplate->offset; sec_asn1d_add_to_subitems (state, dest, 0, PR_FALSE); child->dest = NULL; } /* * Account for those bytes; see if we are done. */ if (state->pending) { PORT_Assert (!state->indefinite); PORT_Assert (child_consumed <= state->pending); state->pending -= child_consumed; if (state->pending == 0) { child->place = notInUse; state->place = afterGroup; return; } } /* * Do the "before" field notification for next item in group. */ sec_asn1d_notify_before (state->top, child->dest, child->depth); /* * Now we do the next one. */ sec_asn1d_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). * XXX The handling of "missing" is ugly. Fix it. */static voidsec_asn1d_next_in_sequence (sec_asn1d_state *state){ sec_asn1d_state *child; unsigned long child_consumed; PRBool child_missing; PORT_Assert (state->place == duringSequence); PORT_Assert (state->child != NULL); child = state->child; /* * Do the "after" field notification. */ sec_asn1d_notify_after (state->top, child->dest, child->depth); child_missing = (PRBool) child->missing; child_consumed = child->consumed; child->consumed = 0; /* * Take care of accounting. */ if (child_missing) { PORT_Assert (child->optional); } else { state->consumed += child_consumed; /* * Free any grandchild. */ sec_asn1d_free_child (child, PR_FALSE); if (state->pending) { PORT_Assert (!state->indefinite); PORT_Assert (child_consumed <= state->pending); state->pending -= child_consumed; if (state->pending == 0) { child->theTemplate++; while (child->theTemplate->kind != 0) { if ((child->theTemplate->kind & SEC_ASN1_OPTIONAL) == 0) { PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; return; } child->theTemplate++; } child->place = notInUse; state->place = afterEndOfContents; return; } } } /* * Move forward. */ child->theTemplate++; if (child->theTemplate->kind == 0) { /* * We are done with this sequence. */ child->place = notInUse; if (state->pending) { PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; } else if (child_missing) { /* * We got to the end, but have a child that started parsing * and ended up "missing". The only legitimate reason for * this is that we had one or more optional fields at the * end of our sequence, and we were encoded indefinite-length, * so when we went looking for those optional fields we * found our end-of-contents octets instead. * (Yes, this is ugly; dunno a better way to handle it.) * So, first confirm the situation, and then mark that we * are done. */ if (state->indefinite && child->endofcontents) { PORT_Assert (child_consumed == 2); state->consumed += child_consumed; state->place = afterEndOfContents; } else { PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; } } else { /* * We have to finish out, maybe reading end-of-contents octets; * let the normal logic do the right thing. */ state->place = beforeEndOfContents; } } else { unsigned char child_found_tag_modifiers = 0; unsigned long child_found_tag_number = 0; /* * Reset state and push. */ if (state->dest != NULL) child->dest = (char *)state->dest + child->theTemplate->offset; /* * Do the "before" field notification. */ sec_asn1d_notify_before (state->top, child->dest, child->depth); if (child_missing) { /* if previous child was missing, copy the tag data we already have */ child_found_tag_modifiers = child->found_tag_modifiers; child_found_tag_number = child->found_tag_number; } state->top->current = child; child = sec_asn1d_init_state_based_on_template (child); if (child_missing) { child->place = afterIdentifier; child->found_tag_modifiers = child_found_tag_modifiers; child->found_tag_number = child_found_tag_number; child->consumed = child_consumed; if (child->underlying_kind == SEC_ASN1_ANY && !child->top->filter_only) { /* * If the new field is an ANY, and we are storing, then * we need to save the tag out. We would have done this * already in the normal case, but since we were looking * for an optional field, and we did not find it, we only * now realize we need to save the tag. */ unsigned char identifier; /* * Check that we did not end up with a high tag; for that * we need to re-encode the tag into multiple bytes in order * to store it back to look like what we parsed originally. * In practice this does not happen, but for completeness * sake it should probably be made to work at some point. */ PORT_Assert (child_found_tag_number < SEC_ASN1_HIGH_TAG_NUMBER); identifier = child_found_tag_modifiers | child_found_tag_number; sec_asn1d_record_any_header (child, (char *) &identifier, 1); } } }}static voidsec_asn1d_concat_substrings (sec_asn1d_state *state){ PORT_Assert (state->place == afterConstructedString); if (state->subitems_head != NULL) { struct subitem *substring; unsigned long alloc_len, item_len; unsigned char *where; SECItem *item; PRBool is_bit_string; item_len = 0; is_bit_string = (state->underlying_kind == SEC_ASN1_BIT_STRING) ? PR_TRUE : PR_FALSE; substring = state->subitems_head; while (substring != NULL) { /* * All bit-string substrings except the last one should be * a clean multiple of 8 bits. */ if (is_bit_string && (substring->next == NULL) && (substring->len & 0x7)) { PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; return; } item_len += substring->len; substring = substring->next; } if (is_bit_string) {#ifdef XP_WIN16 /* win16 compiler gets an internal error otherwise */ alloc_len = (((long)item_len + 7) / 8);#else alloc_len = ((item_len + 7) >> 3);#endif } else { /* * Add 2 for the end-of-contents octets of an indefinite-length * ANY that is *not* also an INNER. Because we zero-allocate * below, all we need to do is increase the length here. */ if (state->underlying_kind == SEC_ASN1_ANY && state->indefinite) item_len += 2; alloc_len = item_len; } item = (SECItem *)(state->dest); PORT_Assert (item != NULL); PORT_Assert (item->data == NULL); item->data = (unsigned char*)sec_asn1d_zalloc (state->top->their_pool, alloc_len); if (item->data == NULL) { state->top->status = decodeError; return; } item->len = item_len; where = item->data; substring = state->subitems_head; while (substring != NULL) { if (is_bit_string) item_len = (substring->len + 7) >> 3; else item_len = substring->len; PORT_Memcpy (where, substring->data, item_len); where += item_len; substring = substring->next; } /* * Because we use arenas and have a mark set, we later free * everything we have allocated, so this does *not* present * a memory leak (it is just temporarily left dangling). */ state->subitems_head = state->subitems_tail = NULL; } state->place = afterEndOfContents;}static voidsec_asn1d_concat_group (sec_asn1d_state *state){ const void ***placep; PORT_Assert (state->place == afterGroup); placep = (const void***)state->dest; if (state->subitems_head != NULL) { struct subitem *item; const void **group; int count; count = 0; item = state->subitems_head; while (item != NULL) { PORT_Assert (item->next != NULL || item == state->subitems_tail); count++; item = item->next; } group = (const void**)sec_asn1d_zalloc (state->top->their_pool, (count + 1) * (sizeof(void *))); if (group == NULL) { state->top->status = decodeError; return; } PORT_Assert (placep != NULL); *placep = group; item = state->subitems_head; while (item != NULL) { *group++ = item->data; item = item->next; } *group = NULL; /* * Because we use arenas and have a mark set, we later free * everything we have allocated, so this does *not* present * a memory leak (it is just temporarily left dangling). */ state->subitems_head = state->subitems_tail = NULL; } else if (placep != NULL) { *placep = NULL; } state->place = afterEndOfContents;}/* * For those states that push a child to handle a subtemplate, * "absorb" that child (transfer necessary information). */static voidsec_asn1d_absorb_child (sec_asn1d_state *state){ /* * There is absolutely supposed to be a child there. */ PORT_Assert (state->child != NULL);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?