/src/nss/lib/util/quickder.c
Line | Count | Source |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | /* |
6 | | Optimized ASN.1 DER decoder |
7 | | */ |
8 | | |
9 | | #include "secerr.h" |
10 | | #include "secasn1.h" /* for SEC_ASN1GetSubtemplate */ |
11 | | #include "secitem.h" |
12 | | |
13 | | /* |
14 | | * simple definite-length ASN.1 decoder |
15 | | */ |
16 | | |
17 | | static unsigned char* |
18 | | definite_length_decoder(const unsigned char* buf, |
19 | | const unsigned int buf_length, |
20 | | unsigned int* out_data_length, |
21 | | PRBool includeTag) |
22 | 55.4M | { |
23 | 55.4M | unsigned char tag; |
24 | 55.4M | unsigned int used_length = 0; |
25 | 55.4M | unsigned int data_length = 0; |
26 | 55.4M | unsigned char length_field_len = 0; |
27 | 55.4M | unsigned char byte; |
28 | 55.4M | unsigned int i; |
29 | | |
30 | 55.4M | if (used_length >= buf_length) { |
31 | | /* Tag field was not found! */ |
32 | 0 | return NULL; |
33 | 0 | } |
34 | 55.4M | tag = buf[used_length++]; |
35 | | |
36 | 55.4M | if (tag == 0) { |
37 | | /* End-of-contents octects should not be present in DER because |
38 | | DER doesn't use the indefinite length form. */ |
39 | 1.65k | return NULL; |
40 | 1.65k | } |
41 | | |
42 | 55.4M | if ((tag & 0x1F) == 0x1F) { |
43 | | /* High tag number (a tag number > 30) is not supported */ |
44 | 1.07k | return NULL; |
45 | 1.07k | } |
46 | | |
47 | 55.4M | if (used_length >= buf_length) { |
48 | | /* Length field was not found! */ |
49 | 3.16k | return NULL; |
50 | 3.16k | } |
51 | 55.4M | byte = buf[used_length++]; |
52 | | |
53 | 55.4M | if (!(byte & 0x80)) { |
54 | | /* Short form: The high bit is not set. */ |
55 | 51.3M | data_length = byte; /* clarity; we're returning a 32-bit int. */ |
56 | 51.3M | } else { |
57 | | /* Long form. Extract the field length */ |
58 | 4.12M | length_field_len = byte & 0x7F; |
59 | 4.12M | if (length_field_len == 0) { |
60 | | /* DER doesn't use the indefinite length form. */ |
61 | 817 | return NULL; |
62 | 817 | } |
63 | | |
64 | 4.12M | if (length_field_len > sizeof(data_length)) { |
65 | | /* We don't support an extended length field longer than |
66 | | 4 bytes (2^32) */ |
67 | 3.77k | return NULL; |
68 | 3.77k | } |
69 | | |
70 | 4.11M | if (length_field_len > (buf_length - used_length)) { |
71 | | /* Extended length field was not found */ |
72 | 671 | return NULL; |
73 | 671 | } |
74 | | |
75 | | /* Iterate across the extended length field */ |
76 | 10.5M | for (i = 0; i < length_field_len; i++) { |
77 | 6.47M | byte = buf[used_length++]; |
78 | 6.47M | data_length = (data_length << 8) | byte; |
79 | | |
80 | 6.47M | if (i == 0) { |
81 | 4.11M | PRBool too_long = PR_FALSE; |
82 | 4.11M | if (length_field_len == 1) { |
83 | 1.77M | too_long = ((byte & 0x80) == 0); /* Short form suffices */ |
84 | 2.34M | } else { |
85 | 2.34M | too_long = (byte == 0); /* This zero byte can be omitted */ |
86 | 2.34M | } |
87 | 4.11M | if (too_long) { |
88 | | /* The length is longer than needed. */ |
89 | 1.21k | return NULL; |
90 | 1.21k | } |
91 | 4.11M | } |
92 | 6.47M | } |
93 | 4.11M | } |
94 | | |
95 | 55.4M | if ((tag & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_NULL && data_length != 0) { |
96 | | /* The DER encoding of NULL has no contents octets */ |
97 | 4.41k | return NULL; |
98 | 4.41k | } |
99 | | |
100 | 55.4M | if (data_length > (buf_length - used_length)) { |
101 | | /* The decoded length exceeds the available buffer */ |
102 | 21.0k | return NULL; |
103 | 21.0k | } |
104 | | |
105 | 55.4M | if (includeTag) { |
106 | 48.3M | data_length += used_length; |
107 | 48.3M | } |
108 | | |
109 | 55.4M | *out_data_length = data_length; |
110 | 55.4M | return ((unsigned char*)buf + (includeTag ? 0 : used_length)); |
111 | 55.4M | } |
112 | | |
113 | | static SECStatus |
114 | | GetItem(SECItem* src, SECItem* dest, PRBool includeTag) |
115 | 56.0M | { |
116 | 56.0M | if ((!src) || (!dest) || (!src->data && src->len)) { |
117 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
118 | 0 | return SECFailure; |
119 | 0 | } |
120 | | |
121 | 56.0M | if (!src->len) { |
122 | | /* reaching the end of the buffer is not an error */ |
123 | 578k | dest->data = NULL; |
124 | 578k | dest->len = 0; |
125 | 578k | return SECSuccess; |
126 | 578k | } |
127 | | |
128 | 55.4M | dest->data = definite_length_decoder(src->data, src->len, &dest->len, |
129 | 55.4M | includeTag); |
130 | 55.4M | if (dest->data == NULL) { |
131 | 37.8k | PORT_SetError(SEC_ERROR_BAD_DER); |
132 | 37.8k | return SECFailure; |
133 | 37.8k | } |
134 | 55.4M | src->len -= (int)(dest->data - src->data) + dest->len; |
135 | 55.4M | src->data = dest->data + dest->len; |
136 | 55.4M | return SECSuccess; |
137 | 55.4M | } |
138 | | |
139 | | /* check if the actual component's type matches the type in the template */ |
140 | | |
141 | | static SECStatus |
142 | | MatchComponentType(const SEC_ASN1Template* templateEntry, |
143 | | SECItem* item, PRBool* match, void* dest) |
144 | 19.1M | { |
145 | 19.1M | unsigned long kind = 0; |
146 | 19.1M | unsigned char tag = 0; |
147 | | |
148 | 19.1M | if ((!item) || (!item->data && item->len) || (!templateEntry) || (!match)) { |
149 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
150 | 0 | return SECFailure; |
151 | 0 | } |
152 | | |
153 | 19.1M | if (!item->len) { |
154 | 520k | *match = PR_FALSE; |
155 | 520k | return SECSuccess; |
156 | 520k | } |
157 | | |
158 | 18.5M | kind = templateEntry->kind; |
159 | 18.5M | tag = *(unsigned char*)item->data; |
160 | | |
161 | 18.5M | if (((kind & SEC_ASN1_INLINE) || |
162 | 17.1M | (kind & SEC_ASN1_POINTER)) && |
163 | 1.42M | (0 == (kind & SEC_ASN1_TAG_MASK))) { |
164 | | /* These cases are special because the template's "kind" does not |
165 | | give us the information for the ASN.1 tag of the next item. It can |
166 | | only be figured out from the subtemplate. */ |
167 | 1.42M | if (!(kind & SEC_ASN1_OPTIONAL)) { |
168 | | /* This is a required component. If there is a type mismatch, |
169 | | the decoding of the subtemplate will fail, so assume this |
170 | | is a match at the parent level and let it fail later. This |
171 | | avoids a redundant check in matching cases */ |
172 | 1.42M | *match = PR_TRUE; |
173 | 1.42M | return SECSuccess; |
174 | 1.42M | } else { |
175 | | /* optional component. This is the hard case. Now we need to |
176 | | look at the subtemplate to get the expected kind */ |
177 | 5.03k | const SEC_ASN1Template* subTemplate = |
178 | 5.03k | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
179 | 5.03k | if (!subTemplate) { |
180 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
181 | 0 | return SECFailure; |
182 | 0 | } |
183 | 5.03k | if ((subTemplate->kind & SEC_ASN1_INLINE) || |
184 | 5.03k | (subTemplate->kind & SEC_ASN1_POINTER)) { |
185 | | /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE, |
186 | | otherwise you may get a false positive due to the recursion |
187 | | optimization above that always matches the type if the |
188 | | component is required . Nesting these should never be |
189 | | required, so that no one should miss this ability */ |
190 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
191 | 0 | return SECFailure; |
192 | 0 | } |
193 | 5.03k | return MatchComponentType(subTemplate, item, match, |
194 | 5.03k | (void*)((char*)dest + templateEntry->offset)); |
195 | 5.03k | } |
196 | 1.42M | } |
197 | | |
198 | 17.1M | if (kind & SEC_ASN1_CHOICE) { |
199 | | /* we need to check the component's tag against each choice's tag */ |
200 | | /* XXX it would be nice to save the index of the choice here so that |
201 | | DecodeChoice wouldn't have to do this again. However, due to the |
202 | | recursivity of MatchComponentType, we don't know if we are in a |
203 | | required or optional component, so we can't write anywhere in |
204 | | the destination within this function */ |
205 | 196k | unsigned choiceIndex = 1; |
206 | 196k | const SEC_ASN1Template* choiceEntry; |
207 | 217k | while ((choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind)) { |
208 | 211k | if ((SECSuccess == MatchComponentType(choiceEntry, item, match, |
209 | 211k | (void*)((char*)dest + choiceEntry->offset))) && |
210 | 211k | (PR_TRUE == *match)) { |
211 | 190k | return SECSuccess; |
212 | 190k | } |
213 | 211k | } |
214 | | /* no match, caller must decide if this is BAD DER, or not. */ |
215 | 6.28k | *match = PR_FALSE; |
216 | 6.28k | return SECSuccess; |
217 | 196k | } |
218 | | |
219 | 16.9M | if (kind & SEC_ASN1_ANY) { |
220 | | /* SEC_ASN1_ANY always matches */ |
221 | 7.97M | *match = PR_TRUE; |
222 | 7.97M | return SECSuccess; |
223 | 7.97M | } |
224 | | |
225 | 8.99M | if ((0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) && |
226 | 1.76M | (!(kind & SEC_ASN1_EXPLICIT)) && |
227 | 1.21M | (((kind & SEC_ASN1_SAVE) || |
228 | 830k | (kind & SEC_ASN1_SKIP)) && |
229 | 1.20M | (!(kind & SEC_ASN1_OPTIONAL)))) { |
230 | | /* when saving or skipping a required component, a type is not |
231 | | required in the template. This is for legacy support of |
232 | | SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to |
233 | | deprecate these usages and always require a type, as this |
234 | | disables type checking, and effectively forbids us from |
235 | | transparently ignoring optional components we aren't aware of */ |
236 | 1.20M | *match = PR_TRUE; |
237 | 1.20M | return SECSuccess; |
238 | 1.20M | } |
239 | | |
240 | | /* first, do a class check */ |
241 | 7.78M | if ((tag & SEC_ASN1_CLASS_MASK) != |
242 | 7.78M | (((unsigned char)kind) & SEC_ASN1_CLASS_MASK)) { |
243 | | /* this is only to help debugging of the decoder in case of problems */ |
244 | | /* unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK; */ |
245 | | /* unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK; */ |
246 | 9.66k | *match = PR_FALSE; |
247 | 9.66k | return SECSuccess; |
248 | 9.66k | } |
249 | | |
250 | | /* now do a tag check */ |
251 | 7.77M | if (((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) != |
252 | 7.77M | (tag & SEC_ASN1_TAGNUM_MASK)) { |
253 | 504k | *match = PR_FALSE; |
254 | 504k | return SECSuccess; |
255 | 504k | } |
256 | | |
257 | | /* now, do a method check. This depends on the class */ |
258 | 7.27M | switch (tag & SEC_ASN1_CLASS_MASK) { |
259 | 6.58M | case SEC_ASN1_UNIVERSAL: |
260 | | /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be |
261 | | primitive or constructed based on the tag */ |
262 | 6.58M | switch (tag & SEC_ASN1_TAGNUM_MASK) { |
263 | 2.93M | case SEC_ASN1_SEQUENCE: |
264 | 3.20M | case SEC_ASN1_SET: |
265 | 3.20M | case SEC_ASN1_EMBEDDED_PDV: |
266 | | /* this component must be a constructed type */ |
267 | | /* XXX add any new universal constructed type here */ |
268 | 3.20M | if (tag & SEC_ASN1_CONSTRUCTED) { |
269 | 3.20M | *match = PR_TRUE; |
270 | 3.20M | return SECSuccess; |
271 | 3.20M | } |
272 | 609 | break; |
273 | | |
274 | 3.38M | default: |
275 | | /* this component must be a primitive type */ |
276 | 3.38M | if (!(tag & SEC_ASN1_CONSTRUCTED)) { |
277 | 3.38M | *match = PR_TRUE; |
278 | 3.38M | return SECSuccess; |
279 | 3.38M | } |
280 | 346 | break; |
281 | 6.58M | } |
282 | 955 | break; |
283 | | |
284 | 685k | default: |
285 | | /* for all other classes, we check the method based on the template */ |
286 | 685k | if ((unsigned char)(kind & SEC_ASN1_METHOD_MASK) == |
287 | 685k | (tag & SEC_ASN1_METHOD_MASK)) { |
288 | 685k | *match = PR_TRUE; |
289 | 685k | return SECSuccess; |
290 | 685k | } |
291 | | /* method does not match between template and component */ |
292 | 215 | break; |
293 | 7.27M | } |
294 | | |
295 | 1.17k | *match = PR_FALSE; |
296 | 1.17k | return SECSuccess; |
297 | 7.27M | } |
298 | | |
299 | | #ifdef DEBUG |
300 | | |
301 | | static SECStatus |
302 | | CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate) |
303 | 2.64M | { |
304 | 2.64M | SECStatus rv = SECSuccess; |
305 | 2.64M | const SEC_ASN1Template* sequenceEntry = NULL; |
306 | 2.64M | unsigned long seqIndex = 0; |
307 | 2.64M | unsigned long lastEntryIndex = 0; |
308 | 2.64M | unsigned long ambiguityIndex = 0; |
309 | 2.64M | PRBool foundAmbiguity = PR_FALSE; |
310 | | |
311 | 10.6M | do { |
312 | 10.6M | sequenceEntry = &sequenceTemplate[seqIndex++]; |
313 | 10.6M | if (sequenceEntry->kind) { |
314 | | /* ensure that we don't have an optional component of SEC_ASN1_ANY |
315 | | in the middle of the sequence, since we could not handle it */ |
316 | | /* XXX this function needs to dig into the subtemplates to find |
317 | | the next tag */ |
318 | 8.04M | if ((PR_FALSE == foundAmbiguity) && |
319 | 8.04M | (sequenceEntry->kind & SEC_ASN1_OPTIONAL) && |
320 | 1.98M | (sequenceEntry->kind & SEC_ASN1_ANY)) { |
321 | 754k | foundAmbiguity = PR_TRUE; |
322 | 754k | ambiguityIndex = seqIndex - 1; |
323 | 754k | } |
324 | 8.04M | } |
325 | 10.6M | } while (sequenceEntry->kind); |
326 | | |
327 | 2.64M | lastEntryIndex = seqIndex - 2; |
328 | | |
329 | 2.64M | if (PR_FALSE != foundAmbiguity) { |
330 | 754k | if (ambiguityIndex < lastEntryIndex) { |
331 | | /* ambiguity can only be tolerated on the last entry */ |
332 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
333 | 0 | rv = SECFailure; |
334 | 0 | } |
335 | 754k | } |
336 | | |
337 | | /* XXX also enforce ASN.1 requirement that tags be |
338 | | distinct for consecutive optional components */ |
339 | | |
340 | 2.64M | return rv; |
341 | 2.64M | } |
342 | | |
343 | | #endif |
344 | | |
345 | | static SECStatus DecodeItem(void* dest, |
346 | | const SEC_ASN1Template* templateEntry, |
347 | | SECItem* src, PLArenaPool* arena, PRBool checkTag); |
348 | | |
349 | | static SECStatus |
350 | | DecodeSequence(void* dest, |
351 | | const SEC_ASN1Template* templateEntry, |
352 | | SECItem* src, PLArenaPool* arena) |
353 | 2.64M | { |
354 | 2.64M | SECStatus rv = SECSuccess; |
355 | 2.64M | SECItem source; |
356 | 2.64M | SECItem sequence; |
357 | 2.64M | const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]); |
358 | 2.64M | const SEC_ASN1Template* sequenceEntry = NULL; |
359 | 2.64M | unsigned long seqindex = 0; |
360 | | |
361 | 2.64M | #ifdef DEBUG |
362 | | /* for a sequence, we need to validate the template. */ |
363 | 2.64M | rv = CheckSequenceTemplate(sequenceTemplate); |
364 | 2.64M | #endif |
365 | | |
366 | 2.64M | source = *src; |
367 | | |
368 | | /* get the sequence */ |
369 | 2.64M | if (SECSuccess == rv) { |
370 | 2.64M | rv = GetItem(&source, &sequence, PR_FALSE); |
371 | 2.64M | } |
372 | | |
373 | | /* process it */ |
374 | 2.64M | if (SECSuccess == rv) |
375 | 10.1M | do { |
376 | 10.1M | sequenceEntry = &sequenceTemplate[seqindex++]; |
377 | 10.1M | if ((sequenceEntry && sequenceEntry->kind) && |
378 | 8.01M | (sequenceEntry->kind != SEC_ASN1_SKIP_REST)) { |
379 | 7.55M | rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE); |
380 | 7.55M | } |
381 | 10.1M | } while ((SECSuccess == rv) && |
382 | 10.1M | (sequenceEntry->kind && |
383 | 7.99M | sequenceEntry->kind != SEC_ASN1_SKIP_REST)); |
384 | | /* we should have consumed all the bytes in the sequence by now |
385 | | unless the caller doesn't care about the rest of the sequence */ |
386 | 2.64M | if (SECSuccess == rv && sequence.len && |
387 | 461k | sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST) { |
388 | | /* it isn't 100% clear whether this is a bad DER or a bad template. |
389 | | The problem is that logically, they don't match - there is extra |
390 | | data in the DER that the template doesn't know about */ |
391 | 1.08k | PORT_SetError(SEC_ERROR_BAD_DER); |
392 | 1.08k | rv = SECFailure; |
393 | 1.08k | } |
394 | | |
395 | 2.64M | return rv; |
396 | 2.64M | } |
397 | | |
398 | | static SECStatus |
399 | | DecodeInline(void* dest, |
400 | | const SEC_ASN1Template* templateEntry, |
401 | | SECItem* src, PLArenaPool* arena, PRBool checkTag) |
402 | 2.09M | { |
403 | 2.09M | const SEC_ASN1Template* inlineTemplate = |
404 | 2.09M | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
405 | 2.09M | return DecodeItem((void*)((char*)dest + templateEntry->offset), |
406 | 2.09M | inlineTemplate, src, arena, checkTag); |
407 | 2.09M | } |
408 | | |
409 | | static SECStatus |
410 | | DecodePointer(void* dest, |
411 | | const SEC_ASN1Template* templateEntry, |
412 | | SECItem* src, PLArenaPool* arena, PRBool checkTag) |
413 | 7.48k | { |
414 | 7.48k | const SEC_ASN1Template* ptrTemplate = |
415 | 7.48k | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
416 | 7.48k | if (!ptrTemplate) { |
417 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
418 | 0 | return SECFailure; |
419 | 0 | } |
420 | 7.48k | void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size); |
421 | 7.48k | *(void**)((char*)dest + templateEntry->offset) = subdata; |
422 | 7.48k | if (subdata) { |
423 | 7.48k | return DecodeItem(subdata, ptrTemplate, src, arena, checkTag); |
424 | 7.48k | } else { |
425 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
426 | 0 | return SECFailure; |
427 | 0 | } |
428 | 7.48k | } |
429 | | |
430 | | static SECStatus |
431 | | DecodeImplicit(void* dest, |
432 | | const SEC_ASN1Template* templateEntry, |
433 | | SECItem* src, PLArenaPool* arena) |
434 | 37.6k | { |
435 | 37.6k | if (templateEntry->kind & SEC_ASN1_POINTER) { |
436 | 0 | return DecodePointer((void*)((char*)dest), |
437 | 0 | templateEntry, src, arena, PR_FALSE); |
438 | 37.6k | } else { |
439 | 37.6k | return DecodeInline((void*)((char*)dest), |
440 | 37.6k | templateEntry, src, arena, PR_FALSE); |
441 | 37.6k | } |
442 | 37.6k | } |
443 | | |
444 | | static SECStatus |
445 | | DecodeChoice(void* dest, |
446 | | const SEC_ASN1Template* templateEntry, |
447 | | SECItem* src, PLArenaPool* arena) |
448 | 190k | { |
449 | 190k | SECStatus rv = SECSuccess; |
450 | 190k | SECItem choice; |
451 | 190k | const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]); |
452 | 190k | const SEC_ASN1Template* choiceEntry = NULL; |
453 | 190k | unsigned long choiceindex = 0; |
454 | | |
455 | | /* XXX for a choice component, we should validate the template to make |
456 | | sure the tags are distinct, in debug builds. This hasn't been |
457 | | implemented yet */ |
458 | | /* rv = CheckChoiceTemplate(sequenceTemplate); */ |
459 | | |
460 | | /* process it */ |
461 | 198k | do { |
462 | 198k | choice = *src; |
463 | 198k | choiceEntry = &choiceTemplate[choiceindex++]; |
464 | 198k | if (choiceEntry->kind) { |
465 | 198k | rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE); |
466 | 198k | } |
467 | 198k | } while ((SECFailure == rv) && (choiceEntry->kind)); |
468 | | |
469 | 190k | if (SECFailure == rv) { |
470 | | /* the component didn't match any of the choices */ |
471 | 63 | PORT_SetError(SEC_ERROR_BAD_DER); |
472 | 190k | } else { |
473 | | /* set the type in the union here */ |
474 | 190k | int* which = (int*)((char*)dest + templateEntry->offset); |
475 | 190k | *which = (int)choiceEntry->size; |
476 | 190k | } |
477 | | |
478 | | /* we should have consumed all the bytes by now */ |
479 | | /* fail if we have not */ |
480 | 190k | if (SECSuccess == rv && choice.len) { |
481 | | /* there is extra data that isn't listed in the template */ |
482 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
483 | 0 | rv = SECFailure; |
484 | 0 | } |
485 | 190k | return rv; |
486 | 190k | } |
487 | | |
488 | | static SECStatus |
489 | | DecodeGroup(void* dest, |
490 | | const SEC_ASN1Template* templateEntry, |
491 | | SECItem* src, PLArenaPool* arena) |
492 | 560k | { |
493 | 560k | SECStatus rv = SECSuccess; |
494 | 560k | SECItem source; |
495 | 560k | SECItem group; |
496 | 560k | PRUint32 totalEntries = 0; |
497 | 560k | PRUint32 entryIndex = 0; |
498 | 560k | void** entries = NULL; |
499 | | |
500 | 560k | const SEC_ASN1Template* subTemplate = |
501 | 560k | SEC_ASN1GetSubtemplate(templateEntry, dest, PR_FALSE); |
502 | | |
503 | 560k | source = *src; |
504 | | |
505 | | /* get the group */ |
506 | 560k | if (SECSuccess == rv) { |
507 | 560k | rv = GetItem(&source, &group, PR_FALSE); |
508 | 560k | } |
509 | | |
510 | | /* XXX we should check the subtemplate in debug builds */ |
511 | 560k | if (SECSuccess == rv) { |
512 | | /* first, count the number of entries. Benchmarking showed that this |
513 | | counting pass is more efficient than trying to allocate entries as |
514 | | we read the DER, even if allocating many entries at a time |
515 | | */ |
516 | 560k | SECItem counter = group; |
517 | 29.9M | do { |
518 | 29.9M | SECItem anitem; |
519 | 29.9M | rv = GetItem(&counter, &anitem, PR_TRUE); |
520 | 29.9M | if (SECSuccess == rv && (anitem.len)) { |
521 | 29.9M | totalEntries++; |
522 | 29.9M | } |
523 | 29.9M | } while ((SECSuccess == rv) && (counter.len)); |
524 | | |
525 | | /* Limit entry data to 1 GiB. */ |
526 | 560k | if (SECSuccess == rv && subTemplate->size && |
527 | 558k | totalEntries > ((size_t)1 << 30) / subTemplate->size) { |
528 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
529 | 0 | rv = SECFailure; |
530 | 0 | } |
531 | | |
532 | 560k | if (SECSuccess == rv) { |
533 | | /* allocate room for pointer array and entries */ |
534 | | /* we want to allocate the array even if there is 0 entry */ |
535 | 558k | entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*) * (totalEntries + 1) + /* the extra one is for NULL termination */ |
536 | 558k | (size_t)subTemplate->size * totalEntries); |
537 | | |
538 | 558k | if (entries) { |
539 | 558k | entries[totalEntries] = NULL; /* terminate the array */ |
540 | 558k | } else { |
541 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
542 | 0 | rv = SECFailure; |
543 | 0 | } |
544 | 558k | if (SECSuccess == rv) { |
545 | 558k | void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*) * (totalEntries + 1)); |
546 | | /* and fix the pointers in the array */ |
547 | 558k | PRUint32 entriesIndex = 0; |
548 | 30.3M | for (entriesIndex = 0; entriesIndex < totalEntries; entriesIndex++) { |
549 | 29.8M | entries[entriesIndex] = |
550 | 29.8M | (char*)entriesData + ((size_t)subTemplate->size * entriesIndex); |
551 | 29.8M | } |
552 | 558k | } |
553 | 558k | } |
554 | 560k | } |
555 | | |
556 | 560k | if (SECSuccess == rv && totalEntries) |
557 | 7.10M | do { |
558 | 7.10M | if (!(entryIndex < totalEntries)) { |
559 | 0 | rv = SECFailure; |
560 | 0 | break; |
561 | 0 | } |
562 | 7.10M | rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE); |
563 | 7.10M | } while ((SECSuccess == rv) && (group.len)); |
564 | | /* we should be at the end of the set by now */ |
565 | | /* save the entries where requested */ |
566 | 560k | memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**)); |
567 | | |
568 | 560k | return rv; |
569 | 560k | } |
570 | | |
571 | | static SECStatus |
572 | | DecodeExplicit(void* dest, |
573 | | const SEC_ASN1Template* templateEntry, |
574 | | SECItem* src, PLArenaPool* arena) |
575 | 647k | { |
576 | 647k | SECStatus rv = SECSuccess; |
577 | 647k | SECItem subItem; |
578 | 647k | SECItem constructed = *src; |
579 | | |
580 | 647k | rv = GetItem(&constructed, &subItem, PR_FALSE); |
581 | | |
582 | 647k | if (SECSuccess == rv) { |
583 | 647k | if (templateEntry->kind & SEC_ASN1_POINTER) { |
584 | 0 | rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE); |
585 | 647k | } else { |
586 | 647k | rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE); |
587 | 647k | } |
588 | 647k | } |
589 | | |
590 | 647k | return rv; |
591 | 647k | } |
592 | | |
593 | | /* new decoder implementation. This is a recursive function */ |
594 | | |
595 | | static SECStatus |
596 | | DecodeItem(void* dest, |
597 | | const SEC_ASN1Template* templateEntry, |
598 | | SECItem* src, PLArenaPool* arena, PRBool checkTag) |
599 | 18.9M | { |
600 | 18.9M | SECStatus rv = SECSuccess; |
601 | 18.9M | SECItem temp; |
602 | 18.9M | SECItem mark = { siBuffer, NULL, 0 }; |
603 | 18.9M | PRBool pop = PR_FALSE; |
604 | 18.9M | PRBool decode = PR_TRUE; |
605 | 18.9M | PRBool save = PR_FALSE; |
606 | 18.9M | unsigned long kind; |
607 | 18.9M | PRBool match = PR_TRUE; |
608 | | |
609 | 18.9M | PR_ASSERT(src && dest && templateEntry && arena); |
610 | | #if 0 |
611 | | if (!src || !dest || !templateEntry || !arena) |
612 | | { |
613 | | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
614 | | rv = SECFailure; |
615 | | } |
616 | | #endif |
617 | | |
618 | 18.9M | if (SECSuccess == rv) { |
619 | | /* do the template validation */ |
620 | 18.9M | kind = templateEntry->kind; |
621 | 18.9M | if (!kind) { |
622 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
623 | 0 | rv = SECFailure; |
624 | 0 | } |
625 | 18.9M | } |
626 | | |
627 | 18.9M | if (SECSuccess == rv) { |
628 | 18.9M | #ifdef DEBUG |
629 | 18.9M | if (kind & SEC_ASN1_DEBUG_BREAK) { |
630 | | /* when debugging the decoder or a template that fails to |
631 | | decode, put SEC_ASN1_DEBUG in the component that gives you |
632 | | trouble. The decoder will then get to this block and assert. |
633 | | If you want to debug the rest of the code, you can set a |
634 | | breakpoint and set dontassert to PR_TRUE, which will let |
635 | | you skip over the assert and continue the debugging session |
636 | | past it. */ |
637 | 0 | PRBool dontassert = PR_FALSE; |
638 | 0 | PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/ |
639 | 0 | } |
640 | 18.9M | #endif |
641 | | |
642 | 18.9M | if ((kind & SEC_ASN1_SKIP) || |
643 | 18.1M | (kind & SEC_ASN1_SAVE)) { |
644 | | /* if skipping or saving this component, don't decode it */ |
645 | 1.20M | decode = PR_FALSE; |
646 | 1.20M | } |
647 | | |
648 | 18.9M | if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL)) { |
649 | | /* if saving this component, or if it is optional, we may not want to |
650 | | move past it, so save the position in case we have to rewind */ |
651 | 2.35M | mark = *src; |
652 | 2.35M | if (kind & SEC_ASN1_SAVE) { |
653 | 382k | save = PR_TRUE; |
654 | 382k | if (0 == (kind & SEC_ASN1_SKIP)) { |
655 | | /* we will for sure have to rewind when saving this |
656 | | component and not skipping it. This is true for all |
657 | | legacy uses of SEC_ASN1_SAVE where the following entry |
658 | | in the template would causes the same component to be |
659 | | processed again */ |
660 | 382k | pop = PR_TRUE; |
661 | 382k | } |
662 | 382k | } |
663 | 2.35M | } |
664 | | |
665 | 18.9M | rv = GetItem(src, &temp, PR_TRUE); |
666 | 18.9M | } |
667 | | |
668 | 18.9M | if (SECSuccess == rv) { |
669 | | /* now check if the component matches what we expect in the template */ |
670 | | |
671 | 18.9M | if (PR_TRUE == checkTag) |
672 | | |
673 | 18.8M | { |
674 | 18.8M | rv = MatchComponentType(templateEntry, &temp, &match, dest); |
675 | 18.8M | } |
676 | | |
677 | 18.9M | if ((SECSuccess == rv) && (PR_TRUE != match)) { |
678 | 1.02M | if (kind & SEC_ASN1_OPTIONAL) { |
679 | | |
680 | | /* the optional component is missing. This is not fatal. */ |
681 | | /* Rewind, don't decode, and don't save */ |
682 | 900k | pop = PR_TRUE; |
683 | 900k | decode = PR_FALSE; |
684 | 900k | save = PR_FALSE; |
685 | 900k | } else { |
686 | | /* a required component is missing. abort */ |
687 | 120k | PORT_SetError(SEC_ERROR_BAD_DER); |
688 | 120k | rv = SECFailure; |
689 | 120k | } |
690 | 1.02M | } |
691 | 18.9M | } |
692 | | |
693 | 18.9M | if ((SECSuccess == rv) && (PR_TRUE == decode)) { |
694 | | /* the order of processing here is is the tricky part */ |
695 | | /* we start with our special cases */ |
696 | | /* first, check the component class */ |
697 | 16.7M | if (kind & SEC_ASN1_INLINE) { |
698 | | /* decode inline template */ |
699 | 1.41M | rv = DecodeInline(dest, templateEntry, &temp, arena, PR_TRUE); |
700 | 1.41M | } |
701 | | |
702 | 15.2M | else if (kind & SEC_ASN1_EXPLICIT) { |
703 | 647k | rv = DecodeExplicit(dest, templateEntry, &temp, arena); |
704 | 14.6M | } else if ((SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) && |
705 | | |
706 | 37.6k | (!(kind & SEC_ASN1_EXPLICIT))) { |
707 | | |
708 | | /* decode implicitly tagged components */ |
709 | 37.6k | rv = DecodeImplicit(dest, templateEntry, &temp, arena); |
710 | 14.6M | } else if (kind & SEC_ASN1_POINTER) { |
711 | 7.48k | rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE); |
712 | 14.5M | } else if (kind & SEC_ASN1_CHOICE) { |
713 | 190k | rv = DecodeChoice(dest, templateEntry, &temp, arena); |
714 | 14.4M | } else if (kind & SEC_ASN1_ANY) { |
715 | | /* catch-all ANY type, don't decode */ |
716 | 7.97M | save = PR_TRUE; |
717 | 7.97M | if (kind & SEC_ASN1_INNER) { |
718 | | /* skip the tag and length */ |
719 | 0 | SECItem newtemp = temp; |
720 | 0 | rv = GetItem(&newtemp, &temp, PR_FALSE); |
721 | 0 | } |
722 | 7.97M | } else if (kind & SEC_ASN1_GROUP) { |
723 | 560k | if ((SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) || |
724 | 560k | (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK))) { |
725 | 560k | rv = DecodeGroup(dest, templateEntry, &temp, arena); |
726 | 560k | } else { |
727 | | /* a group can only be a SET OF or SEQUENCE OF */ |
728 | 0 | PORT_SetError(SEC_ERROR_BAD_TEMPLATE); |
729 | 0 | rv = SECFailure; |
730 | 0 | } |
731 | 5.87M | } else if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) { |
732 | | /* plain SEQUENCE */ |
733 | 2.64M | rv = DecodeSequence(dest, templateEntry, &temp, arena); |
734 | 3.23M | } else { |
735 | | /* handle all other types as "save" */ |
736 | | /* we should only get here for primitive universal types */ |
737 | 3.23M | SECItem newtemp = temp; |
738 | 3.23M | rv = GetItem(&newtemp, &temp, PR_FALSE); |
739 | 3.23M | save = PR_TRUE; |
740 | 3.23M | if ((SECSuccess == rv) && |
741 | 3.23M | SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK)) { |
742 | 3.23M | unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK; |
743 | 3.23M | if (temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN || |
744 | 8.39k | tagnum == SEC_ASN1_INTEGER || |
745 | 8.19k | tagnum == SEC_ASN1_BIT_STRING || |
746 | 7.76k | tagnum == SEC_ASN1_OBJECT_ID || |
747 | 7.48k | tagnum == SEC_ASN1_ENUMERATED || |
748 | 7.46k | tagnum == SEC_ASN1_UTC_TIME || |
749 | 7.43k | tagnum == SEC_ASN1_GENERALIZED_TIME)) { |
750 | | /* these types MUST have at least one content octet */ |
751 | 1.16k | PORT_SetError(SEC_ERROR_BAD_DER); |
752 | 1.16k | rv = SECFailure; |
753 | 1.16k | } else |
754 | 3.22M | switch (tagnum) { |
755 | | /* special cases of primitive types */ |
756 | 356k | case SEC_ASN1_INTEGER: { |
757 | 356k | SECItem* destItem = (SECItem*)((char*)dest + |
758 | 356k | templateEntry->offset); |
759 | 356k | if (destItem && (siUnsignedInteger == destItem->type)) { |
760 | | /* A leading 0 is only allowed when a value |
761 | | * would otherwise be interpreted as negative. */ |
762 | 166k | if (temp.len > 1 && temp.data[0] == 0) { |
763 | 45.6k | temp.data++; |
764 | 45.6k | temp.len--; |
765 | 45.6k | if (!(temp.data[0] & 0x80)) { |
766 | 47 | PORT_SetError(SEC_ERROR_BAD_DER); |
767 | 47 | rv = SECFailure; |
768 | 47 | } |
769 | 45.6k | } |
770 | 166k | } |
771 | 356k | break; |
772 | 0 | } |
773 | | |
774 | 670k | case SEC_ASN1_BIT_STRING: { |
775 | | /* Can't be 8 or more spare bits, or any spare bits |
776 | | * if there are no octets. */ |
777 | 670k | if (temp.data[0] >= 8 || (temp.data[0] > 0 && temp.len == 1)) { |
778 | 1.04k | PORT_SetError(SEC_ERROR_BAD_DER); |
779 | 1.04k | rv = SECFailure; |
780 | 1.04k | break; |
781 | 1.04k | } |
782 | | /* change the length in the SECItem to be the number |
783 | | of bits */ |
784 | 669k | temp.len = (temp.len - 1) * 8 - (temp.data[0] & 0x7); |
785 | 669k | temp.data++; |
786 | 669k | break; |
787 | 670k | } |
788 | | |
789 | 2.20M | default: { |
790 | 2.20M | break; |
791 | 670k | } |
792 | 3.22M | } |
793 | 3.23M | } |
794 | 3.23M | } |
795 | 16.7M | } |
796 | | |
797 | 18.9M | if ((SECSuccess == rv) && (PR_TRUE == save)) { |
798 | 11.5M | SECItem* destItem = (SECItem*)((char*)dest + templateEntry->offset); |
799 | 11.5M | if (destItem) { |
800 | | /* we leave the type alone in the destination SECItem. |
801 | | If part of the destination was allocated by the decoder, in |
802 | | cases of POINTER, SET OF and SEQUENCE OF, then type is set to |
803 | | siBuffer due to the use of PORT_ArenaZAlloc*/ |
804 | 11.5M | destItem->data = temp.len ? temp.data : NULL; |
805 | 11.5M | destItem->len = temp.len; |
806 | 11.5M | } else { |
807 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
808 | 0 | rv = SECFailure; |
809 | 0 | } |
810 | 11.5M | } |
811 | | |
812 | 18.9M | if (PR_TRUE == pop) { |
813 | | /* we don't want to move ahead, so restore the position */ |
814 | 1.28M | *src = mark; |
815 | 1.28M | } |
816 | 18.9M | return rv; |
817 | 18.9M | } |
818 | | |
819 | | /* the function below is the public one */ |
820 | | |
821 | | SECStatus |
822 | | SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest, |
823 | | const SEC_ASN1Template* templateEntry, |
824 | | const SECItem* src) |
825 | 2.00M | { |
826 | 2.00M | SECStatus rv = SECSuccess; |
827 | 2.00M | SECItem newsrc; |
828 | | |
829 | 2.00M | if (!arena || !templateEntry || !src) { |
830 | 11 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
831 | 11 | rv = SECFailure; |
832 | 11 | } |
833 | | |
834 | 2.00M | if (SECSuccess == rv) { |
835 | 2.00M | newsrc = *src; |
836 | 2.00M | rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE); |
837 | 2.00M | if (SECSuccess == rv && newsrc.len) { |
838 | 1.97k | rv = SECFailure; |
839 | 1.97k | PORT_SetError(SEC_ERROR_EXTRA_INPUT); |
840 | 1.97k | } |
841 | 2.00M | } |
842 | | |
843 | 2.00M | return rv; |
844 | 2.00M | } |