Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / lib / certdb / genname.c
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
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/
8  *
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.
13  *
14  * The Original Code is the Netscape security libraries.
15  *
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.
20  *
21  * Contributor(s):
22  *
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.
34  *
35  * ***** END LICENSE BLOCK ***** */
36
37 #include "plarena.h"
38 #include "seccomon.h"
39 #include "secitem.h"
40 #include "secoidt.h"
41 #include "secasn1.h"
42 #include "secder.h"
43 #include "certt.h"
44 #include "cert.h"
45 #include "certi.h"
46 #include "xconst.h"
47 #include "secerr.h"
48 #include "secoid.h"
49 #include "prprf.h"
50 #include "genname.h"
51
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)
57
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, }
68 };
69
70 const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = {
71     { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
72 };
73
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, }
83 };
84
85
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, } 
94 };
95
96 static const SEC_ASN1Template CERTOtherNameTemplate[] = {
97     { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0 ,
98       offsetof(CERTGeneralName, name.OthName), CERTOthNameTemplate, 
99       sizeof(CERTGeneralName) }
100 };
101
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, } 
110 };
111
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)}
117 };
118
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)}
124 };
125
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)}
130 };
131
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)}
136 };
137
138
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)}
143 };
144
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)}
150 };
151
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)}
157 };
158
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)}
164 };
165
166
167 const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
168     { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN , 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
169 };
170
171
172
173 CERTGeneralName *
174 CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type)
175 {
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;
182     }
183     return name;
184 }
185
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.
189 */
190 SECStatus
191 cert_CopyOneGeneralName(PRArenaPool      *arena, 
192                         CERTGeneralName  *dest, 
193                         CERTGeneralName  *src)
194 {
195     SECStatus rv;
196     void *mark = NULL;
197
198     PORT_Assert(dest != NULL);
199     dest->type = src->type;
200
201     mark = PORT_ArenaMark(arena);
202
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;
211
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;
219
220     default: 
221         rv = SECITEM_CopyItem(arena, &dest->name.other, 
222                                       &src->name.other);
223         break;
224
225     }
226     if (rv != SECSuccess) {
227         PORT_ArenaRelease(arena, mark);
228     } else {
229         PORT_ArenaUnmark(arena, mark);
230     }
231     return rv;
232 }
233
234
235 void
236 CERT_DestroyGeneralNameList(CERTGeneralNameList *list)
237 {
238     PZLock *lock;
239
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);
249         }
250     }
251     return;
252 }
253
254 CERTGeneralNameList *
255 CERT_CreateGeneralNameList(CERTGeneralName *name) {
256     PRArenaPool *arena;
257     CERTGeneralNameList *list = NULL;
258
259     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
260     if (arena == NULL) {
261         goto done;
262     }
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;
274     }
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;
282
283 loser:
284     PORT_FreeArena(arena, PR_FALSE);
285     return NULL;
286 }
287
288 CERTGeneralName *
289 CERT_GetNextGeneralName(CERTGeneralName *current)
290 {
291     PRCList *next;
292     
293     next = current->l.next;
294     return (CERTGeneralName *) (((char *) next) - offsetof(CERTGeneralName, l));
295 }
296
297 CERTGeneralName *
298 CERT_GetPrevGeneralName(CERTGeneralName *current)
299 {
300     PRCList *prev;
301     prev = current->l.prev;
302     return (CERTGeneralName *) (((char *) prev) - offsetof(CERTGeneralName, l));
303 }
304
305 CERTNameConstraint *
306 CERT_GetNextNameConstraint(CERTNameConstraint *current)
307 {
308     PRCList *next;
309     
310     next = current->l.next;
311     return (CERTNameConstraint *) (((char *) next) - offsetof(CERTNameConstraint, l));
312 }
313
314 CERTNameConstraint *
315 CERT_GetPrevNameConstraint(CERTNameConstraint *current)
316 {
317     PRCList *prev;
318     prev = current->l.prev;
319     return (CERTNameConstraint *) (((char *) prev) - offsetof(CERTNameConstraint, l));
320 }
321
322 SECItem *
323 CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest, PRArenaPool *arena)
324 {
325
326     const SEC_ASN1Template * template;
327
328     PORT_Assert(arena);
329     if (arena == NULL) {
330         PORT_SetError(SEC_ERROR_INVALID_ARGS);
331         return NULL;
332     }
333     /* TODO: mark arena */
334     if (dest == NULL) {
335         dest = PORT_ArenaZNew(arena, SECItem);
336         if (!dest)
337             goto loser;
338     }
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;
348         }
349         if (genName->derDirectoryName.data == NULL) {
350             goto loser;
351         }
352     }
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;
367     }
368     dest = SEC_ASN1EncodeItem(arena, dest, genName, template);
369     if (!dest) {
370         goto loser;
371     }
372     /* TODO: unmark arena */
373     return dest;
374 loser:
375     /* TODO: release arena back to mark */
376     return NULL;
377 }
378
379 SECItem **
380 cert_EncodeGeneralNames(PRArenaPool *arena, CERTGeneralName *names)
381 {
382     CERTGeneralName  *current_name;
383     SECItem          **items = NULL;
384     int              count = 0;
385     int              i;
386     PRCList          *head;
387
388     PORT_Assert(arena);
389     /* TODO: mark arena */
390     current_name = names;
391     if (names != NULL) {
392         count = 1;
393     }
394     head = &(names->l);
395     while (current_name->l.next != head) {
396         current_name = CERT_GetNextGeneralName(current_name);
397         ++count;
398     }
399     current_name = CERT_GetNextGeneralName(current_name);
400     items = PORT_ArenaNewArray(arena, SECItem *, count + 1);
401     if (items == NULL) {
402         goto loser;
403     }
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;
408         }
409         current_name = CERT_GetNextGeneralName(current_name);
410     }
411     items[i] = NULL;
412     /* TODO: unmark arena */
413     return items;
414 loser:
415     /* TODO: release arena to mark */
416     return NULL;
417 }
418
419 CERTGeneralName *
420 CERT_DecodeGeneralName(PRArenaPool      *reqArena,
421                        SECItem          *encodedName,
422                        CERTGeneralName  *genName)
423 {
424     const SEC_ASN1Template *         template;
425     CERTGeneralNameType              genNameType;
426     SECStatus                        rv = SECSuccess;
427     SECItem* newEncodedName;
428
429     if (!reqArena) {
430         PORT_SetError(SEC_ERROR_INVALID_ARGS);
431         return NULL;
432     }
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;
438     }
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;
448     }
449
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;
462     }
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;
472     }
473
474     /* TODO: unmark arena */
475     return genName;
476 loser:
477     /* TODO: release arena to mark */
478     return NULL;
479 }
480
481 CERTGeneralName *
482 cert_DecodeGeneralNames (PRArenaPool  *arena,
483                          SECItem      **encodedGenName)
484 {
485     PRCList                           *head = NULL;
486     PRCList                           *tail = NULL;
487     CERTGeneralName                   *currentName = NULL;
488
489     PORT_Assert(arena);
490     if (!encodedGenName || !arena) {
491         PORT_SetError(SEC_ERROR_INVALID_ARGS);
492         return NULL;
493     }
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;
502         }
503         currentName->l.next = head;
504         currentName->l.prev = tail;
505         tail = head->prev = tail->next = &(currentName->l);
506         encodedGenName++;
507     }
508     if (currentName) {
509         /* TODO: unmark arena */
510         return CERT_GetNextGeneralName(currentName);
511     }
512     /* TODO: release arena to mark */
513     return NULL;
514 }
515
516 void
517 CERT_DestroyGeneralName(CERTGeneralName *name)
518 {
519     cert_DestroyGeneralNames(name);
520 }
521
522 SECStatus
523 cert_DestroyGeneralNames(CERTGeneralName *name)
524 {
525     CERTGeneralName    *first;
526     CERTGeneralName    *next = NULL;
527
528
529     first = name;
530     do {
531         next = CERT_GetNextGeneralName(name);
532         PORT_Free(name);
533         name = next;
534     } while (name != first);
535     return SECSuccess;
536 }
537
538 static SECItem *
539 cert_EncodeNameConstraint(CERTNameConstraint  *constraint, 
540                          SECItem             *dest,
541                          PRArenaPool         *arena)
542 {
543     PORT_Assert(arena);
544     if (dest == NULL) {
545         dest = PORT_ArenaZNew(arena, SECItem);
546         if (dest == NULL) {
547             return NULL;
548         }
549     }
550     CERT_EncodeGeneralName(&(constraint->name), &(constraint->DERName), arena);
551     
552     dest = SEC_ASN1EncodeItem (arena, dest, constraint,
553                                CERTNameConstraintTemplate);
554     return dest;
555
556
557 SECStatus 
558 cert_EncodeNameConstraintSubTree(CERTNameConstraint  *constraints,
559                                  PRArenaPool         *arena,
560                                  SECItem             ***dest,
561                                  PRBool              permited)
562 {
563     CERTNameConstraint  *current_constraint = constraints;
564     SECItem             **items = NULL;
565     int                 count = 0;
566     int                 i;
567     PRCList             *head;
568
569     PORT_Assert(arena);
570     /* TODO: mark arena */
571     if (constraints != NULL) {
572         count = 1;
573     }
574     head = &constraints->l;
575     while (current_constraint->l.next != head) {
576         current_constraint = CERT_GetNextNameConstraint(current_constraint);
577         ++count;
578     }
579     current_constraint = CERT_GetNextNameConstraint(current_constraint);
580     items = PORT_ArenaZNewArray(arena, SECItem *, count + 1);
581     if (items == NULL) {
582         goto loser;
583     }
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;
589         }
590         current_constraint = CERT_GetNextNameConstraint(current_constraint);
591     }
592     *dest = items;
593     if (*dest == NULL) {
594         goto loser;
595     }
596     /* TODO: unmark arena */
597     return SECSuccess;
598 loser:
599     /* TODO: release arena to mark */
600     return SECFailure;
601 }
602
603 SECStatus 
604 cert_EncodeNameConstraints(CERTNameConstraints  *constraints,
605                            PRArenaPool          *arena,
606                            SECItem              *dest)
607 {
608     SECStatus    rv = SECSuccess;
609
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;
618         }
619     }
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;
626         }
627     }
628     dest = SEC_ASN1EncodeItem(arena, dest, constraints, 
629                               CERTNameConstraintsTemplate);
630     if (dest == NULL) {
631         goto loser;
632     }
633     /* TODO: unmark arena */
634     return SECSuccess;
635 loser:
636     /* TODO: release arena to mark */
637     return SECFailure;
638 }
639
640
641 CERTNameConstraint *
642 cert_DecodeNameConstraint(PRArenaPool       *reqArena,
643                           SECItem           *encodedConstraint)
644 {
645     CERTNameConstraint     *constraint;
646     SECStatus              rv = SECSuccess;
647     CERTGeneralName        *temp;
648     SECItem*               newEncodedConstraint;
649
650     if (!reqArena) {
651         PORT_SetError(SEC_ERROR_INVALID_ARGS);
652         return NULL;
653     }
654     newEncodedConstraint = SECITEM_ArenaDupItem(reqArena, encodedConstraint);
655     if (!newEncodedConstraint) {
656         return NULL;
657     }
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;
667     }
668     temp = CERT_DecodeGeneralName(reqArena, &(constraint->DERName),
669                                   &(constraint->name));
670     if (temp != &(constraint->name)) {
671         goto loser;
672     }
673
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.
677      */
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;
684 }
685
686 CERTNameConstraint *
687 cert_DecodeNameConstraintSubTree(PRArenaPool   *arena,
688                                  SECItem       **subTree,
689                                  PRBool        permited)
690 {
691     CERTNameConstraint   *current = NULL;
692     CERTNameConstraint   *first = NULL;
693     CERTNameConstraint   *last = NULL;
694     int                  i = 0;
695
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;
702         }
703         if (last == NULL) {
704             first = last = current;
705         }
706         current->l.prev = &(last->l);
707         current->l.next = last->l.next;
708         last->l.next = &(current->l);
709         i++;
710     }
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;
717 }
718
719 CERTNameConstraints *
720 cert_DecodeNameConstraints(PRArenaPool   *reqArena,
721                            SECItem       *encodedConstraints)
722 {
723     CERTNameConstraints   *constraints;
724     SECStatus             rv;
725     SECItem*              newEncodedConstraints;
726
727     if (!reqArena) {
728         PORT_SetError(SEC_ERROR_INVALID_ARGS);
729         return NULL;
730     }
731     PORT_Assert(encodedConstraints);
732     newEncodedConstraints = SECITEM_ArenaDupItem(reqArena, encodedConstraints);
733
734     /* TODO: mark arena */
735     constraints = PORT_ArenaZNew(reqArena, CERTNameConstraints);
736     if (constraints == NULL) {
737         goto loser;
738     }
739     rv = SEC_QuickDERDecodeItem(reqArena, constraints,
740                                 CERTNameConstraintsTemplate,
741                                 newEncodedConstraints);
742     if (rv != SECSuccess) {
743         goto loser;
744     }
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;
753         }
754     }
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;
763         }
764     }
765     /* TODO: unmark arena */
766     return constraints;
767 loser:
768     /* TODO: release arena back to mark */
769     return NULL;
770 }
771
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.
784 */
785 SECStatus
786 CERT_CopyGeneralName(PRArenaPool      *arena, 
787                      CERTGeneralName  *dest, 
788                      CERTGeneralName  *src)
789 {
790     SECStatus rv;
791     CERTGeneralName *destHead = dest;
792     CERTGeneralName *srcHead = src;
793
794     PORT_Assert(dest != NULL);
795     if (!dest) {
796         PORT_SetError(SEC_ERROR_INVALID_ARGS);
797         return SECFailure;
798     }
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);
819             }
820         }
821     } while (src != srcHead && rv == SECSuccess);
822     /* TODO: unmark arena */
823     return rv;
824 loser:
825     /* TODO: release back to mark */
826     return SECFailure;
827 }
828
829
830 CERTGeneralNameList *
831 CERT_DupGeneralNameList(CERTGeneralNameList *list)
832 {
833     if (list != NULL) {
834         PZ_Lock(list->lock);
835         list->refCount++;
836         PZ_Unlock(list->lock);
837     }
838     return list;
839 }
840
841 /* Allocate space and copy CERTNameConstraint from src to dest */
842 CERTNameConstraint *
843 CERT_CopyNameConstraint(PRArenaPool         *arena, 
844                         CERTNameConstraint  *dest, 
845                         CERTNameConstraint  *src)
846 {
847     SECStatus  rv;
848     
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);
856     }
857     rv = CERT_CopyGeneralName(arena, &dest->name, &src->name);
858     if (rv != SECSuccess) {
859         goto loser;
860     }
861     rv = SECITEM_CopyItem(arena, &dest->DERName, &src->DERName);
862     if (rv != SECSuccess) {
863         goto loser;
864     }
865     rv = SECITEM_CopyItem(arena, &dest->min, &src->min);
866     if (rv != SECSuccess) {
867         goto loser;
868     }
869     rv = SECITEM_CopyItem(arena, &dest->max, &src->max);
870     if (rv != SECSuccess) {
871         goto loser;
872     }
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;
879 }
880
881
882 CERTGeneralName *
883 cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2)
884 {
885     PRCList *begin1;
886     PRCList *begin2;
887     PRCList *end1;
888     PRCList *end2;
889
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;
904     }
905 }
906
907
908 CERTNameConstraint *
909 cert_CombineConstraintsLists(CERTNameConstraint *list1, CERTNameConstraint *list2)
910 {
911     PRCList *begin1;
912     PRCList *begin2;
913     PRCList *end1;
914     PRCList *end2;
915
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;
930     }
931 }
932
933
934 /* Add a CERTNameConstraint to the CERTNameConstraint list */
935 CERTNameConstraint *
936 CERT_AddNameConstraint(CERTNameConstraint *list, 
937                        CERTNameConstraint *constraint)
938 {
939     PORT_Assert(constraint != NULL);
940     constraint->l.next = constraint->l.prev = &constraint->l;
941     list = cert_CombineConstraintsLists(list, constraint);
942     return list;
943 }
944
945
946 SECStatus
947 CERT_GetNameConstraintByType (CERTNameConstraint *constraints,
948                               CERTGeneralNameType type, 
949                               CERTNameConstraint **returnList,
950                               PRArenaPool *arena)
951 {
952     CERTNameConstraint *current = NULL;
953     void               *mark = NULL;
954
955     *returnList = NULL;
956     if (!constraints)
957         return SECSuccess;
958
959     mark = PORT_ArenaMark(arena);
960
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);
970         }
971         current = CERT_GetNextNameConstraint(current);
972     } while (current != constraints);
973     PORT_ArenaUnmark(arena, mark);
974     return SECSuccess;
975
976 loser:
977     PORT_ArenaRelease(arena, mark);
978     return SECFailure;
979 }
980
981 void *
982 CERT_GetGeneralNameByType (CERTGeneralName *genNames,
983                            CERTGeneralNameType type, PRBool derFormat)
984 {
985     CERTGeneralName *current;
986     
987     if (!genNames)
988         return NULL;
989     current = genNames;
990
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 * */
1002
1003             case certOtherName: 
1004                 return (void *)&current->name.OthName;         /* OthName * */
1005
1006             case certDirectoryName: 
1007                 return derFormat 
1008                        ? (void *)&current->derDirectoryName    /* SECItem * */
1009                        : (void *)&current->name.directoryName; /* CERTName * */
1010             }
1011             PORT_Assert(0); 
1012             return NULL;
1013         }
1014         current = CERT_GetNextGeneralName(current);
1015     } while (current != genNames);
1016     return NULL;
1017 }
1018
1019 int
1020 CERT_GetNamesLength(CERTGeneralName *names)
1021 {
1022     int              length = 0;
1023     CERTGeneralName  *first;
1024
1025     first = names;
1026     if (names != NULL) {
1027         do {
1028             length++;
1029             names = CERT_GetNextGeneralName(names);
1030         } while (names != first);
1031     }
1032     return length;
1033 }
1034
1035 /* Creates new GeneralNames for any email addresses found in the 
1036 ** input DN, and links them onto the list for the DN.
1037 */
1038 SECStatus
1039 cert_ExtractDNEmailAddrs(CERTGeneralName *name, PLArenaPool *arena)
1040 {
1041     CERTGeneralName *nameList = NULL;
1042     const CERTRDN  **nRDNs = (const CERTRDN **)(name->name.directoryName.rdns);
1043     SECStatus        rv        = SECSuccess;
1044
1045     PORT_Assert(name->type == certDirectoryName);
1046     if (name->type != certDirectoryName) {
1047         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1048         return SECFailure;
1049     }
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);
1068                 }
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;
1080
1081 loser:
1082     /* TODO: release arena back to mark */
1083     return SECFailure;
1084 }
1085
1086 /* Extract all names except Subject Common Name from a cert 
1087 ** in preparation for a name constraints test.
1088 */
1089 CERTGeneralName *
1090 CERT_GetCertificateNames(CERTCertificate *cert, PRArenaPool *arena)
1091 {
1092     return CERT_GetConstrainedCertificateNames(cert, arena, PR_FALSE);
1093 }
1094
1095 /* This function is called by CERT_VerifyCertChain to extract all
1096 ** names from a cert in preparation for a name constraints test.
1097 */
1098 CERTGeneralName *
1099 CERT_GetConstrainedCertificateNames(CERTCertificate *cert, PRArenaPool *arena,
1100                                     PRBool includeSubjectCommonName)
1101 {
1102     CERTGeneralName  *DN;
1103     CERTGeneralName  *SAN;
1104     PRUint32         numDNSNames = 0;
1105     SECStatus        rv;
1106
1107     if (!arena) {
1108         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1109         return NULL;
1110     }
1111     /* TODO: mark arena */
1112     DN = CERT_NewGeneralName(arena, certDirectoryName);
1113     if (DN == NULL) {
1114         goto loser;
1115     }
1116     rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject);
1117     if (rv != SECSuccess) {
1118         goto loser;
1119     }
1120     rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject);
1121     if (rv != SECSuccess) {
1122         goto loser;
1123     }
1124     /* Extract email addresses from DN, construct CERTGeneralName structs 
1125     ** for them, add them to the name list 
1126     */
1127     rv = cert_ExtractDNEmailAddrs(DN, arena);
1128     if (rv != SECSuccess)
1129         goto loser;
1130
1131     /* Now extract any GeneralNames from the subject name names extension. */
1132     SAN = cert_GetSubjectAltNameList(cert, arena);
1133     if (SAN) {
1134         numDNSNames = cert_CountDNSPatterns(SAN);
1135         DN = cert_CombineNamesLists(DN, SAN);
1136     }
1137     if (!numDNSNames && includeSubjectCommonName) {
1138         char *cn = CERT_GetCommonName(&cert->subject);
1139         if (cn) {
1140             CERTGeneralName *CN = CERT_NewGeneralName(arena, certDNSName);
1141             if (CN) {
1142                 SECItem cnItem = {siBuffer, NULL, 0};
1143                 cnItem.data = (unsigned char *)cn;
1144                 cnItem.len  = strlen(cn);
1145                 rv = SECITEM_CopyItem(arena, &CN->name.other, &cnItem);
1146                 if (rv == SECSuccess) {
1147                     DN = cert_CombineNamesLists(DN, CN);
1148                 }
1149             }
1150             PORT_Free(cn);
1151         }
1152     }
1153     if (rv == SECSuccess) {
1154         /* TODO: unmark arena */
1155         return DN;
1156     }
1157 loser:
1158     /* TODO: release arena to mark */
1159     return NULL;
1160 }
1161
1162 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for 
1163 ** URI name constraints.  SECFailure otherwise.
1164 ** If the constraint begins with a dot, it is a domain name, otherwise
1165 ** It is a host name.  Examples:
1166 **  Constraint            Name             Result
1167 ** ------------      ---------------      --------
1168 **  foo.bar.com          foo.bar.com      matches
1169 **  foo.bar.com          FoO.bAr.CoM      matches
1170 **  foo.bar.com      www.foo.bar.com      no match
1171 **  foo.bar.com        nofoo.bar.com      no match
1172 ** .foo.bar.com      www.foo.bar.com      matches
1173 ** .foo.bar.com        nofoo.bar.com      no match
1174 ** .foo.bar.com          foo.bar.com      no match
1175 ** .foo.bar.com     www..foo.bar.com      no match
1176 */
1177 static SECStatus
1178 compareURIN2C(const SECItem *name, const SECItem *constraint)
1179 {
1180     int offset;
1181     /* The spec is silent on intepreting zero-length constraints.
1182     ** We interpret them as matching no URI names.
1183     */
1184     if (!constraint->len)
1185         return SECFailure;
1186     if (constraint->data[0] != '.') { 
1187         /* constraint is a host name. */
1188         if (name->len != constraint->len ||
1189             PL_strncasecmp((char *)name->data, 
1190                            (char *)constraint->data, constraint->len))
1191             return SECFailure;
1192         return SECSuccess;
1193     }
1194     /* constraint is a domain name. */
1195     if (name->len < constraint->len)
1196         return SECFailure;
1197     offset = name->len - constraint->len;
1198     if (PL_strncasecmp((char *)(name->data + offset), 
1199                        (char *)constraint->data, constraint->len))
1200         return SECFailure;
1201     if (!offset || 
1202         (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
1203         return SECSuccess;
1204     return SECFailure;
1205 }
1206
1207 /* for DNSname constraints, RFC 3280 says, (section 4.2.1.11, page 38)
1208 **
1209 ** DNS name restrictions are expressed as foo.bar.com.  Any DNS name
1210 ** that can be constructed by simply adding to the left hand side of the
1211 ** name satisfies the name constraint.  For example, www.foo.bar.com
1212 ** would satisfy the constraint but foo1.bar.com would not.
1213 **
1214 ** But NIST's PKITS test suite requires that the constraint be treated
1215 ** as a domain name, and requires that any name added to the left hand
1216 ** side end in a dot ".".  Sensible, but not strictly following the RFC.
1217 **
1218 **  Constraint            Name            RFC 3280  NIST PKITS
1219 ** ------------      ---------------      --------  ----------
1220 **  foo.bar.com          foo.bar.com      matches    matches
1221 **  foo.bar.com          FoO.bAr.CoM      matches    matches
1222 **  foo.bar.com      www.foo.bar.com      matches    matches
1223 **  foo.bar.com        nofoo.bar.com      MATCHES    NO MATCH
1224 ** .foo.bar.com      www.foo.bar.com      matches    matches? disallowed?
1225 ** .foo.bar.com          foo.bar.com      no match   no match
1226 ** .foo.bar.com     www..foo.bar.com      matches    probably not 
1227 **
1228 ** We will try to conform to NIST's PKITS tests, and the unstated 
1229 ** rules they imply.
1230 */
1231 static SECStatus
1232 compareDNSN2C(const SECItem *name, const SECItem *constraint)
1233 {
1234     int offset;
1235     /* The spec is silent on intepreting zero-length constraints.
1236     ** We interpret them as matching all DNSnames.
1237     */
1238     if (!constraint->len)
1239         return SECSuccess;
1240     if (name->len < constraint->len)
1241         return SECFailure;
1242     offset = name->len - constraint->len;
1243     if (PL_strncasecmp((char *)(name->data + offset), 
1244                        (char *)constraint->data, constraint->len))
1245         return SECFailure;
1246     if (!offset || 
1247         (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
1248         return SECSuccess;
1249     return SECFailure;
1250 }
1251
1252 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for
1253 ** internet email addresses.  SECFailure otherwise.
1254 ** If constraint contains a '@' then the two strings much match exactly.
1255 ** Else if constraint starts with a '.'. then it must match the right-most
1256 ** substring of the name, 
1257 ** else constraint string must match entire name after the name's '@'.
1258 ** Empty constraint string matches all names. All comparisons case insensitive.
1259 */
1260 static SECStatus
1261 compareRFC822N2C(const SECItem *name, const SECItem *constraint)
1262 {
1263     int offset;
1264     if (!constraint->len)
1265         return SECSuccess;
1266     if (name->len < constraint->len)
1267         return SECFailure;
1268     if (constraint->len == 1 && constraint->data[0] == '.')
1269         return SECSuccess;
1270     for (offset = constraint->len - 1; offset >= 0; --offset) {
1271         if (constraint->data[offset] == '@') {
1272             return (name->len == constraint->len && 
1273                 !PL_strncasecmp((char *)name->data, 
1274                                 (char *)constraint->data, constraint->len))
1275                 ? SECSuccess : SECFailure;
1276         }
1277     }
1278     offset = name->len - constraint->len;
1279     if (PL_strncasecmp((char *)(name->data + offset), 
1280                        (char *)constraint->data, constraint->len))
1281         return SECFailure;
1282     if (constraint->data[0] == '.')
1283         return SECSuccess;
1284     if (offset > 0 && name->data[offset - 1] == '@')
1285         return SECSuccess;
1286     return SECFailure;
1287 }
1288
1289 /* name contains either a 4 byte IPv4 address or a 16 byte IPv6 address.
1290 ** constraint contains an address of the same length, and a subnet mask
1291 ** of the same length.  Compare name's address to the constraint's 
1292 ** address, subject to the mask.
1293 ** Return SECSuccess if they match, SECFailure if they don't. 
1294 */
1295 static SECStatus
1296 compareIPaddrN2C(const SECItem *name, const SECItem *constraint)
1297 {
1298     int i;
1299     if (name->len == 4 && constraint->len == 8) { /* ipv4 addr */
1300         for (i = 0; i < 4; i++) {
1301             if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+4])
1302                 goto loser;
1303         }
1304         return SECSuccess;
1305     }
1306     if (name->len == 16 && constraint->len == 32) { /* ipv6 addr */
1307         for (i = 0; i < 16; i++) {
1308             if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+16])
1309                 goto loser;
1310         }
1311         return SECSuccess;
1312     }
1313 loser:
1314     return SECFailure;
1315 }
1316
1317 /* start with a SECItem that points to a URI.  Parse it lookingg for 
1318 ** a hostname.  Modify item->data and item->len to define the hostname,
1319 ** but do not modify and data at item->data.  
1320 ** If anything goes wrong, the contents of *item are undefined.
1321 */
1322 static SECStatus
1323 parseUriHostname(SECItem * item)
1324 {
1325     int i;
1326     PRBool found = PR_FALSE;
1327     for (i = 0; (unsigned)(i+2) < item->len; ++i) {
1328         if (item->data[i  ] == ':' &&
1329             item->data[i+1] == '/' &&
1330             item->data[i+2] == '/') {
1331             i += 3;
1332             item->data += i;
1333             item->len  -= i;
1334             found = PR_TRUE;
1335             break;
1336         }
1337     }
1338     if (!found) 
1339         return SECFailure;
1340     /* now look for a '/', which is an upper bound in the end of the name */
1341     for (i = 0; (unsigned)i < item->len; ++i) {
1342         if (item->data[i] == '/') {
1343             item->len = i;
1344             break;
1345         }
1346     }
1347     /* now look for a ':', which marks the end of the name */
1348     for (i = item->len; --i >= 0; ) {
1349         if (item->data[i] == ':') {
1350             item->len = i;
1351             break;
1352         }
1353     }
1354     /* now look for an '@', which marks the beginning of the hostname */
1355     for (i = 0; (unsigned)i < item->len; ++i) {
1356         if (item->data[i] == '@') {
1357             ++i;
1358             item->data += i;
1359             item->len  -= i;
1360             break;
1361         }
1362     }
1363     return item->len ? SECSuccess : SECFailure;
1364 }
1365
1366 /* This function takes one name, and a list of constraints.
1367 ** It searches the constraints looking for a match.
1368 ** It returns SECSuccess if the name satisfies the constraints, i.e.,
1369 ** if excluded, then the name does not match any constraint, 
1370 ** if permitted, then the name matches at least one constraint.
1371 ** It returns SECFailure if the name fails to satisfy the constraints,
1372 ** or if some code fails (e.g. out of memory, or invalid constraint)
1373 */
1374 SECStatus
1375 cert_CompareNameWithConstraints(CERTGeneralName     *name, 
1376                                 CERTNameConstraint  *constraints,
1377                                 PRBool              excluded)
1378 {
1379     SECStatus           rv     = SECSuccess;
1380     SECStatus           matched = SECFailure;
1381     CERTNameConstraint  *current;
1382
1383     PORT_Assert(constraints);  /* caller should not call with NULL */
1384     if (!constraints) {
1385         PORT_SetError(SEC_ERROR_INVALID_ARGS);
1386         return SECFailure;
1387     }
1388
1389     current = constraints;
1390     do {
1391         rv = SECSuccess;
1392         matched = SECFailure;
1393         PORT_Assert(name->type == current->name.type);
1394         switch (name->type) {
1395
1396         case certDNSName:
1397             matched = compareDNSN2C(&name->name.other, 
1398                                     &current->name.name.other);
1399             break;
1400
1401         case certRFC822Name:
1402             matched = compareRFC822N2C(&name->name.other, 
1403                                        &current->name.name.other);
1404             break;
1405
1406         case certURI:
1407             {
1408                 /* make a modifiable copy of the URI SECItem. */
1409                 SECItem uri = name->name.other;
1410                 /* find the hostname in the URI */
1411                 rv = parseUriHostname(&uri);
1412                 if (rv == SECSuccess) {
1413                     /* does our hostname meet the constraint? */
1414                     matched = compareURIN2C(&uri, &current->name.name.other);
1415                 }
1416             }
1417             break;
1418
1419         case certDirectoryName:
1420             /* Determine if the constraint directory name is a "prefix"
1421             ** for the directory name being tested. 
1422             */
1423           {
1424             /* status defaults to SECEqual, so that a constraint with 
1425             ** no AVAs will be a wildcard, matching all directory names.
1426             */
1427             SECComparison   status = SECEqual;
1428             const CERTRDN **cRDNs = 
1429                     (const CERTRDN **)current->name.name.directoryName.rdns;  
1430             const CERTRDN **nRDNs = 
1431                     (const CERTRDN **)name->name.directoryName.rdns;
1432             while (cRDNs && *cRDNs && nRDNs && *nRDNs) { 
1433                 /* loop over name RDNs and constraint RDNs in lock step */
1434                 const CERTRDN *cRDN = *cRDNs++;
1435                 const CERTRDN *nRDN = *nRDNs++;
1436                 CERTAVA **cAVAs = cRDN->avas;
1437                 while (cAVAs && *cAVAs) { /* loop over constraint AVAs */
1438                     CERTAVA *cAVA = *cAVAs++;
1439                     CERTAVA **nAVAs = nRDN->avas;
1440                     while (nAVAs && *nAVAs) { /* loop over name AVAs */
1441                         CERTAVA *nAVA = *nAVAs++;
1442                         status = CERT_CompareAVA(cAVA, nAVA);
1443                         if (status == SECEqual) 
1444                             break;
1445                     } /* loop over name AVAs */
1446                     if (status != SECEqual) 
1447                         break;
1448                 } /* loop over constraint AVAs */
1449                 if (status != SECEqual) 
1450                     break;
1451             } /* loop over name RDNs and constraint RDNs */
1452             matched = (status == SECEqual) ? SECSuccess : SECFailure;
1453             break;
1454           }
1455
1456         case certIPAddress:     /* type 8 */
1457             matched = compareIPaddrN2C(&name->name.other, 
1458                                        &current->name.name.other);
1459             break;
1460
1461         /* NSS does not know how to compare these "Other" type names with 
1462         ** their respective constraints.  But it does know how to tell
1463         ** if the constraint applies to the type of name (by comparing
1464         ** the constraint OID to the name OID).  NSS makes no use of "Other"
1465         ** type names at all, so NSS errs on the side of leniency for these 
1466         ** types, provided that their OIDs match.  So, when an "Other"
1467         ** name constraint appears in an excluded subtree, it never causes
1468         ** a name to fail.  When an "Other" name constraint appears in a
1469         ** permitted subtree, AND the constraint's OID matches the name's
1470         ** OID, then name is treated as if it matches the constraint.
1471         */
1472         case certOtherName:     /* type 1 */
1473             matched = (!excluded &&
1474                        name->type == current->name.type &&
1475                        SECITEM_ItemsAreEqual(&name->name.OthName.oid,
1476                                              &current->name.name.OthName.oid))
1477                  ? SECSuccess : SECFailure;
1478             break;
1479
1480         /* NSS does not know how to compare these types of names with their
1481         ** respective constraints.  But NSS makes no use of these types of 
1482         ** names at all, so it errs on the side of leniency for these types.
1483         ** Constraints for these types of names never cause the name to 
1484         ** fail the constraints test.  NSS behaves as if the name matched
1485         ** for permitted constraints, and did not match for excluded ones.
1486         */
1487         case certX400Address:   /* type 4 */
1488         case certEDIPartyName:  /* type 6 */
1489         case certRegisterID:    /* type 9 */
1490             matched = excluded ? SECFailure : SECSuccess;
1491             break;
1492
1493         default: /* non-standard types are not supported */
1494             rv = SECFailure;
1495             break;
1496         }
1497         if (matched == SECSuccess || rv != SECSuccess)
1498             break;
1499         current = CERT_GetNextNameConstraint(current);
1500     } while (current != constraints);
1501     if (rv == SECSuccess) {
1502         if (matched == SECSuccess) 
1503             rv = excluded ? SECFailure : SECSuccess;
1504         else
1505             rv = excluded ? SECSuccess : SECFailure;
1506         return rv;
1507     }
1508
1509     return SECFailure;
1510 }
1511
1512 /* Add and link a CERTGeneralName to a CERTNameConstraint list. Most
1513 ** likely the CERTNameConstraint passed in is either the permitted
1514 ** list or the excluded list of a CERTNameConstraints.
1515 */
1516 SECStatus
1517 CERT_AddNameConstraintByGeneralName(PLArenaPool *arena,
1518                                     CERTNameConstraint **constraints,
1519                                     CERTGeneralName *name)
1520 {
1521     SECStatus rv;
1522     CERTNameConstraint *current = NULL;
1523     CERTNameConstraint *first = *constraints;
1524     void *mark = NULL;
1525
1526     mark = PORT_ArenaMark(arena);
1527
1528     current = PORT_ArenaZNew(arena, CERTNameConstraint);
1529     if (current == NULL) {
1530         rv = SECFailure;
1531         goto done;
1532     }
1533     
1534     rv = cert_CopyOneGeneralName(arena, &current->name, name);
1535     if (rv != SECSuccess) {
1536         goto done;
1537     }
1538     
1539     current->name.l.prev = current->name.l.next = &(current->name.l);
1540     
1541     if (first == NULL) {
1542         *constraints = current;
1543         PR_INIT_CLIST(&current->l);
1544     } else {
1545         PR_INSERT_BEFORE(&current->l, &first->l);
1546     }
1547
1548 done:
1549     if (rv == SECFailure) {
1550         PORT_ArenaRelease(arena, mark);
1551     } else {
1552         PORT_ArenaUnmark(arena, mark);
1553     }
1554     return rv;
1555 }
1556
1557 /* Extract the name constraints extension from the CA cert. */
1558 SECStatus
1559 CERT_FindNameConstraintsExten(PRArenaPool      *arena,
1560                               CERTCertificate  *cert,
1561                               CERTNameConstraints **constraints)
1562 {
1563     SECStatus            rv = SECSuccess;
1564     SECItem              constraintsExtension;
1565     void                *mark = NULL;
1566     
1567     *constraints = NULL;
1568
1569     rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, 
1570                                 &constraintsExtension);
1571     if (rv != SECSuccess) {
1572         if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
1573             rv = SECSuccess;
1574         }
1575         return rv;
1576     }
1577
1578     mark = PORT_ArenaMark(arena);
1579
1580     *constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
1581     if (*constraints == NULL) { /* decode failed */
1582         rv = SECFailure;
1583     }
1584     PORT_Free (constraintsExtension.data);
1585
1586     if (rv == SECFailure) {
1587         PORT_ArenaRelease(arena, mark);
1588     } else {
1589         PORT_ArenaUnmark(arena, mark);
1590     }
1591
1592     return rv;
1593 }
1594
1595 /* Verify name against all the constraints relevant to that type of
1596 ** the name.
1597 */
1598 SECStatus
1599 CERT_CheckNameSpace(PRArenaPool          *arena,
1600                     CERTNameConstraints  *constraints,
1601                     CERTGeneralName      *currentName)
1602 {
1603     CERTNameConstraint  *matchingConstraints;
1604     SECStatus            rv = SECSuccess;
1605     
1606     if (constraints->excluded != NULL) {
1607         rv = CERT_GetNameConstraintByType(constraints->excluded, 
1608                                           currentName->type, 
1609                                           &matchingConstraints, arena);
1610         if (rv == SECSuccess && matchingConstraints != NULL) {
1611             rv = cert_CompareNameWithConstraints(currentName, 
1612                                                  matchingConstraints,
1613                                                  PR_TRUE);
1614         }
1615         if (rv != SECSuccess) {
1616             return(rv);
1617         }
1618     }
1619     
1620     if (constraints->permited != NULL) {
1621         rv = CERT_GetNameConstraintByType(constraints->permited, 
1622                                           currentName->type, 
1623                                           &matchingConstraints, arena);
1624         if (rv == SECSuccess && matchingConstraints != NULL) {
1625             rv = cert_CompareNameWithConstraints(currentName, 
1626                                                  matchingConstraints,
1627                                                  PR_FALSE);
1628         }
1629         if (rv != SECSuccess) {
1630             return(rv);
1631         }
1632     }
1633
1634     return(SECSuccess);
1635 }
1636
1637 /* Extract the name constraints extension from the CA cert.
1638 ** Test each and every name in namesList against all the constraints
1639 ** relevant to that type of name.
1640 ** Returns NULL in pBadCert for success, if all names are acceptable.
1641 ** If some name is not acceptable, returns a pointer to the cert that
1642 ** contained that name.
1643 */
1644 SECStatus
1645 CERT_CompareNameSpace(CERTCertificate  *cert,
1646                       CERTGeneralName  *namesList,
1647                       CERTCertificate **certsList,
1648                       PRArenaPool      *reqArena,
1649                       CERTCertificate **pBadCert)
1650 {
1651     SECStatus            rv = SECSuccess;
1652     CERTNameConstraints  *constraints;
1653     CERTGeneralName      *currentName;
1654     int                  count = 0;
1655     CERTCertificate      *badCert = NULL;
1656
1657     /* If no names to check, then no names can be bad. */
1658     if (!namesList)
1659         goto done;
1660     rv = CERT_FindNameConstraintsExten(reqArena, cert, &constraints);
1661     if (rv != SECSuccess) {
1662         count = -1;
1663         goto done;
1664     }
1665
1666     currentName = namesList;
1667     do {
1668         if (constraints){
1669             rv = CERT_CheckNameSpace(reqArena, constraints, currentName);
1670             if (rv != SECSuccess) {
1671                 break;
1672             }
1673         }
1674         currentName = CERT_GetNextGeneralName(currentName);
1675         count ++;
1676     } while (currentName != namesList);
1677
1678 done:
1679     if (rv != SECSuccess) {
1680         badCert = (count >= 0) ? certsList[count] : cert;
1681     }
1682     if (pBadCert)
1683         *pBadCert = badCert;
1684
1685     return rv;
1686 }
1687
1688 #if 0
1689 /* not exported from shared libs, not used.  Turn on if we ever need it. */
1690 SECStatus
1691 CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b)
1692 {
1693     CERTGeneralName *currentA;
1694     CERTGeneralName *currentB;
1695     PRBool found;
1696
1697     currentA = a;
1698     currentB = b;
1699     if (a != NULL) {
1700         do { 
1701             if (currentB == NULL) {
1702                 return SECFailure;
1703             }
1704             currentB = CERT_GetNextGeneralName(currentB);
1705             currentA = CERT_GetNextGeneralName(currentA);
1706         } while (currentA != a);
1707     }
1708     if (currentB != b) {
1709         return SECFailure;
1710     }
1711     currentA = a;
1712     do {
1713         currentB = b;
1714         found = PR_FALSE;
1715         do {
1716             if (currentB->type == currentA->type) {
1717                 switch (currentB->type) {
1718                   case certDNSName:
1719                   case certEDIPartyName:
1720                   case certIPAddress:
1721                   case certRegisterID:
1722                   case certRFC822Name:
1723                   case certX400Address:
1724                   case certURI:
1725                     if (SECITEM_CompareItem(&currentA->name.other,
1726                                             &currentB->name.other) 
1727                         == SECEqual) {
1728                         found = PR_TRUE;
1729                     }
1730                     break;
1731                   case certOtherName:
1732                     if (SECITEM_CompareItem(&currentA->name.OthName.oid,
1733                                             &currentB->name.OthName.oid) 
1734                         == SECEqual &&
1735                         SECITEM_CompareItem(&currentA->name.OthName.name,
1736                                             &currentB->name.OthName.name)
1737                         == SECEqual) {
1738                         found = PR_TRUE;
1739                     }
1740                     break;
1741                   case certDirectoryName:
1742                     if (CERT_CompareName(&currentA->name.directoryName,
1743                                          &currentB->name.directoryName)
1744                         == SECEqual) {
1745                         found = PR_TRUE;
1746                     }
1747                 }
1748                     
1749             }
1750             currentB = CERT_GetNextGeneralName(currentB);
1751         } while (currentB != b && found != PR_TRUE);
1752         if (found != PR_TRUE) {
1753             return SECFailure;
1754         }
1755         currentA = CERT_GetNextGeneralName(currentA);
1756     } while (currentA != a);
1757     return SECSuccess;
1758 }
1759
1760 SECStatus
1761 CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b)
1762 {
1763     SECStatus rv;
1764
1765     if (a == b) {
1766         return SECSuccess;
1767     }
1768     if (a != NULL && b != NULL) {
1769         PZ_Lock(a->lock);
1770         PZ_Lock(b->lock);
1771         rv = CERT_CompareGeneralName(a->name, b->name);
1772         PZ_Unlock(a->lock);
1773         PZ_Unlock(b->lock);
1774     } else {
1775         rv = SECFailure;
1776     }
1777     return rv;
1778 }
1779 #endif
1780
1781 #if 0
1782 /* This function is not exported from NSS shared libraries, and is not
1783 ** used inside of NSS.
1784 ** XXX it doesn't check for failed allocations. :-(
1785 */
1786 void *
1787 CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
1788                                   CERTGeneralNameType type,
1789                                   PRArenaPool *arena)
1790 {
1791     CERTName *name = NULL; 
1792     SECItem *item = NULL;
1793     OtherName *other = NULL;
1794     OtherName *tmpOther = NULL;
1795     void *data;
1796
1797     PZ_Lock(list->lock);
1798     data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE);
1799     if (data != NULL) {
1800         switch (type) {
1801           case certDNSName:
1802           case certEDIPartyName:
1803           case certIPAddress:
1804           case certRegisterID:
1805           case certRFC822Name:
1806           case certX400Address:
1807           case certURI:
1808             if (arena != NULL) {
1809                 item = PORT_ArenaNew(arena, SECItem);
1810                 if (item != NULL) {
1811 XXX                 SECITEM_CopyItem(arena, item, (SECItem *) data);
1812                 }
1813             } else { 
1814                 item = SECITEM_DupItem((SECItem *) data);
1815             }
1816             PZ_Unlock(list->lock);
1817             return item;
1818           case certOtherName:
1819             other = (OtherName *) data;
1820             if (arena != NULL) {
1821                 tmpOther = PORT_ArenaNew(arena, OtherName);
1822             } else {
1823                 tmpOther = PORT_New(OtherName);
1824             }
1825             if (tmpOther != NULL) {
1826 XXX             SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
1827 XXX             SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
1828             }
1829             PZ_Unlock(list->lock);
1830             return tmpOther;
1831           case certDirectoryName:
1832             if (arena) {
1833                 name = PORT_ArenaZNew(list->arena, CERTName);
1834                 if (name) {
1835 XXX                 CERT_CopyName(arena, name, (CERTName *) data);
1836                 }
1837             }
1838             PZ_Unlock(list->lock);
1839             return name;
1840         }
1841     }
1842     PZ_Unlock(list->lock);
1843     return NULL;
1844 }
1845 #endif
1846
1847 #if 0
1848 /* This function is not exported from NSS shared libraries, and is not
1849 ** used inside of NSS.
1850 ** XXX it should NOT be a void function, since it does allocations
1851 ** that can fail.
1852 */
1853 void
1854 CERT_AddGeneralNameToList(CERTGeneralNameList *list, 
1855                           CERTGeneralNameType type,
1856                           void *data, SECItem *oid)
1857 {
1858     CERTGeneralName *name;
1859
1860     if (list != NULL && data != NULL) {
1861         PZ_Lock(list->lock);
1862         name = CERT_NewGeneralName(list->arena, type);
1863         if (!name)
1864             goto done;
1865         switch (type) {
1866           case certDNSName:
1867           case certEDIPartyName:
1868           case certIPAddress:
1869           case certRegisterID:
1870           case certRFC822Name:
1871           case certX400Address:
1872           case certURI:
1873 XXX         SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
1874             break;
1875           case certOtherName:
1876 XXX         SECITEM_CopyItem(list->arena, &name->name.OthName.name,
1877                              (SECItem *) data);
1878 XXX         SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
1879                              oid);
1880             break;
1881           case certDirectoryName:
1882 XXX         CERT_CopyName(list->arena, &name->name.directoryName,
1883                           (CERTName *) data);
1884             break;
1885         }
1886         list->name = cert_CombineNamesLists(list->name, name);
1887         list->len++;
1888 done:
1889         PZ_Unlock(list->lock);
1890     }
1891     return;
1892 }
1893 #endif