summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/nsSSLStatus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/manager/ssl/nsSSLStatus.cpp')
-rw-r--r--security/manager/ssl/nsSSLStatus.cpp379
1 files changed, 379 insertions, 0 deletions
diff --git a/security/manager/ssl/nsSSLStatus.cpp b/security/manager/ssl/nsSSLStatus.cpp
new file mode 100644
index 000000000..1538b2aa7
--- /dev/null
+++ b/security/manager/ssl/nsSSLStatus.cpp
@@ -0,0 +1,379 @@
+/* -*- 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 "mozilla/Casting.h"
+#include "nsSSLStatus.h"
+#include "nsIClassInfoImpl.h"
+#include "nsIObjectOutputStream.h"
+#include "nsIObjectInputStream.h"
+#include "nsNSSCertificate.h"
+#include "SignedCertificateTimestamp.h"
+#include "ssl.h"
+
+NS_IMETHODIMP
+nsSSLStatus::GetServerCert(nsIX509Cert** aServerCert)
+{
+ NS_ENSURE_ARG_POINTER(aServerCert);
+
+ nsCOMPtr<nsIX509Cert> cert = mServerCert;
+ cert.forget(aServerCert);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetKeyLength(uint32_t* aKeyLength)
+{
+ NS_ENSURE_ARG_POINTER(aKeyLength);
+ 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
+nsSSLStatus::GetSecretKeyLength(uint32_t* aSecretKeyLength)
+{
+ NS_ENSURE_ARG_POINTER(aSecretKeyLength);
+ 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
+nsSSLStatus::GetCipherName(nsACString& aCipherName)
+{
+ 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
+nsSSLStatus::GetProtocolVersion(uint16_t* aProtocolVersion)
+{
+ NS_ENSURE_ARG_POINTER(aProtocolVersion);
+ if (!mHaveCipherSuiteAndProtocol) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ *aProtocolVersion = mProtocolVersion;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetCertificateTransparencyStatus(
+ uint16_t* aCertificateTransparencyStatus)
+{
+ NS_ENSURE_ARG_POINTER(aCertificateTransparencyStatus);
+
+ *aCertificateTransparencyStatus = mCertificateTransparencyStatus;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetIsDomainMismatch(bool* aIsDomainMismatch)
+{
+ NS_ENSURE_ARG_POINTER(aIsDomainMismatch);
+
+ *aIsDomainMismatch = mHaveCertErrorBits && mIsDomainMismatch;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetIsNotValidAtThisTime(bool* aIsNotValidAtThisTime)
+{
+ NS_ENSURE_ARG_POINTER(aIsNotValidAtThisTime);
+
+ *aIsNotValidAtThisTime = mHaveCertErrorBits && mIsNotValidAtThisTime;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetIsUntrusted(bool* aIsUntrusted)
+{
+ NS_ENSURE_ARG_POINTER(aIsUntrusted);
+
+ *aIsUntrusted = mHaveCertErrorBits && mIsUntrusted;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::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
+nsSSLStatus::Read(nsIObjectInputStream* aStream)
+{
+ nsCOMPtr<nsISupports> cert;
+ nsresult rv = aStream->ReadObject(true, getter_AddRefs(cert));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mServerCert = do_QueryInterface(cert);
+ if (!mServerCert) {
+ return NS_NOINTERFACE;
+ }
+
+ rv = aStream->Read16(&mCipherSuite);
+ 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);
+ mProtocolVersion = protocolVersionAndStreamFormatVersion & 0xFF;
+ const uint8_t streamFormatVersion =
+ (protocolVersionAndStreamFormatVersion >> 8) & 0xFF;
+
+ rv = aStream->ReadBoolean(&mIsDomainMismatch);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = aStream->ReadBoolean(&mIsNotValidAtThisTime);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = aStream->ReadBoolean(&mIsUntrusted);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = aStream->ReadBoolean(&mIsEV);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aStream->ReadBoolean(&mHasIsEVStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = aStream->ReadBoolean(&mHaveCipherSuiteAndProtocol);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = aStream->ReadBoolean(&mHaveCertErrorBits);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Added in version 1 (see bug 1305289).
+ if (streamFormatVersion >= 1) {
+ rv = aStream->Read16(&mCertificateTransparencyStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::Write(nsIObjectOutputStream* aStream)
+{
+ // The current version of the binary stream format.
+ const uint8_t STREAM_FORMAT_VERSION = 1;
+
+ nsresult rv = aStream->WriteCompoundObject(mServerCert,
+ NS_GET_IID(nsIX509Cert),
+ true);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = aStream->Write16(mCipherSuite);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uint16_t protocolVersionAndStreamFormatVersion =
+ mozilla::AssertedCast<uint8_t>(mProtocolVersion) |
+ (STREAM_FORMAT_VERSION << 8);
+ rv = aStream->Write16(protocolVersionAndStreamFormatVersion);
+ 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);
+
+ // Added in version 1.
+ rv = aStream->Write16(mCertificateTransparencyStatus);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetInterfaces(uint32_t* aCount, nsIID*** aArray)
+{
+ *aCount = 0;
+ *aArray = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetScriptableHelper(nsIXPCScriptable** aHelper)
+{
+ *aHelper = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetContractID(char** aContractID)
+{
+ *aContractID = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetClassDescription(char** aClassDescription)
+{
+ *aClassDescription = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetClassID(nsCID** aClassID)
+{
+ *aClassID = (nsCID*) moz_xmalloc(sizeof(nsCID));
+ if (!*aClassID) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ return GetClassIDNoAlloc(*aClassID);
+}
+
+NS_IMETHODIMP
+nsSSLStatus::GetFlags(uint32_t* aFlags)
+{
+ *aFlags = 0;
+ return NS_OK;
+}
+
+static NS_DEFINE_CID(kSSLStatusCID, NS_SSLSTATUS_CID);
+
+NS_IMETHODIMP
+nsSSLStatus::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc)
+{
+ *aClassIDNoAlloc = kSSLStatusCID;
+ return NS_OK;
+}
+
+nsSSLStatus::nsSSLStatus()
+: mCipherSuite(0)
+, mProtocolVersion(0)
+, mCertificateTransparencyStatus(nsISSLStatus::
+ CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE)
+, mIsDomainMismatch(false)
+, mIsNotValidAtThisTime(false)
+, mIsUntrusted(false)
+, mIsEV(false)
+, mHasIsEVStatus(false)
+, mHaveCipherSuiteAndProtocol(false)
+, mHaveCertErrorBits(false)
+{
+}
+
+NS_IMPL_ISUPPORTS(nsSSLStatus, nsISSLStatus, nsISerializable, nsIClassInfo)
+
+nsSSLStatus::~nsSSLStatus()
+{
+}
+
+void
+nsSSLStatus::SetServerCert(nsNSSCertificate* aServerCert, EVStatus aEVStatus)
+{
+ MOZ_ASSERT(aServerCert);
+
+ mServerCert = aServerCert;
+ mIsEV = (aEVStatus == EVStatus::EV);
+ mHasIsEVStatus = true;
+}
+
+void
+nsSSLStatus::SetCertificateTransparencyInfo(
+ const mozilla::psm::CertificateTransparencyInfo& info)
+{
+ using mozilla::ct::SignedCertificateTimestamp;
+
+ if (!info.enabled) {
+ // CT disabled.
+ mCertificateTransparencyStatus =
+ nsISSLStatus::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE;
+ return;
+ }
+
+ if (!info.processedSCTs) {
+ // No SCTs processed on the connection.
+ mCertificateTransparencyStatus =
+ nsISSLStatus::CERTIFICATE_TRANSPARENCY_NONE;
+ return;
+ }
+
+ bool hasOKSCTs = false;
+ bool hasUnknownLogSCTs = false;
+ bool hasInvalidSCTs = false;
+ for (const SignedCertificateTimestamp& sct : info.verifyResult.scts) {
+ switch (sct.verificationStatus) {
+ case SignedCertificateTimestamp::VerificationStatus::OK:
+ hasOKSCTs = true;
+ break;
+ case SignedCertificateTimestamp::VerificationStatus::UnknownLog:
+ hasUnknownLogSCTs = true;
+ break;
+ case SignedCertificateTimestamp::VerificationStatus::InvalidSignature:
+ case SignedCertificateTimestamp::VerificationStatus::InvalidTimestamp:
+ hasInvalidSCTs = true;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unexpected SCT::VerificationStatus type");
+ }
+ }
+
+ if (hasOKSCTs) {
+ mCertificateTransparencyStatus =
+ nsISSLStatus::CERTIFICATE_TRANSPARENCY_OK;
+ } else if (hasUnknownLogSCTs) {
+ mCertificateTransparencyStatus =
+ nsISSLStatus::CERTIFICATE_TRANSPARENCY_UNKNOWN_LOG;
+ } else if (hasInvalidSCTs) {
+ mCertificateTransparencyStatus =
+ nsISSLStatus::CERTIFICATE_TRANSPARENCY_INVALID;
+ }
+}