summaryrefslogtreecommitdiff
path: root/security/nss/lib/util/secasn1d.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/util/secasn1d.c')
-rw-r--r--security/nss/lib/util/secasn1d.c69
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);