diff options
Diffstat (limited to '')
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 Binary files differnew file mode 100644 index 0000000000..fe1aca389a --- /dev/null +++ b/security/nss/lib/pki/doc/standiag.png 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". "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. + 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. 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. 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. + This needs to be described in a separate document showing how + to set up a token using CKFW. 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. This + is not part of the exposed API. It is a low-level API allowing +NSS to manage cryptoki devices.<br> + <br> + The relationship is like this:<br> + <br> + libpki --> libdev --> cryptoki<br> + <br> + As an example,<br> + <br> + NSSTrustDomain_FindCertificate --> NSSToken_FindCertificate --> + C_FindObjects<br> + <br> + <a href="http://lxr.mozilla.org/mozilla/ident?i=NSSModule">NSSModule</a> + <br> + Replaces the SECMOD API. The module manages a +PRLibrary that holds a cryptoki implementation via a number of slots. + 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. 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? This session would + be used for slot management calls (sections 9.5 and9.6 of PKCS#11). 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. Much of the +cryptoki API is directed towards slots. However, some functionality + clearly belongs with a token type. For example, a certificate + lives on a token, not a slot, so one would expect a function NSSToken_FindCertificate. + 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. Most + functions take a slotID as an argument, even though it is obvious that + the event is intended to occur on a token. That leaves various + possibilities:</li> + + <ol> + <li>Implement the API entirely as NSSToken. If the token is not + present, some calls will simply fail.</li> + <li>Divide the API between NSSToken and NSSSlot, as described above. + NSSSlot would handle cryptoki calls specified as "slot management", + while NSSToken handles actual token operations.</li> + <li>Others?</li> + + </ol> + <li>Session management. Tokens needs a threadsafe session handle + to perform operations. 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). For those functions, the token could + maintain a default session. Thus all NSSToken API functions would take + sessionOpt as an argument. 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. Created from a slot. Used to manage + sessions for crypto contexts. 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. The way to keep open this possibility + is to keep only generally useful information in the NSSCertificate type. + Examples would be the certificate encoding, label, trust (obtained + from cryptoki calls), an email address, etc. 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? 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." It is a collection of modules capable of performing + cryptographic operations and storing certs and keys. This collection + is managed by NSS in a manner opaque to the consumer. The slots + will have various orderings determining which has preference for a +given operation. 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? We already have the suggestion + that there be two kinds of ordering: storage and search. How +will they be constructed/managed? 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? Nelson wonders what it means to Stan + when a cert does not live on a token yet. Bob, Terry, and I discussed + this. 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). NSSCertificate would + keep a handle to this type, so that it only needs to decode the cert +once. 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). + 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. 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. Therefore, in a hash of certificates, the key is the certificate +pointer itself. One possibility is to store the decoded cert (NSSX509DecodedParts +above) as the value in the {key, value} pair. When a cert is decoded, +the cert pointer and decoding pointer are added to the hash. Subsequent +lookups have access to one or both of these pointers. 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. However, + it has already been realized that PSM and CMS may need special access to +tokens. 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. 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> + . The old NSS code had various types related to algorithms + running around in it. We had SECOidTag, SECAlgorithmID, SECItem's + for parameters, CK_MECHANISM for cryptoki, etc. 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 </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 new command line tool, pkiutil, has been created to use only + the Stan API. It depends on a new library, cmdlib, meant to replace + the old secutil library. The old library had code used by products + that needed to be integrated into the main library codebase somehow. 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. + Copy "libnssckbi.so" (or whatever it is) to cmd/pkiutil. Then + run "pkiutil -L" or "pkiutil --list". 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; +} |