Bug 479393, Add libpkix-based certificate validation to PSM (off by default), r=rrelyea, r=bsmith

This commit is contained in:
Kai Engert 2011-05-05 22:41:40 +02:00
Родитель de8d6b2b66
Коммит a62ee5e18e
14 изменённых файлов: 645 добавлений и 54 удалений

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

@ -214,12 +214,13 @@ interface nsIX509Cert : nsISupports {
* Obtain an array of human readable strings describing
* the certificate's certified usages.
*
* @param ignoreOcsp Do not use OCSP even if it is currently activated.
* @param localOnly Do not hit the network, even if revocation information
* downloading is currently activated.
* @param verified The certificate verification result, see constants.
* @param count The number of human readable usages returned.
* @param usages The array of human readable usages.
*/
void getUsagesArray(in boolean ignoreOcsp,
void getUsagesArray(in boolean localOnly,
out PRUint32 verified,
out PRUint32 count,
[array, size_is(count)] out wstring usages);
@ -228,11 +229,12 @@ interface nsIX509Cert : nsISupports {
* Obtain a single comma separated human readable string describing
* the certificate's certified usages.
*
* @param ignoreOcsp Do not use OCSP even if it is currently activated.
* @param localOnly Do not hit the network, even if revocation information
* downloading is currently activated.
* @param verified The certificate verification result, see constants.
* @param purposes The string listing the usages.
*/
void getUsagesString(in boolean ignoreOcsp, out PRUint32 verified, out AString usages);
void getUsagesString(in boolean localOnly, out PRUint32 verified, out AString usages);
/**
* Verify the certificate for a particular usage.

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

@ -54,6 +54,7 @@ GRE_MODULE = 1
LIBXUL_LIBRARY = 1
CPPSRCS = \
nsCERTValInParamWrapper.cpp \
nsNSSCleaner.cpp \
nsCertOverrideService.cpp \
nsRecentBadCerts.cpp \

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

@ -0,0 +1,157 @@
/* ***** 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) 2011
* 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 "nsCERTValInParamWrapper.h"
NS_IMPL_THREADSAFE_ADDREF(nsCERTValInParamWrapper)
NS_IMPL_THREADSAFE_RELEASE(nsCERTValInParamWrapper)
nsCERTValInParamWrapper::nsCERTValInParamWrapper()
:mAlreadyConstructed(PR_FALSE)
,mCVIN(nsnull)
,mRev(nsnull)
{
MOZ_COUNT_CTOR(nsCERTValInParamWrapper);
}
nsCERTValInParamWrapper::~nsCERTValInParamWrapper()
{
MOZ_COUNT_DTOR(nsCERTValInParamWrapper);
if (mRev) {
CERT_DestroyCERTRevocationFlags(mRev);
}
if (mCVIN)
PORT_Free(mCVIN);
}
nsresult nsCERTValInParamWrapper::Construct(missing_cert_download_config mcdc,
crl_download_config cdc,
ocsp_download_config odc,
ocsp_strict_config osc,
any_revo_fresh_config arfc,
const char *firstNetworkRevocationMethod)
{
if (mAlreadyConstructed)
return NS_ERROR_FAILURE;
CERTValInParam *p = (CERTValInParam*)PORT_Alloc(3 * sizeof(CERTValInParam));
if (!p)
return NS_ERROR_OUT_OF_MEMORY;
CERTRevocationFlags *rev = CERT_AllocCERTRevocationFlags(
cert_revocation_method_ocsp +1, 1,
cert_revocation_method_ocsp +1, 1);
if (!rev) {
PORT_Free(p);
return NS_ERROR_OUT_OF_MEMORY;
}
p[0].type = cert_pi_useAIACertFetch;
p[0].value.scalar.b = (mcdc == missing_cert_download_on);
p[1].type = cert_pi_revocationFlags;
p[1].value.pointer.revocation = rev;
p[2].type = cert_pi_end;
rev->leafTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
rev->chainTests.cert_rev_flags_per_method[cert_revocation_method_crl] =
// implicit default source - makes no sense for CRLs
CERT_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE
// let's not stop on fresh CRL. If OCSP is enabled, too, let's check it
| CERT_REV_M_CONTINUE_TESTING_ON_FRESH_INFO
// no fresh CRL? well, let other flag decide whether to fail or not
| CERT_REV_M_IGNORE_MISSING_FRESH_INFO
// testing using local CRLs is always allowed
| CERT_REV_M_TEST_USING_THIS_METHOD
// no local crl and don't know where to get it from? ignore
| CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE
// crl download based on parameter
| ((cdc == crl_download_allowed) ?
CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING)
;
rev->leafTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] =
rev->chainTests.cert_rev_flags_per_method[cert_revocation_method_ocsp] =
// is ocsp enabled at all?
((odc == ocsp_on) ?
CERT_REV_M_TEST_USING_THIS_METHOD : CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD)
// ocsp enabled controls network fetching, too
| ((odc == ocsp_on) ?
CERT_REV_M_ALLOW_NETWORK_FETCHING : CERT_REV_M_FORBID_NETWORK_FETCHING)
// ocsp set to strict==required?
| ((osc == ocsp_strict) ?
CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO : CERT_REV_M_IGNORE_MISSING_FRESH_INFO)
// if app has a default OCSP responder configured, let's use it
| CERT_REV_M_ALLOW_IMPLICIT_DEFAULT_SOURCE
// of course OCSP doesn't work without a source. let's accept such certs
| CERT_REV_M_SKIP_TEST_ON_MISSING_SOURCE
// ocsp success is sufficient
| CERT_REV_M_STOP_TESTING_ON_FRESH_INFO
;
PRBool wantsCrlFirst = (firstNetworkRevocationMethod != nsnull)
&& (strcmp("crl", firstNetworkRevocationMethod) == 0);
rev->leafTests.preferred_methods[0] =
rev->chainTests.preferred_methods[0] =
wantsCrlFirst ? cert_revocation_method_crl : cert_revocation_method_ocsp;
rev->leafTests.cert_rev_method_independent_flags =
rev->chainTests.cert_rev_method_independent_flags =
// avoiding the network is good, let's try local first
CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
// is overall revocation requirement strict or relaxed?
| ((arfc == any_revo_strict) ?
CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE : CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT)
;
mAlreadyConstructed = PR_TRUE;
mCVIN = p;
mRev = rev;
return NS_OK;
}

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

@ -0,0 +1,102 @@
/* ***** 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) 2011
* 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 _nsCERTValInParamWrapper_H
#define _nsCERTValInParamWrapper_H
#include "nsISupports.h"
#include "cert.h"
/*
* This is a wrapper around type
* CERTValInParam is a nested input parameter type for CERT_PKIXVerifyCert.
* The values inside this type depend on application preferences,
* as a consequence it's expensive to construct this object.
* (and we shall avoid to access prefs from secondary threads anyway).
* We want to create an instance of that input type once, and use as long as possible.
* Every time the preferences change, we will create a new default object.
*
* A race is possible between "verification function is active and object in use"
* and "must switch to new defaults".
*
* The global default object may be replaced at any time with a new object.
* The contents of inner CERTValInParam are supposed to be stable (const).
*
* In order to protect against the race, we use a reference counted wrapper.
* Each user of a foreign nsCERTValInParamWrapper object
* (e.g. the current global default object)
* must use nsRefPtr<nsCERTValInParamWrapper> = other-object
* prior to calling CERT_PKIXVerifyCert.
*
* This guarantees the object will still be alive after the call,
* and if the default object has been replaced in the meantime,
* the reference counter will go to zero, and the old default
* object will get destroyed automatically.
*/
class nsCERTValInParamWrapper
{
public:
NS_IMETHOD_(nsrefcnt) AddRef();
NS_IMETHOD_(nsrefcnt) Release();
public:
nsCERTValInParamWrapper();
virtual ~nsCERTValInParamWrapper();
enum missing_cert_download_config { missing_cert_download_off = 0, missing_cert_download_on };
enum crl_download_config { crl_local_only = 0, crl_download_allowed };
enum ocsp_download_config { ocsp_off = 0, ocsp_on };
enum ocsp_strict_config { ocsp_relaxed = 0, ocsp_strict };
enum any_revo_fresh_config { any_revo_relaxed = 0, any_revo_strict };
nsresult Construct(missing_cert_download_config ac, crl_download_config cdc,
ocsp_download_config odc, ocsp_strict_config osc,
any_revo_fresh_config arfc,
const char *firstNetworkRevocationMethod);
private:
nsAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
PRBool mAlreadyConstructed;
CERTValInParam *mCVIN;
CERTRevocationFlags *mRev;
public:
CERTValInParam *GetRawPointerForNSS() { return mCVIN; }
};
#endif

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

@ -46,6 +46,7 @@
#include "nsIArray.h"
#include "nsArrayUtils.h"
#include "nsCertVerificationThread.h"
#include "nsCERTValInParamWrapper.h"
#include "prlog.h"
#ifdef PR_LOGGING
@ -53,6 +54,8 @@ extern PRLogModuleInfo* gPIPNSSLog;
#endif
#include "nsNSSCleaner.h"
#include "nsNSSComponent.h"
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
@ -247,6 +250,8 @@ nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, PRUint3
NSSCMSSignerInfo *si;
PRInt32 nsigners;
nsresult rv = NS_ERROR_FAILURE;
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
nsCOMPtr<nsINSSComponent> inss;
if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - not signed\n"));
@ -287,9 +292,10 @@ nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, PRUint3
PR_ASSERT(nsigners > 0);
si = NSS_CMSSignedData_GetSignerInfo(sigd, 0);
// See bug 324474. We want to make sure the signing cert is
// still valid at the current time.
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), si->cert, PR_TRUE,
certificateUsageEmailSigner,
si->cmsg->pwfn_arg, NULL) != SECSuccess) {
@ -297,6 +303,28 @@ nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, PRUint3
rv = NS_ERROR_CMS_VERIFY_UNTRUSTED;
goto loser;
}
}
else {
CERTValOutParam cvout[1];
cvout[0].type = cert_po_end;
inss = do_GetService(kNSSComponentCID, &rv);
if (!inss) {
goto loser;
}
if (NS_FAILED(inss->GetDefaultCERTValInParam(survivingParams))) {
goto loser;
}
rv = CERT_PKIXVerifyCert(si->cert, certificateUsageEmailSigner,
survivingParams->GetRawPointerForNSS(),
cvout, si->cmsg->pwfn_arg);
if (rv != SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted now\n"));
rv = NS_ERROR_CMS_VERIFY_UNTRUSTED;
goto loser;
}
}
// We verify the first signer info, only //
if (NSS_CMSSignedData_VerifySignerInfo(sigd, 0, CERT_GetDefaultCertDB(), certUsageEmailSigner) != SECSuccess) {

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

@ -75,6 +75,7 @@
#include "ocsp.h"
#include "nssb64.h"
#include "secerr.h"
#include "sslerr.h"
using namespace mozilla;
@ -958,6 +959,60 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
PR_Free(signer);
}
SECStatus
PSM_SSL_PKIX_AuthCertificate(PRFileDesc *fd, CERTCertificate *peerCert, PRBool checksig, PRBool isServer)
{
SECStatus rv;
SECCertUsage certUsage;
SECCertificateUsage certificateusage;
void * pinarg;
char * hostname;
pinarg = SSL_RevealPinArg(fd);
hostname = SSL_RevealURL(fd);
/* this may seem backwards, but isn't. */
certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
certificateusage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer;
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, checksig, certUsage,
pinarg);
}
else {
nsresult nsrv;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss)
return SECFailure;
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
if (NS_FAILED(inss->GetDefaultCERTValInParam(survivingParams)))
return SECFailure;
CERTValOutParam cvout[1];
cvout[0].type = cert_po_end;
rv = CERT_PKIXVerifyCert(peerCert, certificateusage,
survivingParams->GetRawPointerForNSS(),
cvout, pinarg);
}
if ( rv == SECSuccess && isServer ) {
/* cert is OK. This is the client side of an SSL connection.
* Now check the name field in the cert against the desired hostname.
* NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
*/
if (hostname && hostname[0])
rv = CERT_VerifyCertName(peerCert, hostname);
else
rv = SECFailure;
if (rv != SECSuccess)
PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
}
PORT_Free(hostname);
return rv;
}
struct nsSerialBinaryBlacklistEntry
{
unsigned int len;
@ -1025,8 +1080,7 @@ SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
}
}
// first the default action
SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
SECStatus rv = PSM_SSL_PKIX_AuthCertificate(fd, serverCert, checksig, isServer);
// We want to remember the CA certs in the temp db, so that the application can find the
// complete chain at any time it might need it.

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

@ -1289,6 +1289,15 @@ nsNSSCertificate::VerifyForUsage(PRUint32 usage, PRUint32 *verificationResult)
NS_ENSURE_ARG(verificationResult);
nsresult nsrv;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss)
return nsrv;
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
nsrv = inss->GetDefaultCERTValInParam(survivingParams);
if (NS_FAILED(nsrv))
return nsrv;
SECCertificateUsage nss_usage;
switch (usage)
@ -1345,10 +1354,21 @@ nsNSSCertificate::VerifyForUsage(PRUint32 usage, PRUint32 *verificationResult)
return NS_ERROR_FAILURE;
}
SECStatus verify_result;
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
CERTCertDBHandle *defaultcertdb = CERT_GetDefaultCertDB();
if (CERT_VerifyCertificateNow(defaultcertdb, mCert, PR_TRUE,
nss_usage, NULL, NULL) == SECSuccess)
verify_result = CERT_VerifyCertificateNow(defaultcertdb, mCert, PR_TRUE,
nss_usage, NULL, NULL);
}
else {
CERTValOutParam cvout[1];
cvout[0].type = cert_po_end;
verify_result = CERT_PKIXVerifyCert(mCert, nss_usage,
survivingParams->GetRawPointerForNSS(),
cvout, NULL);
}
if (verify_result == SECSuccess)
{
*verificationResult = VERIFIED_OK;
}
@ -1401,7 +1421,7 @@ nsNSSCertificate::VerifyForUsage(PRUint32 usage, PRUint32 *verificationResult)
NS_IMETHODIMP
nsNSSCertificate::GetUsagesArray(PRBool ignoreOcsp,
nsNSSCertificate::GetUsagesArray(PRBool localOnly,
PRUint32 *_verified,
PRUint32 *_count,
PRUnichar ***_usages)
@ -1416,7 +1436,7 @@ nsNSSCertificate::GetUsagesArray(PRBool ignoreOcsp,
const char *suffix = "";
PRUint32 tmpCount;
nsUsageArrayHelper uah(mCert);
rv = uah.GetUsagesArray(suffix, ignoreOcsp, max_usages, _verified, &tmpCount, tmpUsages);
rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount, tmpUsages);
NS_ENSURE_SUCCESS(rv,rv);
if (tmpCount > 0) {
*_usages = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * tmpCount);
@ -1456,7 +1476,7 @@ nsNSSCertificate::RequestUsagesArrayAsync(nsICertVerificationListener *aResultLi
}
NS_IMETHODIMP
nsNSSCertificate::GetUsagesString(PRBool ignoreOcsp,
nsNSSCertificate::GetUsagesString(PRBool localOnly,
PRUint32 *_verified,
nsAString &_usages)
{
@ -1470,7 +1490,7 @@ nsNSSCertificate::GetUsagesString(PRBool ignoreOcsp,
const char *suffix = "_p";
PRUint32 tmpCount;
nsUsageArrayHelper uah(mCert);
rv = uah.GetUsagesArray(suffix, ignoreOcsp, max_usages, _verified, &tmpCount, tmpUsages);
rv = uah.GetUsagesArray(suffix, localOnly, max_usages, _verified, &tmpCount, tmpUsages);
NS_ENSURE_SUCCESS(rv,rv);
_usages.Truncate();
for (PRUint32 i=0; i<tmpCount; i++) {

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

@ -533,9 +533,18 @@ nsNSSCertificateDB::ImportEmailCertificate(PRUint8 * data, PRUint32 length,
CERTCertListNode *node;
PRTime now;
SECCertUsage certusage;
SECCertificateUsage certificateusage;
SECItem **rawArray;
int numcerts;
int i;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss)
return nsrv;
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
nsrv = inss->GetDefaultCERTValInParam(survivingParams);
if (NS_FAILED(nsrv))
return nsrv;
PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
@ -549,6 +558,7 @@ nsNSSCertificateDB::ImportEmailCertificate(PRUint8 * data, PRUint32 length,
certdb = CERT_GetDefaultCertDB();
certusage = certUsageEmailRecipient;
certificateusage = certificateUsageEmailRecipient;
numcerts = certCollection->numcerts;
@ -591,6 +601,9 @@ nsNSSCertificateDB::ImportEmailCertificate(PRUint8 * data, PRUint32 length,
* valid chains, then import them.
*/
now = PR_Now();
CERTValOutParam cvout[1];
cvout[0].type = cert_po_end;
for (node = CERT_LIST_HEAD(certList);
!CERT_LIST_END(node,certList);
node = CERT_LIST_NEXT(node)) {
@ -601,10 +614,20 @@ nsNSSCertificateDB::ImportEmailCertificate(PRUint8 * data, PRUint32 length,
continue;
}
if (CERT_VerifyCert(certdb, node->cert,
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
if (CERT_VerifyCert(certdb, node->cert,
PR_TRUE, certusage, now, ctx, NULL) != SECSuccess) {
alert_and_skip = true;
}
}
else {
if (CERT_PKIXVerifyCert(node->cert, certificateusage,
survivingParams->GetRawPointerForNSS(),
cvout, ctx)
!= SECSuccess) {
alert_and_skip = true;
}
}
CERTCertificateList *certChain = nsnull;
CERTCertificateListCleaner chainCleaner(certChain);
@ -774,6 +797,14 @@ nsresult
nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfaceRequestor *ctx)
{
SECItem **rawArray;
nsresult nsrv;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss)
return nsrv;
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
nsrv = inss->GetDefaultCERTValInParam(survivingParams);
if (NS_FAILED(nsrv))
return nsrv;
/* filter out the certs we don't want */
SECStatus srv = CERT_FilterCertListByUsage(certList, certUsageAnyCA, PR_TRUE);
@ -784,18 +815,30 @@ nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfac
/* go down the remaining list of certs and verify that they have
* valid chains, if yes, then import.
*/
PRTime now = PR_Now();
CERTCertListNode *node;
CERTValOutParam cvout[1];
cvout[0].type = cert_po_end;
for (node = CERT_LIST_HEAD(certList);
!CERT_LIST_END(node,certList);
node = CERT_LIST_NEXT(node)) {
bool alert_and_skip = false;
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
if (CERT_VerifyCert(CERT_GetDefaultCertDB(), node->cert,
PR_TRUE, certUsageVerifyCA, now, ctx, NULL) != SECSuccess) {
PR_TRUE, certUsageVerifyCA, PR_Now(), ctx, NULL) != SECSuccess) {
alert_and_skip = true;
}
}
else {
if (CERT_PKIXVerifyCert(node->cert, certificateUsageVerifyCA,
survivingParams->GetRawPointerForNSS(),
cvout, ctx)
!= SECSuccess) {
alert_and_skip = true;
}
}
CERTCertificateList *certChain = nsnull;
CERTCertificateListCleaner chainCleaner(certChain);

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

@ -284,7 +284,7 @@ nsNSSCertificateFakeTransport::VerifyForUsage(PRUint32 usage, PRUint32 *verifica
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetUsagesArray(PRBool ignoreOcsp,
nsNSSCertificateFakeTransport::GetUsagesArray(PRBool localOnly,
PRUint32 *_verified,
PRUint32 *_count,
PRUnichar ***_usages)
@ -301,7 +301,7 @@ nsNSSCertificateFakeTransport::RequestUsagesArrayAsync(nsICertVerificationListen
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetUsagesString(PRBool ignoreOcsp,
nsNSSCertificateFakeTransport::GetUsagesString(PRBool localOnly,
PRUint32 *_verified,
nsAString &_usages)
{

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

@ -117,6 +117,7 @@
#include "base64.h"
#include "secerr.h"
#include "sslerr.h"
#include "cert.h"
#include "nsXULAppAPI.h"
@ -139,6 +140,7 @@ PRLogModuleInfo* gPIPNSSLog = nsnull;
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
int nsNSSComponent::mInstanceCount = 0;
PRBool nsNSSComponent::globalConstFlagUsePKIXVerification = PR_FALSE;
// XXX tmp callback for slot password
extern char * PR_CALLBACK
@ -147,7 +149,6 @@ pk11PasswordPrompt(PK11SlotInfo *slot, PRBool retry, void *arg);
#define PIPNSS_STRBUNDLE_URL "chrome://pipnss/locale/pipnss.properties"
#define NSSERR_STRBUNDLE_URL "chrome://pipnss/locale/nsserrors.properties"
static PLHashNumber PR_CALLBACK certHashtable_keyHash(const void *key)
{
if (!key)
@ -589,8 +590,6 @@ nsNSSComponent::DispatchEventToWindow(nsIDOMWindow *domWin,
}
static void setOCSPOptions(nsIPrefBranch * pref);
NS_IMETHODIMP
nsNSSComponent::PIPBundleFormatStringFromName(const char *name,
const PRUnichar **params,
@ -671,7 +670,6 @@ nsNSSComponent::GetNSSBundleString(const char *name,
return rv;
}
NS_IMETHODIMP
nsNSSComponent::SkipOcsp()
{
@ -685,7 +683,18 @@ nsNSSComponent::SkipOcsp()
NS_IMETHODIMP
nsNSSComponent::SkipOcspOff()
{
setOCSPOptions(mPrefBranch);
nsNSSShutDownPreventionLock locker;
PRInt32 ocspEnabled;
if (NS_FAILED(mPrefBranch->GetIntPref("security.OCSP.enabled", &ocspEnabled)))
ocspEnabled = OCSP_ENABLED_DEFAULT;
// 0 = disabled, 1 = enabled,
// 2 = enabled with given default responder
setNonPkixOcspEnabled(ocspEnabled, mPrefBranch);
if (ocspEnabled)
SSL_ClearSessionCache();
return NS_OK;
}
@ -1111,12 +1120,9 @@ nsresult nsNSSComponent::GetNSSCipherIDFromPrefString(const nsACString &aPrefStr
return NS_ERROR_NOT_AVAILABLE;
}
static void setOCSPOptions(nsIPrefBranch * pref)
static void
setNonPkixOcspEnabled(PRInt32 ocspEnabled, nsIPrefBranch * pref)
{
nsNSSShutDownPreventionLock locker;
// Set up OCSP //
PRInt32 ocspEnabled;
pref->GetIntPref("security.OCSP.enabled", &ocspEnabled);
switch (ocspEnabled) {
case 0:
CERT_DisableOCSPChecking(CERT_GetDefaultCertDB());
@ -1125,7 +1131,6 @@ static void setOCSPOptions(nsIPrefBranch * pref)
case 1:
CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
SSL_ClearSessionCache();
break;
case 2:
{
@ -1140,21 +1145,89 @@ static void setOCSPOptions(nsIPrefBranch * pref)
CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
CERT_SetOCSPDefaultResponder(CERT_GetDefaultCertDB(), url, signingCA);
CERT_EnableOCSPDefaultResponder(CERT_GetDefaultCertDB());
SSL_ClearSessionCache();
nsMemory::Free(signingCA);
nsMemory::Free(url);
}
break;
}
}
#define CRL_DOWNLOAD_DEFAULT PR_FALSE
#define OCSP_ENABLED_DEFAULT 1
#define OCSP_REQUIRED_DEFAULT 0
#define FRESH_REVOCATION_REQUIRED_DEFAULT PR_FALSE
#define MISSING_CERT_DOWNLOAD_DEFAULT PR_FALSE
#define FIRST_REVO_METHOD_DEFAULT "ocsp"
#define USE_NSS_LIBPKIX_DEFAULT PR_FALSE
// Caller must hold a lock on nsNSSComponent::mutex when calling this function
void nsNSSComponent::setValidationOptions(nsIPrefBranch * pref)
{
nsNSSShutDownPreventionLock locker;
nsresult rv;
PRBool crlDownloading;
rv = pref->GetBoolPref("security.CRL_download.enabled", &crlDownloading);
if (NS_FAILED(rv))
crlDownloading = CRL_DOWNLOAD_DEFAULT;
PRInt32 ocspEnabled;
rv = pref->GetIntPref("security.OCSP.enabled", &ocspEnabled);
// 0 = disabled, 1 = enabled,
// 2 = enabled with given default responder
if (NS_FAILED(rv))
ocspEnabled = OCSP_ENABLED_DEFAULT;
PRBool ocspRequired;
pref->GetBoolPref("security.OCSP.require", &ocspRequired);
if (ocspRequired) {
CERT_SetOCSPFailureMode(ocspMode_FailureIsVerificationFailure);
}
else {
CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure);
rv = pref->GetBoolPref("security.OCSP.require", &ocspRequired);
if (NS_FAILED(rv))
ocspRequired = OCSP_REQUIRED_DEFAULT;
PRBool anyFreshRequired;
rv = pref->GetBoolPref("security.fresh_revocation_info.require", &anyFreshRequired);
if (NS_FAILED(rv))
anyFreshRequired = FRESH_REVOCATION_REQUIRED_DEFAULT;
PRBool aiaDownloadEnabled;
rv = pref->GetBoolPref("security.missing_cert_download.enabled", &aiaDownloadEnabled);
if (NS_FAILED(rv))
aiaDownloadEnabled = MISSING_CERT_DOWNLOAD_DEFAULT;
nsCString firstNetworkRevo;
rv = pref->GetCharPref("security.first_network_revocation_method", getter_Copies(firstNetworkRevo));
if (NS_FAILED(rv))
firstNetworkRevo = FIRST_REVO_METHOD_DEFAULT;
setNonPkixOcspEnabled(ocspEnabled, pref);
CERT_SetOCSPFailureMode( ocspRequired ?
ocspMode_FailureIsVerificationFailure
: ocspMode_FailureIsNotAVerificationFailure);
nsRefPtr<nsCERTValInParamWrapper> newCVIN = new nsCERTValInParamWrapper;
if (NS_SUCCEEDED(newCVIN->Construct(
aiaDownloadEnabled ?
nsCERTValInParamWrapper::missing_cert_download_on : nsCERTValInParamWrapper::missing_cert_download_off,
crlDownloading ?
nsCERTValInParamWrapper::crl_download_allowed : nsCERTValInParamWrapper::crl_local_only,
ocspEnabled ?
nsCERTValInParamWrapper::ocsp_on : nsCERTValInParamWrapper::ocsp_off,
ocspRequired ?
nsCERTValInParamWrapper::ocsp_strict : nsCERTValInParamWrapper::ocsp_relaxed,
anyFreshRequired ?
nsCERTValInParamWrapper::any_revo_strict : nsCERTValInParamWrapper::any_revo_relaxed,
firstNetworkRevo.get()))) {
// Swap to new defaults, and will cause the old defaults to be released,
// as soon as any concurrent use of the old default objects has finished.
mDefaultCERTValInParam = newCVIN;
}
/*
* The new defaults might change the validity of already established SSL sessions,
* let's not reuse them.
*/
SSL_ClearSessionCache();
}
nsresult
@ -1642,6 +1715,10 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
TryCFM2MachOMigration(cfmSecurityPath, profilePath);
#endif
rv = mPrefBranch->GetBoolPref("security.use_libpkix_verification", &globalConstFlagUsePKIXVerification);
if (NS_FAILED(rv))
globalConstFlagUsePKIXVerification = USE_NSS_LIBPKIX_DEFAULT;
PRBool supress_warning_preference = PR_FALSE;
rv = mPrefBranch->GetBoolPref("security.suppress_nss_rw_impossible_warning", &supress_warning_preference);
@ -1767,8 +1844,23 @@ nsNSSComponent::InitializeNSS(PRBool showWarningBox)
SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
PORT_SetUCS2_ASCIIConversionFunction(pip_ucs2_ascii_conversion_fn);
// Set up OCSP //
setOCSPOptions(mPrefBranch);
// dynamic options from prefs
setValidationOptions(mPrefBranch);
// static validation options for usagesarray - do not hit the network
mDefaultCERTValInParamLocalOnly = new nsCERTValInParamWrapper;
rv = mDefaultCERTValInParamLocalOnly->Construct(
nsCERTValInParamWrapper::missing_cert_download_off,
nsCERTValInParamWrapper::crl_local_only,
nsCERTValInParamWrapper::ocsp_off,
nsCERTValInParamWrapper::ocsp_relaxed,
nsCERTValInParamWrapper::any_revo_relaxed,
"ocsp");
if (NS_FAILED(rv)) {
nsPSMInitPanic::SetPanic();
return rv;
}
RegisterMyOCSPAIAInfoCallback();
mHttpForNSS.initTable();
@ -2273,8 +2365,13 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
#endif
} else if (prefName.Equals("security.OCSP.enabled")
|| prefName.Equals("security.CRL_download.enabled")
|| prefName.Equals("security.fresh_revocation_info.require")
|| prefName.Equals("security.missing_cert_download.enabled")
|| prefName.Equals("security.first_network_revocation_method")
|| prefName.Equals("security.OCSP.require")) {
setOCSPOptions(mPrefBranch);
MutexAutoLock lock(mutex);
setValidationOptions(mPrefBranch);
} else {
/* Look through the cipher table and set according to pref setting */
for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
@ -2561,6 +2658,26 @@ nsNSSComponent::IsNSSInitialized(PRBool *initialized)
return NS_OK;
}
NS_IMETHODIMP
nsNSSComponent::GetDefaultCERTValInParam(nsRefPtr<nsCERTValInParamWrapper> &out)
{
MutexAutoLock lock(mutex);
if (!mNSSInitialized)
return NS_ERROR_NOT_INITIALIZED;
out = mDefaultCERTValInParam;
return NS_OK;
}
NS_IMETHODIMP
nsNSSComponent::GetDefaultCERTValInParamLocalOnly(nsRefPtr<nsCERTValInParamWrapper> &out)
{
MutexAutoLock lock(mutex);
if (!mNSSInitialized)
return NS_ERROR_NOT_INITIALIZED;
out = mDefaultCERTValInParamLocalOnly;
return NS_OK;
}
//---------------------------------------------
// Implementing nsICryptoHash
//---------------------------------------------

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

@ -71,6 +71,7 @@
#include "nsNSSHelper.h"
#include "nsClientAuthRemember.h"
#include "nsCERTValInParamWrapper.h"
#define NS_NSSCOMPONENT_CID \
{0xa277189c, 0x1dd1, 0x11b2, {0xa8, 0xc9, 0xe4, 0xe8, 0xbf, 0xb1, 0x33, 0x8e}}
@ -141,6 +142,8 @@ protected:
nsresult handleContentDownloadError(nsresult errCode);
};
class nsNSSComponent;
class NS_NO_VTABLE nsINSSComponent : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_INSSCOMPONENT_IID)
@ -190,6 +193,9 @@ class NS_NO_VTABLE nsINSSComponent : public nsISupports {
NS_IMETHOD EnsureIdentityInfoLoaded() = 0;
NS_IMETHOD IsNSSInitialized(PRBool *initialized) = 0;
NS_IMETHOD GetDefaultCERTValInParam(nsRefPtr<nsCERTValInParamWrapper> &out) = 0;
NS_IMETHOD GetDefaultCERTValInParamLocalOnly(nsRefPtr<nsCERTValInParamWrapper> &out) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsINSSComponent, NS_INSSCOMPONENT_IID)
@ -287,6 +293,8 @@ public:
NS_IMETHOD EnsureIdentityInfoLoaded();
NS_IMETHOD IsNSSInitialized(PRBool *initialized);
NS_IMETHOD GetDefaultCERTValInParam(nsRefPtr<nsCERTValInParamWrapper> &out);
NS_IMETHOD GetDefaultCERTValInParamLocalOnly(nsRefPtr<nsCERTValInParamWrapper> &out);
private:
nsresult InitializeNSS(PRBool showWarningBox);
@ -309,6 +317,7 @@ private:
void LaunchSmartCardThreads();
void ShutdownSmartCardThreads();
void CleanupIdentityInfo();
void setValidationOptions(nsIPrefBranch * pref);
nsresult InitializePIPNSSBundle();
nsresult ConfigureInternalPKCS11Token();
nsresult RegisterPSMContentListener();
@ -352,9 +361,14 @@ private:
nsCertVerificationThread *mCertVerificationThread;
nsNSSHttpInterface mHttpForNSS;
nsRefPtr<nsClientAuthRememberService> mClientAuthRememberService;
nsRefPtr<nsCERTValInParamWrapper> mDefaultCERTValInParam;
nsRefPtr<nsCERTValInParamWrapper> mDefaultCERTValInParamLocalOnly;
static PRStatus PR_CALLBACK IdentityInfoInit(void);
PRCallOnceType mIdentityInfoCallOnce;
public:
static PRBool globalConstFlagUsePKIXVerification;
};
class PSMContentListener : public nsIURIContentListener,

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

@ -116,6 +116,8 @@ NSSCleanupAutoPtrClass(char, PL_strfree)
NSSCleanupAutoPtrClass(void, PR_FREEIF)
NSSCleanupAutoPtrClass_WithParam(PRArenaPool, PORT_FreeArena, FalseParam, PR_FALSE)
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
/* SSM_UserCertChoice: enum for cert choice info */
typedef enum {ASK, AUTO} SSM_UserCertChoice;
@ -3377,6 +3379,14 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
PRErrorCode errorCodeMismatch = SECSuccess;
PRErrorCode errorCodeExpired = SECSuccess;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss)
return cancel_and_failure(infoObject);
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
nsrv = inss->GetDefaultCERTValInParam(survivingParams);
if (NS_FAILED(nsrv))
return cancel_and_failure(infoObject);
char *hostname = SSL_RevealURL(sslSocket);
if (!hostname)
return cancel_and_failure(infoObject);
@ -3415,10 +3425,22 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket)
verify_log->arena = log_arena;
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
srv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), peerCert,
PR_TRUE, certificateUsageSSLServer,
PR_Now(), (void*)infoObject,
verify_log, NULL);
}
else {
CERTValOutParam cvout[2];
cvout[0].type = cert_po_errorLog;
cvout[0].value.pointer.log = verify_log;
cvout[1].type = cert_po_end;
srv = CERT_PKIXVerifyCert(peerCert, certificateUsageSSLServer,
survivingParams->GetRawPointerForNSS(),
cvout, (void*)infoObject);
}
// We ignore the result code of the cert verification.
// Either it is a failure, which is expected, and we'll process the

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

@ -152,7 +152,7 @@ nsUsageArrayHelper::verifyFailed(PRUint32 *_verified, int err)
nsresult
nsUsageArrayHelper::GetUsagesArray(const char *suffix,
PRBool ignoreOcsp,
PRBool localOnly,
PRUint32 outArraySize,
PRUint32 *_verified,
PRUint32 *_count,
@ -167,7 +167,7 @@ nsUsageArrayHelper::GetUsagesArray(const char *suffix,
nsCOMPtr<nsINSSComponent> nssComponent;
if (ignoreOcsp) {
if (!nsNSSComponent::globalConstFlagUsePKIXVerification && localOnly) {
nsresult rv;
nssComponent = do_GetService(kNSSComponentCID, &rv);
if (NS_FAILED(rv))
@ -177,12 +177,15 @@ nsUsageArrayHelper::GetUsagesArray(const char *suffix,
nssComponent->SkipOcsp();
}
}
PRUint32 &count = *_count;
count = 0;
SECCertificateUsage usages;
CERT_VerifyCertificateNow(defaultcertdb, mCert, PR_TRUE,
SECCertificateUsage usages = 0;
SECStatus verifyResult;
if (!nsNSSComponent::globalConstFlagUsePKIXVerification) {
verifyResult =
CERT_VerifyCertificateNow(defaultcertdb, mCert, PR_TRUE,
certificateUsageSSLClient |
certificateUsageSSLServer |
certificateUsageSSLServerWithStepUp |
@ -192,7 +195,39 @@ nsUsageArrayHelper::GetUsagesArray(const char *suffix,
certificateUsageSSLCA |
certificateUsageStatusResponder,
NULL, &usages);
int err = PR_GetError();
}
else {
nsresult nsrv;
nsCOMPtr<nsINSSComponent> inss = do_GetService(kNSSComponentCID, &nsrv);
if (!inss)
return nsrv;
nsRefPtr<nsCERTValInParamWrapper> survivingParams;
if (localOnly)
nsrv = inss->GetDefaultCERTValInParamLocalOnly(survivingParams);
else
nsrv = inss->GetDefaultCERTValInParam(survivingParams);
if (NS_FAILED(nsrv))
return nsrv;
CERTValOutParam cvout[2];
cvout[0].type = cert_po_usages;
cvout[0].value.scalar.usages = 0;
cvout[1].type = cert_po_end;
verifyResult =
CERT_PKIXVerifyCert(mCert, certificateUsageCheckAllUsages,
survivingParams->GetRawPointerForNSS(),
cvout, NULL);
usages = cvout[0].value.scalar.usages;
}
if (verifyResult != SECSuccess) {
int err = PR_GetError();
verifyFailed(_verified, err);
return NS_OK;
}
// The following list of checks must be < max_returned_out_array_size
@ -215,14 +250,10 @@ nsUsageArrayHelper::GetUsagesArray(const char *suffix,
check(suffix, usages & certificateUsageAnyCA, count, outUsages);
#endif
if (ignoreOcsp && nssComponent) {
if (!nsNSSComponent::globalConstFlagUsePKIXVerification && localOnly && nssComponent) {
nssComponent->SkipOcspOff();
}
if (count == 0) {
verifyFailed(_verified, err);
} else {
*_verified = nsNSSCertificate::VERIFIED_OK;
}
*_verified = nsNSSCertificate::VERIFIED_OK;
return NS_OK;
}

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

@ -48,7 +48,7 @@ public:
nsUsageArrayHelper(CERTCertificate *aCert);
nsresult GetUsagesArray(const char *suffix,
PRBool ignoreOcsp,
PRBool localOnly,
PRUint32 outArraySize,
PRUint32 *_verified,
PRUint32 *_count,