/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished * Encoding Rules).
*/
/* * Bit strings have their length adjusted -- the first octet of the * contents contains a value between 0 and 7 which says how many bits * at the end of the octets are not actually part of the bit string; * when parsing bit strings we put that value here because we need it * later, for adjustment of the length (when the whole string is done).
*/ unsignedint bit_string_unused_bits;
/* * The following are used for indefinite-length constructed strings.
*/ struct subitem *subitems_head; struct subitem *subitems_tail;
PRPackedBool
allocate, /* when true, need to allocate the destination */
endofcontents, /* this state ended up parsing its parent's end-of-contents octets */ explicit, /* we are handling an explicit header */
indefinite, /* the current item has indefinite-length encoding */
missing, /* an optional field that was not present */
optional, /* the template says this field may be omitted */
substring; /* this is a substring of a constructed string */
/* * An "outsider" will have an opaque pointer to this, created by calling * SEC_ASN1DecoderStart(). It will be passed back in to all subsequent * calls to SEC_ASN1DecoderUpdate(), and when done it is passed to * SEC_ASN1DecoderFinish().
*/ struct sec_DecoderContext_struct {
PLArenaPool *our_pool; /* for our internal allocs */
PLArenaPool *their_pool; /* for destination structure allocs */ #ifdef SEC_ASN1D_FREE_ON_ERROR /* \ * XXX see comment below (by same \ * ifdef) that explains why this \ * does not work (need more smarts \ * in order to free back to mark) \
*/ /* * XXX how to make their_mark work in the case where they do NOT * give us a pool pointer?
*/ void *their_mark; /* free on error */ #endif
/* The maximum size the caller is willing to allow a single element * to be before returning an error. * * In the case of an indefinite length element, this is the sum total * of all child elements. * * In the case of a definite length element, this represents the maximum * size of the top-level element.
*/ unsignedlong max_element_size;
SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */ void *notify_arg; /* argument to notify_proc */
PRBool during_notify; /* true during call to notify_proc */
SEC_ASN1WriteProc filter_proc; /* pass field bytes to this */ void *filter_arg; /* argument to that function */
PRBool filter_only; /* do not allocate/store fields */
};
/* * XXX this is a fairly generic function that may belong elsewhere
*/ staticvoid *
sec_asn1d_alloc(PLArenaPool *poolp, unsignedlong len)
{ void *thing;
if (poolp != NULL) { /* * Allocate from the pool.
*/
thing = PORT_ArenaAlloc(poolp, len);
} else { /* * Allocate generically.
*/
thing = PORT_Alloc(len);
}
return thing;
}
/* * XXX this is a fairly generic function that may belong elsewhere
*/ staticvoid *
sec_asn1d_zalloc(PLArenaPool *poolp, unsignedlong len)
{ void *thing;
/* XXX Check that both of these tests are really needed/appropriate. */ if (state == NULL || state->top->status == decodeError) return state;
encode_kind = state->theTemplate->kind;
if (encode_kind & SEC_ASN1_SAVE) { /* * This is a "magic" field that saves away all bytes, allowing * the immediately following field to still be decoded from this * same spot -- sort of a fork.
*/ /* check that there are no extraneous bits */
PORT_Assert(encode_kind == SEC_ASN1_SAVE); if (state->top->filter_only) { /* * If we are not storing, then we do not do the SAVE field * at all. Just move ahead to the "real" field instead, * doing the appropriate notify calls before and after.
*/
sec_asn1d_notify_after(state->top, state->dest, state->depth); /* * Since we are not storing, allow for our current dest value * to be NULL. (This might not actually occur, but right now I * cannot convince myself one way or the other.) If it is NULL, * assume that our parent dest can help us out.
*/ if (state->dest == NULL)
state->dest = state->parent->dest; else
state->dest = (char *)state->dest - state->theTemplate->offset;
state->theTemplate++; if (state->dest != NULL)
state->dest = (char *)state->dest + state->theTemplate->offset;
sec_asn1d_notify_before(state->top, state->dest, state->depth);
encode_kind = state->theTemplate->kind;
PORT_Assert((encode_kind & SEC_ASN1_SAVE) == 0);
} else {
sec_asn1d_scrub_state(state);
state->place = duringSaveEncoding;
state = sec_asn1d_push_state(state->top, SEC_AnyTemplate,
state->dest, PR_FALSE); if (state != NULL)
state = sec_asn1d_init_state_based_on_template(state); return state;
}
}
if (encode_kind & SEC_ASN1_POINTER) { /* * A POINTER means we need to allocate the destination for * this field. But, since it may also be an optional field, * we defer the allocation until later; we just record that * it needs to be done. * * There are two possible scenarios here -- one is just a * plain POINTER (kind of like INLINE, except with allocation) * and the other is an implicitly-tagged POINTER. We don't * need to do anything special here for the two cases, but * since the template definition can be tricky, we do check * that there are no extraneous bits set in encode_kind. * * XXX The same conditions which assert should set an error.
*/ if (universal) { /* * "universal" means this entry is a standalone POINTER; * there should be no other bits set in encode_kind.
*/
PORT_Assert(encode_kind == SEC_ASN1_POINTER);
} else { /* * If we get here we have an implicitly-tagged field * that needs to be put into a POINTER. The subtemplate * will determine how to decode the field, but encode_kind * describes the (implicit) tag we are looking for. * The non-tag bits of encode_kind will be ignored by * the code below; none of them should be set, however, * except for the POINTER bit itself -- so check that.
*/
PORT_Assert((encode_kind & ~SEC_ASN1_TAG_MASK) == SEC_ASN1_POINTER);
} if (!state->top->filter_only)
child_allocate = PR_TRUE;
dest = NULL;
state->place = afterPointer;
} else {
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;
} elseif (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_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 = (unsignedchar)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;
}
}
static sec_asn1d_state *
sec_asn1d_get_enclosing_construct(sec_asn1d_state *state)
{ for (state = state->parent; state; state = state->parent) {
sec_asn1d_parse_place place = state->place; if (place != afterImplicit &&
place != afterPointer &&
place != afterInline &&
place != afterSaveEncoding &&
place != duringSaveEncoding &&
place != duringChoice) {
/* we've walked up the stack to a state that represents ** the enclosing construct.
*/ break;
}
} return state;
}
static PRBool
sec_asn1d_parent_allows_EOC(sec_asn1d_state *state)
{ /* get state of enclosing construct. */
state = sec_asn1d_get_enclosing_construct(state); if (state) {
sec_asn1d_parse_place place = state->place; /* Is it one of the types that permits an unexpected EOC? */ int eoc_permitted =
(place == duringGroup ||
place == duringConstructedString ||
state->child->optional); return (state->indefinite && eoc_permitted) ? PR_TRUE : PR_FALSE;
} return PR_FALSE;
}
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 && sec_asn1d_parent_allows_EOC(state)) { /* * 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;
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;
}
/* If we're parsing an ANY, SKIP, or SAVE template, and ** the object being saved is definite length encoded and constructed, ** there's no point in decoding that construct's members. ** So, just forget it's constructed and treat it as primitive. ** (SAVE appears as an ANY at this point)
*/ if (!state->indefinite &&
(state->underlying_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP))) {
state->found_tag_modifiers &= ~SEC_ASN1_CONSTRUCTED;
}
return 1;
}
staticunsignedlong
sec_asn1d_parse_more_length(sec_asn1d_state *state, constchar *buf, unsignedlong len)
{ int count;
while (len && state->pending) { if (HIGH_BITS(state->contents_length, 9) != 0) { /* * The given full content length overflows our container; * just give up.
*/
PORT_SetError(SEC_ERROR_BAD_DER);
state->top->status = decodeError; return 0;
}
if (state->pending == 0)
state->place = afterLength;
return count;
}
/* * Helper function for sec_asn1d_prepare_for_contents. * Checks that a value representing a number of bytes consumed can be * subtracted from a remaining length. If so, returns PR_TRUE. * Otherwise, sets the error SEC_ERROR_BAD_DER, indicates that there was a * decoding error in the given SEC_ASN1DecoderContext, and returns PR_FALSE.
*/ static PRBool
sec_asn1d_check_and_subtract_length(unsignedlong *remaining, unsignedlong consumed,
SEC_ASN1DecoderContext *cx)
{
PORT_Assert(remaining);
PORT_Assert(cx); if (!remaining || !cx) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
cx->status = decodeError; return PR_FALSE;
} if (*remaining < consumed) {
PORT_SetError(SEC_ERROR_BAD_DER);
cx->status = decodeError; return PR_FALSE;
}
*remaining -= consumed; return PR_TRUE;
}
/** * The maximum length for a child element should be constrained to the * length remaining in the first definite length element in the ancestor * stack. If there is no definite length element in the ancestor stack, * there's nothing to constrain the length of the child, so there's no * further processing necessary. * * It's necessary to walk the ancestor stack, because it's possible to have * definite length children that are part of an indefinite length element, * which is itself part of an indefinite length element, and which is * ultimately part of a definite length element. A simple example of this * would be the handling of constructed OCTET STRINGs in BER encoding. * * This algorithm finds the first definite length element in the ancestor * stack, if any, and if so, ensures that the length of the child element * is consistent with the number of bytes remaining in the constraining * ancestor element (that is, after accounting for any other sibling * elements that may have been read). * * It's slightly complicated by the need to account both for integer * underflow and overflow, as well as ensure that for indefinite length * encodings, there's also enough space for the End-of-Contents (EOC) * octets (Tag = 0x00, Length = 0x00, or two bytes).
*/
/* Determine the maximum length available for this element by finding the
* first definite length ancestor, if any. */
parent = sec_asn1d_get_enclosing_construct(state); while (parent && parent->indefinite) {
parent = sec_asn1d_get_enclosing_construct(parent);
} /* If parent is null, state is either the outermost state / at the top of * the stack, or the outermost state uses indefinite length encoding. In * these cases, there's nothing external to constrain this element, so
* there's nothing to check. */ if (parent) { unsignedlong remaining = parent->pending;
parent = state; do { if (!sec_asn1d_check_and_subtract_length(
&remaining, parent->consumed, state->top) || /* If parent->indefinite is true, parent->contents_length is
* zero and this is a no-op. */
!sec_asn1d_check_and_subtract_length(
&remaining, parent->contents_length, state->top) || /* If parent->indefinite is true, then ensure there is enough
* space for an EOC tag of 2 bytes. */
(parent->indefinite && !sec_asn1d_check_and_subtract_length(&remaining, 2, state->top))) { /* This element is larger than its enclosing element, which is
* invalid. */ return;
}
} while ((parent = sec_asn1d_get_enclosing_construct(parent)) &&
parent->indefinite);
}
/* * 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) {
(void)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 || state->underlying_kind == (SEC_ASN1_SET_OF | SEC_ASN1_DYNAMIC) || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF | SEC_ASN1_DYNAMIC)); 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);
(void)sec_asn1d_init_state_based_on_template(state);
}
} else { /* * A group of zero; we are done. * Set state to afterGroup and let that code plant the NULL.
*/
state->place = afterGroup;
} 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);
(void)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);
PORT_SetError(SEC_ERROR_BAD_DER); /* XXX */
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) {
PORT_SetError(SEC_ERROR_BAD_DER);
state->top->status = decodeError; break;
} if (state->dest != NULL) {
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) {
PORT_SetError(SEC_ERROR_BAD_DER);
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) {
PORT_SetError(SEC_ERROR_BAD_DER);
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;
} elseif (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); if (!item) {
PORT_SetError(SEC_ERROR_BAD_DER);
state->top->status = decodeError; return;
}
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;
}
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;
} elseif (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;
}
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->max_element_size > 0 &&
state->contents_length > state->top->max_element_size) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
state->top->status = decodeError; return;
}
if (state->top->filter_only) {
item->data = NULL;
} else {
item->data = (unsignedchar *)
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;
}
}
}
staticvoid
sec_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_ArenaZRelease(state->top->our_pool, state->our_mark); if (error && state->top->their_pool == NULL) { /* * XXX We need to free anything allocated. * At this point, we failed in the middle of decoding. But we * can't free the data we previously allocated with PR_Malloc * unless we keep track of every pointer. So instead we have a * memory leak when decoding fails half-way, unless an arena is * used. See bug 95311 .
*/
}
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;
}
/* We have just saved an entire encoded ASN.1 object (type) for a SAVE ** template, and now in the next template, we are going to decode that ** saved data by calling SEC_ASN1DecoderUpdate recursively. ** If that recursive call fails with needBytes, it is a fatal error, ** because the encoded object should have been complete. ** If that recursive call fails with decodeError, it will have already ** cleaned up the state stack, so we must bail out quickly. ** ** These checks of the status returned by the recursive call are now ** done in the caller of this function, immediately after it returns.
*/ staticvoid
sec_asn1d_reuse_encoding(sec_asn1d_state *state)
{
sec_asn1d_state *child; unsignedlong consumed;
SECItem *item; void *dest;
/* * 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; if (state->top->status == needBytes) { return;
}
staticunsignedlong
sec_asn1d_parse_more_bit_string(sec_asn1d_state *state, constchar *buf, unsignedlong len)
{
PORT_Assert(state->place == duringBitString); if (state->pending == 0) { /* An empty bit string with some unused bits is invalid. */ if (state->bit_string_unused_bits) {
PORT_SetError(SEC_ERROR_BAD_DER);
state->top->status = decodeError;
} else { /* An empty bit string with no unused bits is OK. */
state->place = beforeEndOfContents;
} return 0;
}
len = sec_asn1d_parse_leaf(state, buf, len); return len;
}
/* * XXX All callers should be looking at return value to detect * out-of-memory errors (and stop!).
*/ staticstruct subitem *
sec_asn1d_add_to_subitems(sec_asn1d_state *state, constvoid *data, unsignedlong len,
PRBool copy_data)
{ struct subitem *thing;
/* * 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)
*/ staticvoid
sec_asn1d_next_substring(sec_asn1d_state *state)
{
sec_asn1d_state *child;
SECItem *item; unsignedlong child_consumed;
PRBool done;
/** * At this point, there's three states at play: * child: The element that was just parsed * state: The currently processed element * 'parent' (aka state->parent): The enclosing construct * of state, or NULL if this is the top-most element. * * This state handles both substrings of a constructed string AND * child elements of items whose template type was that of * SEC_ASN1_ANY, SEC_ASN1_SAVE, SEC_ASN1_ANY_CONTENTS, SEC_ASN1_SKIP * template, as described in sec_asn1d_prepare_for_contents. For * brevity, these will be referred to as 'string' and 'any' types. * * This leads to the following possibilities: * 1: This element is an indefinite length string, part of a * definite length string. * 2: This element is an indefinite length string, part of an * indefinite length string. * 3: This element is an indefinite length any, part of a * definite length any. * 4: This element is an indefinite length any, part of an * indefinite length any. * 5: This element is an indefinite length any and does not * meet any of the above criteria. Note that this would include * an indefinite length string type matching an indefinite * length any template. * * In Cases #1 and #3, the definite length 'parent' element will * have allocated state->dest based on the parent elements definite * size. During the processing of 'child', sec_asn1d_parse_leaf will * have copied the (string, any) data directly into the offset of * dest, as appropriate, so there's no need for this class to still * store the child - it's already been processed. * * In Cases #2 and #4, dest will be set to the parent element's dest, * but dest->data will not have been allocated yet, due to the * indefinite length encoding. In this situation, it's necessary to * hold onto child (and all other children) until the EOC, at which * point, it becomes possible to compute 'state's overall length. Once * 'state' has a computed length, this can then be fed to 'parent' (via * this state), and then 'parent' can similarly compute the length of * all of its children up to the EOC, which will ultimately transit to * sec_asn1d_concat_substrings, determine the overall size needed, * allocate, and copy the contents (of all of parent's children, which * would include 'state', just as 'state' will have copied all of its * children via sec_asn1d_concat_substrings) * * The final case, Case #5, will manifest in that item->data and * item->len will be NULL/0, respectively, since this element was * indefinite-length encoded. In that case, both the tag and length will * already exist in state's subitems, via sec_asn1d_record_any_header, * and so the contents (aka 'child') should be added to that list of * items to concatenate in sec_asn1d_concat_substrings once the EOC * is encountered. * * To distinguish #2/#4 from #1/#3, it's sufficient to walk the ancestor * tree. If the current type is a string type, then the enclosing * construct will be that same type (#1/#2). If the current type is an * any type, then the enclosing construct is either an any type (#3/#4) * or some other type (#5). Since this is BER, this nesting relationship * between 'state' and 'parent' may go through several levels of * constructed encoding, so continue walking the ancestor chain until a * clear determination can be made. * * The variable preallocatedString is used to indicate Case #1/#3, * indicating an in-place copy has already occurred, and Cases #2, #4, * and #5 all have the same behaviour of adding a new substring.
*/
preallocatedString = PR_FALSE;
temp_state = state; while (temp_state && item == temp_state->dest && temp_state->indefinite) {
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.