Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/lib/pki/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  pkistore.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/. */


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

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

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

#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */

#ifndef PKISTORE_H
#include "pkistore.h"
#endif /* PKISTORE_H */

#include "cert.h"
#include "pki3hack.h"

#include "prbit.h"

/*
 * Certificate Store
 *
 * This differs from the cache in that it is a true storage facility.  Items
 * stay in until they are explicitly removed.  It is only used by crypto
 * contexts at this time, but may be more generally useful...
 *
 */


struct nssCertificateStoreStr {
    PRBool i_alloced_arena;
    NSSArena *arena;
    PZLock *lock;
    nssHash *subject;
    nssHash *issuer_and_serial;
};

typedef struct certificate_hash_entry_str certificate_hash_entry;

struct certificate_hash_entry_str {
    NSSCertificate *cert;
    NSSTrust *trust;
    nssSMIMEProfile *profile;
};

/* forward static declarations */
static NSSCertificate *
nssCertStore_FindCertByIssuerAndSerialNumberLocked(
    nssCertificateStore *store,
    NSSDER *issuer,
    NSSDER *serial);

NSS_IMPLEMENT nssCertificateStore *
nssCertificateStore_Create(NSSArena *arenaOpt)
{
    NSSArena *arena;
    nssCertificateStore *store;
    PRBool i_alloced_arena;
    if (arenaOpt) {
        arena = arenaOpt;
        i_alloced_arena = PR_FALSE;
    } else {
        arena = nssArena_Create();
        if (!arena) {
            return NULL;
        }
        i_alloced_arena = PR_TRUE;
    }
    store = nss_ZNEW(arena, nssCertificateStore);
    if (!store) {
        goto loser;
    }
    store->lock = PZ_NewLock(nssILockOther);
    if (!store->lock) {
        goto loser;
    }
    /* Create the issuer/serial --> {cert, trust, S/MIME profile } hash */
    store->issuer_and_serial = nssHash_CreateCertificate(arena, 0);
    if (!store->issuer_and_serial) {
        goto loser;
    }
    /* Create the subject DER --> subject list hash */
    store->subject = nssHash_CreateItem(arena, 0);
    if (!store->subject) {
        goto loser;
    }
    store->arena = arena;
    store->i_alloced_arena = i_alloced_arena;
    return store;
loser:
    if (store) {
        if (store->lock) {
            PZ_DestroyLock(store->lock);
        }
        if (store->issuer_and_serial) {
            nssHash_Destroy(store->issuer_and_serial);
        }
        if (store->subject) {
            nssHash_Destroy(store->subject);
        }
    }
    if (i_alloced_arena) {
        nssArena_Destroy(arena);
    }
    return NULL;
}

extern const NSSError NSS_ERROR_BUSY;

NSS_IMPLEMENT PRStatus
nssCertificateStore_Destroy(nssCertificateStore *store)
{
    if (nssHash_Count(store->issuer_and_serial) > 0) {
        nss_SetError(NSS_ERROR_BUSY);
        return PR_FAILURE;
    }
    PZ_DestroyLock(store->lock);
    nssHash_Destroy(store->issuer_and_serial);
    nssHash_Destroy(store->subject);
    if (store->i_alloced_arena) {
        nssArena_Destroy(store->arena);
    } else {
        nss_ZFreeIf(store);
    }
    return PR_SUCCESS;
}

static PRStatus
add_certificate_entry(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    PRStatus nssrv;
    certificate_hash_entry *entry;
    entry = nss_ZNEW(cert->object.arena, certificate_hash_entry);
    if (!entry) {
        return PR_FAILURE;
    }
    entry->cert = cert;
    nssrv = nssHash_Add(store->issuer_and_serial, cert, entry);
    if (nssrv != PR_SUCCESS) {
        nss_ZFreeIf(entry);
    }
    return nssrv;
}

static PRStatus
add_subject_entry(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    PRStatus nssrv;
    nssList *subjectList;
    subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
    if (subjectList) {
        /* The subject is already in, add this cert to the list */
        nssrv = nssList_AddUnique(subjectList, cert);
    } else {
        /* Create a new subject list for the subject */
        subjectList = nssList_Create(NULL, PR_FALSE);
        if (!subjectList) {
            return PR_FAILURE;
        }
        nssList_SetSortFunction(subjectList, nssCertificate_SubjectListSort);
        /* Add the cert entry to this list of subjects */
        nssrv = nssList_Add(subjectList, cert);
        if (nssrv != PR_SUCCESS) {
            return nssrv;
        }
        /* Add the subject list to the cache */
        nssrv = nssHash_Add(store->subject, &cert->subject, subjectList);
    }
    return nssrv;
}

/* declared below */
static void
remove_certificate_entry(
    nssCertificateStore *store,
    NSSCertificate *cert);

/* Caller must hold store->lock */
static PRStatus
nssCertificateStore_AddLocked(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    PRStatus nssrv = add_certificate_entry(store, cert);
    if (nssrv == PR_SUCCESS) {
        nssrv = add_subject_entry(store, cert);
        if (nssrv == PR_FAILURE) {
            remove_certificate_entry(store, cert);
        }
    }
    return nssrv;
}

NSS_IMPLEMENT NSSCertificate *
nssCertificateStore_FindOrAdd(
    nssCertificateStore *store,
    NSSCertificate *c)
{
    PRStatus nssrv;
    NSSCertificate *rvCert = NULL;

    PZ_Lock(store->lock);
    rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked(
        store, &c->issuer, &c->serial);
    if (!rvCert) {
        nssrv = nssCertificateStore_AddLocked(store, c);
        if (PR_SUCCESS == nssrv) {
            rvCert = nssCertificate_AddRef(c);
        }
    }
    PZ_Unlock(store->lock);
    return rvCert;
}

static void
remove_certificate_entry(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    certificate_hash_entry *entry;
    entry = (certificate_hash_entry *)
        nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry) {
        nssHash_Remove(store->issuer_and_serial, cert);
        if (entry->trust) {
            nssTrust_Destroy(entry->trust);
        }
        if (entry->profile) {
            nssSMIMEProfile_Destroy(entry->profile);
        }
        nss_ZFreeIf(entry);
    }
}

static void
remove_subject_entry(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    nssList *subjectList;
    /* Get the subject list for the cert's subject */
    subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
    if (subjectList) {
        /* Remove the cert from the subject hash */
        nssList_Remove(subjectList, cert);
        nssHash_Remove(store->subject, &cert->subject);
        if (nssList_Count(subjectList) == 0) {
            nssList_Destroy(subjectList);
        } else {
            /* The cert being released may have keyed the subject entry.
             * Since there are still subject certs around, get another and
             * rekey the entry just in case.
             */

            NSSCertificate *subjectCert;
            (void)nssList_GetArray(subjectList, (void **)&subjectCert, 1);
            nssHash_Add(store->subject, &subjectCert->subject, subjectList);
        }
    }
}

NSS_IMPLEMENT void
nssCertificateStore_RemoveCertLOCKED(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    certificate_hash_entry *entry;
    entry = (certificate_hash_entry *)
        nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry && entry->cert == cert) {
        remove_certificate_entry(store, cert);
        remove_subject_entry(store, cert);
    }
}

NSS_IMPLEMENT void
nssCertificateStore_Lock(nssCertificateStore *store, nssCertificateStoreTrace *out)
{
#ifdef DEBUG
    PORT_Assert(out);
    out->store = store;
    out->lock = store->lock;
    out->locked = PR_TRUE;
    PZ_Lock(out->lock);
#else
    PZ_Lock(store->lock);
#endif
}

NSS_IMPLEMENT void
nssCertificateStore_Unlock(
    nssCertificateStore *store, const nssCertificateStoreTrace *in,
    nssCertificateStoreTrace *out)
{
#ifdef DEBUG
    PORT_Assert(in);
    PORT_Assert(out);
    out->store = store;
    out->lock = store->lock;
    PORT_Assert(!out->locked);
    out->unlocked = PR_TRUE;

    PORT_Assert(in->store == out->store);
    PORT_Assert(in->lock == out->lock);
    PORT_Assert(in->locked);
    PORT_Assert(!in->unlocked);

    PZ_Unlock(out->lock);
#else
    PZ_Unlock(store->lock);
#endif
}

static NSSCertificate **
get_array_from_list(
    nssList *certList,
    NSSCertificate *rvOpt[],
    PRUint32 maximumOpt,
    NSSArena *arenaOpt)
{
    PRUint32 count;
    NSSCertificate **rvArray = NULL;
    count = nssList_Count(certList);
    if (count == 0) {
        return NULL;
    }
    if (maximumOpt > 0) {
        count = PR_MIN(maximumOpt, count);
    }
    if (rvOpt) {
        nssList_GetArray(certList, (void **)rvOpt, count);
    } else {
        rvArray = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1);
        if (rvArray) {
            nssList_GetArray(certList, (void **)rvArray, count);
        }
    }
    return rvArray;
}

NSS_IMPLEMENT NSSCertificate **
nssCertificateStore_FindCertificatesBySubject(
    nssCertificateStore *store,
    NSSDER *subject,
    NSSCertificate *rvOpt[],
    PRUint32 maximumOpt,
    NSSArena *arenaOpt)
{
    NSSCertificate **rvArray = NULL;
    nssList *subjectList;
    PZ_Lock(store->lock);
    subjectList = (nssList *)nssHash_Lookup(store->subject, subject);
    if (subjectList) {
        nssCertificateList_AddReferences(subjectList);
        rvArray = get_array_from_list(subjectList,
                                      rvOpt, maximumOpt, arenaOpt);
    }
    PZ_Unlock(store->lock);
    return rvArray;
}

/* Because only subject indexing is implemented, all other lookups require
 * full traversal (unfortunately, PLHashTable doesn't allow you to exit
 * early from the enumeration).  The assumptions are that 1) lookups by
 * fields other than subject will be rare, and 2) the hash will not have
 * a large number of entries.  These assumptions will be tested.
 *
 * XXX
 * For NSS 3.4, it is worth consideration to do all forms of indexing,
 * because the only crypto context is global and persistent.
 */


struct nickname_template_str {
    NSSUTF8 *nickname;
    nssList *subjectList;
};

static void
match_nickname(const void *k, void *v, void *a)
{
    PRStatus nssrv;
    NSSCertificate *c;
    NSSUTF8 *nickname;
    nssList *subjectList = (nssList *)v;
    struct nickname_template_str *nt = (struct nickname_template_str *)a;
    nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
    nickname = nssCertificate_GetNickname(c, NULL);
    if (nssrv == PR_SUCCESS && nickname &&
        nssUTF8_Equal(nickname, nt->nickname, &nssrv)) {
        nt->subjectList = subjectList;
    }
    nss_ZFreeIf(nickname);
}

/*
 * Find all cached certs with this label.
 */

NSS_IMPLEMENT NSSCertificate **
nssCertificateStore_FindCertificatesByNickname(
    nssCertificateStore *store,
    const NSSUTF8 *nickname,
    NSSCertificate *rvOpt[],
    PRUint32 maximumOpt,
    NSSArena *arenaOpt)
{
    NSSCertificate **rvArray = NULL;
    struct nickname_template_str nt;
    nt.nickname = (char *)nickname;
    nt.subjectList = NULL;
    PZ_Lock(store->lock);
    nssHash_Iterate(store->subject, match_nickname, &nt);
    if (nt.subjectList) {
        nssCertificateList_AddReferences(nt.subjectList);
        rvArray = get_array_from_list(nt.subjectList,
                                      rvOpt, maximumOpt, arenaOpt);
    }
    PZ_Unlock(store->lock);
    return rvArray;
}

struct email_template_str {
    NSSASCII7 *email;
    nssList *emailList;
};

static void
match_email(const void *k, void *v, void *a)
{
    PRStatus nssrv;
    NSSCertificate *c;
    nssList *subjectList = (nssList *)v;
    struct email_template_str *et = (struct email_template_str *)a;
    nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
    if (nssrv == PR_SUCCESS &&
        nssUTF8_Equal(c->email, et->email, &nssrv)) {
        nssListIterator *iter = nssList_CreateIterator(subjectList);
        if (iter) {
            for (c = (NSSCertificate *)nssListIterator_Start(iter);
                 c != (NSSCertificate *)NULL;
                 c = (NSSCertificate *)nssListIterator_Next(iter)) {
                nssList_Add(et->emailList, c);
            }
            nssListIterator_Finish(iter);
            nssListIterator_Destroy(iter);
        }
    }
}

/*
 * Find all cached certs with this email address.
 */

NSS_IMPLEMENT NSSCertificate **
nssCertificateStore_FindCertificatesByEmail(
    nssCertificateStore *store,
    NSSASCII7 *email,
    NSSCertificate *rvOpt[],
    PRUint32 maximumOpt,
    NSSArena *arenaOpt)
{
    NSSCertificate **rvArray = NULL;
    struct email_template_str et;
    et.email = email;
    et.emailList = nssList_Create(NULL, PR_FALSE);
    if (!et.emailList) {
        return NULL;
    }
    PZ_Lock(store->lock);
    nssHash_Iterate(store->subject, match_email, &et);
    if (et.emailList) {
        /* get references before leaving the store's lock protection */
        nssCertificateList_AddReferences(et.emailList);
    }
    PZ_Unlock(store->lock);
    if (et.emailList) {
        rvArray = get_array_from_list(et.emailList,
                                      rvOpt, maximumOpt, arenaOpt);
        nssList_Destroy(et.emailList);
    }
    return rvArray;
}

/* Caller holds store->lock */
static NSSCertificate *
nssCertStore_FindCertByIssuerAndSerialNumberLocked(
    nssCertificateStore *store,
    NSSDER *issuer,
    NSSDER *serial)
{
    certificate_hash_entry *entry;
    NSSCertificate *rvCert = NULL;
    NSSCertificate index;

    index.issuer = *issuer;
    index.serial = *serial;
    entry = (certificate_hash_entry *)
        nssHash_Lookup(store->issuer_and_serial, &index);
    if (entry) {
        rvCert = nssCertificate_AddRef(entry->cert);
    }
    return rvCert;
}

NSS_IMPLEMENT NSSCertificate *
nssCertificateStore_FindCertificateByIssuerAndSerialNumber(
    nssCertificateStore *store,
    NSSDER *issuer,
    NSSDER *serial)
{
    NSSCertificate *rvCert = NULL;

    PZ_Lock(store->lock);
    rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked(
        store, issuer, serial);
    PZ_Unlock(store->lock);
    return rvCert;
}

NSS_IMPLEMENT NSSCertificate *
nssCertificateStore_FindCertificateByEncodedCertificate(
    nssCertificateStore *store,
    NSSDER *encoding)
{
    PRStatus nssrv = PR_FAILURE;
    NSSDER issuer, serial;
    NSSCertificate *rvCert = NULL;
    nssrv = nssPKIX509_GetIssuerAndSerialFromDER(encoding, &issuer, &serial);
    if (nssrv != PR_SUCCESS) {
        return NULL;
    }
    rvCert = nssCertificateStore_FindCertificateByIssuerAndSerialNumber(store,
                                                                        &issuer,
                                                                        &serial);
    PORT_Free(issuer.data);
    PORT_Free(serial.data);
    return rvCert;
}

NSS_EXTERN PRStatus
nssCertificateStore_AddTrust(
    nssCertificateStore *store,
    NSSTrust *trust)
{
    NSSCertificate *cert;
    certificate_hash_entry *entry;
    cert = trust->certificate;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
        nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry) {
        NSSTrust *newTrust = nssTrust_AddRef(trust);
        if (entry->trust) {
            nssTrust_Destroy(entry->trust);
        }
        entry->trust = newTrust;
    }
    PZ_Unlock(store->lock);
    return (entry) ? PR_SUCCESS : PR_FAILURE;
}

NSS_IMPLEMENT NSSTrust *
nssCertificateStore_FindTrustForCertificate(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    certificate_hash_entry *entry;
    NSSTrust *rvTrust = NULL;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
        nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry && entry->trust) {
        rvTrust = nssTrust_AddRef(entry->trust);
    }
    PZ_Unlock(store->lock);
    return rvTrust;
}

NSS_EXTERN PRStatus
nssCertificateStore_AddSMIMEProfile(
    nssCertificateStore *store,
    nssSMIMEProfile *profile)
{
    NSSCertificate *cert;
    certificate_hash_entry *entry;
    cert = profile->certificate;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
        nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry) {
        nssSMIMEProfile *newProfile = nssSMIMEProfile_AddRef(profile);
        if (entry->profile) {
            nssSMIMEProfile_Destroy(entry->profile);
        }
        entry->profile = newProfile;
    }
    PZ_Unlock(store->lock);
    return (entry) ? PR_SUCCESS : PR_FAILURE;
}

NSS_IMPLEMENT nssSMIMEProfile *
nssCertificateStore_FindSMIMEProfileForCertificate(
    nssCertificateStore *store,
    NSSCertificate *cert)
{
    certificate_hash_entry *entry;
    nssSMIMEProfile *rvProfile = NULL;
    PZ_Lock(store->lock);
    entry = (certificate_hash_entry *)
        nssHash_Lookup(store->issuer_and_serial, cert);
    if (entry && entry->profile) {
        rvProfile = nssSMIMEProfile_AddRef(entry->profile);
    }
    PZ_Unlock(store->lock);
    return rvProfile;
}

/* XXX this is also used by cache and should be somewhere else */

static PLHashNumber
nss_certificate_hash(const void *key)
{
    unsigned int i;
    PLHashNumber h;
    NSSCertificate *c = (NSSCertificate *)key;
    h = 0;
    for (i = 0; i < c->issuer.size; i++)
        h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->issuer.data)[i];
    for (i = 0; i < c->serial.size; i++)
        h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->serial.data)[i];
    return h;
}

static int
nss_compare_certs(const void *v1, const void *v2)
{
    PRStatus ignore;
    NSSCertificate *c1 = (NSSCertificate *)v1;
    NSSCertificate *c2 = (NSSCertificate *)v2;
    return (int)(nssItem_Equal(&c1->issuer, &c2->issuer, &ignore) &&
                 nssItem_Equal(&c1->serial, &c2->serial, &ignore));
}

NSS_IMPLEMENT nssHash *
nssHash_CreateCertificate(
    NSSArena *arenaOpt,
    PRUint32 numBuckets)
{
    return nssHash_Create(arenaOpt,
                          numBuckets,
                          nss_certificate_hash,
                          nss_compare_certs,
                          PL_CompareValues);
}

NSS_IMPLEMENT void
nssCertificateStore_DumpStoreInfo(
    nssCertificateStore *store,
    void (*cert_dump_iter)(const void *, void *, void *),
    void *arg)
{
    PZ_Lock(store->lock);
    nssHash_Iterate(store->issuer_and_serial, cert_dump_iter, arg);
    PZ_Unlock(store->lock);
}

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.2 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.