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