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