secasn1d.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,402 行 · 第 1/5 页
C
2,402 行
item = (SECItem *)(state->dest); item->data = NULL; item->len = 0; } state->place = afterEndOfContents; break; case SEC_ASN1_BMP_STRING: /* Error if length is not divisable by 2 */ if (state->contents_length % 2) { state->top->status = decodeError; break; } /* otherwise, handle as other string types */ goto regular_string_type; case SEC_ASN1_UNIVERSAL_STRING: /* Error if length is not divisable by 4 */ if (state->contents_length % 4) { state->top->status = decodeError; break; } /* otherwise, handle as other string types */ goto regular_string_type; case SEC_ASN1_SKIP: case SEC_ASN1_ANY: case SEC_ASN1_ANY_CONTENTS: /* * These are not (necessarily) strings, but they need nearly * identical handling (especially when we need to deal with * constructed sub-pieces), so we pretend they are. */ /* fallthru */regular_string_type: case SEC_ASN1_BIT_STRING: case SEC_ASN1_IA5_STRING: case SEC_ASN1_OCTET_STRING: case SEC_ASN1_PRINTABLE_STRING: case SEC_ASN1_T61_STRING: case SEC_ASN1_UTC_TIME: case SEC_ASN1_UTF8_STRING: case SEC_ASN1_VISIBLE_STRING: /* * We are allocating for a primitive or a constructed string. * If it is a constructed string, it may also be indefinite-length. * If it is primitive, the length can (legally) be zero. * Our first order of business is to allocate the memory for * the string, if we can (if we know the length). */ item = (SECItem *)(state->dest); /* * If the item is a definite-length constructed string, then * the contents_length is actually larger than what we need * (because it also counts each intermediate header which we * will be throwing away as we go), but it is a perfectly good * upper bound that we just allocate anyway, and then concat * as we go; we end up wasting a few extra bytes but save a * whole other copy. */ alloc_len = state->contents_length; poolp = NULL; /* quiet compiler warnings about unused... */ if (item == NULL || state->top->filter_only) { if (item != NULL) { item->data = NULL; item->len = 0; } alloc_len = 0; } else if (state->substring) { /* * If we are a substring of a constructed string, then we may * not have to allocate anything (because our parent, the * actual constructed string, did it for us). If we are a * substring and we *do* have to allocate, that means our * parent is an indefinite-length, so we allocate from our pool; * later our parent will copy our string into the aggregated * whole and free our pool allocation. */ if (item->data == NULL) { PORT_Assert (item->len == 0); poolp = state->top->our_pool; } else { alloc_len = 0; } } else { item->len = 0; item->data = NULL; poolp = state->top->their_pool; } if (alloc_len || ((! state->indefinite) && (state->subitems_head != NULL))) { struct subitem *subitem; int len; PORT_Assert (item->len == 0 && item->data == NULL); /* * Check for and handle an ANY which has stashed aside the * header (identifier and length) bytes for us to include * in the saved contents. */ if (state->subitems_head != NULL) { PORT_Assert (state->underlying_kind == SEC_ASN1_ANY); for (subitem = state->subitems_head; subitem != NULL; subitem = subitem->next) alloc_len += subitem->len; } item->data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len); if (item->data == NULL) { state->top->status = decodeError; break; } len = 0; for (subitem = state->subitems_head; subitem != NULL; subitem = subitem->next) { PORT_Memcpy (item->data + len, subitem->data, subitem->len); len += subitem->len; } item->len = len; /* * 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; } if (state->contents_length == 0 && (! state->indefinite)) { /* * A zero-length simple or constructed string; we are done. */ state->place = afterEndOfContents; } else if (state->found_tag_modifiers & SEC_ASN1_CONSTRUCTED) { const SEC_ASN1Template *sub; switch (state->underlying_kind) { case SEC_ASN1_ANY: case SEC_ASN1_ANY_CONTENTS: sub = SEC_AnyTemplate; break; case SEC_ASN1_BIT_STRING: sub = SEC_BitStringTemplate; break; case SEC_ASN1_BMP_STRING: sub = SEC_BMPStringTemplate; break; case SEC_ASN1_GENERALIZED_TIME: sub = SEC_GeneralizedTimeTemplate; break; case SEC_ASN1_IA5_STRING: sub = SEC_IA5StringTemplate; break; case SEC_ASN1_OCTET_STRING: sub = SEC_OctetStringTemplate; break; case SEC_ASN1_PRINTABLE_STRING: sub = SEC_PrintableStringTemplate; break; case SEC_ASN1_T61_STRING: sub = SEC_T61StringTemplate; break; case SEC_ASN1_UNIVERSAL_STRING: sub = SEC_UniversalStringTemplate; break; case SEC_ASN1_UTC_TIME: sub = SEC_UTCTimeTemplate; break; case SEC_ASN1_UTF8_STRING: sub = SEC_UTF8StringTemplate; break; case SEC_ASN1_VISIBLE_STRING: sub = SEC_VisibleStringTemplate; break; case SEC_ASN1_SKIP: sub = SEC_SkipTemplate; break; default: /* redundant given outer switch cases, but */ PORT_Assert(0); /* the compiler does not seem to know that, */ sub = NULL; /* so just do enough to quiet it. */ break; } state->place = duringConstructedString; state = sec_asn1d_push_state (state->top, sub, item, PR_TRUE); if (state != NULL) { state->substring = PR_TRUE; /* XXX propogate? */ state = sec_asn1d_init_state_based_on_template (state); } } else if (state->indefinite) { /* * An indefinite-length string *must* be constructed! */ PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; } else { /* * A non-zero-length simple string. */ if (state->underlying_kind == SEC_ASN1_BIT_STRING) state->place = beforeBitString; else state->place = duringLeaf; } break; default: /* * We are allocating for a simple leaf item. */ if (state->contents_length) { if (state->dest != NULL) { item = (SECItem *)(state->dest); item->len = 0; if (state->top->filter_only) { item->data = NULL; } else { item->data = (unsigned char*) sec_asn1d_zalloc (state->top->their_pool, state->contents_length); if (item->data == NULL) { state->top->status = decodeError; return; } } } state->place = duringLeaf; } else { /* * An indefinite-length or zero-length item is not allowed. * (All legal cases of such were handled above.) */ PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; } }}static voidsec_asn1d_free_child (sec_asn1d_state *state, PRBool error){ if (state->child != NULL) { PORT_Assert (error || state->child->consumed == 0); PORT_Assert (state->our_mark != NULL); PORT_ArenaRelease (state->top->our_pool, state->our_mark); if (error && state->top->their_pool == NULL) { /* * XXX We need to free anything allocated. */ PORT_Assert (0); } state->child = NULL; state->our_mark = NULL; } else { /* * It is important that we do not leave a mark unreleased/unmarked. * But I do not think we should ever have one set in this case, only * if we had a child (handled above). So check for that. If this * assertion should ever get hit, then we probably need to add code * here to release back to our_mark (and then set our_mark to NULL). */ PORT_Assert (state->our_mark == NULL); } state->place = beforeEndOfContents;}static voidsec_asn1d_reuse_encoding (sec_asn1d_state *state){ sec_asn1d_state *child; unsigned long consumed; SECItem *item; void *dest; child = state->child; PORT_Assert (child != NULL); consumed = child->consumed; child->consumed = 0; item = (SECItem *)(state->dest); PORT_Assert (item != NULL); PORT_Assert (item->len == consumed); /* * Free any grandchild. */ sec_asn1d_free_child (child, PR_FALSE); /* * Notify after the SAVE field. */ sec_asn1d_notify_after (state->top, state->dest, state->depth); /* * Adjust to get new dest and move forward. */ dest = (char *)state->dest - state->theTemplate->offset; state->theTemplate++; child->dest = (char *)dest + state->theTemplate->offset; child->theTemplate = state->theTemplate; /* * Notify before the "real" field. */ PORT_Assert (state->depth == child->depth); sec_asn1d_notify_before (state->top, child->dest, child->depth); /* * This will tell DecoderUpdate to return when it is done. */ state->place = afterSaveEncoding; /* * We already have a child; "push" it by making it current. */ state->top->current = child; /* * And initialize it so it is ready to parse. */ (void) sec_asn1d_init_state_based_on_template(child); /* * Now parse that out of our data. */ if (SEC_ASN1DecoderUpdate (state->top, (char *) item->data, item->len) != SECSuccess) return; PORT_Assert (state->top->current == state); PORT_Assert (state->child == child); /* * That should have consumed what we consumed before. */ PORT_Assert (consumed == child->consumed); child->consumed = 0; /* * Done. */ state->consumed += consumed; child->place = notInUse; state->place = afterEndOfContents;}static unsigned longsec_asn1d_parse_leaf (sec_asn1d_state *state, const char *buf, unsigned long len){ SECItem *item; if (len == 0) { state->top->status = needBytes; return 0; } if (state->pending < len) len = state->pending; item = (SECItem *)(state->dest); if (item != NULL && item->data != NULL) { PORT_Memcpy (item->data + item->len, buf, len); item->len += len; } state->pending -= len; if (state->pending == 0) state->place = beforeEndOfContents; return len;}static unsigned longsec_asn1d_parse_bit_string (sec_asn1d_state *state, const char *buf, unsigned long len){ unsigned char byte; PORT_Assert (state->pending > 0); PORT_Assert (state->place == beforeBitString); if (len == 0) { state->top->status = needBytes; return 0; } byte = (unsigned char) *buf; if (byte > 7) { PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; return 0; } state->bit_string_unused_bits = byte; state->place = duringBitString; state->pending -= 1; return 1;}static unsigned longsec_asn1d_parse_more_bit_string (sec_asn1d_state *state, const char *buf, unsigned long len){ PORT_Assert (state->pending > 0); PORT_Assert (state->place == duringBitString); len = sec_asn1d_parse_leaf (state, buf, len); if (state->place == beforeEndOfContents && state->dest != NULL) { SECItem *item; item = (SECItem *)(state->dest); if (item->len) item->len = (item->len << 3) - state->bit_string_unused_bits; } return len;}/* * XXX All callers should be looking at return value to detect * out-of-memory errors (and stop!). */static struct subitem *sec_asn1d_add_to_subitems (sec_asn1d_state *state, const void *data, unsigned long len, PRBool copy_data){ struct subitem *thing; thing = (struct subitem*)sec_asn1d_zalloc (state->top->our_pool, sizeof (struct subitem)); if (thing == NULL) { state->top->status = decodeError; return NULL; } if (copy_data) { void *copy; copy = sec_asn1d_alloc (state->top->our_pool, len); if (copy == NULL) { state->top->status = decodeError; return NULL; } PORT_Memcpy (copy, data, len); thing->data = copy; } else { thing->data = data; } thing->len = len; thing->next = NULL; if (state->subitems_head == NULL) { PORT_Assert (state->subitems_tail == NULL); state->subitems_head = state->subitems_tail = thing; } else { state->subitems_tail->next = thing; state->subitems_tail = thing; } return thing;}static voidsec_asn1d_record_any_header (sec_asn1d_state *state, const char *buf, unsigned long len)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?