/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=2 ts=8 et tw=80 : */ /* 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 "VerifySSLServerCertParent.h" #include "cert.h" #include "nsNSSComponent.h" #include "secerr.h" #include "SharedCertVerifier.h" #include "NSSCertDBTrustDomain.h" #include "SSLServerCertVerification.h" #include "nsNSSIOLayer.h" #include "nsISocketProvider.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/Unused.h" extern mozilla::LazyLogModule gPIPNSSLog; using mozilla::ipc::AssertIsOnBackgroundThread; using mozilla::ipc::IsOnBackgroundThread; using namespace mozilla::pkix; namespace mozilla { namespace psm { VerifySSLServerCertParent::VerifySSLServerCertParent() {} void VerifySSLServerCertParent::OnVerifiedSSLServerCert( const nsTArray& aBuiltCertChain, uint16_t aCertificateTransparencyStatus, uint8_t aEVStatus, bool aSucceeded, PRErrorCode aFinalError, uint32_t aOverridableErrorCategory, bool aIsBuiltCertChainRootBuiltInRoot, bool aMadeOCSPRequests) { AssertIsOnBackgroundThread(); if (!CanSend()) { return; } if (aSucceeded) { Unused << SendOnVerifiedSSLServerCertSuccess( aBuiltCertChain, aCertificateTransparencyStatus, aEVStatus, aIsBuiltCertChainRootBuiltInRoot, aMadeOCSPRequests); } else { Unused << SendOnVerifiedSSLServerCertFailure( aFinalError, aOverridableErrorCategory, aMadeOCSPRequests); } Unused << Send__delete__(this); } namespace { class IPCServerCertVerificationResult final : public BaseSSLServerCertVerificationResult { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IPCServerCertVerificationResult, override) IPCServerCertVerificationResult(nsIEventTarget* aTarget, VerifySSLServerCertParent* aParent) : mTarget(aTarget), mParent(aParent) {} void Dispatch(nsTArray>&& aBuiltChain, nsTArray>&& aPeerCertChain, uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus, bool aSucceeded, PRErrorCode aFinalError, nsITransportSecurityInfo::OverridableErrorCategory aOverridableErrorCategory, bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags, bool aMadeOCSPRequests) override; private: ~IPCServerCertVerificationResult() = default; nsCOMPtr mTarget; RefPtr mParent; }; void IPCServerCertVerificationResult::Dispatch( nsTArray>&& aBuiltChain, nsTArray>&& aPeerCertChain, uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus, bool aSucceeded, PRErrorCode aFinalError, nsITransportSecurityInfo::OverridableErrorCategory aOverridableErrorCategory, bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags, bool aMadeOCSPRequests) { nsTArray builtCertChain; if (aSucceeded) { for (auto& cert : aBuiltChain) { builtCertChain.AppendElement(ByteArray(cert)); } } nsresult nrv = mTarget->Dispatch( NS_NewRunnableFunction( "psm::VerifySSLServerCertParent::OnVerifiedSSLServerCert", [parent(mParent), builtCertChain{std::move(builtCertChain)}, aCertificateTransparencyStatus, aEVStatus, aSucceeded, aFinalError, aOverridableErrorCategory, aIsBuiltCertChainRootBuiltInRoot, aMadeOCSPRequests, aProviderFlags]() { if (aSucceeded && !(aProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE)) { nsTArray> certBytesArray; for (const auto& cert : builtCertChain) { certBytesArray.AppendElement(cert.data().Clone()); } // This dispatches an event that will run when the socket thread // is idle. SaveIntermediateCerts(certBytesArray); } parent->OnVerifiedSSLServerCert( builtCertChain, aCertificateTransparencyStatus, static_cast(aEVStatus), aSucceeded, aFinalError, static_cast(aOverridableErrorCategory), aIsBuiltCertChainRootBuiltInRoot, aMadeOCSPRequests); }), NS_DISPATCH_NORMAL); MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(nrv)); Unused << nrv; } } // anonymous namespace bool VerifySSLServerCertParent::Dispatch( nsTArray&& aPeerCertChain, const nsACString& aHostName, const int32_t& aPort, const OriginAttributes& aOriginAttributes, const Maybe& aStapledOCSPResponse, const Maybe& aSctsFromTLSExtension, const Maybe& aDcInfo, const uint32_t& aProviderFlags, const uint32_t& aCertVerifierFlags) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("VerifySSLServerCertParent::Dispatch")); AssertIsOnBackgroundThread(); mBackgroundThread = NS_GetCurrentThread(); nsTArray> peerCertBytes; for (auto& certBytes : aPeerCertChain) { nsTArray bytes; peerCertBytes.AppendElement(std::move(certBytes.data())); } Maybe> stapledOCSPResponse; if (aStapledOCSPResponse) { stapledOCSPResponse.emplace(aStapledOCSPResponse->data().Clone()); } Maybe> sctsFromTLSExtension; if (aSctsFromTLSExtension) { sctsFromTLSExtension.emplace(aSctsFromTLSExtension->data().Clone()); } Maybe dcInfo; if (aDcInfo) { dcInfo.emplace(); dcInfo->scheme = static_cast(aDcInfo->scheme()); dcInfo->authKeyBits = aDcInfo->authKeyBits(); } RefPtr resultTask = new IPCServerCertVerificationResult(mBackgroundThread, this); SECStatus status = SSLServerCertVerificationJob::Dispatch( 0, nullptr, std::move(peerCertBytes), aHostName, aPort, aOriginAttributes, stapledOCSPResponse, sctsFromTLSExtension, dcInfo, aProviderFlags, Now(), aCertVerifierFlags, resultTask); if (status != SECWouldBlock) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("VerifySSLServerCertParent::Dispatch - dispatch failed")); return false; } return true; } void VerifySSLServerCertParent::ActorDestroy(ActorDestroyReason aWhy) {} VerifySSLServerCertParent::~VerifySSLServerCertParent() = default; } // namespace psm } // namespace mozilla