relanding Bug 399043, Workaround for Add-Certificate-Exception for (mail) ports blocked by Necko r=rrelyea, a=sayrer

This commit is contained in:
kaie@kuix.de 2007-10-19 12:16:34 -07:00
parent da462460fd
commit 62979d92f2
8 changed files with 449 additions and 3 deletions

View File

@ -83,6 +83,32 @@ function initExceptionDialog() {
gDialog.getButton("extra1").disabled = true;
}
// returns true if found and global status could be set
function findRecentBadCert(uri) {
try {
var recentCertsSvc = Components.classes["@mozilla.org/security/recentbadcerts;1"]
.getService(Components.interfaces.nsIRecentBadCertsService);
if (!recentCertsSvc)
return false;
var hostWithPort = uri.host + ":" + uri.port;
gSSLStatus = recentCertsSvc.getRecentBadCert(hostWithPort);
if (!gSSLStatus)
return false;
gCert = gSSLStatus.QueryInterface(Components.interfaces.nsISSLStatus).serverCert;
if (!gCert)
return false;
gBroken = true;
}
catch (e) {
return false;
}
updateCertStatus();
return true;
}
/**
* Attempt to download the certificate for the location specified, and populate
* the Certificate Status section with the result.
@ -95,8 +121,13 @@ function checkCert() {
gBroken = false;
updateCertStatus();
var req = new XMLHttpRequest();
var uri = getURI();
// Is the cert already known in the list of recently seen bad certs?
if (findRecentBadCert(uri) == true)
return;
var req = new XMLHttpRequest();
try {
if(uri) {
req.open('GET', uri.prePath, false);

View File

@ -62,6 +62,7 @@ SDK_XPIDLSRCS = \
XPIDLSRCS = \
nsICertOverrideService.idl \
nsIRecentBadCertsService.idl \
nsIFormSigningDialog.idl \
nsIX509Cert2.idl \
nsIX509Cert3.idl \

View File

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Red Hat, Inc.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kai Engert <kengert@redhat.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIArray;
interface nsIX509Cert;
interface nsISSLStatus;
%{C++
#define NS_RECENTBADCERTS_CONTRACTID "@mozilla.org/security/recentbadcerts;1"
%}
/**
* This represents a global list of recently seen bad ssl status
* including the bad cert.
* The implementation will decide how many entries it will hold,
* the number is expected to be small.
*/
[scriptable, uuid(a5ae8b05-a76e-408f-b0ba-02a831265749)]
interface nsIRecentBadCertsService : nsISupports {
/**
* Retrieve the recently seen bad ssl status for the given hostname:port.
* If no SSL cert was recently seen for the given hostname:port, return null.
* If a good cert was seen for the given hostname:port, return null.
*
* @param aHostNameWithPort The host:port whose entry should be tested
* @return null or a recently seen bad ssl status with cert
*/
nsISSLStatus getRecentBadCert(in AString aHostNameWithPort);
/**
* A bad certificate that should be remembered by the service.
* Will be added as the most recently seen cert.
* The service may forget older entries to make room for the new one.
*
* @param aHostNameWithPort The host:port whose entry should be tested
* @param aCert The bad ssl status with certificate
*/
void addBadCert(in AString aHostNameWithPort,
in nsISSLStatus aStatus);
};

View File

@ -59,6 +59,7 @@ PACKAGE_FILE = pipnss.pkg
CPPSRCS = \
nsNSSCleaner.cpp \
nsCertOverrideService.cpp \
nsRecentBadCerts.cpp \
nsPSMBackgroundThread.cpp \
nsSSLThread.cpp \
nsCertVerificationThread.cpp \

View File

@ -60,6 +60,7 @@
#include "nsIClientAuthDialogs.h"
#include "nsICertOverrideService.h"
#include "nsIBadCertListener2.h"
#include "nsRecentBadCerts.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
@ -2342,7 +2343,8 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
nsCString hostWithPortString = hostString;
hostWithPortString.AppendLiteral(":");
hostWithPortString.AppendInt(port);
NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
// Check the name field against the desired hostname.
if (hostname && hostname[0] &&
@ -2444,7 +2446,7 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
{
PRBool haveStoredOverride;
nsrv = overrideService->HasMatchingOverride(NS_ConvertUTF8toUTF16(hostWithPortString),
nsrv = overrideService->HasMatchingOverride(hostWithPortStringUTF16,
ix509,
&storedOverrideBits,
&haveStoredOverride);
@ -2487,6 +2489,13 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
}
}
nsCOMPtr<nsIRecentBadCertsService> recentBadCertsService =
do_GetService(NS_RECENTBADCERTS_CONTRACTID);
if (recentBadCertsService) {
recentBadCertsService->AddBadCert(hostWithPortStringUTF16, status);
}
PR_SetError(errorCodeToReport, 0);
if (!suppressMessage) {
nsHandleInvalidCertError(infoObject,
@ -2496,6 +2505,7 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
errorCodeToReport,
ix509);
}
return cancel_and_failure(infoObject);
}

View File

@ -24,6 +24,7 @@
* Hubbie Shaw
* Doug Turner <dougt@netscape.com>
* Brian Ryner <bryner@brianryner.com>
* Kai Engert <kengert@redhat.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -74,6 +75,7 @@
#include "nsDataSignatureVerifier.h"
#include "nsCertOverrideService.h"
#include "nsRandomGenerator.h"
#include "nsRecentBadCerts.h"
// We must ensure that the nsNSSComponent has been loaded before
// creating any other components.
@ -196,6 +198,7 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsKeyObjectFactory)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsDataSignatureVerifier)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(PR_FALSE, nsCertOverrideService, Init)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(PR_FALSE, nsRandomGenerator)
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(PR_FALSE, nsRecentBadCertsService, Init)
static NS_METHOD RegisterPSMContentListeners(
nsIComponentManager *aCompMgr,
@ -472,6 +475,13 @@ static const nsModuleComponentInfo components[] =
NS_RANDOMGENERATOR_CID,
NS_RANDOMGENERATOR_CONTRACTID,
nsRandomGeneratorConstructor
},
{
"PSM Recent Bad Certs Service",
NS_RECENTBADCERTS_CID,
NS_RECENTBADCERTS_CONTRACTID,
nsRecentBadCertsServiceConstructor
}
};

View File

@ -0,0 +1,190 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Red Hat, Inc.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kai Engert <kengert@redhat.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsRecentBadCerts.h"
#include "nsIX509Cert.h"
#include "nsSSLStatus.h"
#include "nsCOMPtr.h"
#include "nsNSSCertificate.h"
#include "nsCRT.h"
#include "nsPromiseFlatString.h"
#include "nsStringBuffer.h"
#include "nsAutoLock.h"
#include "nsAutoPtr.h"
#include "nspr.h"
#include "pk11pub.h"
#include "certdb.h"
#include "sechash.h"
#include "nsNSSCleaner.h"
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
NS_IMPL_THREADSAFE_ISUPPORTS1(nsRecentBadCertsService,
nsIRecentBadCertsService)
nsRecentBadCertsService::nsRecentBadCertsService()
:mNextStorePosition(0)
{
monitor = PR_NewMonitor();
}
nsRecentBadCertsService::~nsRecentBadCertsService()
{
if (monitor)
PR_DestroyMonitor(monitor);
}
nsresult
nsRecentBadCertsService::Init()
{
return NS_OK;
}
NS_IMETHODIMP
nsRecentBadCertsService::GetRecentBadCert(const nsAString & aHostNameWithPort,
nsISSLStatus **aStatus)
{
NS_ENSURE_ARG_POINTER(aStatus);
if (!aHostNameWithPort.Length())
return NS_ERROR_INVALID_ARG;
*aStatus = nsnull;
nsCOMPtr<nsSSLStatus> status = new nsSSLStatus();
if (!status)
return NS_ERROR_OUT_OF_MEMORY;
SECItem foundDER;
foundDER.len = 0;
foundDER.data = nsnull;
PRBool isDomainMismatch;
PRBool isNotValidAtThisTime;
PRBool isUntrusted;
{
nsAutoMonitor lock(monitor);
for (size_t i=0; i<const_recently_seen_list_size; ++i) {
if (mCerts[i].mHostWithPort.Equals(aHostNameWithPort)) {
SECStatus srv = SECITEM_CopyItem(nsnull, &foundDER, &mCerts[i].mDERCert);
if (srv != SECSuccess)
return NS_ERROR_OUT_OF_MEMORY;
isDomainMismatch = mCerts[i].isDomainMismatch;
isNotValidAtThisTime = mCerts[i].isNotValidAtThisTime;
isUntrusted = mCerts[i].isUntrusted;
}
}
}
if (foundDER.len) {
CERTCertificate *nssCert;
CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();
nssCert = CERT_FindCertByDERCert(certdb, &foundDER);
if (!nssCert)
nssCert = CERT_NewTempCertificate(certdb, &foundDER,
nsnull, // no nickname
PR_FALSE, // not perm
PR_TRUE); // copy der
SECITEM_FreeItem(&foundDER, PR_FALSE);
if (!nssCert)
return NS_ERROR_FAILURE;
status->mServerCert = new nsNSSCertificate(nssCert);
CERT_DestroyCertificate(nssCert);
status->mHaveCertStatus = PR_TRUE;
status->mIsDomainMismatch = isDomainMismatch;
status->mIsNotValidAtThisTime = isNotValidAtThisTime;
status->mIsUntrusted = isUntrusted;
*aStatus = status;
NS_IF_ADDREF(*aStatus);
}
return NS_OK;
}
NS_IMETHODIMP
nsRecentBadCertsService::AddBadCert(const nsAString &hostWithPort,
nsISSLStatus *aStatus)
{
NS_ENSURE_ARG(aStatus);
nsCOMPtr<nsIX509Cert> cert;
nsresult rv;
rv = aStatus->GetServerCert(getter_AddRefs(cert));
NS_ENSURE_SUCCESS(rv, rv);
PRBool isDomainMismatch;
PRBool isNotValidAtThisTime;
PRBool isUntrusted;
rv = aStatus->GetIsDomainMismatch(&isDomainMismatch);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStatus->GetIsNotValidAtThisTime(&isNotValidAtThisTime);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStatus->GetIsUntrusted(&isUntrusted);
NS_ENSURE_SUCCESS(rv, rv);
SECItem tempItem;
rv = cert->GetRawDER(&tempItem.len, (PRUint8 **)&tempItem.data);
NS_ENSURE_SUCCESS(rv, rv);
{
nsAutoMonitor lock(monitor);
RecentBadCert &updatedEntry = mCerts[mNextStorePosition];
++mNextStorePosition;
if (mNextStorePosition == const_recently_seen_list_size)
mNextStorePosition = 0;
updatedEntry.Clear();
updatedEntry.mHostWithPort = hostWithPort;
updatedEntry.mDERCert = tempItem; // consume
updatedEntry.isDomainMismatch = isDomainMismatch;
updatedEntry.isNotValidAtThisTime = isNotValidAtThisTime;
updatedEntry.isUntrusted = isUntrusted;
}
return NS_OK;
}

View File

@ -0,0 +1,124 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Red Hat, Inc.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kai Engert <kengert@redhat.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef __RECENTBADCERTS_H__
#define __RECENTBADCERTS_H__
#include "nsIRecentBadCertsService.h"
#include "nsTHashtable.h"
#include "nsString.h"
#include "prmon.h"
#include "secitem.h"
class RecentBadCert
{
public:
RecentBadCert()
{
mDERCert.len = 0;
mDERCert.data = nsnull;
isDomainMismatch = PR_FALSE;
isNotValidAtThisTime = PR_FALSE;
isUntrusted = PR_FALSE;
}
~RecentBadCert()
{
Clear();
}
void Clear()
{
mHostWithPort.Truncate();
if (mDERCert.len)
nsMemory::Free(mDERCert.data);
mDERCert.len = 0;
mDERCert.data = nsnull;
}
nsString mHostWithPort;
SECItem mDERCert;
PRBool isDomainMismatch;
PRBool isNotValidAtThisTime;
PRBool isUntrusted;
private:
RecentBadCert(const RecentBadCert &other)
{
NS_NOTREACHED("RecentBadCert(const RecentBadCert &other) not implemented");
this->operator=(other);
}
RecentBadCert &operator=(const RecentBadCert &other)
{
NS_NOTREACHED("RecentBadCert &operator=(const RecentBadCert &other) not implemented");
return *this;
}
};
class nsRecentBadCertsService : public nsIRecentBadCertsService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRECENTBADCERTSSERVICE
nsRecentBadCertsService();
~nsRecentBadCertsService();
nsresult Init();
protected:
PRMonitor *monitor;
enum {const_recently_seen_list_size = 5};
RecentBadCert mCerts[const_recently_seen_list_size];
// will be in the range of 0 to list_size-1
PRUint32 mNextStorePosition;
};
#define NS_RECENTBADCERTS_CID { /* e7caf8c0-3570-47fe-aa1b-da47539b5d07 */ \
0xe7caf8c0, \
0x3570, \
0x47fe, \
{0xaa, 0x1b, 0xda, 0x47, 0x53, 0x9b, 0x5d, 0x07} \
}
#endif