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
CountArray(void ** array)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 **
AddToArray(PLArenaPool * arena,void ** array,void * element)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
CERT_GetAVATag(CERTAVA * ava)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
SetupAVAType(PLArenaPool * arena,SECOidTag type,SECItem * it,unsigned * maxLenp)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
SetupAVAValue(PLArenaPool * arena,int valueType,const SECItem * in,SECItem * out,unsigned maxLen)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 *
CERT_CreateAVAFromRaw(PLArenaPool * pool,const SECItem * OID,const SECItem * value)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 *
CERT_CreateAVAFromSECItem(PLArenaPool * arena,SECOidTag kind,int valueType,SECItem * value)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 *
CERT_CreateAVA(PLArenaPool * arena,SECOidTag kind,int valueType,char * value)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 *
CERT_CopyAVA(PLArenaPool * arena,CERTAVA * from)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 *
CERT_CreateRDN(PLArenaPool * arena,CERTAVA * ava0,...)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
CERT_AddAVA(PLArenaPool * arena,CERTRDN * rdn,CERTAVA * ava)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
CERT_CopyRDN(PLArenaPool * arena,CERTRDN * to,CERTRDN * from)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 
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_NameTemplate)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
CERT_DestroyName(CERTName * name)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
CERT_AddRDN(CERTName * name,CERTRDN * rdn)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
CERT_CopyName(PLArenaPool * arena,CERTName * to,const CERTName * from)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
canonicalize(SECItem * foo)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
CERT_CompareDERPrintableStrings(const SECItem * a,const SECItem * b)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
CERT_CompareAVA(const CERTAVA * a,const CERTAVA * b)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
CERT_CompareRDN(const CERTRDN * a,const CERTRDN * b)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
CERT_CompareName(const CERTName * a,const CERTName * b)569 CERT_CompareName(const CERTName *a, const CERTName *b)
570 {
571     CERTRDN **ardns;
572     CERTRDN **brdns;
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     while (rv == SECEqual && *ardns) {
591         rv = CERT_CompareRDN(*ardns++, *brdns++);
592     }
593     return rv;
594 }
595 
596 /* Moved from certhtml.c */
597 SECItem *
CERT_DecodeAVAValue(const SECItem * derAVAValue)598 CERT_DecodeAVAValue(const SECItem *derAVAValue)
599 {
600     SECItem *retItem;
601     const SEC_ASN1Template *theTemplate = NULL;
602     enum { conv_none,
603            conv_ucs4,
604            conv_ucs2,
605            conv_iso88591 } convert = conv_none;
606     SECItem avaValue = { siBuffer, 0 };
607     PORTCheapArenaPool tmpArena;
608 
609     if (!derAVAValue || !derAVAValue->len || !derAVAValue->data) {
610         PORT_SetError(SEC_ERROR_INVALID_ARGS);
611         return NULL;
612     }
613 
614     switch (derAVAValue->data[0]) {
615         case SEC_ASN1_UNIVERSAL_STRING:
616             convert = conv_ucs4;
617             theTemplate = SEC_ASN1_GET(SEC_UniversalStringTemplate);
618             break;
619         case SEC_ASN1_IA5_STRING:
620             theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
621             break;
622         case SEC_ASN1_PRINTABLE_STRING:
623             theTemplate = SEC_ASN1_GET(SEC_PrintableStringTemplate);
624             break;
625         case SEC_ASN1_T61_STRING:
626             /*
627              * Per common practice, we're not decoding actual T.61, but instead
628              * treating T61-labeled strings as containing ISO-8859-1.
629              */
630             convert = conv_iso88591;
631             theTemplate = SEC_ASN1_GET(SEC_T61StringTemplate);
632             break;
633         case SEC_ASN1_BMP_STRING:
634             convert = conv_ucs2;
635             theTemplate = SEC_ASN1_GET(SEC_BMPStringTemplate);
636             break;
637         case SEC_ASN1_UTF8_STRING:
638             /* No conversion needed ! */
639             theTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
640             break;
641         default:
642             PORT_SetError(SEC_ERROR_INVALID_AVA);
643             return NULL;
644     }
645 
646     PORT_Memset(&avaValue, 0, sizeof(SECItem));
647     PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
648     if (SEC_QuickDERDecodeItem(&tmpArena.arena, &avaValue, theTemplate,
649                                derAVAValue) != SECSuccess) {
650         PORT_DestroyCheapArena(&tmpArena);
651         return NULL;
652     }
653 
654     if (convert != conv_none) {
655         unsigned int utf8ValLen = avaValue.len * 3;
656         unsigned char *utf8Val =
657             (unsigned char *)PORT_ArenaZAlloc(&tmpArena.arena, utf8ValLen);
658 
659         switch (convert) {
660             case conv_ucs4:
661                 if (avaValue.len % 4 != 0 ||
662                     !PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data,
663                                               avaValue.len, utf8Val, utf8ValLen,
664                                               &utf8ValLen)) {
665                     PORT_DestroyCheapArena(&tmpArena);
666                     PORT_SetError(SEC_ERROR_INVALID_AVA);
667                     return NULL;
668                 }
669                 break;
670             case conv_ucs2:
671                 if (avaValue.len % 2 != 0 ||
672                     !PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data,
673                                               avaValue.len, utf8Val, utf8ValLen,
674                                               &utf8ValLen)) {
675                     PORT_DestroyCheapArena(&tmpArena);
676                     PORT_SetError(SEC_ERROR_INVALID_AVA);
677                     return NULL;
678                 }
679                 break;
680             case conv_iso88591:
681                 if (!PORT_ISO88591_UTF8Conversion(avaValue.data, avaValue.len,
682                                                   utf8Val, utf8ValLen,
683                                                   &utf8ValLen)) {
684                     PORT_DestroyCheapArena(&tmpArena);
685                     PORT_SetError(SEC_ERROR_INVALID_AVA);
686                     return NULL;
687                 }
688                 break;
689             case conv_none:
690                 PORT_Assert(0); /* not reached */
691                 break;
692         }
693 
694         avaValue.data = utf8Val;
695         avaValue.len = utf8ValLen;
696     }
697 
698     retItem = SECITEM_DupItem(&avaValue);
699     PORT_DestroyCheapArena(&tmpArena);
700     return retItem;
701 }
702