Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / security / nss / lib / certdb / secname.c
blob2a3f7b9d4b280810e5c8fe81b70f2ac0e08ff139
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * John Gardiner Myers <jgmyers@speakeasy.net>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "cert.h"
39 #include "secoid.h"
40 #include "secder.h" /* XXX remove this when remove the DERTemplates */
41 #include "secasn1.h"
42 #include "secitem.h"
43 #include <stdarg.h>
44 #include "secerr.h"
45 #include "certi.h"
47 static const SEC_ASN1Template cert_AVATemplate[] = {
48 { SEC_ASN1_SEQUENCE,
49 0, NULL, sizeof(CERTAVA) },
50 { SEC_ASN1_OBJECT_ID,
51 offsetof(CERTAVA,type), },
52 { SEC_ASN1_ANY,
53 offsetof(CERTAVA,value), },
54 { 0, }
57 const SEC_ASN1Template CERT_RDNTemplate[] = {
58 { SEC_ASN1_SET_OF,
59 offsetof(CERTRDN,avas), cert_AVATemplate, sizeof(CERTRDN) }
63 static int
64 CountArray(void **array)
66 int count = 0;
67 if (array) {
68 while (*array++) {
69 count++;
72 return count;
75 static void **
76 AddToArray(PRArenaPool *arena, void **array, void *element)
78 unsigned count;
79 void **ap;
81 /* Count up number of slots already in use in the array */
82 count = 0;
83 ap = array;
84 if (ap) {
85 while (*ap++) {
86 count++;
90 if (array) {
91 array = (void**) PORT_ArenaGrow(arena, array,
92 (count + 1) * sizeof(void *),
93 (count + 2) * sizeof(void *));
94 } else {
95 array = (void**) PORT_ArenaAlloc(arena, (count + 2) * sizeof(void *));
97 if (array) {
98 array[count] = element;
99 array[count+1] = 0;
101 return array;
105 SECOidTag
106 CERT_GetAVATag(CERTAVA *ava)
108 SECOidData *oid;
109 if (!ava->type.data) return (SECOidTag)-1;
111 oid = SECOID_FindOID(&ava->type);
113 if ( oid ) {
114 return(oid->offset);
116 return (SECOidTag)-1;
119 static SECStatus
120 SetupAVAType(PRArenaPool *arena, SECOidTag type, SECItem *it, unsigned *maxLenp)
122 unsigned char *oid;
123 unsigned oidLen;
124 unsigned char *cp;
125 int maxLen;
126 SECOidData *oidrec;
128 oidrec = SECOID_FindOIDByTag(type);
129 if (oidrec == NULL)
130 return SECFailure;
132 oid = oidrec->oid.data;
133 oidLen = oidrec->oid.len;
135 maxLen = cert_AVAOidTagToMaxLen(type);
136 if (maxLen < 0) {
137 PORT_SetError(SEC_ERROR_INVALID_ARGS);
138 return SECFailure;
141 it->data = cp = (unsigned char*) PORT_ArenaAlloc(arena, oidLen);
142 if (cp == NULL) {
143 return SECFailure;
145 it->len = oidLen;
146 PORT_Memcpy(cp, oid, oidLen);
147 *maxLenp = (unsigned)maxLen;
148 return SECSuccess;
151 static SECStatus
152 SetupAVAValue(PRArenaPool *arena, int valueType, char *value, SECItem *it,
153 unsigned maxLen)
155 unsigned valueLen, valueLenLen, total;
156 unsigned ucs4Len = 0, ucs4MaxLen;
157 unsigned char *cp, *ucs4Val;
159 switch (valueType) {
160 case SEC_ASN1_PRINTABLE_STRING:
161 case SEC_ASN1_IA5_STRING:
162 case SEC_ASN1_T61_STRING:
163 case SEC_ASN1_UTF8_STRING: /* no conversion required */
164 valueLen = PORT_Strlen(value);
165 break;
166 case SEC_ASN1_UNIVERSAL_STRING:
167 valueLen = PORT_Strlen(value);
168 ucs4MaxLen = valueLen * 6;
169 ucs4Val = (unsigned char *)PORT_ArenaZAlloc(arena, ucs4MaxLen);
170 if(!ucs4Val || !PORT_UCS4_UTF8Conversion(PR_TRUE,
171 (unsigned char *)value, valueLen,
172 ucs4Val, ucs4MaxLen, &ucs4Len)) {
173 PORT_SetError(SEC_ERROR_INVALID_ARGS);
174 return SECFailure;
176 value = (char *)ucs4Val;
177 valueLen = ucs4Len;
178 maxLen *= 4;
179 break;
180 default:
181 PORT_SetError(SEC_ERROR_INVALID_ARGS);
182 return SECFailure;
185 if (valueLen > maxLen) {
186 PORT_SetError(SEC_ERROR_INVALID_ARGS);
187 return SECFailure;
190 valueLenLen = DER_LengthLength(valueLen);
191 total = 1 + valueLenLen + valueLen;
192 it->data = cp = (unsigned char*) PORT_ArenaAlloc(arena, total);
193 if (!cp) {
194 return SECFailure;
196 it->len = total;
197 cp = (unsigned char*) DER_StoreHeader(cp, valueType, valueLen);
198 PORT_Memcpy(cp, value, valueLen);
199 return SECSuccess;
202 CERTAVA *
203 CERT_CreateAVAFromRaw(PRArenaPool *pool, const SECItem * OID,
204 const SECItem * value)
206 CERTAVA *ava;
207 int rv;
209 ava = PORT_ArenaZNew(pool, CERTAVA);
210 if (ava) {
211 rv = SECITEM_CopyItem(pool, &ava->type, OID);
212 if (rv)
213 return NULL;
215 rv = SECITEM_CopyItem(pool, &ava->value, value);
216 if (rv)
217 return NULL;
219 return ava;
222 CERTAVA *
223 CERT_CreateAVA(PRArenaPool *arena, SECOidTag kind, int valueType, char *value)
225 CERTAVA *ava;
226 int rv;
227 unsigned maxLen;
229 ava = (CERTAVA*) PORT_ArenaZAlloc(arena, sizeof(CERTAVA));
230 if (ava) {
231 rv = SetupAVAType(arena, kind, &ava->type, &maxLen);
232 if (rv) {
233 /* Illegal AVA type */
234 return 0;
236 rv = SetupAVAValue(arena, valueType, value, &ava->value, maxLen);
237 if (rv) {
238 /* Illegal value type */
239 return 0;
242 return ava;
245 CERTAVA *
246 CERT_CopyAVA(PRArenaPool *arena, CERTAVA *from)
248 CERTAVA *ava;
249 int rv;
251 ava = (CERTAVA*) PORT_ArenaZAlloc(arena, sizeof(CERTAVA));
252 if (ava) {
253 rv = SECITEM_CopyItem(arena, &ava->type, &from->type);
254 if (rv) goto loser;
255 rv = SECITEM_CopyItem(arena, &ava->value, &from->value);
256 if (rv) goto loser;
258 return ava;
260 loser:
261 return 0;
264 /************************************************************************/
265 /* XXX This template needs to go away in favor of the new SEC_ASN1 version. */
266 static const SEC_ASN1Template cert_RDNTemplate[] = {
267 { SEC_ASN1_SET_OF,
268 offsetof(CERTRDN,avas), cert_AVATemplate, sizeof(CERTRDN) }
272 CERTRDN *
273 CERT_CreateRDN(PRArenaPool *arena, CERTAVA *ava0, ...)
275 CERTAVA *ava;
276 CERTRDN *rdn;
277 va_list ap;
278 unsigned count;
279 CERTAVA **avap;
281 rdn = (CERTRDN*) PORT_ArenaAlloc(arena, sizeof(CERTRDN));
282 if (rdn) {
283 /* Count number of avas going into the rdn */
284 count = 0;
285 if (ava0) {
286 count++;
287 va_start(ap, ava0);
288 while ((ava = va_arg(ap, CERTAVA*)) != 0) {
289 count++;
291 va_end(ap);
294 /* Now fill in the pointers */
295 rdn->avas = avap =
296 (CERTAVA**) PORT_ArenaAlloc( arena, (count + 1)*sizeof(CERTAVA*));
297 if (!avap) {
298 return 0;
300 if (ava0) {
301 *avap++ = ava0;
302 va_start(ap, ava0);
303 while ((ava = va_arg(ap, CERTAVA*)) != 0) {
304 *avap++ = ava;
306 va_end(ap);
308 *avap++ = 0;
310 return rdn;
313 SECStatus
314 CERT_AddAVA(PRArenaPool *arena, CERTRDN *rdn, CERTAVA *ava)
316 rdn->avas = (CERTAVA**) AddToArray(arena, (void**) rdn->avas, ava);
317 return rdn->avas ? SECSuccess : SECFailure;
320 SECStatus
321 CERT_CopyRDN(PRArenaPool *arena, CERTRDN *to, CERTRDN *from)
323 CERTAVA **avas, *fava, *tava;
324 SECStatus rv = SECSuccess;
326 /* Copy each ava from from */
327 avas = from->avas;
328 if (avas) {
329 if (avas[0] == NULL) {
330 rv = CERT_AddAVA(arena, to, NULL);
331 return rv;
333 while ((fava = *avas++) != 0) {
334 tava = CERT_CopyAVA(arena, fava);
335 if (!tava) {
336 rv = SECFailure;
337 break;
339 rv = CERT_AddAVA(arena, to, tava);
340 if (rv != SECSuccess)
341 break;
344 return rv;
347 /************************************************************************/
349 const SEC_ASN1Template CERT_NameTemplate[] = {
350 { SEC_ASN1_SEQUENCE_OF,
351 offsetof(CERTName,rdns), CERT_RDNTemplate, sizeof(CERTName) }
354 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_NameTemplate)
356 CERTName *
357 CERT_CreateName(CERTRDN *rdn0, ...)
359 CERTRDN *rdn;
360 CERTName *name;
361 va_list ap;
362 unsigned count;
363 CERTRDN **rdnp;
364 PRArenaPool *arena;
366 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
367 if ( !arena ) {
368 return(0);
371 name = (CERTName*) PORT_ArenaAlloc(arena, sizeof(CERTName));
372 if (name) {
373 name->arena = arena;
375 /* Count number of RDNs going into the Name */
376 if (!rdn0) {
377 count = 0;
378 } else {
379 count = 1;
380 va_start(ap, rdn0);
381 while ((rdn = va_arg(ap, CERTRDN*)) != 0) {
382 count++;
384 va_end(ap);
387 /* Allocate space (including space for terminal null ptr) */
388 name->rdns = rdnp =
389 (CERTRDN**) PORT_ArenaAlloc(arena, (count + 1) * sizeof(CERTRDN*));
390 if (!name->rdns) {
391 goto loser;
394 /* Now fill in the pointers */
395 if (count > 0) {
396 *rdnp++ = rdn0;
397 va_start(ap, rdn0);
398 while ((rdn = va_arg(ap, CERTRDN*)) != 0) {
399 *rdnp++ = rdn;
401 va_end(ap);
404 /* null terminate the list */
405 *rdnp++ = 0;
407 return name;
409 loser:
410 PORT_FreeArena(arena, PR_FALSE);
411 return(0);
414 void
415 CERT_DestroyName(CERTName *name)
417 if (name)
419 PRArenaPool *arena = name->arena;
420 name->rdns = NULL;
421 name->arena = NULL;
422 if (arena) PORT_FreeArena(arena, PR_FALSE);
426 SECStatus
427 CERT_AddRDN(CERTName *name, CERTRDN *rdn)
429 name->rdns = (CERTRDN**) AddToArray(name->arena, (void**) name->rdns, rdn);
430 return name->rdns ? SECSuccess : SECFailure;
433 SECStatus
434 CERT_CopyName(PRArenaPool *arena, CERTName *to, CERTName *from)
436 CERTRDN **rdns, *frdn, *trdn;
437 SECStatus rv = SECSuccess;
439 if (!to || !from) {
440 PORT_SetError(SEC_ERROR_INVALID_ARGS);
441 return SECFailure;
444 CERT_DestroyName(to);
445 to->arena = arena;
447 /* Copy each rdn from from */
448 rdns = from->rdns;
449 if (rdns) {
450 if (rdns[0] == NULL) {
451 rv = CERT_AddRDN(to, NULL);
452 return rv;
454 while ((frdn = *rdns++) != NULL) {
455 trdn = CERT_CreateRDN(arena, NULL);
456 if (!trdn) {
457 rv = SECFailure;
458 break;
460 rv = CERT_CopyRDN(arena, trdn, frdn);
461 if (rv != SECSuccess)
462 break;
463 rv = CERT_AddRDN(to, trdn);
464 if (rv != SECSuccess)
465 break;
468 return rv;
471 /************************************************************************/
473 static void
474 canonicalize(SECItem * foo)
476 int ch, lastch, len, src, dest;
478 /* strip trailing whitespace. */
479 len = foo->len;
480 while (len > 0 && ((ch = foo->data[len - 1]) == ' ' ||
481 ch == '\t' || ch == '\r' || ch == '\n')) {
482 len--;
485 src = 0;
486 /* strip leading whitespace. */
487 while (src < len && ((ch = foo->data[src]) == ' ' ||
488 ch == '\t' || ch == '\r' || ch == '\n')) {
489 src++;
491 dest = 0; lastch = ' ';
492 while (src < len) {
493 ch = foo->data[src++];
494 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
495 ch = ' ';
496 if (ch == lastch)
497 continue;
498 } else if (ch >= 'A' && ch <= 'Z') {
499 ch |= 0x20; /* downshift */
501 foo->data[dest++] = lastch = ch;
503 foo->len = dest;
506 /* SECItems a and b contain DER-encoded printable strings. */
507 SECComparison
508 CERT_CompareDERPrintableStrings(const SECItem *a, const SECItem *b)
510 SECComparison rv = SECLessThan;
511 SECItem * aVal = CERT_DecodeAVAValue(a);
512 SECItem * bVal = CERT_DecodeAVAValue(b);
514 if (aVal && aVal->len && aVal->data &&
515 bVal && bVal->len && bVal->data) {
516 canonicalize(aVal);
517 canonicalize(bVal);
518 rv = SECITEM_CompareItem(aVal, bVal);
520 SECITEM_FreeItem(aVal, PR_TRUE);
521 SECITEM_FreeItem(bVal, PR_TRUE);
522 return rv;
525 SECComparison
526 CERT_CompareAVA(const CERTAVA *a, const CERTAVA *b)
528 SECComparison rv;
530 rv = SECITEM_CompareItem(&a->type, &b->type);
531 if (SECEqual != rv)
532 return rv; /* Attribute types don't match. */
533 /* Let's be optimistic. Maybe the values will just compare equal. */
534 rv = SECITEM_CompareItem(&a->value, &b->value);
535 if (SECEqual == rv)
536 return rv; /* values compared exactly. */
537 if (a->value.len && a->value.data && b->value.len && b->value.data) {
538 /* Here, the values did not match.
539 ** If the values had different encodings, convert them to the same
540 ** encoding and compare that way.
542 if (a->value.data[0] != b->value.data[0]) {
543 /* encodings differ. Convert both to UTF-8 and compare. */
544 SECItem * aVal = CERT_DecodeAVAValue(&a->value);
545 SECItem * bVal = CERT_DecodeAVAValue(&b->value);
546 if (aVal && aVal->len && aVal->data &&
547 bVal && bVal->len && bVal->data) {
548 rv = SECITEM_CompareItem(aVal, bVal);
550 SECITEM_FreeItem(aVal, PR_TRUE);
551 SECITEM_FreeItem(bVal, PR_TRUE);
552 } else if (a->value.data[0] == 0x13) { /* both are printable strings. */
553 /* printable strings */
554 rv = CERT_CompareDERPrintableStrings(&a->value, &b->value);
557 return rv;
560 SECComparison
561 CERT_CompareRDN(CERTRDN *a, CERTRDN *b)
563 CERTAVA **aavas, *aava;
564 CERTAVA **bavas, *bava;
565 int ac, bc;
566 SECComparison rv = SECEqual;
568 aavas = a->avas;
569 bavas = b->avas;
572 ** Make sure array of ava's are the same length. If not, then we are
573 ** not equal
575 ac = CountArray((void**) aavas);
576 bc = CountArray((void**) bavas);
577 if (ac < bc) return SECLessThan;
578 if (ac > bc) return SECGreaterThan;
580 while (NULL != (aava = *aavas++)) {
581 for (bavas = b->avas; bava = *bavas++; ) {
582 rv = SECITEM_CompareItem(&aava->type, &bava->type);
583 if (SECEqual == rv) {
584 rv = CERT_CompareAVA(aava, bava);
585 if (SECEqual != rv)
586 return rv;
587 break;
590 if (!bava) /* didn't find a match */
591 return SECGreaterThan;
593 return rv;
596 SECComparison
597 CERT_CompareName(CERTName *a, CERTName *b)
599 CERTRDN **ardns, *ardn;
600 CERTRDN **brdns, *brdn;
601 int ac, bc;
602 SECComparison rv = SECEqual;
604 ardns = a->rdns;
605 brdns = b->rdns;
608 ** Make sure array of rdn's are the same length. If not, then we are
609 ** not equal
611 ac = CountArray((void**) ardns);
612 bc = CountArray((void**) brdns);
613 if (ac < bc) return SECLessThan;
614 if (ac > bc) return SECGreaterThan;
616 for (;;) {
617 ardn = *ardns++;
618 brdn = *brdns++;
619 if (!ardn) {
620 break;
622 rv = CERT_CompareRDN(ardn, brdn);
623 if (rv) return rv;
625 return rv;
628 /* Moved from certhtml.c */
629 SECItem *
630 CERT_DecodeAVAValue(const SECItem *derAVAValue)
632 SECItem *retItem;
633 const SEC_ASN1Template *theTemplate = NULL;
634 enum { conv_none, conv_ucs4, conv_ucs2, conv_iso88591 } convert = conv_none;
635 SECItem avaValue = {siBuffer, 0};
636 PLArenaPool *newarena = NULL;
638 if (!derAVAValue || !derAVAValue->len || !derAVAValue->data) {
639 PORT_SetError(SEC_ERROR_INVALID_ARGS);
640 return NULL;
643 switch(derAVAValue->data[0]) {
644 case SEC_ASN1_UNIVERSAL_STRING:
645 convert = conv_ucs4;
646 theTemplate = SEC_ASN1_GET(SEC_UniversalStringTemplate);
647 break;
648 case SEC_ASN1_IA5_STRING:
649 theTemplate = SEC_ASN1_GET(SEC_IA5StringTemplate);
650 break;
651 case SEC_ASN1_PRINTABLE_STRING:
652 theTemplate = SEC_ASN1_GET(SEC_PrintableStringTemplate);
653 break;
654 case SEC_ASN1_T61_STRING:
656 * Per common practice, we're not decoding actual T.61, but instead
657 * treating T61-labeled strings as containing ISO-8859-1.
659 convert = conv_iso88591;
660 theTemplate = SEC_ASN1_GET(SEC_T61StringTemplate);
661 break;
662 case SEC_ASN1_BMP_STRING:
663 convert = conv_ucs2;
664 theTemplate = SEC_ASN1_GET(SEC_BMPStringTemplate);
665 break;
666 case SEC_ASN1_UTF8_STRING:
667 /* No conversion needed ! */
668 theTemplate = SEC_ASN1_GET(SEC_UTF8StringTemplate);
669 break;
670 default:
671 PORT_SetError(SEC_ERROR_INVALID_AVA);
672 return NULL;
675 PORT_Memset(&avaValue, 0, sizeof(SECItem));
676 newarena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
677 if (!newarena) {
678 return NULL;
680 if(SEC_QuickDERDecodeItem(newarena, &avaValue, theTemplate, derAVAValue)
681 != SECSuccess) {
682 PORT_FreeArena(newarena, PR_FALSE);
683 return NULL;
686 if (convert != conv_none) {
687 unsigned int utf8ValLen = avaValue.len * 3;
688 unsigned char *utf8Val = (unsigned char*)
689 PORT_ArenaZAlloc(newarena, utf8ValLen);
691 switch (convert) {
692 case conv_ucs4:
693 if(avaValue.len % 4 != 0 ||
694 !PORT_UCS4_UTF8Conversion(PR_FALSE, avaValue.data, avaValue.len,
695 utf8Val, utf8ValLen, &utf8ValLen)) {
696 PORT_FreeArena(newarena, PR_FALSE);
697 PORT_SetError(SEC_ERROR_INVALID_AVA);
698 return NULL;
700 break;
701 case conv_ucs2:
702 if(avaValue.len % 2 != 0 ||
703 !PORT_UCS2_UTF8Conversion(PR_FALSE, avaValue.data, avaValue.len,
704 utf8Val, utf8ValLen, &utf8ValLen)) {
705 PORT_FreeArena(newarena, PR_FALSE);
706 PORT_SetError(SEC_ERROR_INVALID_AVA);
707 return NULL;
709 break;
710 case conv_iso88591:
711 if(!PORT_ISO88591_UTF8Conversion(avaValue.data, avaValue.len,
712 utf8Val, utf8ValLen, &utf8ValLen)) {
713 PORT_FreeArena(newarena, PR_FALSE);
714 PORT_SetError(SEC_ERROR_INVALID_AVA);
715 return NULL;
717 break;
718 case conv_none:
719 PORT_Assert(0); /* not reached */
720 break;
723 avaValue.data = utf8Val;
724 avaValue.len = utf8ValLen;
727 retItem = SECITEM_DupItem(&avaValue);
728 PORT_FreeArena(newarena, PR_FALSE);
729 return retItem;