summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/pki/certificate.c
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/certificate.c
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/lib/pki/certificate.c')
-rw-r--r--security/nss/lib/pki/certificate.c1101
1 files changed, 1101 insertions, 0 deletions
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;
+ }
+}