mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-23 13:04:28 +00:00
Bug 1029155 - Store peer certificate chain from failed connections on TransportSecurityInfo r=keeler
This commit is contained in:
parent
93111c8f0e
commit
691dcd68c1
1
config/external/nss/nss.def
vendored
1
config/external/nss/nss.def
vendored
@ -647,6 +647,7 @@ SSL_NumImplementedCiphers DATA
|
||||
SSL_OptionSet
|
||||
SSL_OptionSetDefault
|
||||
SSL_PeerCertificate
|
||||
SSL_PeerCertificateChain
|
||||
SSL_PeerStapledOCSPResponses
|
||||
SSL_ResetHandshake
|
||||
SSL_SetCanFalseStartCallback
|
||||
|
@ -6,9 +6,18 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(8813d03b-e76c-4240-9691-d327d9b91e88)]
|
||||
interface nsIX509CertList;
|
||||
|
||||
[scriptable, uuid(154898ce-e14f-4981-bfc5-00a41722f44b)]
|
||||
interface nsITransportSecurityInfo : nsISupports {
|
||||
readonly attribute unsigned long securityState;
|
||||
readonly attribute wstring errorMessage;
|
||||
|
||||
/**
|
||||
* If certificate verification failed, this will be the peer certificate
|
||||
* chain provided in the handshake, so it can be used for error reporting.
|
||||
* If verification succeeded, this will be null.
|
||||
*/
|
||||
readonly attribute nsIX509CertList failedCertChain;
|
||||
};
|
||||
|
||||
|
@ -621,6 +621,7 @@ public:
|
||||
const void* fdForLogging,
|
||||
TransportSecurityInfo* infoObject,
|
||||
CERTCertificate* serverCert,
|
||||
ScopedCERTCertList& peerCertChain,
|
||||
SECItem* stapledOCSPResponse,
|
||||
uint32_t providerFlags,
|
||||
Time time,
|
||||
@ -633,6 +634,7 @@ private:
|
||||
const void* fdForLogging,
|
||||
TransportSecurityInfo* infoObject,
|
||||
CERTCertificate* cert,
|
||||
CERTCertList* peerCertChain,
|
||||
SECItem* stapledOCSPResponse,
|
||||
uint32_t providerFlags,
|
||||
Time time,
|
||||
@ -641,6 +643,7 @@ private:
|
||||
const void* const mFdForLogging;
|
||||
const RefPtr<TransportSecurityInfo> mInfoObject;
|
||||
const ScopedCERTCertificate mCert;
|
||||
ScopedCERTCertList mPeerCertChain;
|
||||
const uint32_t mProviderFlags;
|
||||
const Time mTime;
|
||||
const PRTime mPRTime;
|
||||
@ -651,12 +654,13 @@ private:
|
||||
SSLServerCertVerificationJob::SSLServerCertVerificationJob(
|
||||
const RefPtr<SharedCertVerifier>& certVerifier, const void* fdForLogging,
|
||||
TransportSecurityInfo* infoObject, CERTCertificate* cert,
|
||||
SECItem* stapledOCSPResponse, uint32_t providerFlags,
|
||||
Time time, PRTime prtime)
|
||||
CERTCertList* peerCertChain, SECItem* stapledOCSPResponse,
|
||||
uint32_t providerFlags, Time time, PRTime prtime)
|
||||
: mCertVerifier(certVerifier)
|
||||
, mFdForLogging(fdForLogging)
|
||||
, mInfoObject(infoObject)
|
||||
, mCert(CERT_DupCertificate(cert))
|
||||
, mPeerCertChain(peerCertChain)
|
||||
, mProviderFlags(providerFlags)
|
||||
, mTime(time)
|
||||
, mPRTime(prtime)
|
||||
@ -733,9 +737,13 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
AuthCertificate(CertVerifier& certVerifier, TransportSecurityInfo* infoObject,
|
||||
CERTCertificate* cert, SECItem* stapledOCSPResponse,
|
||||
uint32_t providerFlags, Time time)
|
||||
AuthCertificate(CertVerifier& certVerifier,
|
||||
TransportSecurityInfo* infoObject,
|
||||
CERTCertificate* cert,
|
||||
ScopedCERTCertList& peerCertChain,
|
||||
SECItem* stapledOCSPResponse,
|
||||
uint32_t providerFlags,
|
||||
Time time)
|
||||
{
|
||||
MOZ_ASSERT(infoObject);
|
||||
MOZ_ASSERT(cert);
|
||||
@ -747,7 +755,6 @@ AuthCertificate(CertVerifier& certVerifier, TransportSecurityInfo* infoObject,
|
||||
bool saveIntermediates =
|
||||
!(providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE);
|
||||
|
||||
ScopedCERTCertList certList;
|
||||
SECOidTag evOidPolicy;
|
||||
rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
|
||||
time, infoObject,
|
||||
@ -799,6 +806,13 @@ AuthCertificate(CertVerifier& certVerifier, TransportSecurityInfo* infoObject,
|
||||
}
|
||||
}
|
||||
|
||||
if (rv != SECSuccess) {
|
||||
// Certificate validation failed; store the peer certificate chain on
|
||||
// infoObject so it can be used for error reporting. Note: infoObject
|
||||
// indirectly takes ownership of peerCertChain.
|
||||
infoObject->SetFailedCertChain(peerCertChain);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -808,6 +822,7 @@ SSLServerCertVerificationJob::Dispatch(
|
||||
const void* fdForLogging,
|
||||
TransportSecurityInfo* infoObject,
|
||||
CERTCertificate* serverCert,
|
||||
ScopedCERTCertList& peerCertChain,
|
||||
SECItem* stapledOCSPResponse,
|
||||
uint32_t providerFlags,
|
||||
Time time,
|
||||
@ -820,10 +835,18 @@ SSLServerCertVerificationJob::Dispatch(
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Copy the certificate list so the runnable can take ownership of it in the
|
||||
// constructor.
|
||||
// We can safely skip checking if NSS has already shut down here since we're
|
||||
// in the middle of verifying a certificate.
|
||||
nsNSSShutDownPreventionLock lock;
|
||||
CERTCertList* peerCertChainCopy = nsNSSCertList::DupCertList(peerCertChain, lock);
|
||||
|
||||
RefPtr<SSLServerCertVerificationJob> job(
|
||||
new SSLServerCertVerificationJob(certVerifier, fdForLogging, infoObject,
|
||||
serverCert, stapledOCSPResponse,
|
||||
providerFlags, time, prtime));
|
||||
serverCert, peerCertChainCopy,
|
||||
stapledOCSPResponse, providerFlags,
|
||||
time, prtime));
|
||||
|
||||
nsresult nrv;
|
||||
if (!gCertVerificationThreadPool) {
|
||||
@ -873,8 +896,8 @@ SSLServerCertVerificationJob::Run()
|
||||
// set the error code if/when it fails.
|
||||
PR_SetError(0, 0);
|
||||
SECStatus rv = AuthCertificate(*mCertVerifier, mInfoObject, mCert.get(),
|
||||
mStapledOCSPResponse, mProviderFlags,
|
||||
mTime);
|
||||
mPeerCertChain, mStapledOCSPResponse,
|
||||
mProviderFlags, mTime);
|
||||
if (rv == SECSuccess) {
|
||||
uint32_t interval = (uint32_t) ((TimeStamp::Now() - mJobStartTime).ToMilliseconds());
|
||||
RefPtr<SSLServerCertVerificationResult> restart(
|
||||
@ -975,6 +998,9 @@ AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Get the peer certificate chain for error reporting
|
||||
ScopedCERTCertList peerCertChain(SSL_PeerCertificateChain(fd));
|
||||
|
||||
socketInfo->SetFullHandshake();
|
||||
|
||||
Time now(Now());
|
||||
@ -1020,8 +1046,8 @@ AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
|
||||
socketInfo->SetCertVerificationWaiting();
|
||||
SECStatus rv = SSLServerCertVerificationJob::Dispatch(
|
||||
certVerifier, static_cast<const void*>(fd), socketInfo,
|
||||
serverCert, stapledOCSPResponse, providerFlags, now,
|
||||
prnow);
|
||||
serverCert, peerCertChain, stapledOCSPResponse,
|
||||
providerFlags, now, prnow);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1031,7 +1057,8 @@ AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
|
||||
// a non-blocking socket.
|
||||
|
||||
SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert,
|
||||
stapledOCSPResponse, providerFlags, now);
|
||||
peerCertChain, stapledOCSPResponse,
|
||||
providerFlags, now);
|
||||
if (rv == SECSuccess) {
|
||||
Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
|
||||
return SECSuccess;
|
||||
|
@ -289,8 +289,8 @@ TransportSecurityInfo::GetInterface(const nsIID & uuid, void * *result)
|
||||
// of the previous value. This is so when older versions attempt to
|
||||
// read a newer serialized TransportSecurityInfo, they will actually
|
||||
// fail and return NS_ERROR_FAILURE instead of silently failing.
|
||||
#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x28ea, 0x45d2, \
|
||||
{ 0xa2, 0x5a, 0x35, 0x7c, 0xae, 0xfa, 0x7f, 0x82 } }
|
||||
#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0xf40a, 0x4060, \
|
||||
{ 0xb2, 0xe1, 0x62, 0xab, 0x2b, 0x85, 0x26, 0xa9 } }
|
||||
static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -331,6 +331,15 @@ TransportSecurityInfo::Write(nsIObjectOutputStream* stream)
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = NS_WriteOptionalCompoundObject(stream,
|
||||
mFailedCertChain,
|
||||
NS_GET_IID(nsIX509CertList),
|
||||
true);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -386,6 +395,14 @@ TransportSecurityInfo::Read(nsIObjectInputStream* stream)
|
||||
if (!mSSLStatus) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> failedCertChainSupports;
|
||||
rv = NS_ReadOptionalObject(stream, true, getter_AddRefs(failedCertChainSupports));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
mFailedCertChain = do_QueryInterface(failedCertChainSupports);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1072,4 +1089,30 @@ TransportSecurityInfo::SetStatusErrorBits(nsIX509Cert & cert,
|
||||
SECFailure);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TransportSecurityInfo::GetFailedCertChain(nsIX509CertList** _result)
|
||||
{
|
||||
NS_ASSERTION(_result, "non-NULL destination required");
|
||||
|
||||
*_result = mFailedCertChain;
|
||||
NS_IF_ADDREF(*_result);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TransportSecurityInfo::SetFailedCertChain(ScopedCERTCertList& certList)
|
||||
{
|
||||
nsNSSShutDownPreventionLock lock;
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIX509CertList> comCertList;
|
||||
// nsNSSCertList takes ownership of certList
|
||||
mFailedCertChain = new nsNSSCertList(certList, lock);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} } // namespace mozilla::psm
|
||||
|
@ -7,16 +7,18 @@
|
||||
#ifndef _MOZILLA_PSM_TRANSPORTSECURITYINFO_H
|
||||
#define _MOZILLA_PSM_TRANSPORTSECURITYINFO_H
|
||||
|
||||
#include "ScopedNSSTypes.h"
|
||||
#include "certt.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsITransportSecurityInfo.h"
|
||||
#include "nsSSLStatus.h"
|
||||
#include "nsISSLStatusProvider.h"
|
||||
#include "nsIAssociatedContentSecurity.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsIAssociatedContentSecurity.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsISSLStatusProvider.h"
|
||||
#include "nsITransportSecurityInfo.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "nsSSLStatus.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
|
||||
namespace mozilla { namespace psm {
|
||||
|
||||
@ -74,6 +76,8 @@ public:
|
||||
nsSSLStatus* SSLStatus() { return mSSLStatus; }
|
||||
void SetStatusErrorBits(nsIX509Cert & cert, uint32_t collected_errors);
|
||||
|
||||
nsresult SetFailedCertChain(ScopedCERTCertList& certList);
|
||||
|
||||
private:
|
||||
mutable ::mozilla::Mutex mMutex;
|
||||
|
||||
@ -100,6 +104,9 @@ private:
|
||||
/* SSL Status */
|
||||
mozilla::RefPtr<nsSSLStatus> mSSLStatus;
|
||||
|
||||
/* Peer cert chain for failed connections (for error reporting) */
|
||||
nsCOMPtr<nsIX509CertList> mFailedCertChain;
|
||||
|
||||
virtual void virtualDestroyNSSReference();
|
||||
void destructorSafeDestroyNSSReference();
|
||||
};
|
||||
|
@ -1545,7 +1545,9 @@ ConstructCERTCertListFromReversedDERArray(
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNSSCertList, nsIX509CertList)
|
||||
NS_IMPL_ISUPPORTS(nsNSSCertList,
|
||||
nsIX509CertList,
|
||||
nsISerializable)
|
||||
|
||||
nsNSSCertList::nsNSSCertList(ScopedCERTCertList& certList,
|
||||
const nsNSSShutDownPreventionLock& proofOfLock)
|
||||
@ -1667,6 +1669,84 @@ nsNSSCertList::GetRawCertList()
|
||||
return mCertList.get();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertList::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(mCertList);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// First, enumerate the certs to get the length of the list
|
||||
uint32_t certListLen = 0;
|
||||
CERTCertListNode* node = nullptr;
|
||||
for (node = CERT_LIST_HEAD(mCertList);
|
||||
!CERT_LIST_END(node, mCertList);
|
||||
node = CERT_LIST_NEXT(node), ++certListLen) {
|
||||
}
|
||||
|
||||
// Write the length of the list
|
||||
rv = aStream->Write32(certListLen);
|
||||
|
||||
// Repeat the loop, and serialize each certificate
|
||||
node = nullptr;
|
||||
for (node = CERT_LIST_HEAD(mCertList);
|
||||
!CERT_LIST_END(node, mCertList);
|
||||
node = CERT_LIST_NEXT(node))
|
||||
{
|
||||
nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::Create(node->cert);
|
||||
if (!cert) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISerializable> serializableCert = do_QueryInterface(cert);
|
||||
rv = aStream->WriteCompoundObject(serializableCert, NS_GET_IID(nsIX509Cert), true);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertList::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(mCertList);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
uint32_t certListLen;
|
||||
rv = aStream->Read32(&certListLen);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < certListLen; ++i) {
|
||||
nsCOMPtr<nsISupports> certSupports;
|
||||
rv = aStream->ReadObject(true, getter_AddRefs(certSupports));
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports);
|
||||
rv = AddCert(cert);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval)
|
||||
{
|
||||
|
@ -82,11 +82,13 @@ SECStatus ConstructCERTCertListFromReversedDERArray(
|
||||
} // namespcae mozilla
|
||||
|
||||
class nsNSSCertList: public nsIX509CertList,
|
||||
public nsISerializable,
|
||||
public nsNSSShutDownObject
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIX509CERTLIST
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
|
||||
// certList is adopted
|
||||
nsNSSCertList(mozilla::ScopedCERTCertList& certList,
|
||||
|
Loading…
x
Reference in New Issue
Block a user