summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/TransportSecurityInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/TransportSecurityInfo.cpp')
-rw-r--r--security/manager/ssl/TransportSecurityInfo.cpp1131
1 files changed, 1131 insertions, 0 deletions
diff --git a/security/manager/ssl/TransportSecurityInfo.cpp b/security/manager/ssl/TransportSecurityInfo.cpp
new file mode 100644
index 0000000000..2bc39157e7
--- /dev/null
+++ b/security/manager/ssl/TransportSecurityInfo.cpp
@@ -0,0 +1,1131 @@
+/* -*- 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 "ipc/IPCMessageUtils.h"
+#include "mozilla/Base64.h"
+#include "mozpkix/pkixtypes.h"
+#include "nsBase64Encoder.h"
+#include "nsIObjectInputStream.h"
+#include "nsIObjectOutputStream.h"
+#include "nsIWebProgressListener.h"
+#include "nsNSSCertHelper.h"
+#include "nsNSSComponent.h"
+#include "nsNSSHelper.h"
+#include "nsReadableUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsStringStream.h"
+#include "nsXULAppAPI.h"
+#include "nsIX509Cert.h"
+#include "secerr.h"
+#include "ssl.h"
+
+#include "mozilla/ipc/IPDLParamTraits.h"
+
+// nsITransportSecurityInfo should not be created via do_CreateInstance. This
+// stub prevents that.
+template <>
+already_AddRefed<nsISupports>
+mozCreateComponent<mozilla::psm::TransportSecurityInfo>() {
+ return nullptr;
+}
+
+namespace mozilla {
+namespace psm {
+
+TransportSecurityInfo::TransportSecurityInfo(
+ uint32_t aSecurityState, PRErrorCode aErrorCode,
+ nsTArray<RefPtr<nsIX509Cert>>&& aFailedCertChain,
+ nsCOMPtr<nsIX509Cert>& aServerCert,
+ nsTArray<RefPtr<nsIX509Cert>>&& aSucceededCertChain,
+ Maybe<uint16_t> aCipherSuite, Maybe<nsCString> aKeaGroupName,
+ Maybe<nsCString> aSignatureSchemeName, Maybe<uint16_t> aProtocolVersion,
+ uint16_t aCertificateTransparencyStatus, Maybe<bool> aIsAcceptedEch,
+ Maybe<bool> aIsDelegatedCredential,
+ Maybe<OverridableErrorCategory> aOverridableErrorCategory,
+ bool aMadeOCSPRequests, bool aUsedPrivateDNS, Maybe<bool> aIsEV,
+ bool aNPNCompleted, const nsCString& aNegotiatedNPN, bool aResumed,
+ bool aIsBuiltCertChainRootBuiltInRoot, const nsCString& aPeerId)
+ : mSecurityState(aSecurityState),
+ mErrorCode(aErrorCode),
+ mFailedCertChain(std::move(aFailedCertChain)),
+ mServerCert(aServerCert),
+ mSucceededCertChain(std::move(aSucceededCertChain)),
+ mCipherSuite(aCipherSuite),
+ mKeaGroupName(aKeaGroupName),
+ mSignatureSchemeName(aSignatureSchemeName),
+ mProtocolVersion(aProtocolVersion),
+ mCertificateTransparencyStatus(aCertificateTransparencyStatus),
+ mIsAcceptedEch(aIsAcceptedEch),
+ mIsDelegatedCredential(aIsDelegatedCredential),
+ mOverridableErrorCategory(aOverridableErrorCategory),
+ mMadeOCSPRequests(aMadeOCSPRequests),
+ mUsedPrivateDNS(aUsedPrivateDNS),
+ mIsEV(aIsEV),
+ mNPNCompleted(aNPNCompleted),
+ mNegotiatedNPN(aNegotiatedNPN),
+ mResumed(aResumed),
+ mIsBuiltCertChainRootBuiltInRoot(aIsBuiltCertChainRootBuiltInRoot),
+ mPeerId(aPeerId) {}
+
+NS_IMPL_ISUPPORTS(TransportSecurityInfo, nsITransportSecurityInfo)
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetSecurityState(uint32_t* state) {
+ *state = mSecurityState;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetErrorCode(int32_t* state) {
+ *state = mErrorCode;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetErrorCodeString(nsAString& aErrorString) {
+ const char* codeName = PR_ErrorToName(mErrorCode);
+ aErrorString.Truncate();
+ if (codeName) {
+ aErrorString = NS_ConvertASCIItoUTF16(codeName);
+ }
+
+ return NS_OK;
+}
+
+// 16786594-0296-4471-8096-8f84497ca428
+#define TRANSPORTSECURITYINFO_CID \
+ { \
+ 0x16786594, 0x0296, 0x4471, { \
+ 0x80, 0x96, 0x8f, 0x84, 0x49, 0x7c, 0xa4, 0x28 \
+ } \
+ }
+static NS_DEFINE_CID(kTransportSecurityInfoCID, TRANSPORTSECURITYINFO_CID);
+
+// 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);
+
+NS_IMETHODIMP
+TransportSecurityInfo::ToString(nsACString& aResult) {
+ RefPtr<nsBase64Encoder> stream(new nsBase64Encoder());
+ nsCOMPtr<nsIObjectOutputStream> objStream(NS_NewObjectOutputStream(stream));
+ nsresult rv = objStream->WriteID(kTransportSecurityInfoCID);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = objStream->WriteID(NS_ISUPPORTS_IID);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteID(kTransportSecurityInfoMagic);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->Write32(mSecurityState);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // mSubRequestsBrokenSecurity was removed in bug 748809
+ rv = objStream->Write32(0);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // mSubRequestsNoSecurity was removed in bug 748809
+ rv = objStream->Write32(0);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = objStream->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 = objStream->WriteWStringZ(NS_ConvertUTF8toUTF16("9").get());
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // moved from nsISSLStatus
+ rv = NS_WriteOptionalCompoundObject(objStream, mServerCert,
+ NS_GET_IID(nsIX509Cert), true);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->Write16(mCipherSuite.isSome() ? *mCipherSuite : 0);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->Write16(mProtocolVersion.isSome() ? *mProtocolVersion : 0);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->Write32(mOverridableErrorCategory.isSome()
+ ? *mOverridableErrorCategory
+ : OverridableErrorCategory::ERROR_UNSET);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = objStream->WriteBoolean(mIsEV.isSome() ? *mIsEV : false);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->WriteBoolean(mIsEV.isSome()); // previously mHasIsEV
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = objStream->WriteBoolean(
+ mCipherSuite.isSome()); // previously mHaveCipherSuiteAndProtocol
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = objStream->WriteBoolean(
+ mOverridableErrorCategory.isSome()); // previously mHaveCertErrorBits
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->Write16(mCertificateTransparencyStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->WriteStringZ(mKeaGroupName.isSome() ? (*mKeaGroupName).get()
+ : "");
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->WriteStringZ(
+ mSignatureSchemeName.isSome() ? (*mSignatureSchemeName).get() : "");
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = objStream->Write16(mSucceededCertChain.Length());
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ for (const auto& cert : mSucceededCertChain) {
+ rv = objStream->WriteCompoundObject(cert, NS_GET_IID(nsIX509Cert), true);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ // END moved from nsISSLStatus
+ rv = objStream->Write16(mFailedCertChain.Length());
+ NS_ENSURE_SUCCESS(rv, rv);
+ for (const auto& cert : mFailedCertChain) {
+ rv = objStream->WriteCompoundObject(cert, NS_GET_IID(nsIX509Cert), true);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ rv = objStream->WriteBoolean(
+ mIsDelegatedCredential.isSome() ? *mIsDelegatedCredential : false);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteBoolean(mNPNCompleted);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteStringZ(mNegotiatedNPN.get());
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteBoolean(mResumed);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteBoolean(mIsBuiltCertChainRootBuiltInRoot);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteBoolean(mIsAcceptedEch.isSome() ? *mIsAcceptedEch
+ : false);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteStringZ(mPeerId.get());
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteBoolean(mMadeOCSPRequests);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->WriteBoolean(mUsedPrivateDNS);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = stream->Finish(aResult);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+nsresult TransportSecurityInfo::ReadOldOverridableErrorBits(
+ nsIObjectInputStream* aStream,
+ OverridableErrorCategory& aOverridableErrorCategory) {
+ bool isDomainMismatch;
+ nsresult rv = aStream->ReadBoolean(&isDomainMismatch);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool isNotValidAtThisTime;
+ rv = aStream->ReadBoolean(&isNotValidAtThisTime);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool isUntrusted;
+ rv = aStream->ReadBoolean(&isUntrusted);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (isUntrusted) {
+ aOverridableErrorCategory =
+ nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST;
+ } else if (isDomainMismatch) {
+ aOverridableErrorCategory =
+ nsITransportSecurityInfo::OverridableErrorCategory::ERROR_DOMAIN;
+ } else if (isNotValidAtThisTime) {
+ aOverridableErrorCategory =
+ nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME;
+ } else {
+ aOverridableErrorCategory =
+ nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET;
+ }
+
+ return NS_OK;
+}
+
+// This is for backward compatibility to be able to read nsISSLStatus
+// serialized object.
+nsresult TransportSecurityInfo::ReadSSLStatus(
+ nsIObjectInputStream* aStream, nsCOMPtr<nsIX509Cert>& aServerCert,
+ Maybe<uint16_t>& aCipherSuite, Maybe<uint16_t>& aProtocolVersion,
+ Maybe<OverridableErrorCategory>& aOverridableErrorCategory,
+ Maybe<bool>& aIsEV, uint16_t& aCertificateTransparencyStatus,
+ Maybe<nsCString>& aKeaGroupName, Maybe<nsCString>& aSignatureSchemeName,
+ nsTArray<RefPtr<nsIX509Cert>>& aSucceededCertChain) {
+ bool nsISSLStatusPresent;
+ nsresult rv = aStream->ReadBoolean(&nsISSLStatusPresent);
+ 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);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = aStream->ReadID(&iid);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ static const nsIID nsSSLStatusIID = {
+ 0xfa9ba95b,
+ 0xca3b,
+ 0x498a,
+ {0xb8, 0x89, 0x7c, 0x79, 0xcf, 0x28, 0xfe, 0xe8}};
+ if (!iid.Equals(nsSSLStatusIID)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsCOMPtr<nsISupports> cert;
+ rv = aStream->ReadObject(true, getter_AddRefs(cert));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (cert) {
+ aServerCert = do_QueryInterface(cert);
+ if (!aServerCert) {
+ return NS_NOINTERFACE;
+ }
+ }
+
+ uint16_t cipherSuite;
+ rv = aStream->Read16(&cipherSuite);
+ 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);
+ NS_ENSURE_SUCCESS(rv, rv);
+ const uint8_t streamFormatVersion =
+ (protocolVersionAndStreamFormatVersion >> 8) & 0xFF;
+
+ OverridableErrorCategory overridableErrorCategory;
+ rv = ReadOldOverridableErrorBits(aStream, overridableErrorCategory);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool isEV;
+ rv = aStream->ReadBoolean(&isEV);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool hasIsEVStatus;
+ rv = aStream->ReadBoolean(&hasIsEVStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (hasIsEVStatus) {
+ aIsEV.emplace(isEV);
+ }
+ bool haveCipherSuiteAndProtocol;
+ rv = aStream->ReadBoolean(&haveCipherSuiteAndProtocol);
+ if (haveCipherSuiteAndProtocol) {
+ aCipherSuite.emplace(cipherSuite);
+ aProtocolVersion.emplace(protocolVersionAndStreamFormatVersion & 0xFF);
+ }
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool haveCertErrorBits;
+ rv = aStream->ReadBoolean(&haveCertErrorBits);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (haveCertErrorBits) {
+ aOverridableErrorCategory.emplace(overridableErrorCategory);
+ }
+
+ // Added in version 1 (see bug 1305289).
+ if (streamFormatVersion >= 1) {
+ rv = aStream->Read16(&aCertificateTransparencyStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // Added in version 2 (see bug 1304923).
+ if (streamFormatVersion >= 2) {
+ nsCString keaGroupName;
+ rv = aStream->ReadCString(keaGroupName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (haveCipherSuiteAndProtocol) {
+ aKeaGroupName.emplace(keaGroupName);
+ }
+
+ nsCString signatureSchemeName;
+ rv = aStream->ReadCString(signatureSchemeName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (haveCipherSuiteAndProtocol) {
+ aSignatureSchemeName.emplace(signatureSchemeName);
+ }
+ }
+
+ // Added in version 3 (see bug 1406856).
+ if (streamFormatVersion >= 3) {
+ rv = ReadCertList(aStream, aSucceededCertChain);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // Read only to consume bytes from the stream.
+ nsTArray<RefPtr<nsIX509Cert>> failedCertChain;
+ rv = ReadCertList(aStream, failedCertChain);
+ 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) {
+ bool nsIX509CertListPresent;
+
+ nsresult rv = aStream->ReadBoolean(&nsIX509CertListPresent);
+ 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);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = aStream->ReadID(&iid);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ static const nsIID nsIX509CertListIID = {
+ 0xae74cda5,
+ 0xcd2f,
+ 0x473f,
+ {0x96, 0xf5, 0xf0, 0xb7, 0xff, 0xf6, 0x2c, 0x68}};
+
+ if (!iid.Equals(nsIX509CertListIID)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ uint32_t certListSize;
+ rv = aStream->Read32(&certListSize);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return ReadCertificatesFromStream(aStream, certListSize, aCertList);
+}
+
+nsresult TransportSecurityInfo::ReadCertificatesFromStream(
+ nsIObjectInputStream* aStream, uint32_t aSize,
+ nsTArray<RefPtr<nsIX509Cert>>& aCertList) {
+ nsresult rv;
+ for (uint32_t i = 0; i < aSize; ++i) {
+ nsCOMPtr<nsISupports> support;
+ rv = aStream->ReadObject(true, getter_AddRefs(support));
+ 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;
+}
+
+static nsITransportSecurityInfo::OverridableErrorCategory
+IntToOverridableErrorCategory(uint32_t intVal) {
+ switch (intVal) {
+ case static_cast<uint32_t>(
+ nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST):
+ return nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST;
+ case static_cast<uint32_t>(
+ nsITransportSecurityInfo::OverridableErrorCategory::ERROR_DOMAIN):
+ return nsITransportSecurityInfo::OverridableErrorCategory::ERROR_DOMAIN;
+ case static_cast<uint32_t>(
+ nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME):
+ return nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME;
+ default:
+ break;
+ }
+ return nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET;
+}
+
+nsresult TransportSecurityInfo::Read(const nsCString& aSerializedSecurityInfo,
+ nsITransportSecurityInfo** aResult) {
+ *aResult = nullptr;
+
+ nsCString decodedSecurityInfo;
+ nsresult rv = Base64Decode(aSerializedSecurityInfo, decodedSecurityInfo);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsCOMPtr<nsIInputStream> inputStream;
+ rv = NS_NewCStringInputStream(getter_AddRefs(inputStream),
+ std::move(decodedSecurityInfo));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ nsCOMPtr<nsIObjectInputStream> objStream(
+ NS_NewObjectInputStream(inputStream));
+ if (!objStream) {
+ return rv;
+ }
+
+ nsCID cid;
+ rv = objStream->ReadID(&cid);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (!cid.Equals(kTransportSecurityInfoCID)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ nsIID iid;
+ rv = objStream->ReadID(&iid);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (!iid.Equals(NS_ISUPPORTS_IID)) {
+ return rv;
+ }
+
+ nsID id;
+ rv = objStream->ReadID(&id);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ if (!id.Equals(kTransportSecurityInfoMagic)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ uint32_t aSecurityState = 0;
+ PRErrorCode aErrorCode = 0;
+ nsTArray<RefPtr<nsIX509Cert>> aFailedCertChain;
+ nsCOMPtr<nsIX509Cert> aServerCert;
+ nsTArray<RefPtr<nsIX509Cert>> aSucceededCertChain;
+ Maybe<uint16_t> aCipherSuite;
+ Maybe<nsCString> aKeaGroupName;
+ Maybe<nsCString> aSignatureSchemeName;
+ Maybe<uint16_t> aProtocolVersion;
+ uint16_t aCertificateTransparencyStatus;
+ Maybe<bool> aIsAcceptedEch;
+ Maybe<bool> aIsDelegatedCredential;
+ Maybe<OverridableErrorCategory> aOverridableErrorCategory;
+ bool aMadeOCSPRequests = false;
+ bool aUsedPrivateDNS = false;
+ Maybe<bool> aIsEV;
+ bool aNPNCompleted = false;
+ nsCString aNegotiatedNPN;
+ bool aResumed = false;
+ bool aIsBuiltCertChainRootBuiltInRoot = false;
+ nsCString aPeerId;
+ rv = objStream->Read32(&aSecurityState);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // mSubRequestsBrokenSecurity was removed in bug 748809
+ uint32_t unusedSubRequestsBrokenSecurity;
+ rv = objStream->Read32(&unusedSubRequestsBrokenSecurity);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // mSubRequestsNoSecurity was removed in bug 748809
+ uint32_t unusedSubRequestsNoSecurity;
+ rv = objStream->Read32(&unusedSubRequestsNoSecurity);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ uint32_t errorCode;
+ rv = objStream->Read32(&errorCode);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // PRErrorCode will be a negative value
+ aErrorCode = static_cast<PRErrorCode>(errorCode);
+
+ // Re-purpose mErrorMessageCached to represent serialization version
+ // If string doesn't match exact version it will be treated as older
+ // serialization.
+ nsAutoString serVersion;
+ rv = objStream->ReadString(serVersion);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ int32_t serVersionParsedToInt = 0;
+
+ if (!serVersion.IsEmpty()) {
+ char first = serVersion.First();
+ // Check whether the first character of serVersion is a number
+ // since ToInteger() skipps some non integer values.
+ if (first >= '0' && first <= '9') {
+ nsresult error = NS_OK;
+ serVersionParsedToInt = serVersion.ToInteger(&error);
+ if (NS_FAILED(error)) {
+ return error;
+ }
+ }
+ }
+
+ // moved from nsISSLStatus
+ if (serVersionParsedToInt < 1) {
+ // nsISSLStatus may be present
+ rv = ReadSSLStatus(objStream, aServerCert, aCipherSuite, aProtocolVersion,
+ aOverridableErrorCategory, aIsEV,
+ aCertificateTransparencyStatus, aKeaGroupName,
+ aSignatureSchemeName, aSucceededCertChain);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ nsCOMPtr<nsISupports> cert;
+ rv = NS_ReadOptionalObject(objStream, true, getter_AddRefs(cert));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (cert) {
+ aServerCert = do_QueryInterface(cert);
+ if (!aServerCert) {
+ return NS_NOINTERFACE;
+ }
+ }
+
+ uint16_t cipherSuite;
+ rv = objStream->Read16(&cipherSuite);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint16_t protocolVersion;
+ rv = objStream->Read16(&protocolVersion);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ OverridableErrorCategory overridableErrorCategory;
+ if (serVersionParsedToInt < 8) {
+ rv = ReadOldOverridableErrorBits(objStream, overridableErrorCategory);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ uint32_t overridableErrorCategoryInt;
+ rv = objStream->Read32(&overridableErrorCategoryInt);
+ NS_ENSURE_SUCCESS(rv, rv);
+ overridableErrorCategory =
+ IntToOverridableErrorCategory(overridableErrorCategoryInt);
+ }
+ bool isEV;
+ rv = objStream->ReadBoolean(&isEV);
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool hasIsEVStatus;
+ rv = objStream->ReadBoolean(&hasIsEVStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (hasIsEVStatus) {
+ aIsEV.emplace(isEV);
+ }
+ bool haveCipherSuiteAndProtocol;
+ rv = objStream->ReadBoolean(&haveCipherSuiteAndProtocol);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (haveCipherSuiteAndProtocol) {
+ aCipherSuite.emplace(cipherSuite);
+ aProtocolVersion.emplace(protocolVersion);
+ }
+ bool haveCertErrorBits;
+ rv = objStream->ReadBoolean(&haveCertErrorBits);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (haveCertErrorBits) {
+ aOverridableErrorCategory.emplace(overridableErrorCategory);
+ }
+
+ rv = objStream->Read16(&aCertificateTransparencyStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCString keaGroupName;
+ rv = objStream->ReadCString(keaGroupName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (haveCipherSuiteAndProtocol) {
+ aKeaGroupName.emplace(keaGroupName);
+ }
+
+ nsCString signatureSchemeName;
+ rv = objStream->ReadCString(signatureSchemeName);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (haveCipherSuiteAndProtocol) {
+ aSignatureSchemeName.emplace(signatureSchemeName);
+ }
+
+ if (serVersionParsedToInt < 3) {
+ // The old data structure of certList(nsIX509CertList) presents
+ rv = ReadCertList(objStream, aSucceededCertChain);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ uint16_t certCount;
+ rv = objStream->Read16(&certCount);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv =
+ ReadCertificatesFromStream(objStream, certCount, aSucceededCertChain);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+ // END moved from nsISSLStatus
+ if (serVersionParsedToInt < 3) {
+ // The old data structure of certList(nsIX509CertList) presents
+ rv = ReadCertList(objStream, aFailedCertChain);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else {
+ uint16_t certCount;
+ rv = objStream->Read16(&certCount);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = ReadCertificatesFromStream(objStream, certCount, aFailedCertChain);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ // mIsDelegatedCredential added in bug 1562773
+ if (serVersionParsedToInt >= 2) {
+ bool isDelegatedCredential;
+ rv = objStream->ReadBoolean(&isDelegatedCredential);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // If aCipherSuite is Some, the serialized TransportSecurityinfo had its
+ // cipher suite and protocol information, which means it has this
+ // information.
+ if (aCipherSuite.isSome()) {
+ aIsDelegatedCredential.emplace(isDelegatedCredential);
+ }
+ }
+
+ // mNPNCompleted, mNegotiatedNPN, mResumed added in bug 1584104
+ if (serVersionParsedToInt >= 4) {
+ rv = objStream->ReadBoolean(&aNPNCompleted);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->ReadCString(aNegotiatedNPN);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->ReadBoolean(&aResumed);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ // mIsBuiltCertChainRootBuiltInRoot added in bug 1485652
+ if (serVersionParsedToInt >= 5) {
+ rv = objStream->ReadBoolean(&aIsBuiltCertChainRootBuiltInRoot);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ // mIsAcceptedEch added in bug 1678079
+ if (serVersionParsedToInt >= 6) {
+ bool isAcceptedEch;
+ rv = objStream->ReadBoolean(&isAcceptedEch);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // If aCipherSuite is Some, the serialized TransportSecurityinfo had its
+ // cipher suite and protocol information, which means it has this
+ // information.
+ if (aCipherSuite.isSome()) {
+ aIsAcceptedEch.emplace(isAcceptedEch);
+ }
+ }
+
+ // mPeerId added in bug 1738664
+ if (serVersionParsedToInt >= 7) {
+ rv = objStream->ReadCString(aPeerId);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ if (serVersionParsedToInt >= 9) {
+ rv = objStream->ReadBoolean(&aMadeOCSPRequests);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = objStream->ReadBoolean(&aUsedPrivateDNS);
+ if (NS_FAILED(rv)) {
+ return rv;
+ };
+ }
+
+ RefPtr<nsITransportSecurityInfo> securityInfo(new TransportSecurityInfo(
+ aSecurityState, aErrorCode, std::move(aFailedCertChain), aServerCert,
+ std::move(aSucceededCertChain), aCipherSuite, aKeaGroupName,
+ aSignatureSchemeName, aProtocolVersion, aCertificateTransparencyStatus,
+ aIsAcceptedEch, aIsDelegatedCredential, aOverridableErrorCategory,
+ aMadeOCSPRequests, aUsedPrivateDNS, aIsEV, aNPNCompleted, aNegotiatedNPN,
+ aResumed, aIsBuiltCertChainRootBuiltInRoot, aPeerId));
+ securityInfo.forget(aResult);
+ return NS_OK;
+}
+
+void TransportSecurityInfo::SerializeToIPC(IPC::MessageWriter* aWriter) {
+ WriteParam(aWriter, mSecurityState);
+ WriteParam(aWriter, mErrorCode);
+ WriteParam(aWriter, mFailedCertChain);
+ WriteParam(aWriter, mServerCert);
+ WriteParam(aWriter, mSucceededCertChain);
+ WriteParam(aWriter, mCipherSuite);
+ WriteParam(aWriter, mKeaGroupName);
+ WriteParam(aWriter, mSignatureSchemeName);
+ WriteParam(aWriter, mProtocolVersion);
+ WriteParam(aWriter, mCertificateTransparencyStatus);
+ WriteParam(aWriter, mIsAcceptedEch);
+ WriteParam(aWriter, mIsDelegatedCredential);
+ WriteParam(aWriter, mOverridableErrorCategory);
+ WriteParam(aWriter, mMadeOCSPRequests);
+ WriteParam(aWriter, mUsedPrivateDNS);
+ WriteParam(aWriter, mIsEV);
+ WriteParam(aWriter, mNPNCompleted);
+ WriteParam(aWriter, mNegotiatedNPN);
+ WriteParam(aWriter, mResumed);
+ WriteParam(aWriter, mIsBuiltCertChainRootBuiltInRoot);
+ WriteParam(aWriter, mPeerId);
+}
+
+bool TransportSecurityInfo::DeserializeFromIPC(
+ IPC::MessageReader* aReader, RefPtr<nsITransportSecurityInfo>* aResult) {
+ uint32_t aSecurityState;
+ PRErrorCode aErrorCode;
+ nsTArray<RefPtr<nsIX509Cert>> aFailedCertChain;
+ nsCOMPtr<nsIX509Cert> aServerCert;
+ nsTArray<RefPtr<nsIX509Cert>> aSucceededCertChain;
+ Maybe<uint16_t> aCipherSuite;
+ Maybe<nsCString> aKeaGroupName;
+ Maybe<nsCString> aSignatureSchemeName;
+ Maybe<uint16_t> aProtocolVersion;
+ uint16_t aCertificateTransparencyStatus;
+ Maybe<bool> aIsAcceptedEch;
+ Maybe<bool> aIsDelegatedCredential;
+ Maybe<OverridableErrorCategory> aOverridableErrorCategory;
+ bool aMadeOCSPRequests;
+ bool aUsedPrivateDNS;
+ Maybe<bool> aIsEV;
+ bool aNPNCompleted;
+ nsCString aNegotiatedNPN;
+ bool aResumed;
+ bool aIsBuiltCertChainRootBuiltInRoot;
+ nsCString aPeerId;
+
+ if (!ReadParam(aReader, &aSecurityState) ||
+ !ReadParam(aReader, &aErrorCode) ||
+ !ReadParam(aReader, &aFailedCertChain) ||
+ !ReadParam(aReader, &aServerCert) ||
+ !ReadParam(aReader, &aSucceededCertChain) ||
+ !ReadParam(aReader, &aCipherSuite) ||
+ !ReadParam(aReader, &aKeaGroupName) ||
+ !ReadParam(aReader, &aSignatureSchemeName) ||
+ !ReadParam(aReader, &aProtocolVersion) ||
+ !ReadParam(aReader, &aCertificateTransparencyStatus) ||
+ !ReadParam(aReader, &aIsAcceptedEch) ||
+ !ReadParam(aReader, &aIsDelegatedCredential) ||
+ !ReadParam(aReader, &aOverridableErrorCategory) ||
+ !ReadParam(aReader, &aMadeOCSPRequests) ||
+ !ReadParam(aReader, &aUsedPrivateDNS) || !ReadParam(aReader, &aIsEV) ||
+ !ReadParam(aReader, &aNPNCompleted) ||
+ !ReadParam(aReader, &aNegotiatedNPN) || !ReadParam(aReader, &aResumed) ||
+ !ReadParam(aReader, &aIsBuiltCertChainRootBuiltInRoot) ||
+ !ReadParam(aReader, &aPeerId)) {
+ return false;
+ }
+
+ RefPtr<nsITransportSecurityInfo> securityInfo(new TransportSecurityInfo(
+ aSecurityState, aErrorCode, std::move(aFailedCertChain), aServerCert,
+ std::move(aSucceededCertChain), aCipherSuite, aKeaGroupName,
+ aSignatureSchemeName, aProtocolVersion, aCertificateTransparencyStatus,
+ aIsAcceptedEch, aIsDelegatedCredential, aOverridableErrorCategory,
+ aMadeOCSPRequests, aUsedPrivateDNS, aIsEV, aNPNCompleted, aNegotiatedNPN,
+ aResumed, aIsBuiltCertChainRootBuiltInRoot, aPeerId));
+ *aResult = std::move(securityInfo);
+ return true;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetFailedCertChain(
+ nsTArray<RefPtr<nsIX509Cert>>& aFailedCertChain) {
+ MOZ_ASSERT(aFailedCertChain.IsEmpty());
+ if (!aFailedCertChain.IsEmpty()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ aFailedCertChain.AppendElements(mFailedCertChain);
+ return NS_OK;
+}
+
+NS_IMETHODIMP TransportSecurityInfo::GetServerCert(nsIX509Cert** aServerCert) {
+ NS_ENSURE_ARG_POINTER(aServerCert);
+ nsCOMPtr<nsIX509Cert> cert = mServerCert;
+ cert.forget(aServerCert);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetSucceededCertChain(
+ nsTArray<RefPtr<nsIX509Cert>>& aSucceededCertChain) {
+ MOZ_ASSERT(aSucceededCertChain.IsEmpty());
+ if (!aSucceededCertChain.IsEmpty()) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ aSucceededCertChain.AppendElements(mSucceededCertChain);
+ 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) {
+ if (mCipherSuite.isNothing()) {
+ 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);
+
+ if (mCipherSuite.isNothing()) {
+ 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);
+
+ if (mCipherSuite.isNothing()) {
+ 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& aKeaGroupName) {
+ if (mKeaGroupName.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ aKeaGroupName.Assign(*mKeaGroupName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetSignatureSchemeName(nsACString& aSignatureScheme) {
+ if (mSignatureSchemeName.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ aSignatureScheme.Assign(*mSignatureSchemeName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetProtocolVersion(uint16_t* aProtocolVersion) {
+ if (mProtocolVersion.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ *aProtocolVersion = *mProtocolVersion;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetCertificateTransparencyStatus(
+ uint16_t* aCertificateTransparencyStatus) {
+ NS_ENSURE_ARG_POINTER(aCertificateTransparencyStatus);
+
+ *aCertificateTransparencyStatus = mCertificateTransparencyStatus;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetMadeOCSPRequests(bool* aMadeOCSPRequests) {
+ *aMadeOCSPRequests = mMadeOCSPRequests;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetUsedPrivateDNS(bool* aUsedPrivateDNS) {
+ *aUsedPrivateDNS = mUsedPrivateDNS;
+ 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;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetOverridableErrorCategory(
+ OverridableErrorCategory* aOverridableErrorCategory) {
+ NS_ENSURE_ARG_POINTER(aOverridableErrorCategory);
+
+ if (mOverridableErrorCategory.isSome()) {
+ *aOverridableErrorCategory = *mOverridableErrorCategory;
+ } else {
+ *aOverridableErrorCategory = OverridableErrorCategory::ERROR_UNSET;
+ }
+ 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 (mOverridableErrorCategory.isSome()) {
+ return NS_OK;
+ }
+
+ if (!mIsEV.isSome()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ *aIsEV = *mIsEV;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetIsAcceptedEch(bool* aIsAcceptedEch) {
+ NS_ENSURE_ARG_POINTER(aIsAcceptedEch);
+
+ if (mIsAcceptedEch.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ *aIsAcceptedEch = *mIsAcceptedEch;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetIsDelegatedCredential(bool* aIsDelegatedCredential) {
+ NS_ENSURE_ARG_POINTER(aIsDelegatedCredential);
+
+ if (mIsDelegatedCredential.isNothing()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ *aIsDelegatedCredential = *mIsDelegatedCredential;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN) {
+ if (!mNPNCompleted) {
+ return NS_ERROR_NOT_CONNECTED;
+ }
+
+ aNegotiatedNPN = mNegotiatedNPN;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetResumed(bool* aResumed) {
+ NS_ENSURE_ARG_POINTER(aResumed);
+ *aResumed = mResumed;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+TransportSecurityInfo::GetPeerId(nsACString& aResult) {
+ aResult.Assign(mPeerId);
+ return NS_OK;
+}
+
+} // namespace psm
+} // namespace mozilla