| OLD | NEW |
| (Empty) |
| 1 diff --git a/nss/lib/util/secasn1d.c b/nss/lib/util/secasn1d.c | |
| 2 index d404b72..d85597b 100644 | |
| 3 --- a/nss/lib/util/secasn1d.c | |
| 4 +++ b/nss/lib/util/secasn1d.c | |
| 5 @@ -951,6 +951,33 @@ sec_asn1d_parse_more_length (sec_asn1d_state *state, | |
| 6 return count; | |
| 7 } | |
| 8 | |
| 9 +/* | |
| 10 + * Helper function for sec_asn1d_prepare_for_contents. | |
| 11 + * Checks that a value representing a number of bytes consumed can be | |
| 12 + * subtracted from a remaining length. If so, returns PR_TRUE. | |
| 13 + * Otherwise, sets the error SEC_ERROR_BAD_DER, indicates that there was a | |
| 14 + * decoding error in the given SEC_ASN1DecoderContext, and returns PR_FALSE. | |
| 15 + */ | |
| 16 +static PRBool | |
| 17 +sec_asn1d_check_and_subtract_length (unsigned long *remaining, | |
| 18 + unsigned long consumed, | |
| 19 + SEC_ASN1DecoderContext *cx) | |
| 20 +{ | |
| 21 + PORT_Assert(remaining); | |
| 22 + PORT_Assert(cx); | |
| 23 + if (!remaining || !cx) { | |
| 24 + PORT_SetError (SEC_ERROR_INVALID_ARGS); | |
| 25 + cx->status = decodeError; | |
| 26 + return PR_FALSE; | |
| 27 + } | |
| 28 + if (*remaining < consumed) { | |
| 29 + PORT_SetError (SEC_ERROR_BAD_DER); | |
| 30 + cx->status = decodeError; | |
| 31 + return PR_FALSE; | |
| 32 + } | |
| 33 + *remaining -= consumed; | |
| 34 + return PR_TRUE; | |
| 35 +} | |
| 36 | |
| 37 static void | |
| 38 sec_asn1d_prepare_for_contents (sec_asn1d_state *state) | |
| 39 @@ -966,6 +993,63 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state) | |
| 40 } | |
| 41 #endif | |
| 42 | |
| 43 + /** | |
| 44 + * The maximum length for a child element should be constrained to the | |
| 45 + * length remaining in the first definite length element in the ancestor | |
| 46 + * stack. If there is no definite length element in the ancestor stack, | |
| 47 + * there's nothing to constrain the length of the child, so there's no | |
| 48 + * further processing necessary. | |
| 49 + * | |
| 50 + * It's necessary to walk the ancestor stack, because it's possible to have | |
| 51 + * definite length children that are part of an indefinite length element, | |
| 52 + * which is itself part of an indefinite length element, and which is | |
| 53 + * ultimately part of a definite length element. A simple example of this | |
| 54 + * would be the handling of constructed OCTET STRINGs in BER encoding. | |
| 55 + * | |
| 56 + * This algorithm finds the first definite length element in the ancestor | |
| 57 + * stack, if any, and if so, ensures that the length of the child element | |
| 58 + * is consistent with the number of bytes remaining in the constraining | |
| 59 + * ancestor element (that is, after accounting for any other sibling | |
| 60 + * elements that may have been read). | |
| 61 + * | |
| 62 + * It's slightly complicated by the need to account both for integer | |
| 63 + * underflow and overflow, as well as ensure that for indefinite length | |
| 64 + * encodings, there's also enough space for the End-of-Contents (EOC) | |
| 65 + * octets (Tag = 0x00, Length = 0x00, or two bytes). | |
| 66 + */ | |
| 67 + | |
| 68 + /* Determine the maximum length available for this element by finding the | |
| 69 + * first definite length ancestor, if any. */ | |
| 70 + sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state); | |
| 71 + while (parent && parent->indefinite) { | |
| 72 + parent = sec_asn1d_get_enclosing_construct(parent); | |
| 73 + } | |
| 74 + /* If parent is null, state is either the outermost state / at the top of | |
| 75 + * the stack, or the outermost state uses indefinite length encoding. In | |
| 76 + * these cases, there's nothing external to constrain this element, so | |
| 77 + * there's nothing to check. */ | |
| 78 + if (parent) { | |
| 79 + unsigned long remaining = parent->pending; | |
| 80 + parent = state; | |
| 81 + do { | |
| 82 + if (!sec_asn1d_check_and_subtract_length( | |
| 83 + &remaining, parent->consumed, state->top) || | |
| 84 + /* If parent->indefinite is true, parent->contents_length is | |
| 85 + * zero and this is a no-op. */ | |
| 86 + !sec_asn1d_check_and_subtract_length( | |
| 87 + &remaining, parent->contents_length, state->top) || | |
| 88 + /* If parent->indefinite is true, then ensure there is enough | |
| 89 + * space for an EOC tag of 2 bytes. */ | |
| 90 + (parent->indefinite && !sec_asn1d_check_and_subtract_length( | |
| 91 + &remaining, 2, state->top))) { | |
| 92 + /* This element is larger than its enclosing element, which is | |
| 93 + * invalid. */ | |
| 94 + return; | |
| 95 + } | |
| 96 + } while ((parent = sec_asn1d_get_enclosing_construct(parent)) && | |
| 97 + parent->indefinite); | |
| 98 + } | |
| 99 + | |
| 100 /* | |
| 101 * XXX I cannot decide if this allocation should exclude the case | |
| 102 * where state->endofcontents is true -- figure it out! | |
| 103 @@ -1007,21 +1091,6 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state) | |
| 104 */ | |
| 105 state->pending = state->contents_length; | |
| 106 | |
| 107 - /* If this item has definite length encoding, and | |
| 108 - ** is enclosed by a definite length constructed type, | |
| 109 - ** make sure it isn't longer than the remaining space in that | |
| 110 - ** constructed type. | |
| 111 - */ | |
| 112 - if (state->contents_length > 0) { | |
| 113 - sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state); | |
| 114 - if (parent && !parent->indefinite && | |
| 115 - state->consumed + state->contents_length > parent->pending) { | |
| 116 - PORT_SetError (SEC_ERROR_BAD_DER); | |
| 117 - state->top->status = decodeError; | |
| 118 - return; | |
| 119 - } | |
| 120 - } | |
| 121 - | |
| 122 /* | |
| 123 * An EXPLICIT is nothing but an outer header, which we have | |
| 124 * already parsed and accepted. Now we need to do the inner | |
| 125 @@ -1723,7 +1792,102 @@ sec_asn1d_next_substring (sec_asn1d_state *state) | |
| 126 PORT_Assert (state->indefinite); | |
| 127 | |
| 128 item = (SECItem *)(child->dest); | |
| 129 - if (item != NULL && item->data != NULL) { | |
| 130 + | |
| 131 + /** | |
| 132 + * At this point, there's three states at play: | |
| 133 + * child: The element that was just parsed | |
| 134 + * state: The currently processed element | |
| 135 + * 'parent' (aka state->parent): The enclosing construct | |
| 136 + * of state, or NULL if this is the top-most element. | |
| 137 + * | |
| 138 + * This state handles both substrings of a constructed string AND | |
| 139 + * child elements of items whose template type was that of | |
| 140 + * SEC_ASN1_ANY, SEC_ASN1_SAVE, SEC_ASN1_ANY_CONTENTS, SEC_ASN1_SKIP | |
| 141 + * template, as described in sec_asn1d_prepare_for_contents. For | |
| 142 + * brevity, these will be referred to as 'string' and 'any' types. | |
| 143 + * | |
| 144 + * This leads to the following possibilities: | |
| 145 + * 1: This element is an indefinite length string, part of a | |
| 146 + * definite length string. | |
| 147 + * 2: This element is an indefinite length string, part of an | |
| 148 + * indefinite length string. | |
| 149 + * 3: This element is an indefinite length any, part of a | |
| 150 + * definite length any. | |
| 151 + * 4: This element is an indefinite length any, part of an | |
| 152 + * indefinite length any. | |
| 153 + * 5: This element is an indefinite length any and does not | |
| 154 + * meet any of the above criteria. Note that this would include | |
| 155 + * an indefinite length string type matching an indefinite | |
| 156 + * length any template. | |
| 157 + * | |
| 158 + * In Cases #1 and #3, the definite length 'parent' element will | |
| 159 + * have allocated state->dest based on the parent elements definite | |
| 160 + * size. During the processing of 'child', sec_asn1d_parse_leaf will | |
| 161 + * have copied the (string, any) data directly into the offset of | |
| 162 + * dest, as appropriate, so there's no need for this class to still | |
| 163 + * store the child - it's already been processed. | |
| 164 + * | |
| 165 + * In Cases #2 and #4, dest will be set to the parent element's dest, | |
| 166 + * but dest->data will not have been allocated yet, due to the | |
| 167 + * indefinite length encoding. In this situation, it's necessary to | |
| 168 + * hold onto child (and all other children) until the EOC, at which | |
| 169 + * point, it becomes possible to compute 'state's overall length. Once | |
| 170 + * 'state' has a computed length, this can then be fed to 'parent' (via | |
| 171 + * this state), and then 'parent' can similarly compute the length of | |
| 172 + * all of its children up to the EOC, which will ultimately transit to | |
| 173 + * sec_asn1d_concat_substrings, determine the overall size needed, | |
| 174 + * allocate, and copy the contents (of all of parent's children, which | |
| 175 + * would include 'state', just as 'state' will have copied all of its | |
| 176 + * children via sec_asn1d_concat_substrings) | |
| 177 + * | |
| 178 + * The final case, Case #5, will manifest in that item->data and | |
| 179 + * item->len will be NULL/0, respectively, since this element was | |
| 180 + * indefinite-length encoded. In that case, both the tag and length will | |
| 181 + * already exist in state's subitems, via sec_asn1d_record_any_header, | |
| 182 + * and so the contents (aka 'child') should be added to that list of | |
| 183 + * items to concatenate in sec_asn1d_concat_substrings once the EOC | |
| 184 + * is encountered. | |
| 185 + * | |
| 186 + * To distinguish #2/#4 from #1/#3, it's sufficient to walk the ancestor | |
| 187 + * tree. If the current type is a string type, then the enclosing | |
| 188 + * construct will be that same type (#1/#2). If the current type is an | |
| 189 + * any type, then the enclosing construct is either an any type (#3/#4) | |
| 190 + * or some other type (#5). Since this is BER, this nesting relationship | |
| 191 + * between 'state' and 'parent' may go through several levels of | |
| 192 + * constructed encoding, so continue walking the ancestor chain until a | |
| 193 + * clear determination can be made. | |
| 194 + * | |
| 195 + * The variable preallocatedString is used to indicate Case #1/#3, | |
| 196 + * indicating an in-place copy has already occurred, and Cases #2, #4, | |
| 197 + * and #5 all have the same behaviour of adding a new substring. | |
| 198 + */ | |
| 199 + PRBool preallocatedString = PR_FALSE; | |
| 200 + sec_asn1d_state *temp_state = state; | |
| 201 + while (temp_state && item == temp_state->dest && temp_state->indefinite)
{ | |
| 202 + sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(temp_sta
te); | |
| 203 + if (!parent || parent->underlying_kind != temp_state->underlying_kin
d) { | |
| 204 + /* Case #5 - Either this is a top-level construct or it is part | |
| 205 + * of some other element (e.g. a SEQUENCE), in which case, a | |
| 206 + * new item should be allocated. */ | |
| 207 + break; | |
| 208 + } | |
| 209 + if (!parent->indefinite) { | |
| 210 + /* Cases #1 / #3 - A definite length ancestor exists, for which | |
| 211 + * this is a substring that has already copied into dest. */ | |
| 212 + preallocatedString = PR_TRUE; | |
| 213 + break; | |
| 214 + } | |
| 215 + if (!parent->substring) { | |
| 216 + /* Cases #2 / #4 - If the parent is not a substring, but is | |
| 217 + * indefinite, then there's nothing further up that may have | |
| 218 + * preallocated dest, thus child will not have already | |
| 219 + * been copied in place, therefore it's necessary to save child | |
| 220 + * as a subitem. */ | |
| 221 + break; | |
| 222 + } | |
| 223 + temp_state = parent; | |
| 224 + } | |
| 225 + if (item != NULL && item->data != NULL && !preallocatedString) { | |
| 226 /* | |
| 227 * Save the string away for later concatenation. | |
| 228 */ | |
| OLD | NEW |