2012-04-30 04:00:22 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
2012-05-31 09:33:35 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
#include "TransportSecurityInfo.h"
|
|
|
|
#include "nsNSSComponent.h"
|
|
|
|
#include "nsIWebProgressListener.h"
|
|
|
|
#include "nsNSSCertificate.h"
|
|
|
|
#include "nsIX509CertValidity.h"
|
|
|
|
#include "nsIDateTimeFormat.h"
|
|
|
|
#include "nsDateTimeFormatCID.h"
|
|
|
|
#include "nsICertOverrideService.h"
|
|
|
|
#include "nsIObjectInputStream.h"
|
|
|
|
#include "nsIObjectOutputStream.h"
|
|
|
|
#include "nsNSSCertHelper.h"
|
|
|
|
#include "nsIProgrammingLanguage.h"
|
|
|
|
#include "nsIArray.h"
|
2013-06-22 22:57:15 +00:00
|
|
|
#include "nsComponentManagerUtils.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
2012-04-30 04:00:22 +00:00
|
|
|
#include "PSMRunnable.h"
|
2012-11-12 17:42:28 +00:00
|
|
|
#include "ScopedNSSTypes.h"
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
#include "secerr.h"
|
|
|
|
|
|
|
|
//#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
|
|
|
|
//reports when doing SSL read/write
|
|
|
|
|
|
|
|
//#define DUMP_BUFFER //Enable this define along with
|
|
|
|
//DEBUG_SSL_VERBOSE to dump SSL
|
|
|
|
//read/write buffer to a log.
|
|
|
|
//Uses PR_LOG except on Mac where
|
|
|
|
//we always write out to our own
|
|
|
|
//file.
|
|
|
|
|
|
|
|
namespace mozilla { namespace psm {
|
|
|
|
|
|
|
|
TransportSecurityInfo::TransportSecurityInfo()
|
|
|
|
: mMutex("TransportSecurityInfo::mMutex"),
|
|
|
|
mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
|
|
|
|
mSubRequestsBrokenSecurity(0),
|
|
|
|
mSubRequestsNoSecurity(0),
|
|
|
|
mErrorCode(0),
|
|
|
|
mErrorMessageType(PlainErrorMessage),
|
|
|
|
mPort(0),
|
|
|
|
mIsCertIssuerBlacklisted(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TransportSecurityInfo::~TransportSecurityInfo()
|
|
|
|
{
|
|
|
|
nsNSSShutDownPreventionLock locker;
|
|
|
|
if (isAlreadyShutDown())
|
|
|
|
return;
|
|
|
|
|
|
|
|
shutdown(calledFromObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TransportSecurityInfo::virtualDestroyNSSReference()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-07-19 02:24:14 +00:00
|
|
|
NS_IMPL_ISUPPORTS6(TransportSecurityInfo,
|
|
|
|
nsITransportSecurityInfo,
|
|
|
|
nsIInterfaceRequestor,
|
|
|
|
nsISSLStatusProvider,
|
|
|
|
nsIAssociatedContentSecurity,
|
|
|
|
nsISerializable,
|
|
|
|
nsIClassInfo)
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
TransportSecurityInfo::SetHostName(const char* host)
|
|
|
|
{
|
|
|
|
mHostName.Adopt(host ? NS_strdup(host) : 0);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
TransportSecurityInfo::GetHostName(char **host)
|
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
*host = (mHostName) ? NS_strdup(mHostName) : nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-08-22 15:56:38 +00:00
|
|
|
TransportSecurityInfo::SetPort(int32_t aPort)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
mPort = aPort;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-08-22 15:56:38 +00:00
|
|
|
TransportSecurityInfo::GetPort(int32_t *aPort)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
*aPort = mPort;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRErrorCode
|
|
|
|
TransportSecurityInfo::GetErrorCode() const
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
|
|
|
|
return mErrorCode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TransportSecurityInfo::SetCanceled(PRErrorCode errorCode,
|
|
|
|
SSLErrorMessageType errorMessageType)
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
|
|
|
|
mErrorCode = errorCode;
|
|
|
|
mErrorMessageType = errorMessageType;
|
|
|
|
mErrorMessageCached.Truncate();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
TransportSecurityInfo::GetSecurityState(uint32_t* state)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
*state = mSecurityState;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2012-08-22 15:56:38 +00:00
|
|
|
TransportSecurityInfo::SetSecurityState(uint32_t aState)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
mSecurityState = aState;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute unsigned long countSubRequestsBrokenSecurity; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetCountSubRequestsBrokenSecurity(
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t *aSubRequestsBrokenSecurity)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
*aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::SetCountSubRequestsBrokenSecurity(
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t aSubRequestsBrokenSecurity)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute unsigned long countSubRequestsNoSecurity; */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetCountSubRequestsNoSecurity(
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t *aSubRequestsNoSecurity)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
*aSubRequestsNoSecurity = mSubRequestsNoSecurity;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::SetCountSubRequestsNoSecurity(
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t aSubRequestsNoSecurity)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
mSubRequestsNoSecurity = aSubRequestsNoSecurity;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::Flush()
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2014-01-04 15:02:17 +00:00
|
|
|
TransportSecurityInfo::GetErrorMessage(char16_t** aText)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aText);
|
2012-07-30 14:20:58 +00:00
|
|
|
*aText = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
NS_ERROR("nsNSSSocketInfo::GetErrorMessage called off the main thread");
|
|
|
|
return NS_ERROR_NOT_SAME_THREAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
|
2012-08-28 13:32:34 +00:00
|
|
|
if (mErrorMessageCached.IsEmpty()) {
|
|
|
|
nsresult rv = formatErrorMessage(lock,
|
|
|
|
mErrorCode, mErrorMessageType,
|
|
|
|
true, true, mErrorMessageCached);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
*aText = ToNewUnicode(mErrorMessageCached);
|
2012-10-17 20:48:36 +00:00
|
|
|
return *aText ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
2012-04-30 04:00:22 +00:00
|
|
|
}
|
|
|
|
|
2012-08-28 13:32:34 +00:00
|
|
|
void
|
|
|
|
TransportSecurityInfo::GetErrorLogMessage(PRErrorCode errorCode,
|
|
|
|
SSLErrorMessageType errorMessageType,
|
|
|
|
nsString &result)
|
|
|
|
{
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
NS_ERROR("nsNSSSocketInfo::GetErrorLogMessage called off the main thread");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
(void) formatErrorMessage(lock, errorCode, errorMessageType,
|
|
|
|
false, false, result);
|
|
|
|
}
|
|
|
|
|
2012-04-30 04:00:22 +00:00
|
|
|
static nsresult
|
2012-08-22 15:56:38 +00:00
|
|
|
formatPlainErrorMessage(nsXPIDLCString const & host, int32_t port,
|
2012-08-28 13:32:34 +00:00
|
|
|
PRErrorCode err,
|
|
|
|
bool suppressPort443,
|
|
|
|
nsString &returnedMessage);
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
static nsresult
|
|
|
|
formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
|
|
|
|
PRErrorCode errorCodeToReport,
|
2012-08-22 15:56:38 +00:00
|
|
|
const nsXPIDLCString & host, int32_t port,
|
2012-08-28 13:32:34 +00:00
|
|
|
bool suppressPort443,
|
|
|
|
bool wantsHtml,
|
2012-04-30 04:00:22 +00:00
|
|
|
nsString & returnedMessage);
|
|
|
|
|
|
|
|
// XXX: uses nsNSSComponent string bundles off the main thread when called by
|
2012-08-28 13:32:34 +00:00
|
|
|
// nsNSSSocketInfo::Write().
|
2012-04-30 04:00:22 +00:00
|
|
|
nsresult
|
2012-08-28 13:32:34 +00:00
|
|
|
TransportSecurityInfo::formatErrorMessage(MutexAutoLock const & proofOfLock,
|
|
|
|
PRErrorCode errorCode,
|
|
|
|
SSLErrorMessageType errorMessageType,
|
|
|
|
bool wantsHtml, bool suppressPort443,
|
|
|
|
nsString &result)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
2012-08-28 13:32:34 +00:00
|
|
|
if (errorCode == 0) {
|
|
|
|
result.Truncate();
|
2012-04-30 04:00:22 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
NS_ConvertASCIItoUTF16 hostNameU(mHostName);
|
2012-08-28 13:32:34 +00:00
|
|
|
NS_ASSERTION(errorMessageType != OverridableCertErrorMessage ||
|
2012-04-30 04:00:22 +00:00
|
|
|
(mSSLStatus && mSSLStatus->mServerCert &&
|
|
|
|
mSSLStatus->mHaveCertErrorBits),
|
2012-08-28 13:32:34 +00:00
|
|
|
"GetErrorLogMessage called for cert error without cert");
|
|
|
|
if (errorMessageType == OverridableCertErrorMessage &&
|
2012-04-30 04:00:22 +00:00
|
|
|
mSSLStatus && mSSLStatus->mServerCert) {
|
2012-08-28 13:32:34 +00:00
|
|
|
rv = formatOverridableCertErrorMessage(*mSSLStatus, errorCode,
|
2012-04-30 04:00:22 +00:00
|
|
|
mHostName, mPort,
|
2012-08-28 13:32:34 +00:00
|
|
|
suppressPort443,
|
|
|
|
wantsHtml,
|
|
|
|
result);
|
2012-04-30 04:00:22 +00:00
|
|
|
} else {
|
2012-08-28 13:32:34 +00:00
|
|
|
rv = formatPlainErrorMessage(mHostName, mPort,
|
|
|
|
errorCode,
|
|
|
|
suppressPort443,
|
|
|
|
result);
|
2012-04-30 04:00:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
2012-08-28 13:32:34 +00:00
|
|
|
result.Truncate();
|
2012-04-30 04:00:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetInterface(const nsIID & uuid, void * *result)
|
|
|
|
{
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
|
|
|
|
return NS_ERROR_NOT_SAME_THREAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
if (!mCallbacks) {
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
|
|
|
|
rv = ir->GetInterface(uuid, result);
|
|
|
|
} else {
|
|
|
|
rv = mCallbacks->GetInterface(uuid, result);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
|
|
|
|
#define TRANSPORTSECURITYINFOMAGIC { 0xa9863a23, 0x26b8, 0x4a9c, \
|
|
|
|
{ 0x83, 0xf1, 0xe9, 0xda, 0xdb, 0x36, 0xb8, 0x30 } }
|
|
|
|
static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::Write(nsIObjectOutputStream* stream)
|
|
|
|
{
|
|
|
|
stream->WriteID(kTransportSecurityInfoMagic);
|
|
|
|
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
|
2012-10-17 20:48:36 +00:00
|
|
|
RefPtr<nsSSLStatus> status(mSSLStatus);
|
2012-04-30 04:00:22 +00:00
|
|
|
nsCOMPtr<nsISerializable> certSerializable;
|
|
|
|
|
|
|
|
// Write a redundant copy of the certificate for backward compatibility
|
|
|
|
// with previous versions, which also unnecessarily wrote it.
|
|
|
|
//
|
|
|
|
// As we are reading the object our self, not using ReadObject, we have
|
|
|
|
// to store it here 'manually' as well, mimicking our object stream
|
|
|
|
// implementation.
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
nsCOMPtr<nsIX509Cert> cert = status->mServerCert;
|
|
|
|
certSerializable = do_QueryInterface(cert);
|
|
|
|
|
|
|
|
if (!certSerializable) {
|
|
|
|
NS_ERROR("certificate is missing or isn't serializable");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
NS_WARNING("Serializing nsNSSSocketInfo without mSSLStatus");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the flag if there is the certificate present
|
|
|
|
stream->WriteBoolean(certSerializable);
|
|
|
|
if (certSerializable) {
|
|
|
|
stream->WriteID(kNSSCertificateCID);
|
|
|
|
stream->WriteID(NS_GET_IID(nsISupports));
|
|
|
|
certSerializable->Write(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the version number of the binary stream data format.
|
|
|
|
// The 0xFFFF0000 mask is included to the version number
|
|
|
|
// to distinguish version number from mSecurityState
|
|
|
|
// field stored in times before versioning has been introduced.
|
|
|
|
// This mask value has been chosen as mSecurityState could
|
|
|
|
// never be assigned such value.
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t version = 3;
|
2012-04-30 04:00:22 +00:00
|
|
|
stream->Write32(version | 0xFFFF0000);
|
|
|
|
stream->Write32(mSecurityState);
|
2013-02-03 01:21:45 +00:00
|
|
|
stream->WriteWStringZ(EmptyString().get());
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
// XXX: uses nsNSSComponent string bundles off the main thread
|
2012-08-28 13:32:34 +00:00
|
|
|
nsresult rv = formatErrorMessage(lock,
|
|
|
|
mErrorCode, mErrorMessageType,
|
|
|
|
true, true, mErrorMessageCached);
|
2012-04-30 04:00:22 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
stream->WriteWStringZ(mErrorMessageCached.get());
|
|
|
|
|
|
|
|
stream->WriteCompoundObject(NS_ISUPPORTS_CAST(nsISSLStatus*, status),
|
|
|
|
NS_GET_IID(nsISupports), true);
|
|
|
|
|
2012-11-11 04:49:29 +00:00
|
|
|
stream->Write32((uint32_t)0);
|
|
|
|
stream->Write32((uint32_t)0);
|
2012-08-22 15:56:38 +00:00
|
|
|
stream->Write32((uint32_t)mSubRequestsBrokenSecurity);
|
|
|
|
stream->Write32((uint32_t)mSubRequestsNoSecurity);
|
2012-04-30 04:00:22 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
static bool CheckUUIDEquals(uint32_t m0,
|
2012-04-30 04:00:22 +00:00
|
|
|
nsIObjectInputStream* stream,
|
|
|
|
const nsCID& id)
|
|
|
|
{
|
|
|
|
nsID tempID;
|
|
|
|
tempID.m0 = m0;
|
|
|
|
stream->Read16(&tempID.m1);
|
|
|
|
stream->Read16(&tempID.m2);
|
|
|
|
for (int i = 0; i < 8; ++i)
|
|
|
|
stream->Read8(&tempID.m3[i]);
|
|
|
|
return tempID.Equals(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::Read(nsIObjectInputStream* stream)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t version;
|
2012-04-30 04:00:22 +00:00
|
|
|
bool certificatePresent;
|
|
|
|
|
|
|
|
// Check what we have here...
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t UUID_0;
|
2012-04-30 04:00:22 +00:00
|
|
|
stream->Read32(&UUID_0);
|
|
|
|
if (UUID_0 == kTransportSecurityInfoMagic.m0) {
|
|
|
|
// It seems this stream begins with our magic ID, check it really is there
|
|
|
|
if (!CheckUUIDEquals(UUID_0, stream, kTransportSecurityInfoMagic))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// OK, this seems to be our stream, now continue to check there is
|
|
|
|
// the certificate
|
|
|
|
stream->ReadBoolean(&certificatePresent);
|
|
|
|
stream->Read32(&UUID_0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// There is no magic, assume there is a certificate present as in versions
|
|
|
|
// prior to those with the magic didn't store that flag; we check the
|
|
|
|
// certificate is present by cheking the CID then
|
|
|
|
certificatePresent = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (certificatePresent && UUID_0 == kNSSCertificateCID.m0) {
|
|
|
|
// It seems there is the certificate CID present, check it now; we only
|
|
|
|
// have this single certificate implementation at this time.
|
|
|
|
if (!CheckUUIDEquals(UUID_0, stream, kNSSCertificateCID))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// OK, we have read the CID of the certificate, check the interface ID
|
|
|
|
nsID tempID;
|
|
|
|
stream->ReadID(&tempID);
|
|
|
|
if (!tempID.Equals(NS_GET_IID(nsISupports)))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISerializable> serializable =
|
|
|
|
do_CreateInstance(kNSSCertificateCID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// This is the redundant copy of the certificate; just ignore it
|
|
|
|
serializable->Read(stream);
|
|
|
|
|
|
|
|
// We are done with reading the certificate, now read the version
|
|
|
|
// as we did before.
|
|
|
|
stream->Read32(&version);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// There seems not to be the certificate present in the stream.
|
|
|
|
version = UUID_0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
|
|
|
|
// If the version field we have just read is not masked with 0xFFFF0000
|
|
|
|
// then it is stored mSecurityState field and this is version 1 of
|
|
|
|
// the binary data stream format.
|
|
|
|
if ((version & 0xFFFF0000) == 0xFFFF0000) {
|
|
|
|
version &= ~0xFFFF0000;
|
|
|
|
stream->Read32(&mSecurityState);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mSecurityState = version;
|
|
|
|
version = 1;
|
|
|
|
}
|
2013-02-03 01:21:45 +00:00
|
|
|
nsAutoString dummyShortDesc;
|
|
|
|
stream->ReadString(dummyShortDesc);
|
2012-04-30 04:00:22 +00:00
|
|
|
stream->ReadString(mErrorMessageCached);
|
|
|
|
mErrorCode = 0;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupports> obj;
|
|
|
|
stream->ReadObject(true, getter_AddRefs(obj));
|
|
|
|
|
|
|
|
mSSLStatus = reinterpret_cast<nsSSLStatus*>(obj.get());
|
|
|
|
|
|
|
|
if (!mSSLStatus) {
|
|
|
|
NS_WARNING("deserializing nsNSSSocketInfo without mSSLStatus");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version >= 2) {
|
2012-11-11 04:49:29 +00:00
|
|
|
uint32_t dummySubRequests;
|
|
|
|
stream->Read32((uint32_t*)&dummySubRequests);
|
|
|
|
stream->Read32((uint32_t*)&dummySubRequests);
|
2012-08-22 15:56:38 +00:00
|
|
|
stream->Read32((uint32_t*)&mSubRequestsBrokenSecurity);
|
|
|
|
stream->Read32((uint32_t*)&mSubRequestsNoSecurity);
|
2012-04-30 04:00:22 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
mSubRequestsBrokenSecurity = 0;
|
|
|
|
mSubRequestsNoSecurity = 0;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
TransportSecurityInfo::GetInterfaces(uint32_t *count, nsIID * **array)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
*count = 0;
|
2012-07-30 14:20:58 +00:00
|
|
|
*array = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
TransportSecurityInfo::GetHelperForLanguage(uint32_t language,
|
2012-04-30 04:00:22 +00:00
|
|
|
nsISupports **_retval)
|
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
*_retval = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetContractID(char * *aContractID)
|
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
*aContractID = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetClassDescription(char * *aClassDescription)
|
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
*aClassDescription = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetClassID(nsCID * *aClassID)
|
|
|
|
{
|
|
|
|
*aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
|
|
|
|
if (!*aClassID)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
return GetClassIDNoAlloc(*aClassID);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetImplementationLanguage(
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t *aImplementationLanguage)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
*aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
TransportSecurityInfo::GetFlags(uint32_t *aFlags)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
*aFlags = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kNSSSocketInfoCID, TRANSPORTSECURITYINFO_CID);
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
TransportSecurityInfo::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
|
|
|
|
{
|
|
|
|
*aClassIDNoAlloc = kNSSSocketInfoCID;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
TransportSecurityInfo::GetSSLStatus(nsISSLStatus** _result)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(_result);
|
|
|
|
|
|
|
|
*_result = mSSLStatus;
|
|
|
|
NS_IF_ADDREF(*_result);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
TransportSecurityInfo::SetSSLStatus(nsSSLStatus *aSSLStatus)
|
|
|
|
{
|
|
|
|
mSSLStatus = aSSLStatus;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Formats an error message for non-certificate-related SSL errors
|
|
|
|
* and non-overridable certificate errors (both are of type
|
|
|
|
* PlainErrormMessage). Use formatOverridableCertErrorMessage
|
|
|
|
* for overridable cert errors.
|
|
|
|
*/
|
|
|
|
static nsresult
|
2012-08-22 15:56:38 +00:00
|
|
|
formatPlainErrorMessage(const nsXPIDLCString &host, int32_t port,
|
2012-08-28 13:32:34 +00:00
|
|
|
PRErrorCode err,
|
|
|
|
bool suppressPort443,
|
|
|
|
nsString &returnedMessage)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
2013-11-26 18:18:21 +00:00
|
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t *params[1];
|
2012-04-30 04:00:22 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (host.Length())
|
|
|
|
{
|
|
|
|
nsString hostWithPort;
|
|
|
|
|
|
|
|
// For now, hide port when it's 443 and we're reporting the error.
|
|
|
|
// In the future a better mechanism should be used
|
|
|
|
// to make a decision about showing the port number, possibly by requiring
|
|
|
|
// the context object to implement a specific interface.
|
|
|
|
// The motivation is that Mozilla browser would like to hide the port number
|
|
|
|
// in error pages in the common case.
|
|
|
|
|
|
|
|
hostWithPort.AssignASCII(host);
|
2012-08-28 13:32:34 +00:00
|
|
|
if (!suppressPort443 || port != 443) {
|
2012-04-30 04:00:22 +00:00
|
|
|
hostWithPort.AppendLiteral(":");
|
|
|
|
hostWithPort.AppendInt(port);
|
|
|
|
}
|
|
|
|
params[0] = hostWithPort.get();
|
|
|
|
|
|
|
|
nsString formattedString;
|
|
|
|
rv = component->PIPBundleFormatStringFromName("SSLConnectionErrorPrefix",
|
|
|
|
params, 1,
|
|
|
|
formattedString);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
{
|
|
|
|
returnedMessage.Append(formattedString);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsString explanation;
|
|
|
|
rv = nsNSSErrors::getErrorMessageFromCode(err, component, explanation);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
returnedMessage.Append(explanation);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AppendErrorTextUntrusted(PRErrorCode errTrust,
|
|
|
|
const nsString &host,
|
|
|
|
nsIX509Cert* ix509,
|
|
|
|
nsINSSComponent *component,
|
|
|
|
nsString &returnedMessage)
|
|
|
|
{
|
2012-07-30 14:20:58 +00:00
|
|
|
const char *errorID = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
|
|
|
|
if (cert3) {
|
|
|
|
bool isSelfSigned;
|
|
|
|
if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
|
|
|
|
&& isSelfSigned) {
|
|
|
|
errorID = "certErrorTrust_SelfSigned";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!errorID) {
|
|
|
|
switch (errTrust) {
|
|
|
|
case SEC_ERROR_UNKNOWN_ISSUER:
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIArray> chain;
|
|
|
|
ix509->GetChain(getter_AddRefs(chain));
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t length = 0;
|
2012-04-30 04:00:22 +00:00
|
|
|
if (chain && NS_FAILED(chain->GetLength(&length)))
|
|
|
|
length = 0;
|
|
|
|
if (length == 1)
|
|
|
|
errorID = "certErrorTrust_MissingChain";
|
|
|
|
else
|
|
|
|
errorID = "certErrorTrust_UnknownIssuer";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SEC_ERROR_INADEQUATE_KEY_USAGE:
|
|
|
|
// Should get an individual string in the future
|
|
|
|
// For now, use the same as CaInvalid
|
|
|
|
case SEC_ERROR_CA_CERT_INVALID:
|
|
|
|
errorID = "certErrorTrust_CaInvalid";
|
|
|
|
break;
|
|
|
|
case SEC_ERROR_UNTRUSTED_ISSUER:
|
|
|
|
errorID = "certErrorTrust_Issuer";
|
|
|
|
break;
|
2012-07-11 02:42:50 +00:00
|
|
|
case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
|
|
|
|
errorID = "certErrorTrust_SignatureAlgorithmDisabled";
|
|
|
|
break;
|
2012-04-30 04:00:22 +00:00
|
|
|
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
|
|
|
|
errorID = "certErrorTrust_ExpiredIssuer";
|
|
|
|
break;
|
|
|
|
case SEC_ERROR_UNTRUSTED_CERT:
|
|
|
|
default:
|
|
|
|
errorID = "certErrorTrust_Untrusted";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsString formattedString;
|
|
|
|
nsresult rv = component->GetPIPNSSBundleString(errorID,
|
|
|
|
formattedString);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
{
|
|
|
|
returnedMessage.Append(formattedString);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns TRUE if SAN was used to produce names
|
|
|
|
// return FALSE if nothing was produced
|
|
|
|
// names => a single name or a list of names
|
|
|
|
// multipleNames => whether multiple names were delivered
|
|
|
|
static bool
|
|
|
|
GetSubjectAltNames(CERTCertificate *nssCert,
|
|
|
|
nsINSSComponent *component,
|
|
|
|
nsString &allNames,
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t &nameCount)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
allNames.Truncate();
|
|
|
|
nameCount = 0;
|
|
|
|
|
2012-10-11 06:39:28 +00:00
|
|
|
PLArenaPool *san_arena = nullptr;
|
2012-10-17 20:48:36 +00:00
|
|
|
SECItem altNameExtension = {siBuffer, nullptr, 0 };
|
2012-07-30 14:20:58 +00:00
|
|
|
CERTGeneralName *sanNameList = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
|
2012-07-27 14:03:25 +00:00
|
|
|
SECStatus rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
|
|
|
|
&altNameExtension);
|
2012-04-30 04:00:22 +00:00
|
|
|
if (rv != SECSuccess)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
|
|
if (!san_arena)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
|
|
|
|
if (!sanNameList)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SECITEM_FreeItem(&altNameExtension, false);
|
|
|
|
|
|
|
|
CERTGeneralName *current = sanNameList;
|
|
|
|
do {
|
|
|
|
nsAutoString name;
|
|
|
|
switch (current->type) {
|
|
|
|
case certDNSName:
|
|
|
|
name.AssignASCII((char*)current->name.other.data, current->name.other.len);
|
|
|
|
if (!allNames.IsEmpty()) {
|
2014-01-13 14:28:14 +00:00
|
|
|
allNames.Append(NS_LITERAL_STRING(", "));
|
2012-04-30 04:00:22 +00:00
|
|
|
}
|
|
|
|
++nameCount;
|
|
|
|
allNames.Append(name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case certIPAddress:
|
|
|
|
{
|
|
|
|
char buf[INET6_ADDRSTRLEN];
|
|
|
|
PRNetAddr addr;
|
|
|
|
if (current->name.other.len == 4) {
|
|
|
|
addr.inet.family = PR_AF_INET;
|
|
|
|
memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
|
|
|
|
PR_NetAddrToString(&addr, buf, sizeof(buf));
|
|
|
|
name.AssignASCII(buf);
|
|
|
|
} else if (current->name.other.len == 16) {
|
|
|
|
addr.ipv6.family = PR_AF_INET6;
|
|
|
|
memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
|
|
|
|
PR_NetAddrToString(&addr, buf, sizeof(buf));
|
|
|
|
name.AssignASCII(buf);
|
|
|
|
} else {
|
|
|
|
/* invalid IP address */
|
|
|
|
}
|
|
|
|
if (!name.IsEmpty()) {
|
|
|
|
if (!allNames.IsEmpty()) {
|
2014-01-13 14:28:14 +00:00
|
|
|
allNames.Append(NS_LITERAL_STRING(", "));
|
2012-04-30 04:00:22 +00:00
|
|
|
}
|
|
|
|
++nameCount;
|
|
|
|
allNames.Append(name);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: // all other types of names are ignored
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
current = CERT_GetNextGeneralName(current);
|
|
|
|
} while (current != sanNameList); // double linked
|
|
|
|
|
|
|
|
PORT_FreeArena(san_arena, false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AppendErrorTextMismatch(const nsString &host,
|
|
|
|
nsIX509Cert* ix509,
|
|
|
|
nsINSSComponent *component,
|
2012-08-28 13:32:34 +00:00
|
|
|
bool wantsHtml,
|
2012-04-30 04:00:22 +00:00
|
|
|
nsString &returnedMessage)
|
|
|
|
{
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t *params[1];
|
2012-04-30 04:00:22 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
2012-11-12 17:42:28 +00:00
|
|
|
ScopedCERTCertificate nssCert;
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
|
|
|
|
if (cert2)
|
|
|
|
nssCert = cert2->GetCert();
|
|
|
|
|
|
|
|
if (!nssCert) {
|
|
|
|
// We are unable to extract the valid names, say "not valid for name".
|
|
|
|
params[0] = host.get();
|
|
|
|
nsString formattedString;
|
|
|
|
rv = component->PIPBundleFormatStringFromName("certErrorMismatch",
|
|
|
|
params, 1,
|
|
|
|
formattedString);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
returnedMessage.Append(formattedString);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n"));
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsString allNames;
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t nameCount = 0;
|
2012-04-30 04:00:22 +00:00
|
|
|
bool useSAN = false;
|
|
|
|
|
|
|
|
if (nssCert)
|
|
|
|
useSAN = GetSubjectAltNames(nssCert, component, allNames, nameCount);
|
|
|
|
|
|
|
|
if (!useSAN) {
|
2012-07-30 14:20:58 +00:00
|
|
|
char *certName = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
// currently CERT_FindNSStringExtension is not being exported by NSS.
|
|
|
|
// If it gets exported, enable the following line.
|
|
|
|
// certName = CERT_FindNSStringExtension(nssCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
|
|
|
|
// However, it has been discussed to treat the extension as obsolete and ignore it.
|
|
|
|
if (!certName)
|
|
|
|
certName = CERT_GetCommonName(&nssCert->subject);
|
|
|
|
if (certName) {
|
|
|
|
++nameCount;
|
|
|
|
allNames.AssignASCII(certName);
|
|
|
|
PORT_Free(certName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nameCount > 1) {
|
|
|
|
nsString message;
|
|
|
|
rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple",
|
|
|
|
message);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
returnedMessage.Append(message);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n "));
|
|
|
|
returnedMessage.Append(allNames);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING(" \n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (nameCount == 1) {
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t *params[1];
|
2012-04-30 04:00:22 +00:00
|
|
|
params[0] = allNames.get();
|
2012-08-28 13:32:34 +00:00
|
|
|
|
|
|
|
const char *stringID;
|
|
|
|
if (wantsHtml)
|
|
|
|
stringID = "certErrorMismatchSingle2";
|
|
|
|
else
|
|
|
|
stringID = "certErrorMismatchSinglePlain";
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
nsString formattedString;
|
2012-08-28 13:32:34 +00:00
|
|
|
rv = component->PIPBundleFormatStringFromName(stringID,
|
2012-04-30 04:00:22 +00:00
|
|
|
params, 1,
|
|
|
|
formattedString);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
returnedMessage.Append(formattedString);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // nameCount == 0
|
|
|
|
nsString message;
|
|
|
|
nsresult rv = component->GetPIPNSSBundleString("certErrorMismatchNoNames",
|
|
|
|
message);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
returnedMessage.Append(message);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
GetDateBoundary(nsIX509Cert* ix509,
|
|
|
|
nsString &formattedDate,
|
|
|
|
nsString &nowDate,
|
|
|
|
bool &trueExpired_falseNotYetValid)
|
|
|
|
{
|
|
|
|
trueExpired_falseNotYetValid = true;
|
|
|
|
formattedDate.Truncate();
|
|
|
|
|
|
|
|
PRTime notAfter, notBefore, timeToUse;
|
|
|
|
nsCOMPtr<nsIX509CertValidity> validity;
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
rv = ix509->GetValidity(getter_AddRefs(validity));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
rv = validity->GetNotAfter(¬After);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
rv = validity->GetNotBefore(¬Before);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
PRTime now = PR_Now();
|
2012-10-03 14:13:19 +00:00
|
|
|
if (now > notAfter) {
|
2012-04-30 04:00:22 +00:00
|
|
|
timeToUse = notAfter;
|
|
|
|
} else {
|
|
|
|
timeToUse = notBefore;
|
|
|
|
trueExpired_falseNotYetValid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
dateTimeFormat->FormatPRTime(nullptr, kDateFormatShort,
|
2012-04-30 04:00:22 +00:00
|
|
|
kTimeFormatNoSeconds, timeToUse,
|
|
|
|
formattedDate);
|
2012-07-30 14:20:58 +00:00
|
|
|
dateTimeFormat->FormatPRTime(nullptr, kDateFormatShort,
|
2012-04-30 04:00:22 +00:00
|
|
|
kTimeFormatNoSeconds, now,
|
|
|
|
nowDate);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AppendErrorTextTime(nsIX509Cert* ix509,
|
|
|
|
nsINSSComponent *component,
|
|
|
|
nsString &returnedMessage)
|
|
|
|
{
|
|
|
|
nsAutoString formattedDate, nowDate;
|
|
|
|
bool trueExpired_falseNotYetValid;
|
|
|
|
GetDateBoundary(ix509, formattedDate, nowDate, trueExpired_falseNotYetValid);
|
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t *params[2];
|
2012-04-30 04:00:22 +00:00
|
|
|
params[0] = formattedDate.get(); // might be empty, if helper function had a problem
|
|
|
|
params[1] = nowDate.get();
|
|
|
|
|
|
|
|
const char *key = trueExpired_falseNotYetValid ?
|
|
|
|
"certErrorExpiredNow" : "certErrorNotYetValidNow";
|
|
|
|
nsresult rv;
|
|
|
|
nsString formattedString;
|
|
|
|
rv = component->PIPBundleFormatStringFromName(
|
|
|
|
key,
|
|
|
|
params,
|
|
|
|
ArrayLength(params),
|
|
|
|
formattedString);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
{
|
|
|
|
returnedMessage.Append(formattedString);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AppendErrorTextCode(PRErrorCode errorCodeToReport,
|
|
|
|
nsINSSComponent *component,
|
|
|
|
nsString &returnedMessage)
|
|
|
|
{
|
|
|
|
const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
|
|
|
|
if (codeName)
|
|
|
|
{
|
|
|
|
nsCString error_id(codeName);
|
|
|
|
ToLowerCase(error_id);
|
|
|
|
NS_ConvertASCIItoUTF16 idU(error_id);
|
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t *params[1];
|
2012-04-30 04:00:22 +00:00
|
|
|
params[0] = idU.get();
|
|
|
|
|
|
|
|
nsString formattedString;
|
|
|
|
nsresult rv;
|
|
|
|
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix",
|
|
|
|
params, 1,
|
|
|
|
formattedString);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n"));
|
|
|
|
returnedMessage.Append(formattedString);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n"));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING(" ("));
|
|
|
|
returnedMessage.Append(idU);
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING(")"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Formats an error message for overridable certificate errors (of type
|
|
|
|
* OverridableCertErrorMessage). Use formatPlainErrorMessage to format
|
|
|
|
* non-overridable cert errors and non-cert-related errors.
|
|
|
|
*/
|
|
|
|
static nsresult
|
|
|
|
formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
|
|
|
|
PRErrorCode errorCodeToReport,
|
2012-08-22 15:56:38 +00:00
|
|
|
const nsXPIDLCString & host, int32_t port,
|
2012-08-28 13:32:34 +00:00
|
|
|
bool suppressPort443,
|
|
|
|
bool wantsHtml,
|
2012-04-30 04:00:22 +00:00
|
|
|
nsString & returnedMessage)
|
|
|
|
{
|
2013-11-26 18:18:21 +00:00
|
|
|
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
|
|
|
|
|
2014-01-04 15:02:17 +00:00
|
|
|
const char16_t *params[1];
|
2012-04-30 04:00:22 +00:00
|
|
|
nsresult rv;
|
|
|
|
nsAutoString hostWithPort;
|
|
|
|
nsAutoString hostWithoutPort;
|
|
|
|
|
|
|
|
// For now, hide port when it's 443 and we're reporting the error.
|
|
|
|
// In the future a better mechanism should be used
|
|
|
|
// to make a decision about showing the port number, possibly by requiring
|
|
|
|
// the context object to implement a specific interface.
|
|
|
|
// The motivation is that Mozilla browser would like to hide the port number
|
|
|
|
// in error pages in the common case.
|
|
|
|
|
|
|
|
hostWithoutPort.AppendASCII(host);
|
2012-08-28 13:32:34 +00:00
|
|
|
if (suppressPort443 && port == 443) {
|
2012-04-30 04:00:22 +00:00
|
|
|
params[0] = hostWithoutPort.get();
|
|
|
|
} else {
|
|
|
|
hostWithPort.AppendASCII(host);
|
|
|
|
hostWithPort.Append(':');
|
|
|
|
hostWithPort.AppendInt(port);
|
|
|
|
params[0] = hostWithPort.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
returnedMessage.Truncate();
|
|
|
|
rv = component->PIPBundleFormatStringFromName("certErrorIntro", params, 1,
|
|
|
|
returnedMessage);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
|
|
|
|
|
2012-10-17 20:48:36 +00:00
|
|
|
RefPtr<nsIX509Cert> ix509;
|
|
|
|
rv = sslStatus.GetServerCert(byRef(ix509));
|
2012-04-30 04:00:22 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
bool isUntrusted;
|
|
|
|
rv = sslStatus.GetIsUntrusted(&isUntrusted);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (isUntrusted) {
|
|
|
|
AppendErrorTextUntrusted(errorCodeToReport, hostWithoutPort, ix509,
|
|
|
|
component, returnedMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isDomainMismatch;
|
|
|
|
rv = sslStatus.GetIsDomainMismatch(&isDomainMismatch);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (isDomainMismatch) {
|
2012-08-28 13:32:34 +00:00
|
|
|
AppendErrorTextMismatch(hostWithoutPort, ix509, component, wantsHtml, returnedMessage);
|
2012-04-30 04:00:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool isNotValidAtThisTime;
|
|
|
|
rv = sslStatus.GetIsNotValidAtThisTime(&isNotValidAtThisTime);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (isNotValidAtThisTime) {
|
|
|
|
AppendErrorTextTime(ix509, component, returnedMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
AppendErrorTextCode(errorCodeToReport, component, returnedMessage);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// RememberCertErrorsTable
|
|
|
|
|
|
|
|
/*static*/ RememberCertErrorsTable*
|
2012-07-30 14:20:58 +00:00
|
|
|
RememberCertErrorsTable::sInstance = nullptr;
|
2012-04-30 04:00:22 +00:00
|
|
|
|
|
|
|
RememberCertErrorsTable::RememberCertErrorsTable()
|
2013-09-02 08:41:57 +00:00
|
|
|
: mErrorHosts(16)
|
|
|
|
, mMutex("RememberCertErrorsTable::mMutex")
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsresult
|
2012-09-02 02:35:17 +00:00
|
|
|
GetHostPortKey(TransportSecurityInfo* infoObject, nsAutoCString &result)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
result.Truncate();
|
|
|
|
|
|
|
|
nsXPIDLCString hostName;
|
|
|
|
rv = infoObject->GetHostName(getter_Copies(hostName));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t port;
|
2012-04-30 04:00:22 +00:00
|
|
|
rv = infoObject->GetPort(&port);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
result.Assign(hostName);
|
|
|
|
result.Append(':');
|
|
|
|
result.AppendInt(port);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RememberCertErrorsTable::RememberCertHasError(TransportSecurityInfo* infoObject,
|
|
|
|
nsSSLStatus* status,
|
|
|
|
SECStatus certVerificationResult)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString hostPortKey;
|
2012-04-30 04:00:22 +00:00
|
|
|
rv = GetHostPortKey(infoObject, hostPortKey);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (certVerificationResult != SECSuccess) {
|
|
|
|
NS_ASSERTION(status,
|
|
|
|
"Must have nsSSLStatus object when remembering flags");
|
|
|
|
|
|
|
|
if (!status)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CertStateBits bits;
|
|
|
|
bits.mIsDomainMismatch = status->mIsDomainMismatch;
|
|
|
|
bits.mIsNotValidAtThisTime = status->mIsNotValidAtThisTime;
|
|
|
|
bits.mIsUntrusted = status->mIsUntrusted;
|
|
|
|
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
mErrorHosts.Put(hostPortKey, bits);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
mErrorHosts.Remove(hostPortKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RememberCertErrorsTable::LookupCertErrorBits(TransportSecurityInfo* infoObject,
|
|
|
|
nsSSLStatus* status)
|
|
|
|
{
|
|
|
|
// Get remembered error bits from our cache, because of SSL session caching
|
|
|
|
// the NSS library potentially hasn't notified us for this socket.
|
|
|
|
if (status->mHaveCertErrorBits)
|
|
|
|
// Rather do not modify bits if already set earlier
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString hostPortKey;
|
2012-04-30 04:00:22 +00:00
|
|
|
rv = GetHostPortKey(infoObject, hostPortKey);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return;
|
|
|
|
|
|
|
|
CertStateBits bits;
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
if (!mErrorHosts.Get(hostPortKey, &bits))
|
|
|
|
// No record was found, this host had no cert errors
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This host had cert errors, update the bits correctly
|
|
|
|
status->mHaveCertErrorBits = true;
|
|
|
|
status->mIsDomainMismatch = bits.mIsDomainMismatch;
|
|
|
|
status->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime;
|
|
|
|
status->mIsUntrusted = bits.mIsUntrusted;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
TransportSecurityInfo::SetStatusErrorBits(nsIX509Cert & cert,
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t collected_errors)
|
2012-04-30 04:00:22 +00:00
|
|
|
{
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
|
|
|
|
if (!mSSLStatus)
|
|
|
|
mSSLStatus = new nsSSLStatus();
|
|
|
|
|
|
|
|
mSSLStatus->mServerCert = &cert;
|
|
|
|
|
|
|
|
mSSLStatus->mHaveCertErrorBits = true;
|
|
|
|
mSSLStatus->mIsDomainMismatch =
|
|
|
|
collected_errors & nsICertOverrideService::ERROR_MISMATCH;
|
|
|
|
mSSLStatus->mIsNotValidAtThisTime =
|
|
|
|
collected_errors & nsICertOverrideService::ERROR_TIME;
|
|
|
|
mSSLStatus->mIsUntrusted =
|
|
|
|
collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
|
|
|
|
|
|
|
|
RememberCertErrorsTable::GetInstance().RememberCertHasError(this,
|
|
|
|
mSSLStatus,
|
|
|
|
SECFailure);
|
|
|
|
}
|
|
|
|
|
|
|
|
} } // namespace mozilla::psm
|