Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  pki3hack.c   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


/*
 * Hacks to integrate NSS 3.4 and NSS 4.0 certificates.
 */


#ifndef NSSPKI_H
#include "nsspki.h"
#endif /* NSSPKI_H */

#ifndef PKI_H
#include "pki.h"
#endif /* PKI_H */

#ifndef PKIM_H
#include "pkim.h"
#endif /* PKIM_H */

#ifndef DEV_H
#include "dev.h"
#endif /* DEV_H */

#ifndef DEVNSS3HACK_H
#include "dev3hack.h"
#endif /* DEVNSS3HACK_H */

#ifndef PKINSS3HACK_H
#include "pki3hack.h"
#endif /* PKINSS3HACK_H */

#include "secitem.h"
#include "certdb.h"
#include "certt.h"
#include "cert.h"
#include "certi.h"
#include "pk11func.h"
#include "pkistore.h"
#include "secmod.h"
#include "nssrwlk.h"

NSSTrustDomain *g_default_trust_domain = NULL;

NSSCryptoContext *g_default_crypto_context = NULL;

NSSTrustDomain *
STAN_GetDefaultTrustDomain()
{
    return g_default_trust_domain;
}

NSSCryptoContext *
STAN_GetDefaultCryptoContext()
{
    return g_default_crypto_context;
}

extern const NSSError NSS_ERROR_ALREADY_INITIALIZED;
extern const NSSError NSS_ERROR_INTERNAL_ERROR;

NSS_IMPLEMENT PRStatus
STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot)
{
    NSSToken *token;
    if (!td) {
        td = g_default_trust_domain;
        if (!td) {
            /* we're called while still initting. slot will get added
             * appropriately through normal init processes */

            return PR_SUCCESS;
        }
    }
    token = nssToken_CreateFromPK11SlotInfo(td, slot);
    if (token) {
        /* PK11Slot_SetNSSToken increments the refcount on |token| to 2 */
        PK11Slot_SetNSSToken(slot, token);

        /* we give our reference to |td->tokenList| */
        NSSRWLock_LockWrite(td->tokensLock);
        nssList_Add(td->tokenList, token);
        NSSRWLock_UnlockWrite(td->tokensLock);
    } else {
        PK11Slot_SetNSSToken(slot, NULL);
    }
    return PR_SUCCESS;
}

NSS_IMPLEMENT PRStatus
STAN_ResetTokenInterator(NSSTrustDomain *td)
{
    if (!td) {
        td = g_default_trust_domain;
        if (!td) {
            /* we're called while still initting. slot will get added
             * appropriately through normal init processes */

            return PR_SUCCESS;
        }
    }
    NSSRWLock_LockWrite(td->tokensLock);
    nssListIterator_Destroy(td->tokens);
    td->tokens = nssList_CreateIterator(td->tokenList);
    NSSRWLock_UnlockWrite(td->tokensLock);
    return PR_SUCCESS;
}

NSS_IMPLEMENT PRStatus
STAN_LoadDefaultNSS3TrustDomain(
    void)
{
    NSSTrustDomain *td;
    SECMODModuleList *mlp;
    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
    int i;

    if (g_default_trust_domain || g_default_crypto_context) {
        /* Stan is already initialized or a previous shutdown failed. */
        nss_SetError(NSS_ERROR_ALREADY_INITIALIZED);
        return PR_FAILURE;
    }
    td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL);
    if (!td) {
        return PR_FAILURE;
    }
    /*
     * Deadlock warning: we should never acquire the moduleLock while
     * we hold the tokensLock. We can use the NSSRWLock Rank feature to
     * guarrentee this. tokensLock have a higher rank than module lock.
     */

    td->tokenList = nssList_Create(td->arena, PR_TRUE);
    if (!td->tokenList) {
        goto loser;
    }
    SECMOD_GetReadLock(moduleLock);
    NSSRWLock_LockWrite(td->tokensLock);
    for (mlp = SECMOD_GetDefaultModuleList(); mlp != NULL; mlp = mlp->next) {
        for (i = 0; i < mlp->module->slotCount; i++) {
            STAN_InitTokenForSlotInfo(td, mlp->module->slots[i]);
        }
    }
    td->tokens = nssList_CreateIterator(td->tokenList);
    NSSRWLock_UnlockWrite(td->tokensLock);
    SECMOD_ReleaseReadLock(moduleLock);
    if (!td->tokens) {
        goto loser;
    }
    g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL);
    if (!g_default_crypto_context) {
        goto loser;
    }
    g_default_trust_domain = td;
    return PR_SUCCESS;

loser:
    NSSTrustDomain_Destroy(td);
    return PR_FAILURE;
}

/*
 * must be called holding the ModuleListLock (either read or write).
 */

NSS_IMPLEMENT SECStatus
STAN_AddModuleToDefaultTrustDomain(
    SECMODModule *module)
{
    NSSTrustDomain *td;
    int i;
    td = STAN_GetDefaultTrustDomain();
    for (i = 0; i < module->slotCount; i++) {
        STAN_InitTokenForSlotInfo(td, module->slots[i]);
    }
    STAN_ResetTokenInterator(td);
    return SECSuccess;
}

/*
 * must be called holding the ModuleListLock (either read or write).
 */

NSS_IMPLEMENT SECStatus
STAN_RemoveModuleFromDefaultTrustDomain(
    SECMODModule *module)
{
    NSSToken *token;
    NSSTrustDomain *td;
    int i;
    td = STAN_GetDefaultTrustDomain();
    for (i = 0; i < module->slotCount; i++) {
        token = PK11Slot_GetNSSToken(module->slots[i]);
        if (token) {
            nssToken_NotifyCertsNotVisible(token);
            NSSRWLock_LockWrite(td->tokensLock);
            nssList_Remove(td->tokenList, token);
            NSSRWLock_UnlockWrite(td->tokensLock);
            PK11Slot_SetNSSToken(module->slots[i], NULL);
            (void)nssToken_Destroy(token); /* for the |td->tokenList| reference */
            (void)nssToken_Destroy(token); /* for our PK11Slot_GetNSSToken reference */
        }
    }
    NSSRWLock_LockWrite(td->tokensLock);
    nssListIterator_Destroy(td->tokens);
    td->tokens = nssList_CreateIterator(td->tokenList);
    NSSRWLock_UnlockWrite(td->tokensLock);
    return SECSuccess;
}

NSS_IMPLEMENT PRStatus
STAN_Shutdown()
{
    PRStatus status = PR_SUCCESS;
    if (g_default_trust_domain) {
        if (NSSTrustDomain_Destroy(g_default_trust_domain) == PR_SUCCESS) {
            g_default_trust_domain = NULL;
        } else {
            status = PR_FAILURE;
        }
    }
    if (g_default_crypto_context) {
        if (NSSCryptoContext_Destroy(g_default_crypto_context) == PR_SUCCESS) {
            g_default_crypto_context = NULL;
        } else {
            status = PR_FAILURE;
        }
    }
    return status;
}

/* this function should not be a hack; it will be needed in 4.0 (rename) */
NSS_IMPLEMENT NSSItem *
STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der)
{
    NSSItem *rvKey;
    SECItem secDER;
    SECItem secKey = { 0 };
    SECStatus secrv;
    PLArenaPool *arena;

    SECITEM_FROM_NSSITEM(&secDER, der);

    /* nss3 call uses nss3 arena's */
    arena = PORT_NewArena(256);
    if (!arena) {
        return NULL;
    }
    secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey);
    if (secrv != SECSuccess) {
        PORT_FreeArena(arena, PR_FALSE);
        return NULL;
    }
    rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data);
    PORT_FreeArena(arena, PR_FALSE);
    return rvKey;
}

NSS_IMPLEMENT PRStatus
nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der,
                                     NSSDER *issuer, NSSDER *serial)
{
    SECItem derCert = { 0 };
    SECItem derIssuer = { 0 };
    SECItem derSerial = { 0 };
    SECStatus secrv;
    derCert.data = (unsigned char *)der->data;
    derCert.len = der->size;
    secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
    if (secrv != SECSuccess) {
        return PR_FAILURE;
    }
    secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
    if (secrv != SECSuccess) {
        PORT_Free(derSerial.data);
        return PR_FAILURE;
    }
    issuer->data = derIssuer.data;
    issuer->size = derIssuer.len;
    serial->data = derSerial.data;
    serial->size = derSerial.len;
    return PR_SUCCESS;
}

static NSSItem *
nss3certificate_getIdentifier(nssDecodedCert *dc)
{
    NSSItem *rvID;
    CERTCertificate *c = (CERTCertificate *)dc->data;
    rvID = nssItem_Create(NULL, NULL, c->certKey.len, c->certKey.data);
    return rvID;
}

static void *
nss3certificate_getIssuerIdentifier(nssDecodedCert *dc)
{
    CERTCertificate *c = (CERTCertificate *)dc->data;
    return (void *)c->authKeyID;
}

static nssCertIDMatch
nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id)
{
    CERTCertificate *c = (CERTCertificate *)dc->data;
    CERTAuthKeyID *authKeyID = (CERTAuthKeyID *)id;
    SECItem skid;
    nssCertIDMatch match = nssCertIDMatch_Unknown;

    /* keyIdentifier */
    if (authKeyID->keyID.len > 0 &&
        CERT_FindSubjectKeyIDExtension(c, &skid) == SECSuccess) {
        PRBool skiEqual;
        skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid);
        PORT_Free(skid.data);
        if (skiEqual) {
            /* change the state to positive match, but keep going */
            match = nssCertIDMatch_Yes;
        } else {
            /* exit immediately on failure */
            return nssCertIDMatch_No;
        }
    }

    /* issuer/serial (treated as pair) */
    if (authKeyID->authCertIssuer) {
        SECItem *caName = NULL;
        SECItem *caSN = &authKeyID->authCertSerialNumber;

        caName = (SECItem *)CERT_GetGeneralNameByType(
            authKeyID->authCertIssuer,
            certDirectoryName, PR_TRUE);
        if (caName != NULL &&
            SECITEM_ItemsAreEqual(&c->derIssuer, caName) &&
            SECITEM_ItemsAreEqual(&c->serialNumber, caSN)) {
            match = nssCertIDMatch_Yes;
        } else {
            match = nssCertIDMatch_Unknown;
        }
    }
    return match;
}

static PRBool
nss3certificate_isValidIssuer(nssDecodedCert *dc)
{
    CERTCertificate *c = (CERTCertificate *)dc->data;
    unsigned int ignore;
    return CERT_IsCACert(c, &ignore);
}

static NSSUsage *
nss3certificate_getUsage(nssDecodedCert *dc)
{
    /* CERTCertificate *c = (CERTCertificate *)dc->data; */
    return NULL;
}

static PRBool
nss3certificate_isValidAtTime(nssDecodedCert *dc, NSSTime *time)
{
    SECCertTimeValidity validity;
    CERTCertificate *c = (CERTCertificate *)dc->data;
    validity = CERT_CheckCertValidTimes(c, NSSTime_GetPRTime(time), PR_TRUE);
    if (validity == secCertTimeValid) {
        return PR_TRUE;
    }
    return PR_FALSE;
}

static PRBool
nss3certificate_isNewerThan(nssDecodedCert *dc, nssDecodedCert *cmpdc)
{
    /* I know this isn't right, but this is glue code anyway */
    if (cmpdc->type == dc->type) {
        CERTCertificate *certa = (CERTCertificate *)dc->data;
        CERTCertificate *certb = (CERTCertificate *)cmpdc->data;
        return CERT_IsNewer(certa, certb);
    }
    return PR_FALSE;
}

/* CERT_FilterCertListByUsage */
static PRBool
nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage)
{
    CERTCertificate *cc;
    unsigned int requiredKeyUsage = 0;
    unsigned int requiredCertType = 0;
    SECStatus secrv;
    PRBool match;
    PRBool ca;

    /* This is for NSS 3.3 functions that do not specify a usage */
    if (usage->anyUsage) {
        return PR_TRUE;
    }
    ca = usage->nss3lookingForCA;
    secrv = CERT_KeyUsageAndTypeForCertUsage(usage->nss3usage, ca,
                                             &requiredKeyUsage,
                                             &requiredCertType);
    if (secrv != SECSuccess) {
        return PR_FALSE;
    }
    cc = (CERTCertificate *)dc->data;
    secrv = CERT_CheckKeyUsage(cc, requiredKeyUsage);
    match = (PRBool)(secrv == SECSuccess);
    if (match) {
        unsigned int certType = 0;
        if (ca) {
            (void)CERT_IsCACert(cc, &certType);
        } else {
            certType = cc->nsCertType;
        }
        if (!(certType & requiredCertType)) {
            match = PR_FALSE;
        }
    }
    return match;
}

static PRBool
nss3certificate_isTrustedForUsage(nssDecodedCert *dc, const NSSUsage *usage)
{
    CERTCertificate *cc;
    PRBool ca;
    SECStatus secrv;
    unsigned int requiredFlags;
    unsigned int trustFlags;
    SECTrustType trustType;
    CERTCertTrust trust;

    /* This is for NSS 3.3 functions that do not specify a usage */
    if (usage->anyUsage) {
        return PR_FALSE; /* XXX is this right? */
    }
    cc = (CERTCertificate *)dc->data;
    ca = usage->nss3lookingForCA;
    if (!ca) {
        PRBool trusted;
        unsigned int failedFlags;
        secrv = cert_CheckLeafTrust(cc, usage->nss3usage,
                                    &failedFlags, &trusted);
        return secrv == SECSuccess && trusted;
    }
    secrv = CERT_TrustFlagsForCACertUsage(usage->nss3usage, &requiredFlags,
                                          &trustType);
    if (secrv != SECSuccess) {
        return PR_FALSE;
    }
    secrv = CERT_GetCertTrust(cc, &trust);
    if (secrv != SECSuccess) {
        return PR_FALSE;
    }
    if (trustType == trustTypeNone) {
        /* normally trustTypeNone usages accept any of the given trust bits
         * being on as acceptable. */

        trustFlags = trust.sslFlags | trust.emailFlags |
                     trust.objectSigningFlags;
    } else {
        trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType);
    }
    return (trustFlags & requiredFlags) == requiredFlags;
}

static NSSASCII7 *
nss3certificate_getEmailAddress(nssDecodedCert *dc)
{
    CERTCertificate *cc = (CERTCertificate *)dc->data;
    return (cc && cc->emailAddr && cc->emailAddr[0])
               ? (NSSASCII7 *)cc->emailAddr
               : NULL;
}

static PRStatus
nss3certificate_getDERSerialNumber(nssDecodedCert *dc,
                                   NSSDER *serial, NSSArena *arena)
{
    CERTCertificate *cc = (CERTCertificate *)dc->data;
    SECItem derSerial = { 0 };
    SECStatus secrv;
    secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
    if (secrv == SECSuccess) {
        (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data);
        PORT_Free(derSerial.data);
        return PR_SUCCESS;
    }
    return PR_FAILURE;
}

/* Returns NULL if "encoding" cannot be decoded. */
NSS_IMPLEMENT nssDecodedCert *
nssDecodedPKIXCertificate_Create(
    NSSArena *arenaOpt,
    NSSDER *encoding)
{
    nssDecodedCert *rvDC = NULL;
    CERTCertificate *cert;
    SECItem secDER;

    SECITEM_FROM_NSSITEM(&secDER, encoding);
    cert = CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL);
    if (cert) {
        rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
        if (rvDC) {
            rvDC->type = NSSCertificateType_PKIX;
            rvDC->data = (void *)cert;
            rvDC->getIdentifier = nss3certificate_getIdentifier;
            rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
            rvDC->matchIdentifier = nss3certificate_matchIdentifier;
            rvDC->isValidIssuer = nss3certificate_isValidIssuer;
            rvDC->getUsage = nss3certificate_getUsage;
            rvDC->isValidAtTime = nss3certificate_isValidAtTime;
            rvDC->isNewerThan = nss3certificate_isNewerThan;
            rvDC->matchUsage = nss3certificate_matchUsage;
            rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage;
            rvDC->getEmailAddress = nss3certificate_getEmailAddress;
            rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber;
        } else {
            CERT_DestroyCertificate(cert);
        }
    }
    return rvDC;
}

static nssDecodedCert *
create_decoded_pkix_cert_from_nss3cert(
    NSSArena *arenaOpt,
    CERTCertificate *cc)
{
    nssDecodedCert *rvDC = nss_ZNEW(arenaOpt, nssDecodedCert);
    if (rvDC) {
        rvDC->type = NSSCertificateType_PKIX;
        rvDC->data = (void *)cc;
        rvDC->getIdentifier = nss3certificate_getIdentifier;
        rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier;
        rvDC->matchIdentifier = nss3certificate_matchIdentifier;
        rvDC->isValidIssuer = nss3certificate_isValidIssuer;
        rvDC->getUsage = nss3certificate_getUsage;
        rvDC->isValidAtTime = nss3certificate_isValidAtTime;
        rvDC->isNewerThan = nss3certificate_isNewerThan;
        rvDC->matchUsage = nss3certificate_matchUsage;
        rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage;
        rvDC->getEmailAddress = nss3certificate_getEmailAddress;
        rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber;
    }
    return rvDC;
}

NSS_IMPLEMENT PRStatus
nssDecodedPKIXCertificate_Destroy(nssDecodedCert *dc)
{
    CERTCertificate *cert = (CERTCertificate *)dc->data;

    /* The decoder may only be half initialized (the case where we find we
     * could not decode the certificate). In this case, there is not cert to
     * free, just free the dc structure. */

    if (cert) {
        PRBool freeSlot = cert->ownSlot;
        PK11SlotInfo *slot = cert->slot;
        PLArenaPool *arena = cert->arena;
        /* zero cert before freeing. Any stale references to this cert
         * after this point will probably cause an exception.  */

        PORT_Memset(cert, 0, sizeof *cert);
        /* free the arena that contains the cert. */
        PORT_FreeArena(arena, PR_FALSE);
        if (slot && freeSlot) {
            PK11_FreeSlot(slot);
        }
    }
    nss_ZFreeIf(dc);
    return PR_SUCCESS;
}

/* see pk11cert.c:pk11_HandleTrustObject */
static unsigned int
get_nss3trust_from_nss4trust(nssTrustLevel t)
{
    unsigned int rt = 0;
    if (t == nssTrustLevel_Trusted) {
        rt |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED;
    }
    if (t == nssTrustLevel_TrustedDelegator) {
        rt |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA;
    }
    if (t == nssTrustLevel_NotTrusted) {
        rt |= CERTDB_TERMINAL_RECORD;
    }
    if (t == nssTrustLevel_ValidDelegator) {
        rt |= CERTDB_VALID_CA;
    }
    return rt;
}

static CERTCertTrust *
cert_trust_from_stan_trust(NSSTrust *t, PLArenaPool *arena)
{
    CERTCertTrust *rvTrust;
    unsigned int client;
    if (!t) {
        return NULL;
    }
    rvTrust = PORT_ArenaAlloc(arena, sizeof(CERTCertTrust));
    if (!rvTrust)
        return NULL;
    rvTrust->sslFlags = get_nss3trust_from_nss4trust(t->serverAuth);
    client = get_nss3trust_from_nss4trust(t->clientAuth);
    if (client & (CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA)) {
        client &= ~(CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA);
        rvTrust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA;
    }
    rvTrust->sslFlags |= client;
    rvTrust->emailFlags = get_nss3trust_from_nss4trust(t->emailProtection);
    rvTrust->objectSigningFlags = get_nss3trust_from_nss4trust(t->codeSigning);
    return rvTrust;
}

CERTCertTrust *
nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc)
{
    CERTCertTrust *rvTrust = NULL;
    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
    NSSTrust *t;
    t = nssTrustDomain_FindTrustForCertificate(td, c);
    if (t) {
        rvTrust = cert_trust_from_stan_trust(t, cc->arena);
        if (!rvTrust) {
            nssTrust_Destroy(t);
            return NULL;
        }
        nssTrust_Destroy(t);
    } else {
        rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
        if (!rvTrust) {
            return NULL;
        }
        memset(rvTrust, 0, sizeof(*rvTrust));
    }
    if (NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
        rvTrust->sslFlags |= CERTDB_USER;
        rvTrust->emailFlags |= CERTDB_USER;
        rvTrust->objectSigningFlags |= CERTDB_USER;
    }
    return rvTrust;
}

static nssCryptokiInstance *
get_cert_instance(NSSCertificate *c)
{
    nssCryptokiObject *instance, **ci;
    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
    if (!instances) {
        return NULL;
    }
    instance = NULL;
    for (ci = instances; *ci; ci++) {
        if (!instance) {
            instance = nssCryptokiObject_Clone(*ci);
        } else {
            /* This only really works for two instances...  But 3.4 can't
             * handle more anyway.  The logic is, if there are multiple
             * instances, prefer the one that is not internal (e.g., on
             * a hardware device.
             */

            if (PK11_IsInternal(instance->token->pk11slot)) {
                nssCryptokiObject_Destroy(instance);
                instance = nssCryptokiObject_Clone(*ci);
            }
        }
    }
    nssCryptokiObjectArray_Destroy(instances);
    return instance;
}

char *
STAN_GetCERTCertificateNameForInstance(
    PLArenaPool *arenaOpt,
    NSSCertificate *c,
    nssCryptokiInstance *instance)
{
    NSSCryptoContext *context = c->object.cryptoContext;
    PRStatus nssrv;
    int nicklen, tokenlen, len;
    NSSUTF8 *tokenName = NULL;
    NSSUTF8 *stanNick = NULL;
    char *nickname = NULL;
    char *nick;

    if (instance) {
        stanNick = instance->label;
    } else if (context) {
        stanNick = c->object.tempName;
    }
    if (stanNick) {
        /* fill other fields needed by NSS3 functions using CERTCertificate */
        if (instance && (!PK11_IsInternalKeySlot(instance->token->pk11slot) ||
                         PORT_Strchr(stanNick, ':') != NULL)) {
            tokenName = nssToken_GetName(instance->token);
            tokenlen = nssUTF8_Size(tokenName, &nssrv);
        } else {
            /* don't use token name for internal slot; 3.3 didn't */
            tokenlen = 0;
        }
        nicklen = nssUTF8_Size(stanNick, &nssrv);
        len = tokenlen + nicklen;
        if (arenaOpt) {
            nickname = PORT_ArenaAlloc(arenaOpt, len);
        } else {
            nickname = PORT_Alloc(len);
        }
        nick = nickname;
        if (tokenName) {
            memcpy(nick, tokenName, tokenlen - 1);
            nick += tokenlen - 1;
            *nick++ = ':';
        }
        memcpy(nick, stanNick, nicklen - 1);
        nickname[len - 1] = '\0';
    }
    return nickname;
}

char *
STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c)
{
    char *result;
    nssCryptokiInstance *instance = get_cert_instance(c);
    /* It's OK to call this function, even if instance is NULL */
    result = STAN_GetCERTCertificateNameForInstance(arenaOpt, c, instance);
    if (instance)
        nssCryptokiObject_Destroy(instance);
    return result;
}

static void
fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced)
{
    CERTCertTrust *trust = NULL;
    NSSTrust *nssTrust;
    NSSCryptoContext *context = c->object.cryptoContext;
    nssCryptokiInstance *instance;
    NSSUTF8 *stanNick = NULL;

    /* We are holding the base class object's lock on entry of this function
     * This lock protects writes to fields of the CERTCertificate .
     * It is also needed by some functions to compute values such as trust.
     */

    instance = get_cert_instance(c);

    if (instance) {
        stanNick = instance->label;
    } else if (context) {
        stanNick = c->object.tempName;
    }
    /* fill other fields needed by NSS3 functions using CERTCertificate */
    if ((!cc->nickname && stanNick) || forced) {
        PRStatus nssrv;
        int nicklen, tokenlen, len;
        NSSUTF8 *tokenName = NULL;
        char *nick;
        if (instance &&
            (!PK11_IsInternalKeySlot(instance->token->pk11slot) ||
             (stanNick && PORT_Strchr(stanNick, ':') != NULL))) {
            tokenName = nssToken_GetName(instance->token);
            tokenlen = nssUTF8_Size(tokenName, &nssrv);
        } else {
            /* don't use token name for internal slot; 3.3 didn't */
            tokenlen = 0;
        }
        if (stanNick) {
            nicklen = nssUTF8_Size(stanNick, &nssrv);
            len = tokenlen + nicklen;
            nick = PORT_ArenaAlloc(cc->arena, len);
            if (tokenName) {
                memcpy(nick, tokenName, tokenlen - 1);
                nick[tokenlen - 1] = ':';
                memcpy(nick + tokenlen, stanNick, nicklen - 1);
            } else {
                memcpy(nick, stanNick, nicklen - 1);
            }
            nick[len - 1] = '\0';
            cc->nickname = nick;
        } else {
            cc->nickname = NULL;
        }
    }
    if (context) {
        /* trust */
        nssTrust = nssCryptoContext_FindTrustForCertificate(context, c);
        if (!nssTrust) {
            /* chicken and egg issue:
             *
             * c->issuer and c->serial are empty at this point, but
             * nssTrustDomain_FindTrustForCertificate use them to look up
             * up the trust object, so we point them to cc->derIssuer and
             * cc->serialNumber.
             *
             * Our caller will fill these in with proper arena copies when we
             * return. */

            c->issuer.data = cc->derIssuer.data;
            c->issuer.size = cc->derIssuer.len;
            c->serial.data = cc->serialNumber.data;
            c->serial.size = cc->serialNumber.len;
            nssTrust = nssTrustDomain_FindTrustForCertificate(context->td, c);
        }
        if (nssTrust) {
            trust = cert_trust_from_stan_trust(nssTrust, cc->arena);
            if (trust) {
                /* we should destroy cc->trust before replacing it, but it's
                   allocated in cc->arena, so memory growth will occur on each
                   refresh */

                CERT_LockCertTrust(cc);
                cc->trust = trust;
                CERT_UnlockCertTrust(cc);
            }
            nssTrust_Destroy(nssTrust);
        }
    } else if (instance) {
        /* slot */
        if (cc->slot != instance->token->pk11slot) {
            if (cc->slot) {
                PK11_FreeSlot(cc->slot);
            }
            cc->slot = PK11_ReferenceSlot(instance->token->pk11slot);
        }
        cc->ownSlot = PR_TRUE;
        /* pkcs11ID */
        cc->pkcs11ID = instance->handle;
        /* trust */
        trust = nssTrust_GetCERTCertTrustForCert(c, cc);
        if (trust) {
            /* we should destroy cc->trust before replacing it, but it's
               allocated in cc->arena, so memory growth will occur on each
               refresh */

            CERT_LockCertTrust(cc);
            cc->trust = trust;
            CERT_UnlockCertTrust(cc);
        }
        /* Read the distrust fields from a nssckbi/builtins certificate and
         * fill the fields in CERTCertificate structure when any valid date
         * is found. */

        if (PK11_IsReadOnly(cc->slot) && PK11_HasRootCerts(cc->slot)) {
            /* The values are hard-coded and readonly. Read just once. */
            if (cc->distrust == NULL) {
                CERTCertDistrust distrustModel;
                SECItem model = { siUTCTime, NULL, 0 };
                distrustModel.serverDistrustAfter = model;
                distrustModel.emailDistrustAfter = model;
                SECStatus rServer = PK11_ReadAttribute(
                    cc->slot, cc->pkcs11ID, CKA_NSS_SERVER_DISTRUST_AFTER,
                    cc->arena, &distrustModel.serverDistrustAfter);
                SECStatus rEmail = PK11_ReadAttribute(
                    cc->slot, cc->pkcs11ID, CKA_NSS_EMAIL_DISTRUST_AFTER,
                    cc->arena, &distrustModel.emailDistrustAfter);
                /* Only allocate the Distrust structure if a valid date is found.
                 * The result length of a encoded valid timestamp is exactly 13 */

                const unsigned int kDistrustFieldSize = 13;
                if ((rServer == SECSuccess && rEmail == SECSuccess) &&
                    (distrustModel.serverDistrustAfter.len == kDistrustFieldSize ||
                     distrustModel.emailDistrustAfter.len == kDistrustFieldSize)) {
                    CERTCertDistrust *tmpPtr = PORT_ArenaAlloc(
                        cc->arena, sizeof(CERTCertDistrust));
                    PORT_Memcpy(tmpPtr, &distrustModel,
                                sizeof(CERTCertDistrust));
                    cc->distrust = tmpPtr;
                }
            }
        }
    }
    if (instance) {
        nssCryptokiObject_Destroy(instance);
    }
    /* database handle is now the trust domain */
    cc->dbhandle = c->object.trustDomain;
    /* subjectList ? */
    /* istemp and isperm are supported in NSS 3.4 */
    CERT_LockCertTempPerm(cc);
    cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */
    cc->isperm = PR_TRUE;  /* by default */
    /* pointer back */
    cc->nssCertificate = c;
    CERT_UnlockCertTempPerm(cc);
    if (trust) {
        /* force the cert type to be recomputed to include trust info */
        PRUint32 nsCertType = cert_ComputeCertType(cc);

        /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */
        PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32));
        PR_ATOMIC_SET((PRInt32 *)&cc->nsCertType, nsCertType);
    }
}

static CERTCertificate *
stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate)
{
    nssDecodedCert *dc = NULL;
    CERTCertificate *cc = NULL;
    CERTCertTrust certTrust;

    /* make sure object does not go away until we finish */
    nssPKIObject_AddRef(&c->object);
    nssPKIObject_Lock(&c->object);

    dc = c->decoding;
    if (!dc) {
        dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding);
        if (!dc) {
            goto loser;
        }
        cc = (CERTCertificate *)dc->data;
        PORT_Assert(cc); /* software error */
        if (!cc) {
            nssDecodedPKIXCertificate_Destroy(dc);
            nss_SetError(NSS_ERROR_INTERNAL_ERROR);
            goto loser;
        }
        PORT_Assert(!c->decoding);
        if (!c->decoding) {
            c->decoding = dc;
        } else {
            /* this should never happen. Fail. */
            nssDecodedPKIXCertificate_Destroy(dc);
            nss_SetError(NSS_ERROR_INTERNAL_ERROR);
            goto loser;
        }
    }
    cc = (CERTCertificate *)dc->data;
    PORT_Assert(cc);
    if (!cc) {
        nss_SetError(NSS_ERROR_INTERNAL_ERROR);
        goto loser;
    }
    CERT_LockCertTempPerm(cc);
    NSSCertificate *nssCert = cc->nssCertificate;
    CERT_UnlockCertTempPerm(cc);
    if (!nssCert || forceUpdate) {
        fill_CERTCertificateFields(c, cc, forceUpdate);
    } else if (CERT_GetCertTrust(cc, &certTrust) != SECSuccess) {
        CERTCertTrust *trust;
        if (!c->object.cryptoContext) {
            /* If it's a perm cert, it might have been stored before the
             * trust, so look for the trust again.
             */

            trust = nssTrust_GetCERTCertTrustForCert(c, cc);
        } else {
            /* If it's a temp cert, it might have been stored before the
             * builtin trust module is loaded, so look for the trust
             * again, but don't set the empty trust if it is not found.
             */

            NSSTrust *t = nssTrustDomain_FindTrustForCertificate(c->object.cryptoContext->td, c);
            if (!t) {
                goto loser;
            }
            trust = cert_trust_from_stan_trust(t, cc->arena);
            nssTrust_Destroy(t);
            if (!trust) {
                goto loser;
            }
        }

        CERT_LockCertTrust(cc);
        cc->trust = trust;
        CERT_UnlockCertTrust(cc);
    }

loser:
    nssPKIObject_Unlock(&c->object);
    nssPKIObject_Destroy(&c->object);
    return cc;
}

NSS_IMPLEMENT CERTCertificate *
STAN_ForceCERTCertificateUpdate(NSSCertificate *c)
{
    if (c->decoding) {
        return stan_GetCERTCertificate(c, PR_TRUE);
    }
    return NULL;
}

NSS_IMPLEMENT CERTCertificate *
STAN_GetCERTCertificate(NSSCertificate *c)
{
    return stan_GetCERTCertificate(c, PR_FALSE);
}
/*
 * many callers of STAN_GetCERTCertificate() intend that
 * the CERTCertificate returned inherits the reference to the
 * NSSCertificate. For these callers it's convenient to have
 * this function 'own' the reference and either return a valid
 * CERTCertificate structure which inherits the reference or
 * destroy the reference to NSSCertificate and returns NULL.
 */

NSS_IMPLEMENT CERTCertificate *
STAN_GetCERTCertificateOrRelease(NSSCertificate *c)
{
    CERTCertificate *nss3cert = stan_GetCERTCertificate(c, PR_FALSE);
    if (!nss3cert) {
        nssCertificate_Destroy(c);
    }
    return nss3cert;
}

static nssTrustLevel
get_stan_trust(unsigned int t, PRBool isClientAuth)
{
    if (isClientAuth) {
        if (t & CERTDB_TRUSTED_CLIENT_CA) {
            return nssTrustLevel_TrustedDelegator;
        }
    } else {
        if (t & CERTDB_TRUSTED_CA || t & CERTDB_NS_TRUSTED_CA) {
            return nssTrustLevel_TrustedDelegator;
        }
    }
    if (t & CERTDB_TRUSTED) {
        return nssTrustLevel_Trusted;
    }
    if (t & CERTDB_TERMINAL_RECORD) {
        return nssTrustLevel_NotTrusted;
    }
    if (t & CERTDB_VALID_CA) {
        return nssTrustLevel_ValidDelegator;
    }
    return nssTrustLevel_MustVerify;
}

NSS_EXTERN NSSCertificate *
STAN_GetNSSCertificate(CERTCertificate *cc)
{
    NSSCertificate *c;
    nssCryptokiInstance *instance;
    nssPKIObject *pkiob;
    NSSArena *arena;
    CERT_LockCertTempPerm(cc);
    c = cc->nssCertificate;
    CERT_UnlockCertTempPerm(cc);
    if (c) {
        return c;
    }
    /* i don't think this should happen.  but if it can, need to create
     * NSSCertificate from CERTCertificate values here.  */

    /* Yup, it can happen. */
    arena = NSSArena_Create();
    if (!arena) {
        return NULL;
    }
    c = nss_ZNEW(arena, NSSCertificate);
    if (!c) {
        nssArena_Destroy(arena);
        return NULL;
    }
    NSSITEM_FROM_SECITEM(&c->encoding, &cc->derCert);
    c->type = NSSCertificateType_PKIX;
    pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKIMonitor);
    if (!pkiob) {
        nssArena_Destroy(arena);
        return NULL;
    }
    c->object = *pkiob;
    nssItem_Create(arena,
                   &c->issuer, cc->derIssuer.len, cc->derIssuer.data);
    nssItem_Create(arena,
                   &c->subject, cc->derSubject.len, cc->derSubject.data);
    /* CERTCertificate stores serial numbers decoded.  I need the DER
     * here.  sigh.
     */

    SECItem derSerial;
    SECStatus secrv;
    secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
    if (secrv == SECFailure) {
        nssArena_Destroy(arena);
        return NULL;
    }
    nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data);
    PORT_Free(derSerial.data);

    if (cc->emailAddr && cc->emailAddr[0]) {
        c->email = nssUTF8_Create(arena,
                                  nssStringType_PrintableString,
                                  (NSSUTF8 *)cc->emailAddr,
                                  PORT_Strlen(cc->emailAddr));
    }
    if (cc->slot) {
        instance = nss_ZNEW(arena, nssCryptokiInstance);
        if (!instance) {
            nssArena_Destroy(arena);
            return NULL;
        }
        instance->token = PK11Slot_GetNSSToken(cc->slot);
        if (!instance->token) {
            nssArena_Destroy(arena);
            return NULL;
        }
        instance->handle = cc->pkcs11ID;
        instance->isTokenObject = PR_TRUE;
        if (cc->nickname) {
            instance->label = nssUTF8_Create(arena,
                                             nssStringType_UTF8String,
                                             (NSSUTF8 *)cc->nickname,
                                             PORT_Strlen(cc->nickname));
        }
        nssPKIObject_AddInstance(&c->object, instance);
    }
    c->decoding = create_decoded_pkix_cert_from_nss3cert(NULL, cc);
    CERT_LockCertTempPerm(cc);
    cc->nssCertificate = c;
    CERT_UnlockCertTempPerm(cc);
    return c;
}

static NSSToken *
stan_GetTrustToken(
    NSSCertificate *c)
{
    NSSToken *ttok = NULL;
    NSSToken *rtok = NULL;
    NSSToken *tok = NULL;
    nssCryptokiObject **ip;
    nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
    if (!instances) {
        return PR_FALSE;
    }
    for (ip = instances; *ip; ip++) {
        nssCryptokiObject *instance = *ip;
        nssCryptokiObject *to =
            nssToken_FindTrustForCertificate(instance->token, NULL,
                                             &c->encoding, &c->issuer, &c->serial,
                                             nssTokenSearchType_TokenOnly);
        NSSToken *ctok = instance->token;
        PRBool ro = PK11_IsReadOnly(ctok->pk11slot);

        if (to) {
            nssCryptokiObject_Destroy(to);
            ttok = ctok;
            if (!ro) {
                break;
            }
        } else {
            if (!rtok && ro) {
                rtok = ctok;
            }
            if (!tok && !ro) {
                tok = ctok;
            }
        }
    }
    nssCryptokiObjectArray_Destroy(instances);
    return ttok ? ttok : (tok ? tok : rtok);
}

NSS_EXTERN PRStatus
STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust)
{
    PRStatus nssrv;
    NSSCertificate *c = STAN_GetNSSCertificate(cc);
    NSSToken *tok;
    NSSTrustDomain *td;
    NSSTrust *nssTrust;
    NSSArena *arena;
    CERTCertTrust *oldTrust;
    CERTCertTrust *newTrust;
    nssListIterator *tokens;
    PRBool moving_object;
    nssCryptokiObject *newInstance;
    nssPKIObject *pkiob;

    if (c == NULL) {
        return PR_FAILURE;
    }
    oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc);
    if (oldTrust) {
        if (memcmp(oldTrust, trust, sizeof(CERTCertTrust)) == 0) {
            /* ... and the new trust is no different, done) */
            return PR_SUCCESS;
        } else {
            /* take over memory already allocated in cc's arena */
            newTrust = oldTrust;
        }
    } else {
        newTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust));
    }
    memcpy(newTrust, trust, sizeof(CERTCertTrust));
    CERT_LockCertTrust(cc);
    cc->trust = newTrust;
    CERT_UnlockCertTrust(cc);
    /* Set the NSSCerticate's trust */
    arena = nssArena_Create();
    if (!arena)
        return PR_FAILURE;
    nssTrust = nss_ZNEW(arena, NSSTrust);
    if (!nssTrust) {
        nssArena_Destroy(arena);
        return PR_FAILURE;
    }
    pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock);
    if (!pkiob) {
        nssArena_Destroy(arena);
        return PR_FAILURE;
    }
    nssTrust->object = *pkiob;
    nssTrust->certificate = c;
    nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE);
    nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE);
    nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE);
    nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE);
    nssTrust->stepUpApproved =
        (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA);
    if (c->object.cryptoContext != NULL) {
        /* The cert is in a context, set the trust there */
        NSSCryptoContext *cctx = c->object.cryptoContext;
        nssrv = nssCryptoContext_ImportTrust(cctx, nssTrust);
        if (nssrv != PR_SUCCESS) {
            goto done;
        }
        if (c->object.numInstances == 0) {
            /* The context is the only instance, finished */
            goto done;
        }
    }
    td = STAN_GetDefaultTrustDomain();
    tok = stan_GetTrustToken(c);
    moving_object = PR_FALSE;
    if (tok && PK11_IsReadOnly(tok->pk11slot)) {
        NSSRWLock_LockRead(td->tokensLock);
        tokens = nssList_CreateIterator(td->tokenList);
        if (!tokens) {
            nssrv = PR_FAILURE;
            NSSRWLock_UnlockRead(td->tokensLock);
            goto done;
        }
        for (tok = (NSSToken *)nssListIterator_Start(tokens);
             tok != (NSSToken *)NULL;
             tok = (NSSToken *)nssListIterator_Next(tokens)) {
            if (!PK11_IsReadOnly(tok->pk11slot))
                break;
        }
        nssListIterator_Finish(tokens);
        nssListIterator_Destroy(tokens);
        NSSRWLock_UnlockRead(td->tokensLock);
        moving_object = PR_TRUE;
    }
    if (tok) {
        if (moving_object) {
            /* this is kind of hacky.  the softoken needs the cert
             * object in order to store trust.  forcing it to be perm
             */

            NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
            NSSASCII7 *email = NULL;

            if (PK11_IsInternal(tok->pk11slot)) {
                email = c->email;
            }
            newInstance = nssToken_ImportCertificate(tok, NULL,
                                                     NSSCertificateType_PKIX,
                                                     &c->id,
                                                     nickname,
                                                     &c->encoding,
                                                     &c->issuer,
                                                     &c->subject,
                                                     &c->serial,
                                                     email,
                                                     PR_TRUE);
            nss_ZFreeIf(nickname);
            nickname = NULL;
            if (!newInstance) {
                nssrv = PR_FAILURE;
                goto done;
            }
            nssPKIObject_AddInstance(&c->object, newInstance);
        }
        newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
                                           &c->issuer, &c->serial,
                                           nssTrust->serverAuth,
                                           nssTrust->clientAuth,
                                           nssTrust->codeSigning,
                                           nssTrust->emailProtection,
                                           nssTrust->stepUpApproved, PR_TRUE);
        /* If the selected token can't handle trust, dump the trust on
         * the internal token */

        if (!newInstance && !PK11_IsInternalKeySlot(tok->pk11slot)) {
            PK11SlotInfo *slot = PK11_GetInternalKeySlot();
            NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL);
            NSSASCII7 *email = c->email;
            tok = PK11Slot_GetNSSToken(slot);
            PK11_FreeSlot(slot);
            if (!tok) {
                nssrv = PR_FAILURE;
                goto done;
            }

            newInstance = nssToken_ImportCertificate(tok, NULL,
                                                     NSSCertificateType_PKIX,
                                                     &c->id,
                                                     nickname,
                                                     &c->encoding,
                                                     &c->issuer,
                                                     &c->subject,
                                                     &c->serial,
                                                     email,
                                                     PR_TRUE);
            nss_ZFreeIf(nickname);
            nickname = NULL;
            if (!newInstance) {
                (void)nssToken_Destroy(tok);
                nssrv = PR_FAILURE;
                goto done;
            }
            nssPKIObject_AddInstance(&c->object, newInstance);
            newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding,
                                               &c->issuer, &c->serial,
                                               nssTrust->serverAuth,
                                               nssTrust->clientAuth,
                                               nssTrust->codeSigning,
                                               nssTrust->emailProtection,
                                               nssTrust->stepUpApproved, PR_TRUE);
            (void)nssToken_Destroy(tok);
        }
        if (newInstance) {
            nssCryptokiObject_Destroy(newInstance);
            nssrv = PR_SUCCESS;
        } else {
            nssrv = PR_FAILURE;
        }
    } else {
        nssrv = PR_FAILURE;
    }
done:
    (void)nssTrust_Destroy(nssTrust);
    return nssrv;
}

/*
** Delete trust objects matching the given slot.
** Returns error if a device fails to delete.
**
** This function has the side effect of moving the
** surviving entries to the front of the object list
** and nullifying the rest.
*/

static PRStatus
DeleteCertTrustMatchingSlot(PK11SlotInfo *pk11slot, nssPKIObject *tObject)
{
    int numNotDestroyed = 0; /* the ones skipped plus the failures */
    int failureCount = 0;    /* actual deletion failures by devices */
    unsigned int index;

    nssPKIObject_AddRef(tObject);
    nssPKIObject_Lock(tObject);
    /* Keep going even if a module fails to delete. */
    for (index = 0; index < tObject->numInstances; index++) {
        nssCryptokiObject *instance = tObject->instances[index];
        if (!instance) {
            continue;
        }

        /* ReadOnly and not matched treated the same */
        if (PK11_IsReadOnly(instance->token->pk11slot) ||
            pk11slot != instance->token->pk11slot) {
            tObject->instances[numNotDestroyed++] = instance;
            continue;
        }

        /* Here we have found a matching one */
        tObject->instances[index] = NULL;
        if (nssToken_DeleteStoredObject(instance) == PR_SUCCESS) {
            nssCryptokiObject_Destroy(instance);
        } else {
            tObject->instances[numNotDestroyed++] = instance;
            failureCount++;
        }
    }
    if (numNotDestroyed == 0) {
        nss_ZFreeIf(tObject->instances);
        tObject->numInstances = 0;
    } else {
        tObject->numInstances = numNotDestroyed;
    }

    nssPKIObject_Unlock(tObject);
    nssPKIObject_Destroy(tObject);

    return failureCount == 0 ? PR_SUCCESS : PR_FAILURE;
}

/*
** Delete trust objects matching the slot of the given certificate.
** Returns an error if any device fails to delete.
*/

NSS_EXTERN PRStatus
STAN_DeleteCertTrustMatchingSlot(NSSCertificate *c)
{
    PRStatus nssrv = PR_SUCCESS;

    unsigned int i;
    nssPKIObject *tobject = NULL;
    nssPKIObject *cobject = &c->object;

    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
    NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c);
    if (!nssTrust) {
        return PR_FAILURE;
    }

    tobject = &nssTrust->object;

    /* Iterate through the cert and trust object instances looking for
     * those with matching pk11 slots to delete. Even if some device
     * can't delete we keep going. Keeping a status variable for the
     * loop so that once it's failed the other gets set.
     */

    NSSRWLock_LockRead(td->tokensLock);
    nssPKIObject_AddRef(cobject);
    nssPKIObject_Lock(cobject);
    for (i = 0; i < cobject->numInstances; i++) {
        nssCryptokiObject *cInstance = cobject->instances[i];
        if (cInstance && !PK11_IsReadOnly(cInstance->token->pk11slot)) {
            PRStatus status;
            if (!tobject->numInstances || !tobject->instances)
                continue;
            status = DeleteCertTrustMatchingSlot(cInstance->token->pk11slot, tobject);
            if (status == PR_FAILURE) {
                /* set the outer one but keep going */
                nssrv = PR_FAILURE;
            }
        }
    }
    nssTrust_Destroy(nssTrust);
    nssPKIObject_Unlock(cobject);
    nssPKIObject_Destroy(cobject);
    NSSRWLock_UnlockRead(td->tokensLock);
    return nssrv;
}

/* CERT_TraversePermCertsForSubject */
NSS_IMPLEMENT PRStatus
nssTrustDomain_TraverseCertificatesBySubject(
    NSSTrustDomain *td,
    NSSDER *subject,
    PRStatus (*callback)(NSSCertificate *c, void *arg),
    void *arg)
{
    PRStatus nssrv = PR_SUCCESS;
    NSSArena *tmpArena;
    NSSCertificate **subjectCerts;
    NSSCertificate *c;
    PRIntn i;
    tmpArena = NSSArena_Create();
    if (!tmpArena) {
        return PR_FAILURE;
    }
    subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, subject, NULL,
                                                            0, tmpArena);
    if (subjectCerts) {
        for (i = 0, c = subjectCerts[i]; c; i++) {
            nssrv = callback(c, arg);
            if (nssrv != PR_SUCCESS)
                break;
        }
    }
    nssArena_Destroy(tmpArena);
    return nssrv;
}

/* CERT_TraversePermCertsForNickname */
NSS_IMPLEMENT PRStatus
nssTrustDomain_TraverseCertificatesByNickname(
    NSSTrustDomain *td,
    NSSUTF8 *nickname,
    PRStatus (*callback)(NSSCertificate *c, void *arg),
    void *arg)
{
    PRStatus nssrv = PR_SUCCESS;
    NSSArena *tmpArena;
    NSSCertificate **nickCerts;
    NSSCertificate *c;
    PRIntn i;
    tmpArena = NSSArena_Create();
    if (!tmpArena) {
        return PR_FAILURE;
    }
    nickCerts = NSSTrustDomain_FindCertificatesByNickname(td, nickname, NULL,
                                                          0, tmpArena);
    if (nickCerts) {
        for (i = 0, c = nickCerts[i]; c; i++) {
            nssrv = callback(c, arg);
            if (nssrv != PR_SUCCESS)
                break;
        }
    }
    nssArena_Destroy(tmpArena);
    return nssrv;
}

static void
cert_dump_iter(const void *k, void *v, void *a)
{
    NSSCertificate *c = (NSSCertificate *)k;
    CERTCertificate *cert = STAN_GetCERTCertificate(c);
    printf("[%2d] \"%s\"\n", c->object.refCount, cert->subjectName);
}

void
nss_DumpCertificateCacheInfo()
{
    NSSTrustDomain *td;
    NSSCryptoContext *cc;
    td = STAN_GetDefaultTrustDomain();
    cc = STAN_GetDefaultCryptoContext();
    printf("\n\nCertificates in the cache:\n");
    nssTrustDomain_DumpCacheInfo(td, cert_dump_iter, NULL);
    printf("\n\nCertificates in the temporary store:\n");
    if (cc->certStore) {
        nssCertificateStore_DumpStoreInfo(cc->certStore, cert_dump_iter, NULL);
    }
}

Messung V0.5
C=95 H=88 G=91

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge