tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

genname.c (64892B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "plarena.h"
      6 #include "seccomon.h"
      7 #include "secitem.h"
      8 #include "secoidt.h"
      9 #include "secasn1.h"
     10 #include "secder.h"
     11 #include "certt.h"
     12 #include "cert.h"
     13 #include "certi.h"
     14 #include "xconst.h"
     15 #include "secerr.h"
     16 #include "secoid.h"
     17 #include "prprf.h"
     18 #include "genname.h"
     19 
     20 SEC_ASN1_MKSUB(SEC_AnyTemplate)
     21 SEC_ASN1_MKSUB(SEC_IntegerTemplate)
     22 SEC_ASN1_MKSUB(SEC_IA5StringTemplate)
     23 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
     24 SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
     25 
     26 static const SEC_ASN1Template CERTNameConstraintTemplate[] = {
     27    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraint) },
     28    { SEC_ASN1_ANY, offsetof(CERTNameConstraint, DERName) },
     29    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
     30      offsetof(CERTNameConstraint, min), SEC_ASN1_SUB(SEC_IntegerTemplate) },
     31    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
     32      offsetof(CERTNameConstraint, max), SEC_ASN1_SUB(SEC_IntegerTemplate) },
     33    { 0 }
     34 };
     35 
     36 const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = {
     37    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
     38 };
     39 
     40 static const SEC_ASN1Template CERTNameConstraintsTemplate[] = {
     41    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraints) },
     42    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
     43      offsetof(CERTNameConstraints, DERPermited),
     44      CERT_NameConstraintSubtreeSubTemplate },
     45    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
     46      offsetof(CERTNameConstraints, DERExcluded),
     47      CERT_NameConstraintSubtreeSubTemplate },
     48    { 0 }
     49 };
     50 
     51 static const SEC_ASN1Template CERTOthNameTemplate[] = {
     52    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OtherName) },
     53    { SEC_ASN1_OBJECT_ID, offsetof(OtherName, oid) },
     54    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
     55          SEC_ASN1_XTRN | 0,
     56      offsetof(OtherName, name), SEC_ASN1_SUB(SEC_AnyTemplate) },
     57    { 0 }
     58 };
     59 
     60 static const SEC_ASN1Template CERTOtherNameTemplate[] = {
     61    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0,
     62      offsetof(CERTGeneralName, name.OthName), CERTOthNameTemplate,
     63      sizeof(CERTGeneralName) }
     64 };
     65 
     66 static const SEC_ASN1Template CERT_RFC822NameTemplate[] = {
     67    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
     68      offsetof(CERTGeneralName, name.other),
     69      SEC_ASN1_SUB(SEC_IA5StringTemplate), sizeof(CERTGeneralName) }
     70 };
     71 
     72 static const SEC_ASN1Template CERT_DNSNameTemplate[] = {
     73    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
     74      offsetof(CERTGeneralName, name.other),
     75      SEC_ASN1_SUB(SEC_IA5StringTemplate), sizeof(CERTGeneralName) }
     76 };
     77 
     78 static const SEC_ASN1Template CERT_X400AddressTemplate[] = {
     79    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 3,
     80      offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
     81      sizeof(CERTGeneralName) }
     82 };
     83 
     84 static const SEC_ASN1Template CERT_DirectoryNameTemplate[] = {
     85    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
     86          SEC_ASN1_XTRN | 4,
     87      offsetof(CERTGeneralName, derDirectoryName),
     88      SEC_ASN1_SUB(SEC_AnyTemplate), sizeof(CERTGeneralName) }
     89 };
     90 
     91 static const SEC_ASN1Template CERT_EDIPartyNameTemplate[] = {
     92    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 5,
     93      offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate),
     94      sizeof(CERTGeneralName) }
     95 };
     96 
     97 static const SEC_ASN1Template CERT_URITemplate[] = {
     98    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 6,
     99      offsetof(CERTGeneralName, name.other),
    100      SEC_ASN1_SUB(SEC_IA5StringTemplate), sizeof(CERTGeneralName) }
    101 };
    102 
    103 static const SEC_ASN1Template CERT_IPAddressTemplate[] = {
    104    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 7,
    105      offsetof(CERTGeneralName, name.other),
    106      SEC_ASN1_SUB(SEC_OctetStringTemplate), sizeof(CERTGeneralName) }
    107 };
    108 
    109 static const SEC_ASN1Template CERT_RegisteredIDTemplate[] = {
    110    { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 8,
    111      offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_ObjectIDTemplate),
    112      sizeof(CERTGeneralName) }
    113 };
    114 
    115 const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
    116    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) }
    117 };
    118 
    119 static struct {
    120    CERTGeneralNameType type;
    121    char *name;
    122 } typesArray[] = { { certOtherName, "other" },
    123                   { certRFC822Name, "email" },
    124                   { certRFC822Name, "rfc822" },
    125                   { certDNSName, "dns" },
    126                   { certX400Address, "x400" },
    127                   { certX400Address, "x400addr" },
    128                   { certDirectoryName, "directory" },
    129                   { certDirectoryName, "dn" },
    130                   { certEDIPartyName, "edi" },
    131                   { certEDIPartyName, "ediparty" },
    132                   { certURI, "uri" },
    133                   { certIPAddress, "ip" },
    134                   { certIPAddress, "ipaddr" },
    135                   { certRegisterID, "registerid" } };
    136 
    137 CERTGeneralNameType
    138 CERT_GetGeneralNameTypeFromString(const char *string)
    139 {
    140    int types_count = sizeof(typesArray) / sizeof(typesArray[0]);
    141    int i;
    142 
    143    for (i = 0; i < types_count; i++) {
    144        if (PORT_Strcasecmp(string, typesArray[i].name) == 0) {
    145            return typesArray[i].type;
    146        }
    147    }
    148    return 0;
    149 }
    150 
    151 CERTGeneralName *
    152 CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type)
    153 {
    154    CERTGeneralName *name = arena ? PORT_ArenaZNew(arena, CERTGeneralName)
    155                                  : PORT_ZNew(CERTGeneralName);
    156    if (name) {
    157        name->type = type;
    158        name->l.prev = name->l.next = &name->l;
    159    }
    160    return name;
    161 }
    162 
    163 /* Copy content of one General Name to another.
    164 ** Caller has allocated destination general name.
    165 ** This function does not change the destinate's GeneralName's list linkage.
    166 */
    167 SECStatus
    168 cert_CopyOneGeneralName(PLArenaPool *arena, CERTGeneralName *dest,
    169                        CERTGeneralName *src)
    170 {
    171    SECStatus rv;
    172    void *mark = NULL;
    173 
    174    PORT_Assert(dest != NULL);
    175    dest->type = src->type;
    176 
    177    mark = PORT_ArenaMark(arena);
    178 
    179    switch (src->type) {
    180        case certDirectoryName:
    181            rv = SECITEM_CopyItem(arena, &dest->derDirectoryName,
    182                                  &src->derDirectoryName);
    183            if (rv == SECSuccess)
    184                rv = CERT_CopyName(arena, &dest->name.directoryName,
    185                                   &src->name.directoryName);
    186            break;
    187 
    188        case certOtherName:
    189            rv = SECITEM_CopyItem(arena, &dest->name.OthName.name,
    190                                  &src->name.OthName.name);
    191            if (rv == SECSuccess)
    192                rv = SECITEM_CopyItem(arena, &dest->name.OthName.oid,
    193                                      &src->name.OthName.oid);
    194            break;
    195 
    196        default:
    197            rv = SECITEM_CopyItem(arena, &dest->name.other, &src->name.other);
    198            break;
    199    }
    200    if (rv != SECSuccess) {
    201        PORT_ArenaRelease(arena, mark);
    202    } else {
    203        PORT_ArenaUnmark(arena, mark);
    204    }
    205    return rv;
    206 }
    207 
    208 void
    209 CERT_DestroyGeneralNameList(CERTGeneralNameList *list)
    210 {
    211    PZLock *lock;
    212 
    213    if (list != NULL) {
    214        lock = list->lock;
    215        PZ_Lock(lock);
    216        if (--list->refCount <= 0 && list->arena != NULL) {
    217            PORT_FreeArena(list->arena, PR_FALSE);
    218            PZ_Unlock(lock);
    219            PZ_DestroyLock(lock);
    220        } else {
    221            PZ_Unlock(lock);
    222        }
    223    }
    224    return;
    225 }
    226 
    227 CERTGeneralNameList *
    228 CERT_CreateGeneralNameList(CERTGeneralName *name)
    229 {
    230    PLArenaPool *arena;
    231    CERTGeneralNameList *list = NULL;
    232 
    233    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    234    if (arena == NULL) {
    235        goto done;
    236    }
    237    list = PORT_ArenaZNew(arena, CERTGeneralNameList);
    238    if (!list)
    239        goto loser;
    240    if (name != NULL) {
    241        SECStatus rv;
    242        list->name = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
    243        if (!list->name)
    244            goto loser;
    245        rv = CERT_CopyGeneralName(arena, list->name, name);
    246        if (rv != SECSuccess)
    247            goto loser;
    248    }
    249    list->lock = PZ_NewLock(nssILockList);
    250    if (!list->lock)
    251        goto loser;
    252    list->arena = arena;
    253    list->refCount = 1;
    254 done:
    255    return list;
    256 
    257 loser:
    258    PORT_FreeArena(arena, PR_FALSE);
    259    return NULL;
    260 }
    261 
    262 CERTGeneralName *
    263 CERT_GetNextGeneralName(CERTGeneralName *current)
    264 {
    265    PRCList *next;
    266 
    267    next = current->l.next;
    268    return (CERTGeneralName *)(((char *)next) - offsetof(CERTGeneralName, l));
    269 }
    270 
    271 CERTGeneralName *
    272 CERT_GetPrevGeneralName(CERTGeneralName *current)
    273 {
    274    PRCList *prev;
    275    prev = current->l.prev;
    276    return (CERTGeneralName *)(((char *)prev) - offsetof(CERTGeneralName, l));
    277 }
    278 
    279 CERTNameConstraint *
    280 CERT_GetNextNameConstraint(CERTNameConstraint *current)
    281 {
    282    PRCList *next;
    283 
    284    next = current->l.next;
    285    return (CERTNameConstraint *)(((char *)next) -
    286                                  offsetof(CERTNameConstraint, l));
    287 }
    288 
    289 CERTNameConstraint *
    290 CERT_GetPrevNameConstraint(CERTNameConstraint *current)
    291 {
    292    PRCList *prev;
    293    prev = current->l.prev;
    294    return (CERTNameConstraint *)(((char *)prev) -
    295                                  offsetof(CERTNameConstraint, l));
    296 }
    297 
    298 SECItem *
    299 CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest,
    300                       PLArenaPool *arena)
    301 {
    302 
    303    const SEC_ASN1Template *template;
    304 
    305    PORT_Assert(arena);
    306    if (arena == NULL || !genName) {
    307        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    308        return NULL;
    309    }
    310    /* TODO: mark arena */
    311    if (dest == NULL) {
    312        dest = PORT_ArenaZNew(arena, SECItem);
    313        if (!dest)
    314            goto loser;
    315    }
    316    if (genName->type == certDirectoryName) {
    317        if (genName->derDirectoryName.data == NULL) {
    318            /* The field hasn't been encoded yet. */
    319            SECItem *pre_dest = SEC_ASN1EncodeItem(
    320                arena, &(genName->derDirectoryName),
    321                &(genName->name.directoryName), CERT_NameTemplate);
    322            if (!pre_dest)
    323                goto loser;
    324        }
    325        if (genName->derDirectoryName.data == NULL) {
    326            goto loser;
    327        }
    328    }
    329    switch (genName->type) {
    330        case certURI:
    331            template = CERT_URITemplate;
    332            break;
    333        case certRFC822Name:
    334            template = CERT_RFC822NameTemplate;
    335            break;
    336        case certDNSName:
    337            template = CERT_DNSNameTemplate;
    338            break;
    339        case certIPAddress:
    340            template = CERT_IPAddressTemplate;
    341            break;
    342        case certOtherName:
    343            template = CERTOtherNameTemplate;
    344            break;
    345        case certRegisterID:
    346            template = CERT_RegisteredIDTemplate;
    347            break;
    348        /* for this type, we expect the value is already encoded */
    349        case certEDIPartyName:
    350            template = CERT_EDIPartyNameTemplate;
    351            break;
    352        /* for this type, we expect the value is already encoded */
    353        case certX400Address:
    354            template = CERT_X400AddressTemplate;
    355            break;
    356        case certDirectoryName:
    357            template = CERT_DirectoryNameTemplate;
    358            break;
    359        default:
    360            PORT_Assert(0);
    361            goto loser;
    362    }
    363    dest = SEC_ASN1EncodeItem(arena, dest, genName, template);
    364    if (!dest) {
    365        goto loser;
    366    }
    367    /* TODO: unmark arena */
    368    return dest;
    369 loser:
    370    /* TODO: release arena back to mark */
    371    return NULL;
    372 }
    373 
    374 SECItem **
    375 cert_EncodeGeneralNames(PLArenaPool *arena, CERTGeneralName *names)
    376 {
    377    CERTGeneralName *current_name;
    378    SECItem **items = NULL;
    379    int count = 1;
    380    int i;
    381    PRCList *head;
    382 
    383    if (!names) {
    384        return NULL;
    385    }
    386 
    387    PORT_Assert(arena);
    388    /* TODO: mark arena */
    389    current_name = names;
    390    head = &(names->l);
    391    while (current_name->l.next != head) {
    392        current_name = CERT_GetNextGeneralName(current_name);
    393        ++count;
    394    }
    395    current_name = CERT_GetNextGeneralName(current_name);
    396    items = PORT_ArenaNewArray(arena, SECItem *, count + 1);
    397    if (items == NULL) {
    398        goto loser;
    399    }
    400    for (i = 0; i < count; i++) {
    401        items[i] = CERT_EncodeGeneralName(current_name, (SECItem *)NULL, arena);
    402        if (items[i] == NULL) {
    403            goto loser;
    404        }
    405        current_name = CERT_GetNextGeneralName(current_name);
    406    }
    407    items[i] = NULL;
    408    /* TODO: unmark arena */
    409    return items;
    410 loser:
    411    /* TODO: release arena to mark */
    412    return NULL;
    413 }
    414 
    415 CERTGeneralName *
    416 CERT_DecodeGeneralName(PLArenaPool *reqArena, SECItem *encodedName,
    417                       CERTGeneralName *genName)
    418 {
    419    const SEC_ASN1Template *template;
    420    CERTGeneralNameType genNameType;
    421    SECStatus rv = SECSuccess;
    422    SECItem *newEncodedName;
    423 
    424    if (!reqArena) {
    425        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    426        return NULL;
    427    }
    428    /* make a copy for decoding so the data decoded with QuickDER doesn't
    429       point to temporary memory */
    430    newEncodedName = SECITEM_ArenaDupItem(reqArena, encodedName);
    431    if (!newEncodedName) {
    432        return NULL;
    433    }
    434    /* TODO: mark arena */
    435    genNameType = (CERTGeneralNameType)((*(newEncodedName->data) & 0x0f) + 1);
    436    if (genName == NULL) {
    437        genName = CERT_NewGeneralName(reqArena, genNameType);
    438        if (!genName)
    439            goto loser;
    440    } else {
    441        genName->type = genNameType;
    442        genName->l.prev = genName->l.next = &genName->l;
    443    }
    444 
    445    switch (genNameType) {
    446        case certURI:
    447            template = CERT_URITemplate;
    448            break;
    449        case certRFC822Name:
    450            template = CERT_RFC822NameTemplate;
    451            break;
    452        case certDNSName:
    453            template = CERT_DNSNameTemplate;
    454            break;
    455        case certIPAddress:
    456            template = CERT_IPAddressTemplate;
    457            break;
    458        case certOtherName:
    459            template = CERTOtherNameTemplate;
    460            break;
    461        case certRegisterID:
    462            template = CERT_RegisteredIDTemplate;
    463            break;
    464        case certEDIPartyName:
    465            template = CERT_EDIPartyNameTemplate;
    466            break;
    467        case certX400Address:
    468            template = CERT_X400AddressTemplate;
    469            break;
    470        case certDirectoryName:
    471            template = CERT_DirectoryNameTemplate;
    472            break;
    473        default:
    474            goto loser;
    475    }
    476    rv = SEC_QuickDERDecodeItem(reqArena, genName, template, newEncodedName);
    477    if (rv != SECSuccess)
    478        goto loser;
    479    if (genNameType == certDirectoryName) {
    480        rv = SEC_QuickDERDecodeItem(reqArena, &(genName->name.directoryName),
    481                                    CERT_NameTemplate,
    482                                    &(genName->derDirectoryName));
    483        if (rv != SECSuccess)
    484            goto loser;
    485    }
    486 
    487    /* TODO: unmark arena */
    488    return genName;
    489 loser:
    490    /* TODO: release arena to mark */
    491    return NULL;
    492 }
    493 
    494 CERTGeneralName *
    495 cert_DecodeGeneralNames(PLArenaPool *arena, SECItem **encodedGenName)
    496 {
    497    PRCList *head = NULL;
    498    PRCList *tail = NULL;
    499    CERTGeneralName *currentName = NULL;
    500 
    501    PORT_Assert(arena);
    502    if (!encodedGenName || !arena) {
    503        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    504        return NULL;
    505    }
    506    /* TODO: mark arena */
    507    while (*encodedGenName != NULL) {
    508        currentName = CERT_DecodeGeneralName(arena, *encodedGenName, NULL);
    509        if (currentName == NULL)
    510            break;
    511        if (head == NULL) {
    512            head = &(currentName->l);
    513            tail = head;
    514        }
    515        currentName->l.next = head;
    516        currentName->l.prev = tail;
    517        tail = head->prev = tail->next = &(currentName->l);
    518        encodedGenName++;
    519    }
    520    if (currentName) {
    521        /* TODO: unmark arena */
    522        return CERT_GetNextGeneralName(currentName);
    523    }
    524    /* TODO: release arena to mark */
    525    return NULL;
    526 }
    527 
    528 void
    529 CERT_DestroyGeneralName(CERTGeneralName *name)
    530 {
    531    cert_DestroyGeneralNames(name);
    532 }
    533 
    534 SECStatus
    535 cert_DestroyGeneralNames(CERTGeneralName *name)
    536 {
    537    CERTGeneralName *first;
    538    CERTGeneralName *next = NULL;
    539 
    540    first = name;
    541    do {
    542        next = CERT_GetNextGeneralName(name);
    543        PORT_Free(name);
    544        name = next;
    545    } while (name != first);
    546    return SECSuccess;
    547 }
    548 
    549 static SECItem *
    550 cert_EncodeNameConstraint(CERTNameConstraint *constraint, SECItem *dest,
    551                          PLArenaPool *arena)
    552 {
    553    PORT_Assert(arena);
    554    if (dest == NULL) {
    555        dest = PORT_ArenaZNew(arena, SECItem);
    556        if (dest == NULL) {
    557            return NULL;
    558        }
    559    }
    560    CERT_EncodeGeneralName(&(constraint->name), &(constraint->DERName), arena);
    561 
    562    dest =
    563        SEC_ASN1EncodeItem(arena, dest, constraint, CERTNameConstraintTemplate);
    564    return dest;
    565 }
    566 
    567 SECStatus
    568 cert_EncodeNameConstraintSubTree(CERTNameConstraint *constraints,
    569                                 PLArenaPool *arena, SECItem ***dest,
    570                                 PRBool permited)
    571 {
    572    CERTNameConstraint *current_constraint = constraints;
    573    SECItem **items = NULL;
    574    int count = 0;
    575    int i;
    576    PRCList *head;
    577 
    578    PORT_Assert(arena);
    579    /* TODO: mark arena */
    580    if (constraints != NULL) {
    581        count = 1;
    582    }
    583    head = &constraints->l;
    584    while (current_constraint->l.next != head) {
    585        current_constraint = CERT_GetNextNameConstraint(current_constraint);
    586        ++count;
    587    }
    588    current_constraint = CERT_GetNextNameConstraint(current_constraint);
    589    items = PORT_ArenaZNewArray(arena, SECItem *, count + 1);
    590    if (items == NULL) {
    591        goto loser;
    592    }
    593    for (i = 0; i < count; i++) {
    594        items[i] = cert_EncodeNameConstraint(current_constraint,
    595                                             (SECItem *)NULL, arena);
    596        if (items[i] == NULL) {
    597            goto loser;
    598        }
    599        current_constraint = CERT_GetNextNameConstraint(current_constraint);
    600    }
    601    *dest = items;
    602    if (*dest == NULL) {
    603        goto loser;
    604    }
    605    /* TODO: unmark arena */
    606    return SECSuccess;
    607 loser:
    608    /* TODO: release arena to mark */
    609    return SECFailure;
    610 }
    611 
    612 SECStatus
    613 cert_EncodeNameConstraints(CERTNameConstraints *constraints, PLArenaPool *arena,
    614                           SECItem *dest)
    615 {
    616    SECStatus rv = SECSuccess;
    617 
    618    PORT_Assert(arena);
    619    /* TODO: mark arena */
    620    if (constraints->permited != NULL) {
    621        rv = cert_EncodeNameConstraintSubTree(
    622            constraints->permited, arena, &constraints->DERPermited, PR_TRUE);
    623        if (rv == SECFailure) {
    624            goto loser;
    625        }
    626    }
    627    if (constraints->excluded != NULL) {
    628        rv = cert_EncodeNameConstraintSubTree(
    629            constraints->excluded, arena, &constraints->DERExcluded, PR_FALSE);
    630        if (rv == SECFailure) {
    631            goto loser;
    632        }
    633    }
    634    dest = SEC_ASN1EncodeItem(arena, dest, constraints,
    635                              CERTNameConstraintsTemplate);
    636    if (dest == NULL) {
    637        goto loser;
    638    }
    639    /* TODO: unmark arena */
    640    return SECSuccess;
    641 loser:
    642    /* TODO: release arena to mark */
    643    return SECFailure;
    644 }
    645 
    646 CERTNameConstraint *
    647 cert_DecodeNameConstraint(PLArenaPool *reqArena, SECItem *encodedConstraint)
    648 {
    649    CERTNameConstraint *constraint;
    650    SECStatus rv = SECSuccess;
    651    CERTGeneralName *temp;
    652    SECItem *newEncodedConstraint;
    653 
    654    if (!reqArena) {
    655        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    656        return NULL;
    657    }
    658    newEncodedConstraint = SECITEM_ArenaDupItem(reqArena, encodedConstraint);
    659    if (!newEncodedConstraint) {
    660        return NULL;
    661    }
    662    /* TODO: mark arena */
    663    constraint = PORT_ArenaZNew(reqArena, CERTNameConstraint);
    664    if (!constraint)
    665        goto loser;
    666    rv = SEC_QuickDERDecodeItem(
    667        reqArena, constraint, CERTNameConstraintTemplate, newEncodedConstraint);
    668    if (rv != SECSuccess) {
    669        goto loser;
    670    }
    671    temp = CERT_DecodeGeneralName(reqArena, &(constraint->DERName),
    672                                  &(constraint->name));
    673    if (temp != &(constraint->name)) {
    674        goto loser;
    675    }
    676 
    677    /* ### sjlee: since the name constraint contains only one
    678     *            CERTGeneralName, the list within CERTGeneralName shouldn't
    679     *            point anywhere else.  Otherwise, bad things will happen.
    680     */
    681    constraint->name.l.prev = constraint->name.l.next = &(constraint->name.l);
    682    /* TODO: unmark arena */
    683    return constraint;
    684 loser:
    685    /* TODO: release arena back to mark */
    686    return NULL;
    687 }
    688 
    689 static CERTNameConstraint *
    690 cert_DecodeNameConstraintSubTree(PLArenaPool *arena, SECItem **subTree,
    691                                 PRBool permited)
    692 {
    693    CERTNameConstraint *current = NULL;
    694    CERTNameConstraint *first = NULL;
    695    CERTNameConstraint *last = NULL;
    696    int i = 0;
    697 
    698    PORT_Assert(arena);
    699    /* TODO: mark arena */
    700    while (subTree[i] != NULL) {
    701        current = cert_DecodeNameConstraint(arena, subTree[i]);
    702        if (current == NULL) {
    703            goto loser;
    704        }
    705        if (first == NULL) {
    706            first = current;
    707        } else {
    708            current->l.prev = &(last->l);
    709            last->l.next = &(current->l);
    710        }
    711        last = current;
    712        i++;
    713    }
    714    if (first && last) {
    715        first->l.prev = &(last->l);
    716        last->l.next = &(first->l);
    717    }
    718    /* TODO: unmark arena */
    719    return first;
    720 loser:
    721    /* TODO: release arena back to mark */
    722    return NULL;
    723 }
    724 
    725 CERTNameConstraints *
    726 cert_DecodeNameConstraints(PLArenaPool *reqArena,
    727                           const SECItem *encodedConstraints)
    728 {
    729    CERTNameConstraints *constraints;
    730    SECStatus rv;
    731    SECItem *newEncodedConstraints;
    732 
    733    if (!reqArena) {
    734        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    735        return NULL;
    736    }
    737    PORT_Assert(encodedConstraints);
    738    newEncodedConstraints = SECITEM_ArenaDupItem(reqArena, encodedConstraints);
    739 
    740    /* TODO: mark arena */
    741    constraints = PORT_ArenaZNew(reqArena, CERTNameConstraints);
    742    if (constraints == NULL) {
    743        goto loser;
    744    }
    745    rv = SEC_QuickDERDecodeItem(reqArena, constraints,
    746                                CERTNameConstraintsTemplate,
    747                                newEncodedConstraints);
    748    if (rv != SECSuccess) {
    749        goto loser;
    750    }
    751    if (constraints->DERPermited != NULL &&
    752        constraints->DERPermited[0] != NULL) {
    753        constraints->permited = cert_DecodeNameConstraintSubTree(
    754            reqArena, constraints->DERPermited, PR_TRUE);
    755        if (constraints->permited == NULL) {
    756            goto loser;
    757        }
    758    }
    759    if (constraints->DERExcluded != NULL &&
    760        constraints->DERExcluded[0] != NULL) {
    761        constraints->excluded = cert_DecodeNameConstraintSubTree(
    762            reqArena, constraints->DERExcluded, PR_FALSE);
    763        if (constraints->excluded == NULL) {
    764            goto loser;
    765        }
    766    }
    767    /* TODO: unmark arena */
    768    return constraints;
    769 loser:
    770    /* TODO: release arena back to mark */
    771    return NULL;
    772 }
    773 
    774 /* Copy a chain of one or more general names to a destination chain.
    775 ** Caller has allocated at least the first destination GeneralName struct.
    776 ** Both source and destination chains are circular doubly-linked lists.
    777 ** The first source struct is copied to the first destination struct.
    778 ** If the source chain has more than one member, and the destination chain
    779 ** has only one member, then this function allocates new structs for all but
    780 ** the first copy from the arena and links them into the destination list.
    781 ** If the destination struct is part of a list with more than one member,
    782 ** then this function traverses both the source and destination lists,
    783 ** copying each source struct to the corresponding dest struct.
    784 ** In that case, the destination list MUST contain at least as many
    785 ** structs as the source list or some dest entries will be overwritten.
    786 */
    787 SECStatus
    788 CERT_CopyGeneralName(PLArenaPool *arena, CERTGeneralName *dest,
    789                     CERTGeneralName *src)
    790 {
    791    SECStatus rv;
    792    CERTGeneralName *destHead = dest;
    793    CERTGeneralName *srcHead = src;
    794 
    795    PORT_Assert(dest != NULL);
    796    if (!dest) {
    797        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    798        return SECFailure;
    799    }
    800    /* TODO: mark arena */
    801    do {
    802        rv = cert_CopyOneGeneralName(arena, dest, src);
    803        if (rv != SECSuccess)
    804            goto loser;
    805        src = CERT_GetNextGeneralName(src);
    806        /* if there is only one general name, we shouldn't do this */
    807        if (src != srcHead) {
    808            if (dest->l.next == &destHead->l) {
    809                CERTGeneralName *temp;
    810                temp = CERT_NewGeneralName(arena, (CERTGeneralNameType)0);
    811                if (!temp)
    812                    goto loser;
    813                temp->l.next = &destHead->l;
    814                temp->l.prev = &dest->l;
    815                destHead->l.prev = &temp->l;
    816                dest->l.next = &temp->l;
    817                dest = temp;
    818            } else {
    819                dest = CERT_GetNextGeneralName(dest);
    820            }
    821        }
    822    } while (src != srcHead && rv == SECSuccess);
    823    /* TODO: unmark arena */
    824    return rv;
    825 loser:
    826    /* TODO: release back to mark */
    827    return SECFailure;
    828 }
    829 
    830 CERTGeneralNameList *
    831 CERT_DupGeneralNameList(CERTGeneralNameList *list)
    832 {
    833    if (list != NULL) {
    834        PZ_Lock(list->lock);
    835        list->refCount++;
    836        PZ_Unlock(list->lock);
    837    }
    838    return list;
    839 }
    840 
    841 /* Allocate space and copy CERTNameConstraint from src to dest */
    842 CERTNameConstraint *
    843 CERT_CopyNameConstraint(PLArenaPool *arena, CERTNameConstraint *dest,
    844                        CERTNameConstraint *src)
    845 {
    846    SECStatus rv;
    847 
    848    /* TODO: mark arena */
    849    if (dest == NULL) {
    850        dest = PORT_ArenaZNew(arena, CERTNameConstraint);
    851        if (!dest)
    852            goto loser;
    853        /* mark that it is not linked */
    854        dest->name.l.prev = dest->name.l.next = &(dest->name.l);
    855    }
    856    rv = CERT_CopyGeneralName(arena, &dest->name, &src->name);
    857    if (rv != SECSuccess) {
    858        goto loser;
    859    }
    860    rv = SECITEM_CopyItem(arena, &dest->DERName, &src->DERName);
    861    if (rv != SECSuccess) {
    862        goto loser;
    863    }
    864    rv = SECITEM_CopyItem(arena, &dest->min, &src->min);
    865    if (rv != SECSuccess) {
    866        goto loser;
    867    }
    868    rv = SECITEM_CopyItem(arena, &dest->max, &src->max);
    869    if (rv != SECSuccess) {
    870        goto loser;
    871    }
    872    dest->l.prev = dest->l.next = &dest->l;
    873    /* TODO: unmark arena */
    874    return dest;
    875 loser:
    876    /* TODO: release arena to mark */
    877    return NULL;
    878 }
    879 
    880 CERTGeneralName *
    881 cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2)
    882 {
    883    PRCList *begin1;
    884    PRCList *begin2;
    885    PRCList *end1;
    886    PRCList *end2;
    887 
    888    if (list1 == NULL) {
    889        return list2;
    890    } else if (list2 == NULL) {
    891        return list1;
    892    } else {
    893        begin1 = &list1->l;
    894        begin2 = &list2->l;
    895        end1 = list1->l.prev;
    896        end2 = list2->l.prev;
    897        end1->next = begin2;
    898        end2->next = begin1;
    899        begin1->prev = end2;
    900        begin2->prev = end1;
    901        return list1;
    902    }
    903 }
    904 
    905 CERTNameConstraint *
    906 cert_CombineConstraintsLists(CERTNameConstraint *list1,
    907                             CERTNameConstraint *list2)
    908 {
    909    PRCList *begin1;
    910    PRCList *begin2;
    911    PRCList *end1;
    912    PRCList *end2;
    913 
    914    if (list1 == NULL) {
    915        return list2;
    916    } else if (list2 == NULL) {
    917        return list1;
    918    } else {
    919        begin1 = &list1->l;
    920        begin2 = &list2->l;
    921        end1 = list1->l.prev;
    922        end2 = list2->l.prev;
    923        end1->next = begin2;
    924        end2->next = begin1;
    925        begin1->prev = end2;
    926        begin2->prev = end1;
    927        return list1;
    928    }
    929 }
    930 
    931 /* Add a CERTNameConstraint to the CERTNameConstraint list */
    932 CERTNameConstraint *
    933 CERT_AddNameConstraint(CERTNameConstraint *list, CERTNameConstraint *constraint)
    934 {
    935    PORT_Assert(constraint != NULL);
    936    constraint->l.next = constraint->l.prev = &constraint->l;
    937    list = cert_CombineConstraintsLists(list, constraint);
    938    return list;
    939 }
    940 
    941 SECStatus
    942 CERT_GetNameConstraintByType(CERTNameConstraint *constraints,
    943                             CERTGeneralNameType type,
    944                             CERTNameConstraint **returnList,
    945                             PLArenaPool *arena)
    946 {
    947    CERTNameConstraint *current = NULL;
    948    void *mark = NULL;
    949 
    950    *returnList = NULL;
    951    if (!constraints)
    952        return SECSuccess;
    953 
    954    mark = PORT_ArenaMark(arena);
    955 
    956    current = constraints;
    957    do {
    958        PORT_Assert(current->name.type);
    959        if (current->name.type == type) {
    960            CERTNameConstraint *temp;
    961            temp = CERT_CopyNameConstraint(arena, NULL, current);
    962            if (temp == NULL)
    963                goto loser;
    964            *returnList = CERT_AddNameConstraint(*returnList, temp);
    965        }
    966        current = CERT_GetNextNameConstraint(current);
    967    } while (current != constraints);
    968    PORT_ArenaUnmark(arena, mark);
    969    return SECSuccess;
    970 
    971 loser:
    972    PORT_ArenaRelease(arena, mark);
    973    return SECFailure;
    974 }
    975 
    976 void *
    977 CERT_GetGeneralNameByType(CERTGeneralName *genNames, CERTGeneralNameType type,
    978                          PRBool derFormat)
    979 {
    980    CERTGeneralName *current;
    981 
    982    if (!genNames)
    983        return NULL;
    984    current = genNames;
    985 
    986    do {
    987        if (current->type == type) {
    988            switch (type) {
    989                case certDNSName:
    990                case certEDIPartyName:
    991                case certIPAddress:
    992                case certRegisterID:
    993                case certRFC822Name:
    994                case certX400Address:
    995                case certURI:
    996                    return (void *)&current->name.other; /* SECItem * */
    997 
    998                case certOtherName:
    999                    return (void *)&current->name.OthName; /* OthName * */
   1000 
   1001                case certDirectoryName:
   1002                    return derFormat
   1003                               ? (void *)&current
   1004                                     ->derDirectoryName /* SECItem * */
   1005                               : (void *)&current->name
   1006                                     .directoryName; /* CERTName * */
   1007            }
   1008            PORT_Assert(0);
   1009            return NULL;
   1010        }
   1011        current = CERT_GetNextGeneralName(current);
   1012    } while (current != genNames);
   1013    return NULL;
   1014 }
   1015 
   1016 int
   1017 CERT_GetNamesLength(CERTGeneralName *names)
   1018 {
   1019    int length = 0;
   1020    CERTGeneralName *first;
   1021 
   1022    first = names;
   1023    if (names != NULL) {
   1024        do {
   1025            length++;
   1026            names = CERT_GetNextGeneralName(names);
   1027        } while (names != first);
   1028    }
   1029    return length;
   1030 }
   1031 
   1032 /* Creates new GeneralNames for any email addresses found in the
   1033 ** input DN, and links them onto the list for the DN.
   1034 */
   1035 SECStatus
   1036 cert_ExtractDNEmailAddrs(CERTGeneralName *name, PLArenaPool *arena)
   1037 {
   1038    CERTGeneralName *nameList = NULL;
   1039    const CERTRDN **nRDNs = (const CERTRDN **)(name->name.directoryName.rdns);
   1040    SECStatus rv = SECSuccess;
   1041 
   1042    PORT_Assert(name->type == certDirectoryName);
   1043    if (name->type != certDirectoryName) {
   1044        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1045        return SECFailure;
   1046    }
   1047    /* TODO: mark arena */
   1048    while (nRDNs && *nRDNs) { /* loop over RDNs */
   1049        const CERTRDN *nRDN = *nRDNs++;
   1050        CERTAVA **nAVAs = nRDN->avas;
   1051        while (nAVAs && *nAVAs) { /* loop over AVAs */
   1052            int tag;
   1053            CERTAVA *nAVA = *nAVAs++;
   1054            tag = CERT_GetAVATag(nAVA);
   1055            if (tag == SEC_OID_PKCS9_EMAIL_ADDRESS ||
   1056                tag == SEC_OID_RFC1274_MAIL) { /* email AVA */
   1057                CERTGeneralName *newName = NULL;
   1058                SECItem *avaValue = CERT_DecodeAVAValue(&nAVA->value);
   1059                if (!avaValue)
   1060                    goto loser;
   1061                rv = SECFailure;
   1062                newName = CERT_NewGeneralName(arena, certRFC822Name);
   1063                if (newName) {
   1064                    rv =
   1065                        SECITEM_CopyItem(arena, &newName->name.other, avaValue);
   1066                }
   1067                SECITEM_FreeItem(avaValue, PR_TRUE);
   1068                if (rv != SECSuccess)
   1069                    goto loser;
   1070                nameList = cert_CombineNamesLists(nameList, newName);
   1071            } /* handle one email AVA */
   1072        }     /* loop over AVAs */
   1073    }         /* loop over RDNs */
   1074    /* combine new names with old one. */
   1075    (void)cert_CombineNamesLists(name, nameList);
   1076    /* TODO: unmark arena */
   1077    return SECSuccess;
   1078 
   1079 loser:
   1080    /* TODO: release arena back to mark */
   1081    return SECFailure;
   1082 }
   1083 
   1084 /* Extract all names except Subject Common Name from a cert
   1085 ** in preparation for a name constraints test.
   1086 */
   1087 CERTGeneralName *
   1088 CERT_GetCertificateNames(CERTCertificate *cert, PLArenaPool *arena)
   1089 {
   1090    return CERT_GetConstrainedCertificateNames(cert, arena, PR_FALSE);
   1091 }
   1092 
   1093 /* This function is called by CERT_VerifyCertChain to extract all
   1094 ** names from a cert in preparation for a name constraints test.
   1095 */
   1096 CERTGeneralName *
   1097 CERT_GetConstrainedCertificateNames(const CERTCertificate *cert,
   1098                                    PLArenaPool *arena,
   1099                                    PRBool includeSubjectCommonName)
   1100 {
   1101    CERTGeneralName *DN;
   1102    CERTGeneralName *SAN;
   1103    PRUint32 numDNSNames = 0;
   1104    SECStatus rv;
   1105 
   1106    if (!arena) {
   1107        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1108        return NULL;
   1109    }
   1110    /* TODO: mark arena */
   1111    DN = CERT_NewGeneralName(arena, certDirectoryName);
   1112    if (DN == NULL) {
   1113        goto loser;
   1114    }
   1115    rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject);
   1116    if (rv != SECSuccess) {
   1117        goto loser;
   1118    }
   1119    rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject);
   1120    if (rv != SECSuccess) {
   1121        goto loser;
   1122    }
   1123    /* Extract email addresses from DN, construct CERTGeneralName structs
   1124    ** for them, add them to the name list
   1125    */
   1126    rv = cert_ExtractDNEmailAddrs(DN, arena);
   1127    if (rv != SECSuccess)
   1128        goto loser;
   1129 
   1130    /* Now extract any GeneralNames from the subject name names extension. */
   1131    SAN = cert_GetSubjectAltNameList(cert, arena);
   1132    if (SAN) {
   1133        numDNSNames = cert_CountDNSPatterns(SAN);
   1134        DN = cert_CombineNamesLists(DN, SAN);
   1135    }
   1136    if (!numDNSNames && includeSubjectCommonName) {
   1137        char *cn = CERT_GetCommonName(&cert->subject);
   1138        if (cn) {
   1139            CERTGeneralName *CN = CERT_NewGeneralName(arena, certDNSName);
   1140            if (CN) {
   1141                SECItem cnItem = { siBuffer, NULL, 0 };
   1142                cnItem.data = (unsigned char *)cn;
   1143                cnItem.len = strlen(cn);
   1144                rv = SECITEM_CopyItem(arena, &CN->name.other, &cnItem);
   1145                if (rv == SECSuccess) {
   1146                    DN = cert_CombineNamesLists(DN, CN);
   1147                }
   1148            }
   1149            PORT_Free(cn);
   1150        }
   1151    }
   1152    if (rv == SECSuccess) {
   1153        /* TODO: unmark arena */
   1154        return DN;
   1155    }
   1156 loser:
   1157    /* TODO: release arena to mark */
   1158    return NULL;
   1159 }
   1160 
   1161 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for
   1162 ** URI name constraints.  SECFailure otherwise.
   1163 ** If the constraint begins with a dot, it is a domain name, otherwise
   1164 ** It is a host name.  Examples:
   1165 **  Constraint            Name             Result
   1166 ** ------------      ---------------      --------
   1167 **  foo.bar.com          foo.bar.com      matches
   1168 **  foo.bar.com          FoO.bAr.CoM      matches
   1169 **  foo.bar.com      www.foo.bar.com      no match
   1170 **  foo.bar.com        nofoo.bar.com      no match
   1171 ** .foo.bar.com      www.foo.bar.com      matches
   1172 ** .foo.bar.com        nofoo.bar.com      no match
   1173 ** .foo.bar.com          foo.bar.com      no match
   1174 ** .foo.bar.com     www..foo.bar.com      no match
   1175 */
   1176 static SECStatus
   1177 compareURIN2C(const SECItem *name, const SECItem *constraint)
   1178 {
   1179    int offset;
   1180    /* The spec is silent on intepreting zero-length constraints.
   1181    ** We interpret them as matching no URI names.
   1182    */
   1183    if (!constraint->len)
   1184        return SECFailure;
   1185    if (constraint->data[0] != '.') {
   1186        /* constraint is a host name. */
   1187        if (name->len != constraint->len ||
   1188            PL_strncasecmp((char *)name->data, (char *)constraint->data,
   1189                           constraint->len))
   1190            return SECFailure;
   1191        return SECSuccess;
   1192    }
   1193    /* constraint is a domain name. */
   1194    if (name->len < constraint->len)
   1195        return SECFailure;
   1196    offset = name->len - constraint->len;
   1197    if (PL_strncasecmp((char *)(name->data + offset), (char *)constraint->data,
   1198                       constraint->len))
   1199        return SECFailure;
   1200    if (!offset ||
   1201        (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
   1202        return SECSuccess;
   1203    return SECFailure;
   1204 }
   1205 
   1206 /* for DNSname constraints, RFC 3280 says, (section 4.2.1.11, page 38)
   1207 **
   1208 ** DNS name restrictions are expressed as foo.bar.com.  Any DNS name
   1209 ** that can be constructed by simply adding to the left hand side of the
   1210 ** name satisfies the name constraint.  For example, www.foo.bar.com
   1211 ** would satisfy the constraint but foo1.bar.com would not.
   1212 **
   1213 ** But NIST's PKITS test suite requires that the constraint be treated
   1214 ** as a domain name, and requires that any name added to the left hand
   1215 ** side end in a dot ".".  Sensible, but not strictly following the RFC.
   1216 **
   1217 **  Constraint            Name            RFC 3280  NIST PKITS
   1218 ** ------------      ---------------      --------  ----------
   1219 **  foo.bar.com          foo.bar.com      matches    matches
   1220 **  foo.bar.com          FoO.bAr.CoM      matches    matches
   1221 **  foo.bar.com      www.foo.bar.com      matches    matches
   1222 **  foo.bar.com        nofoo.bar.com      MATCHES    NO MATCH
   1223 ** .foo.bar.com      www.foo.bar.com      matches    matches? disallowed?
   1224 ** .foo.bar.com          foo.bar.com      no match   no match
   1225 ** .foo.bar.com     www..foo.bar.com      matches    probably not
   1226 **
   1227 ** We will try to conform to NIST's PKITS tests, and the unstated
   1228 ** rules they imply.
   1229 */
   1230 static SECStatus
   1231 compareDNSN2C(const SECItem *name, const SECItem *constraint)
   1232 {
   1233    int offset;
   1234    /* The spec is silent on intepreting zero-length constraints.
   1235    ** We interpret them as matching all DNSnames.
   1236    */
   1237    if (!constraint->len)
   1238        return SECSuccess;
   1239    if (name->len < constraint->len)
   1240        return SECFailure;
   1241    offset = name->len - constraint->len;
   1242    if (PL_strncasecmp((char *)(name->data + offset), (char *)constraint->data,
   1243                       constraint->len))
   1244        return SECFailure;
   1245    if (!offset ||
   1246        (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1)
   1247        return SECSuccess;
   1248    return SECFailure;
   1249 }
   1250 
   1251 /* Returns SECSuccess if name matches constraint per RFC 3280 rules for
   1252 ** internet email addresses.  SECFailure otherwise.
   1253 ** If constraint contains a '@' then the two strings much match exactly.
   1254 ** Else if constraint starts with a '.'. then it must match the right-most
   1255 ** substring of the name,
   1256 ** else constraint string must match entire name after the name's '@'.
   1257 ** Empty constraint string matches all names. All comparisons case insensitive.
   1258 */
   1259 static SECStatus
   1260 compareRFC822N2C(const SECItem *name, const SECItem *constraint)
   1261 {
   1262    int offset;
   1263    if (!constraint->len)
   1264        return SECSuccess;
   1265    if (name->len < constraint->len)
   1266        return SECFailure;
   1267    if (constraint->len == 1 && constraint->data[0] == '.')
   1268        return SECSuccess;
   1269    for (offset = constraint->len - 1; offset >= 0; --offset) {
   1270        if (constraint->data[offset] == '@') {
   1271            return (name->len == constraint->len &&
   1272                    !PL_strncasecmp((char *)name->data,
   1273                                    (char *)constraint->data, constraint->len))
   1274                       ? SECSuccess
   1275                       : SECFailure;
   1276        }
   1277    }
   1278    offset = name->len - constraint->len;
   1279    if (PL_strncasecmp((char *)(name->data + offset), (char *)constraint->data,
   1280                       constraint->len))
   1281        return SECFailure;
   1282    if (constraint->data[0] == '.')
   1283        return SECSuccess;
   1284    if (offset > 0 && name->data[offset - 1] == '@')
   1285        return SECSuccess;
   1286    return SECFailure;
   1287 }
   1288 
   1289 /* name contains either a 4 byte IPv4 address or a 16 byte IPv6 address.
   1290 ** constraint contains an address of the same length, and a subnet mask
   1291 ** of the same length.  Compare name's address to the constraint's
   1292 ** address, subject to the mask.
   1293 ** Return SECSuccess if they match, SECFailure if they don't.
   1294 */
   1295 static SECStatus
   1296 compareIPaddrN2C(const SECItem *name, const SECItem *constraint)
   1297 {
   1298    int i;
   1299    if (name->len == 4 && constraint->len == 8) { /* ipv4 addr */
   1300        for (i = 0; i < 4; i++) {
   1301            if ((name->data[i] ^ constraint->data[i]) & constraint->data[i + 4])
   1302                goto loser;
   1303        }
   1304        return SECSuccess;
   1305    }
   1306    if (name->len == 16 && constraint->len == 32) { /* ipv6 addr */
   1307        for (i = 0; i < 16; i++) {
   1308            if ((name->data[i] ^ constraint->data[i]) &
   1309                constraint->data[i + 16])
   1310                goto loser;
   1311        }
   1312        return SECSuccess;
   1313    }
   1314 loser:
   1315    return SECFailure;
   1316 }
   1317 
   1318 /* start with a SECItem that points to a URI.  Parse it lookingg for
   1319 ** a hostname.  Modify item->data and item->len to define the hostname,
   1320 ** but do not modify and data at item->data.
   1321 ** If anything goes wrong, the contents of *item are undefined.
   1322 */
   1323 static SECStatus
   1324 parseUriHostname(SECItem *item)
   1325 {
   1326    int i;
   1327    PRBool found = PR_FALSE;
   1328    for (i = 0; (unsigned)(i + 2) < item->len; ++i) {
   1329        if (item->data[i] == ':' && item->data[i + 1] == '/' &&
   1330            item->data[i + 2] == '/') {
   1331            i += 3;
   1332            item->data += i;
   1333            item->len -= i;
   1334            found = PR_TRUE;
   1335            break;
   1336        }
   1337    }
   1338    if (!found)
   1339        return SECFailure;
   1340    /* now look for a '/', which is an upper bound in the end of the name */
   1341    for (i = 0; (unsigned)i < item->len; ++i) {
   1342        if (item->data[i] == '/') {
   1343            item->len = i;
   1344            break;
   1345        }
   1346    }
   1347    /* now look for a ':', which marks the end of the name */
   1348    for (i = item->len; --i >= 0;) {
   1349        if (item->data[i] == ':') {
   1350            item->len = i;
   1351            break;
   1352        }
   1353    }
   1354    /* now look for an '@', which marks the beginning of the hostname */
   1355    for (i = 0; (unsigned)i < item->len; ++i) {
   1356        if (item->data[i] == '@') {
   1357            ++i;
   1358            item->data += i;
   1359            item->len -= i;
   1360            break;
   1361        }
   1362    }
   1363    return item->len ? SECSuccess : SECFailure;
   1364 }
   1365 
   1366 /* This function takes one name, and a list of constraints.
   1367 ** It searches the constraints looking for a match.
   1368 ** It returns SECSuccess if the name satisfies the constraints, i.e.,
   1369 ** if excluded, then the name does not match any constraint,
   1370 ** if permitted, then the name matches at least one constraint.
   1371 ** It returns SECFailure if the name fails to satisfy the constraints,
   1372 ** or if some code fails (e.g. out of memory, or invalid constraint)
   1373 */
   1374 SECStatus
   1375 cert_CompareNameWithConstraints(const CERTGeneralName *name,
   1376                                const CERTNameConstraint *constraints,
   1377                                PRBool excluded)
   1378 {
   1379    SECStatus rv = SECSuccess;
   1380    SECStatus matched = SECFailure;
   1381    const CERTNameConstraint *current;
   1382 
   1383    PORT_Assert(constraints); /* caller should not call with NULL */
   1384    if (!constraints) {
   1385        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1386        return SECFailure;
   1387    }
   1388 
   1389    current = constraints;
   1390    do {
   1391        rv = SECSuccess;
   1392        matched = SECFailure;
   1393        PORT_Assert(name->type == current->name.type);
   1394        switch (name->type) {
   1395 
   1396            case certDNSName:
   1397                matched =
   1398                    compareDNSN2C(&name->name.other, &current->name.name.other);
   1399                break;
   1400 
   1401            case certRFC822Name:
   1402                matched = compareRFC822N2C(&name->name.other,
   1403                                           &current->name.name.other);
   1404                break;
   1405 
   1406            case certURI: {
   1407                /* make a modifiable copy of the URI SECItem. */
   1408                SECItem uri = name->name.other;
   1409                /* find the hostname in the URI */
   1410                rv = parseUriHostname(&uri);
   1411                if (rv == SECSuccess) {
   1412                    /* does our hostname meet the constraint? */
   1413                    matched = compareURIN2C(&uri, &current->name.name.other);
   1414                }
   1415            } break;
   1416 
   1417            case certDirectoryName:
   1418                /* Determine if the constraint directory name is a "prefix"
   1419                ** for the directory name being tested.
   1420                */
   1421                {
   1422                    /* status defaults to SECEqual, so that a constraint with
   1423                    ** no AVAs will be a wildcard, matching all directory names.
   1424                    */
   1425                    SECComparison status = SECEqual;
   1426                    const CERTRDN **cRDNs =
   1427                        (const CERTRDN **)current->name.name.directoryName.rdns;
   1428                    const CERTRDN **nRDNs =
   1429                        (const CERTRDN **)name->name.directoryName.rdns;
   1430                    while (cRDNs && *cRDNs && nRDNs && *nRDNs) {
   1431                        /* loop over name RDNs and constraint RDNs in lock step
   1432                         */
   1433                        const CERTRDN *cRDN = *cRDNs++;
   1434                        const CERTRDN *nRDN = *nRDNs++;
   1435                        CERTAVA **cAVAs = cRDN->avas;
   1436                        while (cAVAs &&
   1437                               *cAVAs) { /* loop over constraint AVAs */
   1438                            CERTAVA *cAVA = *cAVAs++;
   1439                            CERTAVA **nAVAs = nRDN->avas;
   1440                            while (nAVAs && *nAVAs) { /* loop over name AVAs */
   1441                                CERTAVA *nAVA = *nAVAs++;
   1442                                status = CERT_CompareAVA(cAVA, nAVA);
   1443                                if (status == SECEqual)
   1444                                    break;
   1445                            } /* loop over name AVAs */
   1446                            if (status != SECEqual)
   1447                                break;
   1448                        } /* loop over constraint AVAs */
   1449                        if (status != SECEqual)
   1450                            break;
   1451                    } /* loop over name RDNs and constraint RDNs */
   1452                    matched = (status == SECEqual) ? SECSuccess : SECFailure;
   1453                    break;
   1454                }
   1455 
   1456            case certIPAddress: /* type 8 */
   1457                matched = compareIPaddrN2C(&name->name.other,
   1458                                           &current->name.name.other);
   1459                break;
   1460 
   1461            /* NSS does not know how to compare these "Other" type names with
   1462            ** their respective constraints.  But it does know how to tell
   1463            ** if the constraint applies to the type of name (by comparing
   1464            ** the constraint OID to the name OID).  NSS makes no use of "Other"
   1465            ** type names at all, so NSS errs on the side of leniency for these
   1466            ** types, provided that their OIDs match.  So, when an "Other"
   1467            ** name constraint appears in an excluded subtree, it never causes
   1468            ** a name to fail.  When an "Other" name constraint appears in a
   1469            ** permitted subtree, AND the constraint's OID matches the name's
   1470            ** OID, then name is treated as if it matches the constraint.
   1471            */
   1472            case certOtherName: /* type 1 */
   1473                matched =
   1474                    (!excluded && name->type == current->name.type &&
   1475                     SECITEM_ItemsAreEqual(&name->name.OthName.oid,
   1476                                           &current->name.name.OthName.oid))
   1477                        ? SECSuccess
   1478                        : SECFailure;
   1479                break;
   1480 
   1481            /* NSS does not know how to compare these types of names with their
   1482            ** respective constraints.  But NSS makes no use of these types of
   1483            ** names at all, so it errs on the side of leniency for these types.
   1484            ** Constraints for these types of names never cause the name to
   1485            ** fail the constraints test.  NSS behaves as if the name matched
   1486            ** for permitted constraints, and did not match for excluded ones.
   1487            */
   1488            case certX400Address:  /* type 4 */
   1489            case certEDIPartyName: /* type 6 */
   1490            case certRegisterID:   /* type 9 */
   1491                matched = excluded ? SECFailure : SECSuccess;
   1492                break;
   1493 
   1494            default: /* non-standard types are not supported */
   1495                rv = SECFailure;
   1496                break;
   1497        }
   1498        if (matched == SECSuccess || rv != SECSuccess)
   1499            break;
   1500        current = CERT_GetNextNameConstraint((CERTNameConstraint *)current);
   1501    } while (current != constraints);
   1502    if (rv == SECSuccess) {
   1503        if (matched == SECSuccess)
   1504            rv = excluded ? SECFailure : SECSuccess;
   1505        else
   1506            rv = excluded ? SECSuccess : SECFailure;
   1507        return rv;
   1508    }
   1509 
   1510    return SECFailure;
   1511 }
   1512 
   1513 /* Add and link a CERTGeneralName to a CERTNameConstraint list. Most
   1514 ** likely the CERTNameConstraint passed in is either the permitted
   1515 ** list or the excluded list of a CERTNameConstraints.
   1516 */
   1517 SECStatus
   1518 CERT_AddNameConstraintByGeneralName(PLArenaPool *arena,
   1519                                    CERTNameConstraint **constraints,
   1520                                    CERTGeneralName *name)
   1521 {
   1522    SECStatus rv;
   1523    CERTNameConstraint *current = NULL;
   1524    CERTNameConstraint *first = *constraints;
   1525    void *mark = NULL;
   1526 
   1527    mark = PORT_ArenaMark(arena);
   1528 
   1529    current = PORT_ArenaZNew(arena, CERTNameConstraint);
   1530    if (current == NULL) {
   1531        rv = SECFailure;
   1532        goto done;
   1533    }
   1534 
   1535    rv = cert_CopyOneGeneralName(arena, &current->name, name);
   1536    if (rv != SECSuccess) {
   1537        goto done;
   1538    }
   1539 
   1540    current->name.l.prev = current->name.l.next = &(current->name.l);
   1541 
   1542    if (first == NULL) {
   1543        *constraints = current;
   1544        PR_INIT_CLIST(&current->l);
   1545    } else {
   1546        PR_INSERT_BEFORE(&current->l, &first->l);
   1547    }
   1548 
   1549 done:
   1550    if (rv == SECFailure) {
   1551        PORT_ArenaRelease(arena, mark);
   1552    } else {
   1553        PORT_ArenaUnmark(arena, mark);
   1554    }
   1555    return rv;
   1556 }
   1557 
   1558 /*
   1559 * Here we define a list of name constraints to be imposed on
   1560 * certain certificates, most importantly root certificates.
   1561 *
   1562 * Each entry in the name constraints list is constructed with this
   1563 * macro.  An entry contains two SECItems, which have names in
   1564 * specific forms to make the macro work:
   1565 *
   1566 *  * ${CA}_SUBJECT_DN - The subject DN for which the constraints
   1567 *                       should be applied
   1568 *  * ${CA}_NAME_CONSTRAINTS - The name constraints extension
   1569 *
   1570 * Entities subject to name constraints are identified by subject name
   1571 * so that we can cover all certificates for that entity, including, e.g.,
   1572 * cross-certificates.  We use subject rather than public key because
   1573 * calling methods often have easy access to that field (vs., say, a key ID),
   1574 * and in practice, subject names and public keys are usually in one-to-one
   1575 * correspondence anyway.
   1576 *
   1577 */
   1578 
   1579 #define STRING_TO_SECITEM(str)                          \
   1580    {                                                   \
   1581        siBuffer, (unsigned char *)str, sizeof(str) - 1 \
   1582    }
   1583 
   1584 #define NAME_CONSTRAINTS_ENTRY(CA)                   \
   1585    {                                                \
   1586        STRING_TO_SECITEM(CA##_SUBJECT_DN)           \
   1587        ,                                            \
   1588            STRING_TO_SECITEM(CA##_NAME_CONSTRAINTS) \
   1589    }
   1590 
   1591 /* clang-format off */
   1592 
   1593 /* Agence Nationale de la Securite des Systemes d'Information (ANSSI) */
   1594 
   1595 #define ANSSI_SUBJECT_DN                                                       \
   1596    "\x30\x81\x85"                                                             \
   1597    "\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02" "FR"       /* C */          \
   1598    "\x31\x0F\x30\x0D\x06\x03\x55\x04\x08\x13\x06" "France"   /* ST */         \
   1599    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05" "Paris"    /* L */          \
   1600    "\x31\x10\x30\x0E\x06\x03\x55\x04\x0A\x13\x07" "PM/SGDN"  /* O */          \
   1601    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13\x05" "DCSSI"    /* OU */         \
   1602    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x03\x13\x05" "IGC/A"    /* CN */         \
   1603    "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01"             \
   1604    "\x16\x14" "igca@sgdn.pm.gouv.fr" /* emailAddress */                       \
   1605 
   1606 #define ANSSI_NAME_CONSTRAINTS                                                 \
   1607    "\x30\x5D\xA0\x5B"                                                         \
   1608    "\x30\x05\x82\x03" ".fr"                                                   \
   1609    "\x30\x05\x82\x03" ".gp"                                                   \
   1610    "\x30\x05\x82\x03" ".gf"                                                   \
   1611    "\x30\x05\x82\x03" ".mq"                                                   \
   1612    "\x30\x05\x82\x03" ".re"                                                   \
   1613    "\x30\x05\x82\x03" ".yt"                                                   \
   1614    "\x30\x05\x82\x03" ".pm"                                                   \
   1615    "\x30\x05\x82\x03" ".bl"                                                   \
   1616    "\x30\x05\x82\x03" ".mf"                                                   \
   1617    "\x30\x05\x82\x03" ".wf"                                                   \
   1618    "\x30\x05\x82\x03" ".pf"                                                   \
   1619    "\x30\x05\x82\x03" ".nc"                                                   \
   1620    "\x30\x05\x82\x03" ".tf"
   1621 
   1622 /* TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 */
   1623 
   1624 #define TUBITAK1_SUBJECT_DN                                                    \
   1625    "\x30\x81\xd2"                                                             \
   1626    "\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02"                             \
   1627    /* C */ "TR"                                                               \
   1628    "\x31\x18\x30\x16\x06\x03\x55\x04\x07\x13\x0f"                             \
   1629    /* L */ "Gebze - Kocaeli"                                                  \
   1630    "\x31\x42\x30\x40\x06\x03\x55\x04\x0a\x13\x39"                             \
   1631    /* O */ "Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK"        \
   1632    "\x31\x2d\x30\x2b\x06\x03\x55\x04\x0b\x13\x24"                             \
   1633    /* OU */ "Kamu Sertifikasyon Merkezi - Kamu SM"                            \
   1634    "\x31\x36\x30\x34\x06\x03\x55\x04\x03\x13\x2d"                             \
   1635    /* CN */ "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1"
   1636 
   1637 #define TUBITAK1_NAME_CONSTRAINTS                                              \
   1638    "\x30\x09\xa0\x07"                                                         \
   1639    "\x30\x05\x82\x03" ".tr"
   1640 
   1641 /* clang-format on */
   1642 
   1643 static const SECItem builtInNameConstraints[][2] = {
   1644    NAME_CONSTRAINTS_ENTRY(ANSSI),
   1645    NAME_CONSTRAINTS_ENTRY(TUBITAK1)
   1646 };
   1647 
   1648 SECStatus
   1649 CERT_GetImposedNameConstraints(const SECItem *derSubject, SECItem *extensions)
   1650 {
   1651    size_t i;
   1652 
   1653    if (!extensions) {
   1654        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1655        return SECFailure;
   1656    }
   1657 
   1658    for (i = 0; i < PR_ARRAY_SIZE(builtInNameConstraints); ++i) {
   1659        if (SECITEM_ItemsAreEqual(derSubject, &builtInNameConstraints[i][0])) {
   1660            return SECITEM_CopyItem(NULL, extensions,
   1661                                    &builtInNameConstraints[i][1]);
   1662        }
   1663    }
   1664 
   1665    PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
   1666    return SECFailure;
   1667 }
   1668 
   1669 /*
   1670 * Extract the name constraints extension from the CA cert.
   1671 * If the certificate contains no name constraints extension, but
   1672 * CERT_GetImposedNameConstraints returns a name constraints extension
   1673 * for the subject of the certificate, then that extension will be returned.
   1674 */
   1675 SECStatus
   1676 CERT_FindNameConstraintsExten(PLArenaPool *arena, CERTCertificate *cert,
   1677                              CERTNameConstraints **constraints)
   1678 {
   1679    SECStatus rv = SECSuccess;
   1680    SECItem constraintsExtension;
   1681    void *mark = NULL;
   1682 
   1683    *constraints = NULL;
   1684 
   1685    rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS,
   1686                                &constraintsExtension);
   1687    if (rv != SECSuccess) {
   1688        if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
   1689            return rv;
   1690        }
   1691        rv = CERT_GetImposedNameConstraints(&cert->derSubject,
   1692                                            &constraintsExtension);
   1693        if (rv != SECSuccess) {
   1694            if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
   1695                return SECSuccess;
   1696            }
   1697            return rv;
   1698        }
   1699    }
   1700 
   1701    mark = PORT_ArenaMark(arena);
   1702 
   1703    *constraints = cert_DecodeNameConstraints(arena, &constraintsExtension);
   1704    if (*constraints == NULL) { /* decode failed */
   1705        rv = SECFailure;
   1706    }
   1707    PORT_Free(constraintsExtension.data);
   1708 
   1709    if (rv == SECFailure) {
   1710        PORT_ArenaRelease(arena, mark);
   1711    } else {
   1712        PORT_ArenaUnmark(arena, mark);
   1713    }
   1714 
   1715    return rv;
   1716 }
   1717 
   1718 /* Verify name against all the constraints relevant to that type of
   1719 ** the name.
   1720 */
   1721 SECStatus
   1722 CERT_CheckNameSpace(PLArenaPool *arena, const CERTNameConstraints *constraints,
   1723                    const CERTGeneralName *currentName)
   1724 {
   1725    CERTNameConstraint *matchingConstraints;
   1726    SECStatus rv = SECSuccess;
   1727 
   1728    if (constraints->excluded != NULL) {
   1729        rv = CERT_GetNameConstraintByType(constraints->excluded,
   1730                                          currentName->type,
   1731                                          &matchingConstraints, arena);
   1732        if (rv == SECSuccess && matchingConstraints != NULL) {
   1733            rv = cert_CompareNameWithConstraints(currentName,
   1734                                                 matchingConstraints, PR_TRUE);
   1735        }
   1736        if (rv != SECSuccess) {
   1737            return (rv);
   1738        }
   1739    }
   1740 
   1741    if (constraints->permited != NULL) {
   1742        rv = CERT_GetNameConstraintByType(constraints->permited,
   1743                                          currentName->type,
   1744                                          &matchingConstraints, arena);
   1745        if (rv == SECSuccess && matchingConstraints != NULL) {
   1746            rv = cert_CompareNameWithConstraints(currentName,
   1747                                                 matchingConstraints, PR_FALSE);
   1748        }
   1749        if (rv != SECSuccess) {
   1750            return (rv);
   1751        }
   1752    }
   1753 
   1754    return (SECSuccess);
   1755 }
   1756 
   1757 /* Extract the name constraints extension from the CA cert.
   1758 ** Test each and every name in namesList against all the constraints
   1759 ** relevant to that type of name.
   1760 ** Returns NULL in pBadCert for success, if all names are acceptable.
   1761 ** If some name is not acceptable, returns a pointer to the cert that
   1762 ** contained that name.
   1763 */
   1764 SECStatus
   1765 CERT_CompareNameSpace(CERTCertificate *cert, CERTGeneralName *namesList,
   1766                      CERTCertificate **certsList, PLArenaPool *reqArena,
   1767                      CERTCertificate **pBadCert)
   1768 {
   1769    SECStatus rv = SECSuccess;
   1770    CERTNameConstraints *constraints;
   1771    CERTGeneralName *currentName;
   1772    int count = 0;
   1773    CERTCertificate *badCert = NULL;
   1774 
   1775    /* If no names to check, then no names can be bad. */
   1776    if (!namesList)
   1777        goto done;
   1778    rv = CERT_FindNameConstraintsExten(reqArena, cert, &constraints);
   1779    if (rv != SECSuccess) {
   1780        count = -1;
   1781        goto done;
   1782    }
   1783 
   1784    currentName = namesList;
   1785    do {
   1786        if (constraints) {
   1787            rv = CERT_CheckNameSpace(reqArena, constraints, currentName);
   1788            if (rv != SECSuccess) {
   1789                break;
   1790            }
   1791        }
   1792        currentName = CERT_GetNextGeneralName(currentName);
   1793        count++;
   1794    } while (currentName != namesList);
   1795 
   1796 done:
   1797    if (rv != SECSuccess) {
   1798        badCert = (count >= 0) ? certsList[count] : cert;
   1799    }
   1800    if (pBadCert)
   1801        *pBadCert = badCert;
   1802 
   1803    return rv;
   1804 }
   1805 
   1806 #if 0
   1807 /* not exported from shared libs, not used.  Turn on if we ever need it. */
   1808 SECStatus
   1809 CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b)
   1810 {
   1811    CERTGeneralName *currentA;
   1812    CERTGeneralName *currentB;
   1813    PRBool found;
   1814 
   1815    currentA = a;
   1816    currentB = b;
   1817    if (a != NULL) {
   1818 do {
   1819     if (currentB == NULL) {
   1820 	return SECFailure;
   1821     }
   1822     currentB = CERT_GetNextGeneralName(currentB);
   1823     currentA = CERT_GetNextGeneralName(currentA);
   1824 } while (currentA != a);
   1825    }
   1826    if (currentB != b) {
   1827 return SECFailure;
   1828    }
   1829    currentA = a;
   1830    do {
   1831 currentB = b;
   1832 found = PR_FALSE;
   1833 do {
   1834     if (currentB->type == currentA->type) {
   1835 	switch (currentB->type) {
   1836 	  case certDNSName:
   1837 	  case certEDIPartyName:
   1838 	  case certIPAddress:
   1839 	  case certRegisterID:
   1840 	  case certRFC822Name:
   1841 	  case certX400Address:
   1842 	  case certURI:
   1843 	    if (SECITEM_CompareItem(&currentA->name.other,
   1844 				    &currentB->name.other)
   1845 		== SECEqual) {
   1846 		found = PR_TRUE;
   1847 	    }
   1848 	    break;
   1849 	  case certOtherName:
   1850 	    if (SECITEM_CompareItem(&currentA->name.OthName.oid,
   1851 				    &currentB->name.OthName.oid)
   1852 		== SECEqual &&
   1853 		SECITEM_CompareItem(&currentA->name.OthName.name,
   1854 				    &currentB->name.OthName.name)
   1855 		== SECEqual) {
   1856 		found = PR_TRUE;
   1857 	    }
   1858 	    break;
   1859 	  case certDirectoryName:
   1860 	    if (CERT_CompareName(&currentA->name.directoryName,
   1861 				 &currentB->name.directoryName)
   1862 		== SECEqual) {
   1863 		found = PR_TRUE;
   1864 	    }
   1865 	}
   1866 
   1867     }
   1868     currentB = CERT_GetNextGeneralName(currentB);
   1869 } while (currentB != b && found != PR_TRUE);
   1870 if (found != PR_TRUE) {
   1871     return SECFailure;
   1872 }
   1873 currentA = CERT_GetNextGeneralName(currentA);
   1874    } while (currentA != a);
   1875    return SECSuccess;
   1876 }
   1877 
   1878 SECStatus
   1879 CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b)
   1880 {
   1881    SECStatus rv;
   1882 
   1883    if (a == b) {
   1884 return SECSuccess;
   1885    }
   1886    if (a != NULL && b != NULL) {
   1887 PZ_Lock(a->lock);
   1888 PZ_Lock(b->lock);
   1889 rv = CERT_CompareGeneralName(a->name, b->name);
   1890 PZ_Unlock(a->lock);
   1891 PZ_Unlock(b->lock);
   1892    } else {
   1893 rv = SECFailure;
   1894    }
   1895    return rv;
   1896 }
   1897 #endif
   1898 
   1899 #if 0
   1900 /* This function is not exported from NSS shared libraries, and is not
   1901 ** used inside of NSS.
   1902 ** XXX it doesn't check for failed allocations. :-(
   1903 */
   1904 void *
   1905 CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list,
   1906 			  CERTGeneralNameType type,
   1907 			  PLArenaPool *arena)
   1908 {
   1909    CERTName *name = NULL;
   1910    SECItem *item = NULL;
   1911    OtherName *other = NULL;
   1912    OtherName *tmpOther = NULL;
   1913    void *data;
   1914 
   1915    PZ_Lock(list->lock);
   1916    data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE);
   1917    if (data != NULL) {
   1918 switch (type) {
   1919   case certDNSName:
   1920   case certEDIPartyName:
   1921   case certIPAddress:
   1922   case certRegisterID:
   1923   case certRFC822Name:
   1924   case certX400Address:
   1925   case certURI:
   1926     if (arena != NULL) {
   1927 	item = PORT_ArenaNew(arena, SECItem);
   1928 	if (item != NULL) {
   1929 XXX		    SECITEM_CopyItem(arena, item, (SECItem *) data);
   1930 	}
   1931     } else {
   1932 	item = SECITEM_DupItem((SECItem *) data);
   1933     }
   1934     PZ_Unlock(list->lock);
   1935     return item;
   1936   case certOtherName:
   1937     other = (OtherName *) data;
   1938     if (arena != NULL) {
   1939 	tmpOther = PORT_ArenaNew(arena, OtherName);
   1940     } else {
   1941 	tmpOther = PORT_New(OtherName);
   1942     }
   1943     if (tmpOther != NULL) {
   1944 XXX		SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid);
   1945 XXX		SECITEM_CopyItem(arena, &tmpOther->name, &other->name);
   1946     }
   1947     PZ_Unlock(list->lock);
   1948     return tmpOther;
   1949   case certDirectoryName:
   1950     if (arena) {
   1951 	name = PORT_ArenaZNew(list->arena, CERTName);
   1952 	if (name) {
   1953 XXX		    CERT_CopyName(arena, name, (CERTName *) data);
   1954 	}
   1955     }
   1956     PZ_Unlock(list->lock);
   1957     return name;
   1958 }
   1959    }
   1960    PZ_Unlock(list->lock);
   1961    return NULL;
   1962 }
   1963 #endif
   1964 
   1965 #if 0
   1966 /* This function is not exported from NSS shared libraries, and is not
   1967 ** used inside of NSS.
   1968 ** XXX it should NOT be a void function, since it does allocations
   1969 ** that can fail.
   1970 */
   1971 void
   1972 CERT_AddGeneralNameToList(CERTGeneralNameList *list,
   1973 		  CERTGeneralNameType type,
   1974 		  void *data, SECItem *oid)
   1975 {
   1976    CERTGeneralName *name;
   1977 
   1978    if (list != NULL && data != NULL) {
   1979 PZ_Lock(list->lock);
   1980 name = CERT_NewGeneralName(list->arena, type);
   1981 if (!name)
   1982     goto done;
   1983 switch (type) {
   1984   case certDNSName:
   1985   case certEDIPartyName:
   1986   case certIPAddress:
   1987   case certRegisterID:
   1988   case certRFC822Name:
   1989   case certX400Address:
   1990   case certURI:
   1991 XXX	    SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data);
   1992     break;
   1993   case certOtherName:
   1994 XXX	    SECITEM_CopyItem(list->arena, &name->name.OthName.name,
   1995 		     (SECItem *) data);
   1996 XXX	    SECITEM_CopyItem(list->arena, &name->name.OthName.oid,
   1997 		     oid);
   1998     break;
   1999   case certDirectoryName:
   2000 XXX	    CERT_CopyName(list->arena, &name->name.directoryName,
   2001 		  (CERTName *) data);
   2002     break;
   2003 }
   2004 list->name = cert_CombineNamesLists(list->name, name);
   2005 list->len++;
   2006 done:
   2007 PZ_Unlock(list->lock);
   2008    }
   2009    return;
   2010 }
   2011 #endif