tor-browser

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

certhigh.c (33086B)


      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 #include "nspr.h"
      5 #include "secerr.h"
      6 #include "secasn1.h"
      7 #include "seccomon.h"
      8 #include "pk11func.h"
      9 #include "certdb.h"
     10 #include "certt.h"
     11 #include "cert.h"
     12 #include "certxutl.h"
     13 
     14 #include "certi.h"
     15 #include "nsspki.h"
     16 #include "pki.h"
     17 #include "pkit.h"
     18 #include "pkitm.h"
     19 #include "pki3hack.h"
     20 
     21 PRBool
     22 CERT_MatchNickname(char *name1, char *name2)
     23 {
     24    char *nickname1 = NULL;
     25    char *nickname2 = NULL;
     26    char *token1;
     27    char *token2;
     28 
     29    /* first deal with the straight comparison */
     30    if (PORT_Strcmp(name1, name2) == 0) {
     31        return PR_TRUE;
     32    }
     33    /* we need to handle the case where one name has an explicit token and the other
     34     * doesn't */
     35    token1 = PORT_Strchr(name1, ':');
     36    token2 = PORT_Strchr(name2, ':');
     37    if ((token1 && token2) || (!token1 && !token2)) {
     38        /* either both token names are specified or neither are, not match */
     39        return PR_FALSE;
     40    }
     41    if (token1) {
     42        nickname1 = token1;
     43        nickname2 = name2;
     44    } else {
     45        nickname1 = token2;
     46        nickname2 = name1;
     47    }
     48    nickname1++;
     49    if (PORT_Strcmp(nickname1, nickname2) != 0) {
     50        return PR_FALSE;
     51    }
     52    /* Bug 1192443 - compare the other token with the internal slot here */
     53    return PR_TRUE;
     54 }
     55 
     56 /*
     57 * Find all user certificates that match the given criteria.
     58 *
     59 *      "handle" - database to search
     60 *      "usage" - certificate usage to match
     61 *      "oneCertPerName" - if set then only return the "best" cert per
     62 *                      name
     63 *      "validOnly" - only return certs that are curently valid
     64 *      "proto_win" - window handle passed to pkcs11
     65 */
     66 CERTCertList *
     67 CERT_FindUserCertsByUsage(CERTCertDBHandle *handle,
     68                          SECCertUsage usage,
     69                          PRBool oneCertPerName,
     70                          PRBool validOnly,
     71                          void *proto_win)
     72 {
     73    CERTCertNicknames *nicknames = NULL;
     74    char **nnptr;
     75    int nn;
     76    CERTCertificate *cert = NULL;
     77    CERTCertList *certList = NULL;
     78    SECStatus rv;
     79    PRTime time;
     80    CERTCertListNode *node = NULL;
     81    CERTCertListNode *freenode = NULL;
     82    int n;
     83 
     84    time = PR_Now();
     85 
     86    nicknames = CERT_GetCertNicknames(handle, SEC_CERT_NICKNAMES_USER,
     87                                      proto_win);
     88 
     89    if ((nicknames == NULL) || (nicknames->numnicknames == 0)) {
     90        goto loser;
     91    }
     92 
     93    nnptr = nicknames->nicknames;
     94    nn = nicknames->numnicknames;
     95 
     96    while (nn > 0) {
     97        cert = NULL;
     98        /* use the pk11 call so that we pick up any certs on tokens,
     99         * which may require login
    100         */
    101        if (proto_win != NULL) {
    102            cert = PK11_FindCertFromNickname(*nnptr, proto_win);
    103        }
    104 
    105        /* Sigh, It turns out if the cert is already in the temp db, because
    106         * it's in the perm db, then the nickname lookup doesn't work.
    107         * since we already have the cert here, though, than we can just call
    108         * CERT_CreateSubjectCertList directly. For those cases where we didn't
    109         * find the cert in pkcs #11 (because we didn't have a password arg,
    110         * or because the nickname is for a peer, server, or CA cert, then we
    111         * go look the cert up.
    112         */
    113        if (cert == NULL) {
    114            cert = CERT_FindCertByNickname(handle, *nnptr);
    115        }
    116 
    117        if (cert != NULL) {
    118            /* collect certs for this nickname, sorting them into the list */
    119            certList = CERT_CreateSubjectCertList(certList, handle,
    120                                                  &cert->derSubject, time, validOnly);
    121 
    122            CERT_FilterCertListForUserCerts(certList);
    123 
    124            /* drop the extra reference */
    125            CERT_DestroyCertificate(cert);
    126        }
    127 
    128        nnptr++;
    129        nn--;
    130    }
    131 
    132    /* remove certs with incorrect usage */
    133    rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
    134 
    135    if (rv != SECSuccess) {
    136        goto loser;
    137    }
    138 
    139    /* remove any extra certs for each name */
    140    if (oneCertPerName) {
    141        PRBool *flags;
    142 
    143        nn = nicknames->numnicknames;
    144        nnptr = nicknames->nicknames;
    145 
    146        if (!certList) {
    147            goto loser;
    148        }
    149 
    150        flags = (PRBool *)PORT_ZAlloc(sizeof(PRBool) * nn);
    151        if (flags == NULL) {
    152            goto loser;
    153        }
    154 
    155        node = CERT_LIST_HEAD(certList);
    156 
    157        /* treverse all certs in the list */
    158        while (!CERT_LIST_END(node, certList)) {
    159 
    160            /* find matching nickname index */
    161            for (n = 0; n < nn; n++) {
    162                if (CERT_MatchNickname(nnptr[n], node->cert->nickname)) {
    163                    /* We found a match.  If this is the first one, then
    164                     * set the flag and move on to the next cert.  If this
    165                     * is not the first one then delete it from the list.
    166                     */
    167                    if (flags[n]) {
    168                        /* We have already seen a cert with this nickname,
    169                         * so delete this one.
    170                         */
    171                        freenode = node;
    172                        node = CERT_LIST_NEXT(node);
    173                        CERT_RemoveCertListNode(freenode);
    174                    } else {
    175                        /* keep the first cert for each nickname, but set the
    176                         * flag so we know to delete any others with the same
    177                         * nickname.
    178                         */
    179                        flags[n] = PR_TRUE;
    180                        node = CERT_LIST_NEXT(node);
    181                    }
    182                    break;
    183                }
    184            }
    185            if (n == nn) {
    186                /* if we get here it means that we didn't find a matching
    187                 * nickname, which should not happen.
    188                 */
    189                PORT_Assert(0);
    190                node = CERT_LIST_NEXT(node);
    191            }
    192        }
    193        PORT_Free(flags);
    194    }
    195 
    196    goto done;
    197 
    198 loser:
    199    if (certList != NULL) {
    200        CERT_DestroyCertList(certList);
    201        certList = NULL;
    202    }
    203 
    204 done:
    205    if (nicknames != NULL) {
    206        CERT_FreeNicknames(nicknames);
    207    }
    208 
    209    return (certList);
    210 }
    211 
    212 /*
    213 * Find a user certificate that matchs the given criteria.
    214 *
    215 *      "handle" - database to search
    216 *      "nickname" - nickname to match
    217 *      "usage" - certificate usage to match
    218 *      "validOnly" - only return certs that are curently valid
    219 *      "proto_win" - window handle passed to pkcs11
    220 */
    221 CERTCertificate *
    222 CERT_FindUserCertByUsage(CERTCertDBHandle *handle,
    223                         const char *nickname,
    224                         SECCertUsage usage,
    225                         PRBool validOnly,
    226                         void *proto_win)
    227 {
    228    CERTCertificate *cert = NULL;
    229    CERTCertList *certList = NULL;
    230    SECStatus rv;
    231    PRTime time;
    232 
    233    time = PR_Now();
    234 
    235    /* use the pk11 call so that we pick up any certs on tokens,
    236     * which may require login
    237     */
    238    /* XXX - why is this restricted? */
    239    if (proto_win != NULL) {
    240        cert = PK11_FindCertFromNickname(nickname, proto_win);
    241    }
    242 
    243    /* sigh, There are still problems find smart cards from the temp
    244     * db. This will get smart cards working again. The real fix
    245     * is to make sure we can search the temp db by their token nickname.
    246     */
    247    if (cert == NULL) {
    248        cert = CERT_FindCertByNickname(handle, nickname);
    249    }
    250 
    251    if (cert != NULL) {
    252        unsigned int requiredKeyUsage;
    253        unsigned int requiredCertType;
    254 
    255        rv = CERT_KeyUsageAndTypeForCertUsage(usage, PR_FALSE,
    256                                              &requiredKeyUsage, &requiredCertType);
    257        if (rv != SECSuccess) {
    258            /* drop the extra reference */
    259            CERT_DestroyCertificate(cert);
    260            cert = NULL;
    261            goto loser;
    262        }
    263        /* If we already found the right cert, just return it */
    264        if ((!validOnly || CERT_CheckCertValidTimes(cert, time, PR_FALSE) == secCertTimeValid) &&
    265            (CERT_CheckKeyUsage(cert, requiredKeyUsage) == SECSuccess) &&
    266            (cert->nsCertType & requiredCertType) &&
    267            CERT_IsUserCert(cert)) {
    268            return (cert);
    269        }
    270 
    271        /* collect certs for this nickname, sorting them into the list */
    272        certList = CERT_CreateSubjectCertList(certList, handle,
    273                                              &cert->derSubject, time, validOnly);
    274 
    275        CERT_FilterCertListForUserCerts(certList);
    276 
    277        /* drop the extra reference */
    278        CERT_DestroyCertificate(cert);
    279        cert = NULL;
    280    }
    281 
    282    if (certList == NULL) {
    283        goto loser;
    284    }
    285 
    286    /* remove certs with incorrect usage */
    287    rv = CERT_FilterCertListByUsage(certList, usage, PR_FALSE);
    288 
    289    if (rv != SECSuccess) {
    290        goto loser;
    291    }
    292 
    293    if (!CERT_LIST_EMPTY(certList)) {
    294        cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
    295    }
    296 
    297 loser:
    298    if (certList != NULL) {
    299        CERT_DestroyCertList(certList);
    300    }
    301 
    302    return (cert);
    303 }
    304 
    305 CERTCertList *
    306 CERT_MatchUserCert(CERTCertDBHandle *handle,
    307                   SECCertUsage usage,
    308                   int nCANames, char **caNames,
    309                   void *proto_win)
    310 {
    311    CERTCertList *certList = NULL;
    312    SECStatus rv;
    313 
    314    certList = CERT_FindUserCertsByUsage(handle, usage, PR_TRUE, PR_TRUE,
    315                                         proto_win);
    316    if (certList == NULL) {
    317        goto loser;
    318    }
    319 
    320    rv = CERT_FilterCertListByCANames(certList, nCANames, caNames, usage);
    321    if (rv != SECSuccess) {
    322        goto loser;
    323    }
    324 
    325    goto done;
    326 
    327 loser:
    328    if (certList != NULL) {
    329        CERT_DestroyCertList(certList);
    330        certList = NULL;
    331    }
    332 
    333 done:
    334 
    335    return (certList);
    336 }
    337 
    338 typedef struct stringNode {
    339    struct stringNode *next;
    340    char *string;
    341 } stringNode;
    342 
    343 static PRStatus
    344 CollectNicknames(NSSCertificate *c, void *data)
    345 {
    346    CERTCertNicknames *names;
    347    PRBool saveit = PR_FALSE;
    348    stringNode *node;
    349    int len;
    350 #ifdef notdef
    351    NSSTrustDomain *td;
    352    NSSTrust *trust;
    353 #endif
    354    char *stanNickname;
    355    char *nickname = NULL;
    356 
    357    names = (CERTCertNicknames *)data;
    358 
    359    stanNickname = nssCertificate_GetNickname(c, NULL);
    360 
    361    if (stanNickname) {
    362        nss_ZFreeIf(stanNickname);
    363        stanNickname = NULL;
    364        if (names->what == SEC_CERT_NICKNAMES_USER) {
    365            saveit = NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL);
    366        }
    367 #ifdef notdef
    368        else {
    369            td = NSSCertificate_GetTrustDomain(c);
    370            if (!td) {
    371                return PR_SUCCESS;
    372            }
    373            trust = nssTrustDomain_FindTrustForCertificate(td, c);
    374 
    375            switch (names->what) {
    376                case SEC_CERT_NICKNAMES_ALL:
    377                    if ((trust->sslFlags & (CERTDB_VALID_CA | CERTDB_VALID_PEER)) ||
    378                        (trust->emailFlags & (CERTDB_VALID_CA | CERTDB_VALID_PEER)) ||
    379                        (trust->objectSigningFlags &
    380                         (CERTDB_VALID_CA | CERTDB_VALID_PEER))) {
    381                        saveit = PR_TRUE;
    382                    }
    383 
    384                    break;
    385                case SEC_CERT_NICKNAMES_SERVER:
    386                    if (trust->sslFlags & CERTDB_VALID_PEER) {
    387                        saveit = PR_TRUE;
    388                    }
    389 
    390                    break;
    391                case SEC_CERT_NICKNAMES_CA:
    392                    if (((trust->sslFlags & CERTDB_VALID_CA) == CERTDB_VALID_CA) ||
    393                        ((trust->emailFlags & CERTDB_VALID_CA) == CERTDB_VALID_CA) ||
    394                        ((trust->objectSigningFlags & CERTDB_VALID_CA) ==
    395                         CERTDB_VALID_CA)) {
    396                        saveit = PR_TRUE;
    397                    }
    398                    break;
    399            }
    400        }
    401 #endif
    402    }
    403 
    404    /* traverse the list of collected nicknames and make sure we don't make
    405     * a duplicate
    406     */
    407    if (saveit) {
    408        nickname = STAN_GetCERTCertificateName(NULL, c);
    409        /* nickname can only be NULL here if we are having memory
    410         * alloc problems */
    411        if (nickname == NULL) {
    412            return PR_FAILURE;
    413        }
    414        node = (stringNode *)names->head;
    415        while (node != NULL) {
    416            if (PORT_Strcmp(nickname, node->string) == 0) {
    417                /* if the string matches, then don't save this one */
    418                saveit = PR_FALSE;
    419                break;
    420            }
    421            node = node->next;
    422        }
    423    }
    424 
    425    if (saveit) {
    426 
    427        /* allocate the node */
    428        node = (stringNode *)PORT_ArenaAlloc(names->arena, sizeof(stringNode));
    429        if (node == NULL) {
    430            PORT_Free(nickname);
    431            return PR_FAILURE;
    432        }
    433 
    434        /* copy the string */
    435        len = PORT_Strlen(nickname) + 1;
    436        node->string = (char *)PORT_ArenaAlloc(names->arena, len);
    437        if (node->string == NULL) {
    438            PORT_Free(nickname);
    439            return PR_FAILURE;
    440        }
    441        PORT_Memcpy(node->string, nickname, len);
    442 
    443        /* link it into the list */
    444        node->next = (stringNode *)names->head;
    445        names->head = (void *)node;
    446 
    447        /* bump the count */
    448        names->numnicknames++;
    449    }
    450 
    451    if (nickname)
    452        PORT_Free(nickname);
    453    return (PR_SUCCESS);
    454 }
    455 
    456 CERTCertNicknames *
    457 CERT_GetCertNicknames(CERTCertDBHandle *handle, int what, void *wincx)
    458 {
    459    PLArenaPool *arena;
    460    CERTCertNicknames *names;
    461    int i;
    462    stringNode *node;
    463 
    464    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    465    if (arena == NULL) {
    466        PORT_SetError(SEC_ERROR_NO_MEMORY);
    467        return (NULL);
    468    }
    469 
    470    names = (CERTCertNicknames *)PORT_ArenaAlloc(arena, sizeof(CERTCertNicknames));
    471    if (names == NULL) {
    472        goto loser;
    473    }
    474 
    475    names->arena = arena;
    476    names->head = NULL;
    477    names->numnicknames = 0;
    478    names->nicknames = NULL;
    479    names->what = what;
    480    names->totallen = 0;
    481 
    482    /* make sure we are logged in */
    483    (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
    484 
    485    NSSTrustDomain_TraverseCertificates(handle,
    486                                        CollectNicknames, (void *)names);
    487    if (names->numnicknames) {
    488        names->nicknames = (char **)PORT_ArenaAlloc(arena,
    489                                                    names->numnicknames *
    490                                                        sizeof(char *));
    491 
    492        if (names->nicknames == NULL) {
    493            goto loser;
    494        }
    495 
    496        node = (stringNode *)names->head;
    497 
    498        for (i = 0; i < names->numnicknames; i++) {
    499            PORT_Assert(node != NULL);
    500 
    501            names->nicknames[i] = node->string;
    502            names->totallen += PORT_Strlen(node->string);
    503            node = node->next;
    504        }
    505 
    506        PORT_Assert(node == NULL);
    507    }
    508 
    509    return (names);
    510 
    511 loser:
    512    PORT_FreeArena(arena, PR_FALSE);
    513    return (NULL);
    514 }
    515 
    516 void
    517 CERT_FreeNicknames(CERTCertNicknames *nicknames)
    518 {
    519    PORT_FreeArena(nicknames->arena, PR_FALSE);
    520 
    521    return;
    522 }
    523 
    524 /* [ FROM pcertdb.c ] */
    525 
    526 typedef struct dnameNode {
    527    struct dnameNode *next;
    528    SECItem name;
    529 } dnameNode;
    530 
    531 void
    532 CERT_FreeDistNames(CERTDistNames *names)
    533 {
    534    PORT_FreeArena(names->arena, PR_FALSE);
    535 
    536    return;
    537 }
    538 
    539 static SECStatus
    540 CollectDistNames(CERTCertificate *cert, SECItem *k, void *data)
    541 {
    542    CERTDistNames *names;
    543    PRBool saveit = PR_FALSE;
    544    CERTCertTrust trust;
    545    dnameNode *node;
    546    int len;
    547 
    548    names = (CERTDistNames *)data;
    549 
    550    if (CERT_GetCertTrust(cert, &trust) == SECSuccess) {
    551        /* only collect names of CAs trusted for issuing SSL clients */
    552        if (trust.sslFlags & CERTDB_TRUSTED_CLIENT_CA) {
    553            saveit = PR_TRUE;
    554        }
    555    }
    556 
    557    if (saveit) {
    558        /* allocate the node */
    559        node = (dnameNode *)PORT_ArenaAlloc(names->arena, sizeof(dnameNode));
    560        if (node == NULL) {
    561            return (SECFailure);
    562        }
    563 
    564        /* copy the name */
    565        node->name.len = len = cert->derSubject.len;
    566        node->name.type = siBuffer;
    567        node->name.data = (unsigned char *)PORT_ArenaAlloc(names->arena, len);
    568        if (node->name.data == NULL) {
    569            return (SECFailure);
    570        }
    571        PORT_Memcpy(node->name.data, cert->derSubject.data, len);
    572 
    573        /* link it into the list */
    574        node->next = (dnameNode *)names->head;
    575        names->head = (void *)node;
    576 
    577        /* bump the count */
    578        names->nnames++;
    579    }
    580 
    581    return (SECSuccess);
    582 }
    583 
    584 /*
    585 * Return all of the CAs that are "trusted" for SSL.
    586 */
    587 CERTDistNames *
    588 CERT_DupDistNames(CERTDistNames *orig)
    589 {
    590    PLArenaPool *arena;
    591    CERTDistNames *names;
    592    int i;
    593    SECStatus rv;
    594 
    595    /* allocate an arena to use */
    596    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    597    if (arena == NULL) {
    598        PORT_SetError(SEC_ERROR_NO_MEMORY);
    599        return (NULL);
    600    }
    601 
    602    /* allocate the header structure */
    603    names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
    604    if (names == NULL) {
    605        goto loser;
    606    }
    607 
    608    /* initialize the header struct */
    609    names->arena = arena;
    610    names->head = NULL;
    611    names->nnames = orig->nnames;
    612    names->names = NULL;
    613 
    614    /* construct the array from the list */
    615    if (orig->nnames) {
    616        names->names = (SECItem *)PORT_ArenaNewArray(arena, SECItem,
    617                                                     orig->nnames);
    618        if (names->names == NULL) {
    619            goto loser;
    620        }
    621        for (i = 0; i < orig->nnames; i++) {
    622            rv = SECITEM_CopyItem(arena, &names->names[i], &orig->names[i]);
    623            if (rv != SECSuccess) {
    624                goto loser;
    625            }
    626        }
    627    }
    628    return (names);
    629 
    630 loser:
    631    PORT_FreeArena(arena, PR_FALSE);
    632    return (NULL);
    633 }
    634 
    635 CERTDistNames *
    636 CERT_GetSSLCACerts(CERTCertDBHandle *handle)
    637 {
    638    PLArenaPool *arena;
    639    CERTDistNames *names;
    640    int i;
    641    SECStatus rv;
    642    dnameNode *node;
    643 
    644    /* allocate an arena to use */
    645    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    646    if (arena == NULL) {
    647        PORT_SetError(SEC_ERROR_NO_MEMORY);
    648        return (NULL);
    649    }
    650 
    651    /* allocate the header structure */
    652    names = (CERTDistNames *)PORT_ArenaAlloc(arena, sizeof(CERTDistNames));
    653    if (names == NULL) {
    654        goto loser;
    655    }
    656 
    657    /* initialize the header struct */
    658    names->arena = arena;
    659    names->head = NULL;
    660    names->nnames = 0;
    661    names->names = NULL;
    662 
    663    /* collect the names from the database */
    664    rv = PK11_TraverseSlotCerts(CollectDistNames, (void *)names, NULL);
    665    if (rv) {
    666        goto loser;
    667    }
    668 
    669    /* construct the array from the list */
    670    if (names->nnames) {
    671        names->names = (SECItem *)PORT_ArenaAlloc(arena, names->nnames * sizeof(SECItem));
    672 
    673        if (names->names == NULL) {
    674            goto loser;
    675        }
    676 
    677        node = (dnameNode *)names->head;
    678 
    679        for (i = 0; i < names->nnames; i++) {
    680            PORT_Assert(node != NULL);
    681 
    682            names->names[i] = node->name;
    683            node = node->next;
    684        }
    685 
    686        PORT_Assert(node == NULL);
    687    }
    688 
    689    return (names);
    690 
    691 loser:
    692    PORT_FreeArena(arena, PR_FALSE);
    693    return (NULL);
    694 }
    695 
    696 CERTDistNames *
    697 CERT_DistNamesFromCertList(CERTCertList *certList)
    698 {
    699    CERTDistNames *dnames = NULL;
    700    PLArenaPool *arena;
    701    CERTCertListNode *node = NULL;
    702    SECItem *names = NULL;
    703    int listLen = 0, i = 0;
    704 
    705    if (certList == NULL) {
    706        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    707        return NULL;
    708    }
    709 
    710    node = CERT_LIST_HEAD(certList);
    711    while (!CERT_LIST_END(node, certList)) {
    712        listLen += 1;
    713        node = CERT_LIST_NEXT(node);
    714    }
    715 
    716    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    717    if (arena == NULL)
    718        goto loser;
    719    dnames = PORT_ArenaZNew(arena, CERTDistNames);
    720    if (dnames == NULL)
    721        goto loser;
    722 
    723    dnames->arena = arena;
    724    dnames->nnames = listLen;
    725    dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, listLen);
    726    if (names == NULL)
    727        goto loser;
    728 
    729    node = CERT_LIST_HEAD(certList);
    730    while (!CERT_LIST_END(node, certList)) {
    731        CERTCertificate *cert = node->cert;
    732        SECStatus rv = SECITEM_CopyItem(arena, &names[i++], &cert->derSubject);
    733        if (rv == SECFailure) {
    734            goto loser;
    735        }
    736        node = CERT_LIST_NEXT(node);
    737    }
    738    return dnames;
    739 loser:
    740    if (arena) {
    741        PORT_FreeArena(arena, PR_FALSE);
    742    }
    743    return NULL;
    744 }
    745 
    746 CERTDistNames *
    747 CERT_DistNamesFromNicknames(CERTCertDBHandle *handle, char **nicknames,
    748                            int nnames)
    749 {
    750    CERTDistNames *dnames = NULL;
    751    PLArenaPool *arena;
    752    int i, rv;
    753    SECItem *names = NULL;
    754    CERTCertificate *cert = NULL;
    755 
    756    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    757    if (arena == NULL)
    758        goto loser;
    759    dnames = PORT_ArenaZNew(arena, CERTDistNames);
    760    if (dnames == NULL)
    761        goto loser;
    762 
    763    dnames->arena = arena;
    764    dnames->nnames = nnames;
    765    dnames->names = names = PORT_ArenaZNewArray(arena, SECItem, nnames);
    766    if (names == NULL)
    767        goto loser;
    768 
    769    for (i = 0; i < nnames; i++) {
    770        cert = CERT_FindCertByNicknameOrEmailAddr(handle, nicknames[i]);
    771        if (cert == NULL)
    772            goto loser;
    773        rv = SECITEM_CopyItem(arena, &names[i], &cert->derSubject);
    774        if (rv == SECFailure)
    775            goto loser;
    776        CERT_DestroyCertificate(cert);
    777    }
    778    return dnames;
    779 
    780 loser:
    781    if (cert != NULL)
    782        CERT_DestroyCertificate(cert);
    783    if (arena != NULL)
    784        PORT_FreeArena(arena, PR_FALSE);
    785    return NULL;
    786 }
    787 
    788 /* [ from pcertdb.c - calls Ascii to Name ] */
    789 /*
    790 * Lookup a certificate in the database by name
    791 */
    792 CERTCertificate *
    793 CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr)
    794 {
    795    CERTName *name;
    796    SECItem *nameItem;
    797    CERTCertificate *cert = NULL;
    798    PLArenaPool *arena = NULL;
    799 
    800    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    801 
    802    if (arena == NULL) {
    803        goto loser;
    804    }
    805 
    806    name = CERT_AsciiToName(nameStr);
    807 
    808    if (name) {
    809        nameItem = SEC_ASN1EncodeItem(arena, NULL, (void *)name,
    810                                      CERT_NameTemplate);
    811        if (nameItem != NULL) {
    812            cert = CERT_FindCertByName(handle, nameItem);
    813        }
    814        CERT_DestroyName(name);
    815    }
    816 
    817 loser:
    818    if (arena) {
    819        PORT_FreeArena(arena, PR_FALSE);
    820    }
    821 
    822    return (cert);
    823 }
    824 
    825 /* From certv3.c */
    826 
    827 CERTCrlDistributionPoints *
    828 CERT_FindCRLDistributionPoints(CERTCertificate *cert)
    829 {
    830    SECItem encodedExtenValue;
    831    SECStatus rv;
    832    CERTCrlDistributionPoints *dps;
    833 
    834    encodedExtenValue.data = NULL;
    835    encodedExtenValue.len = 0;
    836 
    837    rv = cert_FindExtension(cert->extensions, SEC_OID_X509_CRL_DIST_POINTS,
    838                            &encodedExtenValue);
    839    if (rv != SECSuccess) {
    840        return (NULL);
    841    }
    842 
    843    dps = CERT_DecodeCRLDistributionPoints(cert->arena, &encodedExtenValue);
    844 
    845    PORT_Free(encodedExtenValue.data);
    846 
    847    return dps;
    848 }
    849 
    850 /* From crl.c */
    851 CERTSignedCrl *
    852 CERT_ImportCRL(CERTCertDBHandle *handle, SECItem *derCRL, char *url, int type, void *wincx)
    853 {
    854    CERTSignedCrl *retCrl = NULL;
    855    PK11SlotInfo *slot = PK11_GetInternalKeySlot();
    856    retCrl = PK11_ImportCRL(slot, derCRL, url, type, wincx,
    857                            CRL_IMPORT_DEFAULT_OPTIONS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
    858    PK11_FreeSlot(slot);
    859 
    860    return retCrl;
    861 }
    862 
    863 /* From certdb.c */
    864 static SECStatus
    865 cert_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage, PRBool trusted)
    866 {
    867    SECStatus rv;
    868    SECItem *derCert;
    869    CERTCertificate *cert = NULL;
    870    CERTCertificate *newcert = NULL;
    871    CERTCertDBHandle *handle;
    872    CERTCertTrust trust;
    873    PRBool isca;
    874    char *nickname;
    875    unsigned int certtype;
    876    PRBool istemp = PR_FALSE;
    877 
    878    handle = CERT_GetDefaultCertDB();
    879 
    880    while (numcerts--) {
    881        derCert = certs;
    882        certs++;
    883 
    884        /* decode my certificate */
    885        /* This use is ok -- only looks at decoded parts, calls NewTemp later */
    886        newcert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
    887        if (newcert == NULL) {
    888            goto loser;
    889        }
    890 
    891        if (!trusted) {
    892            /* make sure that cert is valid */
    893            rv = CERT_CertTimesValid(newcert);
    894            if (rv == SECFailure) {
    895                goto endloop;
    896            }
    897        }
    898 
    899        /* does it have the CA extension */
    900 
    901        /*
    902         * Make sure that if this is an intermediate CA in the chain that
    903         * it was given permission by its signer to be a CA.
    904         */
    905        isca = CERT_IsCACert(newcert, &certtype);
    906 
    907        if (!isca) {
    908            if (!trusted) {
    909                goto endloop;
    910            }
    911            trust.sslFlags = CERTDB_VALID_CA;
    912            trust.emailFlags = CERTDB_VALID_CA;
    913            trust.objectSigningFlags = CERTDB_VALID_CA;
    914        } else {
    915            /* SSL ca's must have the ssl bit set */
    916            if ((certUsage == certUsageSSLCA) &&
    917                ((certtype & NS_CERT_TYPE_SSL_CA) != NS_CERT_TYPE_SSL_CA)) {
    918                goto endloop;
    919            }
    920 
    921            /* it passed all of the tests, so lets add it to the database */
    922            /* mark it as a CA */
    923            PORT_Memset((void *)&trust, 0, sizeof(trust));
    924            switch (certUsage) {
    925                case certUsageSSLCA:
    926                    trust.sslFlags = CERTDB_VALID_CA;
    927                    break;
    928                case certUsageUserCertImport:
    929                    if ((certtype & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
    930                        trust.sslFlags = CERTDB_VALID_CA;
    931                    }
    932                    if ((certtype & NS_CERT_TYPE_EMAIL_CA) ==
    933                        NS_CERT_TYPE_EMAIL_CA) {
    934                        trust.emailFlags = CERTDB_VALID_CA;
    935                    }
    936                    if ((certtype & NS_CERT_TYPE_OBJECT_SIGNING_CA) ==
    937                        NS_CERT_TYPE_OBJECT_SIGNING_CA) {
    938                        trust.objectSigningFlags = CERTDB_VALID_CA;
    939                    }
    940                    break;
    941                default:
    942                    PORT_Assert(0);
    943                    break;
    944            }
    945        }
    946 
    947        cert = CERT_NewTempCertificate(handle, derCert, NULL,
    948                                       PR_FALSE, PR_FALSE);
    949        if (cert == NULL) {
    950            goto loser;
    951        }
    952 
    953        /* if the cert is temp, make it perm; otherwise we're done */
    954        rv = CERT_GetCertIsTemp(cert, &istemp);
    955        if (rv != SECSuccess) {
    956            goto loser;
    957        }
    958        if (istemp) {
    959            /* get a default nickname for it */
    960            nickname = CERT_MakeCANickname(cert);
    961 
    962            rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
    963 
    964            /* free the nickname */
    965            if (nickname) {
    966                PORT_Free(nickname);
    967            }
    968        } else {
    969            rv = SECSuccess;
    970        }
    971 
    972        if (rv != SECSuccess) {
    973            goto loser;
    974        }
    975 
    976    endloop:
    977        if (newcert) {
    978            CERT_DestroyCertificate(newcert);
    979            newcert = NULL;
    980        }
    981    }
    982 
    983    rv = SECSuccess;
    984    goto done;
    985 loser:
    986    rv = SECFailure;
    987 done:
    988 
    989    if (newcert) {
    990        CERT_DestroyCertificate(newcert);
    991        newcert = NULL;
    992    }
    993 
    994    if (cert) {
    995        CERT_DestroyCertificate(cert);
    996        cert = NULL;
    997    }
    998 
    999    return (rv);
   1000 }
   1001 
   1002 SECStatus
   1003 CERT_ImportCAChain(SECItem *certs, int numcerts, SECCertUsage certUsage)
   1004 {
   1005    return cert_ImportCAChain(certs, numcerts, certUsage, PR_FALSE);
   1006 }
   1007 
   1008 SECStatus
   1009 CERT_ImportCAChainTrusted(SECItem *certs, int numcerts, SECCertUsage certUsage)
   1010 {
   1011    return cert_ImportCAChain(certs, numcerts, certUsage, PR_TRUE);
   1012 }
   1013 
   1014 /* Moved from certdb.c */
   1015 /*
   1016 ** CERT_CertChainFromCert
   1017 **
   1018 ** Construct a CERTCertificateList consisting of the given certificate and all
   1019 ** of the issuer certs until we either get to a self-signed cert or can't find
   1020 ** an issuer.  Since we don't know how many certs are in the chain we have to
   1021 ** build a linked list first as we count them.
   1022 */
   1023 
   1024 typedef struct certNode {
   1025    struct certNode *next;
   1026    CERTCertificate *cert;
   1027 } certNode;
   1028 
   1029 CERTCertificateList *
   1030 CERT_CertChainFromCert(CERTCertificate *cert, SECCertUsage usage,
   1031                       PRBool includeRoot)
   1032 {
   1033    CERTCertificateList *chain = NULL;
   1034    NSSCertificate **stanChain;
   1035    NSSCertificate *stanCert;
   1036    PLArenaPool *arena;
   1037    NSSUsage nssUsage;
   1038    int i, len;
   1039    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
   1040    NSSCryptoContext *cc = STAN_GetDefaultCryptoContext();
   1041 
   1042    stanCert = STAN_GetNSSCertificate(cert);
   1043    if (!stanCert) {
   1044        /* error code is set */
   1045        return NULL;
   1046    }
   1047    nssUsage.anyUsage = PR_FALSE;
   1048    nssUsage.nss3usage = usage;
   1049    nssUsage.nss3lookingForCA = PR_FALSE;
   1050    stanChain = NSSCertificate_BuildChain(stanCert, NULL, &nssUsage, NULL, NULL,
   1051                                          CERT_MAX_CERT_CHAIN, NULL, NULL, td, cc);
   1052    if (!stanChain) {
   1053        PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
   1054        return NULL;
   1055    }
   1056 
   1057    len = 0;
   1058    stanCert = stanChain[0];
   1059    while (stanCert) {
   1060        stanCert = stanChain[++len];
   1061    }
   1062 
   1063    arena = PORT_NewArena(4096);
   1064    if (arena == NULL) {
   1065        goto loser;
   1066    }
   1067 
   1068    chain = (CERTCertificateList *)PORT_ArenaAlloc(arena,
   1069                                                   sizeof(CERTCertificateList));
   1070    if (!chain)
   1071        goto loser;
   1072    chain->certs = (SECItem *)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
   1073    if (!chain->certs)
   1074        goto loser;
   1075    i = 0;
   1076    stanCert = stanChain[i];
   1077    while (stanCert) {
   1078        SECItem derCert;
   1079        CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
   1080        if (!cCert) {
   1081            goto loser;
   1082        }
   1083        derCert.len = (unsigned int)stanCert->encoding.size;
   1084        derCert.data = (unsigned char *)stanCert->encoding.data;
   1085        derCert.type = siBuffer;
   1086        if (SECITEM_CopyItem(arena, &chain->certs[i], &derCert) != SECSuccess) {
   1087            CERT_DestroyCertificate(cCert);
   1088            goto loser;
   1089        }
   1090        stanCert = stanChain[++i];
   1091        if (!stanCert && !cCert->isRoot) {
   1092            /* reached the end of the chain, but the final cert is
   1093             * not a root.  Don't discard it.
   1094             */
   1095            includeRoot = PR_TRUE;
   1096        }
   1097        CERT_DestroyCertificate(cCert);
   1098    }
   1099    if (!includeRoot && len > 1) {
   1100        chain->len = len - 1;
   1101    } else {
   1102        chain->len = len;
   1103    }
   1104 
   1105    chain->arena = arena;
   1106    nss_ZFreeIf(stanChain);
   1107    return chain;
   1108 loser:
   1109    i = 0;
   1110    stanCert = stanChain[i];
   1111    while (stanCert) {
   1112        CERTCertificate *cCert = STAN_GetCERTCertificate(stanCert);
   1113        if (cCert) {
   1114            CERT_DestroyCertificate(cCert);
   1115        }
   1116        stanCert = stanChain[++i];
   1117    }
   1118    nss_ZFreeIf(stanChain);
   1119    if (arena) {
   1120        PORT_FreeArena(arena, PR_FALSE);
   1121    }
   1122    return NULL;
   1123 }
   1124 
   1125 /* Builds a CERTCertificateList holding just one DER-encoded cert, namely
   1126 ** the one for the cert passed as an argument.
   1127 */
   1128 CERTCertificateList *
   1129 CERT_CertListFromCert(CERTCertificate *cert)
   1130 {
   1131    CERTCertificateList *chain = NULL;
   1132    int rv;
   1133    PLArenaPool *arena;
   1134 
   1135    /* arena for SecCertificateList */
   1136    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1137    if (arena == NULL)
   1138        goto no_memory;
   1139 
   1140    /* build the CERTCertificateList */
   1141    chain = (CERTCertificateList *)PORT_ArenaAlloc(arena, sizeof(CERTCertificateList));
   1142    if (chain == NULL)
   1143        goto no_memory;
   1144    chain->certs = (SECItem *)PORT_ArenaAlloc(arena, 1 * sizeof(SECItem));
   1145    if (chain->certs == NULL)
   1146        goto no_memory;
   1147    rv = SECITEM_CopyItem(arena, chain->certs, &(cert->derCert));
   1148    if (rv < 0)
   1149        goto loser;
   1150    chain->len = 1;
   1151    chain->arena = arena;
   1152 
   1153    return chain;
   1154 
   1155 no_memory:
   1156    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1157 loser:
   1158    if (arena != NULL) {
   1159        PORT_FreeArena(arena, PR_FALSE);
   1160    }
   1161    return NULL;
   1162 }
   1163 
   1164 CERTCertificateList *
   1165 CERT_DupCertList(const CERTCertificateList *oldList)
   1166 {
   1167    CERTCertificateList *newList = NULL;
   1168    PLArenaPool *arena = NULL;
   1169    SECItem *newItem;
   1170    SECItem *oldItem;
   1171    int len = oldList->len;
   1172    int rv;
   1173 
   1174    /* arena for SecCertificateList */
   1175    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1176    if (arena == NULL)
   1177        goto no_memory;
   1178 
   1179    /* now build the CERTCertificateList */
   1180    newList = PORT_ArenaNew(arena, CERTCertificateList);
   1181    if (newList == NULL)
   1182        goto no_memory;
   1183    newList->arena = arena;
   1184    newItem = (SECItem *)PORT_ArenaAlloc(arena, len * sizeof(SECItem));
   1185    if (newItem == NULL)
   1186        goto no_memory;
   1187    newList->certs = newItem;
   1188    newList->len = len;
   1189 
   1190    for (oldItem = oldList->certs; len > 0; --len, ++newItem, ++oldItem) {
   1191        rv = SECITEM_CopyItem(arena, newItem, oldItem);
   1192        if (rv < 0)
   1193            goto loser;
   1194    }
   1195    return newList;
   1196 
   1197 no_memory:
   1198    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1199 loser:
   1200    if (arena != NULL) {
   1201        PORT_FreeArena(arena, PR_FALSE);
   1202    }
   1203    return NULL;
   1204 }
   1205 
   1206 void
   1207 CERT_DestroyCertificateList(CERTCertificateList *list)
   1208 {
   1209    PORT_FreeArena(list->arena, PR_FALSE);
   1210 }