Import 1.9b4 NSS tag from cvs
[mozilla-nss.git] / security / nss / lib / certdb / genname.c
blob21c89fe7c21e7c9967ee500344fef2b7895cedee
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):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "plarena.h"
38 #include "seccomon.h"
39 #include "secitem.h"
40 #include "secoidt.h"
41 #include "mcom_db.h"
42 #include "secasn1.h"
43 #include "secder.h"
44 #include "certt.h"
45 #include "cert.h"
46 #include "xconst.h"
47 #include "secerr.h"
48 #include "secoid.h"
49 #include "prprf.h"
50 #include "genname.h"
52 SEC_ASN1_MKSUB(SEC_AnyTemplate)
53 SEC_ASN1_MKSUB(SEC_IntegerTemplate)
54 SEC_ASN1_MKSUB(SEC_IA5StringTemplate)
55 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
56 SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
58 static const SEC_ASN1Template CERTNameConstraintTemplate[] = {
59 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraint) },
60 { SEC_ASN1_ANY, offsetof(CERTNameConstraint, DERName) },
61 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
62 offsetof(CERTNameConstraint, min),
63 SEC_ASN1_SUB(SEC_IntegerTemplate) },
64 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
65 offsetof(CERTNameConstraint, max),
66 SEC_ASN1_SUB(SEC_IntegerTemplate) },
67 { 0, }
70 const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = {
71 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
74 static const SEC_ASN1Template CERTNameConstraintsTemplate[] = {
75 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraints) },
76 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
77 offsetof(CERTNameConstraints, DERPermited),
78 CERT_NameConstraintSubtreeSubTemplate},
79 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
80 offsetof(CERTNameConstraints, DERExcluded),
81 CERT_NameConstraintSubtreeSubTemplate},
82 { 0, }
86 static const SEC_ASN1Template CERTOthNameTemplate[] = {
87 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OtherName) },
88 { SEC_ASN1_OBJECT_ID,
89 offsetof(OtherName, oid) },
90 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
91 SEC_ASN1_XTRN | 0, offsetof(OtherName, name),
92 SEC_ASN1_SUB(SEC_AnyTemplate) },
93 { 0, }
96 static const SEC_ASN1Template CERTOtherNameTemplate[] = {
97 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0 ,
98 offsetof(CERTGeneralName, name.OthName), CERTOthNameTemplate,
99 sizeof(CERTGeneralName) }
102 static const SEC_ASN1Template CERTOtherName2Template[] = {
103 { SEC_ASN1_SEQUENCE | SEC_ASN1_CONTEXT_SPECIFIC | 0 ,
104 0, NULL, sizeof(CERTGeneralName) },
105 { SEC_ASN1_OBJECT_ID,
106 offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, oid) },
107 { SEC_ASN1_ANY,
108 offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, name) },
109 { 0, }
112 static const SEC_ASN1Template CERT_RFC822NameTemplate[] = {
113 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1 ,
114 offsetof(CERTGeneralName, name.other),
115 SEC_ASN1_SUB(SEC_IA5StringTemplate),
116 sizeof (CERTGeneralName)}
119 static const SEC_ASN1Template CERT_DNSNameTemplate[] = {
120 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2 ,
121 offsetof(CERTGeneralName, name.other),
122 SEC_ASN1_SUB(SEC_IA5StringTemplate),
123 sizeof (CERTGeneralName)}
126 static const SEC_ASN1Template CERT_X400AddressTemplate[] = {
127 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 3,
128 offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
129 sizeof (CERTGeneralName)}
132 static const SEC_ASN1Template CERT_DirectoryNameTemplate[] = {
133 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
134 SEC_ASN1_XTRN | 4, offsetof(CERTGeneralName, derDirectoryName),
135 SEC_ASN1_SUB(SEC_AnyTemplate), sizeof (CERTGeneralName)}
139 static const SEC_ASN1Template CERT_EDIPartyNameTemplate[] = {
140 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 5,
141 offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
142 sizeof (CERTGeneralName)}
145 static const SEC_ASN1Template CERT_URITemplate[] = {
146 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 6 ,
147 offsetof(CERTGeneralName, name.other),
148 SEC_ASN1_SUB(SEC_IA5StringTemplate),
149 sizeof (CERTGeneralName)}
152 static const SEC_ASN1Template CERT_IPAddressTemplate[] = {
153 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 7 ,
154 offsetof(CERTGeneralName, name.other),
155 SEC_ASN1_SUB(SEC_OctetStringTemplate),
156 sizeof (CERTGeneralName)}
159 static const SEC_ASN1Template CERT_RegisteredIDTemplate[] = {
160 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 8 ,
161 offsetof(CERTGeneralName, name.other),
162 SEC_ASN1_SUB(SEC_ObjectIDTemplate),
163 sizeof (CERTGeneralName)}
167 const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
168 { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN , 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
173 CERTGeneralName *
174 CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type)
176 CERTGeneralName *name = arena
177 ? PORT_ArenaZNew(arena, CERTGeneralName)
178 : PORT_ZNew(CERTGeneralName);
179 if (name) {
180 name->type = type;
181 name->l.prev = name->l.next = &name->l;
183 return name;
186 /* Copy content of one General Name to another.
187 ** Caller has allocated destination general name.
188 ** This function does not change the destinate's GeneralName's list linkage.
190 SECStatus
191 cert_CopyOneGeneralName(PRArenaPool *arena,
192 CERTGeneralName *dest,
193 CERTGeneralName *src)
195 SECStatus rv;
196 void *mark = NULL;
198 PORT_Assert(dest != NULL);
199 dest->type = src->type;
201 mark = PORT_ArenaMark(arena);
203 switch (src->type) {
204 case certDirectoryName:
205 rv = SECITEM_CopyItem(arena, &dest->derDirectoryName,
206 &src->derDirectoryName);
207 if (rv == SECSuccess)
208 rv = CERT_CopyName(arena, &dest->name.directoryName,
209 &src->name.directoryName);
210 break;
212 case certOtherName:
213 rv = SECITEM_CopyItem(arena, &dest->name.OthName.name,
214 &src->name.OthName.name);
215 if (rv == SECSuccess)
216 rv = SECITEM_CopyItem(arena, &dest->name.OthName.oid,
217 &src->name.OthName.oid);
218 break;
220 default:
221 rv = SECITEM_CopyItem(arena, &dest->name.other,
222 &src->name.other);
223 break;
226 if (rv != SECSuccess) {
227 PORT_ArenaRelease(arena, mark);
228 } else {
229 PORT_ArenaUnmark(arena, mark);
231 return rv;
235 void
236 CERT_DestroyGeneralNameList(CERTGeneralNameList *list)
238 PZLock *lock;
240 if (list != NULL) {
241 lock = list->lock;
242 PZ_Lock(lock);
243 if (--list->refCount <= 0 && list->arena != NULL) {
244 PORT_FreeArena(list->arena, PR_FALSE);
245 PZ_Unlock(lock);
246 PZ_DestroyLock(lock);
247 } else {
248 PZ_Unlock(lock);
251 return;
254 CERTGeneralNameList *
255 CERT_CreateGeneralNameList(CERTGeneralName *name) {
256 PRArenaPool *arena;
257 CERTGeneralNameList *list = NULL;
259 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
260 if (arena == NULL) {
261 goto done;
263 list = PORT_ArenaZNew(arena, CERTGeneralNameList);
264 if (!list)
265 goto loser;
266 if (name != NULL) {
267 SECStatus rv;
268 list->name = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
269 if (!list->name)
270 goto loser;
271 rv = CERT_CopyGeneralName(arena, list->name, name);
272 if (rv != SECSuccess)
273 goto loser;
275 list->lock = PZ_NewLock(nssILockList);
276 if (!list->lock)
277 goto loser;
278 list->arena = arena;
279 list->refCount = 1;
280 done:
281 return list;
283 loser:
284 PORT_FreeArena(arena, PR_FALSE);
285 return NULL;
288 CERTGeneralName *
289 CERT_GetNextGeneralName(CERTGeneralName *current)
291 PRCList *next;
293 next = current->l.next;
294 return (CERTGeneralName *) (((char *) next) - offsetof(CERTGeneralName, l));
297 CERTGeneralName *
298 CERT_GetPrevGeneralName(CERTGeneralName *current)
300 PRCList *prev;
301 prev = current->l.prev;
302 return (CERTGeneralName *) (((char *) prev) - offsetof(CERTGeneralName, l));
305 CERTNameConstraint *
306 CERT_GetNextNameConstraint(CERTNameConstraint *current)
308 PRCList *next;
310 next = current->l.next;
311 return (CERTNameConstraint *) (((char *) next) - offsetof(CERTNameConstraint, l));
314 CERTNameConstraint *
315 CERT_GetPrevNameConstraint(CERTNameConstraint *current)
317 PRCList *prev;
318 prev = current->l.prev;
319 return (CERTNameConstraint *) (((char *) prev) - offsetof(CERTNameConstraint, l));
322 SECItem *
323 CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest, PRArenaPool *arena)
326 const SEC_ASN1Template * template;
328 PORT_Assert(arena);
329 if (arena == NULL) {
330 PORT_SetError(SEC_ERROR_INVALID_ARGS);
331 return NULL;
333 /* TODO: mark arena */
334 if (dest == NULL) {
335 dest = PORT_ArenaZNew(arena, SECItem);
336 if (!dest)
337 goto loser;
339 if (genName->type == certDirectoryName) {
340 if (genName->derDirectoryName.data == NULL) {
341 /* The field hasn't been encoded yet. */
342 SECItem * pre_dest =
343 SEC_ASN1EncodeItem (arena, &(genName->derDirectoryName),
344 &(genName->name.directoryName),
345 CERT_NameTemplate);
346 if (!pre_dest)
347 goto loser;
349 if (genName->derDirectoryName.data == NULL) {
350 goto loser;
353 switch (genName->type) {
354 case certURI: template = CERT_URITemplate; break;
355 case certRFC822Name: template = CERT_RFC822NameTemplate; break;
356 case certDNSName: template = CERT_DNSNameTemplate; break;
357 case certIPAddress: template = CERT_IPAddressTemplate; break;
358 case certOtherName: template = CERTOtherNameTemplate; break;
359 case certRegisterID: template = CERT_RegisteredIDTemplate; break;
360 /* for this type, we expect the value is already encoded */
361 case certEDIPartyName: template = CERT_EDIPartyNameTemplate; break;
362 /* for this type, we expect the value is already encoded */
363 case certX400Address: template = CERT_X400AddressTemplate; break;
364 case certDirectoryName: template = CERT_DirectoryNameTemplate; break;
365 default:
366 PORT_Assert(0); goto loser;
368 dest = SEC_ASN1EncodeItem(arena, dest, genName, template);
369 if (!dest) {
370 goto loser;
372 /* TODO: unmark arena */
373 return dest;
374 loser:
375 /* TODO: release arena back to mark */
376 return NULL;
379 SECItem **
380 cert_EncodeGeneralNames(PRArenaPool *arena, CERTGeneralName *names)
382 CERTGeneralName *current_name;
383 SECItem **items = NULL;
384 int count = 0;
385 int i;
386 PRCList *head;
388 PORT_Assert(arena);
389 /* TODO: mark arena */
390 current_name = names;
391 if (names != NULL) {
392 count = 1;
394 head = &(names->l);
395 while (current_name->l.next != head) {
396 current_name = CERT_GetNextGeneralName(current_name);
397 ++count;
399 current_name = CERT_GetNextGeneralName(current_name);
400 items = PORT_ArenaNewArray(arena, SECItem *, count + 1);
401 if (items == NULL) {
402 goto loser;
404 for (i = 0; i < count; i++) {
405 items[i] = CERT_EncodeGeneralName(current_name, (SECItem *)NULL, arena);
406 if (items[i] == NULL) {
407 goto loser;
409 current_name = CERT_GetNextGeneralName(current_name);
411 items[i] = NULL;
412 /* TODO: unmark arena */
413 return items;
414 loser:
415 /* TODO: release arena to mark */
416 return NULL;
419 CERTGeneralName *
420 CERT_DecodeGeneralName(PRArenaPool *reqArena,
421 SECItem *encodedName,
422 CERTGeneralName *genName)
424 const SEC_ASN1Template * template;
425 CERTGeneralNameType genNameType;
426 SECStatus rv = SECSuccess;
427 SECItem* newEncodedName;
429 if (!reqArena) {
430 PORT_SetError(SEC_ERROR_INVALID_ARGS);
431 return NULL;
433 /* make a copy for decoding so the data decoded with QuickDER doesn't
434 point to temporary memory */
435 newEncodedName = SECITEM_ArenaDupItem(reqArena, encodedName);
436 if (!newEncodedName) {
437 return NULL;
439 /* TODO: mark arena */
440 genNameType = (CERTGeneralNameType)((*(newEncodedName->data) & 0x0f) + 1);
441 if (genName == NULL) {
442 genName = CERT_NewGeneralName(reqArena, genNameType);
443 if (!genName)
444 goto loser;
445 } else {
446 genName->type = genNameType;
447 genName->l.prev = genName->l.next = &genName->l;
450 switch (genNameType) {
451 case certURI: template = CERT_URITemplate; break;
452 case certRFC822Name: template = CERT_RFC822NameTemplate; break;
453 case certDNSName: template = CERT_DNSNameTemplate; break;
454 case certIPAddress: template = CERT_IPAddressTemplate; break;
455 case certOtherName: template = CERTOtherNameTemplate; break;
456 case certRegisterID: template = CERT_RegisteredIDTemplate; break;
457 case certEDIPartyName: template = CERT_EDIPartyNameTemplate; break;
458 case certX400Address: template = CERT_X400AddressTemplate; break;
459 case certDirectoryName: template = CERT_DirectoryNameTemplate; break;
460 default:
461 goto loser;
463 rv = SEC_QuickDERDecodeItem(reqArena, genName, template, newEncodedName);
464 if (rv != SECSuccess)
465 goto loser;
466 if (genNameType == certDirectoryName) {
467 rv = SEC_QuickDERDecodeItem(reqArena, &(genName->name.directoryName),
468 CERT_NameTemplate,
469 &(genName->derDirectoryName));
470 if (rv != SECSuccess)
471 goto loser;
474 /* TODO: unmark arena */
475 return genName;
476 loser:
477 /* TODO: release arena to mark */
478 return NULL;
481 CERTGeneralName *
482 cert_DecodeGeneralNames (PRArenaPool *arena,
483 SECItem **encodedGenName)
485 PRCList *head = NULL;
486 PRCList *tail = NULL;
487 CERTGeneralName *currentName = NULL;
489 PORT_Assert(arena);
490 if (!encodedGenName || !arena) {
491 PORT_SetError(SEC_ERROR_INVALID_ARGS);
492 return NULL;
494 /* TODO: mark arena */
495 while (*encodedGenName != NULL) {
496 currentName = CERT_DecodeGeneralName(arena, *encodedGenName, NULL);
497 if (currentName == NULL)
498 break;
499 if (head == NULL) {
500 head = &(currentName->l);
501 tail = head;
503 currentName->l.next = head;
504 currentName->l.prev = tail;
505 tail = head->prev = tail->next = &(currentName->l);
506 encodedGenName++;
508 if (currentName) {
509 /* TODO: unmark arena */
510 return CERT_GetNextGeneralName(currentName);
512 /* TODO: release arena to mark */
513 return NULL;
516 void
517 CERT_DestroyGeneralName(CERTGeneralName *name)
519 cert_DestroyGeneralNames(name);
522 SECStatus
523 cert_DestroyGeneralNames(CERTGeneralName *name)
525 CERTGeneralName *first;
526 CERTGeneralName *next = NULL;
529 first = name;
530 do {
531 next = CERT_GetNextGeneralName(name);
532 PORT_Free(name);
533 name = next;
534 } while (name != first);
535 return SECSuccess;
538 static SECItem *
539 cert_EncodeNameConstraint(CERTNameConstraint *constraint,
540 SECItem *dest,
541 PRArenaPool *arena)
543 PORT_Assert(arena);
544 if (dest == NULL) {
545 dest = PORT_ArenaZNew(arena, SECItem);
546 if (dest == NULL) {
547 return NULL;
550 CERT_EncodeGeneralName(&(constraint->name), &(constraint->DERName), arena);
552 dest = SEC_ASN1EncodeItem (arena, dest, constraint,
553 CERTNameConstraintTemplate);
554 return dest;
557 SECStatus
558 cert_EncodeNameConstraintSubTree(CERTNameConstraint *constraints,
559 PRArenaPool *arena,
560 SECItem ***dest,
561 PRBool permited)
563 CERTNameConstraint *current_constraint = constraints;
564 SECItem **items = NULL;
565 int count = 0;
566 int i;
567 PRCList *head;
569 PORT_Assert(arena);
570 /* TODO: mark arena */
571 if (constraints != NULL) {
572 count = 1;
574 head = &constraints->l;
575 while (current_constraint->l.next != head) {
576 current_constraint = CERT_GetNextNameConstraint(current_constraint);
577 ++count;
579 current_constraint = CERT_GetNextNameConstraint(current_constraint);
580 items = PORT_ArenaZNewArray(arena, SECItem *, count + 1);
581 if (items == NULL) {
582 goto loser;
584 for (i = 0; i < count; i++) {
585 items[i] = cert_EncodeNameConstraint(current_constraint,
586 (SECItem *) NULL, arena);
587 if (items[i] == NULL) {
588 goto loser;
590 current_constraint = CERT_GetNextNameConstraint(current_constraint);
592 *dest = items;
593 if (*dest == NULL) {
594 goto loser;
596 /* TODO: unmark arena */
597 return SECSuccess;
598 loser:
599 /* TODO: release arena to mark */
600 return SECFailure;
603 SECStatus
604 cert_EncodeNameConstraints(CERTNameConstraints *constraints,
605 PRArenaPool *arena,
606 SECItem *dest)
608 SECStatus rv = SECSuccess;
610 PORT_Assert(arena);
611 /* TODO: mark arena */
612 if (constraints->permited != NULL) {
613 rv = cert_EncodeNameConstraintSubTree(constraints->permited, arena,
614 &constraints->DERPermited,
615 PR_TRUE);
616 if (rv == SECFailure) {
617 goto loser;
620 if (constraints->excluded != NULL) {
621 rv = cert_EncodeNameConstraintSubTree(constraints->excluded, arena,
622 &constraints->DERExcluded,
623 PR_FALSE);
624 if (rv == SECFailure) {
625 goto loser;
628 dest = SEC_ASN1EncodeItem(arena, dest, constraints,
629 CERTNameConstraintsTemplate);
630 if (dest == NULL) {
631 goto loser;
633 /* TODO: unmark arena */
634 return SECSuccess;
635 loser:
636 /* TODO: release arena to mark */
637 return SECFailure;
641 CERTNameConstraint *
642 cert_DecodeNameConstraint(PRArenaPool *reqArena,
643 SECItem *encodedConstraint)
645 CERTNameConstraint *constraint;
646 SECStatus rv = SECSuccess;
647 CERTGeneralName *temp;
648 SECItem* newEncodedConstraint;
650 if (!reqArena) {
651 PORT_SetError(SEC_ERROR_INVALID_ARGS);
652 return NULL;
654 newEncodedConstraint = SECITEM_ArenaDupItem(reqArena, encodedConstraint);
655 if (!newEncodedConstraint) {
656 return NULL;
658 /* TODO: mark arena */
659 constraint = PORT_ArenaZNew(reqArena, CERTNameConstraint);
660 if (!constraint)
661 goto loser;
662 rv = SEC_QuickDERDecodeItem(reqArena, constraint,
663 CERTNameConstraintTemplate,
664 newEncodedConstraint);
665 if (rv != SECSuccess) {
666 goto loser;
668 temp = CERT_DecodeGeneralName(reqArena, &(constraint->DERName),
669 &(constraint->name));
670 if (temp != &(constraint->name)) {
671 goto loser;
674 /* ### sjlee: since the name constraint contains only one
675 * CERTGeneralName, the list within CERTGeneralName shouldn't
676 * point anywhere else. Otherwise, bad things will happen.
678 constraint->name.l.prev = constraint->name.l.next = &(constraint->name.l);
679 /* TODO: unmark arena */
680 return constraint;
681 loser:
682 /* TODO: release arena back to mark */
683 return NULL;
686 CERTNameConstraint *
687 cert_DecodeNameConstraintSubTree(PRArenaPool *arena,
688 SECItem **subTree,
689 PRBool permited)
691 CERTNameConstraint *current = NULL;
692 CERTNameConstraint *first = NULL;
693 CERTNameConstraint *last = NULL;
694 int i = 0;
696 PORT_Assert(arena);
697 /* TODO: mark arena */
698 while (subTree[i] != NULL) {
699 current = cert_DecodeNameConstraint(arena, subTree[i]);
700 if (current == NULL) {
701 goto loser;
703 if (last == NULL) {
704 first = last = current;
706 current->l.prev = &(last->l);
707 current->l.next = last->l.next;
708 last->l.next = &(current->l);
709 i++;
711 first->l.prev = &(current->l);
712 /* TODO: unmark arena */
713 return first;
714 loser:
715 /* TODO: release arena back to mark */
716 return NULL;
719 CERTNameConstraints *
720 cert_DecodeNameConstraints(PRArenaPool *reqArena,
721 SECItem *encodedConstraints)
723 CERTNameConstraints *constraints;
724 SECStatus rv;
725 SECItem* newEncodedConstraints;
727 if (!reqArena) {
728 PORT_SetError(SEC_ERROR_INVALID_ARGS);
729 return NULL;
731 PORT_Assert(encodedConstraints);
732 newEncodedConstraints = SECITEM_ArenaDupItem(reqArena, encodedConstraints);
734 /* TODO: mark arena */
735 constraints = PORT_ArenaZNew(reqArena, CERTNameConstraints);
736 if (constraints == NULL) {
737 goto loser;
739 rv = SEC_QuickDERDecodeItem(reqArena, constraints,
740 CERTNameConstraintsTemplate,
741 newEncodedConstraints);
742 if (rv != SECSuccess) {
743 goto loser;
745 if (constraints->DERPermited != NULL &&
746 constraints->DERPermited[0] != NULL) {
747 constraints->permited =
748 cert_DecodeNameConstraintSubTree(reqArena,
749 constraints->DERPermited,
750 PR_TRUE);
751 if (constraints->permited == NULL) {
752 goto loser;
755 if (constraints->DERExcluded != NULL &&
756 constraints->DERExcluded[0] != NULL) {
757 constraints->excluded =
758 cert_DecodeNameConstraintSubTree(reqArena,
759 constraints->DERExcluded,
760 PR_FALSE);
761 if (constraints->excluded == NULL) {
762 goto loser;
765 /* TODO: unmark arena */
766 return constraints;
767 loser:
768 /* TODO: release arena back to mark */
769 return NULL;
772 /* Copy a chain of one or more general names to a destination chain.
773 ** Caller has allocated at least the first destination GeneralName struct.
774 ** Both source and destination chains are circular doubly-linked lists.
775 ** The first source struct is copied to the first destination struct.
776 ** If the source chain has more than one member, and the destination chain
777 ** has only one member, then this function allocates new structs for all but
778 ** the first copy from the arena and links them into the destination list.
779 ** If the destination struct is part of a list with more than one member,
780 ** then this function traverses both the source and destination lists,
781 ** copying each source struct to the corresponding dest struct.
782 ** In that case, the destination list MUST contain at least as many
783 ** structs as the source list or some dest entries will be overwritten.
785 SECStatus
786 CERT_CopyGeneralName(PRArenaPool *arena,
787 CERTGeneralName *dest,
788 CERTGeneralName *src)
790 SECStatus rv;
791 CERTGeneralName *destHead = dest;
792 CERTGeneralName *srcHead = src;
794 PORT_Assert(dest != NULL);
795 if (!dest) {
796 PORT_SetError(SEC_ERROR_INVALID_ARGS);
797 return SECFailure;
799 /* TODO: mark arena */
800 do {
801 rv = cert_CopyOneGeneralName(arena, dest, src);
802 if (rv != SECSuccess)
803 goto loser;
804 src = CERT_GetNextGeneralName(src);
805 /* if there is only one general name, we shouldn't do this */
806 if (src != srcHead) {
807 if (dest->l.next == &destHead->l) {
808 CERTGeneralName *temp;
809 temp = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
810 if (!temp)
811 goto loser;
812 temp->l.next = &destHead->l;
813 temp->l.prev = &dest->l;
814 destHead->l.prev = &temp->l;
815 dest->l.next = &temp->l;
816 dest = temp;
817 } else {
818 dest = CERT_GetNextGeneralName(dest);
821 } while (src != srcHead && rv == SECSuccess);
822 /* TODO: unmark arena */
823 return rv;
824 loser:
825 /* TODO: release back to mark */
826 return SECFailure;
830 CERTGeneralNameList *
831 CERT_DupGeneralNameList(CERTGeneralNameList *list)
833 if (list != NULL) {
834 PZ_Lock(list->lock);
835 list->refCount++;
836 PZ_Unlock(list->lock);
838 return list;
841 /* Allocate space and copy CERTNameConstraint from src to dest */
842 CERTNameConstraint *
843 CERT_CopyNameConstraint(PRArenaPool *arena,
844 CERTNameConstraint *dest,
845 CERTNameConstraint *src)
847 SECStatus rv;
849 /* TODO: mark arena */
850 if (dest == NULL) {
851 dest = PORT_ArenaZNew(arena, CERTNameConstraint);
852 if (!dest)
853 goto loser;
854 /* mark that it is not linked */
855 dest->name.l.prev = dest->name.l.next = &(dest->name.l);
857 rv = CERT_CopyGeneralName(arena, &dest->name, &src->name);
858 if (rv != SECSuccess) {
859 goto loser;
861 rv = SECITEM_CopyItem(arena, &dest->DERName, &src->DERName);
862 if (rv != SECSuccess) {
863 goto loser;
865 rv = SECITEM_CopyItem(arena, &dest->min, &src->min);
866 if (rv != SECSuccess) {
867 goto loser;
869 rv = SECITEM_CopyItem(arena, &dest->max, &src->max);
870 if (rv != SECSuccess) {
871 goto loser;
873 dest->l.prev = dest->l.next = &dest->l;
874 /* TODO: unmark arena */
875 return dest;
876 loser:
877 /* TODO: release arena to mark */
878 return NULL;
882 CERTGeneralName *
883 cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2)
885 PRCList *begin1;
886 PRCList *begin2;
887 PRCList *end1;
888 PRCList *end2;
890 if (list1 == NULL){
891 return list2;
892 } else if (list2 == NULL) {
893 return list1;
894 } else {
895 begin1 = &list1->l;
896 begin2 = &list2->l;
897 end1 = list1->l.prev;
898 end2 = list2->l.prev;
899 end1->next = begin2;
900 end2->next = begin1;
901 begin1->prev = end2;
902 begin2->prev = end1;
903 return list1;
908 CERTNameConstraint *
909 cert_CombineConstraintsLists(CERTNameConstraint *list1, CERTNameConstraint *list2)
911 PRCList *begin1;
912 PRCList *begin2;
913 PRCList *end1;
914 PRCList *end2;
916 if (list1 == NULL){
917 return list2;
918 } else if (list2 == NULL) {
919 return list1;
920 } else {
921 begin1 = &list1->l;
922 begin2 = &list2->l;
923 end1 = list1->l.prev;
924 end2 = list2->l.prev;
925 end1->next = begin2;
926 end2->next = begin1;
927 begin1->prev = end2;
928 begin2->prev = end1;
929 return list1;
934 /* Add a CERTNameConstraint to the CERTNameConstraint list */
935 CERTNameConstraint *
936 CERT_AddNameConstraint(CERTNameConstraint *list,
937 CERTNameConstraint *constraint)
939 PORT_Assert(constraint != NULL);
940 constraint->l.next = constraint->l.prev = &constraint->l;
941 list = cert_CombineConstraintsLists(list, constraint);
942 return list;
946 SECStatus
947 CERT_GetNameConstraintByType (CERTNameConstraint *constraints,
948 CERTGeneralNameType type,
949 CERTNameConstraint **returnList,
950 PRArenaPool *arena)
952 CERTNameConstraint *current = NULL;
953 void *mark = NULL;
955 *returnList = NULL;
956 if (!constraints)
957 return SECSuccess;
959 mark = PORT_ArenaMark(arena);
961 current = constraints;
962 do {
963 PORT_Assert(current->name.type);
964 if (current->name.type == type) {
965 CERTNameConstraint *temp;
966 temp = CERT_CopyNameConstraint(arena, NULL, current);
967 if (temp == NULL)
968 goto loser;
969 *returnList = CERT_AddNameConstraint(*returnList, temp);
971 current = CERT_GetNextNameConstraint(current);
972 } while (current != constraints);
973 PORT_ArenaUnmark(arena, mark);
974 return SECSuccess;
976 loser:
977 PORT_ArenaRelease(arena, mark);
978 return SECFailure;
981 void *
982 CERT_GetGeneralNameByType (CERTGeneralName *genNames,
983 CERTGeneralNameType type, PRBool derFormat)
985 CERTGeneralName *current;
987 if (!genNames)
988 return NULL;
989 current = genNames;
991 do {
992 if (current->type == type) {
993 switch (type) {
994 case certDNSName:
995 case certEDIPartyName:
996 case certIPAddress:
997 case certRegisterID:
998 case certRFC822Name:
999 case certX400Address:
1000 case certURI:
1001 return (void *)&current->name.other; /* SECItem * */
1003 case certOtherName:
1004 return (void *)&current->name.OthName; /* OthName * */
1006 case certDirectoryName:
1007 return derFormat
1008 ? (void *)&current->derDirectoryName /* SECItem * */
1009 : (void *)&current->name.directoryName; /* CERTName * */
1011 PORT_Assert(0);
1012 return NULL;
1014 current = CERT_GetNextGeneralName(current);
1015 } while (current != genNames);
1016 return NULL;
1020 CERT_GetNamesLength(CERTGeneralName *names)
1022 int length = 0;
1023 CERTGeneralName *first;
1025 first = names;
1026 if (names != NULL) {
1027 do {
1028 length++;
1029 names = CERT_GetNextGeneralName(names);
1030 } while (names != first);
1032 return length;
1035 /* Creates new GeneralNames for any email addresses found in the
1036 ** input DN, and links them onto the list for the DN.
1038 SECStatus
1039 cert_ExtractDNEmailAddrs(CERTGeneralName *name, PLArenaPool *arena)
1041 CERTGeneralName *nameList = NULL;
1042 const CERTRDN **nRDNs = (const CERTRDN **)(name->name.directoryName.rdns);
1043 SECStatus rv = SECSuccess;
1045 PORT_Assert(name->type == certDirectoryName);
1046 if (name->type != certDirectoryName) {
1047 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1048 return SECFailure;
1050 /* TODO: mark arena */
1051 while (nRDNs && *nRDNs) { /* loop over RDNs */
1052 const CERTRDN *nRDN = *nRDNs++;
1053 CERTAVA **nAVAs = nRDN->avas;
1054 while (nAVAs && *nAVAs) { /* loop over AVAs */
1055 int tag;
1056 CERTAVA *nAVA = *nAVAs++;
1057 tag = CERT_GetAVATag(nAVA);
1058 if ( tag == SEC_OID_PKCS9_EMAIL_ADDRESS ||
1059 tag == SEC_OID_RFC1274_MAIL) { /* email AVA */
1060 CERTGeneralName *newName = NULL;
1061 SECItem *avaValue = CERT_DecodeAVAValue(&nAVA->value);
1062 if (!avaValue)
1063 goto loser;
1064 rv = SECFailure;
1065 newName = CERT_NewGeneralName(arena, certRFC822Name);
1066 if (newName) {
1067 rv = SECITEM_CopyItem(arena, &newName->name.other, avaValue);
1069 SECITEM_FreeItem(avaValue, PR_TRUE);
1070 if (rv != SECSuccess)
1071 goto loser;
1072 nameList = cert_CombineNamesLists(nameList, newName);
1073 } /* handle one email AVA */
1074 } /* loop over AVAs */
1075 } /* loop over RDNs */
1076 /* combine new names with old one. */
1077 name = cert_CombineNamesLists(name, nameList);
1078 /* TODO: unmark arena */
1079 return SECSuccess;
1081 loser:
1082 /* TODO: release arena back to mark */
1083 return SECFailure;
1086 /* This function is called by CERT_VerifyCertChain to extract all
1087 ** names from a cert in preparation for a name constraints test.
1089 CERTGeneralName *
1090 CERT_GetCertificateNames(CERTCertificate *cert, PRArenaPool *arena)
1092 CERTGeneralName *DN;
1093 CERTGeneralName *altName = NULL;
1094 SECItem altNameExtension = {siBuffer, NULL, 0 };
1095 SECStatus rv;
1097 /* TODO: mark arena */
1098 DN = CERT_NewGeneralName(arena, certDirectoryName);
1099 if (DN == NULL) {
1100 goto loser;
1102 rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject);
1103 if (rv != SECSuccess) {
1104 goto loser;
1106 rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject);
1107 if (rv != SECSuccess) {
1108 goto loser;
1110 /* Extract email addresses from DN, construct CERTGeneralName structs
1111 ** for them, add them to the name list
1113 rv = cert_ExtractDNEmailAddrs(DN, arena);
1114 if (rv != SECSuccess)
1115 goto loser;
1117 /* Now extract any GeneralNames from the subject name names extension. */
1118 rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
1119 &altNameExtension);
1120 if (rv == SECSuccess) {
1121 altName = CERT_DecodeAltNameExtension(arena, &altNameExtension);
1122 rv = altName ? SECSuccess : SECFailure;
1124 if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND)
1125 rv = SECSuccess;
1126 if (altNameExtension.data)
1127 SECITEM_FreeItem(&altNameExtension, PR_FALSE);
1128 if (rv != SECSuccess)
1129 goto loser;
1130 DN = cert_CombineNamesLists(DN, altName);
1132 /* TODO: unmark arena */
1133 return DN;
1134 loser:
1135 /* TODO: release arena to mark */
1136 return NULL;
1139 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for
1140 ** URI name constraints. SECFailure otherwise.
1141 ** If the constraint begins with a dot, it is a domain name, otherwise
1142 ** It is a host name. Examples:
1143 ** Constraint Name Result
1144 ** ------------ --------------- --------
1145 ** foo.bar.com foo.bar.com matches
1146 ** foo.bar.com FoO.bAr.CoM matches
1147 ** foo.bar.com www.foo.bar.com no match
1148 ** foo.bar.com nofoo.bar.com no match
1149 ** .foo.bar.com www.foo.bar.com matches
1150 ** .foo.bar.com nofoo.bar.com no match
1151 ** .foo.bar.com foo.bar.com no match
1152 ** .foo.bar.com www..foo.bar.com no match
1154 static SECStatus
1155 compareURIN2C(const SECItem *name, const SECItem *constraint)
1157 int offset;
1158 /* The spec is silent on intepreting zero-length constraints.
1159 ** We interpret them as matching no URI names.
1161 if (!constraint->len)
1162 return SECFailure;
1163 if (constraint->data[0] != '.') {
1164 /* constraint is a host name. */
1165 if (name->len != constraint->len ||
1166 PL_strncasecmp((char *)name->data,
1167 (char *)constraint->data, constraint->len))
1168 return SECFailure;
1169 return SECSuccess;
1171 /* constraint is a domain name. */
1172 if (name->len < constraint->len)
1173 return SECFailure;
1174 offset = name->len - constraint->len;
1175 if (PL_strncasecmp((char *)(name->data + offset),
1176 (char *)constraint->data, constraint->len))
1177 return SECFailure;
1178 if (!offset ||
1179 (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
1180 return SECSuccess;
1181 return SECFailure;
1184 /* for DNSname constraints, RFC 3280 says, (section 4.2.1.11, page 38)
1186 ** DNS name restrictions are expressed as foo.bar.com. Any DNS name
1187 ** that can be constructed by simply adding to the left hand side of the
1188 ** name satisfies the name constraint. For example, www.foo.bar.com
1189 ** would satisfy the constraint but foo1.bar.com would not.
1191 ** But NIST's PKITS test suite requires that the constraint be treated
1192 ** as a domain name, and requires that any name added to the left hand
1193 ** side end in a dot ".". Sensible, but not strictly following the RFC.
1195 ** Constraint Name RFC 3280 NIST PKITS
1196 ** ------------ --------------- -------- ----------
1197 ** foo.bar.com foo.bar.com matches matches
1198 ** foo.bar.com FoO.bAr.CoM matches matches
1199 ** foo.bar.com www.foo.bar.com matches matches
1200 ** foo.bar.com nofoo.bar.com MATCHES NO MATCH
1201 ** .foo.bar.com www.foo.bar.com matches matches? disallowed?
1202 ** .foo.bar.com foo.bar.com no match no match
1203 ** .foo.bar.com www..foo.bar.com matches probably not
1205 ** We will try to conform to NIST's PKITS tests, and the unstated
1206 ** rules they imply.
1208 static SECStatus
1209 compareDNSN2C(const SECItem *name, const SECItem *constraint)
1211 int offset;
1212 /* The spec is silent on intepreting zero-length constraints.
1213 ** We interpret them as matching all DNSnames.
1215 if (!constraint->len)
1216 return SECSuccess;
1217 if (name->len < constraint->len)
1218 return SECFailure;
1219 offset = name->len - constraint->len;
1220 if (PL_strncasecmp((char *)(name->data + offset),
1221 (char *)constraint->data, constraint->len))
1222 return SECFailure;
1223 if (!offset ||
1224 (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
1225 return SECSuccess;
1226 return SECFailure;
1229 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for
1230 ** internet email addresses. SECFailure otherwise.
1231 ** If constraint contains a '@' then the two strings much match exactly.
1232 ** Else if constraint starts with a '.'. then it must match the right-most
1233 ** substring of the name,
1234 ** else constraint string must match entire name after the name's '@'.
1235 ** Empty constraint string matches all names. All comparisons case insensitive.
1237 static SECStatus
1238 compareRFC822N2C(const SECItem *name, const SECItem *constraint)
1240 int offset;
1241 if (!constraint->len)
1242 return SECSuccess;
1243 if (name->len < constraint->len)
1244 return SECFailure;
1245 if (constraint->len == 1 && constraint->data[0] == '.')
1246 return SECSuccess;
1247 for (offset = constraint->len - 1; offset >= 0; --offset) {
1248 if (constraint->data[offset] == '@') {
1249 return (name->len == constraint->len &&
1250 !PL_strncasecmp((char *)name->data,
1251 (char *)constraint->data, constraint->len))
1252 ? SECSuccess : SECFailure;
1255 offset = name->len - constraint->len;
1256 if (PL_strncasecmp((char *)(name->data + offset),
1257 (char *)constraint->data, constraint->len))
1258 return SECFailure;
1259 if (constraint->data[0] == '.')
1260 return SECSuccess;
1261 if (offset > 0 && name->data[offset - 1] == '@')
1262 return SECSuccess;
1263 return SECFailure;
1266 /* name contains either a 4 byte IPv4 address or a 16 byte IPv6 address.
1267 ** constraint contains an address of the same length, and a subnet mask
1268 ** of the same length. Compare name's address to the constraint's
1269 ** address, subject to the mask.
1270 ** Return SECSuccess if they match, SECFailure if they don't.
1272 static SECStatus
1273 compareIPaddrN2C(const SECItem *name, const SECItem *constraint)
1275 int i;
1276 if (name->len == 4 && constraint->len == 8) { /* ipv4 addr */
1277 for (i = 0; i < 4; i++) {
1278 if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+4])
1279 goto loser;
1281 return SECSuccess;
1283 if (name->len == 16 && constraint->len == 32) { /* ipv6 addr */
1284 for (i = 0; i < 16; i++) {
1285 if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+16])
1286 goto loser;
1288 return SECSuccess;
1290 loser:
1291 return SECFailure;
1294 /* start with a SECItem that points to a URI. Parse it lookingg for
1295 ** a hostname. Modify item->data and item->len to define the hostname,
1296 ** but do not modify and data at item->data.
1297 ** If anything goes wrong, the contents of *item are undefined.
1299 static SECStatus
1300 parseUriHostname(SECItem * item)
1302 int i;
1303 PRBool found = PR_FALSE;
1304 for (i = 0; (unsigned)(i+2) < item->len; ++i) {
1305 if (item->data[i ] == ':' &&
1306 item->data[i+1] == '/' &&
1307 item->data[i+2] == '/') {
1308 i += 3;
1309 item->data += i;
1310 item->len -= i;
1311 found = PR_TRUE;
1312 break;
1315 if (!found)
1316 return SECFailure;
1317 /* now look for a '/', which is an upper bound in the end of the name */
1318 for (i = 0; (unsigned)i < item->len; ++i) {
1319 if (item->data[i] == '/') {
1320 item->len = i;
1321 break;
1324 /* now look for a ':', which marks the end of the name */
1325 for (i = item->len; --i >= 0; ) {
1326 if (item->data[i] == ':') {
1327 item->len = i;
1328 break;
1331 /* now look for an '@', which marks the beginning of the hostname */
1332 for (i = 0; (unsigned)i < item->len; ++i) {
1333 if (item->data[i] == '@') {
1334 ++i;
1335 item->data += i;
1336 item->len -= i;
1337 break;
1340 return item->len ? SECSuccess : SECFailure;
1343 /* This function takes one name, and a list of constraints.
1344 ** It searches the constraints looking for a match.
1345 ** It returns SECSuccess if the name satisfies the constraints, i.e.,
1346 ** if excluded, then the name does not match any constraint,
1347 ** if permitted, then the name matches at least one constraint.
1348 ** It returns SECFailure if the name fails to satisfy the constraints,
1349 ** or if some code fails (e.g. out of memory, or invalid constraint)
1351 SECStatus
1352 cert_CompareNameWithConstraints(CERTGeneralName *name,
1353 CERTNameConstraint *constraints,
1354 PRBool excluded)
1356 SECStatus rv = SECSuccess;
1357 SECStatus matched = SECFailure;
1358 CERTNameConstraint *current;
1360 PORT_Assert(constraints); /* caller should not call with NULL */
1361 if (!constraints) {
1362 PORT_SetError(SEC_ERROR_INVALID_ARGS);
1363 return SECFailure;
1366 current = constraints;
1367 do {
1368 rv = SECSuccess;
1369 matched = SECFailure;
1370 PORT_Assert(name->type == current->name.type);
1371 switch (name->type) {
1373 case certDNSName:
1374 matched = compareDNSN2C(&name->name.other,
1375 &current->name.name.other);
1376 break;
1378 case certRFC822Name:
1379 matched = compareRFC822N2C(&name->name.other,
1380 &current->name.name.other);
1381 break;
1383 case certURI:
1385 /* make a modifiable copy of the URI SECItem. */
1386 SECItem uri = name->name.other;
1387 /* find the hostname in the URI */
1388 rv = parseUriHostname(&uri);
1389 if (rv == SECSuccess) {
1390 /* does our hostname meet the constraint? */
1391 matched = compareURIN2C(&uri, &current->name.name.other);
1394 break;
1396 case certDirectoryName:
1397 /* Determine if the constraint directory name is a "prefix"
1398 ** for the directory name being tested.
1401 /* status defaults to SECEqual, so that a constraint with
1402 ** no AVAs will be a wildcard, matching all directory names.
1404 SECComparison status = SECEqual;
1405 const CERTRDN **cRDNs =
1406 (const CERTRDN **)current->name.name.directoryName.rdns;
1407 const CERTRDN **nRDNs =
1408 (const CERTRDN **)name->name.directoryName.rdns;
1409 while (cRDNs && *cRDNs && nRDNs && *nRDNs) {
1410 /* loop over name RDNs and constraint RDNs in lock step */
1411 const CERTRDN *cRDN = *cRDNs++;
1412 const CERTRDN *nRDN = *nRDNs++;
1413 CERTAVA **cAVAs = cRDN->avas;
1414 while (cAVAs && *cAVAs) { /* loop over constraint AVAs */
1415 CERTAVA *cAVA = *cAVAs++;
1416 CERTAVA **nAVAs = nRDN->avas;
1417 while (nAVAs && *nAVAs) { /* loop over name AVAs */
1418 CERTAVA *nAVA = *nAVAs++;
1419 status = CERT_CompareAVA(cAVA, nAVA);
1420 if (status == SECEqual)
1421 break;
1422 } /* loop over name AVAs */
1423 if (status != SECEqual)
1424 break;
1425 } /* loop over constraint AVAs */
1426 if (status != SECEqual)
1427 break;
1428 } /* loop over name RDNs and constraint RDNs */
1429 matched = (status == SECEqual) ? SECSuccess : SECFailure;
1430 break;
1433 case certIPAddress: /* type 8 */
1434 matched = compareIPaddrN2C(&name->name.other,
1435 &current->name.name.other);
1436 break;
1438 /* NSS does not know how to compare these "Other" type names with
1439 ** their respective constraints. But it does know how to tell
1440 ** if the constraint applies to the type of name (by comparing
1441 ** the constraint OID to the name OID). NSS makes no use of "Other"
1442 ** type names at all, so NSS errs on the side of leniency for these
1443 ** types, provided that their OIDs match. So, when an "Other"
1444 ** name constraint appears in an excluded subtree, it never causes
1445 ** a name to fail. When an "Other" name constraint appears in a
1446 ** permitted subtree, AND the constraint's OID matches the name's
1447 ** OID, then name is treated as if it matches the constraint.
1449 case certOtherName: /* type 1 */
1450 matched = (!excluded &&
1451 name->type == current->name.type &&
1452 SECITEM_ItemsAreEqual(&name->name.OthName.oid,
1453 &current->name.name.OthName.oid))
1454 ? SECSuccess : SECFailure;
1455 break;
1457 /* NSS does not know how to compare these types of names with their
1458 ** respective constraints. But NSS makes no use of these types of
1459 ** names at all, so it errs on the side of leniency for these types.
1460 ** Constraints for these types of names never cause the name to
1461 ** fail the constraints test. NSS behaves as if the name matched
1462 ** for permitted constraints, and did not match for excluded ones.
1464 case certX400Address: /* type 4 */
1465 case certEDIPartyName: /* type 6 */
1466 case certRegisterID: /* type 9 */
1467 matched = excluded ? SECFailure : SECSuccess;
1468 break;
1470 default: /* non-standard types are not supported */
1471 rv = SECFailure;
1472 break;
1474 if (matched == SECSuccess || rv != SECSuccess)
1475 break;
1476 current = CERT_GetNextNameConstraint(current);
1477 } while (current != constraints);
1478 if (rv == SECSuccess) {
1479 if (matched == SECSuccess)
1480 rv = excluded ? SECFailure : SECSuccess;
1481 else
1482 rv = excluded ? SECSuccess : SECFailure;
1483 return rv;
1486 return SECFailure;
1489 /* Add and link a CERTGeneralName to a CERTNameConstraint list. Most
1490 ** likely the CERTNameConstraint passed in is either the permitted
1491 ** list or the excluded list of a CERTNameConstraints.
1493 SECStatus
1494 CERT_AddNameConstraintByGeneralName(PLArenaPool *arena,
1495 CERTNameConstraint **constraints,
1496 CERTGeneralName *name)
1498 SECStatus rv;
1499 CERTNameConstraint *current = NULL;
1500 CERTNameConstraint *first = *constraints;
1501 void *mark = NULL;
1503 mark = PORT_ArenaMark(arena);
1505 current = PORT_ArenaZNew(arena, CERTNameConstraint);
1506 if (current == NULL) {
1507 rv = SECFailure;
1508 goto done;
1511 rv = cert_CopyOneGeneralName(arena, &current->name, name);
1512 if (rv != SECSuccess) {
1513 goto done;
1516 current->name.l.prev = current->name.l.next = &(current->name.l);
1518 if (first == NULL) {
1519 *constraints = current;
1520 PR_INIT_CLIST(&current->l);
1521 } else {
1522 PR_INSERT_BEFORE(&current->l, &first->l);
1525 done:
1526 if (rv == SECFailure) {
1527 PORT_ArenaRelease(arena, mark);
1528 } else {
1529 PORT_ArenaUnmark(arena, mark);
1531 return rv;
1534 /* Extract the name constraints extension from the CA cert. */
1535 SECStatus
1536 CERT_FindNameConstraintsExten(PRArenaPool *arena,
1537 CERTCertificate *cert,
1538 CERTNameConstraints **constraints)
1540 SECStatus rv = SECSuccess;
1541 SECItem constraintsExtension;
1542 void *mark = NULL;
1544 *constraints = NULL;
1546 rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS,
1547 &constraintsExtension);
1548 if (rv != SECSuccess) {
1549 if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
1550 rv = SECSuccess;
1552 return rv;
1555 mark = PORT_ArenaMark(arena);
1557 *constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
1558 if (*constraints == NULL) { /* decode failed */
1559 rv = SECFailure;
1561 PORT_Free (constraintsExtension.data);
1563 if (rv == SECFailure) {
1564 PORT_ArenaRelease(arena, mark);
1565 } else {
1566 PORT_ArenaUnmark(arena, mark);
1569 return rv;
1572 /* Verify name against all the constraints relevant to that type of
1573 ** the name.
1575 SECStatus
1576 CERT_CheckNameSpace(PRArenaPool *arena,
1577 CERTNameConstraints *constraints,
1578 CERTGeneralName *currentName)
1580 CERTNameConstraint *matchingConstraints;
1581 SECStatus rv = SECSuccess;
1583 if (constraints->excluded != NULL) {
1584 rv = CERT_GetNameConstraintByType(constraints->excluded,
1585 currentName->type,
1586 &matchingConstraints, arena);
1587 if (rv == SECSuccess && matchingConstraints != NULL) {
1588 rv = cert_CompareNameWithConstraints(currentName,
1589 matchingConstraints,
1590 PR_TRUE);
1592 if (rv != SECSuccess) {
1593 return(rv);
1597 if (constraints->permited != NULL) {
1598 rv = CERT_GetNameConstraintByType(constraints->permited,
1599 currentName->type,
1600 &matchingConstraints, arena);
1601 if (rv == SECSuccess && matchingConstraints != NULL) {
1602 rv = cert_CompareNameWithConstraints(currentName,
1603 matchingConstraints,
1604 PR_FALSE);
1606 if (rv != SECSuccess) {
1607 return(rv);
1611 return(SECSuccess);
1614 /* Extract the name constraints extension from the CA cert.
1615 ** Test each and every name in namesList against all the constraints
1616 ** relevant to that type of name.
1617 ** Returns NULL in pBadCert for success, if all names are acceptable.
1618 ** If some name is not acceptable, returns a pointer to the cert that
1619 ** contained that name.
1621 SECStatus
1622 CERT_CompareNameSpace(CERTCertificate *cert,
1623 CERTGeneralName *namesList,
1624 CERTCertificate **certsList,
1625 PRArenaPool *reqArena,
1626 CERTCertificate **pBadCert)
1628 SECStatus rv = SECSuccess;
1629 CERTNameConstraints *constraints;
1630 CERTGeneralName *currentName;
1631 int count = 0;
1632 CERTCertificate *badCert = NULL;
1634 /* If no names to check, then no names can be bad. */
1635 if (!namesList)
1636 goto done;
1637 rv = CERT_FindNameConstraintsExten(reqArena, cert, &constraints);
1638 if (rv != SECSuccess) {
1639 count = -1;
1640 goto done;
1643 currentName = namesList;
1644 do {
1645 if (constraints){
1646 rv = CERT_CheckNameSpace(reqArena, constraints, currentName);
1647 if (rv != SECSuccess) {
1648 break;
1651 currentName = CERT_GetNextGeneralName(currentName);
1652 count ++;
1653 } while (currentName != namesList);
1655 done:
1656 if (rv != SECSuccess) {
1657 badCert = (count >= 0) ? certsList[count] : cert;
1659 if (pBadCert)
1660 *pBadCert = badCert;
1662 return rv;
1665 /* Search the cert for an X509_SUBJECT_ALT_NAME extension.
1666 ** ASN1 Decode it into a list of alternate names.
1667 ** Search the list of alternate names for one with the NETSCAPE_NICKNAME OID.
1668 ** ASN1 Decode that name. Turn the result into a zString.
1669 ** Look for duplicate nickname already in the certdb.
1670 ** If one is found, create a nickname string that is not a duplicate.
1672 char *
1673 CERT_GetNickName(CERTCertificate *cert,
1674 CERTCertDBHandle *handle,
1675 PRArenaPool *nicknameArena)
1677 CERTGeneralName *current;
1678 CERTGeneralName *names;
1679 char *nickname = NULL;
1680 char *returnName = NULL;
1681 char *basename = NULL;
1682 PRArenaPool *arena = NULL;
1683 CERTCertificate *tmpcert;
1684 SECStatus rv;
1685 int count;
1686 int found = 0;
1687 SECItem altNameExtension;
1688 SECItem nick;
1690 if (handle == NULL) {
1691 handle = CERT_GetDefaultCertDB();
1693 altNameExtension.data = NULL;
1694 rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME,
1695 &altNameExtension);
1696 if (rv != SECSuccess) {
1697 goto loser;
1699 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1700 if (arena == NULL) {
1701 goto loser;
1703 names = CERT_DecodeAltNameExtension(arena, &altNameExtension);
1704 if (names == NULL) {
1705 goto loser;
1707 current = names;
1708 do {
1709 if (current->type == certOtherName &&
1710 SECOID_FindOIDTag(&current->name.OthName.oid) ==
1711 SEC_OID_NETSCAPE_NICKNAME) {
1712 found = 1;
1713 break;
1715 current = CERT_GetNextGeneralName(current);
1716 } while (current != names);
1717 if (!found)
1718 goto loser;
1720 rv = SEC_QuickDERDecodeItem(arena, &nick,
1721 SEC_ASN1_GET(SEC_IA5StringTemplate),
1722 &current->name.OthName.name);
1723 if (rv != SECSuccess) {
1724 goto loser;
1727 /* make a null terminated string out of nick, with room enough at
1728 ** the end to add on a number of up to 21 digits in length, (a signed
1729 ** 64-bit number in decimal) plus a space and a "#".
1731 nickname = (char*)PORT_ZAlloc(nick.len + 24);
1732 if (!nickname)
1733 goto loser;
1734 PORT_Strncpy(nickname, (char *)nick.data, nick.len);
1736 /* Don't let this cert's nickname duplicate one already in the DB.
1737 ** If it does, create a variant of the nickname that doesn't.
1739 count = 0;
1740 while ((tmpcert = CERT_FindCertByNickname(handle, nickname)) != NULL) {
1741 CERT_DestroyCertificate(tmpcert);
1742 if (!basename) {
1743 basename = PORT_Strdup(nickname);
1744 if (!basename)
1745 goto loser;
1747 count++;
1748 sprintf(nickname, "%s #%d", basename, count);
1751 /* success */
1752 if (nicknameArena) {
1753 returnName = PORT_ArenaStrdup(nicknameArena, nickname);
1754 } else {
1755 returnName = nickname;
1756 nickname = NULL;
1758 loser:
1759 if (arena != NULL)
1760 PORT_FreeArena(arena, PR_FALSE);
1761 if (nickname)
1762 PORT_Free(nickname);
1763 if (basename)
1764 PORT_Free(basename);
1765 if (altNameExtension.data)
1766 PORT_Free(altNameExtension.data);
1767 return returnName;
1770 #if 0
1771 /* not exported from shared libs, not used. Turn on if we ever need it. */
1772 SECStatus
1773 CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b)
1775 CERTGeneralName *currentA;
1776 CERTGeneralName *currentB;
1777 PRBool found;
1779 currentA = a;
1780 currentB = b;
1781 if (a != NULL) {
1782 do {
1783 if (currentB == NULL) {
1784 return SECFailure;
1786 currentB = CERT_GetNextGeneralName(currentB);
1787 currentA = CERT_GetNextGeneralName(currentA);
1788 } while (currentA != a);
1790 if (currentB != b) {
1791 return SECFailure;
1793 currentA = a;
1794 do {
1795 currentB = b;
1796 found = PR_FALSE;
1797 do {
1798 if (currentB->type == currentA->type) {
1799 switch (currentB->type) {
1800 case certDNSName:
1801 case certEDIPartyName:
1802 case certIPAddress:
1803 case certRegisterID:
1804 case certRFC822Name:
1805 case certX400Address:
1806 case certURI:
1807 if (SECITEM_CompareItem(&currentA->name.other,
1808 &currentB->name.other)
1809 == SECEqual) {
1810 found = PR_TRUE;
1812 break;
1813 case certOtherName:
1814 if (SECITEM_CompareItem(&currentA->name.OthName.oid,
1815 &currentB->name.OthName.oid)
1816 == SECEqual &&
1817 SECITEM_CompareItem(&currentA->name.OthName.name,
1818 &currentB->name.OthName.name)
1819 == SECEqual) {
1820 found = PR_TRUE;
1822 break;
1823 case certDirectoryName:
1824 if (CERT_CompareName(&currentA->name.directoryName,
1825 &currentB->name.directoryName)
1826 == SECEqual) {
1827 found = PR_TRUE;
1832 currentB = CERT_GetNextGeneralName(currentB);
1833 } while (currentB != b && found != PR_TRUE);
1834 if (found != PR_TRUE) {
1835 return SECFailure;
1837 currentA = CERT_GetNextGeneralName(currentA);
1838 } while (currentA != a);
1839 return SECSuccess;
1842 SECStatus
1843 CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b)
1845 SECStatus rv;
1847 if (a == b) {
1848 return SECSuccess;
1850 if (a != NULL && b != NULL) {
1851 PZ_Lock(a->lock);
1852 PZ_Lock(b->lock);
1853 rv = CERT_CompareGeneralName(a->name, b->name);
1854 PZ_Unlock(a->lock);
1855 PZ_Unlock(b->lock);
1856 } else {
1857 rv = SECFailure;
1859 return rv;
1861 #endif
1863 #if 0
1864 /* This function is not exported from NSS shared libraries, and is not
1865 ** used inside of NSS.
1866 ** XXX it doesn't check for failed allocations. :-(
1868 void *
1869 CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
1870 CERTGeneralNameType type,
1871 PRArenaPool *arena)
1873 CERTName *name = NULL;
1874 SECItem *item = NULL;
1875 OtherName *other = NULL;
1876 OtherName *tmpOther = NULL;
1877 void *data;
1879 PZ_Lock(list->lock);
1880 data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE);
1881 if (data != NULL) {
1882 switch (type) {
1883 case certDNSName:
1884 case certEDIPartyName:
1885 case certIPAddress:
1886 case certRegisterID:
1887 case certRFC822Name:
1888 case certX400Address:
1889 case certURI:
1890 if (arena != NULL) {
1891 item = PORT_ArenaNew(arena, SECItem);
1892 if (item != NULL) {
1893 XXX SECITEM_CopyItem(arena, item, (SECItem *) data);
1895 } else {
1896 item = SECITEM_DupItem((SECItem *) data);
1898 PZ_Unlock(list->lock);
1899 return item;
1900 case certOtherName:
1901 other = (OtherName *) data;
1902 if (arena != NULL) {
1903 tmpOther = PORT_ArenaNew(arena, OtherName);
1904 } else {
1905 tmpOther = PORT_New(OtherName);
1907 if (tmpOther != NULL) {
1908 XXX SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
1909 XXX SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
1911 PZ_Unlock(list->lock);
1912 return tmpOther;
1913 case certDirectoryName:
1914 if (arena) {
1915 name = PORT_ArenaZNew(list->arena, CERTName);
1916 if (name) {
1917 XXX CERT_CopyName(arena, name, (CERTName *) data);
1920 PZ_Unlock(list->lock);
1921 return name;
1924 PZ_Unlock(list->lock);
1925 return NULL;
1927 #endif
1929 #if 0
1930 /* This function is not exported from NSS shared libraries, and is not
1931 ** used inside of NSS.
1932 ** XXX it should NOT be a void function, since it does allocations
1933 ** that can fail.
1935 void
1936 CERT_AddGeneralNameToList(CERTGeneralNameList *list,
1937 CERTGeneralNameType type,
1938 void *data, SECItem *oid)
1940 CERTGeneralName *name;
1942 if (list != NULL && data != NULL) {
1943 PZ_Lock(list->lock);
1944 name = CERT_NewGeneralName(list->arena, type);
1945 if (!name)
1946 goto done;
1947 switch (type) {
1948 case certDNSName:
1949 case certEDIPartyName:
1950 case certIPAddress:
1951 case certRegisterID:
1952 case certRFC822Name:
1953 case certX400Address:
1954 case certURI:
1955 XXX SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
1956 break;
1957 case certOtherName:
1958 XXX SECITEM_CopyItem(list->arena, &name->name.OthName.name,
1959 (SECItem *) data);
1960 XXX SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
1961 oid);
1962 break;
1963 case certDirectoryName:
1964 XXX CERT_CopyName(list->arena, &name->name.directoryName,
1965 (CERTName *) data);
1966 break;
1968 list->name = cert_CombineNamesLists(list->name, name);
1969 list->len++;
1970 done:
1971 PZ_Unlock(list->lock);
1973 return;
1975 #endif