summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/pki
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/nss/lib/pki
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/lib/pki')
-rw-r--r--security/nss/lib/pki/Makefile14
-rw-r--r--security/nss/lib/pki/asymmkey.c361
-rw-r--r--security/nss/lib/pki/certdecode.c60
-rw-r--r--security/nss/lib/pki/certificate.c1101
-rw-r--r--security/nss/lib/pki/cryptocontext.c914
-rw-r--r--security/nss/lib/pki/doc/standiag.pngbin0 -> 20475 bytes
-rw-r--r--security/nss/lib/pki/doc/standoc.html442
-rw-r--r--security/nss/lib/pki/exports.gyp32
-rw-r--r--security/nss/lib/pki/manifest.mn42
-rw-r--r--security/nss/lib/pki/nsspki.h2791
-rw-r--r--security/nss/lib/pki/nsspkit.h247
-rw-r--r--security/nss/lib/pki/pki.gyp32
-rw-r--r--security/nss/lib/pki/pki.h141
-rw-r--r--security/nss/lib/pki/pki3hack.c1510
-rw-r--r--security/nss/lib/pki/pki3hack.h149
-rw-r--r--security/nss/lib/pki/pkibase.c1224
-rw-r--r--security/nss/lib/pki/pkim.h547
-rw-r--r--security/nss/lib/pki/pkistore.c675
-rw-r--r--security/nss/lib/pki/pkistore.h138
-rw-r--r--security/nss/lib/pki/pkit.h183
-rw-r--r--security/nss/lib/pki/pkitm.h88
-rw-r--r--security/nss/lib/pki/symmkey.c238
-rw-r--r--security/nss/lib/pki/tdcache.c1113
-rw-r--r--security/nss/lib/pki/trustdomain.c1230
24 files changed, 13272 insertions, 0 deletions
diff --git a/security/nss/lib/pki/Makefile b/security/nss/lib/pki/Makefile
new file mode 100644
index 0000000000..3f49eaa45d
--- /dev/null
+++ b/security/nss/lib/pki/Makefile
@@ -0,0 +1,14 @@
+#
+# 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/.
+
+include manifest.mn
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+ifdef BUILD_IDG
+DEFINES += -DNSSDEBUG
+endif
+
+include $(CORE_DEPTH)/coreconf/rules.mk
diff --git a/security/nss/lib/pki/asymmkey.c b/security/nss/lib/pki/asymmkey.c
new file mode 100644
index 0000000000..c5fa8a4e0e
--- /dev/null
+++ b/security/nss/lib/pki/asymmkey.c
@@ -0,0 +1,361 @@
+/* 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 NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+NSS_IMPLEMENT PRStatus
+NSSPrivateKey_Destroy(
+ NSSPrivateKey *vk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPrivateKey_DeleteStoredObject(
+ NSSPrivateKey *vk,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSPrivateKey_GetSignatureLength(
+ NSSPrivateKey *vk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return -1;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSPrivateKey_GetPrivateModulusLength(
+ NSSPrivateKey *vk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return -1;
+}
+
+NSS_IMPLEMENT PRBool
+NSSPrivateKey_IsStillPresent(
+ NSSPrivateKey *vk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FALSE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_Encode(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *ap,
+ NSSItem *passwordOpt, /* NULL will cause a callback; "" for no password */
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSPrivateKey_GetTrustDomain(
+ NSSPrivateKey *vk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSPrivateKey_GetToken(NSSPrivateKey *vk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSPrivateKey_GetSlot(NSSPrivateKey *vk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSPrivateKey_GetModule(
+ NSSPrivateKey *vk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_Decrypt(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *encryptedData,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_Sign(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPrivateKey_SignRecover(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSPrivateKey_UnwrapSymmetricKey(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSPrivateKey_DeriveSymmetricKey(
+ NSSPrivateKey *vk,
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt, /* zero for best allowed */
+ NSSOperations operations,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSPublicKey *
+NSSPrivateKey_FindPublicKey(
+ NSSPrivateKey *vk
+ /* { don't need the callback here, right? } */
+)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSPrivateKey_CreateCryptoContext(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSPrivateKey_FindCertificates(
+ NSSPrivateKey *vk,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSPrivateKey_FindBestCertificate(
+ NSSPrivateKey *vk,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPublicKey_Destroy(NSSPublicKey *bk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPublicKey_DeleteStoredObject(
+ NSSPublicKey *bk,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_Encode(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *ap,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSPublicKey_GetTrustDomain(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSPublicKey_GetToken(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSPublicKey_GetSlot(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSPublicKey_GetModule(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_Encrypt(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSPublicKey_Verify(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_VerifyRecover(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSPublicKey_WrapSymmetricKey(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSPublicKey_CreateCryptoContext(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSPublicKey_FindCertificates(
+ NSSPublicKey *bk,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSPublicKey_FindBestCertificate(
+ NSSPublicKey *bk,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSPublicKey_FindPrivateKey(
+ NSSPublicKey *bk,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
diff --git a/security/nss/lib/pki/certdecode.c b/security/nss/lib/pki/certdecode.c
new file mode 100644
index 0000000000..61c8033209
--- /dev/null
+++ b/security/nss/lib/pki/certdecode.c
@@ -0,0 +1,60 @@
+/* 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 PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+/* This is defined in pki3hack.c */
+NSS_EXTERN nssDecodedCert *
+nssDecodedPKIXCertificate_Create(
+ NSSArena *arenaOpt,
+ NSSDER *encoding);
+
+NSS_IMPLEMENT PRStatus
+nssDecodedPKIXCertificate_Destroy(
+ nssDecodedCert *dc);
+
+NSS_IMPLEMENT nssDecodedCert *
+nssDecodedCert_Create(
+ NSSArena *arenaOpt,
+ NSSDER *encoding,
+ NSSCertificateType type)
+{
+ nssDecodedCert *rvDC = NULL;
+ switch (type) {
+ case NSSCertificateType_PKIX:
+ rvDC = nssDecodedPKIXCertificate_Create(arenaOpt, encoding);
+ break;
+ default:
+#if 0
+ nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+#endif
+ return (nssDecodedCert *)NULL;
+ }
+ return rvDC;
+}
+
+NSS_IMPLEMENT PRStatus
+nssDecodedCert_Destroy(
+ nssDecodedCert *dc)
+{
+ if (!dc) {
+ return PR_FAILURE;
+ }
+ switch (dc->type) {
+ case NSSCertificateType_PKIX:
+ return nssDecodedPKIXCertificate_Destroy(dc);
+ default:
+#if 0
+ nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+#endif
+ break;
+ }
+ return PR_FAILURE;
+}
diff --git a/security/nss/lib/pki/certificate.c b/security/nss/lib/pki/certificate.c
new file mode 100644
index 0000000000..0cfdcb12b5
--- /dev/null
+++ b/security/nss/lib/pki/certificate.c
@@ -0,0 +1,1101 @@
+/* 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 NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#include "pkistore.h"
+
+#include "pki3hack.h"
+#include "pk11func.h"
+#include "hasht.h"
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+/* Creates a certificate from a base object */
+NSS_IMPLEMENT NSSCertificate *
+nssCertificate_Create(
+ nssPKIObject *object)
+{
+ PRStatus status;
+ NSSCertificate *rvCert;
+ nssArenaMark *mark;
+ NSSArena *arena = object->arena;
+ PR_ASSERT(object->instances != NULL && object->numInstances > 0);
+ PR_ASSERT(object->lockType == nssPKIMonitor);
+ mark = nssArena_Mark(arena);
+ rvCert = nss_ZNEW(arena, NSSCertificate);
+ if (!rvCert) {
+ return (NSSCertificate *)NULL;
+ }
+ rvCert->object = *object;
+ /* XXX should choose instance based on some criteria */
+ status = nssCryptokiCertificate_GetAttributes(object->instances[0],
+ NULL, /* XXX sessionOpt */
+ arena,
+ &rvCert->type,
+ &rvCert->id,
+ &rvCert->encoding,
+ &rvCert->issuer,
+ &rvCert->serial,
+ &rvCert->subject);
+ if (status != PR_SUCCESS ||
+ !rvCert->encoding.data ||
+ !rvCert->encoding.size ||
+ !rvCert->issuer.data ||
+ !rvCert->issuer.size ||
+ !rvCert->serial.data ||
+ !rvCert->serial.size) {
+ if (mark)
+ nssArena_Release(arena, mark);
+ return (NSSCertificate *)NULL;
+ }
+ if (mark)
+ nssArena_Unmark(arena, mark);
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssCertificate_AddRef(
+ NSSCertificate *c)
+{
+ if (c) {
+ nssPKIObject_AddRef(&c->object);
+ }
+ return c;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCertificate_Destroy(
+ NSSCertificate *c)
+{
+ nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
+ nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
+
+ if (c) {
+ PRUint32 i;
+ nssDecodedCert *dc = c->decoding;
+ NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
+ NSSCryptoContext *cc = c->object.cryptoContext;
+
+ PR_ASSERT(c->object.refCount > 0);
+
+ /* --- LOCK storage --- */
+ if (cc) {
+ nssCertificateStore_Lock(cc->certStore, &lockTrace);
+ } else {
+ nssTrustDomain_LockCertCache(td);
+ }
+ if (PR_ATOMIC_DECREMENT(&c->object.refCount) == 0) {
+ /* --- remove cert and UNLOCK storage --- */
+ if (cc) {
+ nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
+ nssCertificateStore_Unlock(cc->certStore, &lockTrace,
+ &unlockTrace);
+ } else {
+ nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
+ nssTrustDomain_UnlockCertCache(td);
+ }
+ /* free cert data */
+ for (i = 0; i < c->object.numInstances; i++) {
+ nssCryptokiObject_Destroy(c->object.instances[i]);
+ }
+ nssPKIObject_DestroyLock(&c->object);
+ nssArena_Destroy(c->object.arena);
+ nssDecodedCert_Destroy(dc);
+ } else {
+ /* --- UNLOCK storage --- */
+ if (cc) {
+ nssCertificateStore_Unlock(cc->certStore,
+ &lockTrace,
+ &unlockTrace);
+ } else {
+ nssTrustDomain_UnlockCertCache(td);
+ }
+ }
+ }
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_Destroy(NSSCertificate *c)
+{
+ return nssCertificate_Destroy(c);
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetEncoding(NSSCertificate *c)
+{
+ if (c->encoding.size > 0 && c->encoding.data) {
+ return &c->encoding;
+ } else {
+ return (NSSDER *)NULL;
+ }
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetIssuer(NSSCertificate *c)
+{
+ if (c->issuer.size > 0 && c->issuer.data) {
+ return &c->issuer;
+ } else {
+ return (NSSDER *)NULL;
+ }
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetSerialNumber(NSSCertificate *c)
+{
+ if (c->serial.size > 0 && c->serial.data) {
+ return &c->serial;
+ } else {
+ return (NSSDER *)NULL;
+ }
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCertificate_GetSubject(NSSCertificate *c)
+{
+ if (c->subject.size > 0 && c->subject.data) {
+ return &c->subject;
+ } else {
+ return (NSSDER *)NULL;
+ }
+}
+
+/* Returns a copy, Caller must free using nss_ZFreeIf */
+NSS_IMPLEMENT NSSUTF8 *
+nssCertificate_GetNickname(
+ NSSCertificate *c,
+ NSSToken *tokenOpt)
+{
+ return nssPKIObject_GetNicknameForToken(&c->object, tokenOpt);
+}
+
+NSS_IMPLEMENT NSSASCII7 *
+nssCertificate_GetEmailAddress(NSSCertificate *c)
+{
+ return c->email;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_DeleteStoredObject(
+ NSSCertificate *c,
+ NSSCallback *uhh)
+{
+ return nssPKIObject_DeleteStoredObject(&c->object, uhh, PR_TRUE);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_Validate(
+ NSSCertificate *c,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt /* NULL for none */
+)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT void ** /* void *[] */
+NSSCertificate_ValidateCompletely(
+ NSSCertificate *c,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt, /* NULL for none */
+ void **rvOpt, /* NULL for allocate */
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt /* NULL for heap */
+)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_ValidateAndDiscoverUsagesAndPolicies(
+ NSSCertificate *c,
+ NSSTime **notBeforeOutOpt,
+ NSSTime **notAfterOutOpt,
+ void *allowedUsages,
+ void *disallowedUsages,
+ void *allowedPolicies,
+ void *disallowedPolicies,
+ /* more args.. work on this fgmr */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSDER *
+NSSCertificate_Encode(
+ NSSCertificate *c,
+ NSSDER *rvOpt,
+ NSSArena *arenaOpt)
+{
+ /* Item, DER, BER are all typedefs now... */
+ return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt);
+}
+
+NSS_IMPLEMENT nssDecodedCert *
+nssCertificate_GetDecoding(
+ NSSCertificate *c)
+{
+ nssDecodedCert *deco = NULL;
+ if (c->type == NSSCertificateType_PKIX) {
+ (void)STAN_GetCERTCertificate(c);
+ }
+ nssPKIObject_Lock(&c->object);
+ if (!c->decoding) {
+ deco = nssDecodedCert_Create(NULL, &c->encoding, c->type);
+ PORT_Assert(!c->decoding);
+ c->decoding = deco;
+ } else {
+ deco = c->decoding;
+ }
+ nssPKIObject_Unlock(&c->object);
+ return deco;
+}
+
+static NSSCertificate **
+filter_subject_certs_for_id(
+ NSSCertificate **subjectCerts,
+ void *id)
+{
+ NSSCertificate **si;
+ nssDecodedCert *dcp;
+ int nextOpenSlot = 0;
+ int i;
+ nssCertIDMatch matchLevel = nssCertIDMatch_Unknown;
+ nssCertIDMatch match;
+
+ /* walk the subject certs */
+ for (si = subjectCerts; *si; si++) {
+ dcp = nssCertificate_GetDecoding(*si);
+ if (!dcp) {
+ NSSCertificate_Destroy(*si);
+ continue;
+ }
+ match = dcp->matchIdentifier(dcp, id);
+ switch (match) {
+ case nssCertIDMatch_Yes:
+ if (matchLevel == nssCertIDMatch_Unknown) {
+ /* we have non-definitive matches, forget them */
+ for (i = 0; i < nextOpenSlot; i++) {
+ NSSCertificate_Destroy(subjectCerts[i]);
+ subjectCerts[i] = NULL;
+ }
+ nextOpenSlot = 0;
+ /* only keep definitive matches from now on */
+ matchLevel = nssCertIDMatch_Yes;
+ }
+ /* keep the cert */
+ subjectCerts[nextOpenSlot++] = *si;
+ break;
+ case nssCertIDMatch_Unknown:
+ if (matchLevel == nssCertIDMatch_Unknown) {
+ /* only have non-definitive matches so far, keep it */
+ subjectCerts[nextOpenSlot++] = *si;
+ break;
+ }
+ /* else fall through, we have a definitive match already */
+ case nssCertIDMatch_No:
+ default:
+ NSSCertificate_Destroy(*si);
+ *si = NULL;
+ }
+ }
+ subjectCerts[nextOpenSlot] = NULL;
+ return subjectCerts;
+}
+
+static NSSCertificate **
+filter_certs_for_valid_issuers(NSSCertificate **certs)
+{
+ NSSCertificate **cp;
+ nssDecodedCert *dcp;
+ int nextOpenSlot = 0;
+
+ for (cp = certs; *cp; cp++) {
+ dcp = nssCertificate_GetDecoding(*cp);
+ if (dcp && dcp->isValidIssuer(dcp)) {
+ certs[nextOpenSlot++] = *cp;
+ } else {
+ NSSCertificate_Destroy(*cp);
+ }
+ }
+ certs[nextOpenSlot] = NULL;
+ return certs;
+}
+
+static NSSCertificate *
+find_cert_issuer(
+ NSSCertificate *c,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSTrustDomain *td,
+ NSSCryptoContext *cc)
+{
+ NSSArena *arena;
+ NSSCertificate **certs = NULL;
+ NSSCertificate **ccIssuers = NULL;
+ NSSCertificate **tdIssuers = NULL;
+ NSSCertificate *issuer = NULL;
+
+ if (!cc)
+ cc = c->object.cryptoContext;
+ if (!td)
+ td = NSSCertificate_GetTrustDomain(c);
+ arena = nssArena_Create();
+ if (!arena) {
+ return (NSSCertificate *)NULL;
+ }
+ if (cc) {
+ ccIssuers = nssCryptoContext_FindCertificatesBySubject(cc,
+ &c->issuer,
+ NULL,
+ 0,
+ arena);
+ }
+ if (td)
+ tdIssuers = nssTrustDomain_FindCertificatesBySubject(td,
+ &c->issuer,
+ NULL,
+ 0,
+ arena);
+ certs = nssCertificateArray_Join(ccIssuers, tdIssuers);
+ if (certs) {
+ nssDecodedCert *dc = NULL;
+ void *issuerID = NULL;
+ dc = nssCertificate_GetDecoding(c);
+ if (dc) {
+ issuerID = dc->getIssuerIdentifier(dc);
+ }
+ /* XXX review based on CERT_FindCertIssuer
+ * this function is not using the authCertIssuer field as a fallback
+ * if authority key id does not exist
+ */
+ if (issuerID) {
+ certs = filter_subject_certs_for_id(certs, issuerID);
+ }
+ certs = filter_certs_for_valid_issuers(certs);
+ issuer = nssCertificateArray_FindBestCertificate(certs,
+ timeOpt,
+ usage,
+ policiesOpt);
+ nssCertificateArray_Destroy(certs);
+ }
+ nssArena_Destroy(arena);
+ return issuer;
+}
+
+/* This function returns the built chain, as far as it gets,
+** even if/when it fails to find an issuer, and returns PR_FAILURE
+*/
+NSS_IMPLEMENT NSSCertificate **
+nssCertificate_BuildChain(
+ NSSCertificate *c,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit,
+ NSSArena *arenaOpt,
+ PRStatus *statusOpt,
+ NSSTrustDomain *td,
+ NSSCryptoContext *cc)
+{
+ NSSCertificate **rvChain = NULL;
+ NSSUsage issuerUsage = *usage;
+ nssPKIObjectCollection *collection = NULL;
+ PRUint32 rvCount = 0;
+ PRStatus st;
+ PRStatus ret = PR_SUCCESS;
+
+ if (!c || !cc ||
+ (!td && (td = NSSCertificate_GetTrustDomain(c)) == NULL)) {
+ goto loser;
+ }
+ /* bump the usage up to CA level */
+ issuerUsage.nss3lookingForCA = PR_TRUE;
+ collection = nssCertificateCollection_Create(td, NULL);
+ if (!collection)
+ goto loser;
+ st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
+ if (st != PR_SUCCESS)
+ goto loser;
+ for (rvCount = 1; (!rvLimit || rvCount < rvLimit); ++rvCount) {
+ CERTCertificate *cCert = STAN_GetCERTCertificate(c);
+ if (cCert->isRoot) {
+ /* not including the issuer of the self-signed cert, which is,
+ * of course, itself
+ */
+ break;
+ }
+ c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt, td, cc);
+ if (!c) {
+ ret = PR_FAILURE;
+ break;
+ }
+ st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c);
+ nssCertificate_Destroy(c); /* collection has it */
+ if (st != PR_SUCCESS)
+ goto loser;
+ }
+ rvChain = nssPKIObjectCollection_GetCertificates(collection,
+ rvOpt,
+ rvLimit,
+ arenaOpt);
+ if (rvChain) {
+ nssPKIObjectCollection_Destroy(collection);
+ if (statusOpt)
+ *statusOpt = ret;
+ if (ret != PR_SUCCESS)
+ nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
+ return rvChain;
+ }
+
+loser:
+ if (collection)
+ nssPKIObjectCollection_Destroy(collection);
+ if (statusOpt)
+ *statusOpt = PR_FAILURE;
+ nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND);
+ return rvChain;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCertificate_BuildChain(
+ NSSCertificate *c,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt,
+ PRStatus *statusOpt,
+ NSSTrustDomain *td,
+ NSSCryptoContext *cc)
+{
+ return nssCertificate_BuildChain(c, timeOpt, usage, policiesOpt,
+ rvOpt, rvLimit, arenaOpt, statusOpt,
+ td, cc);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+nssCertificate_GetCryptoContext(NSSCertificate *c)
+{
+ return c->object.cryptoContext;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+nssCertificate_GetTrustDomain(NSSCertificate *c)
+{
+ return c->object.trustDomain;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSCertificate_GetTrustDomain(NSSCertificate *c)
+{
+ return nssCertificate_GetTrustDomain(c);
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSCertificate_GetToken(
+ NSSCertificate *c,
+ PRStatus *statusOpt)
+{
+ return (NSSToken *)NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSCertificate_GetSlot(
+ NSSCertificate *c,
+ PRStatus *statusOpt)
+{
+ return (NSSSlot *)NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSCertificate_GetModule(
+ NSSCertificate *c,
+ PRStatus *statusOpt)
+{
+ return (NSSModule *)NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCertificate_Encrypt(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCertificate_Verify(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCertificate_VerifyRecover(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCertificate_WrapSymmetricKey(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSCertificate_CreateCryptoContext(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSPublicKey *
+NSSCertificate_GetPublicKey(
+ NSSCertificate *c)
+{
+#if 0
+ CK_ATTRIBUTE pubktemplate[] = {
+ { CKA_CLASS, NULL, 0 },
+ { CKA_ID, NULL, 0 },
+ { CKA_SUBJECT, NULL, 0 }
+ };
+ PRStatus nssrv;
+ CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]);
+ NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey);
+ if (c->id.size > 0) {
+ /* CKA_ID */
+ NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]);
+ } else {
+ /* failure, yes? */
+ return (NSSPublicKey *)NULL;
+ }
+ if (c->subject.size > 0) {
+ /* CKA_SUBJECT */
+ NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]);
+ } else {
+ /* failure, yes? */
+ return (NSSPublicKey *)NULL;
+ }
+ /* Try the cert's token first */
+ if (c->token) {
+ nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count);
+ }
+#endif
+ /* Try all other key tokens */
+ return (NSSPublicKey *)NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSCertificate_FindPrivateKey(
+ NSSCertificate *c,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRBool
+NSSCertificate_IsPrivateKeyAvailable(
+ NSSCertificate *c,
+ NSSCallback *uhh,
+ PRStatus *statusOpt)
+{
+ PRBool isUser = PR_FALSE;
+ nssCryptokiObject **ip;
+ nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
+ if (!instances) {
+ return PR_FALSE;
+ }
+ for (ip = instances; *ip; ip++) {
+ nssCryptokiObject *instance = *ip;
+ if (nssToken_IsPrivateKeyAvailable(instance->token, c, instance)) {
+ isUser = PR_TRUE;
+ }
+ }
+ nssCryptokiObjectArray_Destroy(instances);
+ return isUser;
+}
+
+/* sort the subject cert list from newest to oldest */
+PRIntn
+nssCertificate_SubjectListSort(
+ void *v1,
+ void *v2)
+{
+ NSSCertificate *c1 = (NSSCertificate *)v1;
+ NSSCertificate *c2 = (NSSCertificate *)v2;
+ nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1);
+ nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2);
+ if (!dc1) {
+ return dc2 ? 1 : 0;
+ } else if (!dc2) {
+ return -1;
+ } else {
+ return dc1->isNewerThan(dc1, dc2) ? -1 : 1;
+ }
+}
+
+NSS_IMPLEMENT PRBool
+NSSUserCertificate_IsStillPresent(
+ NSSUserCertificate *uc,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FALSE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSUserCertificate_Decrypt(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSUserCertificate_Sign(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSUserCertificate_SignRecover(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSUserCertificate_UnwrapSymmetricKey(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSUserCertificate_DeriveSymmetricKey(
+ NSSUserCertificate *uc, /* provides private key */
+ NSSCertificate *c, /* provides public key */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt, /* zero for best allowed */
+ NSSOperations operations,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT nssSMIMEProfile *
+nssSMIMEProfile_Create(
+ NSSCertificate *cert,
+ NSSItem *profileTime,
+ NSSItem *profileData)
+{
+ NSSArena *arena;
+ nssSMIMEProfile *rvProfile;
+ nssPKIObject *object;
+ NSSTrustDomain *td = nssCertificate_GetTrustDomain(cert);
+ NSSCryptoContext *cc = nssCertificate_GetCryptoContext(cert);
+ arena = nssArena_Create();
+ if (!arena) {
+ return NULL;
+ }
+ object = nssPKIObject_Create(arena, NULL, td, cc, nssPKILock);
+ if (!object) {
+ goto loser;
+ }
+ rvProfile = nss_ZNEW(arena, nssSMIMEProfile);
+ if (!rvProfile) {
+ goto loser;
+ }
+ rvProfile->object = *object;
+ rvProfile->certificate = cert;
+ rvProfile->email = nssUTF8_Duplicate(cert->email, arena);
+ rvProfile->subject = nssItem_Duplicate(&cert->subject, arena, NULL);
+ if (profileTime) {
+ rvProfile->profileTime = nssItem_Duplicate(profileTime, arena, NULL);
+ }
+ if (profileData) {
+ rvProfile->profileData = nssItem_Duplicate(profileData, arena, NULL);
+ }
+ return rvProfile;
+loser:
+ if (object)
+ nssPKIObject_Destroy(object);
+ else if (arena)
+ nssArena_Destroy(arena);
+ return (nssSMIMEProfile *)NULL;
+}
+
+/* execute a callback function on all members of a cert list */
+NSS_EXTERN PRStatus
+nssCertificateList_DoCallback(
+ nssList *certList,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg)
+{
+ nssListIterator *certs;
+ NSSCertificate *cert;
+ certs = nssList_CreateIterator(certList);
+ if (!certs) {
+ return PR_FAILURE;
+ }
+ for (cert = (NSSCertificate *)nssListIterator_Start(certs);
+ cert != (NSSCertificate *)NULL;
+ cert = (NSSCertificate *)nssListIterator_Next(certs)) {
+ (void)(*callback)(cert, arg);
+ }
+ nssListIterator_Finish(certs);
+ nssListIterator_Destroy(certs);
+ return PR_SUCCESS;
+}
+
+static PRStatus
+add_ref_callback(NSSCertificate *c, void *a)
+{
+ nssCertificate_AddRef(c);
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT void
+nssCertificateList_AddReferences(
+ nssList *certList)
+{
+ (void)nssCertificateList_DoCallback(certList, add_ref_callback, NULL);
+}
+
+/*
+ * Is this trust record safe to apply to all certs of the same issuer/SN
+ * independent of the cert matching the hash. This is only true is the trust
+ * is unknown or distrusted. In general this feature is only useful to
+ * explicitly distrusting certs. It is not safe to use to trust certs, so
+ * only allow unknown and untrusted trust types.
+ */
+PRBool
+nssTrust_IsSafeToIgnoreCertHash(nssTrustLevel serverAuth,
+ nssTrustLevel clientAuth, nssTrustLevel codeSigning,
+ nssTrustLevel email, PRBool stepup)
+{
+ /* step up is a trust type, if it's on, we must have a hash for the cert */
+ if (stepup) {
+ return PR_FALSE;
+ }
+ if ((serverAuth != nssTrustLevel_Unknown) &&
+ (serverAuth != nssTrustLevel_NotTrusted)) {
+ return PR_FALSE;
+ }
+ if ((clientAuth != nssTrustLevel_Unknown) &&
+ (clientAuth != nssTrustLevel_NotTrusted)) {
+ return PR_FALSE;
+ }
+ if ((codeSigning != nssTrustLevel_Unknown) &&
+ (codeSigning != nssTrustLevel_NotTrusted)) {
+ return PR_FALSE;
+ }
+ if ((email != nssTrustLevel_Unknown) &&
+ (email != nssTrustLevel_NotTrusted)) {
+ return PR_FALSE;
+ }
+ /* record only has Unknown and Untrusted entries, ok to accept without a
+ * hash */
+ return PR_TRUE;
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssTrust_Create(
+ nssPKIObject *object,
+ NSSItem *certData)
+{
+ PRStatus status;
+ PRUint32 i;
+ PRUint32 lastTrustOrder, myTrustOrder;
+ unsigned char sha1_hashcmp[SHA1_LENGTH];
+ unsigned char sha1_hashin[SHA1_LENGTH];
+ NSSItem sha1_hash;
+ NSSTrust *rvt;
+ nssCryptokiObject *instance;
+ nssTrustLevel serverAuth, clientAuth, codeSigning, emailProtection;
+ SECStatus rv; /* Should be stan flavor */
+ PRBool stepUp;
+
+ lastTrustOrder = 1 << 16; /* just make it big */
+ PR_ASSERT(object->instances != NULL && object->numInstances > 0);
+ rvt = nss_ZNEW(object->arena, NSSTrust);
+ if (!rvt) {
+ return (NSSTrust *)NULL;
+ }
+ rvt->object = *object;
+
+ /* should be stan flavor of Hashbuf */
+ rv = PK11_HashBuf(SEC_OID_SHA1, sha1_hashcmp, certData->data, certData->size);
+ if (rv != SECSuccess) {
+ return (NSSTrust *)NULL;
+ }
+ sha1_hash.data = sha1_hashin;
+ sha1_hash.size = sizeof(sha1_hashin);
+ /* trust has to peek into the base object members */
+ nssPKIObject_Lock(object);
+ for (i = 0; i < object->numInstances; i++) {
+ instance = object->instances[i];
+ myTrustOrder = nssToken_GetTrustOrder(instance->token);
+ status = nssCryptokiTrust_GetAttributes(instance, NULL,
+ &sha1_hash,
+ &serverAuth,
+ &clientAuth,
+ &codeSigning,
+ &emailProtection,
+ &stepUp);
+ if (status != PR_SUCCESS) {
+ nssPKIObject_Unlock(object);
+ return (NSSTrust *)NULL;
+ }
+ /* if no hash is specified, then trust applies to all certs with
+ * this issuer/SN. NOTE: This is only true for entries that
+ * have distrust and unknown record */
+ if (!(
+ /* we continue if there is no hash, and the trust type is
+ * safe to accept without a hash ... or ... */
+ ((sha1_hash.size == 0) &&
+ nssTrust_IsSafeToIgnoreCertHash(serverAuth, clientAuth,
+ codeSigning, emailProtection,
+ stepUp)) ||
+ /* we have a hash of the correct size, and it matches */
+ ((sha1_hash.size == SHA1_LENGTH) && (PORT_Memcmp(sha1_hashin,
+ sha1_hashcmp,
+ SHA1_LENGTH) == 0)))) {
+ nssPKIObject_Unlock(object);
+ return (NSSTrust *)NULL;
+ }
+ if (rvt->serverAuth == nssTrustLevel_Unknown ||
+ myTrustOrder < lastTrustOrder) {
+ rvt->serverAuth = serverAuth;
+ }
+ if (rvt->clientAuth == nssTrustLevel_Unknown ||
+ myTrustOrder < lastTrustOrder) {
+ rvt->clientAuth = clientAuth;
+ }
+ if (rvt->emailProtection == nssTrustLevel_Unknown ||
+ myTrustOrder < lastTrustOrder) {
+ rvt->emailProtection = emailProtection;
+ }
+ if (rvt->codeSigning == nssTrustLevel_Unknown ||
+ myTrustOrder < lastTrustOrder) {
+ rvt->codeSigning = codeSigning;
+ }
+ rvt->stepUpApproved = stepUp;
+ lastTrustOrder = myTrustOrder;
+ }
+ nssPKIObject_Unlock(object);
+ return rvt;
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssTrust_AddRef(NSSTrust *trust)
+{
+ if (trust) {
+ nssPKIObject_AddRef(&trust->object);
+ }
+ return trust;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTrust_Destroy(NSSTrust *trust)
+{
+ if (trust) {
+ (void)nssPKIObject_Destroy(&trust->object);
+ }
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT nssSMIMEProfile *
+nssSMIMEProfile_AddRef(nssSMIMEProfile *profile)
+{
+ if (profile) {
+ nssPKIObject_AddRef(&profile->object);
+ }
+ return profile;
+}
+
+NSS_IMPLEMENT PRStatus
+nssSMIMEProfile_Destroy(nssSMIMEProfile *profile)
+{
+ if (profile) {
+ (void)nssPKIObject_Destroy(&profile->object);
+ }
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT NSSCRL *
+nssCRL_Create(nssPKIObject *object)
+{
+ PRStatus status;
+ NSSCRL *rvCRL;
+ NSSArena *arena = object->arena;
+ PR_ASSERT(object->instances != NULL && object->numInstances > 0);
+ rvCRL = nss_ZNEW(arena, NSSCRL);
+ if (!rvCRL) {
+ return (NSSCRL *)NULL;
+ }
+ rvCRL->object = *object;
+ /* XXX should choose instance based on some criteria */
+ status = nssCryptokiCRL_GetAttributes(object->instances[0],
+ NULL, /* XXX sessionOpt */
+ arena,
+ &rvCRL->encoding,
+ NULL, /* subject */
+ NULL, /* class */
+ &rvCRL->url,
+ &rvCRL->isKRL);
+ if (status != PR_SUCCESS) {
+ if (!arena) {
+ nssPKIObject_Destroy((nssPKIObject *)rvCRL);
+ }
+ return (NSSCRL *)NULL;
+ }
+ return rvCRL;
+}
+
+NSS_IMPLEMENT NSSCRL *
+nssCRL_AddRef(NSSCRL *crl)
+{
+ if (crl) {
+ nssPKIObject_AddRef(&crl->object);
+ }
+ return crl;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCRL_Destroy(NSSCRL *crl)
+{
+ if (crl) {
+ (void)nssPKIObject_Destroy(&crl->object);
+ }
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCRL_DeleteStoredObject(
+ NSSCRL *crl,
+ NSSCallback *uhh)
+{
+ return nssPKIObject_DeleteStoredObject(&crl->object, uhh, PR_TRUE);
+}
+
+NSS_IMPLEMENT NSSDER *
+nssCRL_GetEncoding(NSSCRL *crl)
+{
+ if (crl && crl->encoding.data != NULL && crl->encoding.size > 0) {
+ return &crl->encoding;
+ } else {
+ return (NSSDER *)NULL;
+ }
+}
diff --git a/security/nss/lib/pki/cryptocontext.c b/security/nss/lib/pki/cryptocontext.c
new file mode 100644
index 0000000000..52a0cf5312
--- /dev/null
+++ b/security/nss/lib/pki/cryptocontext.c
@@ -0,0 +1,914 @@
+/* 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 DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#ifndef PKISTORE_H
+#include "pkistore.h"
+#endif /* PKISTORE_H */
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
+
+NSS_IMPLEMENT NSSCryptoContext *
+nssCryptoContext_Create(
+ NSSTrustDomain *td,
+ NSSCallback *uhhOpt)
+{
+ NSSArena *arena;
+ NSSCryptoContext *rvCC;
+ arena = NSSArena_Create();
+ if (!arena) {
+ return NULL;
+ }
+ rvCC = nss_ZNEW(arena, NSSCryptoContext);
+ if (!rvCC) {
+ return NULL;
+ }
+ rvCC->td = td;
+ rvCC->arena = arena;
+ rvCC->certStore = nssCertificateStore_Create(rvCC->arena);
+ if (!rvCC->certStore) {
+ nssArena_Destroy(arena);
+ return NULL;
+ }
+
+ return rvCC;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_Destroy(NSSCryptoContext *cc)
+{
+ PRStatus status = PR_SUCCESS;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc) {
+ return PR_FAILURE;
+ }
+ if (cc->certStore) {
+ status = nssCertificateStore_Destroy(cc->certStore);
+ if (status == PR_FAILURE) {
+ return status;
+ }
+ } else {
+ status = PR_FAILURE;
+ }
+ nssArena_Destroy(cc->arena);
+ return status;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_SetDefaultCallback(
+ NSSCryptoContext *td,
+ NSSCallback *newCallback,
+ NSSCallback **oldCallbackOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSCallback *
+NSSCryptoContext_GetDefaultCallback(
+ NSSCryptoContext *td,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSCryptoContext_GetTrustDomain(NSSCryptoContext *td)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindOrImportCertificate(
+ NSSCryptoContext *cc,
+ NSSCertificate *c)
+{
+ NSSCertificate *rvCert = NULL;
+
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+ return rvCert;
+ }
+ rvCert = nssCertificateStore_FindOrAdd(cc->certStore, c);
+ if (rvCert == c && c->object.cryptoContext != cc) {
+ PORT_Assert(!c->object.cryptoContext);
+ c->object.cryptoContext = cc;
+ }
+ if (rvCert) {
+ /* an NSSCertificate cannot be part of two crypto contexts
+ ** simultaneously. If this assertion fails, then there is
+ ** a serious Stan design flaw.
+ */
+ PORT_Assert(cc == c->object.cryptoContext);
+ }
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_ImportPKIXCertificate(
+ NSSCryptoContext *cc,
+ struct NSSPKIXCertificateStr *pc)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_ImportEncodedCertificate(
+ NSSCryptoContext *cc,
+ NSSBER *ber)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ImportEncodedPKIXCertificateChain(
+ NSSCryptoContext *cc,
+ NSSBER *ber)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCryptoContext_ImportTrust(
+ NSSCryptoContext *cc,
+ NSSTrust *trust)
+{
+ PRStatus nssrv;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return PR_FAILURE;
+ }
+ nssrv = nssCertificateStore_AddTrust(cc->certStore, trust);
+#if 0
+ if (nssrv == PR_SUCCESS) {
+ trust->object.cryptoContext = cc;
+ }
+#endif
+ return nssrv;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCryptoContext_ImportSMIMEProfile(
+ NSSCryptoContext *cc,
+ nssSMIMEProfile *profile)
+{
+ PRStatus nssrv;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return PR_FAILURE;
+ }
+ nssrv = nssCertificateStore_AddSMIMEProfile(cc->certStore, profile);
+#if 0
+ if (nssrv == PR_SUCCESS) {
+ profile->object.cryptoContext = cc;
+ }
+#endif
+ return nssrv;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNickname(
+ NSSCryptoContext *cc,
+ const NSSUTF8 *name,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt /* NULL for none */
+)
+{
+ NSSCertificate **certs;
+ NSSCertificate *rvCert = NULL;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ certs = nssCertificateStore_FindCertificatesByNickname(cc->certStore,
+ name,
+ NULL, 0, NULL);
+ if (certs) {
+ rvCert = nssCertificateArray_FindBestCertificate(certs,
+ timeOpt,
+ usage,
+ policiesOpt);
+ nssCertificateArray_Destroy(certs);
+ }
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesByNickname(
+ NSSCryptoContext *cc,
+ NSSUTF8 *name,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ NSSCertificate **rvCerts;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ rvCerts = nssCertificateStore_FindCertificatesByNickname(cc->certStore,
+ name,
+ rvOpt,
+ maximumOpt,
+ arenaOpt);
+ return rvCerts;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(
+ NSSCryptoContext *cc,
+ NSSDER *issuer,
+ NSSDER *serialNumber)
+{
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ return nssCertificateStore_FindCertificateByIssuerAndSerialNumber(
+ cc->certStore,
+ issuer,
+ serialNumber);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateBySubject(
+ NSSCryptoContext *cc,
+ NSSDER *subject,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ NSSCertificate **certs;
+ NSSCertificate *rvCert = NULL;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ certs = nssCertificateStore_FindCertificatesBySubject(cc->certStore,
+ subject,
+ NULL, 0, NULL);
+ if (certs) {
+ rvCert = nssCertificateArray_FindBestCertificate(certs,
+ timeOpt,
+ usage,
+ policiesOpt);
+ nssCertificateArray_Destroy(certs);
+ }
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssCryptoContext_FindCertificatesBySubject(
+ NSSCryptoContext *cc,
+ NSSDER *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ NSSCertificate **rvCerts;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ rvCerts = nssCertificateStore_FindCertificatesBySubject(cc->certStore,
+ subject,
+ rvOpt,
+ maximumOpt,
+ arenaOpt);
+ return rvCerts;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesBySubject(
+ NSSCryptoContext *cc,
+ NSSDER *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ return nssCryptoContext_FindCertificatesBySubject(cc, subject,
+ rvOpt, maximumOpt,
+ arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNameComponents(
+ NSSCryptoContext *cc,
+ NSSUTF8 *nameComponents,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesByNameComponents(
+ NSSCryptoContext *cc,
+ NSSUTF8 *nameComponents,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindCertificateByEncodedCertificate(
+ NSSCryptoContext *cc,
+ NSSBER *encodedCertificate)
+{
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ return nssCertificateStore_FindCertificateByEncodedCertificate(
+ cc->certStore,
+ encodedCertificate);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestCertificateByEmail(
+ NSSCryptoContext *cc,
+ NSSASCII7 *email,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ NSSCertificate **certs;
+ NSSCertificate *rvCert = NULL;
+
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ certs = nssCertificateStore_FindCertificatesByEmail(cc->certStore,
+ email,
+ NULL, 0, NULL);
+ if (certs) {
+ rvCert = nssCertificateArray_FindBestCertificate(certs,
+ timeOpt,
+ usage,
+ policiesOpt);
+ nssCertificateArray_Destroy(certs);
+ }
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindCertificatesByEmail(
+ NSSCryptoContext *cc,
+ NSSASCII7 *email,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ NSSCertificate **rvCerts;
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ rvCerts = nssCertificateStore_FindCertificatesByEmail(cc->certStore,
+ email,
+ rvOpt,
+ maximumOpt,
+ arenaOpt);
+ return rvCerts;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindCertificateByOCSPHash(
+ NSSCryptoContext *cc,
+ NSSItem *hash)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestUserCertificate(
+ NSSCryptoContext *cc,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindUserCertificates(
+ NSSCryptoContext *cc,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForSSLClientAuth(
+ NSSCryptoContext *cc,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSCryptoContext_FindUserCertificatesForSSLClientAuth(
+ NSSCryptoContext *cc,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForEmailSigning(
+ NSSCryptoContext *cc,
+ NSSASCII7 *signerOpt,
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSCryptoContext_FindUserCertificatesForEmailSigning(
+ NSSCryptoContext *cc,
+ NSSASCII7 *signerOpt, /* fgmr or a more general name? */
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssCryptoContext_FindTrustForCertificate(
+ NSSCryptoContext *cc,
+ NSSCertificate *cert)
+{
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ return nssCertificateStore_FindTrustForCertificate(cc->certStore, cert);
+}
+
+NSS_IMPLEMENT nssSMIMEProfile *
+nssCryptoContext_FindSMIMEProfileForCertificate(
+ NSSCryptoContext *cc,
+ NSSCertificate *cert)
+{
+ PORT_Assert(cc && cc->certStore);
+ if (!cc || !cc->certStore) {
+ return NULL;
+ }
+ return nssCertificateStore_FindSMIMEProfileForCertificate(cc->certStore,
+ cert);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_GenerateKeyPair(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *ap,
+ NSSPrivateKey **pvkOpt,
+ NSSPublicKey **pbkOpt,
+ PRBool privateKeyIsSensitive,
+ NSSToken *destination,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *ap,
+ PRUint32 keysize,
+ NSSToken *destination,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKeyFromPassword(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *ap,
+ NSSUTF8 *passwordOpt, /* if null, prompt */
+ NSSToken *destinationOpt,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_FindSymmetricKeyByAlgorithmAndKeyID(
+ NSSCryptoContext *cc,
+ NSSOID *algorithm,
+ NSSItem *keyID,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+struct token_session_str {
+ NSSToken *token;
+ nssSession *session;
+};
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Decrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *encryptedData,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginDecrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueDecrypt(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishDecrypt(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Sign(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginSign(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ContinueSign(
+ NSSCryptoContext *cc,
+ NSSItem *data)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishSign(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_SignRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginSignRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueSignRecover(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishSignRecover(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_UnwrapSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSCryptoContext_DeriveSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt, /* zero for best allowed */
+ NSSOperations operations,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Encrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginEncrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueEncrypt(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishEncrypt(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_Verify(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginVerify(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ContinueVerify(
+ NSSCryptoContext *cc,
+ NSSItem *data)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_FinishVerify(
+ NSSCryptoContext *cc)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_VerifyRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginVerifyRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_ContinueVerifyRecover(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishVerifyRecover(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_WrapSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_Digest(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ return nssToken_Digest(cc->token, cc->session, apOpt,
+ data, rvOpt, arenaOpt);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_BeginDigest(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt)
+{
+ return nssToken_BeginDigest(cc->token, cc->session, apOpt);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSCryptoContext_ContinueDigest(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *item)
+{
+ /*
+ NSSAlgorithmAndParameters *ap;
+ ap = (apOpt) ? apOpt : cc->ap;
+ */
+ /* why apOpt? can't change it at this point... */
+ return nssToken_ContinueDigest(cc->token, cc->session, item);
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSCryptoContext_FinishDigest(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ return nssToken_FinishDigest(cc->token, cc->session, rvOpt, arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSCryptoContext_Clone(NSSCryptoContext *cc)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
diff --git a/security/nss/lib/pki/doc/standiag.png b/security/nss/lib/pki/doc/standiag.png
new file mode 100644
index 0000000000..fe1aca389a
--- /dev/null
+++ b/security/nss/lib/pki/doc/standiag.png
Binary files differ
diff --git a/security/nss/lib/pki/doc/standoc.html b/security/nss/lib/pki/doc/standoc.html
new file mode 100644
index 0000000000..2e110fcbef
--- /dev/null
+++ b/security/nss/lib/pki/doc/standoc.html
@@ -0,0 +1,442 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<!-- 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/. -->
+
+
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ <title>Stan Design - Work In Progress</title>
+</head>
+ <body>
+ <br>
+ This is a working document for progress on Stan design/development.<br>
+ <br>
+ Current <a href="#build">build</a>
+ and <a href="#test">test</a>
+ instructions.<br>
+ <br>
+ The current set of Stan libraries.<br>
+ <a href="#asn1">asn1</a>
+ <br>
+ <a href="#base">base</a>
+ <br>
+ <a href="#ckfw">ckfw</a>
+ <br>
+ <a href="#dev">dev</a>
+ <br>
+ <a href="#pki">pki</a>
+ <br>
+ <a href="#pki1">pki1</a>
+ <br>
+ <a href="#pkix">pkix</a>
+ <br>
+ <br>
+ "Public" types below (those available to consumers of
+ NSS) begin with "NSS". &nbsp;"Protected" types (those only available
+ within NSS) begin with "nss".<br>
+ <br>
+ Open issues appears as numbered indents.<br>
+ <br>
+ <br>
+
+<hr width="100%" size="2" align="Left"><br>
+
+<h3><a name="asn1"></a>
+ <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/asn1/">
+ ASN.1</a>
+ </h3>
+ ASN.1 encoder/decoder wrapping around the current
+ ASN.1 implementation.<br>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSASN1EncodingType"> NSSASN1EncodingType</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1Item">nssASN1Item</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1Template">nssASN1Template</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1ChooseTemplateFunction">
+ nssASN1ChooseTemplateFunction</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1Encoder">nssASN1Encoder</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1Decoder">nssASN1Decoder</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1EncodingPart"> nssASN1EncodingPart</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1NotifyFunction">
+ nssASN1NotifyFunction</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1EncoderWriteFunction">
+ nssASN1EncoderWriteFunction</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssASN1DecoderFilterFunction">
+ nssASN1DecoderFilterFunction</a>
+ <br>
+ <br>
+
+<hr width="100%" size="2" align="Left">
+<h3><a name="base"></a>
+ <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/base/">
+ Base</a>
+ </h3>
+ Set of base utilities for Stan implementation.
+&nbsp;These are all fairly straightforward, except for nssPointerTracker.<br>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSError">NSSError</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSArena">NSSArena</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSItem">NSSItem</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSBER">NSSBER</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSDER">NSSDER</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSBitString">NSSBitString</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSUTF8">NSSUTF8</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSASCII7">NSSASCII7</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssArenaMark">nssArenaMark</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssPointerTracker">nssPointerTracker</a>
+ <br>
+ This is intended for debug builds only.<br>
+
+<ol>
+ <li>Ignored for now.<br>
+ </li>
+
+</ol>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssStringType">nssStringType</a>
+ <br>
+ <br>
+ Suggested additions:<br>
+
+<ol>
+ <li>nssList - A list that optionally uses a lock. &nbsp;This list would
+ manage the currently loaded modules in a trust domain, etc.</li>
+
+ <ul>
+ <li>SECMODListLock kept track of the number of waiting threads. &nbsp;Will
+ this be needed in the trust domain?</li>
+
+ </ul>
+
+</ol>
+ <br>
+
+<hr width="100%" size="2" align="Left">
+<h3><a name="ckfw"></a>
+ <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/">
+ CKFW</a>
+ </h3>
+ The cryptoki framework, used for building cryptoki tokens.
+ &nbsp;This needs to be described in a separate document showing how
+ to set up a token using CKFW. &nbsp;This code only relates to tokens,
+ so it is not relevant here.<br>
+ <br>
+ <br>
+
+<hr width="100%" size="2" align="Left">
+<h3><a name="dev"></a>
+ <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/dev/">
+ Device</a>
+ </h3>
+ Defines cryptoki devices used in NSS. &nbsp;This
+ is not part of the exposed API. &nbsp;It is a low-level API allowing
+NSS to manage cryptoki devices.<br>
+ <br>
+ The relationship is like this:<br>
+ <br>
+ libpki --&gt; libdev --&gt; cryptoki<br>
+ <br>
+ As an example,<br>
+ <br>
+ NSSTrustDomain_FindCertificate --&gt; NSSToken_FindCertificate --&gt;
+ C_FindObjects<br>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSModule">NSSModule</a>
+ <br>
+ Replaces the SECMOD API. &nbsp;The module manages a
+PRLibrary that holds a cryptoki implementation via a number of slots.
+&nbsp;The API should provide the ability to Load and Unload a module,
+Login and Logout to the module (through its slots), and to locate a
+particular slot/token.<br>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSSlot">NSSSlot</a>
+ <br>
+ This and NSSToken combine to replace the PK11 API parts
+ that relate to slot and token management. &nbsp;The slot API should
+ provide the ability to Login/Logout to a slot, check the login status,
+ determine basic configuration information about the slot, and modify
+ the password settings.<br>
+
+<ol>
+ <li>Should slots also maintain a default session? &nbsp;This session would
+ be used for slot management calls (sections 9.5 and9.6 of PKCS#11). &nbsp;Or
+ is the token session sufficient (this would not work if C_GetTokenInfo and
+ C_InitToken need to be wrapped in a threadsafe session).<br>
+ </li>
+
+</ol>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSToken">NSSToken</a>
+ <br>
+ Fills in the gaps left by NSSSlot. &nbsp;Much of the
+cryptoki API is directed towards slots. &nbsp;However, some functionality
+ clearly belongs with a token type. &nbsp;For example, a certificate
+ lives on a token, not a slot, so one would expect a function NSSToken_FindCertificate.
+ &nbsp;Thus functions that deal with importing/exporting an object
+and performing actual cryptographic operations belong here.<br>
+
+<ol>
+ <li>The distinction between a slot and a token is not clear. &nbsp;Most
+ functions take a slotID as an argument, even though it is obvious that
+ the event is intended to occur on a token. &nbsp;That leaves various
+ possibilities:</li>
+
+ <ol>
+ <li>Implement the API entirely as NSSToken. &nbsp;If the token is not
+ present, some calls will simply fail.</li>
+ <li>Divide the API between NSSToken and NSSSlot, as described above.
+&nbsp;NSSSlot would handle cryptoki calls specified as "slot management",
+ while NSSToken handles actual token operations.</li>
+ <li>Others?</li>
+
+ </ol>
+ <li>Session management. &nbsp;Tokens needs a threadsafe session handle
+ to perform operations. &nbsp;CryptoContexts are meant to provide such sessions,
+ but other objects will need access to token functions as well (examples:
+the TrustDomain_Find functions, _Login, _Logout, and others that do not exist
+ such as NSSToken_ChangePassword). &nbsp;For those functions, the token could
+ maintain a default session. &nbsp;Thus all NSSToken API functions would take
+ sessionOpt as an argument. &nbsp;If the caller is going to provide a session,
+ it sends an NSSSession there, otherwise it sends NULL and the default session
+ is utilized.<br>
+ </li>
+
+</ol>
+ Proposed:<br>
+ NSSSession<br>
+ Wraps a Cryptoki session. &nbsp;Created from a slot. &nbsp;Used to manage
+ sessions for crypto contexts. &nbsp;Has a lock field, which locks the session
+ if the slot is not threadsafe.<br>
+ <br>
+
+<hr width="100%" size="2" align="Left"><br>
+
+<h3><a name="pki"></a>
+ <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/pki/">
+ PKI</a>
+ </h3>
+ The NSS PKI library.<br>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSCertificate">NSS</a>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSCertificate">Certificate</a>
+ <br>
+
+<ol>
+ <li>The API leaves open the possibility of NSSCertificate meaning various
+ certificate types, not just X.509. &nbsp;The way to keep open this possibility
+ is to keep only generally useful information in the NSSCertificate type.
+&nbsp;Examples would be the certificate encoding, label, trust (obtained
+ from cryptoki calls), an email address, etc. &nbsp;Some type of generic
+reference should be kept to the decoded certificate, which would then be
+accessed by a type-specific API (e.g., NSSX509_GetSubjectName).</li>
+
+</ol>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSUserCertificate">NSSUserCertificate</a>
+ <br>
+
+<ol>
+ <li>Should this be a typedef of NSSCertificate?&nbsp; This implies that
+ any function that requires an NSSUserCertificate would fail when called
+ with a certificate lacking a private key. </li>
+
+</ol>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSPrivateKey">NSSPrivateKey</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSPublicKey">NSSPublicKey</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSSymmetricKey">NSSSymmetricKey</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSTrustDomain">NSSTrustDomain</a>
+ <br>
+ A trust domain is "the field in which certificates may
+ be validated." &nbsp;It is a collection of modules capable of performing
+ cryptographic operations and storing certs and keys. &nbsp;This collection
+ is managed by NSS in a manner opaque to the consumer. &nbsp;The slots
+ will have various orderings determining which has preference for a
+given operation. &nbsp;For example, the trust domain may order the storage
+ of user certificates one way, and the storage of email certificates in
+ another way [is that a good example?].<br>
+ <br>
+
+<ol>
+ <li> How will ordering work? &nbsp;We already have the suggestion
+ that there be two kinds of ordering: storage and search. &nbsp;How
+will they be constructed/managed? &nbsp;Do we want to expose access
+to a token that overrides this ordering (i.e., the download of updated
+root certs may need to override storage order)</li>
+ <li>How are certs cached? &nbsp;Nelson wonders what it means to Stan
+ when a cert does not live on a token yet. &nbsp;Bob, Terry, and I discussed
+ this. &nbsp;My conclusion is that there should be a type, separate
+from NSSCertificate, that holds the decoded cert parts (e.g., NSSX509Certificate,
+ or to avoid confusion, NSSX509DecodedParts). &nbsp;NSSCertificate would
+ keep a handle to this type, so that it only needs to decode the cert
+once. &nbsp;The NSSTrustDomain would keep a hash table of cached certs,
+some of which may not live on a token yet (i.e., they are only NSSX509DecodedParts).
+ &nbsp;This cache could be accessed in the same way the temp db was,
+and when the cert is ready to be moved onto a token a call to NSSTrustDomain_ImportCertificate
+ is made. &nbsp;Note that this is essentially the same as CERT_TempCertToPerm.</li>
+
+ <ul>
+ <li>The hashtable in lib/base (copied from ckfw/hash.c) uses the identity
+hash. &nbsp;Therefore, in a hash of certificates, the key is the certificate
+pointer itself. &nbsp;One possibility is to store the decoded cert (NSSX509DecodedParts
+above) as the value in the {key, value} pair. &nbsp;When a cert is decoded,
+the cert pointer and decoding pointer are added to the hash. &nbsp;Subsequent
+lookups have access to one or both of these pointers. &nbsp;This keeps NSSCertificate
+separate from its decoding, while providing a way to locate it.</li>
+
+ </ul>
+ <li>The API is designed to keep token details hidden from the user. &nbsp;However,
+ it has already been realized that PSM and CMS may need special access to
+tokens. &nbsp;Is this part of the TrustDomain API, or should PSM and CMS
+be allowed to use "friend" headers from the Token API?</li>
+ <li>Do we want to allow traversal via NSSTrustDomain_TraverseXXXX?<br>
+ </li>
+
+</ol>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSCryptoContext"><br>
+ NSSCryptoContext</a>
+ <br>
+ Analgous to a Cryptoki session. &nbsp;Manages session objects only.<br>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSTime">NSSTime</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSUsage">NSSUsage</a>
+ <br>
+
+<ol>
+ <li> See Fred's <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/pki/nsspkit.h#187">
+ comments</a>
+ .</li>
+
+</ol>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSPolicies">NSSPolicies</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSAlgorithmAndParameters">
+ NSSAlgorithmAndParameters</a>
+ <br>
+
+<ol>
+ <li> Again, Fred's <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/pki/nsspkit.h#215">
+ comments</a>
+ . &nbsp;The old NSS code had various types related to algorithms
+ running around in it. &nbsp;We had SECOidTag, SECAlgorithmID, SECItem's
+ for parameters, CK_MECHANISM for cryptoki, etc. &nbsp;This type should
+ be able to encapsulate all of those.</li>
+
+</ol>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSCallback">NSSCallback</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSOperations">NSSOperations</a>
+ <br>
+ <br>
+ <br>
+
+<hr width="100%" size="2"><br>
+ <br>
+ A diagram to suggest a possible TrustDomain architecture.<br>
+ <br>
+ <img src="./standiag.png" alt="Trust Domain Diagram" width="748" height="367">
+ <br>
+
+<hr width="100%" size="2" align="Left"><br>
+
+<h3><a name="pki1"></a>
+ <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/pki1/">
+ PKI1</a>
+ </h3>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSOID">NSSOID</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSATAV">NSSATAV</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSRDN">NSSRDN</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSRDNSeq">NSSRDNSeq</a>
+ <br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSName">NSSName</a>
+ <br>
+ NSSNameChoice<br>
+ NSSGeneralName<br>
+ NSSGeneralNameChoice<br>
+ NSSOtherName<br>
+ NSSRFC822Name<br>
+ NSSDNSName<br>
+ NSSX400Address<br>
+ NSSEdiParityAddress<br>
+ NSSURI<br>
+ NSSIPAddress<br>
+ NSSRegisteredID<br>
+ NSSGeneralNameSeq<br>
+ <a href="http://lxr.mozilla.org/mozilla/ident?i=nssAttributeTypeAliasTable">
+ nssAttributeTypeAliasTable</a>
+ <br>
+ <br>
+ <br>
+
+<hr width="100%" size="2" align="Left"><br>
+
+<h3><a name="pkix"></a>
+ <a href="http://lxr.mozilla.org/mozilla/source/security/nss/lib/pkix/">
+ PKIX&nbsp;</a>
+ </h3>
+ There is a plethora of PKIX related types here.<br>
+ <br>
+
+<hr width="100%" size="2" align="Left"><br>
+
+<h3><a name="build"></a>
+ Building Stan</h3>
+ <br>
+ From nss/lib, run "make BUILD_STAN=1"<br>
+ <br>
+
+<hr width="100%" size="2" align="Left"><br>
+
+<h3><a name="test"></a>
+ Testing Stan</h3>
+ A&nbsp;new command line tool, pkiutil, has been created to use only
+ the Stan API. &nbsp;It depends on a new library, cmdlib, meant to replace
+ the old secutil library. &nbsp;The old library had code used by products
+ that needed to be integrated into the main library codebase somehow. &nbsp;The
+ goal of the new cmdlib is to have functionality needed strictly for NSS
+ tools.<br>
+ <br>
+ How to build:<br>
+
+<ol>
+ <li>cd nss/cmd/cmdlib; make</li>
+ <li>cd ../pkiutil; make</li>
+
+</ol>
+ pkiutil will give detailed help with either "pkiutil -?" or "pkiutil
+ --help".<br>
+ <br>
+ So far, the only available test is to list certs on the builtins token.
+ &nbsp;Copy "libnssckbi.so" (or whatever it is) to cmd/pkiutil. &nbsp;Then
+ run "pkiutil -L" or "pkiutil --list". &nbsp;The list of certificate nicknames
+ should be displayed.<br>
+ <br>
+ <br>
+
+</body>
+</html>
diff --git a/security/nss/lib/pki/exports.gyp b/security/nss/lib/pki/exports.gyp
new file mode 100644
index 0000000000..a9707ae16c
--- /dev/null
+++ b/security/nss/lib/pki/exports.gyp
@@ -0,0 +1,32 @@
+# 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/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_pki_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'nsspki.h',
+ 'nsspkit.h',
+ 'pki.h',
+ 'pki3hack.h',
+ 'pkim.h',
+ 'pkistore.h',
+ 'pkit.h',
+ 'pkitm.h'
+ ],
+ 'destination': '<(nss_private_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/pki/manifest.mn b/security/nss/lib/pki/manifest.mn
new file mode 100644
index 0000000000..98af6b8a7d
--- /dev/null
+++ b/security/nss/lib/pki/manifest.mn
@@ -0,0 +1,42 @@
+#
+# 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/.
+
+CORE_DEPTH = ../..
+
+PRIVATE_EXPORTS = \
+ pki.h \
+ pkit.h \
+ nsspkit.h \
+ nsspki.h \
+ pkistore.h \
+ pki3hack.h \
+ pkitm.h \
+ pkim.h \
+ $(NULL)
+
+MODULE = nss
+
+CSRCS = \
+ asymmkey.c \
+ certificate.c \
+ cryptocontext.c \
+ symmkey.c \
+ trustdomain.c \
+ tdcache.c \
+ certdecode.c \
+ pkistore.c \
+ pkibase.c \
+ pki3hack.c \
+ $(NULL)
+
+#DEFINES = -DDEBUG_CACHE
+
+REQUIRES = nspr
+
+LIBRARY_NAME = nsspki
+SHARED_LIBRARY = $(NULL)
+
+# This part of the code, including all sub-dirs, can be optimized for size
+export ALLOW_OPT_CODE_SIZE = 1
diff --git a/security/nss/lib/pki/nsspki.h b/security/nss/lib/pki/nsspki.h
new file mode 100644
index 0000000000..f3c6e51684
--- /dev/null
+++ b/security/nss/lib/pki/nsspki.h
@@ -0,0 +1,2791 @@
+/* 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 NSSPKI_H
+#define NSSPKI_H
+
+/*
+ * nsspki.h
+ *
+ * This file prototypes the methods of the top-level PKI objects.
+ */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#include "pkcs11uri.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A note about interfaces
+ *
+ * Although these APIs are specified in C, a language which does
+ * not have fancy support for abstract interfaces, this library
+ * was designed from an object-oriented perspective. It may be
+ * useful to consider the standard interfaces which went into
+ * the writing of these APIs.
+ *
+ * Basic operations on all objects:
+ * Destroy -- free a pointer to an object
+ * DeleteStoredObject -- delete an object permanently
+ *
+ * Public Key cryptographic operations:
+ * Encrypt
+ * Verify
+ * VerifyRecover
+ * Wrap
+ * Derive
+ *
+ * Private Key cryptographic operations:
+ * IsStillPresent
+ * Decrypt
+ * Sign
+ * SignRecover
+ * Unwrap
+ * Derive
+ *
+ * Symmetric Key cryptographic operations:
+ * IsStillPresent
+ * Encrypt
+ * Decrypt
+ * Sign
+ * SignRecover
+ * Verify
+ * VerifyRecover
+ * Wrap
+ * Unwrap
+ * Derive
+ *
+ */
+
+/*
+ * NSSCertificate
+ *
+ * These things can do crypto ops like public keys, except that the trust,
+ * usage, and other constraints are checked. These objects are "high-level,"
+ * so trust, usages, etc. are in the form we throw around (client auth,
+ * email signing, etc.). Remember that theoretically another implementation
+ * (think PGP) could be beneath this object.
+ */
+
+/*
+ * NSSCertificate_Destroy
+ *
+ * Free a pointer to a certificate object.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_Destroy(NSSCertificate *c);
+
+/*
+ * NSSCertificate_DeleteStoredObject
+ *
+ * Permanently remove this certificate from storage. If this is the
+ * only (remaining) certificate corresponding to a private key,
+ * public key, and/or other object; then that object (those objects)
+ * are deleted too.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_DeleteStoredObject(
+ NSSCertificate *c,
+ NSSCallback *uhh);
+
+/*
+ * NSSCertificate_Validate
+ *
+ * Verify that this certificate is trusted, for the specified usage(s),
+ * at the specified time, {word word} the specified policies.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_Validate(
+ NSSCertificate *c,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/*
+ * NSSCertificate_ValidateCompletely
+ *
+ * Verify that this certificate is trusted. The difference between
+ * this and the previous call is that NSSCertificate_Validate merely
+ * returns success or failure with an appropriate error stack.
+ * However, there may be (and often are) multiple problems with a
+ * certificate. This routine returns an array of errors, specifying
+ * every problem.
+ */
+
+/*
+ * Return value must be an array of objects, each of which has
+ * an NSSError, and any corresponding certificate (in the chain)
+ * and/or policy.
+ */
+
+NSS_EXTERN void ** /* void *[] */
+NSSCertificate_ValidateCompletely(
+ NSSCertificate *c,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt, /* NULL for none */
+ void **rvOpt, /* NULL for allocate */
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt /* NULL for heap */
+);
+
+/*
+ * NSSCertificate_ValidateAndDiscoverUsagesAndPolicies
+ *
+ * Returns PR_SUCCESS if the certificate is valid for at least something.
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_ValidateAndDiscoverUsagesAndPolicies(
+ NSSCertificate *c,
+ NSSTime **notBeforeOutOpt,
+ NSSTime **notAfterOutOpt,
+ void *allowedUsages,
+ void *disallowedUsages,
+ void *allowedPolicies,
+ void *disallowedPolicies,
+ /* more args.. work on this fgmr */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCertificate_Encode
+ *
+ */
+
+NSS_EXTERN NSSDER *
+NSSCertificate_Encode(
+ NSSCertificate *c,
+ NSSDER *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCertificate_BuildChain
+ *
+ * This routine returns NSSCertificate *'s for each certificate
+ * in the "chain" starting from the specified one up to and
+ * including the root. The zeroth element in the array is the
+ * specified ("leaf") certificate.
+ *
+ * If statusOpt is supplied, and is returned as PR_FAILURE, possible
+ * error values are:
+ *
+ * NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND - the chain is incomplete
+ *
+ */
+
+extern const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND;
+
+NSS_EXTERN NSSCertificate **
+NSSCertificate_BuildChain(
+ NSSCertificate *c,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt,
+ PRStatus *statusOpt,
+ NSSTrustDomain *td,
+ NSSCryptoContext *cc);
+
+/*
+ * NSSCertificate_GetTrustDomain
+ *
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSCertificate_GetTrustDomain(NSSCertificate *c);
+
+/*
+ * NSSCertificate_GetToken
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSToken *
+NSSCertificate_GetToken(
+ NSSCertificate *c,
+ PRStatus *statusOpt);
+
+/*
+ * NSSCertificate_GetSlot
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSSlot *
+NSSCertificate_GetSlot(
+ NSSCertificate *c,
+ PRStatus *statusOpt);
+
+/*
+ * NSSCertificate_GetModule
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSModule *
+NSSCertificate_GetModule(
+ NSSCertificate *c,
+ PRStatus *statusOpt);
+
+/*
+ * NSSCertificate_Encrypt
+ *
+ * Encrypt a single chunk of data with the public key corresponding to
+ * this certificate.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCertificate_Encrypt(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCertificate_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCertificate_Verify(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh);
+
+/*
+ * NSSCertificate_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCertificate_VerifyRecover(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCertificate_WrapSymmetricKey
+ *
+ * This method tries very hard to to succeed, even in situations
+ * involving sensitive keys and multiple modules.
+ * { relyea: want to add verbiage? }
+ */
+
+NSS_EXTERN NSSItem *
+NSSCertificate_WrapSymmetricKey(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCertificate_CreateCryptoContext
+ *
+ * Create a crypto context, in this certificate's trust domain, with this
+ * as the distinguished certificate.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSCertificate_CreateCryptoContext(
+ NSSCertificate *c,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh);
+
+/*
+ * NSSCertificate_GetPublicKey
+ *
+ * Returns the public key corresponding to this certificate.
+ */
+
+NSS_EXTERN NSSPublicKey *
+NSSCertificate_GetPublicKey(NSSCertificate *c);
+
+/*
+ * NSSCertificate_FindPrivateKey
+ *
+ * Finds and returns the private key corresponding to this certificate,
+ * if it is available.
+ *
+ * { Should this hang off of NSSUserCertificate? }
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSCertificate_FindPrivateKey(
+ NSSCertificate *c,
+ NSSCallback *uhh);
+
+/*
+ * NSSCertificate_IsPrivateKeyAvailable
+ *
+ * Returns success if the private key corresponding to this certificate
+ * is available to be used.
+ *
+ * { Should *this* hang off of NSSUserCertificate?? }
+ */
+
+NSS_EXTERN PRBool
+NSSCertificate_IsPrivateKeyAvailable(
+ NSSCertificate *c,
+ NSSCallback *uhh,
+ PRStatus *statusOpt);
+
+/*
+ * If we make NSSUserCertificate not a typedef of NSSCertificate,
+ * then we'll need implementations of the following:
+ *
+ * NSSUserCertificate_Destroy
+ * NSSUserCertificate_DeleteStoredObject
+ * NSSUserCertificate_Validate
+ * NSSUserCertificate_ValidateCompletely
+ * NSSUserCertificate_ValidateAndDiscoverUsagesAndPolicies
+ * NSSUserCertificate_Encode
+ * NSSUserCertificate_BuildChain
+ * NSSUserCertificate_GetTrustDomain
+ * NSSUserCertificate_GetToken
+ * NSSUserCertificate_GetSlot
+ * NSSUserCertificate_GetModule
+ * NSSUserCertificate_GetCryptoContext
+ * NSSUserCertificate_GetPublicKey
+ */
+
+/*
+ * NSSUserCertificate_IsStillPresent
+ *
+ * Verify that if this certificate lives on a token, that the token
+ * is still present and the certificate still exists. This is a
+ * lightweight call which should be used whenever it should be
+ * verified that the user hasn't perhaps popped out his or her
+ * token and strolled away.
+ */
+
+NSS_EXTERN PRBool
+NSSUserCertificate_IsStillPresent(
+ NSSUserCertificate *uc,
+ PRStatus *statusOpt);
+
+/*
+ * NSSUserCertificate_Decrypt
+ *
+ * Decrypt a single chunk of data with the private key corresponding
+ * to this certificate.
+ */
+
+NSS_EXTERN NSSItem *
+NSSUserCertificate_Decrypt(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSUserCertificate_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSUserCertificate_Sign(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSUserCertificate_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSUserCertificate_SignRecover(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSUserCertificate_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSUserCertificate_UnwrapSymmetricKey(
+ NSSUserCertificate *uc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSUserCertificate_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSUserCertificate_DeriveSymmetricKey(
+ NSSUserCertificate *uc, /* provides private key */
+ NSSCertificate *c, /* provides public key */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt, /* zero for best allowed */
+ NSSOperations operations,
+ NSSCallback *uhh);
+
+/* filter-certs function(s) */
+
+/**
+ ** fgmr -- trust objects
+ **/
+
+/*
+ * NSSPrivateKey
+ *
+ */
+
+/*
+ * NSSPrivateKey_Destroy
+ *
+ * Free a pointer to a private key object.
+ */
+
+NSS_EXTERN PRStatus
+NSSPrivateKey_Destroy(NSSPrivateKey *vk);
+
+/*
+ * NSSPrivateKey_DeleteStoredObject
+ *
+ * Permanently remove this object, and any related objects (such as the
+ * certificates corresponding to this key).
+ */
+
+NSS_EXTERN PRStatus
+NSSPrivateKey_DeleteStoredObject(
+ NSSPrivateKey *vk,
+ NSSCallback *uhh);
+
+/*
+ * NSSPrivateKey_GetSignatureLength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSPrivateKey_GetSignatureLength(NSSPrivateKey *vk);
+
+/*
+ * NSSPrivateKey_GetPrivateModulusLength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSPrivateKey_GetPrivateModulusLength(NSSPrivateKey *vk);
+
+/*
+ * NSSPrivateKey_IsStillPresent
+ *
+ */
+
+NSS_EXTERN PRBool
+NSSPrivateKey_IsStillPresent(
+ NSSPrivateKey *vk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSPrivateKey_Encode
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_Encode(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *ap,
+ NSSItem *passwordOpt, /* NULL will cause a callback; "" for no password */
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPrivateKey_GetTrustDomain
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSPrivateKey_GetTrustDomain(
+ NSSPrivateKey *vk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSPrivateKey_GetToken
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSPrivateKey_GetToken(NSSPrivateKey *vk);
+
+/*
+ * NSSPrivateKey_GetSlot
+ *
+ */
+
+NSS_EXTERN NSSSlot *
+NSSPrivateKey_GetSlot(NSSPrivateKey *vk);
+
+/*
+ * NSSPrivateKey_GetModule
+ *
+ */
+
+NSS_EXTERN NSSModule *
+NSSPrivateKey_GetModule(NSSPrivateKey *vk);
+
+/*
+ * NSSPrivateKey_Decrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_Decrypt(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *encryptedData,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPrivateKey_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_Sign(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPrivateKey_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPrivateKey_SignRecover(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPrivateKey_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSPrivateKey_UnwrapSymmetricKey(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSCallback *uhh);
+
+/*
+ * NSSPrivateKey_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSPrivateKey_DeriveSymmetricKey(
+ NSSPrivateKey *vk,
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt, /* zero for best allowed */
+ NSSOperations operations,
+ NSSCallback *uhh);
+
+/*
+ * NSSPrivateKey_FindPublicKey
+ *
+ */
+
+NSS_EXTERN NSSPublicKey *
+NSSPrivateKey_FindPublicKey(
+ NSSPrivateKey *vk
+ /* { don't need the callback here, right? } */
+);
+
+/*
+ * NSSPrivateKey_CreateCryptoContext
+ *
+ * Create a crypto context, in this key's trust domain,
+ * with this as the distinguished private key.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSPrivateKey_CreateCryptoContext(
+ NSSPrivateKey *vk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhh);
+
+/*
+ * NSSPrivateKey_FindCertificates
+ *
+ * Note that there may be more than one certificate for this
+ * private key. { FilterCertificates function to further
+ * reduce the list. }
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSPrivateKey_FindCertificates(
+ NSSPrivateKey *vk,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPrivateKey_FindBestCertificate
+ *
+ * The parameters for this function will depend on what the users
+ * need. This is just a starting point.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSPrivateKey_FindBestCertificate(
+ NSSPrivateKey *vk,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSPublicKey
+ *
+ * Once you generate, find, or derive one of these, you can use it
+ * to perform (simple) cryptographic operations. Though there may
+ * be certificates associated with these public keys, they are not
+ * verified.
+ */
+
+/*
+ * NSSPublicKey_Destroy
+ *
+ * Free a pointer to a public key object.
+ */
+
+NSS_EXTERN PRStatus
+NSSPublicKey_Destroy(NSSPublicKey *bk);
+
+/*
+ * NSSPublicKey_DeleteStoredObject
+ *
+ * Permanently remove this object, and any related objects (such as the
+ * corresponding private keys and certificates).
+ */
+
+NSS_EXTERN PRStatus
+NSSPublicKey_DeleteStoredObject(
+ NSSPublicKey *bk,
+ NSSCallback *uhh);
+
+/*
+ * NSSPublicKey_Encode
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_Encode(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *ap,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPublicKey_GetTrustDomain
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSPublicKey_GetTrustDomain(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSPublicKey_GetToken
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSToken *
+NSSPublicKey_GetToken(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSPublicKey_GetSlot
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSSlot *
+NSSPublicKey_GetSlot(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSPublicKey_GetModule
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSModule *
+NSSPublicKey_GetModule(
+ NSSPublicKey *bk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSPublicKey_Encrypt
+ *
+ * Encrypt a single chunk of data with the public key corresponding to
+ * this certificate.
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_Encrypt(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPublicKey_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSPublicKey_Verify(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSCallback *uhh);
+
+/*
+ * NSSPublicKey_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_VerifyRecover(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPublicKey_WrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSPublicKey_WrapSymmetricKey(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPublicKey_CreateCryptoContext
+ *
+ * Create a crypto context, in this key's trust domain, with this
+ * as the distinguished public key.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSPublicKey_CreateCryptoContext(
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhh);
+
+/*
+ * NSSPublicKey_FindCertificates
+ *
+ * Note that there may be more than one certificate for this
+ * public key. The current implementation may not find every
+ * last certificate available for this public key: that would
+ * involve trolling e.g. huge ldap databases, which will be
+ * grossly inefficient and not generally useful.
+ * { FilterCertificates function to further reduce the list }
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSPublicKey_FindCertificates(
+ NSSPublicKey *bk,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSPrivateKey_FindBestCertificate
+ *
+ * The parameters for this function will depend on what the users
+ * need. This is just a starting point.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSPublicKey_FindBestCertificate(
+ NSSPublicKey *bk,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSPublicKey_FindPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSPublicKey_FindPrivateKey(
+ NSSPublicKey *bk,
+ NSSCallback *uhh);
+
+/*
+ * NSSSymmetricKey
+ *
+ */
+
+/*
+ * NSSSymmetricKey_Destroy
+ *
+ * Free a pointer to a symmetric key object.
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_Destroy(NSSSymmetricKey *mk);
+
+/*
+ * NSSSymmetricKey_DeleteStoredObject
+ *
+ * Permanently remove this object.
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_DeleteStoredObject(
+ NSSSymmetricKey *mk,
+ NSSCallback *uhh);
+
+/*
+ * NSSSymmetricKey_GetKeyLength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSSymmetricKey_GetKeyLength(NSSSymmetricKey *mk);
+
+/*
+ * NSSSymmetricKey_GetKeyStrength
+ *
+ */
+
+NSS_EXTERN PRUint32
+NSSSymmetricKey_GetKeyStrength(NSSSymmetricKey *mk);
+
+/*
+ * NSSSymmetricKey_IsStillPresent
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_IsStillPresent(NSSSymmetricKey *mk);
+
+/*
+ * NSSSymmetricKey_GetTrustDomain
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSSymmetricKey_GetTrustDomain(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSSymmetricKey_GetToken
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSToken *
+NSSSymmetricKey_GetToken(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSSymmetricKey_GetSlot
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSSlot *
+NSSSymmetricKey_GetSlot(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSSymmetricKey_GetModule
+ *
+ * There doesn't have to be one.
+ */
+
+NSS_EXTERN NSSModule *
+NSSSymmetricKey_GetModule(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt);
+
+/*
+ * NSSSymmetricKey_Encrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_Encrypt(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSSymmetricKey_Decrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_Decrypt(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *encryptedData,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSSymmetricKey_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_Sign(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSSymmetricKey_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_SignRecover(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSSymmetricKey_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSSymmetricKey_Verify(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSCallback *uhh);
+
+/*
+ * NSSSymmetricKey_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_VerifyRecover(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSSymmetricKey_WrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_WrapSymmetricKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSSymmetricKey_WrapPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSSymmetricKey_WrapPrivateKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPrivateKey *keyToWrap,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSSymmetricKey_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSSymmetricKey_UnwrapSymmetricKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSOID *target,
+ PRUint32 keySizeOpt,
+ NSSOperations operations,
+ NSSCallback *uhh);
+
+/*
+ * NSSSymmetricKey_UnwrapPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSSymmetricKey_UnwrapPrivateKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSUTF8 *labelOpt,
+ NSSItem *keyIDOpt,
+ PRBool persistant,
+ PRBool sensitive,
+ NSSToken *destinationOpt,
+ NSSCallback *uhh);
+
+/*
+ * NSSSymmetricKey_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSSymmetricKey_DeriveSymmetricKey(
+ NSSSymmetricKey *originalKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt,
+ NSSOperations operations,
+ NSSCallback *uhh);
+
+/*
+ * NSSSymmetricKey_CreateCryptoContext
+ *
+ * Create a crypto context, in this key's trust domain,
+ * with this as the distinguished symmetric key.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSSymmetricKey_CreateCryptoContext(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhh);
+
+/*
+ * NSSTrustDomain
+ *
+ */
+
+/*
+ * NSSTrustDomain_Create
+ *
+ * This creates a trust domain, optionally with an initial cryptoki
+ * module. If the module name is not null, the module is loaded if
+ * needed (using the uriOpt argument), and initialized with the
+ * opaqueOpt argument. If mumble mumble priority settings, then
+ * module-specification objects in the module can cause the loading
+ * and initialization of further modules.
+ *
+ * The uriOpt is defined to take a URI. At present, we only
+ * support file: URLs pointing to platform-native shared libraries.
+ * However, by specifying this as a URI, this keeps open the
+ * possibility of supporting other, possibly remote, resources.
+ *
+ * The "reserved" arguments is held for when we figure out the
+ * module priority stuff.
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSTrustDomain_Create(
+ NSSUTF8 *moduleOpt,
+ NSSUTF8 *uriOpt,
+ NSSUTF8 *opaqueOpt,
+ void *reserved);
+
+/*
+ * NSSTrustDomain_Destroy
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_Destroy(NSSTrustDomain *td);
+
+/*
+ * NSSTrustDomain_SetDefaultCallback
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_SetDefaultCallback(
+ NSSTrustDomain *td,
+ NSSCallback *newCallback,
+ NSSCallback **oldCallbackOpt);
+
+/*
+ * NSSTrustDomain_GetDefaultCallback
+ *
+ */
+
+NSS_EXTERN NSSCallback *
+NSSTrustDomain_GetDefaultCallback(
+ NSSTrustDomain *td,
+ PRStatus *statusOpt);
+
+/*
+ * Default policies?
+ * Default usage?
+ * Default time, for completeness?
+ */
+
+/*
+ * NSSTrustDomain_LoadModule
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_LoadModule(
+ NSSTrustDomain *td,
+ NSSUTF8 *moduleOpt,
+ NSSUTF8 *uriOpt,
+ NSSUTF8 *opaqueOpt,
+ void *reserved);
+
+/*
+ * NSSTrustDomain_AddModule
+ * NSSTrustDomain_AddSlot
+ * NSSTrustDomain_UnloadModule
+ * Managing modules, slots, tokens; priorities;
+ * Traversing all of the above
+ * this needs more work
+ */
+
+/*
+ * NSSTrustDomain_DisableToken
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_DisableToken(
+ NSSTrustDomain *td,
+ NSSToken *token,
+ NSSError why);
+
+/*
+ * NSSTrustDomain_EnableToken
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_EnableToken(
+ NSSTrustDomain *td,
+ NSSToken *token);
+
+/*
+ * NSSTrustDomain_IsTokenEnabled
+ *
+ * If disabled, "why" is always on the error stack.
+ * The optional argument is just for convenience.
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_IsTokenEnabled(
+ NSSTrustDomain *td,
+ NSSToken *token,
+ NSSError *whyOpt);
+
+/*
+ * NSSTrustDomain_FindTokensByURI
+ *
+ */
+
+NSS_EXTERN NSSToken **
+NSSTrustDomain_FindTokensByURI(
+ NSSTrustDomain *td,
+ PK11URI *uri);
+
+/*
+ * NSSTrustDomain_FindSlotByName
+ *
+ */
+
+NSS_EXTERN NSSSlot *
+NSSTrustDomain_FindSlotByName(
+ NSSTrustDomain *td,
+ NSSUTF8 *slotName);
+
+/*
+ * NSSTrustDomain_FindTokenByName
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindTokenByName(
+ NSSTrustDomain *td,
+ NSSUTF8 *tokenName);
+
+/*
+ * NSSTrustDomain_FindTokenBySlotName
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindTokenBySlotName(
+ NSSTrustDomain *td,
+ NSSUTF8 *slotName);
+
+/*
+ * NSSTrustDomain_FindBestTokenForAlgorithm
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindTokenForAlgorithm(
+ NSSTrustDomain *td,
+ NSSOID *algorithm);
+
+/*
+ * NSSTrustDomain_FindBestTokenForAlgorithms
+ *
+ */
+
+NSS_EXTERN NSSToken *
+NSSTrustDomain_FindBestTokenForAlgorithms(
+ NSSTrustDomain *td,
+ NSSOID *algorithms[], /* may be null-terminated */
+ PRUint32 nAlgorithmsOpt /* limits the array if nonzero */
+);
+
+/*
+ * NSSTrustDomain_Login
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_Login(
+ NSSTrustDomain *td,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSTrustDomain_Logout
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_Logout(NSSTrustDomain *td);
+
+/* Importing things */
+
+/*
+ * NSSTrustDomain_ImportCertificate
+ *
+ * The implementation will pull some data out of the certificate
+ * (e.g. e-mail address) for use in pkcs#11 object attributes.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_ImportCertificate(
+ NSSTrustDomain *td,
+ NSSCertificate *c);
+
+/*
+ * NSSTrustDomain_ImportPKIXCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_ImportPKIXCertificate(
+ NSSTrustDomain *td,
+ /* declared as a struct until these "data types" are defined */
+ struct NSSPKIXCertificateStr *pc);
+
+/*
+ * NSSTrustDomain_ImportEncodedCertificate
+ *
+ * Imports any type of certificate we support.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_ImportEncodedCertificate(
+ NSSTrustDomain *td,
+ NSSBER *ber);
+
+/*
+ * NSSTrustDomain_ImportEncodedCertificateChain
+ *
+ * If you just want the leaf, pass in a maximum of one.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_ImportEncodedCertificateChain(
+ NSSTrustDomain *td,
+ NSSBER *ber,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSTrustDomain_ImportEncodedPrivateKey
+ *
+ */
+
+NSS_EXTERN NSSPrivateKey *
+NSSTrustDomain_ImportEncodedPrivateKey(
+ NSSTrustDomain *td,
+ NSSBER *ber,
+ NSSItem *passwordOpt, /* NULL will cause a callback */
+ NSSCallback *uhhOpt,
+ NSSToken *destination);
+
+/*
+ * NSSTrustDomain_ImportEncodedPublicKey
+ *
+ */
+
+NSS_EXTERN NSSPublicKey *
+NSSTrustDomain_ImportEncodedPublicKey(
+ NSSTrustDomain *td,
+ NSSBER *ber);
+
+/* Other importations: S/MIME capabilities */
+
+/*
+ * NSSTrustDomain_FindBestCertificateByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNickname(
+ NSSTrustDomain *td,
+ const NSSUTF8 *name,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/*
+ * NSSTrustDomain_FindCertificatesByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesByNickname(
+ NSSTrustDomain *td,
+ NSSUTF8 *name,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSTrustDomain_FindCertificateByIssuerAndSerialNumber
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
+ NSSTrustDomain *td,
+ NSSDER *issuer,
+ NSSDER *serialNumber);
+
+/*
+ * NSSTrustDomain_FindCertificatesByIssuerAndSerialNumber
+ *
+ * Theoretically, this should never happen. However, some companies
+ * we know have issued duplicate certificates with the same issuer
+ * and serial number. Do we just ignore them? I'm thinking yes.
+ */
+
+/*
+ * NSSTrustDomain_FindBestCertificateBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestCertificateBySubject(
+ NSSTrustDomain *td,
+ NSSDER /*NSSUTF8*/ *subject,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSTrustDomain_FindCertificatesBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesBySubject(
+ NSSTrustDomain *td,
+ NSSDER /*NSSUTF8*/ *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSTrustDomain_FindBestCertificateByNameComponents
+ *
+ * This call does try several tricks, including a pseudo pkcs#11
+ * attribute for the ldap module to try as a query. Eventually
+ * this call falls back to a traversal if that's what's required.
+ * It will search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNameComponents(
+ NSSTrustDomain *td,
+ NSSUTF8 *nameComponents,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSTrustDomain_FindCertificatesByNameComponents
+ *
+ * This call, too, tries several tricks. It will stop on the first
+ * attempt that generates results, so it won't e.g. traverse the
+ * entire ldap database.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesByNameComponents(
+ NSSTrustDomain *td,
+ NSSUTF8 *nameComponents,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSTrustDomain_FindCertificateByEncodedCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByEncodedCertificate(
+ NSSTrustDomain *td,
+ NSSBER *encodedCertificate);
+
+/*
+ * NSSTrustDomain_FindBestCertificateByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByEmail(
+ NSSTrustDomain *td,
+ NSSASCII7 *email,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSTrustDomain_FindCertificatesByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindCertificatesByEmail(
+ NSSTrustDomain *td,
+ NSSASCII7 *email,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSTrustDomain_FindCertificateByOCSPHash
+ *
+ * There can be only one.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindCertificateByOCSPHash(
+ NSSTrustDomain *td,
+ NSSItem *hash);
+
+/*
+ * NSSTrustDomain_TraverseCertificates
+ *
+ * This function descends from one in older versions of NSS which
+ * traverses the certs in the permanent database. That function
+ * was used to implement selection routines, but was directly
+ * available too. Trust domains are going to contain a lot more
+ * certs now (e.g., an ldap server), so we'd really like to
+ * discourage traversal. Thus for now, this is commented out.
+ * If it's needed, let's look at the situation more closely to
+ * find out what the actual requirements are.
+ */
+
+/* For now, adding this function. This may only be for debugging
+ * purposes.
+ * Perhaps some equivalent function, on a specified token, will be
+ * needed in a "friend" header file?
+ */
+NSS_EXTERN PRStatus *
+NSSTrustDomain_TraverseCertificates(
+ NSSTrustDomain *td,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg);
+
+/*
+ * NSSTrustDomain_FindBestUserCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestUserCertificate(
+ NSSTrustDomain *td,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSTrustDomain_FindUserCertificates
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindUserCertificates(
+ NSSTrustDomain *td,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSTrustDomain_FindBestUserCertificateForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForSSLClientAuth(
+ NSSTrustDomain *td,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSTrustDomain_FindUserCertificatesForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForSSLClientAuth(
+ NSSTrustDomain *td,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSTrustDomain_FindBestUserCertificateForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForEmailSigning(
+ NSSTrustDomain *td,
+ NSSASCII7 *signerOpt,
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSTrustDomain_FindUserCertificatesForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForEmailSigning(
+ NSSTrustDomain *td,
+ NSSASCII7 *signerOpt,
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt);
+
+/*
+ * Here is where we'd add more Find[Best]UserCertificate[s]For<usage>
+ * routines.
+ */
+
+/* Private Keys */
+
+/*
+ * NSSTrustDomain_GenerateKeyPair
+ *
+ * Creates persistant objects. If you want session objects, use
+ * NSSCryptoContext_GenerateKeyPair. The destination token is where
+ * the keys are stored. If that token can do the required math, then
+ * that's where the keys are generated too. Otherwise, the keys are
+ * generated elsewhere and moved to that token.
+ */
+
+NSS_EXTERN PRStatus
+NSSTrustDomain_GenerateKeyPair(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap,
+ NSSPrivateKey **pvkOpt,
+ NSSPublicKey **pbkOpt,
+ PRBool privateKeyIsSensitive,
+ NSSToken *destination,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSTrustDomain_TraversePrivateKeys
+ *
+ *
+ * NSS_EXTERN PRStatus *
+ * NSSTrustDomain_TraversePrivateKeys
+ * (
+ * NSSTrustDomain *td,
+ * PRStatus (*callback)(NSSPrivateKey *vk, void *arg),
+ * void *arg
+ * );
+ */
+
+/* Symmetric Keys */
+
+/*
+ * NSSTrustDomain_GenerateSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKey(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap,
+ PRUint32 keysize,
+ NSSToken *destination,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSTrustDomain_GenerateSymmetricKeyFromPassword
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKeyFromPassword(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap,
+ NSSUTF8 *passwordOpt, /* if null, prompt */
+ NSSToken *destinationOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSTrustDomain_FindSymmetricKeyByAlgorithm
+ *
+ * Is this still needed?
+ *
+ * NSS_EXTERN NSSSymmetricKey *
+ * NSSTrustDomain_FindSymmetricKeyByAlgorithm
+ * (
+ * NSSTrustDomain *td,
+ * NSSOID *algorithm,
+ * NSSCallback *uhhOpt
+ * );
+ */
+
+/*
+ * NSSTrustDomain_FindSymmetricKeyByAlgorithmAndKeyID
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSTrustDomain_FindSymmetricKeyByAlgorithmAndKeyID(
+ NSSTrustDomain *td,
+ NSSOID *algorithm,
+ NSSItem *keyID,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSTrustDomain_TraverseSymmetricKeys
+ *
+ *
+ * NSS_EXTERN PRStatus *
+ * NSSTrustDomain_TraverseSymmetricKeys
+ * (
+ * NSSTrustDomain *td,
+ * PRStatus (*callback)(NSSSymmetricKey *mk, void *arg),
+ * void *arg
+ * );
+ */
+
+/*
+ * NSSTrustDomain_CreateCryptoContext
+ *
+ * If a callback object is specified, it becomes the for the crypto
+ * context; otherwise, this trust domain's default (if any) is
+ * inherited.
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContext(
+ NSSTrustDomain *td,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSTrustDomain_CreateCryptoContextForAlgorithm
+ *
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithm(
+ NSSTrustDomain *td,
+ NSSOID *algorithm);
+
+/*
+ * NSSTrustDomain_CreateCryptoContextForAlgorithmAndParameters
+ *
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithmAndParameters(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap);
+
+/* find/traverse other objects, e.g. s/mime profiles */
+
+/*
+ * NSSCryptoContext
+ *
+ * A crypto context is sort of a short-term snapshot of a trust domain,
+ * used for the life of "one crypto operation." You can also think of
+ * it as a "temporary database."
+ *
+ * Just about all of the things you can do with a trust domain -- importing
+ * or creating certs, keys, etc. -- can be done with a crypto context.
+ * The difference is that the objects will be temporary ("session") objects.
+ *
+ * Also, if the context was created for a key, cert, and/or algorithm; or
+ * if such objects have been "associated" with the context, then the context
+ * can do everything the keys can, like crypto operations.
+ *
+ * And finally, because it keeps the state of the crypto operations, it
+ * can do streaming crypto ops.
+ */
+
+/*
+ * NSSTrustDomain_Destroy
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_Destroy(NSSCryptoContext *cc);
+
+/* establishing a default callback */
+
+/*
+ * NSSCryptoContext_SetDefaultCallback
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_SetDefaultCallback(
+ NSSCryptoContext *cc,
+ NSSCallback *newCallback,
+ NSSCallback **oldCallbackOpt);
+
+/*
+ * NSSCryptoContext_GetDefaultCallback
+ *
+ */
+
+NSS_EXTERN NSSCallback *
+NSSCryptoContext_GetDefaultCallback(
+ NSSCryptoContext *cc,
+ PRStatus *statusOpt);
+
+/*
+ * NSSCryptoContext_GetTrustDomain
+ *
+ */
+
+NSS_EXTERN NSSTrustDomain *
+NSSCryptoContext_GetTrustDomain(
+ NSSCryptoContext *cc);
+
+/* AddModule, etc: should we allow "temporary" changes here? */
+/* DisableToken, etc: ditto */
+/* Ordering of tokens? */
+/* Finding slots+token etc. */
+/* login+logout */
+
+/* Importing things */
+
+/*
+ * NSSCryptoContext_FindOrImportCertificate
+ *
+ * If the certificate store already contains this DER cert, return the
+ * address of the matching NSSCertificate that is already in the store,
+ * and bump its reference count.
+ *
+ * If this DER cert is NOT already in the store, then add the new
+ * NSSCertificate to the store and bump its reference count,
+ * then return its address.
+ *
+ * if this DER cert is not in the store and cannot be added to it,
+ * return NULL;
+ *
+ * Record the associated crypto context in the certificate.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindOrImportCertificate(
+ NSSCryptoContext *cc,
+ NSSCertificate *c);
+
+/*
+ * NSSCryptoContext_ImportPKIXCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_ImportPKIXCertificate(
+ NSSCryptoContext *cc,
+ struct NSSPKIXCertificateStr *pc);
+
+/*
+ * NSSCryptoContext_ImportEncodedCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_ImportEncodedCertificate(
+ NSSCryptoContext *cc,
+ NSSBER *ber);
+
+/*
+ * NSSCryptoContext_ImportEncodedPKIXCertificateChain
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ImportEncodedPKIXCertificateChain(
+ NSSCryptoContext *cc,
+ NSSBER *ber);
+
+/* Other importations: S/MIME capabilities
+ */
+
+/*
+ * NSSCryptoContext_FindBestCertificateByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNickname(
+ NSSCryptoContext *cc,
+ const NSSUTF8 *name,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/*
+ * NSSCryptoContext_FindCertificatesByNickname
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesByNickname(
+ NSSCryptoContext *cc,
+ NSSUTF8 *name,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FindCertificateByIssuerAndSerialNumber
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(
+ NSSCryptoContext *cc,
+ NSSDER *issuer,
+ NSSDER *serialNumber);
+
+/*
+ * NSSCryptoContext_FindBestCertificateBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateBySubject(
+ NSSCryptoContext *cc,
+ NSSDER /*NSSUTF8*/ *subject,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSCryptoContext_FindCertificatesBySubject
+ *
+ * This does not search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesBySubject(
+ NSSCryptoContext *cc,
+ NSSDER /*NSSUTF8*/ *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FindBestCertificateByNameComponents
+ *
+ * This call does try several tricks, including a pseudo pkcs#11
+ * attribute for the ldap module to try as a query. Eventually
+ * this call falls back to a traversal if that's what's required.
+ * It will search through alternate names hidden in extensions.
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateByNameComponents(
+ NSSCryptoContext *cc,
+ NSSUTF8 *nameComponents,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSCryptoContext_FindCertificatesByNameComponents
+ *
+ * This call, too, tries several tricks. It will stop on the first
+ * attempt that generates results, so it won't e.g. traverse the
+ * entire ldap database.
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesByNameComponents(
+ NSSCryptoContext *cc,
+ NSSUTF8 *nameComponents,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FindCertificateByEncodedCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindCertificateByEncodedCertificate(
+ NSSCryptoContext *cc,
+ NSSBER *encodedCertificate);
+
+/*
+ * NSSCryptoContext_FindBestCertificateByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestCertificateByEmail(
+ NSSCryptoContext *cc,
+ NSSASCII7 *email,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSCryptoContext_FindCertificatesByEmail
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindCertificatesByEmail(
+ NSSCryptoContext *cc,
+ NSSASCII7 *email,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FindCertificateByOCSPHash
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindCertificateByOCSPHash(
+ NSSCryptoContext *cc,
+ NSSItem *hash);
+
+/*
+ * NSSCryptoContext_TraverseCertificates
+ *
+ *
+ * NSS_EXTERN PRStatus *
+ * NSSCryptoContext_TraverseCertificates
+ * (
+ * NSSCryptoContext *cc,
+ * PRStatus (*callback)(NSSCertificate *c, void *arg),
+ * void *arg
+ * );
+ */
+
+/*
+ * NSSCryptoContext_FindBestUserCertificate
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestUserCertificate(
+ NSSCryptoContext *cc,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSCryptoContext_FindUserCertificates
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindUserCertificates(
+ NSSCryptoContext *cc,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FindBestUserCertificateForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForSSLClientAuth(
+ NSSCryptoContext *cc,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSCryptoContext_FindUserCertificatesForSSLClientAuth
+ *
+ */
+
+NSS_EXTERN NSSCertificate **
+NSSCryptoContext_FindUserCertificatesForSSLClientAuth(
+ NSSCryptoContext *cc,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FindBestUserCertificateForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindBestUserCertificateForEmailSigning(
+ NSSCryptoContext *cc,
+ NSSASCII7 *signerOpt,
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt);
+
+/*
+ * NSSCryptoContext_FindUserCertificatesForEmailSigning
+ *
+ */
+
+NSS_EXTERN NSSCertificate *
+NSSCryptoContext_FindUserCertificatesForEmailSigning(
+ NSSCryptoContext *cc,
+ NSSASCII7 *signerOpt, /* fgmr or a more general name? */
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt);
+
+/* Private Keys */
+
+/*
+ * NSSCryptoContext_GenerateKeyPair
+ *
+ * Creates session objects. If you want persistant objects, use
+ * NSSTrustDomain_GenerateKeyPair. The destination token is where
+ * the keys are stored. If that token can do the required math, then
+ * that's where the keys are generated too. Otherwise, the keys are
+ * generated elsewhere and moved to that token.
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_GenerateKeyPair(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *ap,
+ NSSPrivateKey **pvkOpt,
+ NSSPublicKey **pbkOpt,
+ PRBool privateKeyIsSensitive,
+ NSSToken *destination,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_TraversePrivateKeys
+ *
+ *
+ * NSS_EXTERN PRStatus *
+ * NSSCryptoContext_TraversePrivateKeys
+ * (
+ * NSSCryptoContext *cc,
+ * PRStatus (*callback)(NSSPrivateKey *vk, void *arg),
+ * void *arg
+ * );
+ */
+
+/* Symmetric Keys */
+
+/*
+ * NSSCryptoContext_GenerateSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *ap,
+ PRUint32 keysize,
+ NSSToken *destination,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_GenerateSymmetricKeyFromPassword
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_GenerateSymmetricKeyFromPassword(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *ap,
+ NSSUTF8 *passwordOpt, /* if null, prompt */
+ NSSToken *destinationOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_FindSymmetricKeyByAlgorithm
+ *
+ *
+ * NSS_EXTERN NSSSymmetricKey *
+ * NSSCryptoContext_FindSymmetricKeyByType
+ * (
+ * NSSCryptoContext *cc,
+ * NSSOID *type,
+ * NSSCallback *uhhOpt
+ * );
+ */
+
+/*
+ * NSSCryptoContext_FindSymmetricKeyByAlgorithmAndKeyID
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_FindSymmetricKeyByAlgorithmAndKeyID(
+ NSSCryptoContext *cc,
+ NSSOID *algorithm,
+ NSSItem *keyID,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_TraverseSymmetricKeys
+ *
+ *
+ * NSS_EXTERN PRStatus *
+ * NSSCryptoContext_TraverseSymmetricKeys
+ * (
+ * NSSCryptoContext *cc,
+ * PRStatus (*callback)(NSSSymmetricKey *mk, void *arg),
+ * void *arg
+ * );
+ */
+
+/* Crypto ops on distinguished keys */
+
+/*
+ * NSSCryptoContext_Decrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Decrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *encryptedData,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_BeginDecrypt
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginDecrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_ContinueDecrypt
+ *
+ */
+
+/*
+ * NSSItem semantics:
+ *
+ * If rvOpt is NULL, a new NSSItem and buffer are allocated.
+ * If rvOpt is not null, but the buffer pointer is null,
+ * then rvOpt is returned but a new buffer is allocated.
+ * In this case, if the length value is not zero, then
+ * no more than that much space will be allocated.
+ * If rvOpt is not null and the buffer pointer is not null,
+ * then that buffer is re-used. No more than the buffer
+ * length value will be used; if it's not enough, an
+ * error is returned. If less is used, the number is
+ * adjusted downwards.
+ *
+ * Note that although this is short of some ideal "Item"
+ * definition, we can usually tell how big these buffers
+ * have to be.
+ *
+ * Feedback is requested; and earlier is better than later.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueDecrypt(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FinishDecrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishDecrypt(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_Sign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Sign(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_BeginSign
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginSign(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_ContinueSign
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ContinueSign(
+ NSSCryptoContext *cc,
+ NSSItem *data);
+
+/*
+ * NSSCryptoContext_FinishSign
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishSign(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_SignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_SignRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_BeginSignRecover
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginSignRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_ContinueSignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueSignRecover(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FinishSignRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishSignRecover(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_UnwrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_UnwrapSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_DeriveSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSSymmetricKey *
+NSSCryptoContext_DeriveSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSPublicKey *bk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt, /* zero for best allowed */
+ NSSOperations operations,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_Encrypt
+ *
+ * Encrypt a single chunk of data with the distinguished public key
+ * of this crypto context.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Encrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_BeginEncrypt
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginEncrypt(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_ContinueEncrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueEncrypt(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FinishEncrypt
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishEncrypt(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_Verify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_Verify(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_BeginVerify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginVerify(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_ContinueVerify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ContinueVerify(
+ NSSCryptoContext *cc,
+ NSSItem *data);
+
+/*
+ * NSSCryptoContext_FinishVerify
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_FinishVerify(
+ NSSCryptoContext *cc);
+
+/*
+ * NSSCryptoContext_VerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_VerifyRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_BeginVerifyRecover
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginVerifyRecover(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_ContinueVerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_ContinueVerifyRecover(
+ NSSCryptoContext *cc,
+ NSSItem *data,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_FinishVerifyRecover
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishVerifyRecover(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_WrapSymmetricKey
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_WrapSymmetricKey(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_Digest
+ *
+ * Digest a single chunk of data with the distinguished digest key
+ * of this crypto context.
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_Digest(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhhOpt,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * NSSCryptoContext_BeginDigest
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_BeginDigest(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhhOpt);
+
+/*
+ * NSSCryptoContext_ContinueDigest
+ *
+ */
+
+NSS_EXTERN PRStatus
+NSSCryptoContext_ContinueDigest(
+ NSSCryptoContext *cc,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *item);
+
+/*
+ * NSSCryptoContext_FinishDigest
+ *
+ */
+
+NSS_EXTERN NSSItem *
+NSSCryptoContext_FinishDigest(
+ NSSCryptoContext *cc,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt);
+
+/*
+ * tbd: Combination ops
+ */
+
+/*
+ * NSSCryptoContext_Clone
+ *
+ */
+
+NSS_EXTERN NSSCryptoContext *
+NSSCryptoContext_Clone(NSSCryptoContext *cc);
+
+/*
+ * NSSCryptoContext_Save
+ * NSSCryptoContext_Restore
+ *
+ * We need to be able to save and restore the state of contexts.
+ * Perhaps a mark-and-release mechanism would be better?
+ */
+
+/*
+ * ..._SignTBSCertificate
+ *
+ * This requires feedback from the cert server team.
+ */
+
+/*
+ * PRBool NSSCertificate_GetIsTrustedFor{xxx}(NSSCertificate *c);
+ * PRStatus NSSCertificate_SetIsTrustedFor{xxx}(NSSCertificate *c, PRBool trusted);
+ *
+ * These will be helper functions which get the trust object for a cert,
+ * and then call the corresponding function(s) on it.
+ *
+ * PKIX trust objects will have methods to manipulate the low-level trust
+ * bits (which are based on key usage and extended key usage), and also the
+ * conceptual high-level usages (e.g. ssl client auth, email encryption, etc.)
+ *
+ * Other types of trust objects (if any) might have different low-level
+ * representations, but hopefully high-level concepts would map.
+ *
+ * Only these high-level general routines would be promoted to the
+ * general certificate level here. Hence the {xxx} above would be things
+ * like "EmailSigning."
+ *
+ *
+ * NSSPKIXTrust *NSSCertificate_GetPKIXTrustObject(NSSCertificate *c);
+ * PRStatus NSSCertificate_SetPKIXTrustObject(NSSCertificate *c, NSPKIXTrust *t);
+ *
+ * I want to hold off on any general trust object until we've investigated
+ * other models more thoroughly.
+ */
+
+PR_END_EXTERN_C
+
+#endif /* NSSPKI_H */
diff --git a/security/nss/lib/pki/nsspkit.h b/security/nss/lib/pki/nsspkit.h
new file mode 100644
index 0000000000..1d6bc7180e
--- /dev/null
+++ b/security/nss/lib/pki/nsspkit.h
@@ -0,0 +1,247 @@
+/* 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 NSSPKIT_H
+#define NSSPKIT_H
+
+/*
+ * nsspkit.h
+ *
+ * This file defines the types of the top-level PKI objects.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * NSSCertificate
+ *
+ * This is the public representation of a Certificate. The certificate
+ * may be one found on a smartcard or other token, one decoded from data
+ * received as part of a protocol, one constructed from constituent
+ * parts, etc. Usually it is associated with ("in") a trust domain; as
+ * it can be verified only within a trust domain. The underlying type
+ * of certificate may be of any supported standard, e.g. PKIX, PGP, etc.
+ *
+ * People speak of "verifying (with) the server's, or correspondant's,
+ * certificate"; for simple operations we support that simplification
+ * by implementing public-key crypto operations as methods on this type.
+ */
+
+struct NSSCertificateStr;
+typedef struct NSSCertificateStr NSSCertificate;
+
+/*
+ * NSSUserCertificate
+ *
+ * A ``User'' certificate is one for which the private key is available.
+ * People speak of "using my certificate to sign my email" and "using
+ * my certificate to authenticate to (or login to) the server"; for
+ * simple operations, we support that simplification by implementing
+ * private-key crypto operations as methods on this type.
+ *
+ * The current design only weakly distinguishes between certificates
+ * and user certificates: as far as the compiler goes they're
+ * interchangeable; debug libraries only have one common pointer-tracker;
+ * etc. However, attempts to do private-key operations on a certificate
+ * for which the private key is not available will fail.
+ *
+ * Open design question: should these types be more firmly separated?
+ */
+
+typedef NSSCertificate NSSUserCertificate;
+
+/*
+ * NSSPrivateKey
+ *
+ * This is the public representation of a Private Key. In general,
+ * the actual value of the key is not available, but operations may
+ * be performed with it.
+ */
+
+struct NSSPrivateKeyStr;
+typedef struct NSSPrivateKeyStr NSSPrivateKey;
+
+/*
+ * NSSPublicKey
+ *
+ */
+
+struct NSSPublicKeyStr;
+typedef struct NSSPublicKeyStr NSSPublicKey;
+
+/*
+ * NSSSymmetricKey
+ *
+ */
+
+struct NSSSymmetricKeyStr;
+typedef struct NSSSymmetricKeyStr NSSSymmetricKey;
+
+/*
+ * NSSTrustDomain
+ *
+ * A Trust Domain is the field in which certificates may be validated.
+ * A trust domain will generally have one or more cryptographic modules
+ * open; these modules perform the cryptographic operations, and
+ * provide the basic "root" trust information from which the trust in
+ * a specific certificate or key depends.
+ *
+ * A client program, or a simple server, would typically have one
+ * trust domain. A server supporting multiple "virtual servers" might
+ * have a separate trust domain for each virtual server. The separate
+ * trust domains might share some modules (e.g., a hardware crypto
+ * accelerator) but not others (e.g., the tokens storing the different
+ * servers' private keys, or the databases with each server's trusted
+ * root certificates).
+ *
+ * This object descends from the "permananet database" in the old code.
+ */
+
+struct NSSTrustDomainStr;
+typedef struct NSSTrustDomainStr NSSTrustDomain;
+
+/*
+ * NSSCryptoContext
+ *
+ * A Crypto Context is a short-term, "helper" object which is used
+ * for the lifetime of one ongoing "crypto operation." Such an
+ * operation may be the creation of a signed message, the use of an
+ * TLS socket connection, etc. Each crypto context is "in" a
+ * specific trust domain, and it may have associated with it a
+ * distinguished certificate, public key, private key, and/or
+ * symmetric key. It can also temporarily hold and use temporary
+ * data (e.g. intermediate certificates) which is not stored
+ * permanently in the trust domain.
+ *
+ * In OO terms, this interface inherits interfaces from the trust
+ * domain, the certificates, and the keys. It also provides
+ * streaming crypto operations.
+ *
+ * This object descends from the "temporary database" concept in the
+ * old code, but it has changed a lot as a result of what we've
+ * learned.
+ */
+
+typedef struct NSSCryptoContextStr NSSCryptoContext;
+
+/*
+ * fgmr others
+ */
+
+/*
+ * OBJECT IDENTIFIER
+ *
+ * This is the basic OID that crops up everywhere.
+ */
+
+struct NSSOIDStr; /* unused opaque structure */
+typedef struct NSSOIDStr NSSOID;
+
+/*
+ * NSSTime
+ *
+ * Unfortunately, we need an "exceptional" value to indicate
+ * an error upon return, or "no value" on input. Note that zero
+ * is a perfectly valid value for both time_t and PRTime.
+ *
+ * If we were to create a "range" object, with two times for
+ * Not Before and Not After, we would have an obvious place for
+ * the somewhat arbitrary logic involved in comparing them.
+ *
+ * Failing that, let's have an NSSTime_CompareRanges function.
+ */
+
+struct NSSTimeStr;
+typedef struct NSSTimeStr NSSTime;
+
+struct NSSTrustStr;
+typedef struct NSSTrustStr NSSTrust;
+
+/*
+ * NSSUsage
+ *
+ * This is trickier than originally planned; I'll write up a
+ * doc on it.
+ *
+ * We'd still like nsspki.h to have a list of common usages,
+ * e.g.:
+ *
+ * extern const NSSUsage *NSSUsage_ClientAuth;
+ * extern const NSSUsage *NSSUsage_ServerAuth;
+ * extern const NSSUsage *NSSUsage_SignEmail;
+ * extern const NSSUsage *NSSUsage_EncryptEmail;
+ * etc.
+ */
+
+struct NSSUsageStr;
+typedef struct NSSUsageStr NSSUsage;
+
+/*
+ * NSSPolicies
+ *
+ * Placeholder, for now.
+ */
+
+struct NSSPoliciesStr;
+typedef struct NSSPoliciesStr NSSPolicies;
+
+/*
+ * NSSAlgorithmAndParameters
+ *
+ * Algorithm is an OID
+ * Parameters depend on the algorithm
+ */
+
+struct NSSAlgorithmAndParametersStr;
+typedef struct NSSAlgorithmAndParametersStr NSSAlgorithmAndParameters;
+
+/*
+ * NSSCallback
+ *
+ * At minimum, a "challenge" method and a closure argument.
+ * Usually the challenge will just be prompting for a password.
+ * How OO do we want to make it?
+ */
+
+typedef struct NSSCallbackStr NSSCallback;
+
+struct NSSCallbackStr {
+ /* Prompt for a password to initialize a slot. */
+ PRStatus (*getInitPW)(NSSUTF8 *slotName, void *arg,
+ NSSUTF8 **ssoPW, NSSUTF8 **userPW);
+ /* Prompt for oldPW and newPW in order to change the
+ * password on a slot.
+ */
+ PRStatus (*getNewPW)(NSSUTF8 *slotName, PRUint32 *retries, void *arg,
+ NSSUTF8 **oldPW, NSSUTF8 **newPW);
+ /* Prompt for slot password. */
+ PRStatus (*getPW)(NSSUTF8 *slotName, PRUint32 *retries, void *arg,
+ NSSUTF8 **password);
+ void *arg;
+};
+
+/* set errors - user cancelled, ... */
+
+typedef PRUint32 NSSOperations;
+/* 1) Do we want these to be preprocessor definitions or constants? */
+/* 2) What is the correct and complete list? */
+
+#define NSSOperations_ENCRYPT 0x0001
+#define NSSOperations_DECRYPT 0x0002
+#define NSSOperations_WRAP 0x0004
+#define NSSOperations_UNWRAP 0x0008
+#define NSSOperations_SIGN 0x0010
+#define NSSOperations_SIGN_RECOVER 0x0020
+#define NSSOperations_VERIFY 0x0040
+#define NSSOperations_VERIFY_RECOVER 0x0080
+
+struct NSSPKIXCertificateStr;
+
+PR_END_EXTERN_C
+
+#endif /* NSSPKIT_H */
diff --git a/security/nss/lib/pki/pki.gyp b/security/nss/lib/pki/pki.gyp
new file mode 100644
index 0000000000..c3475dfb14
--- /dev/null
+++ b/security/nss/lib/pki/pki.gyp
@@ -0,0 +1,32 @@
+# 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/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'nsspki',
+ 'type': 'static_library',
+ 'sources': [
+ 'asymmkey.c',
+ 'certdecode.c',
+ 'certificate.c',
+ 'cryptocontext.c',
+ 'pki3hack.c',
+ 'pkibase.c',
+ 'pkistore.c',
+ 'symmkey.c',
+ 'tdcache.c',
+ 'trustdomain.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+} \ No newline at end of file
diff --git a/security/nss/lib/pki/pki.h b/security/nss/lib/pki/pki.h
new file mode 100644
index 0000000000..00cebe7d4d
--- /dev/null
+++ b/security/nss/lib/pki/pki.h
@@ -0,0 +1,141 @@
+/* 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 PKI_H
+#define PKI_H
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+PR_BEGIN_EXTERN_C
+
+NSS_EXTERN NSSCallback *
+nssTrustDomain_GetDefaultCallback(
+ NSSTrustDomain *td,
+ PRStatus *statusOpt);
+
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_FindCertificatesBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSTrust *
+nssTrustDomain_FindTrustForCertificate(
+ NSSTrustDomain *td,
+ NSSCertificate *c);
+
+NSS_EXTERN NSSCertificate *
+nssCertificate_AddRef(NSSCertificate *c);
+
+NSS_EXTERN PRStatus
+nssCertificate_Destroy(NSSCertificate *c);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetEncoding(NSSCertificate *c);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetIssuer(NSSCertificate *c);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetSerialNumber(NSSCertificate *c);
+
+NSS_EXTERN NSSDER *
+nssCertificate_GetSubject(NSSCertificate *c);
+
+/* Returns a copy, Caller must free using nss_ZFreeIf */
+NSS_EXTERN NSSUTF8 *
+nssCertificate_GetNickname(
+ NSSCertificate *c,
+ NSSToken *tokenOpt);
+
+NSS_EXTERN NSSASCII7 *
+nssCertificate_GetEmailAddress(NSSCertificate *c);
+
+NSS_EXTERN PRBool
+nssCertificate_IssuerAndSerialEqual(
+ NSSCertificate *c1,
+ NSSCertificate *c2);
+
+NSS_EXTERN NSSPrivateKey *
+nssPrivateKey_AddRef(NSSPrivateKey *vk);
+
+NSS_EXTERN PRStatus
+nssPrivateKey_Destroy(NSSPrivateKey *vk);
+
+NSS_EXTERN NSSItem *
+nssPrivateKey_GetID(NSSPrivateKey *vk);
+
+NSS_EXTERN NSSUTF8 *
+nssPrivateKey_GetNickname(
+ NSSPrivateKey *vk,
+ NSSToken *tokenOpt);
+
+NSS_EXTERN PRStatus
+nssPublicKey_Destroy(NSSPublicKey *bk);
+
+NSS_EXTERN NSSItem *
+nssPublicKey_GetID(NSSPublicKey *vk);
+
+NSS_EXTERN NSSCertificate **
+nssCryptoContext_FindCertificatesBySubject(
+ NSSCryptoContext *cc,
+ NSSDER *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/* putting here for now, needs more thought */
+NSS_EXTERN PRStatus
+nssCryptoContext_ImportTrust(
+ NSSCryptoContext *cc,
+ NSSTrust *trust);
+
+NSS_EXTERN NSSTrust *
+nssCryptoContext_FindTrustForCertificate(
+ NSSCryptoContext *cc,
+ NSSCertificate *cert);
+
+NSS_EXTERN PRStatus
+nssCryptoContext_ImportSMIMEProfile(
+ NSSCryptoContext *cc,
+ nssSMIMEProfile *profile);
+
+NSS_EXTERN nssSMIMEProfile *
+nssCryptoContext_FindSMIMEProfileForCertificate(
+ NSSCryptoContext *cc,
+ NSSCertificate *cert);
+
+NSS_EXTERN NSSTrust *
+nssTrust_AddRef(NSSTrust *trust);
+
+NSS_EXTERN PRStatus
+nssTrust_Destroy(NSSTrust *trust);
+
+NSS_EXTERN nssSMIMEProfile *
+nssSMIMEProfile_AddRef(nssSMIMEProfile *profile);
+
+NSS_EXTERN PRStatus
+nssSMIMEProfile_Destroy(nssSMIMEProfile *profile);
+
+NSS_EXTERN nssSMIMEProfile *
+nssSMIMEProfile_Create(
+ NSSCertificate *cert,
+ NSSItem *profileTime,
+ NSSItem *profileData);
+
+PR_END_EXTERN_C
+
+#endif /* PKI_H */
diff --git a/security/nss/lib/pki/pki3hack.c b/security/nss/lib/pki/pki3hack.c
new file mode 100644
index 0000000000..5556cd1769
--- /dev/null
+++ b/security/nss/lib/pki/pki3hack.c
@@ -0,0 +1,1510 @@
+/* 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);
+ }
+}
diff --git a/security/nss/lib/pki/pki3hack.h b/security/nss/lib/pki/pki3hack.h
new file mode 100644
index 0000000000..39b50ab4e4
--- /dev/null
+++ b/security/nss/lib/pki/pki3hack.h
@@ -0,0 +1,149 @@
+/* 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 PKINSS3HACK_H
+#define PKINSS3HACK_H
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef DEVT_H
+#include "devt.h"
+#endif /* DEVT_H */
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#include "base.h"
+
+#include "cert.h"
+
+PR_BEGIN_EXTERN_C
+
+#define NSSITEM_FROM_SECITEM(nssit, secit) \
+ (nssit)->data = (void *)(secit)->data; \
+ (nssit)->size = (PRUint32)(secit)->len;
+
+#define SECITEM_FROM_NSSITEM(secit, nssit) \
+ (secit)->data = (unsigned char *)(nssit)->data; \
+ (secit)->len = (unsigned int)(nssit)->size;
+
+NSS_EXTERN NSSTrustDomain *
+STAN_GetDefaultTrustDomain();
+
+NSS_EXTERN NSSCryptoContext *
+STAN_GetDefaultCryptoContext();
+
+NSS_EXTERN PRStatus
+STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot);
+
+NSS_EXTERN PRStatus
+STAN_ResetTokenInterator(NSSTrustDomain *td);
+
+NSS_EXTERN PRStatus
+STAN_LoadDefaultNSS3TrustDomain(void);
+
+NSS_EXTERN PRStatus
+STAN_Shutdown();
+
+NSS_EXTERN SECStatus
+STAN_AddModuleToDefaultTrustDomain(SECMODModule *module);
+
+NSS_EXTERN SECStatus
+STAN_RemoveModuleFromDefaultTrustDomain(SECMODModule *module);
+
+NSS_EXTERN CERTCertificate *
+STAN_ForceCERTCertificateUpdate(NSSCertificate *c);
+
+NSS_EXTERN CERTCertificate *
+STAN_GetCERTCertificate(NSSCertificate *c);
+
+NSS_EXTERN CERTCertificate *
+STAN_GetCERTCertificateOrRelease(NSSCertificate *c);
+
+NSS_EXTERN NSSCertificate *
+STAN_GetNSSCertificate(CERTCertificate *c);
+
+NSS_EXTERN CERTCertTrust *
+nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc);
+
+NSS_EXTERN PRStatus
+STAN_DeleteCertTrustMatchingSlot(NSSCertificate *c);
+
+NSS_EXTERN PRStatus
+STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust);
+
+NSS_EXTERN PRStatus
+nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der,
+ NSSDER *issuer, NSSDER *serial);
+
+NSS_EXTERN char *
+STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c);
+
+NSS_EXTERN char *
+STAN_GetCERTCertificateNameForInstance(PLArenaPool *arenaOpt,
+ NSSCertificate *c,
+ nssCryptokiInstance *instance);
+
+/* exposing this */
+NSS_EXTERN NSSCertificate *
+NSSCertificate_Create(NSSArena *arenaOpt);
+
+/* This function is being put here because it is a hack for
+ * PK11_FindCertFromNickname.
+ */
+NSS_EXTERN NSSCertificate *
+nssTrustDomain_FindBestCertificateByNicknameForToken(
+ NSSTrustDomain *td,
+ NSSToken *token,
+ NSSUTF8 *name,
+ NSSTime *timeOpt, /* NULL for "now" */
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt /* NULL for none */
+);
+
+/* This function is being put here because it is a hack for
+ * PK11_FindCertsFromNickname.
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_FindCertificatesByNicknameForToken(
+ NSSTrustDomain *td,
+ NSSToken *token,
+ NSSUTF8 *name,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt);
+
+/* CERT_TraversePermCertsForSubject */
+NSS_EXTERN PRStatus
+nssTrustDomain_TraverseCertificatesBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg);
+
+/* CERT_TraversePermCertsForNickname */
+NSS_EXTERN PRStatus
+nssTrustDomain_TraverseCertificatesByNickname(
+ NSSTrustDomain *td,
+ NSSUTF8 *nickname,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg);
+
+/* SEC_TraversePermCerts */
+NSS_EXTERN PRStatus
+nssTrustDomain_TraverseCertificates(
+ NSSTrustDomain *td,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg);
+
+/* CERT_AddTempCertToPerm */
+NSS_EXTERN PRStatus
+nssTrustDomain_AddTempCertToPerm(NSSCertificate *c);
+
+PR_END_EXTERN_C
+
+#endif /* PKINSS3HACK_H */
diff --git a/security/nss/lib/pki/pkibase.c b/security/nss/lib/pki/pkibase.c
new file mode 100644
index 0000000000..f58a262cf2
--- /dev/null
+++ b/security/nss/lib/pki/pkibase.c
@@ -0,0 +1,1224 @@
+/* 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 DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#include "pki3hack.h"
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+NSS_IMPLEMENT void
+nssPKIObject_Lock(nssPKIObject *object)
+{
+ switch (object->lockType) {
+ case nssPKIMonitor:
+ PZ_EnterMonitor(object->sync.mlock);
+ break;
+ case nssPKILock:
+ PZ_Lock(object->sync.lock);
+ break;
+ default:
+ PORT_Assert(0);
+ }
+}
+
+NSS_IMPLEMENT void
+nssPKIObject_Unlock(nssPKIObject *object)
+{
+ switch (object->lockType) {
+ case nssPKIMonitor:
+ PZ_ExitMonitor(object->sync.mlock);
+ break;
+ case nssPKILock:
+ PZ_Unlock(object->sync.lock);
+ break;
+ default:
+ PORT_Assert(0);
+ }
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_NewLock(nssPKIObject *object, nssPKILockType lockType)
+{
+ object->lockType = lockType;
+ switch (lockType) {
+ case nssPKIMonitor:
+ object->sync.mlock = PZ_NewMonitor(nssILockSSL);
+ return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
+ case nssPKILock:
+ object->sync.lock = PZ_NewLock(nssILockSSL);
+ return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
+ default:
+ PORT_Assert(0);
+ return PR_FAILURE;
+ }
+}
+
+NSS_IMPLEMENT void
+nssPKIObject_DestroyLock(nssPKIObject *object)
+{
+ switch (object->lockType) {
+ case nssPKIMonitor:
+ PZ_DestroyMonitor(object->sync.mlock);
+ object->sync.mlock = NULL;
+ break;
+ case nssPKILock:
+ PZ_DestroyLock(object->sync.lock);
+ object->sync.lock = NULL;
+ break;
+ default:
+ PORT_Assert(0);
+ }
+}
+
+NSS_IMPLEMENT nssPKIObject *
+nssPKIObject_Create(
+ NSSArena *arenaOpt,
+ nssCryptokiObject *instanceOpt,
+ NSSTrustDomain *td,
+ NSSCryptoContext *cc,
+ nssPKILockType lockType)
+{
+ NSSArena *arena;
+ nssArenaMark *mark = NULL;
+ nssPKIObject *object;
+ if (arenaOpt) {
+ arena = arenaOpt;
+ mark = nssArena_Mark(arena);
+ } else {
+ arena = nssArena_Create();
+ if (!arena) {
+ return (nssPKIObject *)NULL;
+ }
+ }
+ object = nss_ZNEW(arena, nssPKIObject);
+ if (!object) {
+ goto loser;
+ }
+ object->arena = arena;
+ object->trustDomain = td; /* XXX */
+ object->cryptoContext = cc;
+ if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
+ goto loser;
+ }
+ if (instanceOpt) {
+ if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
+ goto loser;
+ }
+ }
+ PR_ATOMIC_INCREMENT(&object->refCount);
+ if (mark) {
+ nssArena_Unmark(arena, mark);
+ }
+ return object;
+loser:
+ if (mark) {
+ nssArena_Release(arena, mark);
+ } else {
+ nssArena_Destroy(arena);
+ }
+ return (nssPKIObject *)NULL;
+}
+
+NSS_IMPLEMENT PRBool
+nssPKIObject_Destroy(
+ nssPKIObject *object)
+{
+ PRUint32 i;
+ PR_ASSERT(object->refCount > 0);
+ if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) {
+ for (i = 0; i < object->numInstances; i++) {
+ nssCryptokiObject_Destroy(object->instances[i]);
+ }
+ nssPKIObject_DestroyLock(object);
+ nssArena_Destroy(object->arena);
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+NSS_IMPLEMENT nssPKIObject *
+nssPKIObject_AddRef(
+ nssPKIObject *object)
+{
+ PR_ATOMIC_INCREMENT(&object->refCount);
+ return object;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_AddInstance(
+ nssPKIObject *object,
+ nssCryptokiObject *instance)
+{
+ nssCryptokiObject **newInstances = NULL;
+
+ nssPKIObject_Lock(object);
+ if (object->numInstances == 0) {
+ newInstances = nss_ZNEWARRAY(object->arena,
+ nssCryptokiObject *,
+ object->numInstances + 1);
+ } else {
+ PRBool found = PR_FALSE;
+ PRUint32 i;
+ for (i = 0; i < object->numInstances; i++) {
+ if (nssCryptokiObject_Equal(object->instances[i], instance)) {
+ found = PR_TRUE;
+ break;
+ }
+ }
+ if (found) {
+ /* The new instance is identical to one in the array, except
+ * perhaps that the label may be different. So replace
+ * the label in the array instance with the label from the
+ * new instance, and discard the new instance.
+ */
+ nss_ZFreeIf(object->instances[i]->label);
+ object->instances[i]->label = instance->label;
+ nssPKIObject_Unlock(object);
+ instance->label = NULL;
+ nssCryptokiObject_Destroy(instance);
+ return PR_SUCCESS;
+ }
+ newInstances = nss_ZREALLOCARRAY(object->instances,
+ nssCryptokiObject *,
+ object->numInstances + 1);
+ }
+ if (newInstances) {
+ object->instances = newInstances;
+ newInstances[object->numInstances++] = instance;
+ }
+ nssPKIObject_Unlock(object);
+ return (newInstances ? PR_SUCCESS : PR_FAILURE);
+}
+
+NSS_IMPLEMENT PRBool
+nssPKIObject_HasInstance(
+ nssPKIObject *object,
+ nssCryptokiObject *instance)
+{
+ PRUint32 i;
+ PRBool hasIt = PR_FALSE;
+ ;
+ nssPKIObject_Lock(object);
+ for (i = 0; i < object->numInstances; i++) {
+ if (nssCryptokiObject_Equal(object->instances[i], instance)) {
+ hasIt = PR_TRUE;
+ break;
+ }
+ }
+ nssPKIObject_Unlock(object);
+ return hasIt;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObject_RemoveInstanceForToken(
+ nssPKIObject *object,
+ NSSToken *token)
+{
+ PRUint32 i;
+ nssCryptokiObject *instanceToRemove = NULL;
+ nssPKIObject_Lock(object);
+ if (object->numInstances == 0) {
+ nssPKIObject_Unlock(object);
+ return PR_SUCCESS;
+ }
+ for (i = 0; i < object->numInstances; i++) {
+ if (object->instances[i]->token == token) {
+ instanceToRemove = object->instances[i];
+ object->instances[i] = object->instances[object->numInstances - 1];
+ object->instances[object->numInstances - 1] = NULL;
+ break;
+ }
+ }
+ if (--object->numInstances > 0) {
+ nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
+ nssCryptokiObject *,
+ object->numInstances);
+ if (instances) {
+ object->instances = instances;
+ }
+ } else {
+ nss_ZFreeIf(object->instances);
+ }
+ nssCryptokiObject_Destroy(instanceToRemove);
+ nssPKIObject_Unlock(object);
+ return PR_SUCCESS;
+}
+
+/* this needs more thought on what will happen when there are multiple
+ * instances
+ */
+NSS_IMPLEMENT PRStatus
+nssPKIObject_DeleteStoredObject(
+ nssPKIObject *object,
+ NSSCallback *uhh,
+ PRBool isFriendly)
+{
+ PRUint32 i, numNotDestroyed;
+ PRStatus status = PR_SUCCESS;
+ numNotDestroyed = 0;
+ nssPKIObject_Lock(object);
+ for (i = 0; i < object->numInstances; i++) {
+ nssCryptokiObject *instance = object->instances[i];
+ status = nssToken_DeleteStoredObject(instance);
+ object->instances[i] = NULL;
+ if (status == PR_SUCCESS) {
+ nssCryptokiObject_Destroy(instance);
+ } else {
+ object->instances[numNotDestroyed++] = instance;
+ }
+ }
+ if (numNotDestroyed == 0) {
+ nss_ZFreeIf(object->instances);
+ object->numInstances = 0;
+ } else {
+ object->numInstances = numNotDestroyed;
+ }
+ nssPKIObject_Unlock(object);
+ return status;
+}
+
+NSS_IMPLEMENT NSSToken **
+nssPKIObject_GetTokens(
+ nssPKIObject *object,
+ PRStatus *statusOpt)
+{
+ NSSToken **tokens = NULL;
+ nssPKIObject_Lock(object);
+ if (object->numInstances > 0) {
+ tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
+ if (tokens) {
+ PRUint32 i;
+ for (i = 0; i < object->numInstances; i++) {
+ tokens[i] = nssToken_AddRef(object->instances[i]->token);
+ }
+ }
+ }
+ nssPKIObject_Unlock(object);
+ if (statusOpt)
+ *statusOpt = PR_SUCCESS; /* until more logic here */
+ return tokens;
+}
+
+NSS_IMPLEMENT NSSUTF8 *
+nssPKIObject_GetNicknameForToken(
+ nssPKIObject *object,
+ NSSToken *tokenOpt)
+{
+ PRUint32 i;
+ NSSUTF8 *nickname = NULL;
+ nssPKIObject_Lock(object);
+ for (i = 0; i < object->numInstances; i++) {
+ if ((!tokenOpt && object->instances[i]->label) ||
+ (object->instances[i]->token == tokenOpt)) {
+ /* Must copy, see bug 745548 */
+ nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL);
+ break;
+ }
+ }
+ nssPKIObject_Unlock(object);
+ return nickname;
+}
+
+NSS_IMPLEMENT nssCryptokiObject **
+nssPKIObject_GetInstances(
+ nssPKIObject *object)
+{
+ nssCryptokiObject **instances = NULL;
+ PRUint32 i;
+ if (object->numInstances == 0) {
+ return (nssCryptokiObject **)NULL;
+ }
+ nssPKIObject_Lock(object);
+ instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *,
+ object->numInstances + 1);
+ if (instances) {
+ for (i = 0; i < object->numInstances; i++) {
+ instances[i] = nssCryptokiObject_Clone(object->instances[i]);
+ }
+ }
+ nssPKIObject_Unlock(object);
+ return instances;
+}
+
+NSS_IMPLEMENT void
+nssCertificateArray_Destroy(
+ NSSCertificate **certs)
+{
+ if (certs) {
+ NSSCertificate **certp;
+ for (certp = certs; *certp; certp++) {
+ if ((*certp)->decoding) {
+ CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
+ if (cc) {
+ CERT_DestroyCertificate(cc);
+ }
+ continue;
+ }
+ nssCertificate_Destroy(*certp);
+ }
+ nss_ZFreeIf(certs);
+ }
+}
+
+NSS_IMPLEMENT void
+NSSCertificateArray_Destroy(
+ NSSCertificate **certs)
+{
+ nssCertificateArray_Destroy(certs);
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssCertificateArray_Join(
+ NSSCertificate **certs1,
+ NSSCertificate **certs2)
+{
+ if (certs1 && certs2) {
+ NSSCertificate **certs, **cp;
+ PRUint32 count = 0;
+ PRUint32 count1 = 0;
+ cp = certs1;
+ while (*cp++)
+ count1++;
+ count = count1;
+ cp = certs2;
+ while (*cp++)
+ count++;
+ certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
+ if (!certs) {
+ nss_ZFreeIf(certs1);
+ nss_ZFreeIf(certs2);
+ return (NSSCertificate **)NULL;
+ }
+ for (cp = certs2; *cp; cp++, count1++) {
+ certs[count1] = *cp;
+ }
+ nss_ZFreeIf(certs2);
+ return certs;
+ } else if (certs1) {
+ return certs1;
+ } else {
+ return certs2;
+ }
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssCertificateArray_FindBestCertificate(
+ NSSCertificate **certs,
+ NSSTime *timeOpt,
+ const NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ NSSCertificate *bestCert = NULL;
+ nssDecodedCert *bestdc = NULL;
+ NSSTime *time, sTime;
+ PRBool bestCertMatches = PR_FALSE;
+ PRBool thisCertMatches;
+ PRBool bestCertIsValidAtTime = PR_FALSE;
+ PRBool bestCertIsTrusted = PR_FALSE;
+
+ if (timeOpt) {
+ time = timeOpt;
+ } else {
+ NSSTime_Now(&sTime);
+ time = &sTime;
+ }
+ if (!certs) {
+ return (NSSCertificate *)NULL;
+ }
+ for (; *certs; certs++) {
+ nssDecodedCert *dc;
+ NSSCertificate *c = *certs;
+ dc = nssCertificate_GetDecoding(c);
+ if (!dc)
+ continue;
+ thisCertMatches = dc->matchUsage(dc, usage);
+ if (!bestCert) {
+ /* always take the first cert, but remember whether or not
+ * the usage matched
+ */
+ bestCert = nssCertificate_AddRef(c);
+ bestCertMatches = thisCertMatches;
+ bestdc = dc;
+ continue;
+ } else {
+ if (bestCertMatches && !thisCertMatches) {
+ /* if already have a cert for this usage, and if this cert
+ * doesn't have the correct usage, continue
+ */
+ continue;
+ } else if (!bestCertMatches && thisCertMatches) {
+ /* this one does match usage, replace the other */
+ nssCertificate_Destroy(bestCert);
+ bestCert = nssCertificate_AddRef(c);
+ bestCertMatches = thisCertMatches;
+ bestdc = dc;
+ continue;
+ }
+ /* this cert match as well as any cert we've found so far,
+ * defer to time/policies
+ * */
+ }
+ /* time */
+ if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) {
+ /* The current best cert is valid at time */
+ bestCertIsValidAtTime = PR_TRUE;
+ if (!dc->isValidAtTime(dc, time)) {
+ /* If the new cert isn't valid at time, it's not better */
+ continue;
+ }
+ } else {
+ /* The current best cert is not valid at time */
+ if (dc->isValidAtTime(dc, time)) {
+ /* If the new cert is valid at time, it's better */
+ nssCertificate_Destroy(bestCert);
+ bestCert = nssCertificate_AddRef(c);
+ bestdc = dc;
+ bestCertIsValidAtTime = PR_TRUE;
+ continue;
+ }
+ }
+ /* Either they are both valid at time, or neither valid.
+ * If only one is trusted for this usage, take it.
+ */
+ if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) {
+ bestCertIsTrusted = PR_TRUE;
+ if (!dc->isTrustedForUsage(dc, usage)) {
+ continue;
+ }
+ } else {
+ /* The current best cert is not trusted */
+ if (dc->isTrustedForUsage(dc, usage)) {
+ /* If the new cert is trusted, it's better */
+ nssCertificate_Destroy(bestCert);
+ bestCert = nssCertificate_AddRef(c);
+ bestdc = dc;
+ bestCertIsTrusted = PR_TRUE;
+ continue;
+ }
+ }
+ /* Otherwise, take the newer one. */
+ if (!bestdc->isNewerThan(bestdc, dc)) {
+ nssCertificate_Destroy(bestCert);
+ bestCert = nssCertificate_AddRef(c);
+ bestdc = dc;
+ continue;
+ }
+ /* policies */
+ /* XXX later -- defer to policies */
+ }
+ return bestCert;
+}
+
+NSS_IMPLEMENT PRStatus
+nssCertificateArray_Traverse(
+ NSSCertificate **certs,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg)
+{
+ PRStatus status = PR_SUCCESS;
+ if (certs) {
+ NSSCertificate **certp;
+ for (certp = certs; *certp; certp++) {
+ status = (*callback)(*certp, arg);
+ if (status != PR_SUCCESS) {
+ break;
+ }
+ }
+ }
+ return status;
+}
+
+NSS_IMPLEMENT void
+nssCRLArray_Destroy(
+ NSSCRL **crls)
+{
+ if (crls) {
+ NSSCRL **crlp;
+ for (crlp = crls; *crlp; crlp++) {
+ nssCRL_Destroy(*crlp);
+ }
+ nss_ZFreeIf(crls);
+ }
+}
+
+/*
+ * Object collections
+ */
+
+typedef enum {
+ pkiObjectType_Certificate = 0,
+ pkiObjectType_CRL = 1,
+ pkiObjectType_PrivateKey = 2,
+ pkiObjectType_PublicKey = 3
+} pkiObjectType;
+
+/* Each object is defined by a set of items that uniquely identify it.
+ * Here are the uid sets:
+ *
+ * NSSCertificate ==> { issuer, serial }
+ * NSSPrivateKey
+ * (RSA) ==> { modulus, public exponent }
+ *
+ */
+#define MAX_ITEMS_FOR_UID 2
+
+/* pkiObjectCollectionNode
+ *
+ * A node in the collection is the set of unique identifiers for a single
+ * object, along with either the actual object or a proto-object.
+ */
+typedef struct
+{
+ PRCList link;
+ PRBool haveObject;
+ nssPKIObject *object;
+ NSSItem uid[MAX_ITEMS_FOR_UID];
+} pkiObjectCollectionNode;
+
+/* nssPKIObjectCollection
+ *
+ * The collection is the set of all objects, plus the interfaces needed
+ * to manage the objects.
+ *
+ */
+struct nssPKIObjectCollectionStr {
+ NSSArena *arena;
+ NSSTrustDomain *td;
+ NSSCryptoContext *cc;
+ PRCList head; /* list of pkiObjectCollectionNode's */
+ PRUint32 size;
+ pkiObjectType objectType;
+ void (*destroyObject)(nssPKIObject *o);
+ PRStatus (*getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
+ PRStatus (*getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid,
+ NSSArena *arena);
+ nssPKIObject *(*createObject)(nssPKIObject *o);
+ nssPKILockType lockType; /* type of lock to use for new proto-objects */
+};
+
+static nssPKIObjectCollection *
+nssPKIObjectCollection_Create(
+ NSSTrustDomain *td,
+ NSSCryptoContext *ccOpt,
+ nssPKILockType lockType)
+{
+ NSSArena *arena;
+ nssPKIObjectCollection *rvCollection = NULL;
+ arena = nssArena_Create();
+ if (!arena) {
+ return (nssPKIObjectCollection *)NULL;
+ }
+ rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
+ if (!rvCollection) {
+ goto loser;
+ }
+ PR_INIT_CLIST(&rvCollection->head);
+ rvCollection->arena = arena;
+ rvCollection->td = td; /* XXX */
+ rvCollection->cc = ccOpt;
+ rvCollection->lockType = lockType;
+ return rvCollection;
+loser:
+ nssArena_Destroy(arena);
+ return (nssPKIObjectCollection *)NULL;
+}
+
+NSS_IMPLEMENT void
+nssPKIObjectCollection_Destroy(
+ nssPKIObjectCollection *collection)
+{
+ if (collection) {
+ PRCList *link;
+ pkiObjectCollectionNode *node;
+ /* first destroy any objects in the collection */
+ link = PR_NEXT_LINK(&collection->head);
+ while (link != &collection->head) {
+ node = (pkiObjectCollectionNode *)link;
+ if (node->haveObject) {
+ (*collection->destroyObject)(node->object);
+ } else {
+ nssPKIObject_Destroy(node->object);
+ }
+ link = PR_NEXT_LINK(link);
+ }
+ /* then destroy it */
+ nssArena_Destroy(collection->arena);
+ }
+}
+
+NSS_IMPLEMENT PRUint32
+nssPKIObjectCollection_Count(
+ nssPKIObjectCollection *collection)
+{
+ return collection->size;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddObject(
+ nssPKIObjectCollection *collection,
+ nssPKIObject *object)
+{
+ pkiObjectCollectionNode *node;
+ node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
+ if (!node) {
+ return PR_FAILURE;
+ }
+ node->haveObject = PR_TRUE;
+ node->object = nssPKIObject_AddRef(object);
+ (*collection->getUIDFromObject)(object, node->uid);
+ PR_INIT_CLIST(&node->link);
+ PR_INSERT_BEFORE(&node->link, &collection->head);
+ collection->size++;
+ return PR_SUCCESS;
+}
+
+static pkiObjectCollectionNode *
+find_instance_in_collection(
+ nssPKIObjectCollection *collection,
+ nssCryptokiObject *instance)
+{
+ PRCList *link;
+ pkiObjectCollectionNode *node;
+ link = PR_NEXT_LINK(&collection->head);
+ while (link != &collection->head) {
+ node = (pkiObjectCollectionNode *)link;
+ if (nssPKIObject_HasInstance(node->object, instance)) {
+ return node;
+ }
+ link = PR_NEXT_LINK(link);
+ }
+ return (pkiObjectCollectionNode *)NULL;
+}
+
+static pkiObjectCollectionNode *
+find_object_in_collection(
+ nssPKIObjectCollection *collection,
+ NSSItem *uid)
+{
+ PRUint32 i;
+ PRStatus status;
+ PRCList *link;
+ pkiObjectCollectionNode *node;
+ link = PR_NEXT_LINK(&collection->head);
+ while (link != &collection->head) {
+ node = (pkiObjectCollectionNode *)link;
+ for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
+ if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
+ break;
+ }
+ }
+ if (i == MAX_ITEMS_FOR_UID) {
+ return node;
+ }
+ link = PR_NEXT_LINK(link);
+ }
+ return (pkiObjectCollectionNode *)NULL;
+}
+
+static pkiObjectCollectionNode *
+add_object_instance(
+ nssPKIObjectCollection *collection,
+ nssCryptokiObject *instance,
+ PRBool *foundIt)
+{
+ PRUint32 i;
+ PRStatus status;
+ pkiObjectCollectionNode *node;
+ nssArenaMark *mark = NULL;
+ NSSItem uid[MAX_ITEMS_FOR_UID];
+ nsslibc_memset(uid, 0, sizeof uid);
+ /* The list is traversed twice, first (here) looking to match the
+ * { token, handle } tuple, and if that is not found, below a search
+ * for unique identifier is done. Here, a match means this exact object
+ * instance is already in the collection, and we have nothing to do.
+ */
+ *foundIt = PR_FALSE;
+ node = find_instance_in_collection(collection, instance);
+ if (node) {
+ /* The collection is assumed to take over the instance. Since we
+ * are not using it, it must be destroyed.
+ */
+ nssCryptokiObject_Destroy(instance);
+ *foundIt = PR_TRUE;
+ return node;
+ }
+ mark = nssArena_Mark(collection->arena);
+ if (!mark) {
+ goto loser;
+ }
+ status = (*collection->getUIDFromInstance)(instance, uid,
+ collection->arena);
+ if (status != PR_SUCCESS) {
+ goto loser;
+ }
+ /* Search for unique identifier. A match here means the object exists
+ * in the collection, but does not have this instance, so the instance
+ * needs to be added.
+ */
+ node = find_object_in_collection(collection, uid);
+ if (node) {
+ /* This is an object with multiple instances */
+ status = nssPKIObject_AddInstance(node->object, instance);
+ } else {
+ /* This is a completely new object. Create a node for it. */
+ node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
+ if (!node) {
+ goto loser;
+ }
+ node->object = nssPKIObject_Create(NULL, instance,
+ collection->td, collection->cc,
+ collection->lockType);
+ if (!node->object) {
+ goto loser;
+ }
+ for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
+ node->uid[i] = uid[i];
+ }
+ node->haveObject = PR_FALSE;
+ PR_INIT_CLIST(&node->link);
+ PR_INSERT_BEFORE(&node->link, &collection->head);
+ collection->size++;
+ status = PR_SUCCESS;
+ }
+ nssArena_Unmark(collection->arena, mark);
+ return node;
+loser:
+ if (mark) {
+ nssArena_Release(collection->arena, mark);
+ }
+ nssCryptokiObject_Destroy(instance);
+ return (pkiObjectCollectionNode *)NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddInstances(
+ nssPKIObjectCollection *collection,
+ nssCryptokiObject **instances,
+ PRUint32 numInstances)
+{
+ PRStatus status = PR_SUCCESS;
+ PRUint32 i = 0;
+ PRBool foundIt;
+ pkiObjectCollectionNode *node;
+ if (instances) {
+ while ((!numInstances || i < numInstances) && *instances) {
+ if (status == PR_SUCCESS) {
+ node = add_object_instance(collection, *instances, &foundIt);
+ if (node == NULL) {
+ /* add_object_instance freed the current instance */
+ /* free the remaining instances */
+ status = PR_FAILURE;
+ }
+ } else {
+ nssCryptokiObject_Destroy(*instances);
+ }
+ instances++;
+ i++;
+ }
+ }
+ return status;
+}
+
+static void
+nssPKIObjectCollection_RemoveNode(
+ nssPKIObjectCollection *collection,
+ pkiObjectCollectionNode *node)
+{
+ PR_REMOVE_LINK(&node->link);
+ collection->size--;
+}
+
+static PRStatus
+nssPKIObjectCollection_GetObjects(
+ nssPKIObjectCollection *collection,
+ nssPKIObject **rvObjects,
+ PRUint32 rvSize)
+{
+ PRUint32 i = 0;
+ PRCList *link = PR_NEXT_LINK(&collection->head);
+ pkiObjectCollectionNode *node;
+ int error = 0;
+ while ((i < rvSize) && (link != &collection->head)) {
+ node = (pkiObjectCollectionNode *)link;
+ if (!node->haveObject) {
+ /* Convert the proto-object to an object */
+ node->object = (*collection->createObject)(node->object);
+ if (!node->object) {
+ link = PR_NEXT_LINK(link);
+ /*remove bogus object from list*/
+ nssPKIObjectCollection_RemoveNode(collection, node);
+ error++;
+ continue;
+ }
+ node->haveObject = PR_TRUE;
+ }
+ rvObjects[i++] = nssPKIObject_AddRef(node->object);
+ link = PR_NEXT_LINK(link);
+ }
+ if (!error && *rvObjects == NULL) {
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ }
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_Traverse(
+ nssPKIObjectCollection *collection,
+ nssPKIObjectCallback *callback)
+{
+ PRCList *link = PR_NEXT_LINK(&collection->head);
+ pkiObjectCollectionNode *node;
+ while (link != &collection->head) {
+ node = (pkiObjectCollectionNode *)link;
+ if (!node->haveObject) {
+ node->object = (*collection->createObject)(node->object);
+ if (!node->object) {
+ link = PR_NEXT_LINK(link);
+ /*remove bogus object from list*/
+ nssPKIObjectCollection_RemoveNode(collection, node);
+ continue;
+ }
+ node->haveObject = PR_TRUE;
+ }
+ switch (collection->objectType) {
+ case pkiObjectType_Certificate:
+ (void)(*callback->func.cert)((NSSCertificate *)node->object,
+ callback->arg);
+ break;
+ case pkiObjectType_CRL:
+ (void)(*callback->func.crl)((NSSCRL *)node->object,
+ callback->arg);
+ break;
+ case pkiObjectType_PrivateKey:
+ (void)(*callback->func.pvkey)((NSSPrivateKey *)node->object,
+ callback->arg);
+ break;
+ case pkiObjectType_PublicKey:
+ (void)(*callback->func.pbkey)((NSSPublicKey *)node->object,
+ callback->arg);
+ break;
+ }
+ link = PR_NEXT_LINK(link);
+ }
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssPKIObjectCollection_AddInstanceAsObject(
+ nssPKIObjectCollection *collection,
+ nssCryptokiObject *instance)
+{
+ pkiObjectCollectionNode *node;
+ PRBool foundIt;
+ node = add_object_instance(collection, instance, &foundIt);
+ if (node == NULL) {
+ return PR_FAILURE;
+ }
+ if (!node->haveObject) {
+ nssPKIObject *original = node->object;
+ node->object = (*collection->createObject)(node->object);
+ if (!node->object) {
+ /*remove bogus object from list*/
+ nssPKIObject_Destroy(original);
+ nssPKIObjectCollection_RemoveNode(collection, node);
+ return PR_FAILURE;
+ }
+ node->haveObject = PR_TRUE;
+ } else if (!foundIt) {
+ /* The instance was added to a pre-existing node. This
+ * function is *only* being used for certificates, and having
+ * multiple instances of certs in 3.X requires updating the
+ * CERTCertificate.
+ * But only do it if it was a new instance!!! If the same instance
+ * is encountered, we set *foundIt to true. Detect that here and
+ * ignore it.
+ */
+ STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
+ }
+ return PR_SUCCESS;
+}
+
+/*
+ * Certificate collections
+ */
+
+static void
+cert_destroyObject(nssPKIObject *o)
+{
+ NSSCertificate *c = (NSSCertificate *)o;
+ if (c->decoding) {
+ CERTCertificate *cc = STAN_GetCERTCertificate(c);
+ if (cc) {
+ CERT_DestroyCertificate(cc);
+ return;
+ } /* else destroy it as NSSCertificate below */
+ }
+ nssCertificate_Destroy(c);
+}
+
+static PRStatus
+cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
+{
+ NSSCertificate *c = (NSSCertificate *)o;
+ /* The builtins are still returning decoded serial numbers. Until
+ * this compatibility issue is resolved, use the full DER of the
+ * cert to uniquely identify it.
+ */
+ NSSDER *derCert;
+ derCert = nssCertificate_GetEncoding(c);
+ uid[0].data = NULL;
+ uid[0].size = 0;
+ uid[1].data = NULL;
+ uid[1].size = 0;
+ if (derCert != NULL) {
+ uid[0] = *derCert;
+ }
+ return PR_SUCCESS;
+}
+
+static PRStatus
+cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
+ NSSArena *arena)
+{
+ /* The builtins are still returning decoded serial numbers. Until
+ * this compatibility issue is resolved, use the full DER of the
+ * cert to uniquely identify it.
+ */
+ uid[1].data = NULL;
+ uid[1].size = 0;
+ return nssCryptokiCertificate_GetAttributes(instance,
+ NULL, /* XXX sessionOpt */
+ arena, /* arena */
+ NULL, /* type */
+ NULL, /* id */
+ &uid[0], /* encoding */
+ NULL, /* issuer */
+ NULL, /* serial */
+ NULL); /* subject */
+}
+
+static nssPKIObject *
+cert_createObject(nssPKIObject *o)
+{
+ NSSCertificate *cert;
+ cert = nssCertificate_Create(o);
+ /* if (STAN_GetCERTCertificate(cert) == NULL) {
+ nssCertificate_Destroy(cert);
+ return (nssPKIObject *)NULL;
+ } */
+ /* In 3.4, have to maintain uniqueness of cert pointers by caching all
+ * certs. Cache the cert here, before returning. If it is already
+ * cached, take the cached entry.
+ */
+ {
+ NSSTrustDomain *td = o->trustDomain;
+ nssTrustDomain_AddCertsToCache(td, &cert, 1);
+ }
+ return (nssPKIObject *)cert;
+}
+
+NSS_IMPLEMENT nssPKIObjectCollection *
+nssCertificateCollection_Create(
+ NSSTrustDomain *td,
+ NSSCertificate **certsOpt)
+{
+ nssPKIObjectCollection *collection;
+ collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
+ if (!collection) {
+ return NULL;
+ }
+ collection->objectType = pkiObjectType_Certificate;
+ collection->destroyObject = cert_destroyObject;
+ collection->getUIDFromObject = cert_getUIDFromObject;
+ collection->getUIDFromInstance = cert_getUIDFromInstance;
+ collection->createObject = cert_createObject;
+ if (certsOpt) {
+ for (; *certsOpt; certsOpt++) {
+ nssPKIObject *object = (nssPKIObject *)(*certsOpt);
+ (void)nssPKIObjectCollection_AddObject(collection, object);
+ }
+ }
+ return collection;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssPKIObjectCollection_GetCertificates(
+ nssPKIObjectCollection *collection,
+ NSSCertificate **rvOpt,
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt)
+{
+ PRStatus status;
+ PRUint32 rvSize;
+ PRBool allocated = PR_FALSE;
+ if (collection->size == 0) {
+ return (NSSCertificate **)NULL;
+ }
+ if (maximumOpt == 0) {
+ rvSize = collection->size;
+ } else {
+ rvSize = PR_MIN(collection->size, maximumOpt);
+ }
+ if (!rvOpt) {
+ rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
+ if (!rvOpt) {
+ return (NSSCertificate **)NULL;
+ }
+ allocated = PR_TRUE;
+ }
+ status = nssPKIObjectCollection_GetObjects(collection,
+ (nssPKIObject **)rvOpt,
+ rvSize);
+ if (status != PR_SUCCESS) {
+ if (allocated) {
+ nss_ZFreeIf(rvOpt);
+ }
+ return (NSSCertificate **)NULL;
+ }
+ return rvOpt;
+}
+
+/*
+ * CRL/KRL collections
+ */
+
+static void
+crl_destroyObject(nssPKIObject *o)
+{
+ NSSCRL *crl = (NSSCRL *)o;
+ nssCRL_Destroy(crl);
+}
+
+static PRStatus
+crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
+{
+ NSSCRL *crl = (NSSCRL *)o;
+ NSSDER *encoding;
+ encoding = nssCRL_GetEncoding(crl);
+ if (!encoding) {
+ nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
+ return PR_FALSE;
+ }
+ uid[0] = *encoding;
+ uid[1].data = NULL;
+ uid[1].size = 0;
+ return PR_SUCCESS;
+}
+
+static PRStatus
+crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
+ NSSArena *arena)
+{
+ return nssCryptokiCRL_GetAttributes(instance,
+ NULL, /* XXX sessionOpt */
+ arena, /* arena */
+ &uid[0], /* encoding */
+ NULL, /* subject */
+ NULL, /* class */
+ NULL, /* url */
+ NULL); /* isKRL */
+}
+
+static nssPKIObject *
+crl_createObject(nssPKIObject *o)
+{
+ return (nssPKIObject *)nssCRL_Create(o);
+}
+
+NSS_IMPLEMENT nssPKIObjectCollection *
+nssCRLCollection_Create(
+ NSSTrustDomain *td,
+ NSSCRL **crlsOpt)
+{
+ nssPKIObjectCollection *collection;
+ collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
+ if (!collection) {
+ return NULL;
+ }
+ collection->objectType = pkiObjectType_CRL;
+ collection->destroyObject = crl_destroyObject;
+ collection->getUIDFromObject = crl_getUIDFromObject;
+ collection->getUIDFromInstance = crl_getUIDFromInstance;
+ collection->createObject = crl_createObject;
+ if (crlsOpt) {
+ for (; *crlsOpt; crlsOpt++) {
+ nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
+ (void)nssPKIObjectCollection_AddObject(collection, object);
+ }
+ }
+ return collection;
+}
+
+NSS_IMPLEMENT NSSCRL **
+nssPKIObjectCollection_GetCRLs(
+ nssPKIObjectCollection *collection,
+ NSSCRL **rvOpt,
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt)
+{
+ PRStatus status;
+ PRUint32 rvSize;
+ PRBool allocated = PR_FALSE;
+ if (collection->size == 0) {
+ return (NSSCRL **)NULL;
+ }
+ if (maximumOpt == 0) {
+ rvSize = collection->size;
+ } else {
+ rvSize = PR_MIN(collection->size, maximumOpt);
+ }
+ if (!rvOpt) {
+ rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
+ if (!rvOpt) {
+ return (NSSCRL **)NULL;
+ }
+ allocated = PR_TRUE;
+ }
+ status = nssPKIObjectCollection_GetObjects(collection,
+ (nssPKIObject **)rvOpt,
+ rvSize);
+ if (status != PR_SUCCESS) {
+ if (allocated) {
+ nss_ZFreeIf(rvOpt);
+ }
+ return (NSSCRL **)NULL;
+ }
+ return rvOpt;
+}
+
+/* how bad would it be to have a static now sitting around, updated whenever
+ * this was called? would avoid repeated allocs...
+ */
+NSS_IMPLEMENT NSSTime *
+NSSTime_Now(NSSTime *timeOpt)
+{
+ return NSSTime_SetPRTime(timeOpt, PR_Now());
+}
+
+NSS_IMPLEMENT NSSTime *
+NSSTime_SetPRTime(
+ NSSTime *timeOpt,
+ PRTime prTime)
+{
+ NSSTime *rvTime;
+ rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
+ if (rvTime) {
+ rvTime->prTime = prTime;
+ }
+ return rvTime;
+}
+
+NSS_IMPLEMENT PRTime
+NSSTime_GetPRTime(
+ NSSTime *time)
+{
+ return time->prTime;
+}
diff --git a/security/nss/lib/pki/pkim.h b/security/nss/lib/pki/pkim.h
new file mode 100644
index 0000000000..3be3337ccf
--- /dev/null
+++ b/security/nss/lib/pki/pkim.h
@@ -0,0 +1,547 @@
+/* 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
+#define PKIM_H
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#ifndef PKI_H
+#include "pki.h"
+#endif /* PKI_H */
+
+#ifndef PKITM_H
+#include "pkitm.h"
+#endif /* PKITM_H */
+
+PR_BEGIN_EXTERN_C
+
+/* nssPKIObject
+ *
+ * This is the base object class, common to all PKI objects defined in
+ * in this module. Each object can be safely 'casted' to an nssPKIObject,
+ * then passed to these methods.
+ *
+ * nssPKIObject_Create
+ * nssPKIObject_Destroy
+ * nssPKIObject_AddRef
+ * nssPKIObject_AddInstance
+ * nssPKIObject_HasInstance
+ * nssPKIObject_GetTokens
+ * nssPKIObject_GetNicknameForToken
+ * nssPKIObject_RemoveInstanceForToken
+ * nssPKIObject_DeleteStoredObject
+ */
+
+NSS_EXTERN void nssPKIObject_Lock(nssPKIObject *object);
+NSS_EXTERN void nssPKIObject_Unlock(nssPKIObject *object);
+NSS_EXTERN PRStatus nssPKIObject_NewLock(nssPKIObject *object,
+ nssPKILockType lockType);
+NSS_EXTERN void nssPKIObject_DestroyLock(nssPKIObject *object);
+
+/* nssPKIObject_Create
+ *
+ * A generic PKI object. It must live in a trust domain. It may be
+ * initialized with a token instance, or alternatively in a crypto context.
+ */
+NSS_EXTERN nssPKIObject *
+nssPKIObject_Create(
+ NSSArena *arenaOpt,
+ nssCryptokiObject *instanceOpt,
+ NSSTrustDomain *td,
+ NSSCryptoContext *ccOpt,
+ nssPKILockType lockType);
+
+/* nssPKIObject_AddRef
+ */
+NSS_EXTERN nssPKIObject *
+nssPKIObject_AddRef(nssPKIObject *object);
+
+/* nssPKIObject_Destroy
+ *
+ * Returns true if object was destroyed. This notifies the subclass that
+ * all references are gone and it should delete any members it owns.
+ */
+NSS_EXTERN PRBool
+nssPKIObject_Destroy(nssPKIObject *object);
+
+/* nssPKIObject_AddInstance
+ *
+ * Add a token instance to the object, if it does not have it already.
+ */
+NSS_EXTERN PRStatus
+nssPKIObject_AddInstance(
+ nssPKIObject *object,
+ nssCryptokiObject *instance);
+
+/* nssPKIObject_HasInstance
+ *
+ * Query the object for a token instance.
+ */
+NSS_EXTERN PRBool
+nssPKIObject_HasInstance(
+ nssPKIObject *object,
+ nssCryptokiObject *instance);
+
+/* nssPKIObject_GetTokens
+ *
+ * Get all tokens which have an instance of the object.
+ */
+NSS_EXTERN NSSToken **
+nssPKIObject_GetTokens(
+ nssPKIObject *object,
+ PRStatus *statusOpt);
+
+/* nssPKIObject_GetNicknameForToken
+ *
+ * tokenOpt == NULL means take the first available, otherwise return the
+ * nickname for the specified token.
+ */
+NSS_EXTERN NSSUTF8 *
+nssPKIObject_GetNicknameForToken(
+ nssPKIObject *object,
+ NSSToken *tokenOpt);
+
+/* nssPKIObject_RemoveInstanceForToken
+ *
+ * Remove the instance of the object on the specified token.
+ */
+NSS_EXTERN PRStatus
+nssPKIObject_RemoveInstanceForToken(
+ nssPKIObject *object,
+ NSSToken *token);
+
+/* nssPKIObject_DeleteStoredObject
+ *
+ * Delete all token instances of the object, as well as any crypto context
+ * instances (TODO). If any of the instances are read-only, or if the
+ * removal fails, the object will keep those instances. 'isFriendly' refers
+ * to the object -- can this object be removed from a friendly token without
+ * login? For example, certificates are friendly, private keys are not.
+ * Note that if the token is not friendly, authentication will be required
+ * regardless of the value of 'isFriendly'.
+ */
+NSS_EXTERN PRStatus
+nssPKIObject_DeleteStoredObject(
+ nssPKIObject *object,
+ NSSCallback *uhh,
+ PRBool isFriendly);
+
+NSS_EXTERN nssCryptokiObject **
+nssPKIObject_GetInstances(
+ nssPKIObject *object);
+
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_FindCertificatesByID(
+ NSSTrustDomain *td,
+ NSSItem *id,
+ NSSCertificate **rvOpt,
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSCRL **
+nssTrustDomain_FindCRLsBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject);
+
+/* module-private nsspki methods */
+
+NSS_EXTERN NSSCryptoContext *
+nssCryptoContext_Create(
+ NSSTrustDomain *td,
+ NSSCallback *uhhOpt);
+
+/* XXX for the collection */
+NSS_EXTERN NSSCertificate *
+nssCertificate_Create(nssPKIObject *object);
+
+NSS_EXTERN PRStatus
+nssCertificate_SetCertTrust(
+ NSSCertificate *c,
+ NSSTrust *trust);
+
+NSS_EXTERN nssDecodedCert *
+nssCertificate_GetDecoding(NSSCertificate *c);
+
+extern PRIntn
+nssCertificate_SubjectListSort(
+ void *v1,
+ void *v2);
+
+NSS_EXTERN nssDecodedCert *
+nssDecodedCert_Create(
+ NSSArena *arenaOpt,
+ NSSDER *encoding,
+ NSSCertificateType type);
+
+NSS_EXTERN PRStatus
+nssDecodedCert_Destroy(nssDecodedCert *dc);
+
+NSS_EXTERN NSSTrust *
+nssTrust_Create(
+ nssPKIObject *object,
+ NSSItem *certData);
+
+NSS_EXTERN NSSCRL *
+nssCRL_Create(nssPKIObject *object);
+
+NSS_EXTERN NSSCRL *
+nssCRL_AddRef(NSSCRL *crl);
+
+NSS_EXTERN PRStatus
+nssCRL_Destroy(NSSCRL *crl);
+
+NSS_EXTERN PRStatus
+nssCRL_DeleteStoredObject(
+ NSSCRL *crl,
+ NSSCallback *uhh);
+
+NSS_EXTERN NSSPrivateKey *
+nssPrivateKey_Create(nssPKIObject *o);
+
+NSS_EXTERN NSSDER *
+nssCRL_GetEncoding(NSSCRL *crl);
+
+NSS_EXTERN NSSPublicKey *
+nssPublicKey_Create(nssPKIObject *object);
+
+/* nssCertificateArray
+ *
+ * These are being thrown around a lot, might as well group together some
+ * functionality.
+ *
+ * nssCertificateArray_Destroy
+ * nssCertificateArray_Join
+ * nssCertificateArray_FindBestCertificate
+ * nssCertificateArray_Traverse
+ */
+
+/* nssCertificateArray_Destroy
+ *
+ * Will destroy the array and the certs within it. If the array was created
+ * in an arena, will *not* (of course) destroy the arena. However, is safe
+ * to call this method on an arena-allocated array.
+ */
+NSS_EXTERN void
+nssCertificateArray_Destroy(NSSCertificate **certs);
+
+/* nssCertificateArray_Join
+ *
+ * Join two arrays into one. The two arrays, certs1 and certs2, should
+ * be considered invalid after a call to this function (they may be destroyed
+ * as part of the join). certs1 and/or certs2 may be NULL. Safe to
+ * call with arrays allocated in an arena, the result will also be in the
+ * arena.
+ */
+NSS_EXTERN NSSCertificate **
+nssCertificateArray_Join(
+ NSSCertificate **certs1,
+ NSSCertificate **certs2);
+
+/* nssCertificateArray_FindBestCertificate
+ *
+ * Use the usual { time, usage, policies } to find the best cert in the
+ * array.
+ */
+NSS_EXTERN NSSCertificate *
+nssCertificateArray_FindBestCertificate(
+ NSSCertificate **certs,
+ NSSTime *timeOpt,
+ const NSSUsage *usage,
+ NSSPolicies *policiesOpt);
+
+/* nssCertificateArray_Traverse
+ *
+ * Do the callback for each cert, terminate the traversal if the callback
+ * fails.
+ */
+NSS_EXTERN PRStatus
+nssCertificateArray_Traverse(
+ NSSCertificate **certs,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg);
+
+NSS_EXTERN void
+nssCRLArray_Destroy(NSSCRL **crls);
+
+/* nssPKIObjectCollection
+ *
+ * This is a handy way to group objects together and perform operations
+ * on them. It can also handle "proto-objects"-- references to
+ * objects instances on tokens, where the actual object hasn't
+ * been formed yet.
+ *
+ * nssCertificateCollection_Create
+ * nssPrivateKeyCollection_Create
+ * nssPublicKeyCollection_Create
+ *
+ * If this was a language that provided for inheritance, each type would
+ * inherit all of the following methods. Instead, there is only one
+ * type (nssPKIObjectCollection), shared among all. This may cause
+ * confusion; an alternative would be to define all of the methods
+ * for each subtype (nssCertificateCollection_Destroy, ...), but that doesn't
+ * seem worth the code bloat.. It is left up to the caller to remember
+ * what type of collection he/she is dealing with.
+ *
+ * nssPKIObjectCollection_Destroy
+ * nssPKIObjectCollection_Count
+ * nssPKIObjectCollection_AddObject
+ * nssPKIObjectCollection_AddInstances
+ * nssPKIObjectCollection_Traverse
+ *
+ * Back to type-specific methods.
+ *
+ * nssPKIObjectCollection_GetCertificates
+ * nssPKIObjectCollection_GetCRLs
+ * nssPKIObjectCollection_GetPrivateKeys
+ * nssPKIObjectCollection_GetPublicKeys
+ */
+
+/* nssCertificateCollection_Create
+ *
+ * Create a collection of certificates in the specified trust domain.
+ * Optionally provide a starting set of certs.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssCertificateCollection_Create(
+ NSSTrustDomain *td,
+ NSSCertificate **certsOpt);
+
+/* nssCRLCollection_Create
+ *
+ * Create a collection of CRLs/KRLs in the specified trust domain.
+ * Optionally provide a starting set of CRLs.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssCRLCollection_Create(
+ NSSTrustDomain *td,
+ NSSCRL **crlsOpt);
+
+/* nssPrivateKeyCollection_Create
+ *
+ * Create a collection of private keys in the specified trust domain.
+ * Optionally provide a starting set of keys.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssPrivateKeyCollection_Create(
+ NSSTrustDomain *td,
+ NSSPrivateKey **pvkOpt);
+
+/* nssPublicKeyCollection_Create
+ *
+ * Create a collection of public keys in the specified trust domain.
+ * Optionally provide a starting set of keys.
+ */
+NSS_EXTERN nssPKIObjectCollection *
+nssPublicKeyCollection_Create(
+ NSSTrustDomain *td,
+ NSSPublicKey **pvkOpt);
+
+/* nssPKIObjectCollection_Destroy
+ */
+NSS_EXTERN void
+nssPKIObjectCollection_Destroy(nssPKIObjectCollection *collection);
+
+/* nssPKIObjectCollection_Count
+ */
+NSS_EXTERN PRUint32
+nssPKIObjectCollection_Count(nssPKIObjectCollection *collection);
+
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_AddObject(
+ nssPKIObjectCollection *collection,
+ nssPKIObject *object);
+
+/* nssPKIObjectCollection_AddInstances
+ *
+ * Add a set of object instances to the collection. The instances
+ * will be sorted into any existing certs/proto-certs that may be in
+ * the collection. The instances will be absorbed by the collection,
+ * the array should not be used after this call (except to free it).
+ *
+ * Failure means the collection is in an invalid state.
+ *
+ * numInstances = 0 means the array is NULL-terminated
+ */
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_AddInstances(
+ nssPKIObjectCollection *collection,
+ nssCryptokiObject **instances,
+ PRUint32 numInstances);
+
+/* nssPKIObjectCollection_Traverse
+ */
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_Traverse(
+ nssPKIObjectCollection *collection,
+ nssPKIObjectCallback *callback);
+
+/* This function is being added for NSS 3.5. It corresponds to the function
+ * nssToken_TraverseCertificates. The idea is to use the collection during
+ * a traversal, creating certs each time a new instance is added for which
+ * a cert does not already exist.
+ */
+NSS_EXTERN PRStatus
+nssPKIObjectCollection_AddInstanceAsObject(
+ nssPKIObjectCollection *collection,
+ nssCryptokiObject *instance);
+
+/* nssPKIObjectCollection_GetCertificates
+ *
+ * Get all of the certificates in the collection.
+ */
+NSS_EXTERN NSSCertificate **
+nssPKIObjectCollection_GetCertificates(
+ nssPKIObjectCollection *collection,
+ NSSCertificate **rvOpt,
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSCRL **
+nssPKIObjectCollection_GetCRLs(
+ nssPKIObjectCollection *collection,
+ NSSCRL **rvOpt,
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSPrivateKey **
+nssPKIObjectCollection_GetPrivateKeys(
+ nssPKIObjectCollection *collection,
+ NSSPrivateKey **rvOpt,
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSPublicKey **
+nssPKIObjectCollection_GetPublicKeys(
+ nssPKIObjectCollection *collection,
+ NSSPublicKey **rvOpt,
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSTime *
+NSSTime_Now(NSSTime *timeOpt);
+
+NSS_EXTERN NSSTime *
+NSSTime_SetPRTime(
+ NSSTime *timeOpt,
+ PRTime prTime);
+
+NSS_EXTERN PRTime
+NSSTime_GetPRTime(
+ NSSTime *time);
+
+NSS_EXTERN nssHash *
+nssHash_CreateCertificate(
+ NSSArena *arenaOpt,
+ PRUint32 numBuckets);
+
+/* 3.4 Certificate cache routines */
+
+NSS_EXTERN PRStatus
+nssTrustDomain_InitializeCache(
+ NSSTrustDomain *td,
+ PRUint32 cacheSize);
+
+NSS_EXTERN PRStatus
+nssTrustDomain_AddCertsToCache(
+ NSSTrustDomain *td,
+ NSSCertificate **certs,
+ PRUint32 numCerts);
+
+NSS_EXTERN void
+nssTrustDomain_RemoveCertFromCacheLOCKED(
+ NSSTrustDomain *td,
+ NSSCertificate *cert);
+
+NSS_EXTERN void
+nssTrustDomain_LockCertCache(NSSTrustDomain *td);
+
+NSS_EXTERN void
+nssTrustDomain_UnlockCertCache(NSSTrustDomain *td);
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_DestroyCache(NSSTrustDomain *td);
+
+/*
+ * Remove all certs for the given token from the cache. This is
+ * needed if the token is removed.
+ */
+NSS_EXTERN PRStatus
+nssTrustDomain_RemoveTokenCertsFromCache(
+ NSSTrustDomain *td,
+ NSSToken *token);
+
+NSS_EXTERN PRStatus
+nssTrustDomain_UpdateCachedTokenCerts(
+ NSSTrustDomain *td,
+ NSSToken *token);
+
+/*
+ * Find all cached certs with this nickname (label).
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsForNicknameFromCache(
+ NSSTrustDomain *td,
+ const NSSUTF8 *nickname,
+ nssList *certListOpt);
+
+/*
+ * Find all cached certs with this email address.
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsForEmailAddressFromCache(
+ NSSTrustDomain *td,
+ NSSASCII7 *email,
+ nssList *certListOpt);
+
+/*
+ * Find all cached certs with this subject.
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsForSubjectFromCache(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ nssList *certListOpt);
+
+/*
+ * Look for a specific cert in the cache.
+ */
+NSS_EXTERN NSSCertificate *
+nssTrustDomain_GetCertForIssuerAndSNFromCache(
+ NSSTrustDomain *td,
+ NSSDER *issuer,
+ NSSDER *serialNum);
+
+/*
+ * Look for a specific cert in the cache.
+ */
+NSS_EXTERN NSSCertificate *
+nssTrustDomain_GetCertByDERFromCache(
+ NSSTrustDomain *td,
+ NSSDER *der);
+
+/* Get all certs from the cache */
+/* XXX this is being included to make some old-style calls word, not to
+ * say we should keep it
+ */
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsFromCache(
+ NSSTrustDomain *td,
+ nssList *certListOpt);
+
+NSS_EXTERN void
+nssTrustDomain_DumpCacheInfo(
+ NSSTrustDomain *td,
+ void (*cert_dump_iter)(const void *, void *, void *),
+ void *arg);
+
+NSS_EXTERN void
+nssCertificateList_AddReferences(
+ nssList *certList);
+
+PR_END_EXTERN_C
+
+#endif /* PKIM_H */
diff --git a/security/nss/lib/pki/pkistore.c b/security/nss/lib/pki/pkistore.c
new file mode 100644
index 0000000000..6113442a1d
--- /dev/null
+++ b/security/nss/lib/pki/pkistore.c
@@ -0,0 +1,675 @@
+/* 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);
+}
diff --git a/security/nss/lib/pki/pkistore.h b/security/nss/lib/pki/pkistore.h
new file mode 100644
index 0000000000..729f209ce7
--- /dev/null
+++ b/security/nss/lib/pki/pkistore.h
@@ -0,0 +1,138 @@
+/* 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 PKISTORE_H
+#define PKISTORE_H
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * PKI Stores
+ *
+ * This is a set of routines for managing local stores of PKI objects.
+ * Currently, the only application is in crypto contexts, where the
+ * certificate store is used. In the future, methods should be added
+ * here for storing local references to keys.
+ */
+
+/*
+ * nssCertificateStore
+ *
+ * Manages local store of certificate, trust, and S/MIME profile objects.
+ * Within a crypto context, mappings of cert to trust and cert to S/MIME
+ * profile are always 1-1. Therefore, it is reasonable to store all objects
+ * in a single collection, indexed by the certificate.
+ */
+
+NSS_EXTERN nssCertificateStore *
+nssCertificateStore_Create(
+ NSSArena *arenaOpt);
+
+NSS_EXTERN PRStatus
+nssCertificateStore_Destroy(
+ nssCertificateStore *store);
+
+/* Atomic Find cert in store, or add this cert to the store.
+** Ref counts properly maintained.
+*/
+NSS_EXTERN NSSCertificate *
+nssCertificateStore_FindOrAdd(
+ nssCertificateStore *store,
+ NSSCertificate *c);
+
+NSS_EXTERN void
+nssCertificateStore_RemoveCertLOCKED(
+ nssCertificateStore *store,
+ NSSCertificate *cert);
+
+struct nssCertificateStoreTraceStr {
+ nssCertificateStore *store;
+ PZLock *lock;
+ PRBool locked;
+ PRBool unlocked;
+};
+
+typedef struct nssCertificateStoreTraceStr nssCertificateStoreTrace;
+
+NSS_EXTERN void
+nssCertificateStore_Lock(
+ nssCertificateStore *store, nssCertificateStoreTrace *out);
+
+NSS_EXTERN void
+nssCertificateStore_Unlock(
+ nssCertificateStore *store, const nssCertificateStoreTrace *in,
+ nssCertificateStoreTrace *out);
+
+NSS_EXTERN NSSCertificate **
+nssCertificateStore_FindCertificatesBySubject(
+ nssCertificateStore *store,
+ NSSDER *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSCertificate **
+nssCertificateStore_FindCertificatesByNickname(
+ nssCertificateStore *store,
+ const NSSUTF8 *nickname,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSCertificate **
+nssCertificateStore_FindCertificatesByEmail(
+ nssCertificateStore *store,
+ NSSASCII7 *email,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt);
+
+NSS_EXTERN NSSCertificate *
+nssCertificateStore_FindCertificateByIssuerAndSerialNumber(
+ nssCertificateStore *store,
+ NSSDER *issuer,
+ NSSDER *serial);
+
+NSS_EXTERN NSSCertificate *
+nssCertificateStore_FindCertificateByEncodedCertificate(
+ nssCertificateStore *store,
+ NSSDER *encoding);
+
+NSS_EXTERN PRStatus
+nssCertificateStore_AddTrust(
+ nssCertificateStore *store,
+ NSSTrust *trust);
+
+NSS_EXTERN NSSTrust *
+nssCertificateStore_FindTrustForCertificate(
+ nssCertificateStore *store,
+ NSSCertificate *cert);
+
+NSS_EXTERN PRStatus
+nssCertificateStore_AddSMIMEProfile(
+ nssCertificateStore *store,
+ nssSMIMEProfile *profile);
+
+NSS_EXTERN nssSMIMEProfile *
+nssCertificateStore_FindSMIMEProfileForCertificate(
+ nssCertificateStore *store,
+ NSSCertificate *cert);
+
+NSS_EXTERN void
+nssCertificateStore_DumpStoreInfo(
+ nssCertificateStore *store,
+ void (*cert_dump_iter)(const void *, void *, void *),
+ void *arg);
+
+PR_END_EXTERN_C
+
+#endif /* PKISTORE_H */
diff --git a/security/nss/lib/pki/pkit.h b/security/nss/lib/pki/pkit.h
new file mode 100644
index 0000000000..5d17a45312
--- /dev/null
+++ b/security/nss/lib/pki/pkit.h
@@ -0,0 +1,183 @@
+/* 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 PKIT_H
+#define PKIT_H
+
+/*
+ * pkit.h
+ *
+ * This file contains definitions for the types of the top-level PKI objects.
+ */
+
+#ifndef NSSBASET_H
+#include "nssbaset.h"
+#endif /* NSSBASET_H */
+
+#ifndef BASET_H
+#include "baset.h"
+#endif /* BASET_H */
+
+#include "certt.h"
+#include "pkcs11t.h"
+
+#ifndef NSSPKIT_H
+#include "nsspkit.h"
+#endif /* NSSPKIT_H */
+
+#ifndef NSSDEVT_H
+#include "nssdevt.h"
+#endif /* NSSDEVT_H */
+
+#ifndef DEVT_H
+#include "devt.h"
+#endif /* DEVT_H */
+
+#ifndef nssrwlkt_h__
+#include "nssrwlkt.h"
+#endif /* nssrwlkt_h__ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A note on ephemeral certs
+ *
+ * The key objects defined here can only be created on tokens, and can only
+ * exist on tokens. Therefore, any instance of a key object must have
+ * a corresponding cryptoki instance. OTOH, certificates created in
+ * crypto contexts need not be stored as session objects on the token.
+ * There are good performance reasons for not doing so. The certificate
+ * and trust objects have been defined with a cryptoContext field to
+ * allow for ephemeral certs, which may have a single instance in a crypto
+ * context along with any number (including zero) of cryptoki instances.
+ * Since contexts may not share objects, there can be only one context
+ * for each object.
+ */
+
+typedef enum {
+ nssPKILock = 1,
+ nssPKIMonitor = 2
+} nssPKILockType;
+
+/* nssPKIObject
+ *
+ * This is the base object class, common to all PKI objects defined in
+ * nsspkit.h
+ */
+struct nssPKIObjectStr {
+ /* The arena for all object memory */
+ NSSArena *arena;
+ /* Atomically incremented/decremented reference counting */
+ PRInt32 refCount;
+ /* lock protects the array of nssCryptokiInstance's of the object */
+ union {
+ PZLock *lock;
+ PZMonitor *mlock;
+ } sync;
+ nssPKILockType lockType;
+ /* XXX with LRU cache, this cannot be guaranteed up-to-date. It cannot
+ * be compared against the update level of the trust domain, since it is
+ * also affected by import/export. Where is this array needed?
+ */
+ nssCryptokiObject **instances;
+ PRUint32 numInstances;
+ /* The object must live in a trust domain */
+ NSSTrustDomain *trustDomain;
+ /* The object may live in a crypto context */
+ NSSCryptoContext *cryptoContext;
+ /* XXX added so temp certs can have nickname, think more ... */
+ NSSUTF8 *tempName;
+};
+
+typedef struct nssDecodedCertStr nssDecodedCert;
+
+typedef struct nssCertificateStoreStr nssCertificateStore;
+
+/* How wide is the scope of this? */
+typedef struct nssSMIMEProfileStr nssSMIMEProfile;
+
+typedef struct nssPKIObjectStr nssPKIObject;
+
+struct NSSTrustStr {
+ nssPKIObject object;
+ NSSCertificate *certificate;
+ nssTrustLevel serverAuth;
+ nssTrustLevel clientAuth;
+ nssTrustLevel emailProtection;
+ nssTrustLevel codeSigning;
+ PRBool stepUpApproved;
+};
+
+struct nssSMIMEProfileStr {
+ nssPKIObject object;
+ NSSCertificate *certificate;
+ NSSASCII7 *email;
+ NSSDER *subject;
+ NSSItem *profileTime;
+ NSSItem *profileData;
+};
+
+struct NSSCertificateStr {
+ nssPKIObject object;
+ NSSCertificateType type;
+ NSSItem id;
+ NSSBER encoding;
+ NSSDER issuer;
+ NSSDER subject;
+ NSSDER serial;
+ NSSASCII7 *email;
+ nssDecodedCert *decoding;
+};
+
+struct NSSPrivateKeyStr;
+
+struct NSSPublicKeyStr;
+
+struct NSSSymmetricKeyStr;
+
+typedef struct nssTDCertificateCacheStr nssTDCertificateCache;
+
+struct NSSTrustDomainStr {
+ PRInt32 refCount;
+ NSSArena *arena;
+ NSSCallback *defaultCallback;
+ nssList *tokenList;
+ nssListIterator *tokens;
+ nssTDCertificateCache *cache;
+ NSSRWLock *tokensLock;
+ void *spkDigestInfo;
+ CERTStatusConfig *statusConfig;
+};
+
+struct NSSCryptoContextStr {
+ PRInt32 refCount;
+ NSSArena *arena;
+ NSSTrustDomain *td;
+ NSSToken *token;
+ nssSession *session;
+ nssCertificateStore *certStore;
+};
+
+struct NSSTimeStr {
+ PRTime prTime;
+};
+
+struct NSSCRLStr {
+ nssPKIObject object;
+ NSSDER encoding;
+ NSSUTF8 *url;
+ PRBool isKRL;
+};
+
+typedef struct NSSCRLStr NSSCRL;
+
+struct NSSPoliciesStr;
+
+struct NSSAlgorithmAndParametersStr;
+
+struct NSSPKIXCertificateStr;
+
+PR_END_EXTERN_C
+
+#endif /* PKIT_H */
diff --git a/security/nss/lib/pki/pkitm.h b/security/nss/lib/pki/pkitm.h
new file mode 100644
index 0000000000..38a5fac358
--- /dev/null
+++ b/security/nss/lib/pki/pkitm.h
@@ -0,0 +1,88 @@
+/* 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 PKITM_H
+#define PKITM_H
+
+/*
+ * pkitm.h
+ *
+ * This file contains PKI-module specific types.
+ */
+
+#ifndef BASET_H
+#include "baset.h"
+#endif /* BASET_H */
+
+#ifndef PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+PR_BEGIN_EXTERN_C
+
+typedef enum nssCertIDMatchEnum {
+ nssCertIDMatch_Yes = 0,
+ nssCertIDMatch_No = 1,
+ nssCertIDMatch_Unknown = 2
+} nssCertIDMatch;
+
+/*
+ * nssDecodedCert
+ *
+ * This is an interface to allow the PKI module access to certificate
+ * information that can only be found by decoding. The interface is
+ * generic, allowing each certificate type its own way of providing
+ * the information
+ */
+struct nssDecodedCertStr {
+ NSSCertificateType type;
+ void *data;
+ /* returns the unique identifier for the cert */
+ NSSItem *(*getIdentifier)(nssDecodedCert *dc);
+ /* returns the unique identifier for this cert's issuer */
+ void *(*getIssuerIdentifier)(nssDecodedCert *dc);
+ /* is id the identifier for this cert? */
+ nssCertIDMatch (*matchIdentifier)(nssDecodedCert *dc, void *id);
+ /* is this cert a valid CA cert? */
+ PRBool (*isValidIssuer)(nssDecodedCert *dc);
+ /* returns the cert usage */
+ NSSUsage *(*getUsage)(nssDecodedCert *dc);
+ /* is time within the validity period of the cert? */
+ PRBool (*isValidAtTime)(nssDecodedCert *dc, NSSTime *time);
+ /* is the validity period of this cert newer than cmpdc? */
+ PRBool (*isNewerThan)(nssDecodedCert *dc, nssDecodedCert *cmpdc);
+ /* does the usage for this cert match the requested usage? */
+ PRBool (*matchUsage)(nssDecodedCert *dc, const NSSUsage *usage);
+ /* is this cert trusted for the requested usage? */
+ PRBool (*isTrustedForUsage)(nssDecodedCert *dc,
+ const NSSUsage *usage);
+ /* extract the email address */
+ NSSASCII7 *(*getEmailAddress)(nssDecodedCert *dc);
+ /* extract the DER-encoded serial number */
+ PRStatus (*getDERSerialNumber)(nssDecodedCert *dc,
+ NSSDER *derSerial, NSSArena *arena);
+};
+
+struct NSSUsageStr {
+ PRBool anyUsage;
+ SECCertUsage nss3usage;
+ PRBool nss3lookingForCA;
+};
+
+typedef struct nssPKIObjectCollectionStr nssPKIObjectCollection;
+
+typedef struct
+{
+ union {
+ PRStatus (*cert)(NSSCertificate *c, void *arg);
+ PRStatus (*crl)(NSSCRL *crl, void *arg);
+ PRStatus (*pvkey)(NSSPrivateKey *vk, void *arg);
+ PRStatus (*pbkey)(NSSPublicKey *bk, void *arg);
+ } func;
+ void *arg;
+} nssPKIObjectCallback;
+
+PR_END_EXTERN_C
+
+#endif /* PKITM_H */
diff --git a/security/nss/lib/pki/symmkey.c b/security/nss/lib/pki/symmkey.c
new file mode 100644
index 0000000000..3103f20c8b
--- /dev/null
+++ b/security/nss/lib/pki/symmkey.c
@@ -0,0 +1,238 @@
+/* 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 NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_Destroy(NSSSymmetricKey *mk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_DeleteStoredObject(
+ NSSSymmetricKey *mk,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSSymmetricKey_GetKeyLength(NSSSymmetricKey *mk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return -1;
+}
+
+NSS_IMPLEMENT PRUint32
+NSSSymmetricKey_GetKeyStrength(NSSSymmetricKey *mk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return -1;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_IsStillPresent(NSSSymmetricKey *mk)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSSymmetricKey_GetTrustDomain(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSSymmetricKey_GetToken(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSSymmetricKey_GetSlot(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSModule *
+NSSSymmetricKey_GetModule(
+ NSSSymmetricKey *mk,
+ PRStatus *statusOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_Encrypt(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_Decrypt(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *encryptedData,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_Sign(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_SignRecover(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSSymmetricKey_Verify(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *data,
+ NSSItem *signature,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_VerifyRecover(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *signature,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_WrapSymmetricKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSSymmetricKey *keyToWrap,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSItem *
+NSSSymmetricKey_WrapPrivateKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPrivateKey *keyToWrap,
+ NSSCallback *uhh,
+ NSSItem *rvOpt,
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSSymmetricKey_UnwrapSymmetricKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSOID *target,
+ PRUint32 keySizeOpt,
+ NSSOperations operations,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSSymmetricKey_UnwrapPrivateKey(
+ NSSSymmetricKey *wrappingKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSItem *wrappedKey,
+ NSSUTF8 *labelOpt,
+ NSSItem *keyIDOpt,
+ PRBool persistant,
+ PRBool sensitive,
+ NSSToken *destinationOpt,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSSymmetricKey_DeriveSymmetricKey(
+ NSSSymmetricKey *originalKey,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSOID *target,
+ PRUint32 keySizeOpt,
+ NSSOperations operations,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSSymmetricKey_CreateCryptoContext(
+ NSSSymmetricKey *mk,
+ NSSAlgorithmAndParameters *apOpt,
+ NSSCallback *uhh)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
diff --git a/security/nss/lib/pki/tdcache.c b/security/nss/lib/pki/tdcache.c
new file mode 100644
index 0000000000..14cc563c48
--- /dev/null
+++ b/security/nss/lib/pki/tdcache.c
@@ -0,0 +1,1113 @@
+/* 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 PKIT_H
+#include "pkit.h"
+#endif /* PKIT_H */
+
+#ifndef NSSPKI_H
+#include "nsspki.h"
+#endif /* NSSPKI_H */
+
+#ifndef PKI_H
+#include "pki.h"
+#endif /* PKI_H */
+
+#ifndef NSSBASE_H
+#include "nssbase.h"
+#endif /* NSSBASE_H */
+
+#ifndef BASE_H
+#include "base.h"
+#endif /* BASE_H */
+
+#include "cert.h"
+#include "dev.h"
+#include "pki3hack.h"
+
+#ifdef DEBUG_CACHE
+static PRLogModuleInfo *s_log = NULL;
+#endif
+
+#ifdef DEBUG_CACHE
+static void
+log_item_dump(const char *msg, NSSItem *it)
+{
+ char buf[33];
+ int i, j;
+ for (i = 0; i < 10 && i < it->size; i++) {
+ snprintf(&buf[2 * i], sizeof(buf) - 2 * i, "%02X", ((PRUint8 *)it->data)[i]);
+ }
+ if (it->size > 10) {
+ snprintf(&buf[2 * i], sizeof(buf) - 2 * i, "..");
+ i += 1;
+ for (j = it->size - 1; i <= 16 && j > 10; i++, j--) {
+ snprintf(&buf[2 * i], sizeof(buf) - 2 * i, "%02X", ((PRUint8 *)it->data)[j]);
+ }
+ }
+ PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, buf));
+}
+#endif
+
+#ifdef DEBUG_CACHE
+static void
+log_cert_ref(const char *msg, NSSCertificate *c)
+{
+ PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, (c->nickname) ? c->nickname : c->email));
+ log_item_dump("\tserial", &c->serial);
+ log_item_dump("\tsubject", &c->subject);
+}
+#endif
+
+/* Certificate cache routines */
+
+/* XXX
+ * Locking is not handled well at all. A single, global lock with sub-locks
+ * in the collection types. Cleanup needed.
+ */
+
+/* should it live in its own arena? */
+struct nssTDCertificateCacheStr {
+ PZLock *lock; /* Must not be held when calling nssSlot_IsTokenPresent. See bug 1625791. */
+ NSSArena *arena;
+ nssHash *issuerAndSN;
+ nssHash *subject;
+ nssHash *nickname;
+ nssHash *email;
+};
+
+struct cache_entry_str {
+ union {
+ NSSCertificate *cert;
+ nssList *list;
+ void *value;
+ } entry;
+ PRUint32 hits;
+ PRTime lastHit;
+ NSSArena *arena;
+ NSSUTF8 *nickname;
+};
+
+typedef struct cache_entry_str cache_entry;
+
+static cache_entry *
+new_cache_entry(NSSArena *arena, void *value, PRBool ownArena)
+{
+ cache_entry *ce = nss_ZNEW(arena, cache_entry);
+ if (ce) {
+ ce->entry.value = value;
+ ce->hits = 1;
+ ce->lastHit = PR_Now();
+ if (ownArena) {
+ ce->arena = arena;
+ }
+ ce->nickname = NULL;
+ }
+ return ce;
+}
+
+/* this should not be exposed in a header, but is here to keep the above
+ * types/functions static
+ */
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_InitializeCache(
+ NSSTrustDomain *td,
+ PRUint32 cacheSize)
+{
+ NSSArena *arena;
+ nssTDCertificateCache *cache = td->cache;
+#ifdef DEBUG_CACHE
+ s_log = PR_NewLogModule("nss_cache");
+ PR_ASSERT(s_log);
+#endif
+ PR_ASSERT(!cache);
+ arena = nssArena_Create();
+ if (!arena) {
+ return PR_FAILURE;
+ }
+ cache = nss_ZNEW(arena, nssTDCertificateCache);
+ if (!cache) {
+ nssArena_Destroy(arena);
+ return PR_FAILURE;
+ }
+ cache->lock = PZ_NewLock(nssILockCache);
+ if (!cache->lock) {
+ nssArena_Destroy(arena);
+ return PR_FAILURE;
+ }
+ /* Create the issuer and serial DER --> certificate hash */
+ cache->issuerAndSN = nssHash_CreateCertificate(arena, cacheSize);
+ if (!cache->issuerAndSN) {
+ goto loser;
+ }
+ /* Create the subject DER --> subject list hash */
+ cache->subject = nssHash_CreateItem(arena, cacheSize);
+ if (!cache->subject) {
+ goto loser;
+ }
+ /* Create the nickname --> subject list hash */
+ cache->nickname = nssHash_CreateString(arena, cacheSize);
+ if (!cache->nickname) {
+ goto loser;
+ }
+ /* Create the email --> list of subject lists hash */
+ cache->email = nssHash_CreateString(arena, cacheSize);
+ if (!cache->email) {
+ goto loser;
+ }
+ cache->arena = arena;
+ td->cache = cache;
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialized."));
+#endif
+ return PR_SUCCESS;
+loser:
+ PZ_DestroyLock(cache->lock);
+ nssArena_Destroy(arena);
+ td->cache = NULL;
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialization failed."));
+#endif
+ return PR_FAILURE;
+}
+
+/* The entries of the hashtable are currently dependent on the certificate(s)
+ * that produced them. That is, the entries will be freed when the cert is
+ * released from the cache. If there are certs in the cache at any time,
+ * including shutdown, the hash table entries will hold memory. In order for
+ * clean shutdown, it is necessary for there to be no certs in the cache.
+ */
+
+extern const NSSError NSS_ERROR_INTERNAL_ERROR;
+extern const NSSError NSS_ERROR_BUSY;
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_DestroyCache(NSSTrustDomain *td)
+{
+ if (!td->cache) {
+ nss_SetError(NSS_ERROR_INTERNAL_ERROR);
+ return PR_FAILURE;
+ }
+ if (nssHash_Count(td->cache->issuerAndSN) > 0) {
+ nss_SetError(NSS_ERROR_BUSY);
+ return PR_FAILURE;
+ }
+ PZ_DestroyLock(td->cache->lock);
+ nssHash_Destroy(td->cache->issuerAndSN);
+ nssHash_Destroy(td->cache->subject);
+ nssHash_Destroy(td->cache->nickname);
+ nssHash_Destroy(td->cache->email);
+ nssArena_Destroy(td->cache->arena);
+ td->cache = NULL;
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("Cache destroyed."));
+#endif
+ return PR_SUCCESS;
+}
+
+static PRStatus
+remove_issuer_and_serial_entry(
+ nssTDCertificateCache *cache,
+ NSSCertificate *cert)
+{
+ /* Remove the cert from the issuer/serial hash */
+ nssHash_Remove(cache->issuerAndSN, cert);
+#ifdef DEBUG_CACHE
+ log_cert_ref("removed issuer/sn", cert);
+#endif
+ return PR_SUCCESS;
+}
+
+static PRStatus
+remove_subject_entry(
+ nssTDCertificateCache *cache,
+ NSSCertificate *cert,
+ nssList **subjectList,
+ NSSUTF8 **nickname,
+ NSSArena **arena)
+{
+ PRStatus nssrv;
+ cache_entry *ce;
+ *subjectList = NULL;
+ *arena = NULL;
+ /* Get the subject list for the cert's subject */
+ ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
+ if (ce) {
+ /* Remove the cert from the subject hash */
+ nssList_Remove(ce->entry.list, cert);
+ *subjectList = ce->entry.list;
+ *nickname = ce->nickname;
+ *arena = ce->arena;
+ nssrv = PR_SUCCESS;
+#ifdef DEBUG_CACHE
+ log_cert_ref("removed cert", cert);
+ log_item_dump("from subject list", &cert->subject);
+#endif
+ } else {
+ nssrv = PR_FAILURE;
+ }
+ return nssrv;
+}
+
+static PRStatus
+remove_nickname_entry(
+ nssTDCertificateCache *cache,
+ NSSUTF8 *nickname,
+ nssList *subjectList)
+{
+ PRStatus nssrv;
+ if (nickname) {
+ nssHash_Remove(cache->nickname, nickname);
+ nssrv = PR_SUCCESS;
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("removed nickname %s", nickname));
+#endif
+ } else {
+ nssrv = PR_FAILURE;
+ }
+ return nssrv;
+}
+
+static PRStatus
+remove_email_entry(
+ nssTDCertificateCache *cache,
+ NSSCertificate *cert,
+ nssList *subjectList)
+{
+ PRStatus nssrv = PR_FAILURE;
+ cache_entry *ce;
+ /* Find the subject list in the email hash */
+ if (cert->email) {
+ ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
+ if (ce) {
+ nssList *subjects = ce->entry.list;
+ /* Remove the subject list from the email hash */
+ if (subjects) {
+ nssList_Remove(subjects, subjectList);
+#ifdef DEBUG_CACHE
+ log_item_dump("removed subject list", &cert->subject);
+ PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
+#endif
+ if (nssList_Count(subjects) == 0) {
+ /* No more subject lists for email, delete list and
+ * remove hash entry
+ */
+ (void)nssList_Destroy(subjects);
+ nssHash_Remove(cache->email, cert->email);
+ /* there are no entries left for this address, free space
+ * used for email entries
+ */
+ nssArena_Destroy(ce->arena);
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
+#endif
+ }
+ }
+ nssrv = PR_SUCCESS;
+ }
+ }
+ return nssrv;
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_RemoveCertFromCacheLOCKED(
+ NSSTrustDomain *td,
+ NSSCertificate *cert)
+{
+ nssList *subjectList;
+ cache_entry *ce;
+ NSSArena *arena;
+ NSSUTF8 *nickname = NULL;
+
+#ifdef DEBUG_CACHE
+ log_cert_ref("attempt to remove cert", cert);
+#endif
+ ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
+ if (!ce || ce->entry.cert != cert) {
+/* If it's not in the cache, or a different cert is (this is really
+ * for safety reasons, though it shouldn't happen), do nothing
+ */
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("but it wasn't in the cache"));
+#endif
+ return;
+ }
+ (void)remove_issuer_and_serial_entry(td->cache, cert);
+ (void)remove_subject_entry(td->cache, cert, &subjectList,
+ &nickname, &arena);
+ if (nssList_Count(subjectList) == 0) {
+ (void)remove_nickname_entry(td->cache, nickname, subjectList);
+ (void)remove_email_entry(td->cache, cert, subjectList);
+ (void)nssList_Destroy(subjectList);
+ nssHash_Remove(td->cache->subject, &cert->subject);
+ /* there are no entries left for this subject, free the space used
+ * for both the nickname and subject entries
+ */
+ if (arena) {
+ nssArena_Destroy(arena);
+ }
+ }
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_LockCertCache(NSSTrustDomain *td)
+{
+ PZ_Lock(td->cache->lock);
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_UnlockCertCache(NSSTrustDomain *td)
+{
+ PZ_Unlock(td->cache->lock);
+}
+
+struct token_cert_dtor {
+ NSSToken *token;
+ nssTDCertificateCache *cache;
+ NSSCertificate **certs;
+ PRUint32 numCerts, arrSize;
+};
+
+static void
+remove_token_certs(const void *k, void *v, void *a)
+{
+ NSSCertificate *c = (NSSCertificate *)k;
+ nssPKIObject *object = &c->object;
+ struct token_cert_dtor *dtor = a;
+ PRUint32 i;
+ nssPKIObject_AddRef(object);
+ nssPKIObject_Lock(object);
+ for (i = 0; i < object->numInstances; i++) {
+ if (object->instances[i]->token == dtor->token) {
+ nssCryptokiObject_Destroy(object->instances[i]);
+ object->instances[i] = object->instances[object->numInstances - 1];
+ object->instances[object->numInstances - 1] = NULL;
+ object->numInstances--;
+ dtor->certs[dtor->numCerts++] = c;
+ if (dtor->numCerts == dtor->arrSize) {
+ dtor->arrSize *= 2;
+ dtor->certs = nss_ZREALLOCARRAY(dtor->certs,
+ NSSCertificate *,
+ dtor->arrSize);
+ }
+ break;
+ }
+ }
+ nssPKIObject_Unlock(object);
+ nssPKIObject_Destroy(object);
+ return;
+}
+
+/*
+ * Remove all certs for the given token from the cache. This is
+ * needed if the token is removed.
+ */
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_RemoveTokenCertsFromCache(
+ NSSTrustDomain *td,
+ NSSToken *token)
+{
+ NSSCertificate **certs;
+ PRUint32 i, arrSize = 10;
+ struct token_cert_dtor dtor;
+ certs = nss_ZNEWARRAY(NULL, NSSCertificate *, arrSize);
+ if (!certs) {
+ return PR_FAILURE;
+ }
+ dtor.cache = td->cache;
+ dtor.token = token;
+ dtor.certs = certs;
+ dtor.numCerts = 0;
+ dtor.arrSize = arrSize;
+ PZ_Lock(td->cache->lock);
+ nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, &dtor);
+ for (i = 0; i < dtor.numCerts; i++) {
+ if (dtor.certs[i]->object.numInstances == 0) {
+ nssTrustDomain_RemoveCertFromCacheLOCKED(td, dtor.certs[i]);
+ dtor.certs[i] = NULL; /* skip this cert in the second for loop */
+ } else {
+ /* make sure it doesn't disappear on us before we finish */
+ nssCertificate_AddRef(dtor.certs[i]);
+ }
+ }
+ PZ_Unlock(td->cache->lock);
+ for (i = 0; i < dtor.numCerts; i++) {
+ if (dtor.certs[i]) {
+ STAN_ForceCERTCertificateUpdate(dtor.certs[i]);
+ nssCertificate_Destroy(dtor.certs[i]);
+ }
+ }
+ nss_ZFreeIf(dtor.certs);
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_UpdateCachedTokenCerts(
+ NSSTrustDomain *td,
+ NSSToken *token)
+{
+ NSSCertificate **cp, **cached = NULL;
+ nssList *certList;
+ PRUint32 count;
+ certList = nssList_Create(NULL, PR_FALSE);
+ if (!certList)
+ return PR_FAILURE;
+ (void)nssTrustDomain_GetCertsFromCache(td, certList);
+ count = nssList_Count(certList);
+ if (count > 0) {
+ cached = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
+ if (!cached) {
+ nssList_Destroy(certList);
+ return PR_FAILURE;
+ }
+ nssList_GetArray(certList, (void **)cached, count);
+ for (cp = cached; *cp; cp++) {
+ nssCryptokiObject *instance;
+ NSSCertificate *c = *cp;
+ nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+ instance = nssToken_FindCertificateByIssuerAndSerialNumber(
+ token,
+ NULL,
+ &c->issuer,
+ &c->serial,
+ tokenOnly,
+ NULL);
+ if (instance) {
+ nssPKIObject_AddInstance(&c->object, instance);
+ STAN_ForceCERTCertificateUpdate(c);
+ }
+ }
+ nssCertificateArray_Destroy(cached);
+ }
+ nssList_Destroy(certList);
+ return PR_SUCCESS;
+}
+
+static PRStatus
+add_issuer_and_serial_entry(
+ NSSArena *arena,
+ nssTDCertificateCache *cache,
+ NSSCertificate *cert)
+{
+ cache_entry *ce;
+ ce = new_cache_entry(arena, (void *)cert, PR_FALSE);
+#ifdef DEBUG_CACHE
+ log_cert_ref("added to issuer/sn", cert);
+#endif
+ return nssHash_Add(cache->issuerAndSN, cert, (void *)ce);
+}
+
+static PRStatus
+add_subject_entry(
+ NSSArena *arena,
+ nssTDCertificateCache *cache,
+ NSSCertificate *cert,
+ NSSUTF8 *nickname,
+ nssList **subjectList)
+{
+ PRStatus nssrv;
+ nssList *list;
+ cache_entry *ce;
+ *subjectList = NULL; /* this is only set if a new one is created */
+ ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
+ if (ce) {
+ ce->hits++;
+ ce->lastHit = PR_Now();
+ /* The subject is already in, add this cert to the list */
+ nssrv = nssList_AddUnique(ce->entry.list, cert);
+#ifdef DEBUG_CACHE
+ log_cert_ref("added to existing subject list", cert);
+#endif
+ } else {
+ NSSDER *subject;
+ /* Create a new subject list for the subject */
+ list = nssList_Create(arena, PR_FALSE);
+ if (!list) {
+ return PR_FAILURE;
+ }
+ ce = new_cache_entry(arena, (void *)list, PR_TRUE);
+ if (!ce) {
+ return PR_FAILURE;
+ }
+ if (nickname) {
+ ce->nickname = nssUTF8_Duplicate(nickname, arena);
+ }
+ nssList_SetSortFunction(list, nssCertificate_SubjectListSort);
+ /* Add the cert entry to this list of subjects */
+ nssrv = nssList_AddUnique(list, cert);
+ if (nssrv != PR_SUCCESS) {
+ return nssrv;
+ }
+ /* Add the subject list to the cache */
+ subject = nssItem_Duplicate(&cert->subject, arena, NULL);
+ if (!subject) {
+ return PR_FAILURE;
+ }
+ nssrv = nssHash_Add(cache->subject, subject, ce);
+ if (nssrv != PR_SUCCESS) {
+ return nssrv;
+ }
+ *subjectList = list;
+#ifdef DEBUG_CACHE
+ log_cert_ref("created subject list", cert);
+#endif
+ }
+ return nssrv;
+}
+
+static PRStatus
+add_nickname_entry(
+ NSSArena *arena,
+ nssTDCertificateCache *cache,
+ NSSUTF8 *certNickname,
+ nssList *subjectList)
+{
+ PRStatus nssrv = PR_SUCCESS;
+ cache_entry *ce;
+ ce = (cache_entry *)nssHash_Lookup(cache->nickname, certNickname);
+ if (ce) {
+ /* This is a collision. A nickname entry already exists for this
+ * subject, but a subject entry didn't. This would imply there are
+ * two subjects using the same nickname, which is not allowed.
+ */
+ return PR_FAILURE;
+ } else {
+ NSSUTF8 *nickname;
+ ce = new_cache_entry(arena, subjectList, PR_FALSE);
+ if (!ce) {
+ return PR_FAILURE;
+ }
+ nickname = nssUTF8_Duplicate(certNickname, arena);
+ if (!nickname) {
+ return PR_FAILURE;
+ }
+ nssrv = nssHash_Add(cache->nickname, nickname, ce);
+#ifdef DEBUG_CACHE
+ log_cert_ref("created nickname for", cert);
+#endif
+ }
+ return nssrv;
+}
+
+static PRStatus
+add_email_entry(
+ nssTDCertificateCache *cache,
+ NSSCertificate *cert,
+ nssList *subjectList)
+{
+ PRStatus nssrv = PR_SUCCESS;
+ nssList *subjects;
+ cache_entry *ce;
+ ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
+ if (ce) {
+ /* Already have an entry for this email address, but not subject */
+ subjects = ce->entry.list;
+ nssrv = nssList_AddUnique(subjects, subjectList);
+ ce->hits++;
+ ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+ log_cert_ref("added subject to email for", cert);
+#endif
+ } else {
+ NSSASCII7 *email;
+ NSSArena *arena;
+ arena = nssArena_Create();
+ if (!arena) {
+ return PR_FAILURE;
+ }
+ /* Create a new list of subject lists, add this subject */
+ subjects = nssList_Create(arena, PR_TRUE);
+ if (!subjects) {
+ nssArena_Destroy(arena);
+ return PR_FAILURE;
+ }
+ /* Add the new subject to the list */
+ nssrv = nssList_AddUnique(subjects, subjectList);
+ if (nssrv != PR_SUCCESS) {
+ nssArena_Destroy(arena);
+ return nssrv;
+ }
+ /* Add the new entry to the cache */
+ ce = new_cache_entry(arena, (void *)subjects, PR_TRUE);
+ if (!ce) {
+ nssArena_Destroy(arena);
+ return PR_FAILURE;
+ }
+ email = nssUTF8_Duplicate(cert->email, arena);
+ if (!email) {
+ nssArena_Destroy(arena);
+ return PR_FAILURE;
+ }
+ nssrv = nssHash_Add(cache->email, email, ce);
+ if (nssrv != PR_SUCCESS) {
+ nssArena_Destroy(arena);
+ return nssrv;
+ }
+#ifdef DEBUG_CACHE
+ log_cert_ref("created email for", cert);
+#endif
+ }
+ return nssrv;
+}
+
+extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
+
+static void
+remove_object_instances(
+ nssPKIObject *object,
+ nssCryptokiObject **instances,
+ int numInstances)
+{
+ int i;
+
+ for (i = 0; i < numInstances; i++) {
+ nssPKIObject_RemoveInstanceForToken(object, instances[i]->token);
+ }
+}
+
+static SECStatus
+merge_object_instances(
+ nssPKIObject *to,
+ nssPKIObject *from)
+{
+ nssCryptokiObject **instances, **ci;
+ int i;
+ SECStatus rv = SECSuccess;
+
+ instances = nssPKIObject_GetInstances(from);
+ if (instances == NULL) {
+ return SECFailure;
+ }
+ for (ci = instances, i = 0; *ci; ci++, i++) {
+ nssCryptokiObject *instance = nssCryptokiObject_Clone(*ci);
+ if (instance) {
+ if (nssPKIObject_AddInstance(to, instance) == PR_SUCCESS) {
+ continue;
+ }
+ nssCryptokiObject_Destroy(instance);
+ }
+ remove_object_instances(to, instances, i);
+ rv = SECFailure;
+ break;
+ }
+ nssCryptokiObjectArray_Destroy(instances);
+ return rv;
+}
+
+static NSSCertificate *
+add_cert_to_cache(
+ NSSTrustDomain *td,
+ NSSCertificate *cert)
+{
+ NSSArena *arena = NULL;
+ nssList *subjectList = NULL;
+ PRStatus nssrv;
+ PRUint32 added = 0;
+ cache_entry *ce;
+ NSSCertificate *rvCert = NULL;
+ NSSUTF8 *certNickname = nssCertificate_GetNickname(cert, NULL);
+
+ /* Set cc->trust and cc->nssCertificate before taking td->cache->lock.
+ * Otherwise, the sorter in add_subject_entry may eventually call
+ * nssSlot_IsTokenPresent, which must not occur while the cache lock
+ * is held. See bugs 1625791 and 1651564 for details. */
+ if (cert->type == NSSCertificateType_PKIX) {
+ (void)STAN_GetCERTCertificate(cert);
+ }
+
+ PZ_Lock(td->cache->lock);
+ /* If it exists in the issuer/serial hash, it's already in all */
+ ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
+ if (ce) {
+ ce->hits++;
+ ce->lastHit = PR_Now();
+ rvCert = nssCertificate_AddRef(ce->entry.cert);
+#ifdef DEBUG_CACHE
+ log_cert_ref("attempted to add cert already in cache", cert);
+#endif
+ PZ_Unlock(td->cache->lock);
+ nss_ZFreeIf(certNickname);
+ /* collision - somebody else already added the cert
+ * to the cache before this thread got around to it.
+ */
+ /* merge the instances of the cert */
+ if (merge_object_instances(&rvCert->object, &cert->object) != SECSuccess) {
+ nssCertificate_Destroy(rvCert);
+ return NULL;
+ }
+ STAN_ForceCERTCertificateUpdate(rvCert);
+ nssCertificate_Destroy(cert);
+ return rvCert;
+ }
+ /* create a new cache entry for this cert within the cert's arena*/
+ nssrv = add_issuer_and_serial_entry(cert->object.arena, td->cache, cert);
+ if (nssrv != PR_SUCCESS) {
+ goto loser;
+ }
+ added++;
+ /* create an arena for the nickname and subject entries */
+ arena = nssArena_Create();
+ if (!arena) {
+ goto loser;
+ }
+ /* create a new subject list for this cert, or add to existing */
+ nssrv = add_subject_entry(arena, td->cache, cert,
+ certNickname, &subjectList);
+ if (nssrv != PR_SUCCESS) {
+ goto loser;
+ }
+ added++;
+ /* If a new subject entry was created, also need nickname and/or email */
+ if (subjectList != NULL) {
+#ifdef nodef
+ PRBool handle = PR_FALSE;
+#endif
+ if (certNickname) {
+ nssrv = add_nickname_entry(arena, td->cache,
+ certNickname, subjectList);
+ if (nssrv != PR_SUCCESS) {
+ goto loser;
+ }
+#ifdef nodef
+ handle = PR_TRUE;
+#endif
+ added++;
+ }
+ if (cert->email) {
+ nssrv = add_email_entry(td->cache, cert, subjectList);
+ if (nssrv != PR_SUCCESS) {
+ goto loser;
+ }
+#ifdef nodef
+ handle = PR_TRUE;
+#endif
+ added += 2;
+ }
+#ifdef nodef
+ /* I think either a nickname or email address must be associated
+ * with the cert. However, certs are passed to NewTemp without
+ * either. This worked in the old code, so it must work now.
+ */
+ if (!handle) {
+ /* Require either nickname or email handle */
+ nssrv = PR_FAILURE;
+ goto loser;
+ }
+#endif
+ } else {
+ /* A new subject entry was not created. arena is unused. */
+ nssArena_Destroy(arena);
+ }
+ rvCert = cert;
+ PZ_Unlock(td->cache->lock);
+ nss_ZFreeIf(certNickname);
+ return rvCert;
+loser:
+ nss_ZFreeIf(certNickname);
+ certNickname = NULL;
+ /* Remove any handles that have been created */
+ subjectList = NULL;
+ if (added >= 1) {
+ (void)remove_issuer_and_serial_entry(td->cache, cert);
+ }
+ if (added >= 2) {
+ (void)remove_subject_entry(td->cache, cert, &subjectList,
+ &certNickname, &arena);
+ }
+ if (added == 3 || added == 5) {
+ (void)remove_nickname_entry(td->cache, certNickname, subjectList);
+ }
+ if (added >= 4) {
+ (void)remove_email_entry(td->cache, cert, subjectList);
+ }
+ if (subjectList) {
+ nssHash_Remove(td->cache->subject, &cert->subject);
+ nssList_Destroy(subjectList);
+ }
+ if (arena) {
+ nssArena_Destroy(arena);
+ }
+ PZ_Unlock(td->cache->lock);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+nssTrustDomain_AddCertsToCache(
+ NSSTrustDomain *td,
+ NSSCertificate **certs,
+ PRUint32 numCerts)
+{
+ PRUint32 i;
+ NSSCertificate *c;
+ for (i = 0; i < numCerts && certs[i]; i++) {
+ c = add_cert_to_cache(td, certs[i]);
+ if (c == NULL) {
+ return PR_FAILURE;
+ } else {
+ certs[i] = c;
+ }
+ }
+ return PR_SUCCESS;
+}
+
+static NSSCertificate **
+collect_subject_certs(
+ nssList *subjectList,
+ nssList *rvCertListOpt)
+{
+ NSSCertificate *c;
+ NSSCertificate **rvArray = NULL;
+ PRUint32 count;
+ nssCertificateList_AddReferences(subjectList);
+ if (rvCertListOpt) {
+ nssListIterator *iter = nssList_CreateIterator(subjectList);
+ if (!iter) {
+ return (NSSCertificate **)NULL;
+ }
+ for (c = (NSSCertificate *)nssListIterator_Start(iter);
+ c != (NSSCertificate *)NULL;
+ c = (NSSCertificate *)nssListIterator_Next(iter)) {
+ nssList_Add(rvCertListOpt, c);
+ }
+ nssListIterator_Finish(iter);
+ nssListIterator_Destroy(iter);
+ } else {
+ count = nssList_Count(subjectList);
+ rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
+ if (!rvArray) {
+ return (NSSCertificate **)NULL;
+ }
+ nssList_GetArray(subjectList, (void **)rvArray, count);
+ }
+ return rvArray;
+}
+
+/*
+ * Find all cached certs with this subject.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_GetCertsForSubjectFromCache(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ nssList *certListOpt)
+{
+ NSSCertificate **rvArray = NULL;
+ cache_entry *ce;
+#ifdef DEBUG_CACHE
+ log_item_dump("looking for cert by subject", subject);
+#endif
+ PZ_Lock(td->cache->lock);
+ ce = (cache_entry *)nssHash_Lookup(td->cache->subject, subject);
+ if (ce) {
+ ce->hits++;
+ ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+ rvArray = collect_subject_certs(ce->entry.list, certListOpt);
+ }
+ PZ_Unlock(td->cache->lock);
+ return rvArray;
+}
+
+/*
+ * Find all cached certs with this label.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_GetCertsForNicknameFromCache(
+ NSSTrustDomain *td,
+ const NSSUTF8 *nickname,
+ nssList *certListOpt)
+{
+ NSSCertificate **rvArray = NULL;
+ cache_entry *ce;
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by nick %s", nickname));
+#endif
+ PZ_Lock(td->cache->lock);
+ ce = (cache_entry *)nssHash_Lookup(td->cache->nickname, nickname);
+ if (ce) {
+ ce->hits++;
+ ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+ rvArray = collect_subject_certs(ce->entry.list, certListOpt);
+ }
+ PZ_Unlock(td->cache->lock);
+ return rvArray;
+}
+
+/*
+ * Find all cached certs with this email address.
+ */
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_GetCertsForEmailAddressFromCache(
+ NSSTrustDomain *td,
+ NSSASCII7 *email,
+ nssList *certListOpt)
+{
+ NSSCertificate **rvArray = NULL;
+ cache_entry *ce;
+ nssList *collectList = NULL;
+ nssListIterator *iter = NULL;
+ nssList *subjectList;
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by email %s", email));
+#endif
+ PZ_Lock(td->cache->lock);
+ ce = (cache_entry *)nssHash_Lookup(td->cache->email, email);
+ if (ce) {
+ ce->hits++;
+ ce->lastHit = PR_Now();
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+ /* loop over subject lists and get refs for certs */
+ if (certListOpt) {
+ collectList = certListOpt;
+ } else {
+ collectList = nssList_Create(NULL, PR_FALSE);
+ if (!collectList) {
+ PZ_Unlock(td->cache->lock);
+ return NULL;
+ }
+ }
+ iter = nssList_CreateIterator(ce->entry.list);
+ if (!iter) {
+ PZ_Unlock(td->cache->lock);
+ if (!certListOpt) {
+ nssList_Destroy(collectList);
+ }
+ return NULL;
+ }
+ for (subjectList = (nssList *)nssListIterator_Start(iter);
+ subjectList != (nssList *)NULL;
+ subjectList = (nssList *)nssListIterator_Next(iter)) {
+ (void)collect_subject_certs(subjectList, collectList);
+ }
+ nssListIterator_Finish(iter);
+ nssListIterator_Destroy(iter);
+ }
+ PZ_Unlock(td->cache->lock);
+ if (!certListOpt && collectList) {
+ PRUint32 count = nssList_Count(collectList);
+ rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
+ if (rvArray) {
+ nssList_GetArray(collectList, (void **)rvArray, count);
+ }
+ nssList_Destroy(collectList);
+ }
+ return rvArray;
+}
+
+/*
+ * Look for a specific cert in the cache
+ */
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_GetCertForIssuerAndSNFromCache(
+ NSSTrustDomain *td,
+ NSSDER *issuer,
+ NSSDER *serial)
+{
+ NSSCertificate certkey;
+ NSSCertificate *rvCert = NULL;
+ cache_entry *ce;
+ certkey.issuer.data = issuer->data;
+ certkey.issuer.size = issuer->size;
+ certkey.serial.data = serial->data;
+ certkey.serial.size = serial->size;
+#ifdef DEBUG_CACHE
+ log_item_dump("looking for cert by issuer/sn, issuer", issuer);
+ log_item_dump(" serial", serial);
+#endif
+ PZ_Lock(td->cache->lock);
+ ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, &certkey);
+ if (ce) {
+ ce->hits++;
+ ce->lastHit = PR_Now();
+ rvCert = nssCertificate_AddRef(ce->entry.cert);
+#ifdef DEBUG_CACHE
+ PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
+#endif
+ }
+ PZ_Unlock(td->cache->lock);
+ return rvCert;
+}
+
+/*
+ * Look for a specific cert in the cache
+ */
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_GetCertByDERFromCache(
+ NSSTrustDomain *td,
+ NSSDER *der)
+{
+ PRStatus nssrv = PR_FAILURE;
+ NSSDER issuer, serial;
+ NSSCertificate *rvCert;
+ nssrv = nssPKIX509_GetIssuerAndSerialFromDER(der, &issuer, &serial);
+ if (nssrv != PR_SUCCESS) {
+ return NULL;
+ }
+#ifdef DEBUG_CACHE
+ log_item_dump("looking for cert by DER", der);
+#endif
+ rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td,
+ &issuer, &serial);
+ PORT_Free(issuer.data);
+ PORT_Free(serial.data);
+ return rvCert;
+}
+
+static void
+cert_iter(const void *k, void *v, void *a)
+{
+ nssList *certList = (nssList *)a;
+ NSSCertificate *c = (NSSCertificate *)k;
+ nssList_Add(certList, nssCertificate_AddRef(c));
+}
+
+NSS_EXTERN NSSCertificate **
+nssTrustDomain_GetCertsFromCache(
+ NSSTrustDomain *td,
+ nssList *certListOpt)
+{
+ NSSCertificate **rvArray = NULL;
+ nssList *certList;
+ if (certListOpt) {
+ certList = certListOpt;
+ } else {
+ certList = nssList_Create(NULL, PR_FALSE);
+ if (!certList) {
+ return NULL;
+ }
+ }
+ PZ_Lock(td->cache->lock);
+ nssHash_Iterate(td->cache->issuerAndSN, cert_iter, (void *)certList);
+ PZ_Unlock(td->cache->lock);
+ if (!certListOpt) {
+ PRUint32 count = nssList_Count(certList);
+ rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
+ nssList_GetArray(certList, (void **)rvArray, count);
+ /* array takes the references */
+ nssList_Destroy(certList);
+ }
+ return rvArray;
+}
+
+NSS_IMPLEMENT void
+nssTrustDomain_DumpCacheInfo(
+ NSSTrustDomain *td,
+ void (*cert_dump_iter)(const void *, void *, void *),
+ void *arg)
+{
+ PZ_Lock(td->cache->lock);
+ nssHash_Iterate(td->cache->issuerAndSN, cert_dump_iter, arg);
+ PZ_Unlock(td->cache->lock);
+}
diff --git a/security/nss/lib/pki/trustdomain.c b/security/nss/lib/pki/trustdomain.c
new file mode 100644
index 0000000000..fc3b0f0da8
--- /dev/null
+++ b/security/nss/lib/pki/trustdomain.c
@@ -0,0 +1,1230 @@
+/* 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 DEV_H
+#include "dev.h"
+#endif /* DEV_H */
+
+#ifndef PKIM_H
+#include "pkim.h"
+#endif /* PKIM_H */
+
+#include "cert.h"
+#include "dev3hack.h"
+#include "pki3hack.h"
+#include "pk11pub.h"
+#include "nssrwlk.h"
+#include "pk11priv.h"
+
+#define NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE 32
+
+extern const NSSError NSS_ERROR_NOT_FOUND;
+
+typedef PRUint32 nssUpdateLevel;
+
+NSS_IMPLEMENT NSSTrustDomain *
+NSSTrustDomain_Create(
+ NSSUTF8 *moduleOpt,
+ NSSUTF8 *uriOpt,
+ NSSUTF8 *opaqueOpt,
+ void *reserved)
+{
+ NSSArena *arena;
+ NSSTrustDomain *rvTD;
+ arena = NSSArena_Create();
+ if (!arena) {
+ return (NSSTrustDomain *)NULL;
+ }
+ rvTD = nss_ZNEW(arena, NSSTrustDomain);
+ if (!rvTD) {
+ goto loser;
+ }
+ /* protect the token list and the token iterator */
+ rvTD->tokensLock = NSSRWLock_New(100, "tokens");
+ if (!rvTD->tokensLock) {
+ goto loser;
+ }
+ nssTrustDomain_InitializeCache(rvTD, NSSTRUSTDOMAIN_DEFAULT_CACHE_SIZE);
+ rvTD->arena = arena;
+ rvTD->refCount = 1;
+ rvTD->statusConfig = NULL;
+ return rvTD;
+loser:
+ if (rvTD && rvTD->tokensLock) {
+ NSSRWLock_Destroy(rvTD->tokensLock);
+ }
+ nssArena_Destroy(arena);
+ return (NSSTrustDomain *)NULL;
+}
+
+static void
+token_destructor(void *t)
+{
+ NSSToken *tok = (NSSToken *)t;
+ /* Remove the token list's reference to the token */
+ (void)nssToken_Destroy(tok);
+
+ /* Signal that the slot should not give out any more references to the
+ * token. The token might still have a positive refcount after this call.
+ * The token has a reference to the slot, so the slot will not be destroyed
+ * until after the token's refcount drops to 0. */
+ PK11Slot_SetNSSToken(tok->pk11slot, NULL);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_Destroy(
+ NSSTrustDomain *td)
+{
+ PRStatus status = PR_SUCCESS;
+ if (--td->refCount == 0) {
+ /* Destroy each token in the list of tokens */
+ if (td->tokens) {
+ nssListIterator_Destroy(td->tokens);
+ td->tokens = NULL;
+ }
+ if (td->tokenList) {
+ nssList_Clear(td->tokenList, token_destructor);
+ nssList_Destroy(td->tokenList);
+ td->tokenList = NULL;
+ }
+ NSSRWLock_Destroy(td->tokensLock);
+ td->tokensLock = NULL;
+ status = nssTrustDomain_DestroyCache(td);
+ if (status == PR_FAILURE) {
+ return status;
+ }
+ if (td->statusConfig) {
+ td->statusConfig->statusDestroy(td->statusConfig);
+ td->statusConfig = NULL;
+ }
+ /* Destroy the trust domain */
+ nssArena_Destroy(td->arena);
+ }
+ return status;
+}
+
+/* XXX uses tokens until slot list is in place */
+static NSSSlot **
+nssTrustDomain_GetActiveSlots(
+ NSSTrustDomain *td,
+ nssUpdateLevel *updateLevel)
+{
+ PRUint32 count;
+ NSSSlot **slots = NULL;
+ NSSToken **tp, **tokens;
+ *updateLevel = 1;
+ if (!td->tokenList) {
+ return NULL;
+ }
+ NSSRWLock_LockRead(td->tokensLock);
+ count = nssList_Count(td->tokenList);
+ tokens = nss_ZNEWARRAY(NULL, NSSToken *, count + 1);
+ if (!tokens) {
+ NSSRWLock_UnlockRead(td->tokensLock);
+ return NULL;
+ }
+ slots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
+ if (!slots) {
+ NSSRWLock_UnlockRead(td->tokensLock);
+ nss_ZFreeIf(tokens);
+ return NULL;
+ }
+ nssList_GetArray(td->tokenList, (void **)tokens, count);
+ count = 0;
+ for (tp = tokens; *tp; tp++) {
+ NSSSlot *slot = nssToken_GetSlot(*tp);
+ if (!PK11_IsDisabled(slot->pk11slot)) {
+ slots[count++] = slot;
+ } else {
+ nssSlot_Destroy(slot);
+ }
+ }
+ NSSRWLock_UnlockRead(td->tokensLock);
+ nss_ZFreeIf(tokens);
+ if (!count) {
+ nss_ZFreeIf(slots);
+ slots = NULL;
+ }
+ return slots;
+}
+
+/* XXX */
+static nssSession *
+nssTrustDomain_GetSessionForToken(
+ NSSTrustDomain *td,
+ NSSToken *token)
+{
+ return nssToken_GetDefaultSession(token);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_SetDefaultCallback(
+ NSSTrustDomain *td,
+ NSSCallback *newCallback,
+ NSSCallback **oldCallbackOpt)
+{
+ if (oldCallbackOpt) {
+ *oldCallbackOpt = td->defaultCallback;
+ }
+ td->defaultCallback = newCallback;
+ return PR_SUCCESS;
+}
+
+NSS_IMPLEMENT NSSCallback *
+nssTrustDomain_GetDefaultCallback(
+ NSSTrustDomain *td,
+ PRStatus *statusOpt)
+{
+ if (statusOpt) {
+ *statusOpt = PR_SUCCESS;
+ }
+ return td->defaultCallback;
+}
+
+NSS_IMPLEMENT NSSCallback *
+NSSTrustDomain_GetDefaultCallback(
+ NSSTrustDomain *td,
+ PRStatus *statusOpt)
+{
+ return nssTrustDomain_GetDefaultCallback(td, statusOpt);
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_LoadModule(
+ NSSTrustDomain *td,
+ NSSUTF8 *moduleOpt,
+ NSSUTF8 *uriOpt,
+ NSSUTF8 *opaqueOpt,
+ void *reserved)
+{
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_DisableToken(
+ NSSTrustDomain *td,
+ NSSToken *token,
+ NSSError why)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_EnableToken(
+ NSSTrustDomain *td,
+ NSSToken *token)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_IsTokenEnabled(
+ NSSTrustDomain *td,
+ NSSToken *token,
+ NSSError *whyOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSSlot *
+NSSTrustDomain_FindSlotByName(
+ NSSTrustDomain *td,
+ NSSUTF8 *slotName)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSToken **
+NSSTrustDomain_FindTokensByURI(
+ NSSTrustDomain *td,
+ PK11URI *uri)
+{
+ NSSToken *tok = NULL;
+ PK11SlotInfo *slotinfo;
+ NSSToken **tokens;
+ int count, i = 0;
+
+ NSSRWLock_LockRead(td->tokensLock);
+ count = nssList_Count(td->tokenList);
+ tokens = nss_ZNEWARRAY(NULL, NSSToken *, count + 1);
+ if (!tokens) {
+ return NULL;
+ }
+ for (tok = (NSSToken *)nssListIterator_Start(td->tokens);
+ tok != (NSSToken *)NULL;
+ tok = (NSSToken *)nssListIterator_Next(td->tokens)) {
+ if (nssToken_IsPresent(tok)) {
+ slotinfo = tok->pk11slot;
+ if (pk11_MatchUriTokenInfo(slotinfo, uri))
+ tokens[i++] = nssToken_AddRef(tok);
+ }
+ }
+ tokens[i] = NULL;
+ nssListIterator_Finish(td->tokens);
+ NSSRWLock_UnlockRead(td->tokensLock);
+ return tokens;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindTokenByName(
+ NSSTrustDomain *td,
+ NSSUTF8 *tokenName)
+{
+ PRStatus nssrv;
+ NSSUTF8 *myName;
+ NSSToken *tok = NULL;
+ NSSRWLock_LockRead(td->tokensLock);
+ for (tok = (NSSToken *)nssListIterator_Start(td->tokens);
+ tok != (NSSToken *)NULL;
+ tok = (NSSToken *)nssListIterator_Next(td->tokens)) {
+ if (nssToken_IsPresent(tok)) {
+ myName = nssToken_GetName(tok);
+ if (nssUTF8_Equal(tokenName, myName, &nssrv)) {
+ tok = nssToken_AddRef(tok);
+ break;
+ }
+ }
+ }
+ nssListIterator_Finish(td->tokens);
+ NSSRWLock_UnlockRead(td->tokensLock);
+ return tok;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindTokenBySlotName(
+ NSSTrustDomain *td,
+ NSSUTF8 *slotName)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindTokenForAlgorithm(
+ NSSTrustDomain *td,
+ NSSOID *algorithm)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSToken *
+NSSTrustDomain_FindBestTokenForAlgorithms(
+ NSSTrustDomain *td,
+ NSSOID *algorithms[], /* may be null-terminated */
+ PRUint32 nAlgorithmsOpt /* limits the array if nonzero */
+)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_Login(
+ NSSTrustDomain *td,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_Logout(NSSTrustDomain *td)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_ImportCertificate(
+ NSSTrustDomain *td,
+ NSSCertificate *c)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_ImportPKIXCertificate(
+ NSSTrustDomain *td,
+ /* declared as a struct until these "data types" are defined */
+ struct NSSPKIXCertificateStr *pc)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_ImportEncodedCertificate(
+ NSSTrustDomain *td,
+ NSSBER *ber)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_ImportEncodedCertificateChain(
+ NSSTrustDomain *td,
+ NSSBER *ber,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSPrivateKey *
+NSSTrustDomain_ImportEncodedPrivateKey(
+ NSSTrustDomain *td,
+ NSSBER *ber,
+ NSSItem *passwordOpt, /* NULL will cause a callback */
+ NSSCallback *uhhOpt,
+ NSSToken *destination)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSPublicKey *
+NSSTrustDomain_ImportEncodedPublicKey(
+ NSSTrustDomain *td,
+ NSSBER *ber)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+static NSSCertificate **
+get_certs_from_list(nssList *list)
+{
+ PRUint32 count = nssList_Count(list);
+ NSSCertificate **certs = NULL;
+ if (count > 0) {
+ certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
+ if (certs) {
+ nssList_GetArray(list, (void **)certs, count);
+ }
+ }
+ return certs;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_FindCertificatesByNickname(
+ NSSTrustDomain *td,
+ const NSSUTF8 *name,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ NSSToken *token = NULL;
+ NSSSlot **slots = NULL;
+ NSSSlot **slotp;
+ NSSCertificate **rvCerts = NULL;
+ nssPKIObjectCollection *collection = NULL;
+ nssUpdateLevel updateLevel;
+ nssList *nameList;
+ PRUint32 numRemaining = maximumOpt;
+ PRUint32 collectionCount = 0;
+ PRUint32 errors = 0;
+
+ /* First, grab from the cache */
+ nameList = nssList_Create(NULL, PR_FALSE);
+ if (!nameList) {
+ return NULL;
+ }
+ (void)nssTrustDomain_GetCertsForNicknameFromCache(td, name, nameList);
+ rvCerts = get_certs_from_list(nameList);
+ /* initialize the collection of token certificates with the set of
+ * cached certs (if any).
+ */
+ collection = nssCertificateCollection_Create(td, rvCerts);
+ nssCertificateArray_Destroy(rvCerts);
+ nssList_Destroy(nameList);
+ if (!collection) {
+ return (NSSCertificate **)NULL;
+ }
+ /* obtain the current set of active slots in the trust domain */
+ slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+ if (!slots) {
+ goto loser;
+ }
+ /* iterate over the slots */
+ for (slotp = slots; *slotp; slotp++) {
+ token = nssSlot_GetToken(*slotp);
+ if (token) {
+ nssSession *session;
+ nssCryptokiObject **instances = NULL;
+ nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+ PRStatus status = PR_FAILURE;
+
+ session = nssTrustDomain_GetSessionForToken(td, token);
+ if (session) {
+ instances = nssToken_FindCertificatesByNickname(token,
+ session,
+ name,
+ tokenOnly,
+ numRemaining,
+ &status);
+ }
+ (void)nssToken_Destroy(token);
+ if (status != PR_SUCCESS) {
+ errors++;
+ continue;
+ }
+ if (instances) {
+ status = nssPKIObjectCollection_AddInstances(collection,
+ instances, 0);
+ nss_ZFreeIf(instances);
+ if (status != PR_SUCCESS) {
+ errors++;
+ continue;
+ }
+ collectionCount = nssPKIObjectCollection_Count(collection);
+ if (maximumOpt > 0) {
+ if (collectionCount >= maximumOpt)
+ break;
+ numRemaining = maximumOpt - collectionCount;
+ }
+ }
+ }
+ }
+ if (!collectionCount && errors)
+ goto loser;
+ /* Grab the certs collected in the search. */
+ rvCerts = nssPKIObjectCollection_GetCertificates(collection,
+ rvOpt, maximumOpt,
+ arenaOpt);
+ /* clean up */
+ nssPKIObjectCollection_Destroy(collection);
+ nssSlotArray_Destroy(slots);
+ return rvCerts;
+loser:
+ if (slots) {
+ nssSlotArray_Destroy(slots);
+ }
+ if (collection) {
+ nssPKIObjectCollection_Destroy(collection);
+ }
+ return (NSSCertificate **)NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesByNickname(
+ NSSTrustDomain *td,
+ NSSUTF8 *name,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ return nssTrustDomain_FindCertificatesByNickname(td,
+ name,
+ rvOpt,
+ maximumOpt,
+ arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindBestCertificateByNickname(
+ NSSTrustDomain *td,
+ const NSSUTF8 *name,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ NSSCertificate **nicknameCerts;
+ NSSCertificate *rvCert = NULL;
+ nicknameCerts = nssTrustDomain_FindCertificatesByNickname(td, name,
+ NULL,
+ 0,
+ NULL);
+ if (nicknameCerts) {
+ rvCert = nssCertificateArray_FindBestCertificate(nicknameCerts,
+ timeOpt,
+ usage,
+ policiesOpt);
+ nssCertificateArray_Destroy(nicknameCerts);
+ }
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNickname(
+ NSSTrustDomain *td,
+ const NSSUTF8 *name,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ return nssTrustDomain_FindBestCertificateByNickname(td,
+ name,
+ timeOpt,
+ usage,
+ policiesOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate **
+nssTrustDomain_FindCertificatesBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ NSSToken *token = NULL;
+ NSSSlot **slots = NULL;
+ NSSSlot **slotp;
+ NSSCertificate **rvCerts = NULL;
+ nssPKIObjectCollection *collection = NULL;
+ nssUpdateLevel updateLevel;
+ nssList *subjectList;
+ PRUint32 numRemaining = maximumOpt;
+ PRUint32 collectionCount = 0;
+ PRUint32 errors = 0;
+
+ /* look in cache */
+ subjectList = nssList_Create(NULL, PR_FALSE);
+ if (!subjectList) {
+ return NULL;
+ }
+ (void)nssTrustDomain_GetCertsForSubjectFromCache(td, subject, subjectList);
+ rvCerts = get_certs_from_list(subjectList);
+ collection = nssCertificateCollection_Create(td, rvCerts);
+ nssCertificateArray_Destroy(rvCerts);
+ nssList_Destroy(subjectList);
+ if (!collection) {
+ return (NSSCertificate **)NULL;
+ }
+ slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+ if (!slots) {
+ goto loser;
+ }
+ for (slotp = slots; *slotp; slotp++) {
+ token = nssSlot_GetToken(*slotp);
+ if (token) {
+ nssSession *session;
+ nssCryptokiObject **instances = NULL;
+ nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+ PRStatus status = PR_FAILURE;
+
+ session = nssTrustDomain_GetSessionForToken(td, token);
+ if (session) {
+ instances = nssToken_FindCertificatesBySubject(token,
+ session,
+ subject,
+ tokenOnly,
+ numRemaining,
+ &status);
+ }
+ (void)nssToken_Destroy(token);
+ if (status != PR_SUCCESS) {
+ errors++;
+ continue;
+ }
+ if (instances) {
+ status = nssPKIObjectCollection_AddInstances(collection,
+ instances, 0);
+ nss_ZFreeIf(instances);
+ if (status != PR_SUCCESS) {
+ errors++;
+ continue;
+ }
+ collectionCount = nssPKIObjectCollection_Count(collection);
+ if (maximumOpt > 0) {
+ if (collectionCount >= maximumOpt)
+ break;
+ numRemaining = maximumOpt - collectionCount;
+ }
+ }
+ }
+ }
+ if (!collectionCount && errors)
+ goto loser;
+ rvCerts = nssPKIObjectCollection_GetCertificates(collection,
+ rvOpt, maximumOpt,
+ arenaOpt);
+ nssPKIObjectCollection_Destroy(collection);
+ nssSlotArray_Destroy(slots);
+ return rvCerts;
+loser:
+ if (slots) {
+ nssSlotArray_Destroy(slots);
+ }
+ if (collection) {
+ nssPKIObjectCollection_Destroy(collection);
+ }
+ return (NSSCertificate **)NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt,
+ NSSArena *arenaOpt)
+{
+ return nssTrustDomain_FindCertificatesBySubject(td,
+ subject,
+ rvOpt,
+ maximumOpt,
+ arenaOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindBestCertificateBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ NSSCertificate **subjectCerts;
+ NSSCertificate *rvCert = NULL;
+ subjectCerts = nssTrustDomain_FindCertificatesBySubject(td, subject,
+ NULL,
+ 0,
+ NULL);
+ if (subjectCerts) {
+ rvCert = nssCertificateArray_FindBestCertificate(subjectCerts,
+ timeOpt,
+ usage,
+ policiesOpt);
+ nssCertificateArray_Destroy(subjectCerts);
+ }
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ return nssTrustDomain_FindBestCertificateBySubject(td,
+ subject,
+ timeOpt,
+ usage,
+ policiesOpt);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateByNameComponents(
+ NSSTrustDomain *td,
+ NSSUTF8 *nameComponents,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesByNameComponents(
+ NSSTrustDomain *td,
+ NSSUTF8 *nameComponents,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+/* This returns at most a single certificate, so it can stop the loop
+ * when one is found.
+ */
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindCertificateByIssuerAndSerialNumber(
+ NSSTrustDomain *td,
+ NSSDER *issuer,
+ NSSDER *serial)
+{
+ NSSSlot **slots = NULL;
+ NSSSlot **slotp;
+ NSSCertificate *rvCert = NULL;
+ nssPKIObjectCollection *collection = NULL;
+ nssUpdateLevel updateLevel;
+
+ /* see if this search is already cached */
+ rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td,
+ issuer,
+ serial);
+ if (rvCert) {
+ return rvCert;
+ }
+ slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+ if (slots) {
+ for (slotp = slots; *slotp; slotp++) {
+ NSSToken *token = nssSlot_GetToken(*slotp);
+ nssSession *session;
+ nssCryptokiObject *instance;
+ nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+ PRStatus status = PR_FAILURE;
+
+ if (!token)
+ continue;
+ session = nssTrustDomain_GetSessionForToken(td, token);
+ if (session) {
+ instance = nssToken_FindCertificateByIssuerAndSerialNumber(
+ token,
+ session,
+ issuer,
+ serial,
+ tokenOnly,
+ &status);
+ }
+ (void)nssToken_Destroy(token);
+ if (status != PR_SUCCESS) {
+ continue;
+ }
+ if (instance) {
+ if (!collection) {
+ collection = nssCertificateCollection_Create(td, NULL);
+ if (!collection) {
+ break; /* don't keep looping if out if memory */
+ }
+ }
+ status = nssPKIObjectCollection_AddInstances(collection,
+ &instance, 1);
+ if (status == PR_SUCCESS) {
+ (void)nssPKIObjectCollection_GetCertificates(
+ collection, &rvCert, 1, NULL);
+ }
+ if (rvCert) {
+ break; /* found one cert, all done */
+ }
+ }
+ }
+ }
+ if (collection) {
+ nssPKIObjectCollection_Destroy(collection);
+ }
+ if (slots) {
+ nssSlotArray_Destroy(slots);
+ }
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
+ NSSTrustDomain *td,
+ NSSDER *issuer,
+ NSSDER *serial)
+{
+ return nssTrustDomain_FindCertificateByIssuerAndSerialNumber(td,
+ issuer,
+ serial);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+nssTrustDomain_FindCertificateByEncodedCertificate(
+ NSSTrustDomain *td,
+ NSSBER *ber)
+{
+ PRStatus status;
+ NSSCertificate *rvCert = NULL;
+ NSSDER issuer = { 0 };
+ NSSDER serial = { 0 };
+ /* XXX this is not generic... will any cert crack into issuer/serial? */
+ status = nssPKIX509_GetIssuerAndSerialFromDER(ber, &issuer, &serial);
+ if (status != PR_SUCCESS) {
+ return NULL;
+ }
+ rvCert = nssTrustDomain_FindCertificateByIssuerAndSerialNumber(td,
+ &issuer,
+ &serial);
+ PORT_Free(issuer.data);
+ PORT_Free(serial.data);
+ return rvCert;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindCertificateByEncodedCertificate(
+ NSSTrustDomain *td,
+ NSSBER *ber)
+{
+ return nssTrustDomain_FindCertificateByEncodedCertificate(td, ber);
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestCertificateByEmail(
+ NSSTrustDomain *td,
+ NSSASCII7 *email,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ return 0;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindCertificatesByEmail(
+ NSSTrustDomain *td,
+ NSSASCII7 *email,
+ NSSCertificate *rvOpt[],
+ PRUint32 maximumOpt, /* 0 for no max */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindCertificateByOCSPHash(
+ NSSTrustDomain *td,
+ NSSItem *hash)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestUserCertificate(
+ NSSTrustDomain *td,
+ NSSTime *timeOpt,
+ NSSUsage *usage,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindUserCertificates(
+ NSSTrustDomain *td,
+ NSSTime *timeOpt,
+ NSSUsage *usageOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForSSLClientAuth(
+ NSSTrustDomain *td,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForSSLClientAuth(
+ NSSTrustDomain *td,
+ NSSUTF8 *sslHostOpt,
+ NSSDER *rootCAsOpt[], /* null pointer for none */
+ PRUint32 rootCAsMaxOpt, /* zero means list is null-terminated */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate *
+NSSTrustDomain_FindBestUserCertificateForEmailSigning(
+ NSSTrustDomain *td,
+ NSSASCII7 *signerOpt,
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCertificate **
+NSSTrustDomain_FindUserCertificatesForEmailSigning(
+ NSSTrustDomain *td,
+ NSSASCII7 *signerOpt,
+ NSSASCII7 *recipientOpt,
+ /* anything more here? */
+ NSSAlgorithmAndParameters *apOpt,
+ NSSPolicies *policiesOpt,
+ NSSCertificate **rvOpt,
+ PRUint32 rvLimit, /* zero for no limit */
+ NSSArena *arenaOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+static PRStatus
+collector(nssCryptokiObject *instance, void *arg)
+{
+ nssPKIObjectCollection *collection = (nssPKIObjectCollection *)arg;
+ return nssPKIObjectCollection_AddInstanceAsObject(collection, instance);
+}
+
+NSS_IMPLEMENT PRStatus *
+NSSTrustDomain_TraverseCertificates(
+ NSSTrustDomain *td,
+ PRStatus (*callback)(NSSCertificate *c, void *arg),
+ void *arg)
+{
+ NSSToken *token = NULL;
+ NSSSlot **slots = NULL;
+ NSSSlot **slotp;
+ nssPKIObjectCollection *collection = NULL;
+ nssPKIObjectCallback pkiCallback;
+ nssUpdateLevel updateLevel;
+ NSSCertificate **cached = NULL;
+ nssList *certList;
+
+ certList = nssList_Create(NULL, PR_FALSE);
+ if (!certList)
+ return NULL;
+ (void)nssTrustDomain_GetCertsFromCache(td, certList);
+ cached = get_certs_from_list(certList);
+ collection = nssCertificateCollection_Create(td, cached);
+ nssCertificateArray_Destroy(cached);
+ nssList_Destroy(certList);
+ if (!collection) {
+ return (PRStatus *)NULL;
+ }
+ /* obtain the current set of active slots in the trust domain */
+ slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+ if (!slots) {
+ goto loser;
+ }
+ /* iterate over the slots */
+ for (slotp = slots; *slotp; slotp++) {
+ /* get the token for the slot, if present */
+ token = nssSlot_GetToken(*slotp);
+ if (token) {
+ nssSession *session;
+ nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+ /* get a session for the token */
+ session = nssTrustDomain_GetSessionForToken(td, token);
+ if (session) {
+ /* perform the traversal */
+ (void)nssToken_TraverseCertificates(token,
+ session,
+ tokenOnly,
+ collector,
+ collection);
+ }
+ (void)nssToken_Destroy(token);
+ }
+ }
+
+ /* Traverse the collection */
+ pkiCallback.func.cert = callback;
+ pkiCallback.arg = arg;
+ (void)nssPKIObjectCollection_Traverse(collection, &pkiCallback);
+loser:
+ if (slots) {
+ nssSlotArray_Destroy(slots);
+ }
+ if (collection) {
+ nssPKIObjectCollection_Destroy(collection);
+ }
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSTrust *
+nssTrustDomain_FindTrustForCertificate(
+ NSSTrustDomain *td,
+ NSSCertificate *c)
+{
+ NSSSlot **slots;
+ NSSSlot **slotp;
+ nssCryptokiObject *to = NULL;
+ nssPKIObject *pkio = NULL;
+ NSSTrust *rvt = NULL;
+ nssUpdateLevel updateLevel;
+ slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+ if (!slots) {
+ return (NSSTrust *)NULL;
+ }
+ for (slotp = slots; *slotp; slotp++) {
+ NSSToken *token = nssSlot_GetToken(*slotp);
+
+ if (token) {
+ to = nssToken_FindTrustForCertificate(token, NULL,
+ &c->encoding,
+ &c->issuer,
+ &c->serial,
+ nssTokenSearchType_TokenOnly);
+ if (to) {
+ PRStatus status;
+ if (!pkio) {
+ pkio = nssPKIObject_Create(NULL, to, td, NULL, nssPKILock);
+ status = pkio ? PR_SUCCESS : PR_FAILURE;
+ } else {
+ status = nssPKIObject_AddInstance(pkio, to);
+ }
+ if (status != PR_SUCCESS) {
+ nssCryptokiObject_Destroy(to);
+ }
+ }
+ (void)nssToken_Destroy(token);
+ }
+ }
+ if (pkio) {
+ rvt = nssTrust_Create(pkio, &c->encoding);
+ if (rvt) {
+ pkio = NULL; /* rvt object now owns the pkio reference */
+ }
+ }
+ nssSlotArray_Destroy(slots);
+ if (pkio) {
+ nssPKIObject_Destroy(pkio);
+ }
+ return rvt;
+}
+
+NSS_IMPLEMENT NSSCRL **
+nssTrustDomain_FindCRLsBySubject(
+ NSSTrustDomain *td,
+ NSSDER *subject)
+{
+ NSSSlot **slots;
+ NSSSlot **slotp;
+ NSSToken *token;
+ nssUpdateLevel updateLevel;
+ nssPKIObjectCollection *collection;
+ NSSCRL **rvCRLs = NULL;
+ collection = nssCRLCollection_Create(td, NULL);
+ if (!collection) {
+ return (NSSCRL **)NULL;
+ }
+ slots = nssTrustDomain_GetActiveSlots(td, &updateLevel);
+ if (!slots) {
+ goto loser;
+ }
+ for (slotp = slots; *slotp; slotp++) {
+ token = nssSlot_GetToken(*slotp);
+ if (token) {
+ PRStatus status = PR_FAILURE;
+ nssSession *session;
+ nssCryptokiObject **instances = NULL;
+ nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
+
+ /* get a session for the token */
+ session = nssTrustDomain_GetSessionForToken(td, token);
+ if (session) {
+ /* perform the traversal */
+ instances = nssToken_FindCRLsBySubject(token, session, subject,
+ tokenOnly, 0, &status);
+ }
+ (void)nssToken_Destroy(token);
+ if (status == PR_SUCCESS) {
+ /* add the found CRL's to the collection */
+ status = nssPKIObjectCollection_AddInstances(collection,
+ instances, 0);
+ }
+ nss_ZFreeIf(instances);
+ }
+ }
+ rvCRLs = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL);
+loser:
+ nssPKIObjectCollection_Destroy(collection);
+ nssSlotArray_Destroy(slots);
+ return rvCRLs;
+}
+
+NSS_IMPLEMENT PRStatus
+NSSTrustDomain_GenerateKeyPair(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap,
+ NSSPrivateKey **pvkOpt,
+ NSSPublicKey **pbkOpt,
+ PRBool privateKeyIsSensitive,
+ NSSToken *destination,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return PR_FAILURE;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKey(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap,
+ PRUint32 keysize,
+ NSSToken *destination,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSTrustDomain_GenerateSymmetricKeyFromPassword(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap,
+ NSSUTF8 *passwordOpt, /* if null, prompt */
+ NSSToken *destinationOpt,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSSymmetricKey *
+NSSTrustDomain_FindSymmetricKeyByAlgorithmAndKeyID(
+ NSSTrustDomain *td,
+ NSSOID *algorithm,
+ NSSItem *keyID,
+ NSSCallback *uhhOpt)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+nssTrustDomain_CreateCryptoContext(
+ NSSTrustDomain *td,
+ NSSCallback *uhhOpt)
+{
+ return nssCryptoContext_Create(td, uhhOpt);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContext(
+ NSSTrustDomain *td,
+ NSSCallback *uhhOpt)
+{
+ return nssTrustDomain_CreateCryptoContext(td, uhhOpt);
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithm(
+ NSSTrustDomain *td,
+ NSSOID *algorithm)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}
+
+NSS_IMPLEMENT NSSCryptoContext *
+NSSTrustDomain_CreateCryptoContextForAlgorithmAndParameters(
+ NSSTrustDomain *td,
+ NSSAlgorithmAndParameters *ap)
+{
+ nss_SetError(NSS_ERROR_NOT_FOUND);
+ return NULL;
+}