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