Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(107)

Side by Side Diff: patches/nss-ber-fixes.patch

Issue 1504923011: Update NSS to 3.21 RTM and NSPR to 4.11 RTM (Closed) Base URL: http://src.chromium.org/svn/trunk/deps/third_party/nss
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 */
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698