OLD | NEW |
| (Empty) |
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 #include "cert.h" | |
6 #include "secoid.h" | |
7 #include "secder.h" /* XXX remove this when remove the DERTemplates */ | |
8 #include "secasn1.h" | |
9 #include "secitem.h" | |
10 #include <stdarg.h> | |
11 #include "secerr.h" | |
12 #include "certi.h" | |
13 | |
14 static const SEC_ASN1Template cert_AVATemplate[] = { | |
15 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTAVA) }, | |
16 { SEC_ASN1_OBJECT_ID, offsetof(CERTAVA, type) }, | |
17 { SEC_ASN1_ANY, offsetof(CERTAVA, value) }, | |
18 { 0 } | |
19 }; | |
20 | |
21 const SEC_ASN1Template CERT_RDNTemplate[] = { | |
22 { SEC_ASN1_SET_OF, offsetof(CERTRDN, avas), cert_AVATemplate, | |
23 sizeof(CERTRDN) } | |
24 }; | |
25 | |
26 static int | |
27 CountArray(void **array) | |
28 { | |
29 int count = 0; | |
30 if (array) { | |
31 while (*array++) { | |
32 count++; | |
33 } | |
34 } | |
35 return count; | |
36 } | |
37 | |
38 static void ** | |
39 AddToArray(PLArenaPool *arena, void **array, void *element) | |
40 { | |
41 unsigned count; | |
42 void **ap; | |
43 | |
44 /* Count up number of slots already in use in the array */ | |
45 count = 0; | |
46 ap = array; | |
47 if (ap) { | |
48 while (*ap++) { | |
49 count++; | |
50 } | |
51 } | |
52 | |
53 if (array) { | |
54 array = | |
55 (void **)PORT_ArenaGrow(arena, array, (count + 1) * sizeof(void *), | |
56 (count + 2) * sizeof(void *)); | |
57 } else { | |
58 array = (void **)PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *)); | |
59 } | |
60 if (array) { | |
61 array[count] = element; | |
62 array[count + 1] = 0; | |
63 } | |
64 return array; | |
65 } | |
66 | |
67 SECOidTag | |
68 CERT_GetAVATag(CERTAVA *ava) | |
69 { | |
70 SECOidData *oid; | |
71 if (!ava->type.data) | |
72 return (SECOidTag)-1; | |
73 | |
74 oid = SECOID_FindOID(&ava->type); | |
75 | |
76 if (oid) { | |
77 return (oid->offset); | |
78 } | |
79 return (SECOidTag)-1; | |
80 } | |
81 | |
82 static SECStatus | |
83 SetupAVAType(PLArenaPool *arena, SECOidTag type, SECItem *it, unsigned *maxLenp) | |
84 { | |
85 unsigned char *oid; | |
86 unsigned oidLen; | |
87 unsigned char *cp; | |
88 int maxLen; | |
89 SECOidData *oidrec; | |
90 | |
91 oidrec = SECOID_FindOIDByTag(type); | |
92 if (oidrec == NULL) | |
93 return SECFailure; | |
94 | |
95 oid = oidrec->oid.data; | |
96 oidLen = oidrec->oid.len; | |
97 | |
98 maxLen = cert_AVAOidTagToMaxLen(type); | |
99 if (maxLen < 0) { | |
100 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
101 return SECFailure; | |
102 } | |
103 | |
104 it->data = cp = (unsigned char *)PORT_ArenaAlloc(arena, oidLen); | |
105 if (cp == NULL) { | |
106 return SECFailure; | |
107 } | |
108 it->len = oidLen; | |
109 PORT_Memcpy(cp, oid, oidLen); | |
110 *maxLenp = (unsigned)maxLen; | |
111 return SECSuccess; | |
112 } | |
113 | |
114 static SECStatus | |
115 SetupAVAValue(PLArenaPool *arena, int valueType, const SECItem *in, | |
116 SECItem *out, unsigned maxLen) | |
117 { | |
118 PRUint8 *value, *cp, *ucs4Val; | |
119 unsigned valueLen, valueLenLen, total; | |
120 unsigned ucs4Len = 0, ucs4MaxLen; | |
121 | |
122 value = in->data; | |
123 valueLen = in->len; | |
124 switch (valueType) { | |
125 case SEC_ASN1_PRINTABLE_STRING: | |
126 case SEC_ASN1_IA5_STRING: | |
127 case SEC_ASN1_T61_STRING: | |
128 case SEC_ASN1_UTF8_STRING: /* no conversion required */ | |
129 break; | |
130 case SEC_ASN1_UNIVERSAL_STRING: | |
131 ucs4MaxLen = valueLen * 6; | |
132 ucs4Val = (PRUint8 *)PORT_ArenaZAlloc(arena, ucs4MaxLen); | |
133 if (!ucs4Val || | |
134 !PORT_UCS4_UTF8Conversion(PR_TRUE, value, valueLen, ucs4Val, | |
135 ucs4MaxLen, &ucs4Len)) { | |
136 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
137 return SECFailure; | |
138 } | |
139 value = ucs4Val; | |
140 valueLen = ucs4Len; | |
141 maxLen *= 4; | |
142 break; | |
143 default: | |
144 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
145 return SECFailure; | |
146 } | |
147 | |
148 if (valueLen > maxLen) { | |
149 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
150 return SECFailure; | |
151 } | |
152 | |
153 valueLenLen = DER_LengthLength(valueLen); | |
154 total = 1 + valueLenLen + valueLen; | |
155 cp = (PRUint8 *)PORT_ArenaAlloc(arena, total); | |
156 if (!cp) { | |
157 return SECFailure; | |
158 } | |
159 out->data = cp; | |
160 out->len = total; | |
161 cp = (PRUint8 *)DER_StoreHeader(cp, valueType, valueLen); | |
162 PORT_Memcpy(cp, value, valueLen); | |
163 return SECSuccess; | |
164 } | |
165 | |
166 CERTAVA * | |
167 CERT_CreateAVAFromRaw(PLArenaPool *pool, const SECItem *OID, | |
168 const SECItem *value) | |
169 { | |
170 CERTAVA *ava; | |
171 int rv; | |
172 | |
173 ava = PORT_ArenaZNew(pool, CERTAVA); | |
174 if (ava) { | |
175 rv = SECITEM_CopyItem(pool, &ava->type, OID); | |
176 if (rv) | |
177 return NULL; | |
178 | |
179 rv = SECITEM_CopyItem(pool, &ava->value, value); | |
180 if (rv) | |
181 return NULL; | |
182 } | |
183 return ava; | |
184 } | |
185 | |
186 CERTAVA * | |
187 CERT_CreateAVAFromSECItem(PLArenaPool *arena, SECOidTag kind, int valueType, | |
188 SECItem *value) | |
189 { | |
190 CERTAVA *ava; | |
191 int rv; | |
192 unsigned maxLen; | |
193 | |
194 ava = (CERTAVA *)PORT_ArenaZAlloc(arena, sizeof(CERTAVA)); | |
195 if (ava) { | |
196 rv = SetupAVAType(arena, kind, &ava->type, &maxLen); | |
197 if (rv) { | |
198 /* Illegal AVA type */ | |
199 return NULL; | |
200 } | |
201 rv = SetupAVAValue(arena, valueType, value, &ava->value, maxLen); | |
202 if (rv) { | |
203 /* Illegal value type */ | |
204 return NULL; | |
205 } | |
206 } | |
207 return ava; | |
208 } | |
209 | |
210 CERTAVA * | |
211 CERT_CreateAVA(PLArenaPool *arena, SECOidTag kind, int valueType, char *value) | |
212 { | |
213 SECItem item = { siBuffer, NULL, 0 }; | |
214 | |
215 item.data = (PRUint8 *)value; | |
216 item.len = PORT_Strlen(value); | |
217 | |
218 return CERT_CreateAVAFromSECItem(arena, kind, valueType, &item); | |
219 } | |
220 | |
221 CERTAVA * | |
222 CERT_CopyAVA(PLArenaPool *arena, CERTAVA *from) | |
223 { | |
224 CERTAVA *ava; | |
225 int rv; | |
226 | |
227 ava = (CERTAVA *)PORT_ArenaZAlloc(arena, sizeof(CERTAVA)); | |
228 if (ava) { | |
229 rv = SECITEM_CopyItem(arena, &ava->type, &from->type); | |
230 if (rv) | |
231 goto loser; | |
232 rv = SECITEM_CopyItem(arena, &ava->value, &from->value); | |
233 if (rv) | |
234 goto loser; | |
235 } | |
236 return ava; | |
237 | |
238 loser: | |
239 return 0; | |
240 } | |
241 | |
242 CERTRDN * | |
243 CERT_CreateRDN(PLArenaPool *arena, CERTAVA *ava0, ...) | |
244 { | |
245 CERTAVA *ava; | |
246 CERTRDN *rdn; | |
247 va_list ap; | |
248 unsigned count; | |
249 CERTAVA **avap; | |
250 | |
251 rdn = (CERTRDN *)PORT_ArenaAlloc(arena, sizeof(CERTRDN)); | |
252 if (rdn) { | |
253 /* Count number of avas going into the rdn */ | |
254 count = 0; | |
255 if (ava0) { | |
256 count++; | |
257 va_start(ap, ava0); | |
258 while ((ava = va_arg(ap, CERTAVA *)) != 0) { | |
259 count++; | |
260 } | |
261 va_end(ap); | |
262 } | |
263 | |
264 /* Now fill in the pointers */ | |
265 rdn->avas = avap = | |
266 (CERTAVA **)PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTAVA *)); | |
267 if (!avap) { | |
268 return 0; | |
269 } | |
270 if (ava0) { | |
271 *avap++ = ava0; | |
272 va_start(ap, ava0); | |
273 while ((ava = va_arg(ap, CERTAVA *)) != 0) { | |
274 *avap++ = ava; | |
275 } | |
276 va_end(ap); | |
277 } | |
278 *avap++ = 0; | |
279 } | |
280 return rdn; | |
281 } | |
282 | |
283 SECStatus | |
284 CERT_AddAVA(PLArenaPool *arena, CERTRDN *rdn, CERTAVA *ava) | |
285 { | |
286 rdn->avas = (CERTAVA **)AddToArray(arena, (void **)rdn->avas, ava); | |
287 return rdn->avas ? SECSuccess : SECFailure; | |
288 } | |
289 | |
290 SECStatus | |
291 CERT_CopyRDN(PLArenaPool *arena, CERTRDN *to, CERTRDN *from) | |
292 { | |
293 CERTAVA **avas, *fava, *tava; | |
294 SECStatus rv = SECSuccess; | |
295 | |
296 /* Copy each ava from from */ | |
297 avas = from->avas; | |
298 if (avas) { | |
299 if (avas[0] == NULL) { | |
300 rv = CERT_AddAVA(arena, to, NULL); | |
301 return rv; | |
302 } | |
303 while ((fava = *avas++) != 0) { | |
304 tava = CERT_CopyAVA(arena, fava); | |
305 if (!tava) { | |
306 rv = SECFailure; | |
307 break; | |
308 } | |
309 rv = CERT_AddAVA(arena, to, tava); | |
310 if (rv != SECSuccess) | |
311 break; | |
312 } | |
313 } | |
314 return rv; | |
315 } | |
316 | |
317 /************************************************************************/ | |
318 | |
319 const SEC_ASN1Template CERT_NameTemplate[] = { | |
320 { SEC_ASN1_SEQUENCE_OF, offsetof(CERTName, rdns), CERT_RDNTemplate, | |
321 sizeof(CERTName) } | |
322 }; | |
323 | |
324 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_NameTemplate) | |
325 | |
326 CERTName * | |
327 CERT_CreateName(CERTRDN *rdn0, ...) | |
328 { | |
329 CERTRDN *rdn; | |
330 CERTName *name; | |
331 va_list ap; | |
332 unsigned count; | |
333 CERTRDN **rdnp; | |
334 PLArenaPool *arena; | |
335 | |
336 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
337 if (!arena) { | |
338 return (0); | |
339 } | |
340 | |
341 name = (CERTName *)PORT_ArenaAlloc(arena, sizeof(CERTName)); | |
342 if (name) { | |
343 name->arena = arena; | |
344 | |
345 /* Count number of RDNs going into the Name */ | |
346 if (!rdn0) { | |
347 count = 0; | |
348 } else { | |
349 count = 1; | |
350 va_start(ap, rdn0); | |
351 while ((rdn = va_arg(ap, CERTRDN *)) != 0) { | |
352 count++; | |
353 } | |
354 va_end(ap); | |
355 } | |
356 | |
357 /* Allocate space (including space for terminal null ptr) */ | |
358 name->rdns = rdnp = | |
359 (CERTRDN **)PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTRDN *)); | |
360 if (!name->rdns) { | |
361 goto loser; | |
362 } | |
363 | |
364 /* Now fill in the pointers */ | |
365 if (count > 0) { | |
366 *rdnp++ = rdn0; | |
367 va_start(ap, rdn0); | |
368 while ((rdn = va_arg(ap, CERTRDN *)) != 0) { | |
369 *rdnp++ = rdn; | |
370 } | |
371 va_end(ap); | |
372 } | |
373 | |
374 /* null terminate the list */ | |
375 *rdnp++ = 0; | |
376 } | |
377 return name; | |
378 | |
379 loser: | |
380 PORT_FreeArena(arena, PR_FALSE); | |
381 return (0); | |
382 } | |
383 | |
384 void | |
385 CERT_DestroyName(CERTName *name) | |
386 { | |
387 if (name) { | |
388 PLArenaPool *arena = name->arena; | |
389 name->rdns = NULL; | |
390 name->arena = NULL; | |
391 if (arena) | |
392 PORT_FreeArena(arena, PR_FALSE); | |
393 } | |
394 } | |
395 | |
396 SECStatus | |
397 CERT_AddRDN(CERTName *name, CERTRDN *rdn) | |
398 { | |
399 name->rdns = (CERTRDN **)AddToArray(name->arena, (void **)name->rdns, rdn); | |
400 return name->rdns ? SECSuccess : SECFailure; | |
401 } | |
402 | |
403 SECStatus | |
404 CERT_CopyName(PLArenaPool *arena, CERTName *to, const CERTName *from) | |
405 { | |
406 CERTRDN **rdns, *frdn, *trdn; | |
407 SECStatus rv = SECSuccess; | |
408 | |
409 if (!to || !from) { | |
410 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
411 return SECFailure; | |
412 } | |
413 | |
414 CERT_DestroyName(to); | |
415 to->arena = arena; | |
416 | |
417 /* Copy each rdn from from */ | |
418 rdns = from->rdns; | |
419 if (rdns) { | |
420 if (rdns[0] == NULL) { | |
421 rv = CERT_AddRDN(to, NULL); | |
422 return rv; | |
423 } | |
424 while ((frdn = *rdns++) != NULL) { | |
425 trdn = CERT_CreateRDN(arena, NULL); | |
426 if (!trdn) { | |
427 rv = SECFailure; | |
428 break; | |
429 } | |
430 rv = CERT_CopyRDN(arena, trdn, frdn); | |
431 if (rv != SECSuccess) | |
432 break; | |
433 rv = CERT_AddRDN(to, trdn); | |
434 if (rv != SECSuccess) | |
435 break; | |
436 } | |
437 } | |
438 return rv; | |
439 } | |
440 | |
441 /************************************************************************/ | |
442 | |
443 static void | |
444 canonicalize(SECItem *foo) | |
445 { | |
446 int ch, lastch, len, src, dest; | |
447 | |
448 /* strip trailing whitespace. */ | |
449 len = foo->len; | |
450 while (len > 0 && ((ch = foo->data[len - 1]) == ' ' || ch == '\t' || | |
451 ch == '\r' || ch == '\n')) { | |
452 len--; | |
453 } | |
454 | |
455 src = 0; | |
456 /* strip leading whitespace. */ | |
457 while (src < len && ((ch = foo->data[src]) == ' ' || ch == '\t' || | |
458 ch == '\r' || ch == '\n')) { | |
459 src++; | |
460 } | |
461 dest = 0; | |
462 lastch = ' '; | |
463 while (src < len) { | |
464 ch = foo->data[src++]; | |
465 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') { | |
466 ch = ' '; | |
467 if (ch == lastch) | |
468 continue; | |
469 } else if (ch >= 'A' && ch <= 'Z') { | |
470 ch |= 0x20; /* downshift */ | |
471 } | |
472 foo->data[dest++] = lastch = ch; | |
473 } | |
474 foo->len = dest; | |
475 } | |
476 | |
477 /* SECItems a and b contain DER-encoded printable strings. */ | |
478 SECComparison | |
479 CERT_CompareDERPrintableStrings(const SECItem *a, const SECItem *b) | |
480 { | |
481 SECComparison rv = SECLessThan; | |
482 SECItem *aVal = CERT_DecodeAVAValue(a); | |
483 SECItem *bVal = CERT_DecodeAVAValue(b); | |
484 | |
485 if (aVal && aVal->len && aVal->data && bVal && bVal->len && bVal->data) { | |
486 canonicalize(aVal); | |
487 canonicalize(bVal); | |
488 rv = SECITEM_CompareItem(aVal, bVal); | |
489 } | |
490 SECITEM_FreeItem(aVal, PR_TRUE); | |
491 SECITEM_FreeItem(bVal, PR_TRUE); | |
492 return rv; | |
493 } | |
494 | |
495 SECComparison | |
496 CERT_CompareAVA(const CERTAVA *a, const CERTAVA *b) | |
497 { | |
498 SECComparison rv; | |
499 | |
500 rv = SECITEM_CompareItem(&a->type, &b->type); | |
501 if (SECEqual != rv) | |
502 return rv; /* Attribute types don't match. */ | |
503 /* Let's be optimistic. Maybe the values will just compare equal. */ | |
504 rv = SECITEM_CompareItem(&a->value, &b->value); | |
505 if (SECEqual == rv) | |
506 return rv; /* values compared exactly. */ | |
507 if (a->value.len && a->value.data && b->value.len && b->value.data) { | |
508 /* Here, the values did not match. | |
509 ** If the values had different encodings, convert them to the same | |
510 ** encoding and compare that way. | |
511 */ | |
512 if (a->value.data[0] != b->value.data[0]) { | |
513 /* encodings differ. Convert both to UTF-8 and compare. */ | |
514 SECItem *aVal = CERT_DecodeAVAValue(&a->value); | |
515 SECItem *bVal = CERT_DecodeAVAValue(&b->value); | |
516 if (aVal && aVal->len && aVal->data && bVal && bVal->len && | |
517 bVal->data) { | |
518 rv = SECITEM_CompareItem(aVal, bVal); | |
519 } | |
520 SECITEM_FreeItem(aVal, PR_TRUE); | |
521 SECITEM_FreeItem(bVal, PR_TRUE); | |
522 } else if (a->value.data[0] == 0x13) { /* both are printable strings. */ | |
523 /* printable strings */ | |
524 rv = CERT_CompareDERPrintableStrings(&a->value, &b->value); | |
525 } | |
526 } | |
527 return rv; | |
528 } | |
529 | |
530 SECComparison | |
531 CERT_CompareRDN(const CERTRDN *a, const CERTRDN *b) | |
532 { | |
533 CERTAVA **aavas, *aava; | |
534 CERTAVA **bavas, *bava; | |
535 int ac, bc; | |
536 SECComparison rv = SECEqual; | |
537 | |
538 aavas = a->avas; | |
539 bavas = b->avas; | |
540 | |
541 /* | |
542 ** Make sure array of ava's are the same length. If not, then we are | |
543 ** not equal | |
544 */ | |
545 ac = CountArray((void **)aavas); | |
546 bc = CountArray((void **)bavas); | |
547 if (ac < bc) | |
548 return SECLessThan; | |
549 if (ac > bc) | |
550 return SECGreaterThan; | |
551 | |
552 while (NULL != (aava = *aavas++)) { | |
553 for (bavas = b->avas; NULL != (bava = *bavas++);) { | |
554 rv = SECITEM_CompareItem(&aava->type, &bava->type); | |
555 if (SECEqual == rv) { | |
556 rv = CERT_CompareAVA(aava, bava); | |
557 if (SECEqual != rv) | |
558 return rv; | |
559 break; | |
560 } | |
561 } | |
562 if (!bava) /* didn't find a match */ | |
563 return SECGreaterThan; | |
564 } | |
565 return rv; | |
566 } | |
567 | |
568 SECComparison | |
569 CERT_CompareName(const CERTName *a, const CERTName *b) | |
570 { | |
571 CERTRDN **ardns, *ardn; | |
572 CERTRDN **brdns, *brdn; | |
573 int ac, bc; | |
574 SECComparison rv = SECEqual; | |
575 | |
576 ardns = a->rdns; | |
577 brdns = b->rdns; | |
578 | |
579 /* | |
580 ** Make sure array of rdn's are the same length. If not, then we are | |
581 ** not equal | |
582 */ | |
583 ac = CountArray((void **)ardns); | |
584 bc = CountArray((void **)brdns); | |
585 if (ac < bc) | |
586 return SECLessThan; | |
587 if (ac > bc) | |
588 return SECGreaterThan; | |
589 | |
590 for (;;) { | |
591 ardn = *ardns++; | |
592 brdn = *brdns++; | |
593 if (!ardn) { | |
594 break; | |
595 } | |
596 rv = CERT_CompareRDN(ardn, brdn); | |
597 if (rv) | |
598 return rv; | |
599 } | |
600 return rv; | |
601 } | |
602 | |
603 /* Moved from certhtml.c */ | |
604 SECItem * | |
605 CERT_DecodeAVAValue(const SECItem *derAVAValue) | |
606 { | |
607 SECItem *retItem; | |
608 const SEC_ASN1Template *theTemplate = NULL; | |
609 enum { conv_none, conv_ucs4, conv_ucs2, conv_iso88591 } convert = conv_none; | |
610 SECItem avaValue = { siBuffer, 0 }; | |
611 PLArenaPool *newarena = NULL; | |
612 | |
613 if (!derAVAValue || !derAVAValue->len || !derAVAValue->data) { | |
614 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
615 return NULL; | |
616 } | |
617 | |
618 switch (derAVAValue->data[0]) { | |
619 case SEC_ASN1_UNIVERSAL_STRING: | |
620 convert = conv_ucs4; | |
621 theTemplate = SEC_ASN1_GET(SEC_UniversalStringTemplate); | |
622 break; | |
623 case SEC_ASN1_IA5_STRING: | |
624 theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate); | |
625 break; | |
626 case SEC_ASN1_PRINTABLE_STRING: | |
627 theTemplate = SEC_ASN1_GET(SEC_PrintableStringTemplate); | |
628 break; | |
629 case SEC_ASN1_T61_STRING: | |
630 /* | |
631 * Per common practice, we're not decoding actual T.61, but instead | |
632 * treating T61-labeled strings as containing ISO-8859-1. | |
633 */ | |
634 convert = conv_iso88591; | |
635 theTemplate = SEC_ASN1_GET(SEC_T61StringTemplate); | |
636 break; | |
637 case SEC_ASN1_BMP_STRING: | |
638 convert = conv_ucs2; | |
639 theTemplate = SEC_ASN1_GET(SEC_BMPStringTemplate); | |
640 break; | |
641 case SEC_ASN1_UTF8_STRING: | |
642 /* No conversion needed ! */ | |
643 theTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate); | |
644 break; | |
645 default: | |
646 PORT_SetError(SEC_ERROR_INVALID_AVA); | |
647 return NULL; | |
648 } | |
649 | |
650 PORT_Memset(&avaValue, 0, sizeof(SECItem)); | |
651 newarena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
652 if (!newarena) { | |
653 return NULL; | |
654 } | |
655 if (SEC_QuickDERDecodeItem(newarena, &avaValue, theTemplate, derAVAValue) != | |
656 SECSuccess) { | |
657 PORT_FreeArena(newarena, PR_FALSE); | |
658 return NULL; | |
659 } | |
660 | |
661 if (convert != conv_none) { | |
662 unsigned int utf8ValLen = avaValue.len * 3; | |
663 unsigned char *utf8Val = | |
664 (unsigned char *)PORT_ArenaZAlloc(newarena, utf8ValLen); | |
665 | |
666 switch (convert) { | |
667 case conv_ucs4: | |
668 if (avaValue.len % 4 != 0 || | |
669 !PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data, | |
670 avaValue.len, utf8Val, utf8ValLen, | |
671 &utf8ValLen)) { | |
672 PORT_FreeArena(newarena, PR_FALSE); | |
673 PORT_SetError(SEC_ERROR_INVALID_AVA); | |
674 return NULL; | |
675 } | |
676 break; | |
677 case conv_ucs2: | |
678 if (avaValue.len % 2 != 0 || | |
679 !PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data, | |
680 avaValue.len, utf8Val, utf8ValLen, | |
681 &utf8ValLen)) { | |
682 PORT_FreeArena(newarena, PR_FALSE); | |
683 PORT_SetError(SEC_ERROR_INVALID_AVA); | |
684 return NULL; | |
685 } | |
686 break; | |
687 case conv_iso88591: | |
688 if (!PORT_ISO88591_UTF8Conversion(avaValue.data, avaValue.len, | |
689 utf8Val, utf8ValLen, | |
690 &utf8ValLen)) { | |
691 PORT_FreeArena(newarena, PR_FALSE); | |
692 PORT_SetError(SEC_ERROR_INVALID_AVA); | |
693 return NULL; | |
694 } | |
695 break; | |
696 case conv_none: | |
697 PORT_Assert(0); /* not reached */ | |
698 break; | |
699 } | |
700 | |
701 avaValue.data = utf8Val; | |
702 avaValue.len = utf8ValLen; | |
703 } | |
704 | |
705 retItem = SECITEM_DupItem(&avaValue); | |
706 PORT_FreeArena(newarena, PR_FALSE); | |
707 return retItem; | |
708 } | |
OLD | NEW |