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: /* michael@0: * Hacks to integrate NSS 3.4 and NSS 4.0 certificates. michael@0: */ michael@0: michael@0: #ifndef NSSPKI_H michael@0: #include "nsspki.h" michael@0: #endif /* NSSPKI_H */ michael@0: michael@0: #ifndef PKI_H michael@0: #include "pki.h" michael@0: #endif /* PKI_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: #ifndef DEVNSS3HACK_H michael@0: #include "dev3hack.h" michael@0: #endif /* DEVNSS3HACK_H */ michael@0: michael@0: #ifndef PKINSS3HACK_H michael@0: #include "pki3hack.h" michael@0: #endif /* PKINSS3HACK_H */ michael@0: michael@0: #include "secitem.h" michael@0: #include "certdb.h" michael@0: #include "certt.h" michael@0: #include "cert.h" michael@0: #include "certi.h" michael@0: #include "pk11func.h" michael@0: #include "pkistore.h" michael@0: #include "secmod.h" michael@0: #include "nssrwlk.h" michael@0: michael@0: NSSTrustDomain *g_default_trust_domain = NULL; michael@0: michael@0: NSSCryptoContext *g_default_crypto_context = NULL; michael@0: michael@0: NSSTrustDomain * michael@0: STAN_GetDefaultTrustDomain() michael@0: { michael@0: return g_default_trust_domain; michael@0: } michael@0: michael@0: NSSCryptoContext * michael@0: STAN_GetDefaultCryptoContext() michael@0: { michael@0: return g_default_crypto_context; michael@0: } michael@0: michael@0: extern const NSSError NSS_ERROR_ALREADY_INITIALIZED; michael@0: extern const NSSError NSS_ERROR_INTERNAL_ERROR; michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: STAN_InitTokenForSlotInfo(NSSTrustDomain *td, PK11SlotInfo *slot) michael@0: { michael@0: NSSToken *token; michael@0: if (!td) { michael@0: td = g_default_trust_domain; michael@0: if (!td) { michael@0: /* we're called while still initting. slot will get added michael@0: * appropriately through normal init processes */ michael@0: return PR_SUCCESS; michael@0: } michael@0: } michael@0: token = nssToken_CreateFromPK11SlotInfo(td, slot); michael@0: PK11Slot_SetNSSToken(slot, token); michael@0: /* Don't add nonexistent token to TD's token list */ michael@0: if (token) { michael@0: NSSRWLock_LockWrite(td->tokensLock); michael@0: nssList_Add(td->tokenList, token); michael@0: NSSRWLock_UnlockWrite(td->tokensLock); michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: STAN_ResetTokenInterator(NSSTrustDomain *td) michael@0: { michael@0: if (!td) { michael@0: td = g_default_trust_domain; michael@0: if (!td) { michael@0: /* we're called while still initting. slot will get added michael@0: * appropriately through normal init processes */ michael@0: return PR_SUCCESS; michael@0: } michael@0: } michael@0: NSSRWLock_LockWrite(td->tokensLock); michael@0: nssListIterator_Destroy(td->tokens); michael@0: td->tokens = nssList_CreateIterator(td->tokenList); michael@0: NSSRWLock_UnlockWrite(td->tokensLock); michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: STAN_LoadDefaultNSS3TrustDomain ( michael@0: void michael@0: ) michael@0: { michael@0: NSSTrustDomain *td; michael@0: SECMODModuleList *mlp; michael@0: SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock(); michael@0: int i; michael@0: michael@0: if (g_default_trust_domain || g_default_crypto_context) { michael@0: /* Stan is already initialized or a previous shutdown failed. */ michael@0: nss_SetError(NSS_ERROR_ALREADY_INITIALIZED); michael@0: return PR_FAILURE; michael@0: } michael@0: td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL); michael@0: if (!td) { michael@0: return PR_FAILURE; michael@0: } michael@0: /* michael@0: * Deadlock warning: we should never acquire the moduleLock while michael@0: * we hold the tokensLock. We can use the NSSRWLock Rank feature to michael@0: * guarrentee this. tokensLock have a higher rank than module lock. michael@0: */ michael@0: td->tokenList = nssList_Create(td->arena, PR_TRUE); michael@0: if (!td->tokenList) { michael@0: goto loser; michael@0: } michael@0: SECMOD_GetReadLock(moduleLock); michael@0: NSSRWLock_LockWrite(td->tokensLock); michael@0: for (mlp = SECMOD_GetDefaultModuleList(); mlp != NULL; mlp=mlp->next) { michael@0: for (i=0; i < mlp->module->slotCount; i++) { michael@0: STAN_InitTokenForSlotInfo(td, mlp->module->slots[i]); michael@0: } michael@0: } michael@0: td->tokens = nssList_CreateIterator(td->tokenList); michael@0: NSSRWLock_UnlockWrite(td->tokensLock); michael@0: SECMOD_ReleaseReadLock(moduleLock); michael@0: if (!td->tokens) { michael@0: goto loser; michael@0: } michael@0: g_default_crypto_context = NSSTrustDomain_CreateCryptoContext(td, NULL); michael@0: if (!g_default_crypto_context) { michael@0: goto loser; michael@0: } michael@0: g_default_trust_domain = td; michael@0: return PR_SUCCESS; michael@0: michael@0: loser: michael@0: NSSTrustDomain_Destroy(td); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: /* michael@0: * must be called holding the ModuleListLock (either read or write). michael@0: */ michael@0: NSS_IMPLEMENT SECStatus michael@0: STAN_AddModuleToDefaultTrustDomain ( michael@0: SECMODModule *module michael@0: ) michael@0: { michael@0: NSSTrustDomain *td; michael@0: int i; michael@0: td = STAN_GetDefaultTrustDomain(); michael@0: for (i=0; islotCount; i++) { michael@0: STAN_InitTokenForSlotInfo(td, module->slots[i]); michael@0: } michael@0: STAN_ResetTokenInterator(td); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: /* michael@0: * must be called holding the ModuleListLock (either read or write). michael@0: */ michael@0: NSS_IMPLEMENT SECStatus michael@0: STAN_RemoveModuleFromDefaultTrustDomain ( michael@0: SECMODModule *module michael@0: ) michael@0: { michael@0: NSSToken *token; michael@0: NSSTrustDomain *td; michael@0: int i; michael@0: td = STAN_GetDefaultTrustDomain(); michael@0: NSSRWLock_LockWrite(td->tokensLock); michael@0: for (i=0; islotCount; i++) { michael@0: token = PK11Slot_GetNSSToken(module->slots[i]); michael@0: if (token) { michael@0: nssToken_NotifyCertsNotVisible(token); michael@0: nssList_Remove(td->tokenList, token); michael@0: PK11Slot_SetNSSToken(module->slots[i], NULL); michael@0: nssToken_Destroy(token); michael@0: } michael@0: } michael@0: nssListIterator_Destroy(td->tokens); michael@0: td->tokens = nssList_CreateIterator(td->tokenList); michael@0: NSSRWLock_UnlockWrite(td->tokensLock); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: STAN_Shutdown() michael@0: { michael@0: PRStatus status = PR_SUCCESS; michael@0: if (g_default_trust_domain) { michael@0: if (NSSTrustDomain_Destroy(g_default_trust_domain) == PR_SUCCESS) { michael@0: g_default_trust_domain = NULL; michael@0: } else { michael@0: status = PR_FAILURE; michael@0: } michael@0: } michael@0: if (g_default_crypto_context) { michael@0: if (NSSCryptoContext_Destroy(g_default_crypto_context) == PR_SUCCESS) { michael@0: g_default_crypto_context = NULL; michael@0: } else { michael@0: status = PR_FAILURE; michael@0: } michael@0: } michael@0: return status; michael@0: } michael@0: michael@0: /* this function should not be a hack; it will be needed in 4.0 (rename) */ michael@0: NSS_IMPLEMENT NSSItem * michael@0: STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der) michael@0: { michael@0: NSSItem *rvKey; michael@0: SECItem secDER; michael@0: SECItem secKey = { 0 }; michael@0: SECStatus secrv; michael@0: PLArenaPool *arena; michael@0: michael@0: SECITEM_FROM_NSSITEM(&secDER, der); michael@0: michael@0: /* nss3 call uses nss3 arena's */ michael@0: arena = PORT_NewArena(256); michael@0: if (!arena) { michael@0: return NULL; michael@0: } michael@0: secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey); michael@0: if (secrv != SECSuccess) { michael@0: return NULL; michael@0: } michael@0: rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data); michael@0: PORT_FreeArena(arena,PR_FALSE); michael@0: return rvKey; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssPKIX509_GetIssuerAndSerialFromDER(NSSDER *der, NSSArena *arena, michael@0: NSSDER *issuer, NSSDER *serial) michael@0: { michael@0: SECStatus secrv; michael@0: SECItem derCert; michael@0: SECItem derIssuer = { 0 }; michael@0: SECItem derSerial = { 0 }; michael@0: SECITEM_FROM_NSSITEM(&derCert, der); michael@0: secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial); michael@0: if (secrv != SECSuccess) { michael@0: return PR_FAILURE; michael@0: } michael@0: (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data); michael@0: secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer); michael@0: if (secrv != SECSuccess) { michael@0: PORT_Free(derSerial.data); michael@0: return PR_FAILURE; michael@0: } michael@0: (void)nssItem_Create(arena, issuer, derIssuer.len, derIssuer.data); michael@0: PORT_Free(derSerial.data); michael@0: PORT_Free(derIssuer.data); michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: static NSSItem * michael@0: nss3certificate_getIdentifier(nssDecodedCert *dc) michael@0: { michael@0: NSSItem *rvID; michael@0: CERTCertificate *c = (CERTCertificate *)dc->data; michael@0: rvID = nssItem_Create(NULL, NULL, c->certKey.len, c->certKey.data); michael@0: return rvID; michael@0: } michael@0: michael@0: static void * michael@0: nss3certificate_getIssuerIdentifier(nssDecodedCert *dc) michael@0: { michael@0: CERTCertificate *c = (CERTCertificate *)dc->data; michael@0: return (void *)c->authKeyID; michael@0: } michael@0: michael@0: static nssCertIDMatch michael@0: nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id) michael@0: { michael@0: CERTCertificate *c = (CERTCertificate *)dc->data; michael@0: CERTAuthKeyID *authKeyID = (CERTAuthKeyID *)id; michael@0: SECItem skid; michael@0: nssCertIDMatch match = nssCertIDMatch_Unknown; michael@0: michael@0: /* keyIdentifier */ michael@0: if (authKeyID->keyID.len > 0 && michael@0: CERT_FindSubjectKeyIDExtension(c, &skid) == SECSuccess) { michael@0: PRBool skiEqual; michael@0: skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid); michael@0: PORT_Free(skid.data); michael@0: if (skiEqual) { michael@0: /* change the state to positive match, but keep going */ michael@0: match = nssCertIDMatch_Yes; michael@0: } else { michael@0: /* exit immediately on failure */ michael@0: return nssCertIDMatch_No; michael@0: } michael@0: } michael@0: michael@0: /* issuer/serial (treated as pair) */ michael@0: if (authKeyID->authCertIssuer) { michael@0: SECItem *caName = NULL; michael@0: SECItem *caSN = &authKeyID->authCertSerialNumber; michael@0: michael@0: caName = (SECItem *)CERT_GetGeneralNameByType( michael@0: authKeyID->authCertIssuer, michael@0: certDirectoryName, PR_TRUE); michael@0: if (caName != NULL && michael@0: SECITEM_ItemsAreEqual(&c->derIssuer, caName) && michael@0: SECITEM_ItemsAreEqual(&c->serialNumber, caSN)) michael@0: { michael@0: match = nssCertIDMatch_Yes; michael@0: } else { michael@0: match = nssCertIDMatch_Unknown; michael@0: } michael@0: } michael@0: return match; michael@0: } michael@0: michael@0: static PRBool michael@0: nss3certificate_isValidIssuer(nssDecodedCert *dc) michael@0: { michael@0: CERTCertificate *c = (CERTCertificate *)dc->data; michael@0: unsigned int ignore; michael@0: return CERT_IsCACert(c, &ignore); michael@0: } michael@0: michael@0: static NSSUsage * michael@0: nss3certificate_getUsage(nssDecodedCert *dc) michael@0: { michael@0: /* CERTCertificate *c = (CERTCertificate *)dc->data; */ michael@0: return NULL; michael@0: } michael@0: michael@0: static PRBool michael@0: nss3certificate_isValidAtTime(nssDecodedCert *dc, NSSTime *time) michael@0: { michael@0: SECCertTimeValidity validity; michael@0: CERTCertificate *c = (CERTCertificate *)dc->data; michael@0: validity = CERT_CheckCertValidTimes(c, NSSTime_GetPRTime(time), PR_TRUE); michael@0: if (validity == secCertTimeValid) { michael@0: return PR_TRUE; michael@0: } michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: static PRBool michael@0: nss3certificate_isNewerThan(nssDecodedCert *dc, nssDecodedCert *cmpdc) michael@0: { michael@0: /* I know this isn't right, but this is glue code anyway */ michael@0: if (cmpdc->type == dc->type) { michael@0: CERTCertificate *certa = (CERTCertificate *)dc->data; michael@0: CERTCertificate *certb = (CERTCertificate *)cmpdc->data; michael@0: return CERT_IsNewer(certa, certb); michael@0: } michael@0: return PR_FALSE; michael@0: } michael@0: michael@0: /* CERT_FilterCertListByUsage */ michael@0: static PRBool michael@0: nss3certificate_matchUsage(nssDecodedCert *dc, const NSSUsage *usage) michael@0: { michael@0: CERTCertificate *cc; michael@0: unsigned int requiredKeyUsage = 0; michael@0: unsigned int requiredCertType = 0; michael@0: SECStatus secrv; michael@0: PRBool match; michael@0: PRBool ca; michael@0: michael@0: /* This is for NSS 3.3 functions that do not specify a usage */ michael@0: if (usage->anyUsage) { michael@0: return PR_TRUE; michael@0: } michael@0: ca = usage->nss3lookingForCA; michael@0: secrv = CERT_KeyUsageAndTypeForCertUsage(usage->nss3usage, ca, michael@0: &requiredKeyUsage, michael@0: &requiredCertType); michael@0: if (secrv != SECSuccess) { michael@0: return PR_FALSE; michael@0: } michael@0: cc = (CERTCertificate *)dc->data; michael@0: secrv = CERT_CheckKeyUsage(cc, requiredKeyUsage); michael@0: match = (PRBool)(secrv == SECSuccess); michael@0: if (match) { michael@0: unsigned int certType = 0; michael@0: if (ca) { michael@0: (void)CERT_IsCACert(cc, &certType); michael@0: } else { michael@0: certType = cc->nsCertType; michael@0: } michael@0: if (!(certType & requiredCertType)) { michael@0: match = PR_FALSE; michael@0: } michael@0: } michael@0: return match; michael@0: } michael@0: michael@0: static PRBool michael@0: nss3certificate_isTrustedForUsage(nssDecodedCert *dc, const NSSUsage *usage) michael@0: { michael@0: CERTCertificate *cc; michael@0: PRBool ca; michael@0: SECStatus secrv; michael@0: unsigned int requiredFlags; michael@0: unsigned int trustFlags; michael@0: SECTrustType trustType; michael@0: CERTCertTrust trust; michael@0: michael@0: /* This is for NSS 3.3 functions that do not specify a usage */ michael@0: if (usage->anyUsage) { michael@0: return PR_FALSE; /* XXX is this right? */ michael@0: } michael@0: cc = (CERTCertificate *)dc->data; michael@0: ca = usage->nss3lookingForCA; michael@0: if (!ca) { michael@0: PRBool trusted; michael@0: unsigned int failedFlags; michael@0: secrv = cert_CheckLeafTrust(cc, usage->nss3usage, michael@0: &failedFlags, &trusted); michael@0: return secrv == SECSuccess && trusted; michael@0: } michael@0: secrv = CERT_TrustFlagsForCACertUsage(usage->nss3usage, &requiredFlags, michael@0: &trustType); michael@0: if (secrv != SECSuccess) { michael@0: return PR_FALSE; michael@0: } michael@0: secrv = CERT_GetCertTrust(cc, &trust); michael@0: if (secrv != SECSuccess) { michael@0: return PR_FALSE; michael@0: } michael@0: if (trustType == trustTypeNone) { michael@0: /* normally trustTypeNone usages accept any of the given trust bits michael@0: * being on as acceptable. */ michael@0: trustFlags = trust.sslFlags | trust.emailFlags | michael@0: trust.objectSigningFlags; michael@0: } else { michael@0: trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType); michael@0: } michael@0: return (trustFlags & requiredFlags) == requiredFlags; michael@0: } michael@0: michael@0: static NSSASCII7 * michael@0: nss3certificate_getEmailAddress(nssDecodedCert *dc) michael@0: { michael@0: CERTCertificate *cc = (CERTCertificate *)dc->data; michael@0: return (cc && cc->emailAddr && cc->emailAddr[0]) michael@0: ? (NSSASCII7 *)cc->emailAddr : NULL; michael@0: } michael@0: michael@0: static PRStatus michael@0: nss3certificate_getDERSerialNumber(nssDecodedCert *dc, michael@0: NSSDER *serial, NSSArena *arena) michael@0: { michael@0: CERTCertificate *cc = (CERTCertificate *)dc->data; michael@0: SECItem derSerial = { 0 }; michael@0: SECStatus secrv; michael@0: secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); michael@0: if (secrv == SECSuccess) { michael@0: (void)nssItem_Create(arena, serial, derSerial.len, derSerial.data); michael@0: PORT_Free(derSerial.data); michael@0: return PR_SUCCESS; michael@0: } michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: /* Returns NULL if "encoding" cannot be decoded. */ michael@0: NSS_IMPLEMENT nssDecodedCert * michael@0: nssDecodedPKIXCertificate_Create ( michael@0: NSSArena *arenaOpt, michael@0: NSSDER *encoding michael@0: ) michael@0: { michael@0: nssDecodedCert *rvDC = NULL; michael@0: CERTCertificate *cert; michael@0: SECItem secDER; michael@0: michael@0: SECITEM_FROM_NSSITEM(&secDER, encoding); michael@0: cert = CERT_DecodeDERCertificate(&secDER, PR_TRUE, NULL); michael@0: if (cert) { michael@0: rvDC = nss_ZNEW(arenaOpt, nssDecodedCert); michael@0: if (rvDC) { michael@0: rvDC->type = NSSCertificateType_PKIX; michael@0: rvDC->data = (void *)cert; michael@0: rvDC->getIdentifier = nss3certificate_getIdentifier; michael@0: rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; michael@0: rvDC->matchIdentifier = nss3certificate_matchIdentifier; michael@0: rvDC->isValidIssuer = nss3certificate_isValidIssuer; michael@0: rvDC->getUsage = nss3certificate_getUsage; michael@0: rvDC->isValidAtTime = nss3certificate_isValidAtTime; michael@0: rvDC->isNewerThan = nss3certificate_isNewerThan; michael@0: rvDC->matchUsage = nss3certificate_matchUsage; michael@0: rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage; michael@0: rvDC->getEmailAddress = nss3certificate_getEmailAddress; michael@0: rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber; michael@0: } else { michael@0: CERT_DestroyCertificate(cert); michael@0: } michael@0: } michael@0: return rvDC; michael@0: } michael@0: michael@0: static nssDecodedCert * michael@0: create_decoded_pkix_cert_from_nss3cert ( michael@0: NSSArena *arenaOpt, michael@0: CERTCertificate *cc michael@0: ) michael@0: { michael@0: nssDecodedCert *rvDC = nss_ZNEW(arenaOpt, nssDecodedCert); michael@0: if (rvDC) { michael@0: rvDC->type = NSSCertificateType_PKIX; michael@0: rvDC->data = (void *)cc; michael@0: rvDC->getIdentifier = nss3certificate_getIdentifier; michael@0: rvDC->getIssuerIdentifier = nss3certificate_getIssuerIdentifier; michael@0: rvDC->matchIdentifier = nss3certificate_matchIdentifier; michael@0: rvDC->isValidIssuer = nss3certificate_isValidIssuer; michael@0: rvDC->getUsage = nss3certificate_getUsage; michael@0: rvDC->isValidAtTime = nss3certificate_isValidAtTime; michael@0: rvDC->isNewerThan = nss3certificate_isNewerThan; michael@0: rvDC->matchUsage = nss3certificate_matchUsage; michael@0: rvDC->isTrustedForUsage = nss3certificate_isTrustedForUsage; michael@0: rvDC->getEmailAddress = nss3certificate_getEmailAddress; michael@0: rvDC->getDERSerialNumber = nss3certificate_getDERSerialNumber; michael@0: } michael@0: return rvDC; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssDecodedPKIXCertificate_Destroy ( michael@0: nssDecodedCert *dc michael@0: ) michael@0: { michael@0: CERTCertificate *cert = (CERTCertificate *)dc->data; michael@0: michael@0: /* The decoder may only be half initialized (the case where we find we michael@0: * could not decode the certificate). In this case, there is not cert to michael@0: * free, just free the dc structure. */ michael@0: if (cert) { michael@0: PRBool freeSlot = cert->ownSlot; michael@0: PK11SlotInfo *slot = cert->slot; michael@0: PLArenaPool *arena = cert->arena; michael@0: /* zero cert before freeing. Any stale references to this cert michael@0: * after this point will probably cause an exception. */ michael@0: PORT_Memset(cert, 0, sizeof *cert); michael@0: /* free the arena that contains the cert. */ michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: if (slot && freeSlot) { michael@0: PK11_FreeSlot(slot); michael@0: } michael@0: } michael@0: nss_ZFreeIf(dc); michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: /* see pk11cert.c:pk11_HandleTrustObject */ michael@0: static unsigned int michael@0: get_nss3trust_from_nss4trust(nssTrustLevel t) michael@0: { michael@0: unsigned int rt = 0; michael@0: if (t == nssTrustLevel_Trusted) { michael@0: rt |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; michael@0: } michael@0: if (t == nssTrustLevel_TrustedDelegator) { michael@0: rt |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA; michael@0: } michael@0: if (t == nssTrustLevel_NotTrusted) { michael@0: rt |= CERTDB_TERMINAL_RECORD; michael@0: } michael@0: if (t == nssTrustLevel_ValidDelegator) { michael@0: rt |= CERTDB_VALID_CA; michael@0: } michael@0: return rt; michael@0: } michael@0: michael@0: static CERTCertTrust * michael@0: cert_trust_from_stan_trust(NSSTrust *t, PLArenaPool *arena) michael@0: { michael@0: CERTCertTrust *rvTrust; michael@0: unsigned int client; michael@0: if (!t) { michael@0: return NULL; michael@0: } michael@0: rvTrust = PORT_ArenaAlloc(arena, sizeof(CERTCertTrust)); michael@0: if (!rvTrust) return NULL; michael@0: rvTrust->sslFlags = get_nss3trust_from_nss4trust(t->serverAuth); michael@0: client = get_nss3trust_from_nss4trust(t->clientAuth); michael@0: if (client & (CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA)) { michael@0: client &= ~(CERTDB_TRUSTED_CA|CERTDB_NS_TRUSTED_CA); michael@0: rvTrust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA; michael@0: } michael@0: rvTrust->sslFlags |= client; michael@0: rvTrust->emailFlags = get_nss3trust_from_nss4trust(t->emailProtection); michael@0: rvTrust->objectSigningFlags = get_nss3trust_from_nss4trust(t->codeSigning); michael@0: return rvTrust; michael@0: } michael@0: michael@0: CERTCertTrust * michael@0: nssTrust_GetCERTCertTrustForCert(NSSCertificate *c, CERTCertificate *cc) michael@0: { michael@0: CERTCertTrust *rvTrust = NULL; michael@0: NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); michael@0: NSSTrust *t; michael@0: t = nssTrustDomain_FindTrustForCertificate(td, c); michael@0: if (t) { michael@0: rvTrust = cert_trust_from_stan_trust(t, cc->arena); michael@0: if (!rvTrust) { michael@0: nssTrust_Destroy(t); michael@0: return NULL; michael@0: } michael@0: nssTrust_Destroy(t); michael@0: } else { michael@0: rvTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust)); michael@0: if (!rvTrust) { michael@0: return NULL; michael@0: } michael@0: memset(rvTrust, 0, sizeof(*rvTrust)); michael@0: } michael@0: if (NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) { michael@0: rvTrust->sslFlags |= CERTDB_USER; michael@0: rvTrust->emailFlags |= CERTDB_USER; michael@0: rvTrust->objectSigningFlags |= CERTDB_USER; michael@0: } michael@0: return rvTrust; michael@0: } michael@0: michael@0: static nssCryptokiInstance * michael@0: get_cert_instance(NSSCertificate *c) michael@0: { michael@0: nssCryptokiObject *instance, **ci; michael@0: nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object); michael@0: if (!instances) { michael@0: return NULL; michael@0: } michael@0: instance = NULL; michael@0: for (ci = instances; *ci; ci++) { michael@0: if (!instance) { michael@0: instance = nssCryptokiObject_Clone(*ci); michael@0: } else { michael@0: /* This only really works for two instances... But 3.4 can't michael@0: * handle more anyway. The logic is, if there are multiple michael@0: * instances, prefer the one that is not internal (e.g., on michael@0: * a hardware device. michael@0: */ michael@0: if (PK11_IsInternal(instance->token->pk11slot)) { michael@0: nssCryptokiObject_Destroy(instance); michael@0: instance = nssCryptokiObject_Clone(*ci); michael@0: } michael@0: } michael@0: } michael@0: nssCryptokiObjectArray_Destroy(instances); michael@0: return instance; michael@0: } michael@0: michael@0: char * michael@0: STAN_GetCERTCertificateNameForInstance ( michael@0: PLArenaPool *arenaOpt, michael@0: NSSCertificate *c, michael@0: nssCryptokiInstance *instance michael@0: ) michael@0: { michael@0: NSSCryptoContext *context = c->object.cryptoContext; michael@0: PRStatus nssrv; michael@0: int nicklen, tokenlen, len; michael@0: NSSUTF8 *tokenName = NULL; michael@0: NSSUTF8 *stanNick = NULL; michael@0: char *nickname = NULL; michael@0: char *nick; michael@0: michael@0: if (instance) { michael@0: stanNick = instance->label; michael@0: } else if (context) { michael@0: stanNick = c->object.tempName; michael@0: } michael@0: if (stanNick) { michael@0: /* fill other fields needed by NSS3 functions using CERTCertificate */ michael@0: if (instance && (!PK11_IsInternalKeySlot(instance->token->pk11slot) || michael@0: PORT_Strchr(stanNick, ':') != NULL) ) { michael@0: tokenName = nssToken_GetName(instance->token); michael@0: tokenlen = nssUTF8_Size(tokenName, &nssrv); michael@0: } else { michael@0: /* don't use token name for internal slot; 3.3 didn't */ michael@0: tokenlen = 0; michael@0: } michael@0: nicklen = nssUTF8_Size(stanNick, &nssrv); michael@0: len = tokenlen + nicklen; michael@0: if (arenaOpt) { michael@0: nickname = PORT_ArenaAlloc(arenaOpt, len); michael@0: } else { michael@0: nickname = PORT_Alloc(len); michael@0: } michael@0: nick = nickname; michael@0: if (tokenName) { michael@0: memcpy(nick, tokenName, tokenlen-1); michael@0: nick += tokenlen-1; michael@0: *nick++ = ':'; michael@0: } michael@0: memcpy(nick, stanNick, nicklen-1); michael@0: nickname[len-1] = '\0'; michael@0: } michael@0: return nickname; michael@0: } michael@0: michael@0: char * michael@0: STAN_GetCERTCertificateName(PLArenaPool *arenaOpt, NSSCertificate *c) michael@0: { michael@0: char * result; michael@0: nssCryptokiInstance *instance = get_cert_instance(c); michael@0: /* It's OK to call this function, even if instance is NULL */ michael@0: result = STAN_GetCERTCertificateNameForInstance(arenaOpt, c, instance); michael@0: if (instance) michael@0: nssCryptokiObject_Destroy(instance); michael@0: return result; michael@0: } michael@0: michael@0: static void michael@0: fill_CERTCertificateFields(NSSCertificate *c, CERTCertificate *cc, PRBool forced) michael@0: { michael@0: CERTCertTrust* trust = NULL; michael@0: NSSTrust *nssTrust; michael@0: NSSCryptoContext *context = c->object.cryptoContext; michael@0: nssCryptokiInstance *instance; michael@0: NSSUTF8 *stanNick = NULL; michael@0: michael@0: /* We are holding the base class object's lock on entry of this function michael@0: * This lock protects writes to fields of the CERTCertificate . michael@0: * It is also needed by some functions to compute values such as trust. michael@0: */ michael@0: instance = get_cert_instance(c); michael@0: michael@0: if (instance) { michael@0: stanNick = instance->label; michael@0: } else if (context) { michael@0: stanNick = c->object.tempName; michael@0: } michael@0: /* fill other fields needed by NSS3 functions using CERTCertificate */ michael@0: if ((!cc->nickname && stanNick) || forced) { michael@0: PRStatus nssrv; michael@0: int nicklen, tokenlen, len; michael@0: NSSUTF8 *tokenName = NULL; michael@0: char *nick; michael@0: if (instance && michael@0: (!PK11_IsInternalKeySlot(instance->token->pk11slot) || michael@0: (stanNick && PORT_Strchr(stanNick, ':') != NULL))) { michael@0: tokenName = nssToken_GetName(instance->token); michael@0: tokenlen = nssUTF8_Size(tokenName, &nssrv); michael@0: } else { michael@0: /* don't use token name for internal slot; 3.3 didn't */ michael@0: tokenlen = 0; michael@0: } michael@0: if (stanNick) { michael@0: nicklen = nssUTF8_Size(stanNick, &nssrv); michael@0: len = tokenlen + nicklen; michael@0: nick = PORT_ArenaAlloc(cc->arena, len); michael@0: if (tokenName) { michael@0: memcpy(nick, tokenName, tokenlen-1); michael@0: nick[tokenlen-1] = ':'; michael@0: memcpy(nick+tokenlen, stanNick, nicklen-1); michael@0: } else { michael@0: memcpy(nick, stanNick, nicklen-1); michael@0: } michael@0: nick[len-1] = '\0'; michael@0: cc->nickname = nick; michael@0: } else { michael@0: cc->nickname = NULL; michael@0: } michael@0: } michael@0: if (context) { michael@0: /* trust */ michael@0: nssTrust = nssCryptoContext_FindTrustForCertificate(context, c); michael@0: if (!nssTrust) { michael@0: /* chicken and egg issue: michael@0: * michael@0: * c->issuer and c->serial are empty at this point, but michael@0: * nssTrustDomain_FindTrustForCertificate use them to look up michael@0: * up the trust object, so we point them to cc->derIssuer and michael@0: * cc->serialNumber. michael@0: * michael@0: * Our caller will fill these in with proper arena copies when we michael@0: * return. */ michael@0: c->issuer.data = cc->derIssuer.data; michael@0: c->issuer.size = cc->derIssuer.len; michael@0: c->serial.data = cc->serialNumber.data; michael@0: c->serial.size = cc->serialNumber.len; michael@0: nssTrust = nssTrustDomain_FindTrustForCertificate(context->td, c); michael@0: } michael@0: if (nssTrust) { michael@0: trust = cert_trust_from_stan_trust(nssTrust, cc->arena); michael@0: if (trust) { michael@0: /* we should destroy cc->trust before replacing it, but it's michael@0: allocated in cc->arena, so memory growth will occur on each michael@0: refresh */ michael@0: CERT_LockCertTrust(cc); michael@0: cc->trust = trust; michael@0: CERT_UnlockCertTrust(cc); michael@0: } michael@0: nssTrust_Destroy(nssTrust); michael@0: } michael@0: } else if (instance) { michael@0: /* slot */ michael@0: if (cc->slot != instance->token->pk11slot) { michael@0: if (cc->slot) { michael@0: PK11_FreeSlot(cc->slot); michael@0: } michael@0: cc->slot = PK11_ReferenceSlot(instance->token->pk11slot); michael@0: } michael@0: cc->ownSlot = PR_TRUE; michael@0: /* pkcs11ID */ michael@0: cc->pkcs11ID = instance->handle; michael@0: /* trust */ michael@0: trust = nssTrust_GetCERTCertTrustForCert(c, cc); michael@0: if (trust) { michael@0: /* we should destroy cc->trust before replacing it, but it's michael@0: allocated in cc->arena, so memory growth will occur on each michael@0: refresh */ michael@0: CERT_LockCertTrust(cc); michael@0: cc->trust = trust; michael@0: CERT_UnlockCertTrust(cc); michael@0: } michael@0: nssCryptokiObject_Destroy(instance); michael@0: } michael@0: /* database handle is now the trust domain */ michael@0: cc->dbhandle = c->object.trustDomain; michael@0: /* subjectList ? */ michael@0: /* istemp and isperm are supported in NSS 3.4 */ michael@0: cc->istemp = PR_FALSE; /* CERT_NewTemp will override this */ michael@0: cc->isperm = PR_TRUE; /* by default */ michael@0: /* pointer back */ michael@0: cc->nssCertificate = c; michael@0: if (trust) { michael@0: /* force the cert type to be recomputed to include trust info */ michael@0: PRUint32 nsCertType = cert_ComputeCertType(cc); michael@0: michael@0: /* Assert that it is safe to cast &cc->nsCertType to "PRInt32 *" */ michael@0: PORT_Assert(sizeof(cc->nsCertType) == sizeof(PRInt32)); michael@0: PR_ATOMIC_SET((PRInt32 *)&cc->nsCertType, nsCertType); michael@0: } michael@0: } michael@0: michael@0: static CERTCertificate * michael@0: stan_GetCERTCertificate(NSSCertificate *c, PRBool forceUpdate) michael@0: { michael@0: nssDecodedCert *dc = NULL; michael@0: CERTCertificate *cc = NULL; michael@0: CERTCertTrust certTrust; michael@0: michael@0: nssPKIObject_Lock(&c->object); michael@0: michael@0: dc = c->decoding; michael@0: if (!dc) { michael@0: dc = nssDecodedPKIXCertificate_Create(NULL, &c->encoding); michael@0: if (!dc) { michael@0: goto loser; michael@0: } michael@0: cc = (CERTCertificate *)dc->data; michael@0: PORT_Assert(cc); /* software error */ michael@0: if (!cc) { michael@0: nssDecodedPKIXCertificate_Destroy(dc); michael@0: nss_SetError(NSS_ERROR_INTERNAL_ERROR); michael@0: goto loser; michael@0: } michael@0: PORT_Assert(!c->decoding); michael@0: if (!c->decoding) { michael@0: c->decoding = dc; michael@0: } else { michael@0: /* this should never happen. Fail. */ michael@0: nssDecodedPKIXCertificate_Destroy(dc); michael@0: nss_SetError(NSS_ERROR_INTERNAL_ERROR); michael@0: goto loser; michael@0: } michael@0: } michael@0: cc = (CERTCertificate *)dc->data; michael@0: PORT_Assert(cc); michael@0: if (!cc) { michael@0: nss_SetError(NSS_ERROR_INTERNAL_ERROR); michael@0: goto loser; michael@0: } michael@0: if (!cc->nssCertificate || forceUpdate) { michael@0: fill_CERTCertificateFields(c, cc, forceUpdate); michael@0: } else if (CERT_GetCertTrust(cc, &certTrust) != SECSuccess && michael@0: !c->object.cryptoContext) { michael@0: /* if it's a perm cert, it might have been stored before the michael@0: * trust, so look for the trust again. But a temp cert can be michael@0: * ignored. michael@0: */ michael@0: CERTCertTrust* trust = NULL; michael@0: trust = nssTrust_GetCERTCertTrustForCert(c, cc); michael@0: michael@0: CERT_LockCertTrust(cc); michael@0: cc->trust = trust; michael@0: CERT_UnlockCertTrust(cc); michael@0: } michael@0: michael@0: loser: michael@0: nssPKIObject_Unlock(&c->object); michael@0: return cc; michael@0: } michael@0: michael@0: NSS_IMPLEMENT CERTCertificate * michael@0: STAN_ForceCERTCertificateUpdate(NSSCertificate *c) michael@0: { michael@0: if (c->decoding) { michael@0: return stan_GetCERTCertificate(c, PR_TRUE); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: NSS_IMPLEMENT CERTCertificate * michael@0: STAN_GetCERTCertificate(NSSCertificate *c) michael@0: { michael@0: return stan_GetCERTCertificate(c, PR_FALSE); michael@0: } michael@0: /* michael@0: * many callers of STAN_GetCERTCertificate() intend that michael@0: * the CERTCertificate returned inherits the reference to the michael@0: * NSSCertificate. For these callers it's convenient to have michael@0: * this function 'own' the reference and either return a valid michael@0: * CERTCertificate structure which inherits the reference or michael@0: * destroy the reference to NSSCertificate and returns NULL. michael@0: */ michael@0: NSS_IMPLEMENT CERTCertificate * michael@0: STAN_GetCERTCertificateOrRelease(NSSCertificate *c) michael@0: { michael@0: CERTCertificate *nss3cert = stan_GetCERTCertificate(c, PR_FALSE); michael@0: if (!nss3cert) { michael@0: nssCertificate_Destroy(c); michael@0: } michael@0: return nss3cert; michael@0: } michael@0: michael@0: static nssTrustLevel michael@0: get_stan_trust(unsigned int t, PRBool isClientAuth) michael@0: { michael@0: if (isClientAuth) { michael@0: if (t & CERTDB_TRUSTED_CLIENT_CA) { michael@0: return nssTrustLevel_TrustedDelegator; michael@0: } michael@0: } else { michael@0: if (t & CERTDB_TRUSTED_CA || t & CERTDB_NS_TRUSTED_CA) { michael@0: return nssTrustLevel_TrustedDelegator; michael@0: } michael@0: } michael@0: if (t & CERTDB_TRUSTED) { michael@0: return nssTrustLevel_Trusted; michael@0: } michael@0: if (t & CERTDB_TERMINAL_RECORD) { michael@0: return nssTrustLevel_NotTrusted; michael@0: } michael@0: if (t & CERTDB_VALID_CA) { michael@0: return nssTrustLevel_ValidDelegator; michael@0: } michael@0: return nssTrustLevel_MustVerify; michael@0: } michael@0: michael@0: NSS_EXTERN NSSCertificate * michael@0: STAN_GetNSSCertificate(CERTCertificate *cc) michael@0: { michael@0: NSSCertificate *c; michael@0: nssCryptokiInstance *instance; michael@0: nssPKIObject *pkiob; michael@0: NSSArena *arena; michael@0: c = cc->nssCertificate; michael@0: if (c) { michael@0: return c; michael@0: } michael@0: /* i don't think this should happen. but if it can, need to create michael@0: * NSSCertificate from CERTCertificate values here. */ michael@0: /* Yup, it can happen. */ michael@0: arena = NSSArena_Create(); michael@0: if (!arena) { michael@0: return NULL; michael@0: } michael@0: c = nss_ZNEW(arena, NSSCertificate); michael@0: if (!c) { michael@0: nssArena_Destroy(arena); michael@0: return NULL; michael@0: } michael@0: NSSITEM_FROM_SECITEM(&c->encoding, &cc->derCert); michael@0: c->type = NSSCertificateType_PKIX; michael@0: pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKIMonitor); michael@0: if (!pkiob) { michael@0: nssArena_Destroy(arena); michael@0: return NULL; michael@0: } michael@0: c->object = *pkiob; michael@0: nssItem_Create(arena, michael@0: &c->issuer, cc->derIssuer.len, cc->derIssuer.data); michael@0: nssItem_Create(arena, michael@0: &c->subject, cc->derSubject.len, cc->derSubject.data); michael@0: if (PR_TRUE) { michael@0: /* CERTCertificate stores serial numbers decoded. I need the DER michael@0: * here. sigh. michael@0: */ michael@0: SECItem derSerial; michael@0: SECStatus secrv; michael@0: secrv = CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial); michael@0: if (secrv == SECFailure) { michael@0: nssArena_Destroy(arena); michael@0: return NULL; michael@0: } michael@0: nssItem_Create(arena, &c->serial, derSerial.len, derSerial.data); michael@0: PORT_Free(derSerial.data); michael@0: } michael@0: if (cc->emailAddr && cc->emailAddr[0]) { michael@0: c->email = nssUTF8_Create(arena, michael@0: nssStringType_PrintableString, michael@0: (NSSUTF8 *)cc->emailAddr, michael@0: PORT_Strlen(cc->emailAddr)); michael@0: } michael@0: if (cc->slot) { michael@0: instance = nss_ZNEW(arena, nssCryptokiInstance); michael@0: if (!instance) { michael@0: nssArena_Destroy(arena); michael@0: return NULL; michael@0: } michael@0: instance->token = nssToken_AddRef(PK11Slot_GetNSSToken(cc->slot)); michael@0: instance->handle = cc->pkcs11ID; michael@0: instance->isTokenObject = PR_TRUE; michael@0: if (cc->nickname) { michael@0: instance->label = nssUTF8_Create(arena, michael@0: nssStringType_UTF8String, michael@0: (NSSUTF8 *)cc->nickname, michael@0: PORT_Strlen(cc->nickname)); michael@0: } michael@0: nssPKIObject_AddInstance(&c->object, instance); michael@0: } michael@0: c->decoding = create_decoded_pkix_cert_from_nss3cert(NULL, cc); michael@0: cc->nssCertificate = c; michael@0: return c; michael@0: } michael@0: michael@0: static NSSToken* michael@0: stan_GetTrustToken ( michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: NSSToken *ttok = NULL; michael@0: NSSToken *rtok = NULL; michael@0: NSSToken *tok = NULL; 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: nssCryptokiObject *to = michael@0: nssToken_FindTrustForCertificate(instance->token, NULL, michael@0: &c->encoding, &c->issuer, &c->serial, michael@0: nssTokenSearchType_TokenOnly); michael@0: NSSToken *ctok = instance->token; michael@0: PRBool ro = PK11_IsReadOnly(ctok->pk11slot); michael@0: michael@0: if (to) { michael@0: nssCryptokiObject_Destroy(to); michael@0: ttok = ctok; michael@0: if (!ro) { michael@0: break; michael@0: } michael@0: } else { michael@0: if (!rtok && ro) { michael@0: rtok = ctok; michael@0: } michael@0: if (!tok && !ro) { michael@0: tok = ctok; michael@0: } michael@0: } michael@0: } michael@0: nssCryptokiObjectArray_Destroy(instances); michael@0: return ttok ? ttok : (tok ? tok : rtok); michael@0: } michael@0: michael@0: NSS_EXTERN PRStatus michael@0: STAN_ChangeCertTrust(CERTCertificate *cc, CERTCertTrust *trust) michael@0: { michael@0: PRStatus nssrv; michael@0: NSSCertificate *c = STAN_GetNSSCertificate(cc); michael@0: NSSToken *tok; michael@0: NSSTrustDomain *td; michael@0: NSSTrust *nssTrust; michael@0: NSSArena *arena; michael@0: CERTCertTrust *oldTrust; michael@0: CERTCertTrust *newTrust; michael@0: nssListIterator *tokens; michael@0: PRBool moving_object; michael@0: nssCryptokiObject *newInstance; michael@0: nssPKIObject *pkiob; michael@0: michael@0: if (c == NULL) { michael@0: return PR_FAILURE; michael@0: } michael@0: oldTrust = nssTrust_GetCERTCertTrustForCert(c, cc); michael@0: if (oldTrust) { michael@0: if (memcmp(oldTrust, trust, sizeof (CERTCertTrust)) == 0) { michael@0: /* ... and the new trust is no different, done) */ michael@0: return PR_SUCCESS; michael@0: } else { michael@0: /* take over memory already allocated in cc's arena */ michael@0: newTrust = oldTrust; michael@0: } michael@0: } else { michael@0: newTrust = PORT_ArenaAlloc(cc->arena, sizeof(CERTCertTrust)); michael@0: } michael@0: memcpy(newTrust, trust, sizeof(CERTCertTrust)); michael@0: CERT_LockCertTrust(cc); michael@0: cc->trust = newTrust; michael@0: CERT_UnlockCertTrust(cc); michael@0: /* Set the NSSCerticate's trust */ michael@0: arena = nssArena_Create(); michael@0: if (!arena) return PR_FAILURE; michael@0: nssTrust = nss_ZNEW(arena, NSSTrust); michael@0: if (!nssTrust) { michael@0: nssArena_Destroy(arena); michael@0: return PR_FAILURE; michael@0: } michael@0: pkiob = nssPKIObject_Create(arena, NULL, cc->dbhandle, NULL, nssPKILock); michael@0: if (!pkiob) { michael@0: nssArena_Destroy(arena); michael@0: return PR_FAILURE; michael@0: } michael@0: nssTrust->object = *pkiob; michael@0: nssTrust->certificate = c; michael@0: nssTrust->serverAuth = get_stan_trust(trust->sslFlags, PR_FALSE); michael@0: nssTrust->clientAuth = get_stan_trust(trust->sslFlags, PR_TRUE); michael@0: nssTrust->emailProtection = get_stan_trust(trust->emailFlags, PR_FALSE); michael@0: nssTrust->codeSigning = get_stan_trust(trust->objectSigningFlags, PR_FALSE); michael@0: nssTrust->stepUpApproved = michael@0: (PRBool)(trust->sslFlags & CERTDB_GOVT_APPROVED_CA); michael@0: if (c->object.cryptoContext != NULL) { michael@0: /* The cert is in a context, set the trust there */ michael@0: NSSCryptoContext *cc = c->object.cryptoContext; michael@0: nssrv = nssCryptoContext_ImportTrust(cc, nssTrust); michael@0: if (nssrv != PR_SUCCESS) { michael@0: goto done; michael@0: } michael@0: if (c->object.numInstances == 0) { michael@0: /* The context is the only instance, finished */ michael@0: goto done; michael@0: } michael@0: } michael@0: td = STAN_GetDefaultTrustDomain(); michael@0: tok = stan_GetTrustToken(c); michael@0: moving_object = PR_FALSE; michael@0: if (tok && PK11_IsReadOnly(tok->pk11slot)) { michael@0: NSSRWLock_LockRead(td->tokensLock); michael@0: tokens = nssList_CreateIterator(td->tokenList); michael@0: if (!tokens) { michael@0: nssrv = PR_FAILURE; michael@0: NSSRWLock_UnlockRead(td->tokensLock); michael@0: goto done; michael@0: } michael@0: for (tok = (NSSToken *)nssListIterator_Start(tokens); michael@0: tok != (NSSToken *)NULL; michael@0: tok = (NSSToken *)nssListIterator_Next(tokens)) michael@0: { michael@0: if (!PK11_IsReadOnly(tok->pk11slot)) break; michael@0: } michael@0: nssListIterator_Finish(tokens); michael@0: nssListIterator_Destroy(tokens); michael@0: NSSRWLock_UnlockRead(td->tokensLock); michael@0: moving_object = PR_TRUE; michael@0: } michael@0: if (tok) { michael@0: if (moving_object) { michael@0: /* this is kind of hacky. the softoken needs the cert michael@0: * object in order to store trust. forcing it to be perm michael@0: */ michael@0: NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL); michael@0: NSSASCII7 *email = NULL; michael@0: michael@0: if (PK11_IsInternal(tok->pk11slot)) { michael@0: email = c->email; michael@0: } michael@0: newInstance = nssToken_ImportCertificate(tok, NULL, michael@0: NSSCertificateType_PKIX, michael@0: &c->id, michael@0: nickname, michael@0: &c->encoding, michael@0: &c->issuer, michael@0: &c->subject, michael@0: &c->serial, michael@0: email, michael@0: PR_TRUE); michael@0: nss_ZFreeIf(nickname); michael@0: nickname = NULL; michael@0: if (!newInstance) { michael@0: nssrv = PR_FAILURE; michael@0: goto done; michael@0: } michael@0: nssPKIObject_AddInstance(&c->object, newInstance); michael@0: } michael@0: newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding, michael@0: &c->issuer, &c->serial, michael@0: nssTrust->serverAuth, michael@0: nssTrust->clientAuth, michael@0: nssTrust->codeSigning, michael@0: nssTrust->emailProtection, michael@0: nssTrust->stepUpApproved, PR_TRUE); michael@0: /* If the selected token can't handle trust, dump the trust on michael@0: * the internal token */ michael@0: if (!newInstance && !PK11_IsInternalKeySlot(tok->pk11slot)) { michael@0: PK11SlotInfo *slot = PK11_GetInternalKeySlot(); michael@0: NSSUTF8 *nickname = nssCertificate_GetNickname(c, NULL); michael@0: NSSASCII7 *email = c->email; michael@0: tok = PK11Slot_GetNSSToken(slot); michael@0: PK11_FreeSlot(slot); michael@0: michael@0: newInstance = nssToken_ImportCertificate(tok, NULL, michael@0: NSSCertificateType_PKIX, michael@0: &c->id, michael@0: nickname, michael@0: &c->encoding, michael@0: &c->issuer, michael@0: &c->subject, michael@0: &c->serial, michael@0: email, michael@0: PR_TRUE); michael@0: nss_ZFreeIf(nickname); michael@0: nickname = NULL; michael@0: if (!newInstance) { michael@0: nssrv = PR_FAILURE; michael@0: goto done; michael@0: } michael@0: nssPKIObject_AddInstance(&c->object, newInstance); michael@0: newInstance = nssToken_ImportTrust(tok, NULL, &c->encoding, michael@0: &c->issuer, &c->serial, michael@0: nssTrust->serverAuth, michael@0: nssTrust->clientAuth, michael@0: nssTrust->codeSigning, michael@0: nssTrust->emailProtection, michael@0: nssTrust->stepUpApproved, PR_TRUE); michael@0: } michael@0: if (newInstance) { michael@0: nssCryptokiObject_Destroy(newInstance); michael@0: nssrv = PR_SUCCESS; michael@0: } else { michael@0: nssrv = PR_FAILURE; michael@0: } michael@0: } else { michael@0: nssrv = PR_FAILURE; michael@0: } michael@0: done: michael@0: (void)nssTrust_Destroy(nssTrust); michael@0: return nssrv; michael@0: } michael@0: michael@0: /* michael@0: ** Delete trust objects matching the given slot. michael@0: ** Returns error if a device fails to delete. michael@0: ** michael@0: ** This function has the side effect of moving the michael@0: ** surviving entries to the front of the object list michael@0: ** and nullifying the rest. michael@0: */ michael@0: static PRStatus michael@0: DeleteCertTrustMatchingSlot(PK11SlotInfo *pk11slot, nssPKIObject *tObject) michael@0: { michael@0: int numNotDestroyed = 0; /* the ones skipped plus the failures */ michael@0: int failureCount = 0; /* actual deletion failures by devices */ michael@0: int index; michael@0: michael@0: nssPKIObject_Lock(tObject); michael@0: /* Keep going even if a module fails to delete. */ michael@0: for (index = 0; index < tObject->numInstances; index++) { michael@0: nssCryptokiObject *instance = tObject->instances[index]; michael@0: if (!instance) { michael@0: continue; michael@0: } michael@0: michael@0: /* ReadOnly and not matched treated the same */ michael@0: if (PK11_IsReadOnly(instance->token->pk11slot) || michael@0: pk11slot != instance->token->pk11slot) { michael@0: tObject->instances[numNotDestroyed++] = instance; michael@0: continue; michael@0: } michael@0: michael@0: /* Here we have found a matching one */ michael@0: tObject->instances[index] = NULL; michael@0: if (nssToken_DeleteStoredObject(instance) == PR_SUCCESS) { michael@0: nssCryptokiObject_Destroy(instance); michael@0: } else { michael@0: tObject->instances[numNotDestroyed++] = instance; michael@0: failureCount++; michael@0: } michael@0: michael@0: } michael@0: if (numNotDestroyed == 0) { michael@0: nss_ZFreeIf(tObject->instances); michael@0: tObject->numInstances = 0; michael@0: } else { michael@0: tObject->numInstances = numNotDestroyed; michael@0: } michael@0: michael@0: nssPKIObject_Unlock(tObject); michael@0: michael@0: return failureCount == 0 ? PR_SUCCESS : PR_FAILURE; michael@0: } michael@0: michael@0: /* michael@0: ** Delete trust objects matching the slot of the given certificate. michael@0: ** Returns an error if any device fails to delete. michael@0: */ michael@0: NSS_EXTERN PRStatus michael@0: STAN_DeleteCertTrustMatchingSlot(NSSCertificate *c) michael@0: { michael@0: PRStatus nssrv = PR_SUCCESS; michael@0: michael@0: NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); michael@0: NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c); michael@0: /* caller made sure nssTrust isn't NULL */ michael@0: nssPKIObject *tobject = &nssTrust->object; michael@0: nssPKIObject *cobject = &c->object; michael@0: int i; michael@0: michael@0: /* Iterate through the cert and trust object instances looking for michael@0: * those with matching pk11 slots to delete. Even if some device michael@0: * can't delete we keep going. Keeping a status variable for the michael@0: * loop so that once it's failed the other gets set. michael@0: */ michael@0: NSSRWLock_LockRead(td->tokensLock); michael@0: nssPKIObject_Lock(cobject); michael@0: for (i = 0; i < cobject->numInstances; i++) { michael@0: nssCryptokiObject *cInstance = cobject->instances[i]; michael@0: if (cInstance && !PK11_IsReadOnly(cInstance->token->pk11slot)) { michael@0: PRStatus status; michael@0: if (!tobject->numInstances || !tobject->instances) continue; michael@0: status = DeleteCertTrustMatchingSlot(cInstance->token->pk11slot, tobject); michael@0: if (status == PR_FAILURE) { michael@0: /* set the outer one but keep going */ michael@0: nssrv = PR_FAILURE; michael@0: } michael@0: } michael@0: } michael@0: nssPKIObject_Unlock(cobject); michael@0: NSSRWLock_UnlockRead(td->tokensLock); michael@0: return nssrv; michael@0: } michael@0: michael@0: /* CERT_TraversePermCertsForSubject */ michael@0: NSS_IMPLEMENT PRStatus michael@0: nssTrustDomain_TraverseCertificatesBySubject ( michael@0: NSSTrustDomain *td, michael@0: NSSDER *subject, michael@0: PRStatus (*callback)(NSSCertificate *c, void *arg), michael@0: void *arg michael@0: ) michael@0: { michael@0: PRStatus nssrv = PR_SUCCESS; michael@0: NSSArena *tmpArena; michael@0: NSSCertificate **subjectCerts; michael@0: NSSCertificate *c; michael@0: PRIntn i; michael@0: tmpArena = NSSArena_Create(); michael@0: if (!tmpArena) { michael@0: return PR_FAILURE; michael@0: } michael@0: subjectCerts = NSSTrustDomain_FindCertificatesBySubject(td, subject, NULL, michael@0: 0, tmpArena); michael@0: if (subjectCerts) { michael@0: for (i=0, c = subjectCerts[i]; c; i++) { michael@0: nssrv = callback(c, arg); michael@0: if (nssrv != PR_SUCCESS) break; michael@0: } michael@0: } michael@0: nssArena_Destroy(tmpArena); michael@0: return nssrv; michael@0: } michael@0: michael@0: /* CERT_TraversePermCertsForNickname */ michael@0: NSS_IMPLEMENT PRStatus michael@0: nssTrustDomain_TraverseCertificatesByNickname ( michael@0: NSSTrustDomain *td, michael@0: NSSUTF8 *nickname, michael@0: PRStatus (*callback)(NSSCertificate *c, void *arg), michael@0: void *arg michael@0: ) michael@0: { michael@0: PRStatus nssrv = PR_SUCCESS; michael@0: NSSArena *tmpArena; michael@0: NSSCertificate **nickCerts; michael@0: NSSCertificate *c; michael@0: PRIntn i; michael@0: tmpArena = NSSArena_Create(); michael@0: if (!tmpArena) { michael@0: return PR_FAILURE; michael@0: } michael@0: nickCerts = NSSTrustDomain_FindCertificatesByNickname(td, nickname, NULL, michael@0: 0, tmpArena); michael@0: if (nickCerts) { michael@0: for (i=0, c = nickCerts[i]; c; i++) { michael@0: nssrv = callback(c, arg); michael@0: if (nssrv != PR_SUCCESS) break; michael@0: } michael@0: } michael@0: nssArena_Destroy(tmpArena); michael@0: return nssrv; michael@0: } michael@0: michael@0: static void cert_dump_iter(const void *k, void *v, void *a) michael@0: { michael@0: NSSCertificate *c = (NSSCertificate *)k; michael@0: CERTCertificate *cert = STAN_GetCERTCertificate(c); michael@0: printf("[%2d] \"%s\"\n", c->object.refCount, cert->subjectName); michael@0: } michael@0: michael@0: void michael@0: nss_DumpCertificateCacheInfo() michael@0: { michael@0: NSSTrustDomain *td; michael@0: NSSCryptoContext *cc; michael@0: td = STAN_GetDefaultTrustDomain(); michael@0: cc = STAN_GetDefaultCryptoContext(); michael@0: printf("\n\nCertificates in the cache:\n"); michael@0: nssTrustDomain_DumpCacheInfo(td, cert_dump_iter, NULL); michael@0: printf("\n\nCertificates in the temporary store:\n"); michael@0: if (cc->certStore) { michael@0: nssCertificateStore_DumpStoreInfo(cc->certStore, cert_dump_iter, NULL); michael@0: } michael@0: } michael@0: