diff options
Diffstat (limited to 'security/manager/ssl/TransportSecurityInfo.cpp')
-rw-r--r-- | security/manager/ssl/TransportSecurityInfo.cpp | 1240 |
1 files changed, 1240 insertions, 0 deletions
diff --git a/security/manager/ssl/TransportSecurityInfo.cpp b/security/manager/ssl/TransportSecurityInfo.cpp new file mode 100644 index 0000000000..defb672a0e --- /dev/null +++ b/security/manager/ssl/TransportSecurityInfo.cpp @@ -0,0 +1,1240 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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/. */ + +#include "TransportSecurityInfo.h" + +#include "DateTimeFormat.h" +#include "PSMRunnable.h" +#include "ipc/IPCMessageUtils.h" +#include "mozilla/Casting.h" +#include "nsComponentManagerUtils.h" +#include "nsICertOverrideService.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsIWebProgressListener.h" +#include "nsNSSCertHelper.h" +#include "nsNSSCertificate.h" +#include "nsNSSComponent.h" +#include "nsNSSHelper.h" +#include "nsReadableUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsXULAppAPI.h" +#include "mozpkix/pkixtypes.h" +#include "secerr.h" +#include "ssl.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() + : mCipherSuite(0), + mProtocolVersion(0), + mCertificateTransparencyStatus( + nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE), + mKeaGroup(), + mSignatureSchemeName(), + mIsAcceptedEch(false), + mIsDelegatedCredential(false), + mIsDomainMismatch(false), + mIsNotValidAtThisTime(false), + mIsUntrusted(false), + mIsEV(false), + mHasIsEVStatus(false), + mHaveCipherSuiteAndProtocol(false), + mHaveCertErrorBits(false), + mCanceled(false), + mMutex("TransportSecurityInfo::mMutex"), + mNPNCompleted(false), + mResumed(false), + mIsBuiltCertChainRootBuiltInRoot(false), + mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE), + mErrorCode(0), + mPort(0) {} + +NS_IMPL_ISUPPORTS(TransportSecurityInfo, nsITransportSecurityInfo, + nsIInterfaceRequestor, nsISerializable, nsIClassInfo) + +void TransportSecurityInfo::SetHostName(const char* host) { + MutexAutoLock lock(mMutex); + + mHostName.Assign(host); +} + +void TransportSecurityInfo::SetPort(int32_t aPort) { mPort = aPort; } + +void TransportSecurityInfo::SetOriginAttributes( + const OriginAttributes& aOriginAttributes) { + MutexAutoLock lock(mMutex); + + mOriginAttributes = aOriginAttributes; +} + +// NB: GetErrorCode may be called before an error code is set (if ever). In that +// case, this returns (by pointer) 0, which is treated as a successful value. +NS_IMETHODIMP +TransportSecurityInfo::GetErrorCode(int32_t* state) { + // We're in an inconsistent state if we think we've been canceled but no error + // code was set or we haven't been canceled but an error code was set. + MOZ_ASSERT( + !((mCanceled && mErrorCode == 0) || (!mCanceled && mErrorCode != 0))); + if ((mCanceled && mErrorCode == 0) || (!mCanceled && mErrorCode != 0)) { + mCanceled = true; + mErrorCode = SEC_ERROR_LIBRARY_FAILURE; + } + + *state = mErrorCode; + return NS_OK; +} + +void TransportSecurityInfo::SetCanceled(PRErrorCode errorCode) { + MOZ_ASSERT(errorCode != 0); + if (errorCode == 0) { + errorCode = SEC_ERROR_LIBRARY_FAILURE; + } + + mErrorCode = errorCode; + mCanceled = true; +} + +bool TransportSecurityInfo::IsCanceled() { return mCanceled; } + +NS_IMETHODIMP +TransportSecurityInfo::GetSecurityState(uint32_t* state) { + *state = mSecurityState; + return NS_OK; +} + +void TransportSecurityInfo::SetSecurityState(uint32_t aState) { + mSecurityState = aState; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetErrorCodeString(nsAString& aErrorString) { + const char* codeName = PR_ErrorToName(mErrorCode); + aErrorString.Truncate(); + if (codeName) { + aErrorString = NS_ConvertASCIItoUTF16(codeName); + } + + return NS_OK; +} + +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; + } + MutexAutoLock lock(mMutex); + + nsresult rv; + if (!mCallbacks) { + nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext(); + rv = ir->GetInterface(uuid, result); + } else { + rv = mCallbacks->GetInterface(uuid, result); + } + return rv; +} + +// This is a new magic value. However, it re-uses the first 4 bytes +// 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, 0x1faa, 0x4169, { \ + 0xb0, 0xd2, 0x81, 0x29, 0xec, 0x7c, 0xb1, 0xde \ + } \ + } +static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC); + +// NB: Any updates (except disk-only fields) must be kept in sync with +// |SerializeToIPC|. +NS_IMETHODIMP +TransportSecurityInfo::Write(nsIObjectOutputStream* aStream) { + nsresult rv = aStream->WriteID(kTransportSecurityInfoMagic); + if (NS_FAILED(rv)) { + return rv; + } + + MutexAutoLock lock(mMutex); + + rv = aStream->Write32(mSecurityState); + if (NS_FAILED(rv)) { + return rv; + } + // mSubRequestsBrokenSecurity was removed in bug 748809 + rv = aStream->Write32(0); + if (NS_FAILED(rv)) { + return rv; + } + // mSubRequestsNoSecurity was removed in bug 748809 + rv = aStream->Write32(0); + if (NS_FAILED(rv)) { + return rv; + } + rv = aStream->Write32(static_cast<uint32_t>(mErrorCode)); + if (NS_FAILED(rv)) { + return rv; + } + + // Re-purpose mErrorMessageCached to represent serialization version + // If string doesn't match exact version it will be treated as older + // serialization. + rv = aStream->WriteWStringZ(NS_ConvertUTF8toUTF16("6").get()); + if (NS_FAILED(rv)) { + return rv; + } + + // moved from nsISSLStatus + rv = NS_WriteOptionalCompoundObject(aStream, mServerCert, + NS_GET_IID(nsIX509Cert), true); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->Write16(mCipherSuite); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->Write16(mProtocolVersion); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->WriteBoolean(mIsDomainMismatch); + NS_ENSURE_SUCCESS(rv, rv); + rv = aStream->WriteBoolean(mIsNotValidAtThisTime); + NS_ENSURE_SUCCESS(rv, rv); + rv = aStream->WriteBoolean(mIsUntrusted); + NS_ENSURE_SUCCESS(rv, rv); + rv = aStream->WriteBoolean(mIsEV); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->WriteBoolean(mHasIsEVStatus); + NS_ENSURE_SUCCESS(rv, rv); + rv = aStream->WriteBoolean(mHaveCipherSuiteAndProtocol); + NS_ENSURE_SUCCESS(rv, rv); + rv = aStream->WriteBoolean(mHaveCertErrorBits); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->Write16(mCertificateTransparencyStatus); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->WriteStringZ(mKeaGroup.get()); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->WriteStringZ(mSignatureSchemeName.get()); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->Write16(mSucceededCertChain.Length()); + NS_ENSURE_SUCCESS(rv, rv); + + for (const auto& cert : mSucceededCertChain) { + rv = aStream->WriteCompoundObject(cert, NS_GET_IID(nsIX509Cert), true); + NS_ENSURE_SUCCESS(rv, rv); + } + // END moved from nsISSLStatus + rv = aStream->Write16(mFailedCertChain.Length()); + NS_ENSURE_SUCCESS(rv, rv); + for (const auto& cert : mFailedCertChain) { + rv = aStream->WriteCompoundObject(cert, NS_GET_IID(nsIX509Cert), true); + NS_ENSURE_SUCCESS(rv, rv); + } + + rv = aStream->WriteBoolean(mIsDelegatedCredential); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->WriteBoolean(mNPNCompleted); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->WriteStringZ(mNegotiatedNPN.get()); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->WriteBoolean(mResumed); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->WriteBoolean(mIsBuiltCertChainRootBuiltInRoot); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->WriteBoolean(mIsAcceptedEch); + if (NS_FAILED(rv)) { + return rv; + } + + return NS_OK; +} + +#define CHILD_DIAGNOSTIC_ASSERT(condition, message) \ + if (XRE_GetProcessType() == GeckoProcessType_Content) { \ + MOZ_DIAGNOSTIC_ASSERT(condition, message); \ + } + +// This is for backward compatibility to be able to read nsISSLStatus +// serialized object. +nsresult TransportSecurityInfo::ReadSSLStatus(nsIObjectInputStream* aStream, + MutexAutoLock& aProofOfLock) { + bool nsISSLStatusPresent; + nsresult rv = aStream->ReadBoolean(&nsISSLStatusPresent); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + if (!nsISSLStatusPresent) { + return NS_OK; + } + // nsISSLStatus present. Prepare to read elements. + // Throw away cid, validate iid + nsCID cid; + nsIID iid; + rv = aStream->ReadID(&cid); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = aStream->ReadID(&iid); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + static const nsIID nsSSLStatusIID = { + 0xfa9ba95b, + 0xca3b, + 0x498a, + {0xb8, 0x89, 0x7c, 0x79, 0xcf, 0x28, 0xfe, 0xe8}}; + if (!iid.Equals(nsSSLStatusIID)) { + CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail"); + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr<nsISupports> cert; + rv = aStream->ReadObject(true, getter_AddRefs(cert)); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + if (cert) { + mServerCert = do_QueryInterface(cert); + if (!mServerCert) { + CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail"); + return NS_NOINTERFACE; + } + } + + rv = aStream->Read16(&mCipherSuite); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + // The code below is a workaround to allow serializing new fields + // while preserving binary compatibility with older streams. For more details + // on the binary compatibility requirement, refer to bug 1248628. + // Here, we take advantage of the fact that mProtocolVersion was originally + // stored as a 16 bits integer, but the highest 8 bits were never used. + // These bits are now used for stream versioning. + uint16_t protocolVersionAndStreamFormatVersion; + rv = aStream->Read16(&protocolVersionAndStreamFormatVersion); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + mProtocolVersion = protocolVersionAndStreamFormatVersion & 0xFF; + const uint8_t streamFormatVersion = + (protocolVersionAndStreamFormatVersion >> 8) & 0xFF; + + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsDomainMismatch); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsNotValidAtThisTime); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsUntrusted); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsEV); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHasIsEVStatus); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCipherSuiteAndProtocol); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCertErrorBits); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + // Added in version 1 (see bug 1305289). + if (streamFormatVersion >= 1) { + rv = aStream->Read16(&mCertificateTransparencyStatus); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Added in version 2 (see bug 1304923). + if (streamFormatVersion >= 2) { + rv = aStream->ReadCString(mKeaGroup); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->ReadCString(mSignatureSchemeName); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Added in version 3 (see bug 1406856). + if (streamFormatVersion >= 3) { + rv = ReadCertList(aStream, mSucceededCertChain, aProofOfLock); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + + // Read only to consume bytes from the stream. + nsTArray<RefPtr<nsIX509Cert>> failedCertChain; + rv = ReadCertList(aStream, failedCertChain, aProofOfLock); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + } + return rv; +} + +// This is for backward compatability to be able to read nsIX509CertList +// serialized object. +nsresult TransportSecurityInfo::ReadCertList( + nsIObjectInputStream* aStream, nsTArray<RefPtr<nsIX509Cert>>& aCertList, + MutexAutoLock& aProofOfLock) { + bool nsIX509CertListPresent; + + nsresult rv = aStream->ReadBoolean(&nsIX509CertListPresent); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + if (!nsIX509CertListPresent) { + return NS_OK; + } + // nsIX509CertList present. Prepare to read elements. + // Throw away cid, validate iid + nsCID cid; + nsIID iid; + rv = aStream->ReadID(&cid); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = aStream->ReadID(&iid); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + static const nsIID nsIX509CertListIID = { + 0xae74cda5, + 0xcd2f, + 0x473f, + {0x96, 0xf5, 0xf0, 0xb7, 0xff, 0xf6, 0x2c, 0x68}}; + + if (!iid.Equals(nsIX509CertListIID)) { + CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail"); + return NS_ERROR_UNEXPECTED; + } + + uint32_t certListSize; + rv = aStream->Read32(&certListSize); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + return ReadCertificatesFromStream(aStream, certListSize, aCertList, + aProofOfLock); +} + +nsresult TransportSecurityInfo::ReadCertificatesFromStream( + nsIObjectInputStream* aStream, uint32_t aSize, + nsTArray<RefPtr<nsIX509Cert>>& aCertList, MutexAutoLock& aProofOfLock) { + nsresult rv; + for (uint32_t i = 0; i < aSize; ++i) { + nsCOMPtr<nsISupports> support; + rv = aStream->ReadObject(true, getter_AddRefs(support)); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(support); + if (!cert) { + return NS_ERROR_UNEXPECTED; + } + RefPtr<nsIX509Cert> castedCert(cert.get()); + aCertList.AppendElement(castedCert); + } + return NS_OK; +} + +// NB: Any updates (except disk-only fields) must be kept in sync with +// |DeserializeFromIPC|. +NS_IMETHODIMP +TransportSecurityInfo::Read(nsIObjectInputStream* aStream) { + nsID id; + nsresult rv = aStream->ReadID(&id); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + if (!id.Equals(kTransportSecurityInfoMagic)) { + CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail"); + return NS_ERROR_UNEXPECTED; + } + + MutexAutoLock lock(mMutex); + + rv = ReadUint32AndSetAtomicFieldHelper(aStream, mSecurityState); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + // mSubRequestsBrokenSecurity was removed in bug 748809 + uint32_t unusedSubRequestsBrokenSecurity; + rv = aStream->Read32(&unusedSubRequestsBrokenSecurity); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + // mSubRequestsNoSecurity was removed in bug 748809 + uint32_t unusedSubRequestsNoSecurity; + rv = aStream->Read32(&unusedSubRequestsNoSecurity); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + uint32_t errorCode; + rv = aStream->Read32(&errorCode); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + // PRErrorCode will be a negative value + mErrorCode = static_cast<PRErrorCode>(errorCode); + // If mErrorCode is non-zero, SetCanceled was called on the + // TransportSecurityInfo that was serialized. + if (mErrorCode != 0) { + mCanceled = true; + } + + // Re-purpose mErrorMessageCached to represent serialization version + // If string doesn't match exact version it will be treated as older + // serialization. + nsAutoString serVersion; + rv = aStream->ReadString(serVersion); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + + // moved from nsISSLStatus + if (!serVersion.EqualsASCII("1") && !serVersion.EqualsASCII("2") && + !serVersion.EqualsASCII("3") && !serVersion.EqualsASCII("4") && + !serVersion.EqualsASCII("5") && !serVersion.EqualsASCII("6")) { + // nsISSLStatus may be present + rv = ReadSSLStatus(aStream, lock); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + } else { + nsCOMPtr<nsISupports> cert; + rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(cert)); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + if (cert != nullptr) { + mServerCert = do_QueryInterface(cert); + if (!mServerCert) { + CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail"); + return NS_NOINTERFACE; + } + } + + rv = aStream->Read16(&mCipherSuite); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->Read16(&mProtocolVersion); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsDomainMismatch); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsNotValidAtThisTime); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsUntrusted); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsEV); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHasIsEVStatus); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCipherSuiteAndProtocol); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCertErrorBits); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->Read16(&mCertificateTransparencyStatus); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->ReadCString(mKeaGroup); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aStream->ReadCString(mSignatureSchemeName); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + if (!serVersion.EqualsASCII("3") && !serVersion.EqualsASCII("4") && + !serVersion.EqualsASCII("5") && !serVersion.EqualsASCII("6")) { + // The old data structure of certList(nsIX509CertList) presents + rv = ReadCertList(aStream, mSucceededCertChain, lock); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + } else { + uint16_t certCount; + rv = aStream->Read16(&certCount); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ReadCertificatesFromStream(aStream, certCount, mSucceededCertChain, + lock); + NS_ENSURE_SUCCESS(rv, rv); + } + } + // END moved from nsISSLStatus + if (!serVersion.EqualsASCII("3") && !serVersion.EqualsASCII("4") && + !serVersion.EqualsASCII("5") && !serVersion.EqualsASCII("6")) { + // The old data structure of certList(nsIX509CertList) presents + rv = ReadCertList(aStream, mFailedCertChain, lock); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + } else { + uint16_t certCount; + rv = aStream->Read16(&certCount); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + NS_ENSURE_SUCCESS(rv, rv); + + rv = ReadCertificatesFromStream(aStream, certCount, mFailedCertChain, lock); + NS_ENSURE_SUCCESS(rv, rv); + } + + // mIsDelegatedCredential added in bug 1562773 + if (serVersion.EqualsASCII("2") || serVersion.EqualsASCII("3") || + serVersion.EqualsASCII("4") || serVersion.EqualsASCII("5") || + serVersion.EqualsASCII("6")) { + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsDelegatedCredential); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + } + + // mNPNCompleted, mNegotiatedNPN, mResumed added in bug 1584104 + if (serVersion.EqualsASCII("4") || serVersion.EqualsASCII("5") || + serVersion.EqualsASCII("6")) { + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mNPNCompleted); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + + rv = aStream->ReadCString(mNegotiatedNPN); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mResumed); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + } + + // mIsBuiltCertChainRootBuiltInRoot added in bug 1485652 + if (serVersion.EqualsASCII("5") || serVersion.EqualsASCII("6")) { + rv = ReadBoolAndSetAtomicFieldHelper(aStream, + mIsBuiltCertChainRootBuiltInRoot); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + } + + // mIsAcceptedEch added in bug 1678079 + if (serVersion.EqualsASCII("6")) { + rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsAcceptedEch); + CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), + "Deserialization should not fail"); + if (NS_FAILED(rv)) { + return rv; + } + } + + return NS_OK; +} + +#undef CHILD_DIAGNOSTIC_ASSERT + +void TransportSecurityInfo::SerializeToIPC(IPC::Message* aMsg) { + MutexAutoLock guard(mMutex); + + int32_t errorCode = static_cast<int32_t>(mErrorCode); + + WriteParam(aMsg, static_cast<uint32_t>(mSecurityState)); + WriteParam(aMsg, errorCode); + WriteParam(aMsg, mServerCert); + WriteParam(aMsg, mCipherSuite); + WriteParam(aMsg, mProtocolVersion); + WriteParam(aMsg, static_cast<bool>(mIsDomainMismatch)); + WriteParam(aMsg, static_cast<bool>(mIsNotValidAtThisTime)); + WriteParam(aMsg, static_cast<bool>(mIsUntrusted)); + WriteParam(aMsg, static_cast<bool>(mIsEV)); + WriteParam(aMsg, static_cast<bool>(mHasIsEVStatus)); + WriteParam(aMsg, static_cast<bool>(mHaveCipherSuiteAndProtocol)); + WriteParam(aMsg, static_cast<bool>(mHaveCertErrorBits)); + WriteParam(aMsg, mCertificateTransparencyStatus); + WriteParam(aMsg, mKeaGroup); + WriteParam(aMsg, mSignatureSchemeName); + WriteParam(aMsg, mSucceededCertChain); + WriteParam(aMsg, mFailedCertChain); + WriteParam(aMsg, static_cast<bool>(mIsDelegatedCredential)); + WriteParam(aMsg, static_cast<bool>(mNPNCompleted)); + WriteParam(aMsg, mNegotiatedNPN); + WriteParam(aMsg, static_cast<bool>(mResumed)); + WriteParam(aMsg, static_cast<bool>(mIsBuiltCertChainRootBuiltInRoot)); + WriteParam(aMsg, static_cast<bool>(mIsAcceptedEch)); +} + +bool TransportSecurityInfo::DeserializeFromIPC(const IPC::Message* aMsg, + PickleIterator* aIter) { + MutexAutoLock guard(mMutex); + + int32_t errorCode = 0; + + if (!ReadParamAtomicHelper(aMsg, aIter, mSecurityState) || + !ReadParam(aMsg, aIter, &errorCode) || + !ReadParam(aMsg, aIter, &mServerCert) || + !ReadParam(aMsg, aIter, &mCipherSuite) || + !ReadParam(aMsg, aIter, &mProtocolVersion) || + !ReadParamAtomicHelper(aMsg, aIter, mIsDomainMismatch) || + !ReadParamAtomicHelper(aMsg, aIter, mIsNotValidAtThisTime) || + !ReadParamAtomicHelper(aMsg, aIter, mIsUntrusted) || + !ReadParamAtomicHelper(aMsg, aIter, mIsEV) || + !ReadParamAtomicHelper(aMsg, aIter, mHasIsEVStatus) || + !ReadParamAtomicHelper(aMsg, aIter, mHaveCipherSuiteAndProtocol) || + !ReadParamAtomicHelper(aMsg, aIter, mHaveCertErrorBits) || + !ReadParam(aMsg, aIter, &mCertificateTransparencyStatus) || + !ReadParam(aMsg, aIter, &mKeaGroup) || + !ReadParam(aMsg, aIter, &mSignatureSchemeName) || + !ReadParam(aMsg, aIter, &mSucceededCertChain) || + !ReadParam(aMsg, aIter, &mFailedCertChain) || + !ReadParamAtomicHelper(aMsg, aIter, mIsDelegatedCredential) || + !ReadParamAtomicHelper(aMsg, aIter, mNPNCompleted) || + !ReadParam(aMsg, aIter, &mNegotiatedNPN) || + !ReadParamAtomicHelper(aMsg, aIter, mResumed) || + !ReadParamAtomicHelper(aMsg, aIter, mIsBuiltCertChainRootBuiltInRoot) || + !ReadParamAtomicHelper(aMsg, aIter, mIsAcceptedEch)) { + return false; + } + + mErrorCode = static_cast<PRErrorCode>(errorCode); + if (mErrorCode != 0) { + mCanceled = true; + } + + return true; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetInterfaces(nsTArray<nsIID>& array) { + array.Clear(); + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetScriptableHelper(nsIXPCScriptable** _retval) { + *_retval = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetContractID(nsACString& aContractID) { + aContractID.SetIsVoid(true); + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetClassDescription(nsACString& aClassDescription) { + aClassDescription.SetIsVoid(true); + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetClassID(nsCID** aClassID) { + *aClassID = (nsCID*)moz_xmalloc(sizeof(nsCID)); + return GetClassIDNoAlloc(*aClassID); +} + +NS_IMETHODIMP +TransportSecurityInfo::GetFlags(uint32_t* aFlags) { + *aFlags = 0; + return NS_OK; +} + +static NS_DEFINE_CID(kNSSSocketInfoCID, TRANSPORTSECURITYINFO_CID); + +NS_IMETHODIMP +TransportSecurityInfo::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) { + *aClassIDNoAlloc = kNSSSocketInfoCID; + return NS_OK; +} + +// RememberCertErrorsTable + +/*static*/ +RememberCertErrorsTable* RememberCertErrorsTable::sInstance = nullptr; + +RememberCertErrorsTable::RememberCertErrorsTable() + : mErrorHosts(), mMutex("RememberCertErrorsTable::mMutex") {} + +static nsresult GetHostPortKey(TransportSecurityInfo* infoObject, + /*out*/ nsCString& result) { + MOZ_ASSERT(infoObject); + NS_ENSURE_ARG(infoObject); + + result.Truncate(); + + result.Assign(infoObject->GetHostName()); + result.Append(':'); + result.AppendInt(infoObject->GetPort()); + + return NS_OK; +} + +void RememberCertErrorsTable::RememberCertHasError( + TransportSecurityInfo* infoObject, SECStatus certVerificationResult) { + nsresult rv; + + nsAutoCString hostPortKey; + rv = GetHostPortKey(infoObject, hostPortKey); + if (NS_FAILED(rv)) { + return; + } + + if (certVerificationResult != SECSuccess) { + MOZ_ASSERT(infoObject->mHaveCertErrorBits, + "Must have error bits when remembering flags"); + if (!infoObject->mHaveCertErrorBits) { + return; + } + + CertStateBits bits; + bits.mIsDomainMismatch = infoObject->mIsDomainMismatch; + bits.mIsNotValidAtThisTime = infoObject->mIsNotValidAtThisTime; + bits.mIsUntrusted = infoObject->mIsUntrusted; + + MutexAutoLock lock(mMutex); + mErrorHosts.Put(hostPortKey, bits); + } else { + MutexAutoLock lock(mMutex); + mErrorHosts.Remove(hostPortKey); + } +} + +void RememberCertErrorsTable::LookupCertErrorBits( + TransportSecurityInfo* infoObject) { + // Get remembered error bits from our cache, because of SSL session caching + // the NSS library potentially hasn't notified us for this socket. + if (infoObject->mHaveCertErrorBits) { + // Rather do not modify bits if already set earlier + return; + } + + nsresult rv; + + nsAutoCString hostPortKey; + 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 + infoObject->mHaveCertErrorBits = true; + infoObject->mIsDomainMismatch = bits.mIsDomainMismatch; + infoObject->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime; + infoObject->mIsUntrusted = bits.mIsUntrusted; +} + +void TransportSecurityInfo::SetStatusErrorBits(nsNSSCertificate* cert, + uint32_t collected_errors) { + SetServerCert(cert, EVStatus::NotEV); + + mHaveCertErrorBits = true; + mIsDomainMismatch = collected_errors & nsICertOverrideService::ERROR_MISMATCH; + mIsNotValidAtThisTime = collected_errors & nsICertOverrideService::ERROR_TIME; + mIsUntrusted = collected_errors & nsICertOverrideService::ERROR_UNTRUSTED; + + RememberCertErrorsTable::GetInstance().RememberCertHasError(this, SECFailure); +} + +NS_IMETHODIMP +TransportSecurityInfo::GetFailedCertChain( + nsTArray<RefPtr<nsIX509Cert>>& aFailedCertChain) { + MOZ_ASSERT(aFailedCertChain.IsEmpty()); + MutexAutoLock lock(mMutex); + if (!aFailedCertChain.IsEmpty()) { + return NS_ERROR_INVALID_ARG; + } + aFailedCertChain.AppendElements(mFailedCertChain); + return NS_OK; +} + +static nsresult CreateCertChain(nsTArray<RefPtr<nsIX509Cert>>& aOutput, + nsTArray<nsTArray<uint8_t>>&& aCertList) { + nsTArray<nsTArray<uint8_t>> certList = std::move(aCertList); + aOutput.Clear(); + for (auto& certBytes : certList) { + RefPtr<nsIX509Cert> cert = nsNSSCertificate::ConstructFromDER( + BitwiseCast<char*, uint8_t*>(certBytes.Elements()), certBytes.Length()); + if (!cert) { + return NS_ERROR_FAILURE; + } + aOutput.AppendElement(cert); + } + return NS_OK; +} + +nsresult TransportSecurityInfo::SetFailedCertChain( + nsTArray<nsTArray<uint8_t>>&& aCertList) { + MutexAutoLock lock(mMutex); + + return CreateCertChain(mFailedCertChain, std::move(aCertList)); +} + +NS_IMETHODIMP TransportSecurityInfo::GetServerCert(nsIX509Cert** aServerCert) { + NS_ENSURE_ARG_POINTER(aServerCert); + MutexAutoLock lock(mMutex); + + nsCOMPtr<nsIX509Cert> cert = mServerCert; + cert.forget(aServerCert); + return NS_OK; +} + +void TransportSecurityInfo::SetServerCert(nsNSSCertificate* aServerCert, + EVStatus aEVStatus) { + MOZ_ASSERT(aServerCert); + MutexAutoLock lock(mMutex); + + mServerCert = aServerCert; + mIsEV = (aEVStatus == EVStatus::EV); + mHasIsEVStatus = true; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetSucceededCertChain( + nsTArray<RefPtr<nsIX509Cert>>& aSucceededCertChain) { + MOZ_ASSERT(aSucceededCertChain.IsEmpty()); + MutexAutoLock lock(mMutex); + if (!aSucceededCertChain.IsEmpty()) { + return NS_ERROR_INVALID_ARG; + } + aSucceededCertChain.AppendElements(mSucceededCertChain); + return NS_OK; +} + +nsresult TransportSecurityInfo::SetSucceededCertChain( + nsTArray<nsTArray<uint8_t>>&& aCertList) { + MutexAutoLock lock(mMutex); + return CreateCertChain(mSucceededCertChain, std::move(aCertList)); +} + +NS_IMETHODIMP TransportSecurityInfo::SetIsBuiltCertChainRootBuiltInRoot( + bool aIsBuiltInRoot) { + mIsBuiltCertChainRootBuiltInRoot = aIsBuiltInRoot; + return NS_OK; +} + +NS_IMETHODIMP TransportSecurityInfo::GetIsBuiltCertChainRootBuiltInRoot( + bool* aIsBuiltInRoot) { + NS_ENSURE_ARG_POINTER(aIsBuiltInRoot); + *aIsBuiltInRoot = mIsBuiltCertChainRootBuiltInRoot; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetCipherName(nsACString& aCipherName) { + MutexAutoLock lock(mMutex); + + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + + SSLCipherSuiteInfo cipherInfo; + if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo, sizeof(cipherInfo)) != + SECSuccess) { + return NS_ERROR_FAILURE; + } + + aCipherName.Assign(cipherInfo.cipherSuiteName); + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetKeyLength(uint32_t* aKeyLength) { + NS_ENSURE_ARG_POINTER(aKeyLength); + MutexAutoLock lock(mMutex); + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + + SSLCipherSuiteInfo cipherInfo; + if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo, sizeof(cipherInfo)) != + SECSuccess) { + return NS_ERROR_FAILURE; + } + + *aKeyLength = cipherInfo.symKeyBits; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetSecretKeyLength(uint32_t* aSecretKeyLength) { + NS_ENSURE_ARG_POINTER(aSecretKeyLength); + MutexAutoLock lock(mMutex); + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + + SSLCipherSuiteInfo cipherInfo; + if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo, sizeof(cipherInfo)) != + SECSuccess) { + return NS_ERROR_FAILURE; + } + + *aSecretKeyLength = cipherInfo.effectiveKeyBits; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetKeaGroupName(nsACString& aKeaGroup) { + MutexAutoLock lock(mMutex); + + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + + aKeaGroup.Assign(mKeaGroup); + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetSignatureSchemeName(nsACString& aSignatureScheme) { + MutexAutoLock lock(mMutex); + + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + + aSignatureScheme.Assign(mSignatureSchemeName); + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetProtocolVersion(uint16_t* aProtocolVersion) { + MutexAutoLock lock(mMutex); + + NS_ENSURE_ARG_POINTER(aProtocolVersion); + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + + *aProtocolVersion = mProtocolVersion; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetCertificateTransparencyStatus( + uint16_t* aCertificateTransparencyStatus) { + NS_ENSURE_ARG_POINTER(aCertificateTransparencyStatus); + MutexAutoLock lock(mMutex); + + *aCertificateTransparencyStatus = mCertificateTransparencyStatus; + return NS_OK; +} + +// static +uint16_t TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus( + const mozilla::psm::CertificateTransparencyInfo& info) { + using mozilla::ct::CTPolicyCompliance; + + if (!info.enabled) { + // CT disabled. + return nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE; + } + + switch (info.policyCompliance) { + case CTPolicyCompliance::Compliant: + return nsITransportSecurityInfo:: + CERTIFICATE_TRANSPARENCY_POLICY_COMPLIANT; + case CTPolicyCompliance::NotEnoughScts: + return nsITransportSecurityInfo :: + CERTIFICATE_TRANSPARENCY_POLICY_NOT_ENOUGH_SCTS; + case CTPolicyCompliance::NotDiverseScts: + return nsITransportSecurityInfo :: + CERTIFICATE_TRANSPARENCY_POLICY_NOT_DIVERSE_SCTS; + case CTPolicyCompliance::Unknown: + default: + MOZ_ASSERT_UNREACHABLE("Unexpected CTPolicyCompliance type"); + } + + return nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE; +} + +// static +nsTArray<nsTArray<uint8_t>> TransportSecurityInfo::CreateCertBytesArray( + const UniqueCERTCertList& aCertChain) { + nsTArray<nsTArray<uint8_t>> certsBytes; + for (CERTCertListNode* n = CERT_LIST_HEAD(aCertChain); + !CERT_LIST_END(n, aCertChain); n = CERT_LIST_NEXT(n)) { + nsTArray<uint8_t> certBytes; + certBytes.AppendElements(n->cert->derCert.data, n->cert->derCert.len); + certsBytes.AppendElement(std::move(certBytes)); + } + return certsBytes; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetIsDomainMismatch(bool* aIsDomainMismatch) { + NS_ENSURE_ARG_POINTER(aIsDomainMismatch); + *aIsDomainMismatch = mHaveCertErrorBits && mIsDomainMismatch; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetIsNotValidAtThisTime(bool* aIsNotValidAtThisTime) { + NS_ENSURE_ARG_POINTER(aIsNotValidAtThisTime); + *aIsNotValidAtThisTime = mHaveCertErrorBits && mIsNotValidAtThisTime; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetIsUntrusted(bool* aIsUntrusted) { + NS_ENSURE_ARG_POINTER(aIsUntrusted); + *aIsUntrusted = mHaveCertErrorBits && mIsUntrusted; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetIsExtendedValidation(bool* aIsEV) { + NS_ENSURE_ARG_POINTER(aIsEV); + *aIsEV = false; + // Never allow bad certs for EV, regardless of overrides. + if (mHaveCertErrorBits) { + return NS_OK; + } + + if (mHasIsEVStatus) { + *aIsEV = mIsEV; + return NS_OK; + } + + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetIsAcceptedEch(bool* aIsAcceptedEch) { + NS_ENSURE_ARG_POINTER(aIsAcceptedEch); + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + *aIsAcceptedEch = mIsAcceptedEch; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetIsDelegatedCredential(bool* aIsDelegCred) { + NS_ENSURE_ARG_POINTER(aIsDelegCred); + if (!mHaveCipherSuiteAndProtocol) { + return NS_ERROR_NOT_AVAILABLE; + } + *aIsDelegCred = mIsDelegatedCredential; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN) { + MutexAutoLock lock(mMutex); + + if (!mNPNCompleted) { + return NS_ERROR_NOT_CONNECTED; + } + + aNegotiatedNPN = mNegotiatedNPN; + return NS_OK; +} + +NS_IMETHODIMP +TransportSecurityInfo::GetResumed(bool* aResumed) { + *aResumed = mResumed; + return NS_OK; +} + +void TransportSecurityInfo::SetResumed(bool aResumed) { mResumed = aResumed; } + +} // namespace psm +} // namespace mozilla |