Bug 413909: nsCertOverrideService IDN handling is broken, and its port handling is also quite cumbersome, patch by Honza Bambas <honzab@allpeers.com>, r=kaie, a=shaver

This commit is contained in:
gavin%gavinsharp.com 2008-04-22 20:03:21 +00:00
Родитель 3cc41d2ff4
Коммит f2d1dc6606
8 изменённых файлов: 125 добавлений и 57 удалений

Просмотреть файл

@ -6563,7 +6563,9 @@ IdentityHandler.prototype = {
// for certs that are trusted because of a security exception.
var tooltip = this._stringBundle.getFormattedString("identity.identified.verifier",
[iData.caOrg]);
if (this._overrideService.hasMatchingOverride(lookupHost, iData.cert, {}, {}))
if (this._overrideService.hasMatchingOverride(this._lastLocation.hostname,
this._lastLocation.port,
iData.cert, {}, {}))
tooltip = this._stringBundle.getString("identity.identified.verified_by_you");
}
else if (newMode == this.IDENTITY_MODE_IDENTIFIED) {

Просмотреть файл

@ -342,8 +342,9 @@ function addException() {
var permanentCheckbox = document.getElementById("permanent");
var uri = getURI();
overrideService.rememberValidityOverride(
getURI().hostPort,
uri.asciiHost, uri.port,
gCert,
flags,
!permanentCheckbox.checked);

Просмотреть файл

@ -51,7 +51,7 @@ interface nsIX509Cert;
* {host:port, cert-fingerprint, allowed-overrides}
* that the user wants to accept without further warnings.
*/
[scriptable, uuid(13ca097a-935c-4a62-9c91-7a9d803ae701)]
[scriptable, uuid(31738d2a-77d3-4359-84c9-4be2f38fb8c5)]
interface nsICertOverrideService : nsISupports {
/**
@ -76,11 +76,14 @@ interface nsICertOverrideService : nsISupports {
* The implementation will store a fingerprint of the cert.
* The implementation will decide which fingerprint alg is used.
*
* @param aHostNameWithPort The host:port this mapping belongs to
* @param aHostName The host (punycode) this mapping belongs to
* @param aPort The port this mapping belongs to, if it is -1 then it
* is internaly treated as 443
* @param aCert The cert that should always be accepted
* @param aOverrideBits The errors we want to be overriden
*/
void rememberValidityOverride(in AString aHostNameWithPort,
void rememberValidityOverride(in ACString aHostName,
in PRInt32 aPort,
in nsIX509Cert aCert,
in PRUint32 aOverrideBits,
in boolean aTemporary);
@ -92,13 +95,16 @@ interface nsICertOverrideService : nsISupports {
* The implementation will store a fingerprint of the cert.
* The implementation will decide which fingerprint alg is used.
*
* @param aHostNameWithPort The host:port this mapping belongs to
* @param aHostName The host (punycode) this mapping belongs to
* @param aPort The port this mapping belongs to, if it is -1 then it
* is internaly treated as 443
* @param aCert The cert that should always be accepted
* @param aOverrideBits The errors that are currently overriden
* @return whether an override entry for aHostNameWithPort is currently on file
* that matches the given certificate
*/
boolean hasMatchingOverride(in AString aHostNameWithPort,
boolean hasMatchingOverride(in ACString aHostName,
in PRInt32 aPort,
in nsIX509Cert aCert,
out PRUint32 aOverrideBits,
out boolean aIsTemporary);
@ -106,7 +112,9 @@ interface nsICertOverrideService : nsISupports {
/**
* Retrieve the stored override for the given hostname:port.
*
* @param aHostNameWithPort The host:port whose entry should be tested
* @param aHostName The host (punycode) whose entry should be tested
* @param aPort The port whose entry should be tested, if it is -1 then it
* is internaly treated as 443
* @param aHashAlg On return value True, the fingerprint hash algorithm
* as an OID value in dotted notation.
* @param aFingerprint On return value True, the stored fingerprint
@ -114,7 +122,8 @@ interface nsICertOverrideService : nsISupports {
* @return whether a matching override entry for aHostNameWithPort
* and aFingerprint is currently on file
*/
boolean getValidityOverride(in AString aHostNameWithPort,
boolean getValidityOverride(in ACString aHostName,
in PRInt32 aPort,
out ACString aHashAlg,
out ACString aFingerprint,
out PRUint32 aOverrideBits,
@ -123,9 +132,12 @@ interface nsICertOverrideService : nsISupports {
/**
* Remove a override for the given hostname:port.
*
* @param aHostNameWithPort The host:port whose entry should be cleared.
* @param aHostName The host (punycode) whose entry should be cleared.
* @param aPort The port whose entry should be cleared, if it is -1 then it
* is internaly treated as 443
*/
void clearValidityOverride(in AString aHostNameWithPort);
void clearValidityOverride(in ACString aHostName,
in PRInt32 aPort);
/**
* Obtain the full list of hostname:port for which overrides are known.

Просмотреть файл

@ -266,16 +266,30 @@ nsCertOverrideService::Read()
continue;
}
const nsASingleFragmentCString &host = Substring(buffer, hostIndex, algoIndex - hostIndex - 1);
const nsASingleFragmentCString &tmp = Substring(buffer, hostIndex, algoIndex - hostIndex - 1);
const nsASingleFragmentCString &algo_string = Substring(buffer, algoIndex, fingerprintIndex - algoIndex - 1);
const nsASingleFragmentCString &fingerprint = Substring(buffer, fingerprintIndex, overrideBitsIndex - fingerprintIndex - 1);
const nsASingleFragmentCString &bits_string = Substring(buffer, overrideBitsIndex, dbKeyIndex - overrideBitsIndex - 1);
const nsASingleFragmentCString &db_key = Substring(buffer, dbKeyIndex, buffer.Length() - dbKeyIndex);
nsCAutoString host(tmp);
nsCertOverride::OverrideBits bits;
nsCertOverride::convertStringToBits(bits_string, bits);
AddEntryToList(host,
PRInt32 port;
PRInt32 portIndex = host.RFindChar(':');
if (portIndex == kNotFound)
continue; // Ignore broken entries
PRInt32 portParseError;
nsCAutoString portString(Substring(host, portIndex+1));
port = portString.ToInteger(&portParseError);
if (portParseError)
continue; // Ignore broken entries
host.Truncate(portIndex);
AddEntryToList(host, port,
PR_FALSE, // not temporary
algo_string, fingerprint, bits, db_key);
}
@ -303,7 +317,7 @@ WriteEntryCallback(nsCertOverrideEntry *aEntry,
nsCertOverride::convertBitsToString(settings.mOverrideBits,
bits_string);
rawStreamPtr->Write(settings.mHostWithPortUTF8.get(), settings.mHostWithPortUTF8.Length(), &rv);
rawStreamPtr->Write(aEntry->mHostWithPort.get(), aEntry->mHostWithPort.Length(), &rv);
rawStreamPtr->Write(kTab, sizeof(kTab) - 1, &rv);
rawStreamPtr->Write(settings.mFingerprintAlgOID.get(),
settings.mFingerprintAlgOID.Length(), &rv);
@ -452,13 +466,15 @@ GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
}
NS_IMETHODIMP
nsCertOverrideService::RememberValidityOverride(const nsAString & aHostNameWithPort,
nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, PRInt32 aPort,
nsIX509Cert *aCert,
PRUint32 aOverrideBits,
PRBool aTemporary)
{
NS_ENSURE_ARG_POINTER(aCert);
if (aHostNameWithPort.IsEmpty())
if (aHostName.IsEmpty())
return NS_ERROR_INVALID_ARG;
if (aPort < -1)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
@ -487,14 +503,6 @@ nsCertOverrideService::RememberValidityOverride(const nsAString & aHostNameWithP
if (srv != SECSuccess)
return NS_ERROR_FAILURE;
nsCString myHostPort;
myHostPort = NS_ConvertUTF16toUTF8(aHostNameWithPort);
PRInt32 find_colon = myHostPort.FindChar(':');
if (find_colon == -1) {
myHostPort.AppendLiteral(":443");
}
nsCAutoString fpStr;
nsresult rv = GetCertFingerprintByOidTag(nsscert,
mOidTagForStoringNewHashes, fpStr);
@ -518,7 +526,7 @@ nsCertOverrideService::RememberValidityOverride(const nsAString & aHostNameWithP
{
nsAutoMonitor lock(monitor);
AddEntryToList(myHostPort,
AddEntryToList(aHostName, aPort,
aTemporary,
mDottedOidForStoringNewHashes, fpStr,
(nsCertOverride::OverrideBits)aOverrideBits,
@ -531,13 +539,15 @@ nsCertOverrideService::RememberValidityOverride(const nsAString & aHostNameWithP
}
NS_IMETHODIMP
nsCertOverrideService::HasMatchingOverride(const nsAString & aHostNameWithPort,
nsCertOverrideService::HasMatchingOverride(const nsACString & aHostName, PRInt32 aPort,
nsIX509Cert *aCert,
PRUint32 *aOverrideBits,
PRBool *aIsTemporary,
PRBool *_retval)
{
if (aHostNameWithPort.IsEmpty())
if (aHostName.IsEmpty())
return NS_ERROR_INVALID_ARG;
if (aPort < -1)
return NS_ERROR_INVALID_ARG;
NS_ENSURE_ARG_POINTER(aCert);
@ -547,12 +557,13 @@ nsCertOverrideService::HasMatchingOverride(const nsAString & aHostNameWithPort,
*_retval = PR_FALSE;
*aOverrideBits = nsCertOverride::ob_None;
NS_ConvertUTF16toUTF8 hp8(aHostNameWithPort);
nsCAutoString hostPort;
GetHostWithPort(aHostName, aPort, hostPort);
nsCertOverride settings;
{
nsAutoMonitor lock(monitor);
nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hp8.get());
nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
if (!entry)
return NS_OK;
@ -580,7 +591,7 @@ nsCertOverrideService::HasMatchingOverride(const nsAString & aHostNameWithPort,
}
NS_IMETHODIMP
nsCertOverrideService::GetValidityOverride(const nsAString & aHostNameWithPort,
nsCertOverrideService::GetValidityOverride(const nsACString & aHostName, PRInt32 aPort,
nsACString & aHashAlg,
nsACString & aFingerprint,
PRUint32 *aOverrideBits,
@ -593,12 +604,13 @@ nsCertOverrideService::GetValidityOverride(const nsAString & aHostNameWithPort,
*_found = PR_FALSE;
*aOverrideBits = nsCertOverride::ob_None;
NS_ConvertUTF16toUTF8 hp8(aHostNameWithPort);
nsCAutoString hostPort;
GetHostWithPort(aHostName, aPort, hostPort);
nsCertOverride settings;
{
nsAutoMonitor lock(monitor);
nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hp8.get());
nsCertOverrideEntry *entry = mSettingsTable.GetEntry(hostPort.get());
if (entry) {
*_found = PR_TRUE;
@ -617,26 +629,30 @@ nsCertOverrideService::GetValidityOverride(const nsAString & aHostNameWithPort,
}
nsresult
nsCertOverrideService::AddEntryToList(const nsACString &hostWithPortUTF8,
nsCertOverrideService::AddEntryToList(const nsACString &aHostName, PRInt32 aPort,
const PRBool aIsTemporary,
const nsACString &fingerprintAlgOID,
const nsACString &fingerprint,
nsCertOverride::OverrideBits ob,
const nsACString &dbKey)
{
const nsPromiseFlatCString &flat = PromiseFlatCString(hostWithPortUTF8);
nsCAutoString hostPort;
GetHostWithPort(aHostName, aPort, hostPort);
{
nsAutoMonitor lock(monitor);
nsCertOverrideEntry *entry = mSettingsTable.PutEntry(flat.get());
nsCertOverrideEntry *entry = mSettingsTable.PutEntry(hostPort.get());
if (!entry) {
NS_ERROR("can't insert a null entry!");
return NS_ERROR_OUT_OF_MEMORY;
}
entry->mHostWithPort = hostPort;
nsCertOverride &settings = entry->mSettings;
settings.mHostWithPortUTF8 = hostWithPortUTF8;
settings.mAsciiHost = aHostName;
settings.mPort = aPort;
settings.mIsTemporary = aIsTemporary;
settings.mFingerprintAlgOID = fingerprintAlgOID;
settings.mFingerprint = fingerprint;
@ -648,12 +664,13 @@ nsCertOverrideService::AddEntryToList(const nsACString &hostWithPortUTF8,
}
NS_IMETHODIMP
nsCertOverrideService::ClearValidityOverride(const nsAString & aHostNameWithPort)
nsCertOverrideService::ClearValidityOverride(const nsACString & aHostName, PRInt32 aPort)
{
NS_ConvertUTF16toUTF8 hp8(aHostNameWithPort);
nsCAutoString hostPort;
GetHostWithPort(aHostName, aPort, hostPort);
{
nsAutoMonitor lock(monitor);
mSettingsTable.RemoveEntry(hp8.get());
mSettingsTable.RemoveEntry(hostPort.get());
Write();
}
SSL_ClearSessionCache();
@ -853,3 +870,15 @@ nsCertOverrideService::EnumerateCertOverrides(nsIX509Cert *aCert,
}
return NS_OK;
}
void
nsCertOverrideService::GetHostWithPort(const nsACString & aHostName, PRInt32 aPort, nsACString& _retval)
{
nsCAutoString hostPort(aHostName);
if (aPort == -1)
aPort = 443;
hostPort.AppendLiteral(":");
hostPort.AppendInt(aPort);
_retval.Assign(hostPort);
}

Просмотреть файл

@ -58,7 +58,8 @@ public:
ob_Time_error=4 };
nsCertOverride()
:mOverrideBits(ob_None)
:mPort(-1)
,mOverrideBits(ob_None)
{
}
@ -69,7 +70,8 @@ public:
nsCertOverride &operator=(const nsCertOverride &other)
{
mHostWithPortUTF8 = other.mHostWithPortUTF8;
mAsciiHost = other.mAsciiHost;
mPort = other.mPort;
mIsTemporary = other.mIsTemporary;
mFingerprintAlgOID = other.mFingerprintAlgOID;
mFingerprint = other.mFingerprint;
@ -78,7 +80,8 @@ public:
return *this;
}
nsCString mHostWithPortUTF8;
nsCString mAsciiHost;
PRInt32 mPort;
PRBool mIsTemporary; // true: session only, false: stored on disk
nsCString mFingerprint;
nsCString mFingerprintAlgOID;
@ -142,14 +145,15 @@ class nsCertOverrideEntry : public PLDHashEntryHdr
enum { ALLOW_MEMMOVE = PR_FALSE };
// get methods
inline const nsCString &HostWithPort() const { return mSettings.mHostWithPortUTF8; }
inline const nsCString &HostWithPort() const { return mHostWithPort; }
inline KeyTypePointer HostWithPortPtr() const
{
return mSettings.mHostWithPortUTF8.get();
return mHostWithPort.get();
}
nsCertOverride mSettings;
nsCString mHostWithPort;
};
class nsCertOverrideService : public nsICertOverrideService
@ -176,6 +180,11 @@ public:
CertOverrideEnumerator enumerator,
void *aUserData);
// Concates host name and the port number. If the port number is -1 then
// port 443 is automatically used. This method ensures there is always a port
// number separated with colon.
static void GetHostWithPort(const nsACString & aHostName, PRInt32 aPort, nsACString& _retval);
protected:
PRMonitor *monitor;
nsCOMPtr<nsIFile> mSettingsFile;
@ -187,7 +196,7 @@ protected:
void RemoveAllFromMemory();
nsresult Read();
nsresult Write();
nsresult AddEntryToList(const nsACString &hostWithPortUTF8,
nsresult AddEntryToList(const nsACString &host, PRInt32 port,
const PRBool aIsTemporary,
const nsACString &algo_oid,
const nsACString &fingerprint,

Просмотреть файл

@ -143,6 +143,7 @@ NS_IMPL_ISUPPORTS1(nsCertTreeDispInfo, nsICertTreeItem)
nsCertTreeDispInfo::nsCertTreeDispInfo()
:mAddonInfo(nsnull)
,mTypeOfEntry(direct_db)
,mPort(-1)
,mOverrideBits(nsCertOverride::ob_None)
,mIsTemporary(PR_TRUE)
{
@ -152,7 +153,8 @@ nsCertTreeDispInfo::nsCertTreeDispInfo(nsCertTreeDispInfo &other)
{
mAddonInfo = other.mAddonInfo;
mTypeOfEntry = other.mTypeOfEntry;
mHostWithPort = other.mHostWithPort;
mAsciiHost = other.mAsciiHost;
mPort = other.mPort;
mOverrideBits = other.mOverrideBits;
mIsTemporary = other.mIsTemporary;
}
@ -178,7 +180,9 @@ nsCertTreeDispInfo::GetCert(nsIX509Cert **_cert)
NS_IMETHODIMP
nsCertTreeDispInfo::GetHostPort(nsAString &aHostPort)
{
aHostPort = mHostWithPort;
nsCAutoString hostPort;
nsCertOverrideService::GetHostWithPort(mAsciiHost, mPort, hostPort);
aHostPort = NS_ConvertUTF8toUTF16(hostPort);
return NS_OK;
}
@ -389,7 +393,8 @@ MatchingCertOverridesCallback(const nsCertOverride &aSettings,
cap->certai->mUsageCount++;
certdi->mAddonInfo = cap->certai;
certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override;
certdi->mHostWithPort = NS_ConvertUTF8toUTF16(aSettings.mHostWithPortUTF8);
certdi->mAsciiHost = aSettings.mAsciiHost;
certdi->mPort = aSettings.mPort;
certdi->mOverrideBits = aSettings.mOverrideBits;
certdi->mIsTemporary = aSettings.mIsTemporary;
cap->array->InsertElementAt(cap->position, certdi);
@ -399,7 +404,9 @@ MatchingCertOverridesCallback(const nsCertOverride &aSettings,
// this entry is now associated to a displayed cert, remove
// it from the list of remaining entries
cap->tracker->RemoveEntry(aSettings.mHostWithPortUTF8);
nsCAutoString hostPort;
nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort);
cap->tracker->RemoveEntry(hostPort);
}
// Used to collect a list of the (unique) host:port keys
@ -413,7 +420,9 @@ CollectAllHostPortOverridesCallback(const nsCertOverride &aSettings,
if (!collectorTable)
return;
collectorTable->PutEntry(aSettings.mHostWithPortUTF8);
nsCAutoString hostPort;
nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort);
collectorTable->PutEntry(hostPort);
}
struct nsArrayAndPositionAndCounterAndTracker
@ -435,7 +444,9 @@ AddRemaningHostPortOverridesCallback(const nsCertOverride &aSettings,
if (!cap)
return;
if (!cap->tracker->GetEntry(aSettings.mHostWithPortUTF8))
nsCAutoString hostPort;
nsCertOverrideService::GetHostWithPort(aSettings.mAsciiHost, aSettings.mPort, hostPort);
if (!cap->tracker->GetEntry(hostPort))
return;
// This entry is not associated to any stored cert,
@ -445,7 +456,8 @@ AddRemaningHostPortOverridesCallback(const nsCertOverride &aSettings,
if (certdi) {
certdi->mAddonInfo = nsnull;
certdi->mTypeOfEntry = nsCertTreeDispInfo::host_port_override;
certdi->mHostWithPort = NS_ConvertUTF8toUTF16(aSettings.mHostWithPortUTF8);
certdi->mAsciiHost = aSettings.mAsciiHost;
certdi->mPort = aSettings.mPort;
certdi->mOverrideBits = aSettings.mOverrideBits;
certdi->mIsTemporary = aSettings.mIsTemporary;
cap->array->InsertElementAt(cap->position, certdi);
@ -609,7 +621,7 @@ nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
certdi->mAddonInfo = certai;
certai->mUsageCount++;
certdi->mTypeOfEntry = nsCertTreeDispInfo::direct_db;
// not necessary: certdi->mHostWithPort.Clear();
// not necessary: certdi->mAsciiHost.Clear(); certdi->mPort = -1;
certdi->mOverrideBits = nsCertOverride::ob_None;
certdi->mIsTemporary = PR_FALSE;
mDispInfo.InsertElementAt(InsertPosition, certdi);
@ -798,7 +810,7 @@ nsCertTree::DeleteEntryObject(PRUint32 index)
PRBool canRemoveEntry = PR_FALSE;
if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) {
mOverrideService->ClearValidityOverride(certdi->mHostWithPort);
mOverrideService->ClearValidityOverride(certdi->mAsciiHost, certdi->mPort);
if (certdi->mAddonInfo) {
certdi->mAddonInfo->mUsageCount--;
if (certdi->mAddonInfo->mUsageCount == 0) {
@ -1238,7 +1250,9 @@ nsCertTree::GetCellText(PRInt32 row, nsITreeColumn* col,
_retval = NS_ConvertUTF8toUTF16(temp);
} else if (NS_LITERAL_STRING("sitecol").Equals(colID)) {
if (certdi->mTypeOfEntry == nsCertTreeDispInfo::host_port_override) {
_retval = certdi->mHostWithPort;
nsCAutoString hostPort;
nsCertOverrideService::GetHostWithPort(certdi->mAsciiHost, certdi->mPort, hostPort);
_retval = NS_ConvertUTF8toUTF16(hostPort);
}
else {
_retval = NS_LITERAL_STRING("*");

Просмотреть файл

@ -98,7 +98,8 @@ public:
enum {
direct_db, host_port_override
} mTypeOfEntry;
nsString mHostWithPort;
nsCString mAsciiHost;
PRInt32 mPort;
nsCertOverride::OverrideBits mOverrideBits;
PRBool mIsTemporary;
};

Просмотреть файл

@ -2987,7 +2987,7 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
PRBool haveOverride;
PRBool isTemporaryOverride; // we don't care
nsrv = overrideService->HasMatchingOverride(hostWithPortStringUTF16,
nsrv = overrideService->HasMatchingOverride(hostString, port,
ix509,
&overrideBits,
&isTemporaryOverride,