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 = SECSuccess;
01458     SECItem              constraintsExtension;
01459     CERTNameConstraints  *constraints;
01460     CERTGeneralName      *currentName;
01461     int                  count = 0;
01462     CERTNameConstraint  *matchingConstraints;
01463     CERTCertificate      *badCert = NULL;
01464     
01465     /* If no names to check, then no names can be bad. */
01466     if (!namesList)
01467        goto done;
01468     constraintsExtension.data = NULL;
01469     rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, 
01470                                 &constraintsExtension);
01471     if (rv != SECSuccess) {
01472        if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
01473            rv = SECSuccess;
01474        } else {
01475            count = -1;
01476        }
01477        goto done;
01478     }
01479     /* TODO: mark arena */
01480     constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
01481     PORT_Free(constraintsExtension.data);
01482     currentName = namesList;
01483     if (constraints == NULL) { /* decode failed */
01484        rv = SECFailure;
01485        count = -1;
01486        goto done;
01487     } 
01488     do {
01489        if (constraints->excluded != NULL) {
01490            rv = CERT_GetNameConstraintByType(constraints->excluded, 
01491                                              currentName->type, 
01492                                          &matchingConstraints, arena);
01493            if (rv == SECSuccess && matchingConstraints != NULL) {
01494               rv = cert_CompareNameWithConstraints(currentName, 
01495                                                    matchingConstraints,
01496                                                PR_TRUE);
01497            }
01498            if (rv != SECSuccess) 
01499               break;
01500        }
01501        if (constraints->permited != NULL) {
01502            rv = CERT_GetNameConstraintByType(constraints->permited, 
01503                                              currentName->type, 
01504                                          &matchingConstraints, arena);
01505             if (rv == SECSuccess && matchingConstraints != NULL) {
01506               rv = cert_CompareNameWithConstraints(currentName, 
01507                                                    matchingConstraints,
01508                                                PR_FALSE);
01509            }
01510            if (rv != SECSuccess) 
01511               break;
01512        }
01513        currentName = CERT_GetNextGeneralName(currentName);
01514        count ++;
01515     } while (currentName != namesList);
01516 done:
01517     if (rv != SECSuccess) {
01518        badCert = (count >= 0) ? certsList[count] : cert;
01519     }
01520     if (pBadCert)
01521        *pBadCert = badCert;
01522     /* TODO: release back to mark */
01523     return rv;
01524 }
01525 
01526 /* Search the cert for an X509_SUBJECT_ALT_NAME extension.
01527 ** ASN1 Decode it into a list of alternate names.
01528 ** Search the list of alternate names for one with the NETSCAPE_NICKNAME OID.
01529 ** ASN1 Decode that name.  Turn the result into a zString.  
01530 ** Look for duplicate nickname already in the certdb. 
01531 ** If one is found, create a nickname string that is not a duplicate.
01532 */
01533 char *
01534 CERT_GetNickName(CERTCertificate   *cert,
01535                CERTCertDBHandle  *handle,
01536                PRArenaPool      *nicknameArena)
01537 { 
01538     CERTGeneralName  *current;
01539     CERTGeneralName  *names;
01540     char             *nickname   = NULL;
01541     char             *returnName = NULL;
01542     char             *basename   = NULL;
01543     PRArenaPool      *arena      = NULL;
01544     CERTCertificate  *tmpcert;
01545     SECStatus        rv;
01546     int              count;
01547     int              found = 0;
01548     SECItem          altNameExtension;
01549     SECItem          nick;
01550 
01551     if (handle == NULL) {
01552        handle = CERT_GetDefaultCertDB();
01553     }
01554     altNameExtension.data = NULL;
01555     rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, 
01556                             &altNameExtension);
01557     if (rv != SECSuccess) { 
01558        goto loser; 
01559     }
01560     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01561     if (arena == NULL) {
01562        goto loser;
01563     }
01564     names = CERT_DecodeAltNameExtension(arena, &altNameExtension);
01565     if (names == NULL) {
01566        goto loser;
01567     } 
01568     current = names;
01569     do {
01570        if (current->type == certOtherName && 
01571            SECOID_FindOIDTag(&current->name.OthName.oid) == 
01572              SEC_OID_NETSCAPE_NICKNAME) {
01573            found = 1;
01574            break;
01575        }
01576        current = CERT_GetNextGeneralName(current);
01577     } while (current != names);
01578     if (!found)
01579        goto loser;
01580 
01581     rv = SEC_ASN1DecodeItem(arena, &nick, SEC_IA5StringTemplate, 
01582                          &current->name.OthName.name);
01583     if (rv != SECSuccess) {
01584        goto loser;
01585     }
01586 
01587     /* make a null terminated string out of nick, with room enough at
01588     ** the end to add on a number of up to 21 digits in length, (a signed
01589     ** 64-bit number in decimal) plus a space and a "#". 
01590     */
01591     nickname = (char*)PORT_ZAlloc(nick.len + 24);
01592     if (!nickname) 
01593        goto loser;
01594     PORT_Strncpy(nickname, (char *)nick.data, nick.len);
01595 
01596     /* Don't let this cert's nickname duplicate one already in the DB.
01597     ** If it does, create a variant of the nickname that doesn't.
01598     */
01599     count = 0;
01600     while ((tmpcert = CERT_FindCertByNickname(handle, nickname)) != NULL) {
01601        CERT_DestroyCertificate(tmpcert);
01602        if (!basename) {
01603            basename = PORT_Strdup(nickname);
01604            if (!basename)
01605               goto loser;
01606        }
01607        count++;
01608        sprintf(nickname, "%s #%d", basename, count);
01609     }
01610 
01611     /* success */
01612     if (nicknameArena) {
01613        returnName =  PORT_ArenaStrdup(nicknameArena, nickname);
01614     } else {
01615        returnName = nickname;
01616        nickname = NULL;
01617     }
01618 loser:
01619     if (arena != NULL) 
01620        PORT_FreeArena(arena, PR_FALSE);
01621     if (nickname)
01622        PORT_Free(nickname);
01623     if (basename)
01624        PORT_Free(basename);
01625     if (altNameExtension.data)
01626        PORT_Free(altNameExtension.data);
01627     return returnName;
01628 }
01629 
01630 #if 0
01631 /* not exported from shared libs, not used.  Turn on if we ever need it. */
01632 SECStatus
01633 CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b)
01634 {
01635     CERTGeneralName *currentA;
01636     CERTGeneralName *currentB;
01637     PRBool found;
01638 
01639     currentA = a;
01640     currentB = b;
01641     if (a != NULL) {
01642        do { 
01643            if (currentB == NULL) {
01644               return SECFailure;
01645            }
01646            currentB = CERT_GetNextGeneralName(currentB);
01647            currentA = CERT_GetNextGeneralName(currentA);
01648        } while (currentA != a);
01649     }
01650     if (currentB != b) {
01651        return SECFailure;
01652     }
01653     currentA = a;
01654     do {
01655        currentB = b;
01656        found = PR_FALSE;
01657        do {
01658            if (currentB->type == currentA->type) {
01659               switch (currentB->type) {
01660                 case certDNSName:
01661                 case certEDIPartyName:
01662                 case certIPAddress:
01663                 case certRegisterID:
01664                 case certRFC822Name:
01665                 case certX400Address:
01666                 case certURI:
01667                   if (SECITEM_CompareItem(&currentA->name.other,
01668                                        &currentB->name.other) 
01669                      == SECEqual) {
01670                      found = PR_TRUE;
01671                   }
01672                   break;
01673                 case certOtherName:
01674                   if (SECITEM_CompareItem(&currentA->name.OthName.oid,
01675                                        &currentB->name.OthName.oid) 
01676                      == SECEqual &&
01677                      SECITEM_CompareItem(&currentA->name.OthName.name,
01678                                        &currentB->name.OthName.name)
01679                      == SECEqual) {
01680                      found = PR_TRUE;
01681                   }
01682                   break;
01683                 case certDirectoryName:
01684                   if (CERT_CompareName(&currentA->name.directoryName,
01685                                     &currentB->name.directoryName)
01686                      == SECEqual) {
01687                      found = PR_TRUE;
01688                   }
01689               }
01690                   
01691            }
01692            currentB = CERT_GetNextGeneralName(currentB);
01693        } while (currentB != b && found != PR_TRUE);
01694        if (found != PR_TRUE) {
01695            return SECFailure;
01696        }
01697        currentA = CERT_GetNextGeneralName(currentA);
01698     } while (currentA != a);
01699     return SECSuccess;
01700 }
01701 
01702 SECStatus
01703 CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b)
01704 {
01705     SECStatus rv;
01706 
01707     if (a == b) {
01708        return SECSuccess;
01709     }
01710     if (a != NULL && b != NULL) {
01711        PZ_Lock(a->lock);
01712        PZ_Lock(b->lock);
01713        rv = CERT_CompareGeneralName(a->name, b->name);
01714        PZ_Unlock(a->lock);
01715        PZ_Unlock(b->lock);
01716     } else {
01717        rv = SECFailure;
01718     }
01719     return rv;
01720 }
01721 #endif
01722 
01723 #if 0
01724 /* This function is not exported from NSS shared libraries, and is not
01725 ** used inside of NSS.
01726 ** XXX it doesn't check for failed allocations. :-(
01727 */
01728 void *
01729 CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
01730                               CERTGeneralNameType type,
01731                               PRArenaPool *arena)
01732 {
01733     CERTName *name = NULL; 
01734     SECItem *item = NULL;
01735     OtherName *other = NULL;
01736     OtherName *tmpOther = NULL;
01737     void *data;
01738 
01739     PZ_Lock(list->lock);
01740     data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE);
01741     if (data != NULL) {
01742        switch (type) {
01743          case certDNSName:
01744          case certEDIPartyName:
01745          case certIPAddress:
01746          case certRegisterID:
01747          case certRFC822Name:
01748          case certX400Address:
01749          case certURI:
01750            if (arena != NULL) {
01751               item = PORT_ArenaNew(arena, SECItem);
01752               if (item != NULL) {
01753 XXX               SECITEM_CopyItem(arena, item, (SECItem *) data);
01754               }
01755            } else { 
01756               item = SECITEM_DupItem((SECItem *) data);
01757            }
01758            PZ_Unlock(list->lock);
01759            return item;
01760          case certOtherName:
01761            other = (OtherName *) data;
01762            if (arena != NULL) {
01763               tmpOther = PORT_ArenaNew(arena, OtherName);
01764            } else {
01765               tmpOther = PORT_New(OtherName);
01766            }
01767            if (tmpOther != NULL) {
01768 XXX           SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
01769 XXX           SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
01770            }
01771            PZ_Unlock(list->lock);
01772            return tmpOther;
01773          case certDirectoryName:
01774            if (arena) {
01775               name = PORT_ArenaZNew(list->arena, CERTName);
01776               if (name) {
01777 XXX               CERT_CopyName(arena, name, (CERTName *) data);
01778               }
01779            }
01780            PZ_Unlock(list->lock);
01781            return name;
01782        }
01783     }
01784     PZ_Unlock(list->lock);
01785     return NULL;
01786 }
01787 #endif
01788 
01789 #if 0
01790 /* This function is not exported from NSS shared libraries, and is not
01791 ** used inside of NSS.
01792 ** XXX it should NOT be a void function, since it does allocations
01793 ** that can fail.
01794 */
01795 void
01796 CERT_AddGeneralNameToList(CERTGeneralNameList *list, 
01797                        CERTGeneralNameType type,
01798                        void *data, SECItem *oid)
01799 {
01800     CERTGeneralName *name;
01801 
01802     if (list != NULL && data != NULL) {
01803        PZ_Lock(list->lock);
01804        name = cert_NewGeneralName(list->arena, type);
01805        if (!name)
01806            goto done;
01807        switch (type) {
01808          case certDNSName:
01809          case certEDIPartyName:
01810          case certIPAddress:
01811          case certRegisterID:
01812          case certRFC822Name:
01813          case certX400Address:
01814          case certURI:
01815 XXX        SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
01816            break;
01817          case certOtherName:
01818 XXX        SECITEM_CopyItem(list->arena, &name->name.OthName.name,
01819                           (SECItem *) data);
01820 XXX        SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
01821                           oid);
01822            break;
01823          case certDirectoryName:
01824 XXX        CERT_CopyName(list->arena, &name->name.directoryName,
01825                        (CERTName *) data);
01826            break;
01827        }
01828        list->name = cert_CombineNamesLists(list->name, name);
01829        list->len++;
01830 done:
01831        PZ_Unlock(list->lock);
01832     }
01833     return;
01834 }
01835 #endif