diff options
Diffstat (limited to 'security/nss/lib/util/secasn1d.c')
-rw-r--r-- | security/nss/lib/util/secasn1d.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/security/nss/lib/util/secasn1d.c b/security/nss/lib/util/secasn1d.c index 890ddddba..a03d2f4ef 100644 --- a/security/nss/lib/util/secasn1d.c +++ b/security/nss/lib/util/secasn1d.c @@ -600,6 +600,32 @@ sec_asn1d_init_state_based_on_template (sec_asn1d_state *state) return state; } +static PRBool +sec_asn1d_parent_is_indefinite(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. 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; +} static unsigned long sec_asn1d_parse_identifier (sec_asn1d_state *state, @@ -628,15 +654,7 @@ sec_asn1d_parse_identifier (sec_asn1d_state *state, */ 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 - ) - ) - ) { + if (byte == 0 && sec_asn1d_parent_is_indefinite(state)) { /* * Our parent has indefinite-length encoding, and the * entire tag found is 0, so it seems that we have hit the @@ -916,10 +934,9 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *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? + * Set state to afterGroup and let that code plant the NULL. */ - state->place = afterEndOfContents; + state->place = afterGroup; } return; } @@ -1918,7 +1935,8 @@ sec_asn1d_concat_group (sec_asn1d_state *state) PORT_Assert (state->place == afterGroup); placep = (const void***)state->dest; - if (state->subitems_head != NULL) { + PORT_Assert(state->subitems_head == NULL || placep != NULL); + if (placep != NULL) { struct subitem *item; const void **group; int count; @@ -1938,7 +1956,6 @@ sec_asn1d_concat_group (sec_asn1d_state *state) return; } - PORT_Assert (placep != NULL); *placep = group; item = state->subitems_head; @@ -1954,8 +1971,6 @@ sec_asn1d_concat_group (sec_asn1d_state *state) * 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; @@ -2187,6 +2202,26 @@ sec_asn1d_during_choice unsigned char child_found_tag_modifiers = 0; unsigned long child_found_tag_number = 0; + state->consumed += child->consumed; + + if (child->endofcontents) { + /* This choice is probably the first item in a GROUP + ** (e.g. SET_OF) that was indefinite-length encoded. + ** We're actually at the end of that GROUP. + ** We should look up the stack to be sure that we find + ** a state with indefinite length encoding before we + ** find a state (like a SEQUENCE) that is definite. + */ + child->place = notInUse; + state->place = afterChoice; + state->endofcontents = PR_TRUE; /* propagate this up */ + if (sec_asn1d_parent_is_indefinite(state)) + return state; + PORT_SetError(SEC_ERROR_BAD_DER); + state->top->status = decodeError; + return NULL; + } + child->theTemplate++; if( 0 == child->theTemplate->kind ) { @@ -2196,8 +2231,6 @@ sec_asn1d_during_choice return (sec_asn1d_state *)NULL; } - state->consumed += child->consumed; - /* cargo'd from next_in_sequence innards */ if( state->pending ) { PORT_Assert(!state->indefinite); |