secasn1d.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,402 行 · 第 1/5 页
C
2,402 行
dest = state->dest; if (encode_kind & SEC_ASN1_INLINE) { /* check that there are no extraneous bits */ PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); state->place = afterInline; } else { state->place = afterImplicit; } } state->optional = optional; subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest, PR_FALSE); state = sec_asn1d_push_state (state->top, subt, dest, PR_FALSE); if (state == NULL) return NULL; state->allocate = child_allocate; if (universal) { state = sec_asn1d_init_state_based_on_template (state); if (state != NULL) { /* * If this field is optional, we need to record that on * the pushed child so it won't fail if the field isn't * found. I can't think of a way that this new state * could already have optional set (which we would wipe * out below if our local optional is not set) -- but * just to be sure, assert that it isn't set. */ PORT_Assert (!state->optional); state->optional = optional; } return state; } under_kind = state->theTemplate->kind; under_kind &= ~SEC_ASN1_MAY_STREAM; } else if (explicit) { /* * For explicit, we only need to match the encoding tag next, * then we will push another state to handle the entire inner * part. In this case, there is no underlying kind which plays * any part in the determination of the outer, explicit tag. * So we just set under_kind to 0, which is not a valid tag, * and the rest of the tag matching stuff should be okay. */ under_kind = 0; } else { /* * Nothing special; the underlying kind and the given encoding * information are the same. */ under_kind = encode_kind; } /* XXX is this the right set of bits to test here? */ PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0); if (encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) { PORT_Assert (encode_kind == under_kind); if (encode_kind & SEC_ASN1_SKIP) { PORT_Assert (!optional); PORT_Assert (encode_kind == SEC_ASN1_SKIP); state->dest = NULL; } check_tag_mask = 0; expect_tag_modifiers = 0; expect_tag_number = 0; } else { check_tag_mask = SEC_ASN1_TAG_MASK; expect_tag_modifiers = encode_kind & SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK; /* * XXX This assumes only single-octet identifiers. To handle * the HIGH TAG form we would need to do some more work, especially * in how to specify them in the template, because right now we * do not provide a way to specify more *tag* bits in encode_kind. */ expect_tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK; switch (under_kind & SEC_ASN1_TAGNUM_MASK) { case SEC_ASN1_SET: /* * XXX A plain old SET (as opposed to a SET OF) is not implemented. * If it ever is, remove this assert... */ PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0); /* fallthru */ case SEC_ASN1_SEQUENCE: expect_tag_modifiers |= SEC_ASN1_CONSTRUCTED; break; case SEC_ASN1_BIT_STRING: case SEC_ASN1_BMP_STRING: case SEC_ASN1_GENERALIZED_TIME: case SEC_ASN1_IA5_STRING: case SEC_ASN1_OCTET_STRING: case SEC_ASN1_PRINTABLE_STRING: case SEC_ASN1_T61_STRING: case SEC_ASN1_UNIVERSAL_STRING: case SEC_ASN1_UTC_TIME: case SEC_ASN1_UTF8_STRING: case SEC_ASN1_VISIBLE_STRING: check_tag_mask &= ~SEC_ASN1_CONSTRUCTED; break; } } state->check_tag_mask = check_tag_mask; state->expect_tag_modifiers = expect_tag_modifiers; state->expect_tag_number = expect_tag_number; state->underlying_kind = under_kind; state->explicit = explicit; state->optional = optional; sec_asn1d_scrub_state (state); return state;}static unsigned longsec_asn1d_parse_identifier (sec_asn1d_state *state, const char *buf, unsigned long len){ unsigned char byte; unsigned char tag_number; PORT_Assert (state->place == beforeIdentifier); if (len == 0) { state->top->status = needBytes; return 0; } byte = (unsigned char) *buf; tag_number = byte & SEC_ASN1_TAGNUM_MASK; if (IS_HIGH_TAG_NUMBER (tag_number)) { state->place = duringIdentifier; state->found_tag_number = 0; /* * Actually, we have no idea how many bytes are pending, but we * do know that it is at least 1. That is all we know; we have * to look at each byte to know if there is another, etc. */ state->pending = 1; } else { if (byte == 0 && state->parent != NULL && (state->parent->indefinite || ( (state->parent->place == afterImplicit || state->parent->place == afterPointer) && state->parent->parent != NULL && state->parent->parent->indefinite ) ) ) { /* * Our parent has indefinite-length encoding, and the * entire tag found is 0, so it seems that we have hit the * end-of-contents octets. To handle this, we just change * our state to that which expects to get the bytes of the * end-of-contents octets and let that code re-read this byte * so that our categorization of field types is correct. * After that, our parent will then deal with everything else. */ state->place = duringEndOfContents; state->pending = 2; state->found_tag_number = 0; state->found_tag_modifiers = 0; /* * We might be an optional field that is, as we now find out, * missing. Give our parent a clue that this happened. */ if (state->optional) state->missing = PR_TRUE; return 0; } state->place = afterIdentifier; state->found_tag_number = tag_number; } state->found_tag_modifiers = byte & ~SEC_ASN1_TAGNUM_MASK; return 1;}static unsigned longsec_asn1d_parse_more_identifier (sec_asn1d_state *state, const char *buf, unsigned long len){ unsigned char byte; int count; PORT_Assert (state->pending == 1); PORT_Assert (state->place == duringIdentifier); if (len == 0) { state->top->status = needBytes; return 0; } count = 0; while (len && state->pending) { if (HIGH_BITS (state->found_tag_number, TAG_NUMBER_BITS) != 0) { /* * The given high tag number overflows our container; * just give up. This is not likely to *ever* happen. */ PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; return 0; } state->found_tag_number <<= TAG_NUMBER_BITS; byte = (unsigned char) buf[count++]; state->found_tag_number |= (byte & TAG_NUMBER_MASK); len--; if (LAST_TAG_NUMBER_BYTE (byte)) state->pending = 0; } if (state->pending == 0) state->place = afterIdentifier; return count;}static voidsec_asn1d_confirm_identifier (sec_asn1d_state *state){ PRBool match; PORT_Assert (state->place == afterIdentifier); match = (PRBool)(((state->found_tag_modifiers & state->check_tag_mask) == state->expect_tag_modifiers) && ((state->found_tag_number & state->check_tag_mask) == state->expect_tag_number)); if (match) { state->place = beforeLength; } else { if (state->optional) { state->missing = PR_TRUE; state->place = afterEndOfContents; } else { PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; } }}static unsigned longsec_asn1d_parse_length (sec_asn1d_state *state, const char *buf, unsigned long len){ unsigned char byte; PORT_Assert (state->place == beforeLength); if (len == 0) { state->top->status = needBytes; return 0; } /* * The default/likely outcome. It may get adjusted below. */ state->place = afterLength; byte = (unsigned char) *buf; if (LENGTH_IS_SHORT_FORM (byte)) { state->contents_length = byte; } else { state->contents_length = 0; state->pending = LONG_FORM_LENGTH (byte); if (state->pending == 0) { state->indefinite = PR_TRUE; } else { state->place = duringLength; } } return 1;}static unsigned longsec_asn1d_parse_more_length (sec_asn1d_state *state, const char *buf, unsigned long len){ int count; PORT_Assert (state->pending > 0); PORT_Assert (state->place == duringLength); if (len == 0) { state->top->status = needBytes; return 0; } count = 0; while (len && state->pending) { if (HIGH_BITS (state->contents_length, 8) != 0) { /* * The given full content length overflows our container; * just give up. */ PORT_SetError (SEC_ERROR_BAD_DER); state->top->status = decodeError; return 0; } state->contents_length <<= 8; state->contents_length |= (unsigned char) buf[count++]; len--; state->pending--; } if (state->pending == 0) state->place = afterLength; return count;}static voidsec_asn1d_prepare_for_contents (sec_asn1d_state *state){ SECItem *item; PRArenaPool *poolp; unsigned long alloc_len; /* * XXX I cannot decide if this allocation should exclude the case * where state->endofcontents is true -- figure it out! */ if (state->allocate) { void *dest; PORT_Assert (state->dest == NULL); /* * We are handling a POINTER or a member of a GROUP, and need to * allocate for the data structure. */ dest = sec_asn1d_zalloc (state->top->their_pool, state->theTemplate->size); if (dest == NULL) { state->top->status = decodeError; return; } state->dest = (char *)dest + state->theTemplate->offset; /* * For a member of a GROUP, our parent will later put the * pointer wherever it belongs. But for a POINTER, we need * to record the destination now, in case notify or filter * procs need access to it -- they cannot find it otherwise, * until it is too late (for one-pass processing). */ if (state->parent->place == afterPointer) { void **placep; placep = state->parent->dest; *placep = dest; } } /* * Remember, length may be indefinite here! In that case, * both contents_length and pending will be zero. */ state->pending = state->contents_length; /* * An EXPLICIT is nothing but an outer header, which we have * already parsed and accepted. Now we need to do the inner * header and its contents. */ if (state->explicit) { state->place = afterExplicit; state = sec_asn1d_push_state (state->top, SEC_ASN1GetSubtemplate(state->theTemplate, state->dest, PR_FALSE), state->dest, PR_TRUE); if (state != NULL) state = sec_asn1d_init_state_based_on_template (state); return; } /* * For GROUP (SET OF, SEQUENCE OF), even if we know the length here * we cannot tell how many items we will end up with ... so push a * state that can keep track of "children" (the individual members * of the group; we will allocate as we go and put them all together * at the end. */ if (state->underlying_kind & SEC_ASN1_GROUP) { /* XXX If this assertion holds (should be able to confirm it via * inspection, too) then move this code into the switch statement * below under cases SET_OF and SEQUENCE_OF; it will be cleaner. */ PORT_Assert (state->underlying_kind == SEC_ASN1_SET_OF || state->underlying_kind == SEC_ASN1_SEQUENCE_OF); if (state->contents_length != 0 || state->indefinite) { const SEC_ASN1Template *subt; state->place = duringGroup; subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest, PR_FALSE); state = sec_asn1d_push_state (state->top, subt, NULL, PR_TRUE); if (state != NULL) { if (!state->top->filter_only) state->allocate = PR_TRUE; /* XXX propogate this? */ /* * Do the "before" field notification for next in group. */ sec_asn1d_notify_before (state->top, state->dest, state->depth); state = sec_asn1d_init_state_based_on_template (state); } } else { /* * A group of zero; we are done. * XXX Should we store a NULL here? Or set state to * afterGroup and let that code do it? */ state->place = afterEndOfContents; } return; } switch (state->underlying_kind) { case SEC_ASN1_SEQUENCE: /* * We need to push a child to handle the individual fields. */ state->place = duringSequence; state = sec_asn1d_push_state (state->top, state->theTemplate + 1, state->dest, PR_TRUE); if (state != NULL) { /* * Do the "before" field notification. */ sec_asn1d_notify_before (state->top, state->dest, state->depth); state = sec_asn1d_init_state_based_on_template (state); } break; case SEC_ASN1_SET: /* XXX SET is not really implemented */ /* * XXX A plain SET requires special handling; scanning of a * template to see where a field should go (because by definition, * they are not in any particular order, and you have to look at * each tag to disambiguate what the field is). We may never * implement this because in practice, it seems to be unused. */ PORT_Assert(0); state->top->status = decodeError; break; case SEC_ASN1_NULL: /* * The NULL type, by definition, is "nothing", content length of zero. * An indefinite-length encoding is not alloweed. */ if (state->contents_length || state->indefinite) { state->top->status = decodeError; break; } if (state->dest != NULL) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?