// sort blocklist items into lists of serials for each issuer PLDHashOperator ProcessBlocklistEntry(BlocklistItemKey* aHashKey, void* aUserArg) { BlocklistSaveInfo* saveInfo = reinterpret_cast<BlocklistSaveInfo*>(aUserArg); CertBlocklistItem item = aHashKey->GetKey(); if (!item.mIsCurrent) { return PL_DHASH_NEXT; } nsAutoCString encDN; nsAutoCString encOther; nsresult rv = item.ToBase64(encDN, encOther); if (NS_FAILED(rv)) { saveInfo->success = false; return PL_DHASH_STOP; } // If it's a subject / public key block, write it straight out if (item.mItemMechanism == BlockBySubjectAndPubKey) { WriteLine(saveInfo->outputStream, encDN); WriteLine(saveInfo->outputStream, NS_LITERAL_CSTRING("\t") + encOther); return PL_DHASH_NEXT; } // Otherwise, we have to group entries by issuer saveInfo->issuers.PutEntry(encDN); BlocklistStringSet* issuerSet = saveInfo->issuerTable.Get(encDN); if (!issuerSet) { issuerSet = new BlocklistStringSet(); saveInfo->issuerTable.Put(encDN, issuerSet); } issuerSet->PutEntry(encOther); return PL_DHASH_NEXT; }
// void saveEntries(); // Store the blockist in a text file containing base64 encoded issuers and // serial numbers. // // Each item is stored on a separate line; each issuer is followed by its // revoked serial numbers, indented by one space. // // lines starting with a # character are ignored NS_IMETHODIMP CertBlocklist::SaveEntries() { MOZ_LOG(gCertBlockPRLog, LogLevel::Debug, ("CertBlocklist::SaveEntries - not initialized")); MutexAutoLock lock(mMutex); if (!mModified) { return NS_OK; } nsresult rv = EnsureBackingFileInitialized(lock); if (NS_FAILED(rv)) { return rv; } if (!mBackingFile) { // We allow this to succeed with no profile directory for tests MOZ_LOG(gCertBlockPRLog, LogLevel::Warning, ("CertBlocklist::SaveEntries no file in profile to write to")); return NS_OK; } // Data needed for writing blocklist items out to the revocations file IssuerTable issuerTable; BlocklistStringSet issuers; nsCOMPtr<nsIOutputStream> outputStream; rv = NS_NewAtomicFileOutputStream(getter_AddRefs(outputStream), mBackingFile, -1, -1, 0); if (NS_FAILED(rv)) { return rv; } rv = WriteLine(outputStream, NS_LITERAL_CSTRING("# Auto generated contents. Do not edit.")); if (NS_FAILED(rv)) { return rv; } // Sort blocklist items into lists of serials for each issuer for (auto iter = mBlocklist.Iter(); !iter.Done(); iter.Next()) { CertBlocklistItem item = iter.Get()->GetKey(); if (!item.mIsCurrent) { continue; } nsAutoCString encDN; nsAutoCString encOther; nsresult rv = item.ToBase64(encDN, encOther); if (NS_FAILED(rv)) { MOZ_LOG(gCertBlockPRLog, LogLevel::Warning, ("CertBlocklist::SaveEntries writing revocation data failed")); return NS_ERROR_FAILURE; } // If it's a subject / public key block, write it straight out if (item.mItemMechanism == BlockBySubjectAndPubKey) { WriteLine(outputStream, encDN); WriteLine(outputStream, NS_LITERAL_CSTRING("\t") + encOther); continue; } // Otherwise, we have to group entries by issuer issuers.PutEntry(encDN); BlocklistStringSet* issuerSet = issuerTable.Get(encDN); if (!issuerSet) { issuerSet = new BlocklistStringSet(); issuerTable.Put(encDN, issuerSet); } issuerSet->PutEntry(encOther); } for (auto iter = issuers.Iter(); !iter.Done(); iter.Next()) { nsCStringHashKey* hashKey = iter.Get(); nsAutoPtr<BlocklistStringSet> issuerSet; issuerTable.RemoveAndForget(hashKey->GetKey(), issuerSet); nsresult rv = WriteLine(outputStream, hashKey->GetKey()); if (NS_FAILED(rv)) { break; } // Write serial data to the output stream for (auto iter = issuerSet->Iter(); !iter.Done(); iter.Next()) { nsresult rv = WriteLine(outputStream, NS_LITERAL_CSTRING(" ") + iter.Get()->GetKey()); if (NS_FAILED(rv)) { MOZ_LOG(gCertBlockPRLog, LogLevel::Warning, ("CertBlocklist::SaveEntries writing revocation data failed")); return NS_ERROR_FAILURE; } } } nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outputStream); NS_ASSERTION(safeStream, "expected a safe output stream!"); if (!safeStream) { return NS_ERROR_FAILURE; } rv = safeStream->Finish(); if (NS_FAILED(rv)) { MOZ_LOG(gCertBlockPRLog, LogLevel::Warning, ("CertBlocklist::SaveEntries saving revocation data failed")); return rv; } mModified = false; return NS_OK; }