| /* 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; |
| } |
| } |