Back to index

lightning-sunbird  0.9+nobinonly
genname.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #include "plarena.h"
00038 #include "seccomon.h"
00039 #include "secitem.h"
00040 #include "secoidt.h"
00041 #include "mcom_db.h"
00042 #include "secasn1.h"
00043 #include "secder.h"
00044 #include "certt.h"
00045 #include "cert.h"
00046 #include "xconst.h"
00047 #include "secerr.h"
00048 #include "secoid.h"
00049 #include "prprf.h"
00050 #include "genname.h"
00051 
00052 
00053 
00054 static const SEC_ASN1Template CERTNameConstraintTemplate[] = {
00055     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraint) },
00056     { SEC_ASN1_ANY, offsetof(CERTNameConstraint, DERName) },
00057     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, 
00058           offsetof(CERTNameConstraint, min), SEC_IntegerTemplate }, 
00059     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1, 
00060           offsetof(CERTNameConstraint, max), SEC_IntegerTemplate },
00061     { 0, }
00062 };
00063 
00064 const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = {
00065     { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
00066 };
00067 
00068 
00069 const SEC_ASN1Template CERT_NameConstraintSubtreePermitedTemplate[] = {
00070     { SEC_ASN1_CONTEXT_SPECIFIC | 0, 0, CERT_NameConstraintSubtreeSubTemplate }
00071 };
00072 
00073 const SEC_ASN1Template CERT_NameConstraintSubtreeExcludedTemplate[] = {
00074     { SEC_ASN1_CONTEXT_SPECIFIC | 1, 0, CERT_NameConstraintSubtreeSubTemplate }
00075 };
00076 
00077 
00078 static const SEC_ASN1Template CERTNameConstraintsTemplate[] = {
00079     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraints) },
00080     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, 
00081           offsetof(CERTNameConstraints, DERPermited), 
00082          CERT_NameConstraintSubtreeSubTemplate},
00083     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 1, 
00084           offsetof(CERTNameConstraints, DERExcluded), 
00085          CERT_NameConstraintSubtreeSubTemplate},
00086     { 0, }
00087 };
00088 
00089 
00090 static const SEC_ASN1Template CERTOthNameTemplate[] = {
00091     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OtherName) },
00092     { SEC_ASN1_OBJECT_ID, 
00093          offsetof(OtherName, oid) },
00094     { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0,
00095           offsetof(OtherName, name), SEC_AnyTemplate },
00096     { 0, } 
00097 };
00098 
00099 static const SEC_ASN1Template CERTOtherNameTemplate[] = {
00100     { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0 ,
00101       offsetof(CERTGeneralName, name.OthName), CERTOthNameTemplate, 
00102       sizeof(CERTGeneralName) }
00103 };
00104 
00105 static const SEC_ASN1Template CERTOtherName2Template[] = {
00106     { SEC_ASN1_SEQUENCE | SEC_ASN1_CONTEXT_SPECIFIC | 0 ,
00107       0, NULL, sizeof(CERTGeneralName) },
00108     { SEC_ASN1_OBJECT_ID,
00109          offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, oid) },
00110     { SEC_ASN1_ANY,
00111          offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, name) },
00112     { 0, } 
00113 };
00114 
00115 static const SEC_ASN1Template CERT_RFC822NameTemplate[] = {
00116     { SEC_ASN1_CONTEXT_SPECIFIC | 1 ,
00117           offsetof(CERTGeneralName, name.other), SEC_IA5StringTemplate,
00118           sizeof (CERTGeneralName)}
00119 };
00120 
00121 static const SEC_ASN1Template CERT_DNSNameTemplate[] = {
00122     { SEC_ASN1_CONTEXT_SPECIFIC | 2 ,
00123           offsetof(CERTGeneralName, name.other), SEC_IA5StringTemplate,
00124           sizeof (CERTGeneralName)}
00125 };
00126 
00127 static const SEC_ASN1Template CERT_X400AddressTemplate[] = {
00128     { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 3,
00129           offsetof(CERTGeneralName, name.other), SEC_AnyTemplate,
00130           sizeof (CERTGeneralName)}
00131 };
00132 
00133 static const SEC_ASN1Template CERT_DirectoryNameTemplate[] = {
00134     { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 4,
00135           offsetof(CERTGeneralName, derDirectoryName), SEC_AnyTemplate,
00136           sizeof (CERTGeneralName)}
00137 };
00138 
00139 
00140 static const SEC_ASN1Template CERT_EDIPartyNameTemplate[] = {
00141     { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 5,
00142           offsetof(CERTGeneralName, name.other), SEC_AnyTemplate,
00143           sizeof (CERTGeneralName)}
00144 };
00145 
00146 static const SEC_ASN1Template CERT_URITemplate[] = {
00147     { SEC_ASN1_CONTEXT_SPECIFIC | 6 ,
00148           offsetof(CERTGeneralName, name.other), SEC_IA5StringTemplate,
00149           sizeof (CERTGeneralName)}
00150 };
00151 
00152 static const SEC_ASN1Template CERT_IPAddressTemplate[] = {
00153     { SEC_ASN1_CONTEXT_SPECIFIC | 7 ,
00154           offsetof(CERTGeneralName, name.other), SEC_OctetStringTemplate,
00155           sizeof (CERTGeneralName)}
00156 };
00157 
00158 static const SEC_ASN1Template CERT_RegisteredIDTemplate[] = {
00159     { SEC_ASN1_CONTEXT_SPECIFIC | 8 ,
00160           offsetof(CERTGeneralName, name.other), SEC_ObjectIDTemplate,
00161           sizeof (CERTGeneralName)}
00162 };
00163 
00164 
00165 const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
00166     { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
00167 };
00168 
00169 
00170 
00171 CERTGeneralName *
00172 cert_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type)
00173 {
00174     CERTGeneralName *name = arena 
00175                             ? PORT_ArenaZNew(arena, CERTGeneralName)
00176                            : PORT_ZNew(CERTGeneralName);
00177     if (name) {
00178        name->type = type;
00179        name->l.prev = name->l.next = &name->l;
00180     }
00181     return name;
00182 }
00183 
00184 /* Copy content of one General Name to another.
00185 ** Caller has allocated destination general name.
00186 ** This function does not change the destinate's GeneralName's list linkage.
00187 */
00188 SECStatus
00189 cert_CopyOneGeneralName(PRArenaPool      *arena, 
00190                       CERTGeneralName  *dest, 
00191                       CERTGeneralName  *src)
00192 {
00193     SECStatus rv;
00194 
00195     /* TODO: mark arena */
00196     PORT_Assert(dest != NULL);
00197     dest->type = src->type;
00198 
00199     switch (src->type) {
00200     case certDirectoryName: 
00201        rv = SECITEM_CopyItem(arena, &dest->derDirectoryName, 
00202                                   &src->derDirectoryName);
00203        if (rv == SECSuccess) 
00204            rv = CERT_CopyName(arena, &dest->name.directoryName, 
00205                                    &src->name.directoryName);
00206        break;
00207 
00208     case certOtherName: 
00209        rv = SECITEM_CopyItem(arena, &dest->name.OthName.name, 
00210                                   &src->name.OthName.name);
00211        if (rv == SECSuccess) 
00212            rv = SECITEM_CopyItem(arena, &dest->name.OthName.oid, 
00213                                      &src->name.OthName.oid);
00214        break;
00215 
00216     default: 
00217        rv = SECITEM_CopyItem(arena, &dest->name.other, 
00218                                   &src->name.other);
00219        break;
00220 
00221     }
00222     if (rv != SECSuccess) {
00223        /* TODO: release back to mark */
00224     } else {
00225        /* TODO: unmark arena */
00226     }
00227     return rv;
00228 }
00229 
00230 
00231 void
00232 CERT_DestroyGeneralNameList(CERTGeneralNameList *list)
00233 {
00234     PZLock *lock;
00235 
00236     if (list != NULL) {
00237        lock = list->lock;
00238        PZ_Lock(lock);
00239        if (--list->refCount <= 0 && list->arena != NULL) {
00240            PORT_FreeArena(list->arena, PR_FALSE);
00241            PZ_Unlock(lock);
00242            PZ_DestroyLock(lock);
00243        } else {
00244            PZ_Unlock(lock);
00245        }
00246     }
00247     return;
00248 }
00249 
00250 CERTGeneralNameList *
00251 CERT_CreateGeneralNameList(CERTGeneralName *name) {
00252     PRArenaPool *arena;
00253     CERTGeneralNameList *list = NULL;
00254 
00255     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00256     if (arena == NULL) {
00257        goto done;
00258     }
00259     list = PORT_ArenaZNew(arena, CERTGeneralNameList);
00260     if (!list)
00261        goto loser;
00262     if (name != NULL) {
00263        SECStatus rv;
00264        list->name = cert_NewGeneralName(arena, (CERTGeneralNameType)0);
00265        if (!list->name)
00266            goto loser;
00267        rv = CERT_CopyGeneralName(arena, list->name, name);
00268        if (rv != SECSuccess)
00269            goto loser;
00270     }
00271     list->lock = PZ_NewLock(nssILockList);
00272     if (!list->lock)
00273        goto loser;
00274     list->arena = arena;
00275     list->refCount = 1;
00276 done:
00277     return list;
00278 
00279 loser:
00280     PORT_FreeArena(arena, PR_FALSE);
00281     return NULL;
00282 }
00283 
00284 CERTGeneralName *
00285 CERT_GetNextGeneralName(CERTGeneralName *current)
00286 {
00287     PRCList *next;
00288     
00289     next = current->l.next;
00290     return (CERTGeneralName *) (((char *) next) - offsetof(CERTGeneralName, l));
00291 }
00292 
00293 CERTGeneralName *
00294 CERT_GetPrevGeneralName(CERTGeneralName *current)
00295 {
00296     PRCList *prev;
00297     prev = current->l.prev;
00298     return (CERTGeneralName *) (((char *) prev) - offsetof(CERTGeneralName, l));
00299 }
00300 
00301 CERTNameConstraint *
00302 CERT_GetNextNameConstraint(CERTNameConstraint *current)
00303 {
00304     PRCList *next;
00305     
00306     next = current->l.next;
00307     return (CERTNameConstraint *) (((char *) next) - offsetof(CERTNameConstraint, l));
00308 }
00309 
00310 CERTNameConstraint *
00311 CERT_GetPrevNameConstraint(CERTNameConstraint *current)
00312 {
00313     PRCList *prev;
00314     prev = current->l.prev;
00315     return (CERTNameConstraint *) (((char *) prev) - offsetof(CERTNameConstraint, l));
00316 }
00317 
00318 SECItem *
00319 CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest, PRArenaPool *arena)
00320 {
00321 
00322     const SEC_ASN1Template * template;
00323 
00324     PORT_Assert(arena);
00325     if (arena == NULL) {
00326        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00327        return NULL;
00328     }
00329     /* TODO: mark arena */
00330     if (dest == NULL) {
00331        dest = PORT_ArenaZNew(arena, SECItem);
00332        if (!dest)
00333            goto loser;
00334     }
00335     if (genName->type == certDirectoryName) {
00336        if (genName->derDirectoryName.data == NULL) {
00337            /* The field hasn't been encoded yet. */
00338             SECItem * pre_dest =
00339             SEC_ASN1EncodeItem (arena, &(genName->derDirectoryName),
00340                                 &(genName->name.directoryName),
00341                                 CERT_NameTemplate);
00342             if (!pre_dest)
00343                 goto loser;
00344        }
00345        if (genName->derDirectoryName.data == NULL) {
00346            goto loser;
00347        }
00348     }
00349     switch (genName->type) {
00350     case certURI:           template = CERT_URITemplate;           break;
00351     case certRFC822Name:    template = CERT_RFC822NameTemplate;    break;
00352     case certDNSName:       template = CERT_DNSNameTemplate;       break;
00353     case certIPAddress:     template = CERT_IPAddressTemplate;     break;
00354     case certOtherName:     template = CERTOtherNameTemplate;      break;
00355     case certRegisterID:    template = CERT_RegisteredIDTemplate;  break;
00356          /* for this type, we expect the value is already encoded */
00357     case certEDIPartyName:  template = CERT_EDIPartyNameTemplate;  break;
00358         /* for this type, we expect the value is already encoded */
00359     case certX400Address:   template = CERT_X400AddressTemplate;   break;
00360     case certDirectoryName: template = CERT_DirectoryNameTemplate; break;
00361     default:
00362        PORT_Assert(0); goto loser;
00363     }
00364     dest = SEC_ASN1EncodeItem(arena, dest, genName, template);
00365     if (!dest) {
00366        goto loser;
00367     }
00368     /* TODO: unmark arena */
00369     return dest;
00370 loser:
00371     /* TODO: release arena back to mark */
00372     return NULL;
00373 }
00374 
00375 SECItem **
00376 cert_EncodeGeneralNames(PRArenaPool *arena, CERTGeneralName *names)
00377 {
00378     CERTGeneralName  *current_name;
00379     SECItem          **items = NULL;
00380     int              count = 0;
00381     int              i;
00382     PRCList          *head;
00383 
00384     PORT_Assert(arena);
00385     /* TODO: mark arena */
00386     current_name = names;
00387     if (names != NULL) {
00388        count = 1;
00389     }
00390     head = &(names->l);
00391     while (current_name->l.next != head) {
00392        current_name = CERT_GetNextGeneralName(current_name);
00393        ++count;
00394     }
00395     current_name = CERT_GetNextGeneralName(current_name);
00396     items = PORT_ArenaNewArray(arena, SECItem *, count + 1);
00397     if (items == NULL) {
00398        goto loser;
00399     }
00400     for (i = 0; i < count; i++) {
00401        items[i] = CERT_EncodeGeneralName(current_name, (SECItem *)NULL, arena);
00402        if (items[i] == NULL) {
00403            goto loser;
00404        }
00405        current_name = CERT_GetNextGeneralName(current_name);
00406     }
00407     items[i] = NULL;
00408     /* TODO: unmark arena */
00409     return items;
00410 loser:
00411     /* TODO: release arena to mark */
00412     return NULL;
00413 }
00414 
00415 CERTGeneralName *
00416 CERT_DecodeGeneralName(PRArenaPool      *arena,
00417                      SECItem          *encodedName,
00418                      CERTGeneralName  *genName)
00419 {
00420     const SEC_ASN1Template *         template;
00421     CERTGeneralNameType              genNameType;
00422     SECStatus                        rv = SECSuccess;
00423 
00424     PORT_Assert(arena);
00425     /* TODO: mark arena */
00426     genNameType = (CERTGeneralNameType)((*(encodedName->data) & 0x0f) + 1);
00427     if (genName == NULL) {
00428        genName = cert_NewGeneralName(arena, genNameType);
00429        if (!genName)
00430            goto loser;
00431     } else {
00432        genName->type = genNameType;
00433        genName->l.prev = genName->l.next = &genName->l;
00434     }
00435     switch (genNameType) {
00436     case certURI:           template = CERT_URITemplate;           break;
00437     case certRFC822Name:    template = CERT_RFC822NameTemplate;    break;
00438     case certDNSName:              template = CERT_DNSNameTemplate;       break;
00439     case certIPAddress:     template = CERT_IPAddressTemplate;     break;
00440     case certOtherName:     template = CERTOtherNameTemplate;      break;
00441     case certRegisterID:    template = CERT_RegisteredIDTemplate;  break;
00442     case certEDIPartyName:  template = CERT_EDIPartyNameTemplate;  break;
00443     case certX400Address:   template = CERT_X400AddressTemplate;   break;
00444     case certDirectoryName:        template = CERT_DirectoryNameTemplate; break;
00445     default: 
00446         goto loser;
00447     }
00448     rv = SEC_ASN1DecodeItem(arena, genName, template, encodedName);
00449     if (rv != SECSuccess) 
00450        goto loser;
00451     if (genNameType == certDirectoryName) {
00452        rv = SEC_ASN1DecodeItem(arena, &(genName->name.directoryName), 
00453                             CERT_NameTemplate, 
00454                             &(genName->derDirectoryName));
00455         if (rv != SECSuccess)
00456            goto loser;
00457     }
00458 
00459     /* TODO: unmark arena */
00460     return genName;
00461 loser:
00462     /* TODO: release arena to mark */
00463     return NULL;
00464 }
00465 
00466 CERTGeneralName *
00467 cert_DecodeGeneralNames (PRArenaPool  *arena,
00468                       SECItem      **encodedGenName)
00469 {
00470     PRCList                           *head = NULL;
00471     PRCList                           *tail = NULL;
00472     CERTGeneralName                   *currentName = NULL;
00473 
00474     PORT_Assert(arena);
00475     if (!encodedGenName || !arena) {
00476        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00477        return NULL;
00478     }
00479     /* TODO: mark arena */
00480     while (*encodedGenName != NULL) {
00481        currentName = CERT_DecodeGeneralName(arena, *encodedGenName, NULL);
00482        if (currentName == NULL)
00483            break;
00484        if (head == NULL) {
00485            head = &(currentName->l);
00486            tail = head;
00487        }
00488        currentName->l.next = head;
00489        currentName->l.prev = tail;
00490        tail = head->prev = tail->next = &(currentName->l);
00491        encodedGenName++;
00492     }
00493     if (currentName) {
00494        /* TODO: unmark arena */
00495        return CERT_GetNextGeneralName(currentName);
00496     }
00497     /* TODO: release arena to mark */
00498     return NULL;
00499 }
00500 
00501 void
00502 CERT_DestroyGeneralName(CERTGeneralName *name)
00503 {
00504     cert_DestroyGeneralNames(name);
00505 }
00506 
00507 SECStatus
00508 cert_DestroyGeneralNames(CERTGeneralName *name)
00509 {
00510     CERTGeneralName    *first;
00511     CERTGeneralName    *next = NULL;
00512 
00513 
00514     first = name;
00515     do {
00516        next = CERT_GetNextGeneralName(name);
00517        PORT_Free(name);
00518        name = next;
00519     } while (name != first);
00520     return SECSuccess;
00521 }
00522 
00523 static SECItem *
00524 cert_EncodeNameConstraint(CERTNameConstraint  *constraint, 
00525                       SECItem             *dest,
00526                       PRArenaPool         *arena)
00527 {
00528     PORT_Assert(arena);
00529     if (dest == NULL) {
00530        dest = PORT_ArenaZNew(arena, SECItem);
00531        if (dest == NULL) {
00532            return NULL;
00533        }
00534     }
00535     CERT_EncodeGeneralName(&(constraint->name), &(constraint->DERName), arena);
00536     
00537     dest = SEC_ASN1EncodeItem (arena, dest, constraint,
00538                             CERTNameConstraintTemplate);
00539     return dest;
00540 } 
00541 
00542 SECStatus 
00543 cert_EncodeNameConstraintSubTree(CERTNameConstraint  *constraints,
00544                               PRArenaPool         *arena,
00545                              SECItem             ***dest,
00546                              PRBool              permited)
00547 {
00548     CERTNameConstraint  *current_constraint = constraints;
00549     SECItem             **items = NULL;
00550     int                 count = 0;
00551     int                 i;
00552     PRCList             *head;
00553 
00554     PORT_Assert(arena);
00555     /* TODO: mark arena */
00556     if (constraints != NULL) {
00557        count = 1;
00558     }
00559     head = &constraints->l;
00560     while (current_constraint->l.next != head) {
00561        current_constraint = CERT_GetNextNameConstraint(current_constraint);
00562        ++count;
00563     }
00564     current_constraint = CERT_GetNextNameConstraint(current_constraint);
00565     items = PORT_ArenaZNewArray(arena, SECItem *, count + 1);
00566     if (items == NULL) {
00567        goto loser;
00568     }
00569     for (i = 0; i < count; i++) {
00570        items[i] = cert_EncodeNameConstraint(current_constraint, 
00571                                         (SECItem *) NULL, arena);
00572        if (items[i] == NULL) {
00573            goto loser;
00574        }
00575        current_constraint = CERT_GetNextNameConstraint(current_constraint);
00576     }
00577     *dest = items;
00578     if (*dest == NULL) {
00579        goto loser;
00580     }
00581     /* TODO: unmark arena */
00582     return SECSuccess;
00583 loser:
00584     /* TODO: release arena to mark */
00585     return SECFailure;
00586 }
00587 
00588 SECStatus 
00589 cert_EncodeNameConstraints(CERTNameConstraints  *constraints,
00590                         PRArenaPool          *arena,
00591                         SECItem              *dest)
00592 {
00593     SECStatus    rv = SECSuccess;
00594 
00595     PORT_Assert(arena);
00596     /* TODO: mark arena */
00597     if (constraints->permited != NULL) {
00598        rv = cert_EncodeNameConstraintSubTree(constraints->permited, arena,
00599                                          &constraints->DERPermited, 
00600                                          PR_TRUE);
00601        if (rv == SECFailure) {
00602            goto loser;
00603        }
00604     }
00605     if (constraints->excluded != NULL) {
00606        rv = cert_EncodeNameConstraintSubTree(constraints->excluded, arena,
00607                                          &constraints->DERExcluded, 
00608                                          PR_FALSE);
00609        if (rv == SECFailure) {
00610            goto loser;
00611        }
00612     }
00613     dest = SEC_ASN1EncodeItem(arena, dest, constraints, 
00614                            CERTNameConstraintsTemplate);
00615     if (dest == NULL) {
00616        goto loser;
00617     }
00618     /* TODO: unmark arena */
00619     return SECSuccess;
00620 loser:
00621     /* TODO: release arena to mark */
00622     return SECFailure;
00623 }
00624 
00625 
00626 CERTNameConstraint *
00627 cert_DecodeNameConstraint(PRArenaPool       *arena,
00628                        SECItem           *encodedConstraint)
00629 {
00630     CERTNameConstraint     *constraint;
00631     SECStatus              rv = SECSuccess;
00632     CERTGeneralName        *temp;
00633 
00634     PORT_Assert(arena);
00635     /* TODO: mark arena */
00636     constraint = PORT_ArenaZNew(arena, CERTNameConstraint);
00637     if (!constraint)
00638        goto loser;
00639     rv = SEC_ASN1DecodeItem(arena, constraint, CERTNameConstraintTemplate, 
00640                             encodedConstraint);
00641     if (rv != SECSuccess) {
00642        goto loser;
00643     }
00644     temp = CERT_DecodeGeneralName(arena, &(constraint->DERName), 
00645                                          &(constraint->name));
00646     if (temp != &(constraint->name)) {
00647        goto loser;
00648     }
00649 
00650     /* ### sjlee: since the name constraint contains only one 
00651      *            CERTGeneralName, the list within CERTGeneralName shouldn't 
00652      *            point anywhere else.  Otherwise, bad things will happen.
00653      */
00654     constraint->name.l.prev = constraint->name.l.next = &(constraint->name.l);
00655     /* TODO: unmark arena */
00656     return constraint;
00657 loser:
00658     /* TODO: release arena back to mark */
00659     return NULL;
00660 }
00661 
00662 CERTNameConstraint *
00663 cert_DecodeNameConstraintSubTree(PRArenaPool   *arena,
00664                              SECItem       **subTree,
00665                              PRBool        permited)
00666 {
00667     CERTNameConstraint   *current = NULL;
00668     CERTNameConstraint   *first = NULL;
00669     CERTNameConstraint   *last = NULL;
00670     int                  i = 0;
00671 
00672     PORT_Assert(arena);
00673     /* TODO: mark arena */
00674     while (subTree[i] != NULL) {
00675        current = cert_DecodeNameConstraint(arena, subTree[i]);
00676        if (current == NULL) {
00677            goto loser;
00678        }
00679        if (last == NULL) {
00680            first = last = current;
00681        }
00682        current->l.prev = &(last->l);
00683        current->l.next = last->l.next;
00684        last->l.next = &(current->l);
00685        i++;
00686     }
00687     first->l.prev = &(current->l);
00688     /* TODO: unmark arena */
00689     return first;
00690 loser:
00691     /* TODO: release arena back to mark */
00692     return NULL;
00693 }
00694 
00695 CERTNameConstraints *
00696 cert_DecodeNameConstraints(PRArenaPool   *arena,
00697                         SECItem       *encodedConstraints)
00698 {
00699     CERTNameConstraints   *constraints;
00700     SECStatus             rv;
00701 
00702     PORT_Assert(arena);
00703     PORT_Assert(encodedConstraints);
00704     /* TODO: mark arena */
00705     constraints = PORT_ArenaZNew(arena, CERTNameConstraints);
00706     if (constraints == NULL) {
00707        goto loser;
00708     }
00709     rv = SEC_ASN1DecodeItem(arena, constraints, CERTNameConstraintsTemplate, 
00710                          encodedConstraints);
00711     if (rv != SECSuccess) {
00712        goto loser;
00713     }
00714     if (constraints->DERPermited != NULL && 
00715         constraints->DERPermited[0] != NULL) {
00716        constraints->permited = 
00717            cert_DecodeNameConstraintSubTree(arena, constraints->DERPermited,
00718                                         PR_TRUE);
00719        if (constraints->permited == NULL) {
00720            goto loser;
00721        }
00722     }
00723     if (constraints->DERExcluded != NULL && 
00724         constraints->DERExcluded[0] != NULL) {
00725        constraints->excluded = 
00726            cert_DecodeNameConstraintSubTree(arena, constraints->DERExcluded,
00727                                         PR_FALSE);
00728        if (constraints->excluded == NULL) {
00729            goto loser;
00730        }
00731     }
00732     /* TODO: unmark arena */
00733     return constraints;
00734 loser:
00735     /* TODO: release arena back to mark */
00736     return NULL;
00737 }
00738 
00739 /* Copy a chain of one or more general names to a destination chain.
00740 ** Caller has allocated at least the first destination GeneralName struct. 
00741 ** Both source and destination chains are circular doubly-linked lists.
00742 ** The first source struct is copied to the first destination struct.
00743 ** If the source chain has more than one member, and the destination chain 
00744 ** has only one member, then this function allocates new structs for all but 
00745 ** the first copy from the arena and links them into the destination list.  
00746 ** If the destination struct is part of a list with more than one member,
00747 ** then this function traverses both the source and destination lists,
00748 ** copying each source struct to the corresponding dest struct.
00749 ** In that case, the destination list MUST contain at least as many 
00750 ** structs as the source list or some dest entries will be overwritten.
00751 */
00752 SECStatus
00753 CERT_CopyGeneralName(PRArenaPool      *arena, 
00754                    CERTGeneralName  *dest, 
00755                    CERTGeneralName  *src)
00756 {
00757     SECStatus rv;
00758     CERTGeneralName *destHead = dest;
00759     CERTGeneralName *srcHead = src;
00760 
00761     PORT_Assert(dest != NULL);
00762     if (!dest) {
00763        PORT_SetError(SEC_ERROR_INVALID_ARGS);
00764         return SECFailure;
00765     }
00766     /* TODO: mark arena */
00767     do {
00768        rv = cert_CopyOneGeneralName(arena, dest, src);
00769        if (rv != SECSuccess)
00770            goto loser;
00771        src = CERT_GetNextGeneralName(src);
00772        /* if there is only one general name, we shouldn't do this */
00773        if (src != srcHead) {
00774            if (dest->l.next == &destHead->l) {
00775               CERTGeneralName *temp;
00776               temp = cert_NewGeneralName(arena, (CERTGeneralNameType)0);
00777               if (!temp) 
00778                   goto loser;
00779               temp->l.next = &destHead->l;
00780               temp->l.prev = &dest->l;
00781               destHead->l.prev = &temp->l;
00782               dest->l.next = &temp->l;
00783               dest = temp;
00784            } else {
00785               dest = CERT_GetNextGeneralName(dest);
00786            }
00787        }
00788     } while (src != srcHead && rv == SECSuccess);
00789     /* TODO: unmark arena */
00790     return rv;
00791 loser:
00792     /* TODO: release back to mark */
00793     return SECFailure;
00794 }
00795 
00796 
00797 CERTGeneralNameList *
00798 CERT_DupGeneralNameList(CERTGeneralNameList *list)
00799 {
00800     if (list != NULL) {
00801        PZ_Lock(list->lock);
00802        list->refCount++;
00803        PZ_Unlock(list->lock);
00804     }
00805     return list;
00806 }
00807 
00808 CERTNameConstraint *
00809 CERT_CopyNameConstraint(PRArenaPool         *arena, 
00810                      CERTNameConstraint  *dest, 
00811                      CERTNameConstraint  *src)
00812 {
00813     SECStatus  rv;
00814     
00815     /* TODO: mark arena */
00816     if (dest == NULL) {
00817        dest = PORT_ArenaZNew(arena, CERTNameConstraint);
00818        if (!dest)
00819            goto loser;
00820        /* mark that it is not linked */
00821        dest->name.l.prev = dest->name.l.next = &(dest->name.l);
00822     }
00823     rv = CERT_CopyGeneralName(arena, &dest->name, &src->name);
00824     if (rv != SECSuccess) {
00825        goto loser;
00826     }
00827     rv = SECITEM_CopyItem(arena, &dest->DERName, &src->DERName);
00828     if (rv != SECSuccess) {
00829        goto loser;
00830     }
00831     rv = SECITEM_CopyItem(arena, &dest->min, &src->min);
00832     if (rv != SECSuccess) {
00833        goto loser;
00834     }
00835     rv = SECITEM_CopyItem(arena, &dest->max, &src->max);
00836     if (rv != SECSuccess) {
00837        goto loser;
00838     }
00839     dest->l.prev = dest->l.next = &dest->l;
00840     /* TODO: unmark arena */
00841     return dest;
00842 loser:
00843     /* TODO: release arena to mark */
00844     return NULL;
00845 }
00846 
00847 
00848 CERTGeneralName *
00849 cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2)
00850 {
00851     PRCList *begin1;
00852     PRCList *begin2;
00853     PRCList *end1;
00854     PRCList *end2;
00855 
00856     if (list1 == NULL){
00857        return list2;
00858     } else if (list2 == NULL) {
00859        return list1;
00860     } else {
00861        begin1 = &list1->l;
00862        begin2 = &list2->l;
00863        end1 = list1->l.prev;
00864        end2 = list2->l.prev;
00865        end1->next = begin2;
00866        end2->next = begin1;
00867        begin1->prev = end2;
00868        begin2->prev = end1;
00869        return list1;
00870     }
00871 }
00872 
00873 
00874 CERTNameConstraint *
00875 cert_CombineConstraintsLists(CERTNameConstraint *list1, CERTNameConstraint *list2)
00876 {
00877     PRCList *begin1;
00878     PRCList *begin2;
00879     PRCList *end1;
00880     PRCList *end2;
00881 
00882     if (list1 == NULL){
00883        return list2;
00884     } else if (list2 == NULL) {
00885        return list1;
00886     } else {
00887        begin1 = &list1->l;
00888        begin2 = &list2->l;
00889        end1 = list1->l.prev;
00890        end2 = list2->l.prev;
00891        end1->next = begin2;
00892        end2->next = begin1;
00893        begin1->prev = end2;
00894        begin2->prev = end1;
00895        return list1;
00896     }
00897 }
00898 
00899 
00900 CERTNameConstraint *
00901 CERT_AddNameConstraint(CERTNameConstraint *list, 
00902                      CERTNameConstraint *constraint)
00903 {
00904     PORT_Assert(constraint != NULL);
00905     constraint->l.next = constraint->l.prev = &constraint->l;
00906     list = cert_CombineConstraintsLists(list, constraint);
00907     return list;
00908 }
00909 
00910 
00911 SECStatus
00912 CERT_GetNameConstraintByType (CERTNameConstraint *constraints,
00913                            CERTGeneralNameType type, 
00914                            CERTNameConstraint **returnList,
00915                            PRArenaPool *arena)
00916 {
00917     CERTNameConstraint *current;
00918     
00919     *returnList = NULL;
00920     if (!constraints)
00921        return SECSuccess;
00922     /* TODO: mark arena */
00923     current = constraints;
00924     do {
00925        PORT_Assert(current->name.type);
00926        if (current->name.type == type) {
00927            CERTNameConstraint *temp;
00928            temp = CERT_CopyNameConstraint(arena, NULL, current);
00929            if (temp == NULL) 
00930               goto loser;
00931            *returnList = CERT_AddNameConstraint(*returnList, temp);
00932        }
00933        current = CERT_GetNextNameConstraint(current);
00934     } while (current != constraints);
00935     /* TODO: unmark arena */
00936     return SECSuccess;
00937 loser:
00938     /* TODO: release arena back to mark */
00939     return SECFailure;
00940 }
00941 
00942 void *
00943 CERT_GetGeneralNameByType (CERTGeneralName *genNames,
00944                         CERTGeneralNameType type, PRBool derFormat)
00945 {
00946     CERTGeneralName *current;
00947     
00948     if (!genNames)
00949        return NULL;
00950     current = genNames;
00951 
00952     do {
00953        if (current->type == type) {
00954            switch (type) {
00955            case certDNSName:
00956            case certEDIPartyName:
00957            case certIPAddress:
00958            case certRegisterID:
00959            case certRFC822Name:
00960            case certX400Address:
00961            case certURI: 
00962               return (void *)&current->name.other;           /* SECItem * */
00963 
00964            case certOtherName: 
00965               return (void *)&current->name.OthName;         /* OthName * */
00966 
00967            case certDirectoryName: 
00968               return derFormat 
00969                      ? (void *)&current->derDirectoryName    /* SECItem * */
00970                      : (void *)&current->name.directoryName; /* CERTName * */
00971            }
00972            PORT_Assert(0); 
00973            return NULL;
00974        }
00975        current = CERT_GetNextGeneralName(current);
00976     } while (current != genNames);
00977     return NULL;
00978 }
00979 
00980 int
00981 CERT_GetNamesLength(CERTGeneralName *names)
00982 {
00983     int              length = 0;
00984     CERTGeneralName  *first;
00985 
00986     first = names;
00987     if (names != NULL) {
00988        do {
00989            length++;
00990            names = CERT_GetNextGeneralName(names);
00991        } while (names != first);
00992     }
00993     return length;
00994 }
00995 
00996 /* Creates new GeneralNames for any email addresses found in the 
00997 ** input DN, and links them onto the list for the DN.
00998 */
00999 SECStatus
01000 cert_ExtractDNEmailAddrs(CERTGeneralName *name, PLArenaPool *arena)
01001 {
01002     CERTGeneralName  *nameList = NULL;
01003     const CERTRDN    **nRDNs   = name->name.directoryName.rdns;
01004     SECStatus        rv        = SECSuccess;
01005 
01006     PORT_Assert(name->type == certDirectoryName);
01007     if (name->type != certDirectoryName) {
01008         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01009        return SECFailure;
01010     }
01011     /* TODO: mark arena */
01012     while (nRDNs && *nRDNs) { /* loop over RDNs */
01013        const CERTRDN *nRDN = *nRDNs++;
01014        CERTAVA **nAVAs = nRDN->avas;
01015        while (nAVAs && *nAVAs) { /* loop over AVAs */
01016            int tag;
01017            CERTAVA *nAVA = *nAVAs++;
01018            tag = CERT_GetAVATag(nAVA);
01019            if ( tag == SEC_OID_PKCS9_EMAIL_ADDRESS ||
01020                tag == SEC_OID_RFC1274_MAIL) { /* email AVA */
01021               CERTGeneralName *newName = NULL;
01022               SECItem *avaValue = CERT_DecodeAVAValue(&nAVA->value);
01023               if (!avaValue)
01024                   goto loser;
01025               rv = SECFailure;
01026                 newName = cert_NewGeneralName(arena, certRFC822Name);
01027               if (newName) {
01028                  rv = SECITEM_CopyItem(arena, &newName->name.other, avaValue);
01029               }
01030               SECITEM_FreeItem(avaValue, PR_TRUE);
01031               if (rv != SECSuccess)
01032                   goto loser;
01033               nameList = cert_CombineNamesLists(nameList, newName);
01034            } /* handle one email AVA */
01035        } /* loop over AVAs */
01036     } /* loop over RDNs */
01037     /* combine new names with old one. */
01038     name = cert_CombineNamesLists(name, nameList);
01039     /* TODO: unmark arena */
01040     return SECSuccess;
01041 
01042 loser:
01043     /* TODO: release arena back to mark */
01044     return SECFailure;
01045 }
01046 
01047 /* This function is called by CERT_VerifyCertChain to extract all
01048 ** names from a cert in preparation for a name constraints test.
01049 */
01050 CERTGeneralName *
01051 CERT_GetCertificateNames(CERTCertificate *cert, PRArenaPool *arena)
01052 {
01053     CERTGeneralName  *DN;
01054     CERTGeneralName  *altName         = NULL;
01055     SECItem          altNameExtension = {siBuffer, NULL, 0 };
01056     SECStatus        rv;
01057 
01058     /* TODO: mark arena */
01059     DN = cert_NewGeneralName(arena, certDirectoryName);
01060     if (DN == NULL) {
01061        goto loser;
01062     }
01063     rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject);
01064     if (rv != SECSuccess) {
01065        goto loser;
01066     }
01067     rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject);
01068     if (rv != SECSuccess) {
01069        goto loser;
01070     }
01071     /* Extract email addresses from DN, construct CERTGeneralName structs 
01072     ** for them, add them to the name list 
01073     */
01074     rv = cert_ExtractDNEmailAddrs(DN, arena);
01075     if (rv != SECSuccess)
01076         goto loser;
01077 
01078     /* Now extract any GeneralNames from the subject name names extension. */
01079     rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
01080                             &altNameExtension);
01081     if (rv == SECSuccess) {
01082        altName = CERT_DecodeAltNameExtension(arena, &altNameExtension);
01083        rv = altName ? SECSuccess : SECFailure;
01084     }
01085     if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND)
01086        rv = SECSuccess;
01087     if (altNameExtension.data)
01088        SECITEM_FreeItem(&altNameExtension, PR_FALSE);
01089     if (rv != SECSuccess)
01090         goto loser;
01091     DN = cert_CombineNamesLists(DN, altName);
01092 
01093     /* TODO: unmark arena */
01094     return DN;
01095 loser:
01096     /* TODO: release arena to mark */
01097     return NULL;
01098 }
01099 
01100 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for 
01101 ** URI name constraints.  SECFailure otherwise.
01102 ** If the constraint begins with a dot, it is a domain name, otherwise
01103 ** It is a host name.  Examples:
01104 **  Constraint            Name             Result
01105 ** ------------      ---------------      --------
01106 **  foo.bar.com          foo.bar.com      matches
01107 **  foo.bar.com          FoO.bAr.CoM      matches
01108 **  foo.bar.com      www.foo.bar.com      no match
01109 **  foo.bar.com        nofoo.bar.com      no match
01110 ** .foo.bar.com      www.foo.bar.com      matches
01111 ** .foo.bar.com        nofoo.bar.com      no match
01112 ** .foo.bar.com          foo.bar.com      no match
01113 ** .foo.bar.com     www..foo.bar.com      no match
01114 */
01115 static SECStatus
01116 compareURIN2C(const SECItem *name, const SECItem *constraint)
01117 {
01118     int offset;
01119     /* The spec is silent on intepreting zero-length constraints.
01120     ** We interpret them as matching no URI names.
01121     */
01122     if (!constraint->len)
01123         return SECFailure;
01124     if (constraint->data[0] != '.') { 
01125        /* constraint is a host name. */
01126        if (name->len != constraint->len ||
01127            PL_strncasecmp(name->data, constraint->data, constraint->len))
01128            return SECFailure;
01129        return SECSuccess;
01130     }
01131     /* constraint is a domain name. */
01132     if (name->len < constraint->len)
01133         return SECFailure;
01134     offset = name->len - constraint->len;
01135     if (PL_strncasecmp(name->data + offset, constraint->data, constraint->len))
01136         return SECFailure;
01137     if (!offset || 
01138         (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
01139        return SECSuccess;
01140     return SECFailure;
01141 }
01142 
01143 /* for DNSname constraints, RFC 3280 says, (section 4.2.1.11, page 38)
01144 **
01145 ** DNS name restrictions are expressed as foo.bar.com.  Any DNS name
01146 ** that can be constructed by simply adding to the left hand side of the
01147 ** name satisfies the name constraint.  For example, www.foo.bar.com
01148 ** would satisfy the constraint but foo1.bar.com would not.
01149 **
01150 ** But NIST's PKITS test suite requires that the constraint be treated
01151 ** as a domain name, and requires that any name added to the left hand
01152 ** side end in a dot ".".  Sensible, but not strictly following the RFC.
01153 **
01154 **  Constraint            Name            RFC 3280  NIST PKITS
01155 ** ------------      ---------------      --------  ----------
01156 **  foo.bar.com          foo.bar.com      matches    matches
01157 **  foo.bar.com          FoO.bAr.CoM      matches    matches
01158 **  foo.bar.com      www.foo.bar.com      matches    matches
01159 **  foo.bar.com        nofoo.bar.com      MATCHES    NO MATCH
01160 ** .foo.bar.com      www.foo.bar.com      matches    matches? disallowed?
01161 ** .foo.bar.com          foo.bar.com      no match   no match
01162 ** .foo.bar.com     www..foo.bar.com      matches    probably not 
01163 **
01164 ** We will try to conform to NIST's PKITS tests, and the unstated 
01165 ** rules they imply.
01166 */
01167 static SECStatus
01168 compareDNSN2C(const SECItem *name, const SECItem *constraint)
01169 {
01170     int offset;
01171     /* The spec is silent on intepreting zero-length constraints.
01172     ** We interpret them as matching all DNSnames.
01173     */
01174     if (!constraint->len)
01175         return SECSuccess;
01176     if (name->len < constraint->len)
01177         return SECFailure;
01178     offset = name->len - constraint->len;
01179     if (PL_strncasecmp(name->data + offset, constraint->data, constraint->len))
01180         return SECFailure;
01181     if (!offset || 
01182         (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
01183        return SECSuccess;
01184     return SECFailure;
01185 }
01186 
01187 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for
01188 ** internet email addresses.  SECFailure otherwise.
01189 ** If constraint contains a '@' then the two strings much match exactly.
01190 ** Else if constraint starts with a '.'. then it must match the right-most
01191 ** substring of the name, 
01192 ** else constraint string must match entire name after the name's '@'.
01193 ** Empty constraint string matches all names. All comparisons case insensitive.
01194 */
01195 static SECStatus
01196 compareRFC822N2C(const SECItem *name, const SECItem *constraint)
01197 {
01198     int offset;
01199     if (!constraint->len)
01200         return SECSuccess;
01201     if (name->len < constraint->len)
01202         return SECFailure;
01203     if (constraint->len == 1 && constraint->data[0] == '.')
01204         return SECSuccess;
01205     for (offset = constraint->len - 1; offset >= 0; --offset) {
01206        if (constraint->data[offset] == '@') {
01207            return (name->len == constraint->len && 
01208                !PL_strncasecmp(name->data, constraint->data, constraint->len))
01209               ? SECSuccess : SECFailure;
01210        }
01211     }
01212     offset = name->len - constraint->len;
01213     if (PL_strncasecmp(name->data + offset, constraint->data, constraint->len))
01214         return SECFailure;
01215     if (constraint->data[0] == '.')
01216         return SECSuccess;
01217     if (offset > 0 && name->data[offset - 1] == '@')
01218         return SECSuccess;
01219     return SECFailure;
01220 }
01221 
01222 /* name contains either a 4 byte IPv4 address or a 16 byte IPv6 address.
01223 ** constraint contains an address of the same length, and a subnet mask
01224 ** of the same length.  Compare name's address to the constraint's 
01225 ** address, subject to the mask.
01226 ** Return SECSuccess if they match, SECFailure if they don't. 
01227 */
01228 static SECStatus
01229 compareIPaddrN2C(const SECItem *name, const SECItem *constraint)
01230 {
01231     int i;
01232     if (name->len == 4 && constraint->len == 8) { /* ipv4 addr */
01233         for (i = 0; i < 4; i++) {
01234            if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+4])
01235                goto loser;
01236        }
01237        return SECSuccess;
01238     }
01239     if (name->len == 16 && constraint->len == 32) { /* ipv6 addr */
01240         for (i = 0; i < 16; i++) {
01241            if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+16])
01242                goto loser;
01243        }
01244        return SECSuccess;
01245     }
01246 loser:
01247     return SECFailure;
01248 }
01249 
01250 /* start with a SECItem that points to a URI.  Parse it lookingg for 
01251 ** a hostname.  Modify item->data and item->len to define the hostname,
01252 ** but do not modify and data at item->data.  
01253 ** If anything goes wrong, the contents of *item are undefined.
01254 */
01255 static SECStatus
01256 parseUriHostname(SECItem * item)
01257 {
01258     int i;
01259     PRBool found = PR_FALSE;
01260     for (i = 0; (unsigned)(i+2) < item->len; ++i) {
01261        if (item->data[i  ] == ':' &&
01262            item->data[i+1] == '/' &&
01263            item->data[i+2] == '/') {
01264            i += 3;
01265            item->data += i;
01266            item->len  -= i;
01267            found = PR_TRUE;
01268            break;
01269        }
01270     }
01271     if (!found) 
01272         return SECFailure;
01273     /* now look for a '/', which is an upper bound in the end of the name */
01274     for (i = 0; (unsigned)i < item->len; ++i) {
01275        if (item->data[i] == '/') {
01276            item->len = i;
01277            break;
01278        }
01279     }
01280     /* now look for a ':', which marks the end of the name */
01281     for (i = item->len; --i >= 0; ) {
01282         if (item->data[i] == ':') {
01283            item->len = i;
01284            break;
01285        }
01286     }
01287     /* now look for an '@', which marks the beginning of the hostname */
01288     for (i = 0; (unsigned)i < item->len; ++i) {
01289        if (item->data[i] == '@') {
01290            ++i;
01291            item->data += i;
01292            item->len  -= i;
01293            break;
01294        }
01295     }
01296     return item->len ? SECSuccess : SECFailure;
01297 }
01298 
01299 /* This function takes one name, and a list of constraints.
01300 ** It searches the constraints looking for a match.
01301 ** It returns SECSuccess if the name satisfies the constraints, i.e.,
01302 ** if excluded, then the name does not match any constraint, 
01303 ** if permitted, then the name matches at least one constraint.
01304 ** It returns SECFailure if the name fails to satisfy the constraints,
01305 ** or if some code fails (e.g. out of memory, or invalid constraint)
01306 */
01307 static SECStatus
01308 cert_CompareNameWithConstraints(CERTGeneralName     *name, 
01309                             CERTNameConstraint  *constraints,
01310                             PRBool              excluded)
01311 {
01312     SECStatus           rv     = SECSuccess;
01313     SECStatus           matched = SECFailure;
01314     CERTNameConstraint  *current;
01315 
01316     PORT_Assert(constraints);  /* caller should not call with NULL */
01317     if (!constraints) {
01318        PORT_SetError(SEC_ERROR_INVALID_ARGS);
01319         return SECFailure;
01320     }
01321 
01322     current = constraints;
01323     do {
01324        rv = SECSuccess;
01325        matched = SECFailure;
01326        PORT_Assert(name->type == current->name.type);
01327        switch (name->type) {
01328 
01329        case certDNSName:
01330            matched = compareDNSN2C(&name->name.other, 
01331                                    &current->name.name.other);
01332            break;
01333 
01334        case certRFC822Name:
01335            matched = compareRFC822N2C(&name->name.other, 
01336                                       &current->name.name.other);
01337            break;
01338 
01339        case certURI:
01340            {
01341               /* make a modifiable copy of the URI SECItem. */
01342               SECItem uri = name->name.other;
01343               /* find the hostname in the URI */
01344               rv = parseUriHostname(&uri);
01345               if (rv == SECSuccess) {
01346                   /* does our hostname meet the constraint? */
01347                   matched = compareURIN2C(&uri, &current->name.name.other);
01348               }
01349            }
01350            break;
01351 
01352        case certDirectoryName:
01353            /* Determine if the constraint directory name is a "prefix"
01354            ** for the directory name being tested. 
01355            */
01356          {
01357            /* status defaults to SECEqual, so that a constraint with 
01358            ** no AVAs will be a wildcard, matching all directory names.
01359            */
01360            SECComparison   status = SECEqual;
01361            const CERTRDN **cRDNs = current->name.name.directoryName.rdns;  
01362            const CERTRDN **nRDNs = name->name.directoryName.rdns;
01363            while (cRDNs && *cRDNs && nRDNs && *nRDNs) { 
01364               /* loop over name RDNs and constraint RDNs in lock step */
01365               const CERTRDN *cRDN = *cRDNs++;
01366               const CERTRDN *nRDN = *nRDNs++;
01367               CERTAVA **cAVAs = cRDN->avas;
01368               while (cAVAs && *cAVAs) { /* loop over constraint AVAs */
01369                   CERTAVA *cAVA = *cAVAs++;
01370                   CERTAVA **nAVAs = nRDN->avas;
01371                   while (nAVAs && *nAVAs) { /* loop over name AVAs */
01372                      CERTAVA *nAVA = *nAVAs++;
01373                      status = CERT_CompareAVA(cAVA, nAVA);
01374                      if (status == SECEqual) 
01375                          break;
01376                   } /* loop over name AVAs */
01377                   if (status != SECEqual) 
01378                      break;
01379               } /* loop over constraint AVAs */
01380               if (status != SECEqual) 
01381                   break;
01382            } /* loop over name RDNs and constraint RDNs */
01383            matched = (status == SECEqual) ? SECSuccess : SECFailure;
01384            break;
01385          }
01386 
01387        case certIPAddress:  /* type 8 */
01388            matched = compareIPaddrN2C(&name->name.other, 
01389                                       &current->name.name.other);
01390            break;
01391 
01392        /* NSS does not know how to compare these "Other" type names with 
01393        ** their respective constraints.  But it does know how to tell
01394        ** if the constraint applies to the type of name (by comparing
01395        ** the constraint OID to the name OID).  NSS makes no use of "Other"
01396        ** type names at all, so NSS errs on the side of leniency for these 
01397        ** types, provided that their OIDs match.  So, when an "Other"
01398        ** name constraint appears in an excluded subtree, it never causes
01399        ** a name to fail.  When an "Other" name constraint appears in a
01400        ** permitted subtree, AND the constraint's OID matches the name's
01401        ** OID, then name is treated as if it matches the constraint.
01402        */
01403        case certOtherName:  /* type 1 */
01404            matched = (!excluded &&
01405                      name->type == current->name.type &&
01406                      SECITEM_ItemsAreEqual(&name->name.OthName.oid,
01407                                         &current->name.name.OthName.oid))
01408                ? SECSuccess : SECFailure;
01409            break;
01410 
01411        /* NSS does not know how to compare these types of names with their
01412        ** respective constraints.  But NSS makes no use of these types of 
01413        ** names at all, so it errs on the side of leniency for these types.
01414        ** Constraints for these types of names never cause the name to 
01415        ** fail the constraints test.  NSS behaves as if the name matched
01416        ** for permitted constraints, and did not match for excluded ones.
01417        */
01418        case certX400Address:       /* type 4 */
01419        case certEDIPartyName:  /* type 6 */
01420        case certRegisterID: /* type 9 */
01421            matched = excluded ? SECFailure : SECSuccess;
01422            break;
01423 
01424        default: /* non-standard types are not supported */
01425            rv = SECFailure;
01426            break;
01427        }
01428        if (matched == SECSuccess || rv != SECSuccess)
01429            break;
01430        current = CERT_GetNextNameConstraint(current);
01431     } while (current != constraints);
01432     if (rv == SECSuccess) {
01433         if (matched == SECSuccess) 
01434            rv = excluded ? SECFailure : SECSuccess;
01435        else
01436            rv = excluded ? SECSuccess : SECFailure;
01437        return rv;
01438     }
01439 
01440     return SECFailure;
01441 }
01442 
01443 /* Extract the name constraints extension from the CA cert.
01444 ** Test each and every name in namesList against all the constraints
01445 ** relevant to that type of name.
01446 ** Returns NULL for success, all names are acceptable.
01447 ** If some name is not acceptable, returns a pointer to the cert that
01448 ** contained that name.
01449 */
01450 SECStatus
01451 CERT_CompareNameSpace(CERTCertificate  *cert,
01452                     CERTGeneralName  *namesList,
01453                     CERTCertificate **certsList,
01454                     PRArenaPool      *arena,
01455                     CERTCertificate **pBadCert)
01456 {
01457     SECStatus            rv;
01458     SECItem              constraintsExtension;
01459     CERTNameConstraints  *constraints;
01460     CERTGeneralName      *currentName;
01461     int                  count = 0;
01462     CERTNameConstraint  *matchingConstraints;
01463     CERTCertificate      *badCert = NULL;
01464     
01465     constraintsExtension.data = NULL;
01466     rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, 
01467                                 &constraintsExtension);
01468     if (rv != SECSuccess) {
01469        if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
01470            rv = SECSuccess;
01471        } else {
01472            count = -1;
01473        }
01474        goto done;
01475     }
01476     /* TODO: mark arena */
01477     constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
01478     PORT_Free(constraintsExtension.data);
01479     currentName = namesList;
01480     if (constraints == NULL) { /* decode failed */
01481        rv = SECFailure;
01482        count = -1;
01483        goto done;
01484     } 
01485     do {
01486        if (constraints->excluded != NULL) {
01487            rv = CERT_GetNameConstraintByType(constraints->excluded, 
01488                                              currentName->type, 
01489                                          &matchingConstraints, arena);
01490            if (rv == SECSuccess && matchingConstraints != NULL) {
01491               rv = cert_CompareNameWithConstraints(currentName, 
01492                                                    matchingConstraints,
01493                                                PR_TRUE);
01494            }
01495            if (rv != SECSuccess) 
01496               break;
01497        }
01498        if (constraints->permited != NULL) {
01499            rv = CERT_GetNameConstraintByType(constraints->permited, 
01500                                              currentName->type, 
01501                                          &matchingConstraints, arena);
01502             if (rv == SECSuccess && matchingConstraints != NULL) {
01503               rv = cert_CompareNameWithConstraints(currentName, 
01504                                                    matchingConstraints,
01505                                                PR_FALSE);
01506            }
01507            if (rv != SECSuccess) 
01508               break;
01509        }
01510        currentName = CERT_GetNextGeneralName(currentName);
01511        count ++;
01512     } while (currentName != namesList);
01513 done:
01514     if (rv != SECSuccess) {
01515        badCert = (count >= 0) ? certsList[count] : cert;
01516     }
01517     if (pBadCert)
01518        *pBadCert = badCert;
01519     /* TODO: release back to mark */
01520     return rv;
01521 }
01522 
01523 /* Search the cert for an X509_SUBJECT_ALT_NAME extension.
01524 ** ASN1 Decode it into a list of alternate names.
01525 ** Search the list of alternate names for one with the NETSCAPE_NICKNAME OID.
01526 ** ASN1 Decode that name.  Turn the result into a zString.  
01527 ** Look for duplicate nickname already in the certdb. 
01528 ** If one is found, create a nickname string that is not a duplicate.
01529 */
01530 char *
01531 CERT_GetNickName(CERTCertificate   *cert,
01532                CERTCertDBHandle  *handle,
01533                PRArenaPool      *nicknameArena)
01534 { 
01535     CERTGeneralName  *current;
01536     CERTGeneralName  *names;
01537     char             *nickname   = NULL;
01538     char             *returnName = NULL;
01539     char             *basename   = NULL;
01540     PRArenaPool      *arena      = NULL;
01541     CERTCertificate  *tmpcert;
01542     SECStatus        rv;
01543     int              count;
01544     int              found = 0;
01545     SECItem          altNameExtension;
01546     SECItem          nick;
01547 
01548     if (handle == NULL) {
01549        handle = CERT_GetDefaultCertDB();
01550     }
01551     altNameExtension.data = NULL;
01552     rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
01553                             &altNameExtension);
01554     if (rv != SECSuccess) { 
01555        goto loser; 
01556     }
01557     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01558     if (arena == NULL) {
01559        goto loser;
01560     }
01561     names = CERT_DecodeAltNameExtension(arena, &altNameExtension);
01562     if (names == NULL) {
01563        goto loser;
01564     } 
01565     current = names;
01566     do {
01567        if (current->type == certOtherName && 
01568            SECOID_FindOIDTag(&current->name.OthName.oid) == 
01569              SEC_OID_NETSCAPE_NICKNAME) {
01570            found = 1;
01571            break;
01572        }
01573        current = CERT_GetNextGeneralName(current);
01574     } while (current != names);
01575     if (!found)
01576        goto loser;
01577 
01578     rv = SEC_ASN1DecodeItem(arena, &nick, SEC_IA5StringTemplate, 
01579                          &current->name.OthName.name);
01580     if (rv != SECSuccess) {
01581        goto loser;
01582     }
01583 
01584     /* make a null terminated string out of nick, with room enough at
01585     ** the end to add on a number of up to 21 digits in length, (a signed
01586     ** 64-bit number in decimal) plus a space and a "#". 
01587     */
01588     nickname = (char*)PORT_ZAlloc(nick.len + 24);
01589     if (!nickname) 
01590        goto loser;
01591     PORT_Strncpy(nickname, (char *)nick.data, nick.len);
01592 
01593     /* Don't let this cert's nickname duplicate one already in the DB.
01594     ** If it does, create a variant of the nickname that doesn't.
01595     */
01596     count = 0;
01597     while ((tmpcert = CERT_FindCertByNickname(handle, nickname)) != NULL) {
01598        CERT_DestroyCertificate(tmpcert);
01599        if (!basename) {
01600            basename = PORT_Strdup(nickname);
01601            if (!basename)
01602               goto loser;
01603        }
01604        count++;
01605        sprintf(nickname, "%s #%d", basename, count);
01606     }
01607 
01608     /* success */
01609     if (nicknameArena) {
01610        returnName =  PORT_ArenaStrdup(nicknameArena, nickname);
01611     } else {
01612        returnName = nickname;
01613        nickname = NULL;
01614     }
01615 loser:
01616     if (arena != NULL) 
01617        PORT_FreeArena(arena, PR_FALSE);
01618     if (nickname)
01619        PORT_Free(nickname);
01620     if (basename)
01621        PORT_Free(basename);
01622     if (altNameExtension.data)
01623        PORT_Free(altNameExtension.data);
01624     return returnName;
01625 }
01626 
01627 #if 0
01628 /* not exported from shared libs, not used.  Turn on if we ever need it. */
01629 SECStatus
01630 CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b)
01631 {
01632     CERTGeneralName *currentA;
01633     CERTGeneralName *currentB;
01634     PRBool found;
01635 
01636     currentA = a;
01637     currentB = b;
01638     if (a != NULL) {
01639        do { 
01640            if (currentB == NULL) {
01641               return SECFailure;
01642            }
01643            currentB = CERT_GetNextGeneralName(currentB);
01644            currentA = CERT_GetNextGeneralName(currentA);
01645        } while (currentA != a);
01646     }
01647     if (currentB != b) {
01648        return SECFailure;
01649     }
01650     currentA = a;
01651     do {
01652        currentB = b;
01653        found = PR_FALSE;
01654        do {
01655            if (currentB->type == currentA->type) {
01656               switch (currentB->type) {
01657                 case certDNSName:
01658                 case certEDIPartyName:
01659                 case certIPAddress:
01660                 case certRegisterID:
01661                 case certRFC822Name:
01662                 case certX400Address:
01663                 case certURI:
01664                   if (SECITEM_CompareItem(&currentA->name.other,
01665                                        &currentB->name.other) 
01666                      == SECEqual) {
01667                      found = PR_TRUE;
01668                   }
01669                   break;
01670                 case certOtherName:
01671                   if (SECITEM_CompareItem(&currentA->name.OthName.oid,
01672                                        &currentB->name.OthName.oid) 
01673                      == SECEqual &&
01674                      SECITEM_CompareItem(&currentA->name.OthName.name,
01675                                        &currentB->name.OthName.name)
01676                      == SECEqual) {
01677                      found = PR_TRUE;
01678                   }
01679                   break;
01680                 case certDirectoryName:
01681                   if (CERT_CompareName(&currentA->name.directoryName,
01682                                     &currentB->name.directoryName)
01683                      == SECEqual) {
01684                      found = PR_TRUE;
01685                   }
01686               }
01687                   
01688            }
01689            currentB = CERT_GetNextGeneralName(currentB);
01690        } while (currentB != b && found != PR_TRUE);
01691        if (found != PR_TRUE) {
01692            return SECFailure;
01693        }
01694        currentA = CERT_GetNextGeneralName(currentA);
01695     } while (currentA != a);
01696     return SECSuccess;
01697 }
01698 
01699 SECStatus
01700 CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b)
01701 {
01702     SECStatus rv;
01703 
01704     if (a == b) {
01705        return SECSuccess;
01706     }
01707     if (a != NULL && b != NULL) {
01708        PZ_Lock(a->lock);
01709        PZ_Lock(b->lock);
01710        rv = CERT_CompareGeneralName(a->name, b->name);
01711        PZ_Unlock(a->lock);
01712        PZ_Unlock(b->lock);
01713     } else {
01714        rv = SECFailure;
01715     }
01716     return rv;
01717 }
01718 #endif
01719 
01720 #if 0
01721 /* This function is not exported from NSS shared libraries, and is not
01722 ** used inside of NSS.
01723 ** XXX it doesn't check for failed allocations. :-(
01724 */
01725 void *
01726 CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
01727                               CERTGeneralNameType type,
01728                               PRArenaPool *arena)
01729 {
01730     CERTName *name = NULL; 
01731     SECItem *item = NULL;
01732     OtherName *other = NULL;
01733     OtherName *tmpOther = NULL;
01734     void *data;
01735 
01736     PZ_Lock(list->lock);
01737     data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE);
01738     if (data != NULL) {
01739        switch (type) {
01740          case certDNSName:
01741          case certEDIPartyName:
01742          case certIPAddress:
01743          case certRegisterID:
01744          case certRFC822Name:
01745          case certX400Address:
01746          case certURI:
01747            if (arena != NULL) {
01748               item = PORT_ArenaNew(arena, SECItem);
01749               if (item != NULL) {
01750 XXX               SECITEM_CopyItem(arena, item, (SECItem *) data);
01751               }
01752            } else { 
01753               item = SECITEM_DupItem((SECItem *) data);
01754            }
01755            PZ_Unlock(list->lock);
01756            return item;
01757          case certOtherName:
01758            other = (OtherName *) data;
01759            if (arena != NULL) {
01760               tmpOther = PORT_ArenaNew(arena, OtherName);
01761            } else {
01762               tmpOther = PORT_New(OtherName);
01763            }
01764            if (tmpOther != NULL) {
01765 XXX           SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
01766 XXX           SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
01767            }
01768            PZ_Unlock(list->lock);
01769            return tmpOther;
01770          case certDirectoryName:
01771            if (arena) {
01772               name = PORT_ArenaZNew(list->arena, CERTName);
01773               if (name) {
01774 XXX               CERT_CopyName(arena, name, (CERTName *) data);
01775               }
01776            }
01777            PZ_Unlock(list->lock);
01778            return name;
01779        }
01780     }
01781     PZ_Unlock(list->lock);
01782     return NULL;
01783 }
01784 #endif
01785 
01786 #if 0
01787 /* This function is not exported from NSS shared libraries, and is not
01788 ** used inside of NSS.
01789 ** XXX it should NOT be a void function, since it does allocations
01790 ** that can fail.
01791 */
01792 void
01793 CERT_AddGeneralNameToList(CERTGeneralNameList *list, 
01794                        CERTGeneralNameType type,
01795                        void *data, SECItem *oid)
01796 {
01797     CERTGeneralName *name;
01798 
01799     if (list != NULL && data != NULL) {
01800        PZ_Lock(list->lock);
01801        name = cert_NewGeneralName(list->arena, type);
01802        if (!name)
01803            goto done;
01804        switch (type) {
01805          case certDNSName:
01806          case certEDIPartyName:
01807          case certIPAddress:
01808          case certRegisterID:
01809          case certRFC822Name:
01810          case certX400Address:
01811          case certURI:
01812 XXX        SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
01813            break;
01814          case certOtherName:
01815 XXX        SECITEM_CopyItem(list->arena, &name->name.OthName.name,
01816                           (SECItem *) data);
01817 XXX        SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
01818                           oid);
01819            break;
01820          case certDirectoryName:
01821 XXX        CERT_CopyName(list->arena, &name->name.directoryName,
01822                        (CERTName *) data);
01823            break;
01824        }
01825        list->name = cert_CombineNamesLists(list->name, name);
01826        list->len++;
01827 done:
01828        PZ_Unlock(list->lock);
01829     }
01830     return;
01831 }
01832 #endif