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