summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/nsNSSIOLayer.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /security/manager/ssl/nsNSSIOLayer.h
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/manager/ssl/nsNSSIOLayer.h')
-rw-r--r--security/manager/ssl/nsNSSIOLayer.h359
1 files changed, 359 insertions, 0 deletions
diff --git a/security/manager/ssl/nsNSSIOLayer.h b/security/manager/ssl/nsNSSIOLayer.h
new file mode 100644
index 0000000000..beb0a67340
--- /dev/null
+++ b/security/manager/ssl/nsNSSIOLayer.h
@@ -0,0 +1,359 @@
+/* -*- 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/. */
+
+#ifndef nsNSSIOLayer_h
+#define nsNSSIOLayer_h
+
+#include "CommonSocketControl.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/UniquePtr.h"
+#include "nsCOMPtr.h"
+#include "nsDataHashtable.h"
+#include "nsIProxyInfo.h"
+#include "nsISSLSocketControl.h"
+#include "nsNSSCertificate.h"
+#include "nsTHashtable.h"
+#include "sslt.h"
+
+namespace mozilla {
+class OriginAttributes;
+namespace psm {
+class SharedSSLState;
+} // namespace psm
+} // namespace mozilla
+
+using mozilla::OriginAttributes;
+
+class nsIObserver;
+
+class nsNSSSocketInfo final : public CommonSocketControl {
+ public:
+ nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags,
+ uint32_t providerTlsFlags);
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+ void SetForSTARTTLS(bool aForSTARTTLS);
+ bool GetForSTARTTLS();
+
+ nsresult GetFileDescPtr(PRFileDesc** aFilePtr);
+ nsresult SetFileDescPtr(PRFileDesc* aFilePtr);
+
+ bool IsHandshakePending() const { return mHandshakePending; }
+ void SetHandshakeNotPending() { mHandshakePending = false; }
+
+ void SetTLSVersionRange(SSLVersionRange range) { mTLSVersionRange = range; }
+ SSLVersionRange GetTLSVersionRange() const { return mTLSVersionRange; };
+
+ // From nsISSLSocketControl.
+ NS_IMETHOD ProxyStartSSL(void) override;
+ NS_IMETHOD StartTLS(void) override;
+ NS_IMETHOD SetNPNList(nsTArray<nsCString>& aNPNList) override;
+ NS_IMETHOD GetAlpnEarlySelection(nsACString& _retval) override;
+ NS_IMETHOD GetEarlyDataAccepted(bool* aEarlyDataAccepted) override;
+ NS_IMETHOD DriveHandshake(void) override;
+ using nsISSLSocketControl::GetKEAUsed;
+ NS_IMETHOD GetKEAUsed(int16_t* aKEAUsed) override;
+ NS_IMETHOD GetKEAKeyBits(uint32_t* aKEAKeyBits) override;
+ NS_IMETHOD GetProviderTlsFlags(uint32_t* aProviderTlsFlags) override;
+ NS_IMETHOD GetSSLVersionOffered(int16_t* aSSLVersionOffered) override;
+ NS_IMETHOD GetMACAlgorithmUsed(int16_t* aMACAlgorithmUsed) override;
+ bool GetDenyClientCert() override;
+ void SetDenyClientCert(bool aDenyClientCert) override;
+ NS_IMETHOD GetClientCert(nsIX509Cert** aClientCert) override;
+ NS_IMETHOD SetClientCert(nsIX509Cert* aClientCert) override;
+ NS_IMETHOD GetEsniTxt(nsACString& aEsniTxt) override;
+ NS_IMETHOD SetEsniTxt(const nsACString& aEsniTxt) override;
+ NS_IMETHOD GetEchConfig(nsACString& aEchConfig) override;
+ NS_IMETHOD SetEchConfig(const nsACString& aEchConfig) override;
+ NS_IMETHOD GetPeerId(nsACString& aResult) override;
+ NS_IMETHOD GetRetryEchConfig(nsACString& aEchConfig) override;
+
+ PRStatus CloseSocketAndDestroy();
+
+ void SetNegotiatedNPN(const char* value, uint32_t length);
+ void SetEarlyDataAccepted(bool aAccepted);
+
+ void SetHandshakeCompleted();
+ bool IsHandshakeCompleted() const { return mHandshakeCompleted; }
+ void NoteTimeUntilReady();
+
+ void SetFalseStartCallbackCalled() { mFalseStartCallbackCalled = true; }
+ void SetFalseStarted() { mFalseStarted = true; }
+
+ // Note that this is only valid *during* a handshake; at the end of the
+ // handshake, it gets reset back to false.
+ void SetFullHandshake() { mIsFullHandshake = true; }
+ bool IsFullHandshake() const { return mIsFullHandshake; }
+
+ bool GetJoined() { return mJoined; }
+ void SetSentClientCert() { mSentClientCert = true; }
+
+ uint32_t GetProviderTlsFlags() const { return mProviderTlsFlags; }
+
+ mozilla::psm::SharedSSLState& SharedState();
+
+ // XXX: These are only used on for diagnostic purposes
+ enum CertVerificationState {
+ before_cert_verification,
+ waiting_for_cert_verification,
+ after_cert_verification
+ };
+ void SetCertVerificationWaiting();
+ // Use errorCode == 0 to indicate success;
+ void SetCertVerificationResult(PRErrorCode errorCode) override;
+
+ // for logging only
+ PRBool IsWaitingForCertVerification() const {
+ return mCertVerificationState == waiting_for_cert_verification;
+ }
+ void AddPlaintextBytesRead(uint64_t val) { mPlaintextBytesRead += val; }
+
+ bool IsPreliminaryHandshakeDone() const { return mPreliminaryHandshakeDone; }
+ void SetPreliminaryHandshakeDone() { mPreliminaryHandshakeDone = true; }
+
+ void SetKEAUsed(uint16_t kea) { mKEAUsed = kea; }
+
+ void SetKEAKeyBits(uint32_t keaBits) { mKEAKeyBits = keaBits; }
+
+ void SetMACAlgorithmUsed(int16_t mac) { mMACAlgorithmUsed = mac; }
+
+ void SetShortWritePending(int32_t amount, unsigned char data) {
+ mIsShortWritePending = true;
+ mShortWriteOriginalAmount = amount;
+ mShortWritePendingByte = data;
+ }
+
+ bool IsShortWritePending() { return mIsShortWritePending; }
+
+ unsigned char const* GetShortWritePendingByteRef() {
+ return &mShortWritePendingByte;
+ }
+
+ int32_t ResetShortWritePending() {
+ mIsShortWritePending = false;
+ return mShortWriteOriginalAmount;
+ }
+
+#ifdef DEBUG
+ // These helpers assert that the caller does try to send the same data
+ // as it was previously when we hit the short-write. This is a measure
+ // to make sure we communicate correctly to the consumer.
+ void RememberShortWrittenBuffer(const unsigned char* data) {
+ mShortWriteBufferCheck =
+ mozilla::MakeUnique<char[]>(mShortWriteOriginalAmount);
+ memcpy(mShortWriteBufferCheck.get(), data, mShortWriteOriginalAmount);
+ }
+ void CheckShortWrittenBuffer(const unsigned char* data, int32_t amount) {
+ if (!mShortWriteBufferCheck) return;
+ MOZ_ASSERT(amount >= mShortWriteOriginalAmount,
+ "unexpected amount length after short write");
+ MOZ_ASSERT(
+ !memcmp(mShortWriteBufferCheck.get(), data, mShortWriteOriginalAmount),
+ "unexpected buffer content after short write");
+ mShortWriteBufferCheck = nullptr;
+ }
+#endif
+
+ void SetSharedOwningReference(mozilla::psm::SharedSSLState* ref);
+
+ nsresult SetResumptionTokenFromExternalCache();
+
+ void SetClientCertChain(mozilla::UniqueCERTCertList&& clientCertChain) {
+ mClientCertChain = std::move(clientCertChain);
+ }
+
+ protected:
+ virtual ~nsNSSSocketInfo();
+
+ private:
+ PRFileDesc* mFd;
+
+ CertVerificationState mCertVerificationState;
+
+ mozilla::psm::SharedSSLState& mSharedState;
+ bool mForSTARTTLS;
+ SSLVersionRange mTLSVersionRange;
+ bool mHandshakePending;
+ bool mPreliminaryHandshakeDone; // after false start items are complete
+
+ nsresult ActivateSSL();
+
+ nsCString mEsniTxt;
+ nsCString mEchConfig;
+ nsCString mPeerId;
+ bool mEarlyDataAccepted;
+ bool mDenyClientCert;
+ bool mFalseStartCallbackCalled;
+ bool mFalseStarted;
+ bool mIsFullHandshake;
+ bool mNotedTimeUntilReady;
+
+ // True when SSL layer has indicated an "SSL short write", i.e. need
+ // to call on send one or more times to push all pending data to write.
+ bool mIsShortWritePending;
+
+ // These are only valid if mIsShortWritePending is true.
+ //
+ // Value of the last byte pending from the SSL short write that needs
+ // to be passed to subsequent calls to send to perform the flush.
+ unsigned char mShortWritePendingByte;
+
+ // Original amount of data the upper layer has requested to write to
+ // return after the successful flush.
+ int32_t mShortWriteOriginalAmount;
+
+#ifdef DEBUG
+ mozilla::UniquePtr<char[]> mShortWriteBufferCheck;
+#endif
+
+ // mKEA* are used in false start and http/2 detetermination
+ // Values are from nsISSLSocketControl
+ int16_t mKEAUsed;
+ uint32_t mKEAKeyBits;
+ int16_t mMACAlgorithmUsed;
+
+ uint32_t mProviderTlsFlags;
+ mozilla::TimeStamp mSocketCreationTimestamp;
+ uint64_t mPlaintextBytesRead;
+
+ nsCOMPtr<nsIX509Cert> mClientCert;
+ // Regarding the client certificate message in the TLS handshake, RFC 5246
+ // (TLS 1.2) says:
+ // If the certificate_authorities list in the certificate request
+ // message was non-empty, one of the certificates in the certificate
+ // chain SHOULD be issued by one of the listed CAs.
+ // (RFC 8446 (TLS 1.3) has a similar provision)
+ // These certificates may be known to gecko but not NSS (e.g. enterprise
+ // intermediates). In order to make these certificates discoverable to NSS
+ // so it can include them in the message, we cache them here as temporary
+ // certificates.
+ mozilla::UniqueCERTCertList mClientCertChain;
+
+ // if non-null this is a reference to the mSharedState (which is
+ // not an owning reference). If this is used, the info has a private
+ // state that does not share things like intolerance lists with the
+ // rest of the session. This is normally used when you have per
+ // socket tls flags overriding session wide defaults.
+ RefPtr<mozilla::psm::SharedSSLState> mOwningSharedRef;
+};
+
+// This class is used to store the needed information for invoking the client
+// cert selection UI.
+class ClientAuthInfo final {
+ public:
+ explicit ClientAuthInfo(const nsACString& hostName,
+ const OriginAttributes& originAttributes,
+ int32_t port, uint32_t providerFlags,
+ uint32_t providerTlsFlags, nsIX509Cert* clientCert);
+ ~ClientAuthInfo() = default;
+ ClientAuthInfo(ClientAuthInfo&& aOther) noexcept;
+
+ const nsACString& HostName() const;
+ const OriginAttributes& OriginAttributesRef() const;
+ int32_t Port() const;
+ already_AddRefed<nsIX509Cert> GetClientCert() const;
+ uint32_t ProviderFlags() const;
+ uint32_t ProviderTlsFlags() const;
+
+ private:
+ ClientAuthInfo(const ClientAuthInfo&) = delete;
+ void operator=(const ClientAuthInfo&) = delete;
+
+ nsCString mHostName;
+ OriginAttributes mOriginAttributes;
+ int32_t mPort;
+ uint32_t mProviderFlags;
+ uint32_t mProviderTlsFlags;
+ nsCOMPtr<nsIX509Cert> mClientCert;
+};
+
+class nsSSLIOLayerHelpers {
+ public:
+ explicit nsSSLIOLayerHelpers(uint32_t aTlsFlags = 0);
+ ~nsSSLIOLayerHelpers();
+
+ nsresult Init();
+ void Cleanup();
+
+ static bool nsSSLIOLayerInitialized;
+ static PRDescIdentity nsSSLIOLayerIdentity;
+ static PRDescIdentity nsSSLPlaintextLayerIdentity;
+ static PRIOMethods nsSSLIOLayerMethods;
+ static PRIOMethods nsSSLPlaintextLayerMethods;
+
+ bool mTreatUnsafeNegotiationAsBroken;
+
+ void setTreatUnsafeNegotiationAsBroken(bool broken);
+ bool treatUnsafeNegotiationAsBroken();
+
+ private:
+ struct IntoleranceEntry {
+ uint16_t tolerant;
+ uint16_t intolerant;
+ PRErrorCode intoleranceReason;
+
+ void AssertInvariant() const {
+ MOZ_ASSERT(intolerant == 0 || tolerant < intolerant);
+ }
+ };
+ nsDataHashtable<nsCStringHashKey, IntoleranceEntry> mTLSIntoleranceInfo;
+ // Sites that require insecure fallback to TLS 1.0, set by the pref
+ // security.tls.insecure_fallback_hosts, which is a comma-delimited
+ // list of domain names.
+ nsTHashtable<nsCStringHashKey> mInsecureFallbackSites;
+
+ public:
+ void rememberTolerantAtVersion(const nsACString& hostname, int16_t port,
+ uint16_t tolerant);
+ bool fallbackLimitReached(const nsACString& hostname, uint16_t intolerant);
+ bool rememberIntolerantAtVersion(const nsACString& hostname, int16_t port,
+ uint16_t intolerant, uint16_t minVersion,
+ PRErrorCode intoleranceReason);
+ void forgetIntolerance(const nsACString& hostname, int16_t port);
+ void adjustForTLSIntolerance(const nsACString& hostname, int16_t port,
+ /*in/out*/ SSLVersionRange& range);
+ PRErrorCode getIntoleranceReason(const nsACString& hostname, int16_t port);
+
+ void clearStoredData();
+ void loadVersionFallbackLimit();
+ void setInsecureFallbackSites(const nsCString& str);
+ void initInsecureFallbackSites();
+ bool isPublic() const;
+ void removeInsecureFallbackSite(const nsACString& hostname, uint16_t port);
+ bool isInsecureFallbackSite(const nsACString& hostname);
+
+ uint16_t mVersionFallbackLimit;
+
+ private:
+ mozilla::Mutex mutex;
+ nsCOMPtr<nsIObserver> mPrefObserver;
+ uint32_t mTlsFlags;
+};
+
+nsresult nsSSLIOLayerNewSocket(int32_t family, const char* host, int32_t port,
+ nsIProxyInfo* proxy,
+ const OriginAttributes& originAttributes,
+ PRFileDesc** fd, nsISupports** securityInfo,
+ bool forSTARTTLS, uint32_t flags,
+ uint32_t tlsFlags);
+
+nsresult nsSSLIOLayerAddToSocket(int32_t family, const char* host, int32_t port,
+ nsIProxyInfo* proxy,
+ const OriginAttributes& originAttributes,
+ PRFileDesc* fd, nsISupports** securityInfo,
+ bool forSTARTTLS, uint32_t flags,
+ uint32_t tlsFlags);
+
+SECStatus DoGetClientAuthData(ClientAuthInfo&& info,
+ const mozilla::UniqueCERTCertificate& serverCert,
+ nsTArray<nsTArray<uint8_t>>&& collectedCANames,
+ mozilla::UniqueCERTCertificate& outCert,
+ mozilla::UniqueSECKEYPrivateKey& outKey,
+ mozilla::UniqueCERTCertList& outBuiltChain);
+
+#endif // nsNSSIOLayer_h