michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef NSSPKI_H michael@0: #include "nsspki.h" michael@0: #endif /* NSSPKI_H */ michael@0: michael@0: #ifndef PKIT_H michael@0: #include "pkit.h" michael@0: #endif /* PKIT_H */ michael@0: michael@0: #ifndef PKIM_H michael@0: #include "pkim.h" michael@0: #endif /* PKIM_H */ michael@0: michael@0: #ifndef DEV_H michael@0: #include "dev.h" michael@0: #endif /* DEV_H */ michael@0: michael@0: #include "pkistore.h" michael@0: michael@0: #include "pki3hack.h" michael@0: #include "pk11func.h" michael@0: #include "hasht.h" michael@0: michael@0: #ifndef BASE_H michael@0: #include "base.h" michael@0: #endif /* BASE_H */ michael@0: michael@0: extern const NSSError NSS_ERROR_NOT_FOUND; michael@0: michael@0: /* Creates a certificate from a base object */ michael@0: NSS_IMPLEMENT NSSCertificate * michael@0: nssCertificate_Create ( michael@0: nssPKIObject *object michael@0: ) michael@0: { michael@0: PRStatus status; michael@0: NSSCertificate *rvCert; michael@0: nssArenaMark * mark; michael@0: NSSArena *arena = object->arena; michael@0: PR_ASSERT(object->instances != NULL && object->numInstances > 0); michael@0: PR_ASSERT(object->lockType == nssPKIMonitor); michael@0: mark = nssArena_Mark(arena); michael@0: rvCert = nss_ZNEW(arena, NSSCertificate); michael@0: if (!rvCert) { michael@0: return (NSSCertificate *)NULL; michael@0: } michael@0: rvCert->object = *object; michael@0: /* XXX should choose instance based on some criteria */ michael@0: status = nssCryptokiCertificate_GetAttributes(object->instances[0], michael@0: NULL, /* XXX sessionOpt */ michael@0: arena, michael@0: &rvCert->type, michael@0: &rvCert->id, michael@0: &rvCert->encoding, michael@0: &rvCert->issuer, michael@0: &rvCert->serial, michael@0: &rvCert->subject); michael@0: if (status != PR_SUCCESS || michael@0: !rvCert->encoding.data || michael@0: !rvCert->encoding.size || michael@0: !rvCert->issuer.data || michael@0: !rvCert->issuer.size || michael@0: !rvCert->serial.data || michael@0: !rvCert->serial.size) { michael@0: if (mark) michael@0: nssArena_Release(arena, mark); michael@0: return (NSSCertificate *)NULL; michael@0: } michael@0: if (mark) michael@0: nssArena_Unmark(arena, mark); michael@0: return rvCert; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCertificate * michael@0: nssCertificate_AddRef ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: if (c) { michael@0: nssPKIObject_AddRef(&c->object); michael@0: } michael@0: return c; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCertificate_Destroy ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; michael@0: nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; michael@0: michael@0: if (c) { michael@0: PRUint32 i; michael@0: nssDecodedCert *dc = c->decoding; michael@0: NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); michael@0: NSSCryptoContext *cc = c->object.cryptoContext; michael@0: michael@0: PR_ASSERT(c->object.refCount > 0); michael@0: michael@0: /* --- LOCK storage --- */ michael@0: if (cc) { michael@0: nssCertificateStore_Lock(cc->certStore, &lockTrace); michael@0: } else { michael@0: nssTrustDomain_LockCertCache(td); michael@0: } michael@0: if (PR_ATOMIC_DECREMENT(&c->object.refCount) == 0) { michael@0: /* --- remove cert and UNLOCK storage --- */ michael@0: if (cc) { michael@0: nssCertificateStore_RemoveCertLOCKED(cc->certStore, c); michael@0: nssCertificateStore_Unlock(cc->certStore, &lockTrace, michael@0: &unlockTrace); michael@0: } else { michael@0: nssTrustDomain_RemoveCertFromCacheLOCKED(td, c); michael@0: nssTrustDomain_UnlockCertCache(td); michael@0: } michael@0: /* free cert data */ michael@0: for (i=0; iobject.numInstances; i++) { michael@0: nssCryptokiObject_Destroy(c->object.instances[i]); michael@0: } michael@0: nssPKIObject_DestroyLock(&c->object); michael@0: nssArena_Destroy(c->object.arena); michael@0: nssDecodedCert_Destroy(dc); michael@0: } else { michael@0: /* --- UNLOCK storage --- */ michael@0: if (cc) { michael@0: nssCertificateStore_Unlock(cc->certStore, michael@0: &lockTrace, michael@0: &unlockTrace); michael@0: } else { michael@0: nssTrustDomain_UnlockCertCache(td); michael@0: } michael@0: } michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: NSSCertificate_Destroy ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: return nssCertificate_Destroy(c); michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSDER * michael@0: nssCertificate_GetEncoding ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: if (c->encoding.size > 0 && c->encoding.data) { michael@0: return &c->encoding; michael@0: } else { michael@0: return (NSSDER *)NULL; michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSDER * michael@0: nssCertificate_GetIssuer ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: if (c->issuer.size > 0 && c->issuer.data) { michael@0: return &c->issuer; michael@0: } else { michael@0: return (NSSDER *)NULL; michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSDER * michael@0: nssCertificate_GetSerialNumber ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: if (c->serial.size > 0 && c->serial.data) { michael@0: return &c->serial; michael@0: } else { michael@0: return (NSSDER *)NULL; michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSDER * michael@0: nssCertificate_GetSubject ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: if (c->subject.size > 0 && c->subject.data) { michael@0: return &c->subject; michael@0: } else { michael@0: return (NSSDER *)NULL; michael@0: } michael@0: } michael@0: michael@0: /* Returns a copy, Caller must free using nss_ZFreeIf */ michael@0: NSS_IMPLEMENT NSSUTF8 * michael@0: nssCertificate_GetNickname ( michael@0: NSSCertificate *c, michael@0: NSSToken *tokenOpt michael@0: ) michael@0: { michael@0: return nssPKIObject_GetNicknameForToken(&c->object, tokenOpt); michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSASCII7 * michael@0: nssCertificate_GetEmailAddress ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: return c->email; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: NSSCertificate_DeleteStoredObject ( michael@0: NSSCertificate *c, michael@0: NSSCallback *uhh michael@0: ) michael@0: { michael@0: return nssPKIObject_DeleteStoredObject(&c->object, uhh, PR_TRUE); michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: NSSCertificate_Validate ( michael@0: NSSCertificate *c, michael@0: NSSTime *timeOpt, /* NULL for "now" */ michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt /* NULL for none */ michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT void ** /* void *[] */ michael@0: NSSCertificate_ValidateCompletely ( michael@0: NSSCertificate *c, michael@0: NSSTime *timeOpt, /* NULL for "now" */ michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, /* NULL for none */ michael@0: void **rvOpt, /* NULL for allocate */ michael@0: PRUint32 rvLimit, /* zero for no limit */ michael@0: NSSArena *arenaOpt /* NULL for heap */ michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: NSSCertificate_ValidateAndDiscoverUsagesAndPolicies ( michael@0: NSSCertificate *c, michael@0: NSSTime **notBeforeOutOpt, michael@0: NSSTime **notAfterOutOpt, michael@0: void *allowedUsages, michael@0: void *disallowedUsages, michael@0: void *allowedPolicies, michael@0: void *disallowedPolicies, michael@0: /* more args.. work on this fgmr */ michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSDER * michael@0: NSSCertificate_Encode ( michael@0: NSSCertificate *c, michael@0: NSSDER *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: /* Item, DER, BER are all typedefs now... */ michael@0: return nssItem_Duplicate((NSSItem *)&c->encoding, arenaOpt, rvOpt); michael@0: } michael@0: michael@0: NSS_IMPLEMENT nssDecodedCert * michael@0: nssCertificate_GetDecoding ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: nssDecodedCert* deco = NULL; michael@0: if (c->type == NSSCertificateType_PKIX) { michael@0: (void)STAN_GetCERTCertificate(c); michael@0: } michael@0: nssPKIObject_Lock(&c->object); michael@0: if (!c->decoding) { michael@0: deco = nssDecodedCert_Create(NULL, &c->encoding, c->type); michael@0: PORT_Assert(!c->decoding); michael@0: c->decoding = deco; michael@0: } else { michael@0: deco = c->decoding; michael@0: } michael@0: nssPKIObject_Unlock(&c->object); michael@0: return deco; michael@0: } michael@0: michael@0: static NSSCertificate ** michael@0: filter_subject_certs_for_id ( michael@0: NSSCertificate **subjectCerts, michael@0: void *id michael@0: ) michael@0: { michael@0: NSSCertificate **si; michael@0: nssDecodedCert *dcp; michael@0: int nextOpenSlot = 0; michael@0: int i; michael@0: nssCertIDMatch matchLevel = nssCertIDMatch_Unknown; michael@0: nssCertIDMatch match; michael@0: michael@0: /* walk the subject certs */ michael@0: for (si = subjectCerts; *si; si++) { michael@0: dcp = nssCertificate_GetDecoding(*si); michael@0: if (!dcp) { michael@0: NSSCertificate_Destroy(*si); michael@0: continue; michael@0: } michael@0: match = dcp->matchIdentifier(dcp, id); michael@0: switch (match) { michael@0: case nssCertIDMatch_Yes: michael@0: if (matchLevel == nssCertIDMatch_Unknown) { michael@0: /* we have non-definitive matches, forget them */ michael@0: for (i = 0; i < nextOpenSlot; i++) { michael@0: NSSCertificate_Destroy(subjectCerts[i]); michael@0: subjectCerts[i] = NULL; michael@0: } michael@0: nextOpenSlot = 0; michael@0: /* only keep definitive matches from now on */ michael@0: matchLevel = nssCertIDMatch_Yes; michael@0: } michael@0: /* keep the cert */ michael@0: subjectCerts[nextOpenSlot++] = *si; michael@0: break; michael@0: case nssCertIDMatch_Unknown: michael@0: if (matchLevel == nssCertIDMatch_Unknown) { michael@0: /* only have non-definitive matches so far, keep it */ michael@0: subjectCerts[nextOpenSlot++] = *si; michael@0: break; michael@0: } michael@0: /* else fall through, we have a definitive match already */ michael@0: case nssCertIDMatch_No: michael@0: default: michael@0: NSSCertificate_Destroy(*si); michael@0: *si = NULL; michael@0: } michael@0: } michael@0: subjectCerts[nextOpenSlot] = NULL; michael@0: return subjectCerts; michael@0: } michael@0: michael@0: static NSSCertificate ** michael@0: filter_certs_for_valid_issuers ( michael@0: NSSCertificate **certs michael@0: ) michael@0: { michael@0: NSSCertificate **cp; michael@0: nssDecodedCert *dcp; michael@0: int nextOpenSlot = 0; michael@0: michael@0: for (cp = certs; *cp; cp++) { michael@0: dcp = nssCertificate_GetDecoding(*cp); michael@0: if (dcp && dcp->isValidIssuer(dcp)) { michael@0: certs[nextOpenSlot++] = *cp; michael@0: } else { michael@0: NSSCertificate_Destroy(*cp); michael@0: } michael@0: } michael@0: certs[nextOpenSlot] = NULL; michael@0: return certs; michael@0: } michael@0: michael@0: static NSSCertificate * michael@0: find_cert_issuer ( michael@0: NSSCertificate *c, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSTrustDomain *td, michael@0: NSSCryptoContext *cc michael@0: ) michael@0: { michael@0: NSSArena *arena; michael@0: NSSCertificate **certs = NULL; michael@0: NSSCertificate **ccIssuers = NULL; michael@0: NSSCertificate **tdIssuers = NULL; michael@0: NSSCertificate *issuer = NULL; michael@0: michael@0: if (!cc) michael@0: cc = c->object.cryptoContext; michael@0: if (!td) michael@0: td = NSSCertificate_GetTrustDomain(c); michael@0: arena = nssArena_Create(); michael@0: if (!arena) { michael@0: return (NSSCertificate *)NULL; michael@0: } michael@0: if (cc) { michael@0: ccIssuers = nssCryptoContext_FindCertificatesBySubject(cc, michael@0: &c->issuer, michael@0: NULL, michael@0: 0, michael@0: arena); michael@0: } michael@0: if (td) michael@0: tdIssuers = nssTrustDomain_FindCertificatesBySubject(td, michael@0: &c->issuer, michael@0: NULL, michael@0: 0, michael@0: arena); michael@0: certs = nssCertificateArray_Join(ccIssuers, tdIssuers); michael@0: if (certs) { michael@0: nssDecodedCert *dc = NULL; michael@0: void *issuerID = NULL; michael@0: dc = nssCertificate_GetDecoding(c); michael@0: if (dc) { michael@0: issuerID = dc->getIssuerIdentifier(dc); michael@0: } michael@0: /* XXX review based on CERT_FindCertIssuer michael@0: * this function is not using the authCertIssuer field as a fallback michael@0: * if authority key id does not exist michael@0: */ michael@0: if (issuerID) { michael@0: certs = filter_subject_certs_for_id(certs, issuerID); michael@0: } michael@0: certs = filter_certs_for_valid_issuers(certs); michael@0: issuer = nssCertificateArray_FindBestCertificate(certs, michael@0: timeOpt, michael@0: usage, michael@0: policiesOpt); michael@0: nssCertificateArray_Destroy(certs); michael@0: } michael@0: nssArena_Destroy(arena); michael@0: return issuer; michael@0: } michael@0: michael@0: /* This function returns the built chain, as far as it gets, michael@0: ** even if/when it fails to find an issuer, and returns PR_FAILURE michael@0: */ michael@0: NSS_IMPLEMENT NSSCertificate ** michael@0: nssCertificate_BuildChain ( michael@0: NSSCertificate *c, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCertificate **rvOpt, michael@0: PRUint32 rvLimit, michael@0: NSSArena *arenaOpt, michael@0: PRStatus *statusOpt, michael@0: NSSTrustDomain *td, michael@0: NSSCryptoContext *cc michael@0: ) michael@0: { michael@0: NSSCertificate **rvChain = NULL; michael@0: NSSUsage issuerUsage = *usage; michael@0: nssPKIObjectCollection *collection = NULL; michael@0: PRUint32 rvCount = 0; michael@0: PRStatus st; michael@0: PRStatus ret = PR_SUCCESS; michael@0: michael@0: if (!c || !cc || michael@0: (!td && (td = NSSCertificate_GetTrustDomain(c)) == NULL)) { michael@0: goto loser; michael@0: } michael@0: /* bump the usage up to CA level */ michael@0: issuerUsage.nss3lookingForCA = PR_TRUE; michael@0: collection = nssCertificateCollection_Create(td, NULL); michael@0: if (!collection) michael@0: goto loser; michael@0: st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c); michael@0: if (st != PR_SUCCESS) michael@0: goto loser; michael@0: for (rvCount = 1; (!rvLimit || rvCount < rvLimit); ++rvCount) { michael@0: CERTCertificate *cCert = STAN_GetCERTCertificate(c); michael@0: if (cCert->isRoot) { michael@0: /* not including the issuer of the self-signed cert, which is, michael@0: * of course, itself michael@0: */ michael@0: break; michael@0: } michael@0: c = find_cert_issuer(c, timeOpt, &issuerUsage, policiesOpt, td, cc); michael@0: if (!c) { michael@0: ret = PR_FAILURE; michael@0: break; michael@0: } michael@0: st = nssPKIObjectCollection_AddObject(collection, (nssPKIObject *)c); michael@0: nssCertificate_Destroy(c); /* collection has it */ michael@0: if (st != PR_SUCCESS) michael@0: goto loser; michael@0: } michael@0: rvChain = nssPKIObjectCollection_GetCertificates(collection, michael@0: rvOpt, michael@0: rvLimit, michael@0: arenaOpt); michael@0: if (rvChain) { michael@0: nssPKIObjectCollection_Destroy(collection); michael@0: if (statusOpt) michael@0: *statusOpt = ret; michael@0: if (ret != PR_SUCCESS) michael@0: nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND); michael@0: return rvChain; michael@0: } michael@0: michael@0: loser: michael@0: if (collection) michael@0: nssPKIObjectCollection_Destroy(collection); michael@0: if (statusOpt) michael@0: *statusOpt = PR_FAILURE; michael@0: nss_SetError(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND); michael@0: return rvChain; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCertificate ** michael@0: NSSCertificate_BuildChain ( michael@0: NSSCertificate *c, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCertificate **rvOpt, michael@0: PRUint32 rvLimit, /* zero for no limit */ michael@0: NSSArena *arenaOpt, michael@0: PRStatus *statusOpt, michael@0: NSSTrustDomain *td, michael@0: NSSCryptoContext *cc michael@0: ) michael@0: { michael@0: return nssCertificate_BuildChain(c, timeOpt, usage, policiesOpt, michael@0: rvOpt, rvLimit, arenaOpt, statusOpt, michael@0: td, cc); michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCryptoContext * michael@0: nssCertificate_GetCryptoContext ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: return c->object.cryptoContext; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSTrustDomain * michael@0: nssCertificate_GetTrustDomain ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: return c->object.trustDomain; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSTrustDomain * michael@0: NSSCertificate_GetTrustDomain ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: return nssCertificate_GetTrustDomain(c); michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSToken * michael@0: NSSCertificate_GetToken ( michael@0: NSSCertificate *c, michael@0: PRStatus *statusOpt michael@0: ) michael@0: { michael@0: return (NSSToken *)NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSSlot * michael@0: NSSCertificate_GetSlot ( michael@0: NSSCertificate *c, michael@0: PRStatus *statusOpt michael@0: ) michael@0: { michael@0: return (NSSSlot *)NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSModule * michael@0: NSSCertificate_GetModule ( michael@0: NSSCertificate *c, michael@0: PRStatus *statusOpt michael@0: ) michael@0: { michael@0: return (NSSModule *)NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSItem * michael@0: NSSCertificate_Encrypt ( michael@0: NSSCertificate *c, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSItem *data, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh, michael@0: NSSItem *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: NSSCertificate_Verify ( michael@0: NSSCertificate *c, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSItem *data, michael@0: NSSItem *signature, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSItem * michael@0: NSSCertificate_VerifyRecover ( michael@0: NSSCertificate *c, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSItem *signature, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh, michael@0: NSSItem *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSItem * michael@0: NSSCertificate_WrapSymmetricKey ( michael@0: NSSCertificate *c, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSSymmetricKey *keyToWrap, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh, michael@0: NSSItem *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCryptoContext * michael@0: NSSCertificate_CreateCryptoContext ( michael@0: NSSCertificate *c, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSPublicKey * michael@0: NSSCertificate_GetPublicKey ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: #if 0 michael@0: CK_ATTRIBUTE pubktemplate[] = { michael@0: { CKA_CLASS, NULL, 0 }, michael@0: { CKA_ID, NULL, 0 }, michael@0: { CKA_SUBJECT, NULL, 0 } michael@0: }; michael@0: PRStatus nssrv; michael@0: CK_ULONG count = sizeof(pubktemplate) / sizeof(pubktemplate[0]); michael@0: NSS_CK_SET_ATTRIBUTE_ITEM(pubktemplate, 0, &g_ck_class_pubkey); michael@0: if (c->id.size > 0) { michael@0: /* CKA_ID */ michael@0: NSS_CK_ITEM_TO_ATTRIBUTE(&c->id, &pubktemplate[1]); michael@0: } else { michael@0: /* failure, yes? */ michael@0: return (NSSPublicKey *)NULL; michael@0: } michael@0: if (c->subject.size > 0) { michael@0: /* CKA_SUBJECT */ michael@0: NSS_CK_ITEM_TO_ATTRIBUTE(&c->subject, &pubktemplate[2]); michael@0: } else { michael@0: /* failure, yes? */ michael@0: return (NSSPublicKey *)NULL; michael@0: } michael@0: /* Try the cert's token first */ michael@0: if (c->token) { michael@0: nssrv = nssToken_FindObjectByTemplate(c->token, pubktemplate, count); michael@0: } michael@0: #endif michael@0: /* Try all other key tokens */ michael@0: return (NSSPublicKey *)NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSPrivateKey * michael@0: NSSCertificate_FindPrivateKey ( michael@0: NSSCertificate *c, michael@0: NSSCallback *uhh michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRBool michael@0: NSSCertificate_IsPrivateKeyAvailable ( michael@0: NSSCertificate *c, michael@0: NSSCallback *uhh, michael@0: PRStatus *statusOpt michael@0: ) michael@0: { michael@0: PRBool isUser = PR_FALSE; michael@0: nssCryptokiObject **ip; michael@0: nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object); michael@0: if (!instances) { michael@0: return PR_FALSE; michael@0: } michael@0: for (ip = instances; *ip; ip++) { michael@0: nssCryptokiObject *instance = *ip; michael@0: if (nssToken_IsPrivateKeyAvailable(instance->token, c, instance)) { michael@0: isUser = PR_TRUE; michael@0: } michael@0: } michael@0: nssCryptokiObjectArray_Destroy(instances); michael@0: return isUser; michael@0: } michael@0: michael@0: /* sort the subject cert list from newest to oldest */ michael@0: PRIntn michael@0: nssCertificate_SubjectListSort ( michael@0: void *v1, michael@0: void *v2 michael@0: ) michael@0: { michael@0: NSSCertificate *c1 = (NSSCertificate *)v1; michael@0: NSSCertificate *c2 = (NSSCertificate *)v2; michael@0: nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1); michael@0: nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2); michael@0: if (!dc1) { michael@0: return dc2 ? 1 : 0; michael@0: } else if (!dc2) { michael@0: return -1; michael@0: } else { michael@0: return dc1->isNewerThan(dc1, dc2) ? -1 : 1; michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRBool michael@0: NSSUserCertificate_IsStillPresent ( michael@0: NSSUserCertificate *uc, michael@0: PRStatus *statusOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSItem * michael@0: NSSUserCertificate_Decrypt ( michael@0: NSSUserCertificate *uc, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSItem *data, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh, michael@0: NSSItem *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSItem * michael@0: NSSUserCertificate_Sign ( michael@0: NSSUserCertificate *uc, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSItem *data, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh, michael@0: NSSItem *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSItem * michael@0: NSSUserCertificate_SignRecover ( michael@0: NSSUserCertificate *uc, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSItem *data, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh, michael@0: NSSItem *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSSymmetricKey * michael@0: NSSUserCertificate_UnwrapSymmetricKey ( michael@0: NSSUserCertificate *uc, michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSItem *wrappedKey, michael@0: NSSTime *timeOpt, michael@0: NSSUsage *usage, michael@0: NSSPolicies *policiesOpt, michael@0: NSSCallback *uhh, michael@0: NSSItem *rvOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSSymmetricKey * michael@0: NSSUserCertificate_DeriveSymmetricKey ( michael@0: NSSUserCertificate *uc, /* provides private key */ michael@0: NSSCertificate *c, /* provides public key */ michael@0: NSSAlgorithmAndParameters *apOpt, michael@0: NSSOID *target, michael@0: PRUint32 keySizeOpt, /* zero for best allowed */ michael@0: NSSOperations operations, michael@0: NSSCallback *uhh michael@0: ) michael@0: { michael@0: nss_SetError(NSS_ERROR_NOT_FOUND); michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT nssSMIMEProfile * michael@0: nssSMIMEProfile_Create ( michael@0: NSSCertificate *cert, michael@0: NSSItem *profileTime, michael@0: NSSItem *profileData michael@0: ) michael@0: { michael@0: NSSArena *arena; michael@0: nssSMIMEProfile *rvProfile; michael@0: nssPKIObject *object; michael@0: NSSTrustDomain *td = nssCertificate_GetTrustDomain(cert); michael@0: NSSCryptoContext *cc = nssCertificate_GetCryptoContext(cert); michael@0: arena = nssArena_Create(); michael@0: if (!arena) { michael@0: return NULL; michael@0: } michael@0: object = nssPKIObject_Create(arena, NULL, td, cc, nssPKILock); michael@0: if (!object) { michael@0: goto loser; michael@0: } michael@0: rvProfile = nss_ZNEW(arena, nssSMIMEProfile); michael@0: if (!rvProfile) { michael@0: goto loser; michael@0: } michael@0: rvProfile->object = *object; michael@0: rvProfile->certificate = cert; michael@0: rvProfile->email = nssUTF8_Duplicate(cert->email, arena); michael@0: rvProfile->subject = nssItem_Duplicate(&cert->subject, arena, NULL); michael@0: if (profileTime) { michael@0: rvProfile->profileTime = nssItem_Duplicate(profileTime, arena, NULL); michael@0: } michael@0: if (profileData) { michael@0: rvProfile->profileData = nssItem_Duplicate(profileData, arena, NULL); michael@0: } michael@0: return rvProfile; michael@0: loser: michael@0: if (object) nssPKIObject_Destroy(object); michael@0: else if (arena) nssArena_Destroy(arena); michael@0: return (nssSMIMEProfile *)NULL; michael@0: } michael@0: michael@0: /* execute a callback function on all members of a cert list */ michael@0: NSS_EXTERN PRStatus michael@0: nssCertificateList_DoCallback ( michael@0: nssList *certList, michael@0: PRStatus (* callback)(NSSCertificate *c, void *arg), michael@0: void *arg michael@0: ) michael@0: { michael@0: nssListIterator *certs; michael@0: NSSCertificate *cert; michael@0: PRStatus nssrv; michael@0: certs = nssList_CreateIterator(certList); michael@0: if (!certs) { michael@0: return PR_FAILURE; michael@0: } michael@0: for (cert = (NSSCertificate *)nssListIterator_Start(certs); michael@0: cert != (NSSCertificate *)NULL; michael@0: cert = (NSSCertificate *)nssListIterator_Next(certs)) michael@0: { michael@0: nssrv = (*callback)(cert, arg); michael@0: } michael@0: nssListIterator_Finish(certs); michael@0: nssListIterator_Destroy(certs); michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: static PRStatus add_ref_callback(NSSCertificate *c, void *a) michael@0: { michael@0: nssCertificate_AddRef(c); michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT void michael@0: nssCertificateList_AddReferences ( michael@0: nssList *certList michael@0: ) michael@0: { michael@0: (void)nssCertificateList_DoCallback(certList, add_ref_callback, NULL); michael@0: } michael@0: michael@0: michael@0: /* michael@0: * Is this trust record safe to apply to all certs of the same issuer/SN michael@0: * independent of the cert matching the hash. This is only true is the trust michael@0: * is unknown or distrusted. In general this feature is only useful to michael@0: * explicitly distrusting certs. It is not safe to use to trust certs, so michael@0: * only allow unknown and untrusted trust types. michael@0: */ michael@0: PRBool michael@0: nssTrust_IsSafeToIgnoreCertHash(nssTrustLevel serverAuth, michael@0: nssTrustLevel clientAuth, nssTrustLevel codeSigning, michael@0: nssTrustLevel email, PRBool stepup) michael@0: { michael@0: /* step up is a trust type, if it's on, we must have a hash for the cert */ michael@0: if (stepup) { michael@0: return PR_FALSE; michael@0: } michael@0: if ((serverAuth != nssTrustLevel_Unknown) && michael@0: (serverAuth != nssTrustLevel_NotTrusted)) { michael@0: return PR_FALSE; michael@0: } michael@0: if ((clientAuth != nssTrustLevel_Unknown) && michael@0: (clientAuth != nssTrustLevel_NotTrusted)) { michael@0: return PR_FALSE; michael@0: } michael@0: if ((codeSigning != nssTrustLevel_Unknown) && michael@0: (codeSigning != nssTrustLevel_NotTrusted)) { michael@0: return PR_FALSE; michael@0: } michael@0: if ((email != nssTrustLevel_Unknown) && michael@0: (email != nssTrustLevel_NotTrusted)) { michael@0: return PR_FALSE; michael@0: } michael@0: /* record only has Unknown and Untrusted entries, ok to accept without a michael@0: * hash */ michael@0: return PR_TRUE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSTrust * michael@0: nssTrust_Create ( michael@0: nssPKIObject *object, michael@0: NSSItem *certData michael@0: ) michael@0: { michael@0: PRStatus status; michael@0: PRUint32 i; michael@0: PRUint32 lastTrustOrder, myTrustOrder; michael@0: unsigned char sha1_hashcmp[SHA1_LENGTH]; michael@0: unsigned char sha1_hashin[SHA1_LENGTH]; michael@0: NSSItem sha1_hash; michael@0: NSSTrust *rvt; michael@0: nssCryptokiObject *instance; michael@0: nssTrustLevel serverAuth, clientAuth, codeSigning, emailProtection; michael@0: SECStatus rv; /* Should be stan flavor */ michael@0: PRBool stepUp; michael@0: michael@0: lastTrustOrder = 1<<16; /* just make it big */ michael@0: PR_ASSERT(object->instances != NULL && object->numInstances > 0); michael@0: rvt = nss_ZNEW(object->arena, NSSTrust); michael@0: if (!rvt) { michael@0: return (NSSTrust *)NULL; michael@0: } michael@0: rvt->object = *object; michael@0: michael@0: /* should be stan flavor of Hashbuf */ michael@0: rv = PK11_HashBuf(SEC_OID_SHA1,sha1_hashcmp,certData->data,certData->size); michael@0: if (rv != SECSuccess) { michael@0: return (NSSTrust *)NULL; michael@0: } michael@0: sha1_hash.data = sha1_hashin; michael@0: sha1_hash.size = sizeof (sha1_hashin); michael@0: /* trust has to peek into the base object members */ michael@0: nssPKIObject_Lock(object); michael@0: for (i=0; inumInstances; i++) { michael@0: instance = object->instances[i]; michael@0: myTrustOrder = nssToken_GetTrustOrder(instance->token); michael@0: status = nssCryptokiTrust_GetAttributes(instance, NULL, michael@0: &sha1_hash, michael@0: &serverAuth, michael@0: &clientAuth, michael@0: &codeSigning, michael@0: &emailProtection, michael@0: &stepUp); michael@0: if (status != PR_SUCCESS) { michael@0: nssPKIObject_Unlock(object); michael@0: return (NSSTrust *)NULL; michael@0: } michael@0: /* if no hash is specified, then trust applies to all certs with michael@0: * this issuer/SN. NOTE: This is only true for entries that michael@0: * have distrust and unknown record */ michael@0: if (!( michael@0: /* we continue if there is no hash, and the trust type is michael@0: * safe to accept without a hash ... or ... */ michael@0: ((sha1_hash.size == 0) && michael@0: nssTrust_IsSafeToIgnoreCertHash(serverAuth,clientAuth, michael@0: codeSigning, emailProtection,stepUp)) michael@0: || michael@0: /* we have a hash of the correct size, and it matches */ michael@0: ((sha1_hash.size == SHA1_LENGTH) && (PORT_Memcmp(sha1_hashin, michael@0: sha1_hashcmp,SHA1_LENGTH) == 0)) )) { michael@0: nssPKIObject_Unlock(object); michael@0: return (NSSTrust *)NULL; michael@0: } michael@0: if (rvt->serverAuth == nssTrustLevel_Unknown || michael@0: myTrustOrder < lastTrustOrder) michael@0: { michael@0: rvt->serverAuth = serverAuth; michael@0: } michael@0: if (rvt->clientAuth == nssTrustLevel_Unknown || michael@0: myTrustOrder < lastTrustOrder) michael@0: { michael@0: rvt->clientAuth = clientAuth; michael@0: } michael@0: if (rvt->emailProtection == nssTrustLevel_Unknown || michael@0: myTrustOrder < lastTrustOrder) michael@0: { michael@0: rvt->emailProtection = emailProtection; michael@0: } michael@0: if (rvt->codeSigning == nssTrustLevel_Unknown || michael@0: myTrustOrder < lastTrustOrder) michael@0: { michael@0: rvt->codeSigning = codeSigning; michael@0: } michael@0: rvt->stepUpApproved = stepUp; michael@0: lastTrustOrder = myTrustOrder; michael@0: } michael@0: nssPKIObject_Unlock(object); michael@0: return rvt; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSTrust * michael@0: nssTrust_AddRef ( michael@0: NSSTrust *trust michael@0: ) michael@0: { michael@0: if (trust) { michael@0: nssPKIObject_AddRef(&trust->object); michael@0: } michael@0: return trust; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssTrust_Destroy ( michael@0: NSSTrust *trust michael@0: ) michael@0: { michael@0: if (trust) { michael@0: (void)nssPKIObject_Destroy(&trust->object); michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT nssSMIMEProfile * michael@0: nssSMIMEProfile_AddRef ( michael@0: nssSMIMEProfile *profile michael@0: ) michael@0: { michael@0: if (profile) { michael@0: nssPKIObject_AddRef(&profile->object); michael@0: } michael@0: return profile; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssSMIMEProfile_Destroy ( michael@0: nssSMIMEProfile *profile michael@0: ) michael@0: { michael@0: if (profile) { michael@0: (void)nssPKIObject_Destroy(&profile->object); michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCRL * michael@0: nssCRL_Create ( michael@0: nssPKIObject *object michael@0: ) michael@0: { michael@0: PRStatus status; michael@0: NSSCRL *rvCRL; michael@0: NSSArena *arena = object->arena; michael@0: PR_ASSERT(object->instances != NULL && object->numInstances > 0); michael@0: rvCRL = nss_ZNEW(arena, NSSCRL); michael@0: if (!rvCRL) { michael@0: return (NSSCRL *)NULL; michael@0: } michael@0: rvCRL->object = *object; michael@0: /* XXX should choose instance based on some criteria */ michael@0: status = nssCryptokiCRL_GetAttributes(object->instances[0], michael@0: NULL, /* XXX sessionOpt */ michael@0: arena, michael@0: &rvCRL->encoding, michael@0: NULL, /* subject */ michael@0: NULL, /* class */ michael@0: &rvCRL->url, michael@0: &rvCRL->isKRL); michael@0: if (status != PR_SUCCESS) { michael@0: return (NSSCRL *)NULL; michael@0: } michael@0: return rvCRL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCRL * michael@0: nssCRL_AddRef ( michael@0: NSSCRL *crl michael@0: ) michael@0: { michael@0: if (crl) { michael@0: nssPKIObject_AddRef(&crl->object); michael@0: } michael@0: return crl; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCRL_Destroy ( michael@0: NSSCRL *crl michael@0: ) michael@0: { michael@0: if (crl) { michael@0: (void)nssPKIObject_Destroy(&crl->object); michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCRL_DeleteStoredObject ( michael@0: NSSCRL *crl, michael@0: NSSCallback *uhh michael@0: ) michael@0: { michael@0: return nssPKIObject_DeleteStoredObject(&crl->object, uhh, PR_TRUE); michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSDER * michael@0: nssCRL_GetEncoding ( michael@0: NSSCRL *crl michael@0: ) michael@0: { michael@0: if (crl && crl->encoding.data != NULL && crl->encoding.size > 0) { michael@0: return &crl->encoding; michael@0: } else { michael@0: return (NSSDER *)NULL; michael@0: } michael@0: }