tor-browser

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

certificate.c (31987B)


      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 #ifndef NSSPKI_H
      6 #include "nsspki.h"
      7 #endif /* NSSPKI_H */
      8 
      9 #ifndef PKIT_H
     10 #include "pkit.h"
     11 #endif /* PKIT_H */
     12 
     13 #ifndef PKIM_H
     14 #include "pkim.h"
     15 #endif /* PKIM_H */
     16 
     17 #ifndef DEV_H
     18 #include "dev.h"
     19 #endif /* DEV_H */
     20 
     21 #include "pkistore.h"
     22 
     23 #include "pki3hack.h"
     24 #include "pk11func.h"
     25 #include "hasht.h"
     26 
     27 #ifndef BASE_H
     28 #include "base.h"
     29 #endif /* BASE_H */
     30 
     31 extern const NSSError NSS_ERROR_NOT_FOUND;
     32 
     33 /* Creates a certificate from a base object */
     34 NSS_IMPLEMENT NSSCertificate *
     35 nssCertificate_Create(
     36    nssPKIObject *object)
     37 {
     38    PRStatus status;
     39    NSSCertificate *rvCert;
     40    nssArenaMark *mark;
     41    NSSArena *arena = object->arena;
     42    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
     43    PR_ASSERT(object->lockType == nssPKIMonitor);
     44    mark = nssArena_Mark(arena);
     45    rvCert = nss_ZNEW(arena, NSSCertificate);
     46    if (!rvCert) {
     47        return (NSSCertificate *)NULL;
     48    }
     49    rvCert->object = *object;
     50    /* XXX should choose instance based on some criteria */
     51    status = nssCryptokiCertificate_GetAttributes(object->instances[0],
     52                                                  NULL, /* XXX sessionOpt */
     53                                                  arena,
     54                                                  &rvCert->type,
     55                                                  &rvCert->id,
     56                                                  &rvCert->encoding,
     57                                                  &rvCert->issuer,
     58                                                  &rvCert->serial,
     59                                                  &rvCert->subject);
     60    if (status != PR_SUCCESS ||
     61        !rvCert->encoding.data ||
     62        !rvCert->encoding.size ||
     63        !rvCert->issuer.data ||
     64        !rvCert->issuer.size ||
     65        !rvCert->serial.data ||
     66        !rvCert->serial.size) {
     67        if (mark)
     68            nssArena_Release(arena, mark);
     69        return (NSSCertificate *)NULL;
     70    }
     71    if (mark)
     72        nssArena_Unmark(arena, mark);
     73    return rvCert;
     74 }
     75 
     76 NSS_IMPLEMENT NSSCertificate *
     77 nssCertificate_AddRef(
     78    NSSCertificate *c)
     79 {
     80    if (c) {
     81        nssPKIObject_AddRef(&c->object);
     82    }
     83    return c;
     84 }
     85 
     86 NSS_IMPLEMENT PRStatus
     87 nssCertificate_Destroy(
     88    NSSCertificate *c)
     89 {
     90    nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
     91    nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
     92 
     93    if (c) {
     94        PRUint32 i;
     95        nssDecodedCert *dc = c->decoding;
     96        NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
     97        NSSCryptoContext *cc = c->object.cryptoContext;
     98 
     99        PR_ASSERT(c->object.refCount > 0);
    100 
    101        /* --- LOCK storage --- */
    102        if (cc) {
    103            nssCertificateStore_Lock(cc->certStore, &lockTrace);
    104        } else {
    105            nssTrustDomain_LockCertCache(td);
    106        }
    107        if (PR_ATOMIC_DECREMENT(&c->object.refCount) == 0) {
    108            /* --- remove cert and UNLOCK storage --- */
    109            if (cc) {
    110                nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
    111                nssCertificateStore_Unlock(cc->certStore, &lockTrace,
    112                                           &unlockTrace);
    113            } else {
    114                nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
    115                nssTrustDomain_UnlockCertCache(td);
    116            }
    117            /* free cert data */
    118            for (i = 0; i < c->object.numInstances; i++) {
    119                nssCryptokiObject_Destroy(c->object.instances[i]);
    120            }
    121            nssPKIObject_DestroyLock(&c->object);
    122            nssArena_Destroy(c->object.arena);
    123            nssDecodedCert_Destroy(dc);
    124        } else {
    125            /* --- UNLOCK storage --- */
    126            if (cc) {
    127                nssCertificateStore_Unlock(cc->certStore,
    128                                           &lockTrace,
    129                                           &unlockTrace);
    130            } else {
    131                nssTrustDomain_UnlockCertCache(td);
    132            }
    133        }
    134    }
    135    return PR_SUCCESS;
    136 }
    137 
    138 NSS_IMPLEMENT PRStatus
    139 NSSCertificate_Destroy(NSSCertificate *c)
    140 {
    141    return nssCertificate_Destroy(c);
    142 }
    143 
    144 NSS_IMPLEMENT NSSDER *
    145 nssCertificate_GetEncoding(NSSCertificate *c)
    146 {
    147    if (c->encoding.size > 0 && c->encoding.data) {
    148        return &c->encoding;
    149    } else {
    150        return (NSSDER *)NULL;
    151    }
    152 }
    153 
    154 NSS_IMPLEMENT NSSDER *
    155 nssCertificate_GetIssuer(NSSCertificate *c)
    156 {
    157    if (c->issuer.size > 0 && c->issuer.data) {
    158        return &c->issuer;
    159    } else {
    160        return (NSSDER *)NULL;
    161    }
    162 }
    163 
    164 NSS_IMPLEMENT NSSDER *
    165 nssCertificate_GetSerialNumber(NSSCertificate *c)
    166 {
    167    if (c->serial.size > 0 && c->serial.data) {
    168        return &c->serial;
    169    } else {
    170        return (NSSDER *)NULL;
    171    }
    172 }
    173 
    174 NSS_IMPLEMENT NSSDER *
    175 nssCertificate_GetSubject(NSSCertificate *c)
    176 {
    177    if (c->subject.size > 0 && c->subject.data) {
    178        return &c->subject;
    179    } else {
    180        return (NSSDER *)NULL;
    181    }
    182 }
    183 
    184 /* Returns a copy, Caller must free using nss_ZFreeIf */
    185 NSS_IMPLEMENT NSSUTF8 *
    186 nssCertificate_GetNickname(
    187    NSSCertificate *c,
    188    NSSToken *tokenOpt)
    189 {
    190    return nssPKIObject_GetNicknameForToken(&c->object, tokenOpt);
    191 }
    192 
    193 NSS_IMPLEMENT NSSASCII7 *
    194 nssCertificate_GetEmailAddress(NSSCertificate *c)
    195 {
    196    return c->email;
    197 }
    198 
    199 NSS_IMPLEMENT PRStatus
    200 NSSCertificate_DeleteStoredObject(
    201    NSSCertificate *c,
    202    NSSCallback *uhh)
    203 {
    204    return nssPKIObject_DeleteStoredObject(&c->object, uhh, PR_TRUE);
    205 }
    206 
    207 NSS_IMPLEMENT PRStatus
    208 NSSCertificate_Validate(
    209    NSSCertificate *c,
    210    NSSTime *timeOpt, /* NULL for "now" */
    211    NSSUsage *usage,
    212    NSSPolicies *policiesOpt /* NULL for none */
    213 )
    214 {
    215    nss_SetError(NSS_ERROR_NOT_FOUND);
    216    return PR_FAILURE;
    217 }
    218 
    219 NSS_IMPLEMENT void ** /* void *[] */
    220 NSSCertificate_ValidateCompletely(
    221    NSSCertificate *c,
    222    NSSTime *timeOpt, /* NULL for "now" */
    223    NSSUsage *usage,
    224    NSSPolicies *policiesOpt, /* NULL for none */
    225    void **rvOpt,             /* NULL for allocate */
    226    PRUint32 rvLimit,         /* zero for no limit */
    227    NSSArena *arenaOpt        /* NULL for heap */
    228 )
    229 {
    230    nss_SetError(NSS_ERROR_NOT_FOUND);
    231    return NULL;
    232 }
    233 
    234 NSS_IMPLEMENT PRStatus
    235 NSSCertificate_ValidateAndDiscoverUsagesAndPolicies(
    236    NSSCertificate *c,
    237    NSSTime **notBeforeOutOpt,
    238    NSSTime **notAfterOutOpt,
    239    void *allowedUsages,
    240    void *disallowedUsages,
    241    void *allowedPolicies,
    242    void *disallowedPolicies,
    243    /* more args.. work on this fgmr */
    244    NSSArena *arenaOpt)
    245 {
    246    nss_SetError(NSS_ERROR_NOT_FOUND);
    247    return PR_FAILURE;
    248 }
    249 
    250 NSS_IMPLEMENT NSSDER *
    251 NSSCertificate_Encode(
    252    NSSCertificate *c,
    253    NSSDER *rvOpt,
    254    NSSArena *arenaOpt)
    255 {
    256    /* Item, DER, BER are all typedefs now... */
    257    return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt);
    258 }
    259 
    260 NSS_IMPLEMENT nssDecodedCert *
    261 nssCertificate_GetDecoding(
    262    NSSCertificate *c)
    263 {
    264    nssDecodedCert *deco = NULL;
    265    if (c->type == NSSCertificateType_PKIX) {
    266        (void)STAN_GetCERTCertificate(c);
    267    }
    268    nssPKIObject_Lock(&c->object);
    269    if (!c->decoding) {
    270        deco = nssDecodedCert_Create(NULL, &c->encoding, c->type);
    271        PORT_Assert(!c->decoding);
    272        c->decoding = deco;
    273    } else {
    274        deco = c->decoding;
    275    }
    276    nssPKIObject_Unlock(&c->object);
    277    return deco;
    278 }
    279 
    280 static NSSCertificate **
    281 filter_subject_certs_for_id(
    282    NSSCertificate **subjectCerts,
    283    void *id)
    284 {
    285    NSSCertificate **si;
    286    nssDecodedCert *dcp;
    287    int nextOpenSlot = 0;
    288    int i;
    289    nssCertIDMatch matchLevel = nssCertIDMatch_Unknown;
    290    nssCertIDMatch match;
    291 
    292    /* walk the subject certs */
    293    for (si = subjectCerts; *si; si++) {
    294        dcp = nssCertificate_GetDecoding(*si);
    295        if (!dcp) {
    296            NSSCertificate_Destroy(*si);
    297            continue;
    298        }
    299        match = dcp->matchIdentifier(dcp, id);
    300        switch (match) {
    301            case nssCertIDMatch_Yes:
    302                if (matchLevel == nssCertIDMatch_Unknown) {
    303                    /* we have non-definitive matches, forget them */
    304                    for (i = 0; i < nextOpenSlot; i++) {
    305                        NSSCertificate_Destroy(subjectCerts[i]);
    306                        subjectCerts[i] = NULL;
    307                    }
    308                    nextOpenSlot = 0;
    309                    /* only keep definitive matches from now on */
    310                    matchLevel = nssCertIDMatch_Yes;
    311                }
    312                /* keep the cert */
    313                subjectCerts[nextOpenSlot++] = *si;
    314                break;
    315            case nssCertIDMatch_Unknown:
    316                if (matchLevel == nssCertIDMatch_Unknown) {
    317                    /* only have non-definitive matches so far, keep it */
    318                    subjectCerts[nextOpenSlot++] = *si;
    319                    break;
    320                }
    321            /* else fall through, we have a definitive match already */
    322            case nssCertIDMatch_No:
    323            default:
    324                NSSCertificate_Destroy(*si);
    325                *si = NULL;
    326        }
    327    }
    328    subjectCerts[nextOpenSlot] = NULL;
    329    return subjectCerts;
    330 }
    331 
    332 static NSSCertificate **
    333 filter_certs_for_valid_issuers(NSSCertificate **certs)
    334 {
    335    NSSCertificate **cp;
    336    nssDecodedCert *dcp;
    337    int nextOpenSlot = 0;
    338 
    339    for (cp = certs; *cp; cp++) {
    340        dcp = nssCertificate_GetDecoding(*cp);
    341        if (dcp && dcp->isValidIssuer(dcp)) {
    342            certs[nextOpenSlot++] = *cp;
    343        } else {
    344            NSSCertificate_Destroy(*cp);
    345        }
    346    }
    347    certs[nextOpenSlot] = NULL;
    348    return certs;
    349 }
    350 
    351 static NSSCertificate *
    352 find_cert_issuer(
    353    NSSCertificate *c,
    354    NSSTime *timeOpt,
    355    NSSUsage *usage,
    356    NSSPolicies *policiesOpt,
    357    NSSTrustDomain *td,
    358    NSSCryptoContext *cc)
    359 {
    360    NSSArena *arena;
    361    NSSCertificate **certs = NULL;
    362    NSSCertificate **ccIssuers = NULL;
    363    NSSCertificate **tdIssuers = NULL;
    364    NSSCertificate *issuer = NULL;
    365 
    366    if (!cc)
    367        cc = c->object.cryptoContext;
    368    if (!td)
    369        td = NSSCertificate_GetTrustDomain(c);
    370    arena = nssArena_Create();
    371    if (!arena) {
    372        return (NSSCertificate *)NULL;
    373    }
    374    if (cc) {
    375        ccIssuers = nssCryptoContext_FindCertificatesBySubject(cc,
    376                                                               &c->issuer,
    377                                                               NULL,
    378                                                               0,
    379                                                               arena);
    380    }
    381    if (td)
    382        tdIssuers = nssTrustDomain_FindCertificatesBySubject(td,
    383                                                             &c->issuer,
    384                                                             NULL,
    385                                                             0,
    386                                                             arena);
    387    certs = nssCertificateArray_Join(ccIssuers, tdIssuers);
    388    if (certs) {
    389        nssDecodedCert *dc = NULL;
    390        void *issuerID = NULL;
    391        dc = nssCertificate_GetDecoding(c);
    392        if (dc) {
    393            issuerID = dc->getIssuerIdentifier(dc);
    394        }
    395        /* XXX review based on CERT_FindCertIssuer
    396         * this function is not using the authCertIssuer field as a fallback
    397         * if authority key id does not exist
    398         */
    399        if (issuerID) {
    400            certs = filter_subject_certs_for_id(certs, issuerID);
    401        }
    402        certs = filter_certs_for_valid_issuers(certs);
    403        issuer = nssCertificateArray_FindBestCertificate(certs,
    404                                                         timeOpt,
    405                                                         usage,
    406                                                         policiesOpt);
    407        nssCertificateArray_Destroy(certs);
    408    }
    409    nssArena_Destroy(arena);
    410    return issuer;
    411 }
    412 
    413 /* This function returns the built chain, as far as it gets,
    414 ** even if/when it fails to find an issuer, and returns PR_FAILURE
    415 */
    416 NSS_IMPLEMENT NSSCertificate **
    417 nssCertificate_BuildChain(
    418    NSSCertificate *c,
    419    NSSTime *timeOpt,
    420    NSSUsage *usage,
    421    NSSPolicies *policiesOpt,
    422    NSSCertificate **rvOpt,
    423    PRUint32 rvLimit,
    424    NSSArena *arenaOpt,
    425    PRStatus *statusOpt,
    426    NSSTrustDomain *td,
    427    NSSCryptoContext *cc)
    428 {
    429    NSSCertificate **rvChain = NULL;
    430    NSSUsage issuerUsage = *usage;
    431    nssPKIObjectCollection *collection = NULL;
    432    PRUint32 rvCount = 0;
    433    PRStatus st;
    434    PRStatus ret = PR_SUCCESS;
    435 
    436    if (!c || !cc ||
    437        (!td && (td = NSSCertificate_GetTrustDomain(c)) == NULL)) {
    438        goto loser;
    439    }
    440    /* bump the usage up to CA level */
    441    issuerUsage.nss3lookingForCA = PR_TRUE;
    442    collection = nssCertificateCollection_Create(td, NULL);
    443    if (!collection)
    444        goto loser;
    445    st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
    446    if (st != PR_SUCCESS)
    447        goto loser;
    448    for (rvCount = 1; (!rvLimit || rvCount < rvLimit); ++rvCount) {
    449        CERTCertificate *cCert = STAN_GetCERTCertificate(c);
    450        if (cCert->isRoot) {
    451            /* not including the issuer of the self-signed cert, which is,
    452             * of course, itself
    453             */
    454            break;
    455        }
    456        c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt, td, cc);
    457        if (!c) {
    458            ret = PR_FAILURE;
    459            break;
    460        }
    461        st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
    462        nssCertificate_Destroy(c); /* collection has it */
    463        if (st != PR_SUCCESS)
    464            goto loser;
    465    }
    466    rvChain = nssPKIObjectCollection_GetCertificates(collection,
    467                                                     rvOpt,
    468                                                     rvLimit,
    469                                                     arenaOpt);
    470    if (rvChain) {
    471        nssPKIObjectCollection_Destroy(collection);
    472        if (statusOpt)
    473            *statusOpt = ret;
    474        if (ret != PR_SUCCESS)
    475            nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
    476        return rvChain;
    477    }
    478 
    479 loser:
    480    if (collection)
    481        nssPKIObjectCollection_Destroy(collection);
    482    if (statusOpt)
    483        *statusOpt = PR_FAILURE;
    484    nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
    485    return rvChain;
    486 }
    487 
    488 NSS_IMPLEMENT NSSCertificate **
    489 NSSCertificate_BuildChain(
    490    NSSCertificate *c,
    491    NSSTime *timeOpt,
    492    NSSUsage *usage,
    493    NSSPolicies *policiesOpt,
    494    NSSCertificate **rvOpt,
    495    PRUint32 rvLimit, /* zero for no limit */
    496    NSSArena *arenaOpt,
    497    PRStatus *statusOpt,
    498    NSSTrustDomain *td,
    499    NSSCryptoContext *cc)
    500 {
    501    return nssCertificate_BuildChain(c, timeOpt, usage, policiesOpt,
    502                                     rvOpt, rvLimit, arenaOpt, statusOpt,
    503                                     td, cc);
    504 }
    505 
    506 NSS_IMPLEMENT NSSCryptoContext *
    507 nssCertificate_GetCryptoContext(NSSCertificate *c)
    508 {
    509    return c->object.cryptoContext;
    510 }
    511 
    512 NSS_IMPLEMENT NSSTrustDomain *
    513 nssCertificate_GetTrustDomain(NSSCertificate *c)
    514 {
    515    return c->object.trustDomain;
    516 }
    517 
    518 NSS_IMPLEMENT NSSTrustDomain *
    519 NSSCertificate_GetTrustDomain(NSSCertificate *c)
    520 {
    521    return nssCertificate_GetTrustDomain(c);
    522 }
    523 
    524 NSS_IMPLEMENT NSSToken *
    525 NSSCertificate_GetToken(
    526    NSSCertificate *c,
    527    PRStatus *statusOpt)
    528 {
    529    return (NSSToken *)NULL;
    530 }
    531 
    532 NSS_IMPLEMENT NSSSlot *
    533 NSSCertificate_GetSlot(
    534    NSSCertificate *c,
    535    PRStatus *statusOpt)
    536 {
    537    return (NSSSlot *)NULL;
    538 }
    539 
    540 NSS_IMPLEMENT NSSModule *
    541 NSSCertificate_GetModule(
    542    NSSCertificate *c,
    543    PRStatus *statusOpt)
    544 {
    545    return (NSSModule *)NULL;
    546 }
    547 
    548 NSS_IMPLEMENT NSSItem *
    549 NSSCertificate_Encrypt(
    550    NSSCertificate *c,
    551    NSSAlgorithmAndParameters *apOpt,
    552    NSSItem *data,
    553    NSSTime *timeOpt,
    554    NSSUsage *usage,
    555    NSSPolicies *policiesOpt,
    556    NSSCallback *uhh,
    557    NSSItem *rvOpt,
    558    NSSArena *arenaOpt)
    559 {
    560    nss_SetError(NSS_ERROR_NOT_FOUND);
    561    return NULL;
    562 }
    563 
    564 NSS_IMPLEMENT PRStatus
    565 NSSCertificate_Verify(
    566    NSSCertificate *c,
    567    NSSAlgorithmAndParameters *apOpt,
    568    NSSItem *data,
    569    NSSItem *signature,
    570    NSSTime *timeOpt,
    571    NSSUsage *usage,
    572    NSSPolicies *policiesOpt,
    573    NSSCallback *uhh)
    574 {
    575    nss_SetError(NSS_ERROR_NOT_FOUND);
    576    return PR_FAILURE;
    577 }
    578 
    579 NSS_IMPLEMENT NSSItem *
    580 NSSCertificate_VerifyRecover(
    581    NSSCertificate *c,
    582    NSSAlgorithmAndParameters *apOpt,
    583    NSSItem *signature,
    584    NSSTime *timeOpt,
    585    NSSUsage *usage,
    586    NSSPolicies *policiesOpt,
    587    NSSCallback *uhh,
    588    NSSItem *rvOpt,
    589    NSSArena *arenaOpt)
    590 {
    591    nss_SetError(NSS_ERROR_NOT_FOUND);
    592    return NULL;
    593 }
    594 
    595 NSS_IMPLEMENT NSSItem *
    596 NSSCertificate_WrapSymmetricKey(
    597    NSSCertificate *c,
    598    NSSAlgorithmAndParameters *apOpt,
    599    NSSSymmetricKey *keyToWrap,
    600    NSSTime *timeOpt,
    601    NSSUsage *usage,
    602    NSSPolicies *policiesOpt,
    603    NSSCallback *uhh,
    604    NSSItem *rvOpt,
    605    NSSArena *arenaOpt)
    606 {
    607    nss_SetError(NSS_ERROR_NOT_FOUND);
    608    return NULL;
    609 }
    610 
    611 NSS_IMPLEMENT NSSCryptoContext *
    612 NSSCertificate_CreateCryptoContext(
    613    NSSCertificate *c,
    614    NSSAlgorithmAndParameters *apOpt,
    615    NSSTime *timeOpt,
    616    NSSUsage *usage,
    617    NSSPolicies *policiesOpt,
    618    NSSCallback *uhh)
    619 {
    620    nss_SetError(NSS_ERROR_NOT_FOUND);
    621    return NULL;
    622 }
    623 
    624 NSS_IMPLEMENT NSSPublicKey *
    625 NSSCertificate_GetPublicKey(
    626    NSSCertificate *c)
    627 {
    628 #if 0
    629    CK_ATTRIBUTE pubktemplate[] = {
    630    { CKA_CLASS,   NULL, 0 },
    631    { CKA_ID,      NULL, 0 },
    632    { CKA_SUBJECT, NULL, 0 }
    633    };
    634    PRStatus nssrv;
    635    CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]);
    636    NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey);
    637    if (c->id.size > 0) {
    638    /* CKA_ID */
    639    NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]);
    640    } else {
    641    /* failure, yes? */
    642    return (NSSPublicKey *)NULL;
    643    }
    644    if (c->subject.size > 0) {
    645    /* CKA_SUBJECT */
    646    NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]);
    647    } else {
    648    /* failure, yes? */
    649    return (NSSPublicKey *)NULL;
    650    }
    651    /* Try the cert's token first */
    652    if (c->token) {
    653    nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count);
    654    }
    655 #endif
    656    /* Try all other key tokens */
    657    return (NSSPublicKey *)NULL;
    658 }
    659 
    660 NSS_IMPLEMENT NSSPrivateKey *
    661 NSSCertificate_FindPrivateKey(
    662    NSSCertificate *c,
    663    NSSCallback *uhh)
    664 {
    665    nss_SetError(NSS_ERROR_NOT_FOUND);
    666    return NULL;
    667 }
    668 
    669 NSS_IMPLEMENT PRBool
    670 NSSCertificate_IsPrivateKeyAvailable(
    671    NSSCertificate *c,
    672    NSSCallback *uhh,
    673    PRStatus *statusOpt)
    674 {
    675    PRBool isUser = PR_FALSE;
    676    nssCryptokiObject **ip;
    677    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
    678    if (!instances) {
    679        return PR_FALSE;
    680    }
    681    for (ip = instances; *ip; ip++) {
    682        nssCryptokiObject *instance = *ip;
    683        if (nssToken_IsPrivateKeyAvailable(instance->token, c, instance)) {
    684            isUser = PR_TRUE;
    685        }
    686    }
    687    nssCryptokiObjectArray_Destroy(instances);
    688    return isUser;
    689 }
    690 
    691 /* sort the subject cert list from newest to oldest */
    692 PRIntn
    693 nssCertificate_SubjectListSort(
    694    void *v1,
    695    void *v2)
    696 {
    697    NSSCertificate *c1 = (NSSCertificate *)v1;
    698    NSSCertificate *c2 = (NSSCertificate *)v2;
    699    nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1);
    700    nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2);
    701    if (!dc1) {
    702        return dc2 ? 1 : 0;
    703    } else if (!dc2) {
    704        return -1;
    705    } else {
    706        return dc1->isNewerThan(dc1, dc2) ? -1 : 1;
    707    }
    708 }
    709 
    710 NSS_IMPLEMENT PRBool
    711 NSSUserCertificate_IsStillPresent(
    712    NSSUserCertificate *uc,
    713    PRStatus *statusOpt)
    714 {
    715    nss_SetError(NSS_ERROR_NOT_FOUND);
    716    return PR_FALSE;
    717 }
    718 
    719 NSS_IMPLEMENT NSSItem *
    720 NSSUserCertificate_Decrypt(
    721    NSSUserCertificate *uc,
    722    NSSAlgorithmAndParameters *apOpt,
    723    NSSItem *data,
    724    NSSTime *timeOpt,
    725    NSSUsage *usage,
    726    NSSPolicies *policiesOpt,
    727    NSSCallback *uhh,
    728    NSSItem *rvOpt,
    729    NSSArena *arenaOpt)
    730 {
    731    nss_SetError(NSS_ERROR_NOT_FOUND);
    732    return NULL;
    733 }
    734 
    735 NSS_IMPLEMENT NSSItem *
    736 NSSUserCertificate_Sign(
    737    NSSUserCertificate *uc,
    738    NSSAlgorithmAndParameters *apOpt,
    739    NSSItem *data,
    740    NSSTime *timeOpt,
    741    NSSUsage *usage,
    742    NSSPolicies *policiesOpt,
    743    NSSCallback *uhh,
    744    NSSItem *rvOpt,
    745    NSSArena *arenaOpt)
    746 {
    747    nss_SetError(NSS_ERROR_NOT_FOUND);
    748    return NULL;
    749 }
    750 
    751 NSS_IMPLEMENT NSSItem *
    752 NSSUserCertificate_SignRecover(
    753    NSSUserCertificate *uc,
    754    NSSAlgorithmAndParameters *apOpt,
    755    NSSItem *data,
    756    NSSTime *timeOpt,
    757    NSSUsage *usage,
    758    NSSPolicies *policiesOpt,
    759    NSSCallback *uhh,
    760    NSSItem *rvOpt,
    761    NSSArena *arenaOpt)
    762 {
    763    nss_SetError(NSS_ERROR_NOT_FOUND);
    764    return NULL;
    765 }
    766 
    767 NSS_IMPLEMENT NSSSymmetricKey *
    768 NSSUserCertificate_UnwrapSymmetricKey(
    769    NSSUserCertificate *uc,
    770    NSSAlgorithmAndParameters *apOpt,
    771    NSSItem *wrappedKey,
    772    NSSTime *timeOpt,
    773    NSSUsage *usage,
    774    NSSPolicies *policiesOpt,
    775    NSSCallback *uhh,
    776    NSSItem *rvOpt,
    777    NSSArena *arenaOpt)
    778 {
    779    nss_SetError(NSS_ERROR_NOT_FOUND);
    780    return NULL;
    781 }
    782 
    783 NSS_IMPLEMENT NSSSymmetricKey *
    784 NSSUserCertificate_DeriveSymmetricKey(
    785    NSSUserCertificate *uc, /* provides private key */
    786    NSSCertificate *c,      /* provides public key */
    787    NSSAlgorithmAndParameters *apOpt,
    788    NSSOID *target,
    789    PRUint32 keySizeOpt, /* zero for best allowed */
    790    NSSOperations operations,
    791    NSSCallback *uhh)
    792 {
    793    nss_SetError(NSS_ERROR_NOT_FOUND);
    794    return NULL;
    795 }
    796 
    797 NSS_IMPLEMENT nssSMIMEProfile *
    798 nssSMIMEProfile_Create(
    799    NSSCertificate *cert,
    800    NSSItem *profileTime,
    801    NSSItem *profileData)
    802 {
    803    NSSArena *arena;
    804    nssSMIMEProfile *rvProfile;
    805    nssPKIObject *object;
    806    NSSTrustDomain *td = nssCertificate_GetTrustDomain(cert);
    807    NSSCryptoContext *cc = nssCertificate_GetCryptoContext(cert);
    808    arena = nssArena_Create();
    809    if (!arena) {
    810        return NULL;
    811    }
    812    object = nssPKIObject_Create(arena, NULL, td, cc, nssPKILock);
    813    if (!object) {
    814        goto loser;
    815    }
    816    rvProfile = nss_ZNEW(arena, nssSMIMEProfile);
    817    if (!rvProfile) {
    818        goto loser;
    819    }
    820    rvProfile->object = *object;
    821    rvProfile->certificate = cert;
    822    rvProfile->email = nssUTF8_Duplicate(cert->email, arena);
    823    rvProfile->subject = nssItem_Duplicate(&cert->subject, arena, NULL);
    824    if (profileTime) {
    825        rvProfile->profileTime = nssItem_Duplicate(profileTime, arena, NULL);
    826    }
    827    if (profileData) {
    828        rvProfile->profileData = nssItem_Duplicate(profileData, arena, NULL);
    829    }
    830    return rvProfile;
    831 loser:
    832    if (object)
    833        nssPKIObject_Destroy(object);
    834    else if (arena)
    835        nssArena_Destroy(arena);
    836    return (nssSMIMEProfile *)NULL;
    837 }
    838 
    839 /* execute a callback function on all members of a cert list */
    840 NSS_EXTERN PRStatus
    841 nssCertificateList_DoCallback(
    842    nssList *certList,
    843    PRStatus (*callback)(NSSCertificate *c, void *arg),
    844    void *arg)
    845 {
    846    nssListIterator *certs;
    847    NSSCertificate *cert;
    848    certs = nssList_CreateIterator(certList);
    849    if (!certs) {
    850        return PR_FAILURE;
    851    }
    852    for (cert = (NSSCertificate *)nssListIterator_Start(certs);
    853         cert != (NSSCertificate *)NULL;
    854         cert = (NSSCertificate *)nssListIterator_Next(certs)) {
    855        (void)(*callback)(cert, arg);
    856    }
    857    nssListIterator_Finish(certs);
    858    nssListIterator_Destroy(certs);
    859    return PR_SUCCESS;
    860 }
    861 
    862 static PRStatus
    863 add_ref_callback(NSSCertificate *c, void *a)
    864 {
    865    nssCertificate_AddRef(c);
    866    return PR_SUCCESS;
    867 }
    868 
    869 NSS_IMPLEMENT void
    870 nssCertificateList_AddReferences(
    871    nssList *certList)
    872 {
    873    (void)nssCertificateList_DoCallback(certList, add_ref_callback, NULL);
    874 }
    875 
    876 /*
    877 * Is this trust record safe to apply to all certs of the same issuer/SN
    878 * independent of the cert matching the hash. This is only true is the trust
    879 * is unknown or distrusted. In general this feature is only useful to
    880 * explicitly distrusting certs. It is not safe to use to trust certs, so
    881 * only allow unknown and untrusted trust types.
    882 */
    883 PRBool
    884 nssTrust_IsSafeToIgnoreCertHash(nssTrustLevel serverAuth,
    885                                nssTrustLevel clientAuth, nssTrustLevel codeSigning,
    886                                nssTrustLevel email, PRBool stepup)
    887 {
    888    /* step up is a trust type, if it's on, we must have a hash for the cert */
    889    if (stepup) {
    890        return PR_FALSE;
    891    }
    892    if ((serverAuth != nssTrustLevel_Unknown) &&
    893        (serverAuth != nssTrustLevel_NotTrusted)) {
    894        return PR_FALSE;
    895    }
    896    if ((clientAuth != nssTrustLevel_Unknown) &&
    897        (clientAuth != nssTrustLevel_NotTrusted)) {
    898        return PR_FALSE;
    899    }
    900    if ((codeSigning != nssTrustLevel_Unknown) &&
    901        (codeSigning != nssTrustLevel_NotTrusted)) {
    902        return PR_FALSE;
    903    }
    904    if ((email != nssTrustLevel_Unknown) &&
    905        (email != nssTrustLevel_NotTrusted)) {
    906        return PR_FALSE;
    907    }
    908    /* record only has Unknown and Untrusted entries, ok to accept without a
    909     * hash */
    910    return PR_TRUE;
    911 }
    912 
    913 /* verify that hash and mechanism matches certifcate. This function
    914 * uses hashCache and hashCacheMech from the caller to allow us to
    915 * use previous calculated hash values if they are the same */
    916 static PRBool
    917 nssTrust_isValidHash(const NSSItem *hash, CK_MECHANISM_TYPE hashMech,
    918                     NSSItem *cert, NSSItem *hashCache,
    919                     CK_MECHANISM_TYPE *hashCacheMech)
    920 {
    921    if ((hashMech == CKM_INVALID_MECHANISM) || (hash->size == 0)) {
    922        return PR_FALSE;
    923    }
    924    if (*hashCacheMech != hashMech) {
    925        /* the cache doesn't have the correct mech, get a
    926         * new hash for the cert */
    927        hashCache->size = HASH_LENGTH_MAX;
    928        PRStatus ret = NSSAlgorithm_DigestBuf(hashMech, cert, hashCache);
    929        if (ret != PR_SUCCESS) {
    930            *hashCacheMech = CKM_INVALID_MECHANISM;
    931            return PR_FALSE;
    932        }
    933        *hashCacheMech = hashMech;
    934    }
    935    return ((hash->size == hashCache->size) && (PORT_Memcmp(hash->data,
    936                                                            hashCache->data,
    937                                                            hash->size) == 0));
    938 }
    939 
    940 NSS_IMPLEMENT NSSTrust *
    941 nssTrust_Create(
    942    nssPKIObject *object,
    943    NSSItem *certData)
    944 {
    945    PRStatus status;
    946    PRUint32 i;
    947    PRUint32 lastTrustOrder, myTrustOrder;
    948    unsigned char hashCacheBuf[HASH_LENGTH_MAX];
    949    unsigned char hashAttrBuf[HASH_LENGTH_MAX];
    950    NSSItem hashAttr = { hashAttrBuf, sizeof(hashAttrBuf) };
    951    NSSItem hashCache = { hashCacheBuf, sizeof(hashCacheBuf) };
    952    NSSTrust *rvt;
    953    CK_MECHANISM_TYPE hashMech = CKM_INVALID_MECHANISM;
    954    CK_MECHANISM_TYPE hashCacheMech = CKM_INVALID_MECHANISM;
    955    nssCryptokiObject *instance;
    956    nssTrustLevel serverAuth, clientAuth, codeSigning, emailProtection;
    957    PRBool stepUp;
    958 
    959    lastTrustOrder = 1 << 16; /* just make it big */
    960    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
    961    rvt = nss_ZNEW(object->arena, NSSTrust);
    962    if (!rvt) {
    963        return (NSSTrust *)NULL;
    964    }
    965    rvt->object = *object;
    966 
    967    /* trust has to peek into the base object members */
    968    nssPKIObject_Lock(object);
    969    for (i = 0; i < object->numInstances; i++) {
    970        hashAttr.size = sizeof(hashAttrBuf); /* reset to allocated size */
    971        instance = object->instances[i];
    972        myTrustOrder = nssToken_GetTrustOrder(instance->token);
    973        status = nssCryptokiTrust_GetAttributes(instance, NULL,
    974                                                &hashAttr,
    975                                                &hashMech,
    976                                                &serverAuth,
    977                                                &clientAuth,
    978                                                &codeSigning,
    979                                                &emailProtection,
    980                                                &stepUp);
    981        if (status != PR_SUCCESS) {
    982            nssPKIObject_Unlock(object);
    983            return (NSSTrust *)NULL;
    984        }
    985        /* if no hash is specified, then trust applies to all certs with
    986         * this issuer/SN. NOTE: This is only true for entries that
    987         * have distrust and unknown record */
    988        if (!(
    989                /* we continue if there is no hash, and the trust type is
    990                 * safe to accept without a hash ... or ... */
    991                (((hashAttr.size == 0) || (hashMech == CKM_INVALID_MECHANISM)) &&
    992                 nssTrust_IsSafeToIgnoreCertHash(serverAuth, clientAuth,
    993                                                 codeSigning, emailProtection,
    994                                                 stepUp)) ||
    995                /* we have a hash of the correct size, and it matches */
    996                nssTrust_isValidHash(&hashAttr, hashMech, certData,
    997                                     &hashCache, &hashCacheMech))) {
    998 
    999            nssPKIObject_Unlock(object);
   1000            return (NSSTrust *)NULL;
   1001        }
   1002        if (rvt->serverAuth == nssTrustLevel_Unknown ||
   1003            myTrustOrder < lastTrustOrder) {
   1004            rvt->serverAuth = serverAuth;
   1005        }
   1006        if (rvt->clientAuth == nssTrustLevel_Unknown ||
   1007            myTrustOrder < lastTrustOrder) {
   1008            rvt->clientAuth = clientAuth;
   1009        }
   1010        if (rvt->emailProtection == nssTrustLevel_Unknown ||
   1011            myTrustOrder < lastTrustOrder) {
   1012            rvt->emailProtection = emailProtection;
   1013        }
   1014        if (rvt->codeSigning == nssTrustLevel_Unknown ||
   1015            myTrustOrder < lastTrustOrder) {
   1016            rvt->codeSigning = codeSigning;
   1017        }
   1018        rvt->stepUpApproved = stepUp;
   1019        lastTrustOrder = myTrustOrder;
   1020    }
   1021    nssPKIObject_Unlock(object);
   1022    return rvt;
   1023 }
   1024 
   1025 NSS_IMPLEMENT NSSTrust *
   1026 nssTrust_AddRef(NSSTrust *trust)
   1027 {
   1028    if (trust) {
   1029        nssPKIObject_AddRef(&trust->object);
   1030    }
   1031    return trust;
   1032 }
   1033 
   1034 NSS_IMPLEMENT PRStatus
   1035 nssTrust_Destroy(NSSTrust *trust)
   1036 {
   1037    if (trust) {
   1038        (void)nssPKIObject_Destroy(&trust->object);
   1039    }
   1040    return PR_SUCCESS;
   1041 }
   1042 
   1043 NSS_IMPLEMENT nssSMIMEProfile *
   1044 nssSMIMEProfile_AddRef(nssSMIMEProfile *profile)
   1045 {
   1046    if (profile) {
   1047        nssPKIObject_AddRef(&profile->object);
   1048    }
   1049    return profile;
   1050 }
   1051 
   1052 NSS_IMPLEMENT PRStatus
   1053 nssSMIMEProfile_Destroy(nssSMIMEProfile *profile)
   1054 {
   1055    if (profile) {
   1056        (void)nssPKIObject_Destroy(&profile->object);
   1057    }
   1058    return PR_SUCCESS;
   1059 }
   1060 
   1061 NSS_IMPLEMENT NSSCRL *
   1062 nssCRL_Create(nssPKIObject *object)
   1063 {
   1064    PRStatus status;
   1065    NSSCRL *rvCRL;
   1066    NSSArena *arena = object->arena;
   1067    PR_ASSERT(object->instances != NULL && object->numInstances > 0);
   1068    rvCRL = nss_ZNEW(arena, NSSCRL);
   1069    if (!rvCRL) {
   1070        return (NSSCRL *)NULL;
   1071    }
   1072    rvCRL->object = *object;
   1073    /* XXX should choose instance based on some criteria */
   1074    status = nssCryptokiCRL_GetAttributes(object->instances[0],
   1075                                          NULL, /* XXX sessionOpt */
   1076                                          arena,
   1077                                          &rvCRL->encoding,
   1078                                          NULL, /* subject */
   1079                                          NULL, /* class */
   1080                                          &rvCRL->url,
   1081                                          &rvCRL->isKRL);
   1082    if (status != PR_SUCCESS) {
   1083        if (!arena) {
   1084            nssPKIObject_Destroy((nssPKIObject *)rvCRL);
   1085        }
   1086        return (NSSCRL *)NULL;
   1087    }
   1088    return rvCRL;
   1089 }
   1090 
   1091 NSS_IMPLEMENT NSSCRL *
   1092 nssCRL_AddRef(NSSCRL *crl)
   1093 {
   1094    if (crl) {
   1095        nssPKIObject_AddRef(&crl->object);
   1096    }
   1097    return crl;
   1098 }
   1099 
   1100 NSS_IMPLEMENT PRStatus
   1101 nssCRL_Destroy(NSSCRL *crl)
   1102 {
   1103    if (crl) {
   1104        (void)nssPKIObject_Destroy(&crl->object);
   1105    }
   1106    return PR_SUCCESS;
   1107 }
   1108 
   1109 NSS_IMPLEMENT PRStatus
   1110 nssCRL_DeleteStoredObject(
   1111    NSSCRL *crl,
   1112    NSSCallback *uhh)
   1113 {
   1114    return nssPKIObject_DeleteStoredObject(&crl->object, uhh, PR_TRUE);
   1115 }
   1116 
   1117 NSS_IMPLEMENT NSSDER *
   1118 nssCRL_GetEncoding(NSSCRL *crl)
   1119 {
   1120    if (crl && crl->encoding.data != NULL && crl->encoding.size > 0) {
   1121        return &crl->encoding;
   1122    } else {
   1123        return (NSSDER *)NULL;
   1124    }
   1125 }