1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef nsNSSIOLayer_h
8 #define nsNSSIOLayer_h
9 
10 #include "TransportSecurityInfo.h"
11 #include "mozilla/TimeStamp.h"
12 #include "nsCOMPtr.h"
13 #include "nsDataHashtable.h"
14 #include "nsIClientAuthDialogs.h"
15 #include "nsIProxyInfo.h"
16 #include "nsISSLSocketControl.h"
17 #include "nsNSSCertificate.h"
18 #include "nsTHashtable.h"
19 #include "sslt.h"
20 
21 namespace mozilla {
22 class NeckoOriginAttributes;
23 namespace psm {
24 class SharedSSLState;
25 } // namespace psm
26 } // namespace mozilla
27 
28 using mozilla::NeckoOriginAttributes;
29 
30 class nsIObserver;
31 
32 class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo,
33                               public nsISSLSocketControl,
34                               public nsIClientAuthUserDecision
35 {
36 public:
37   nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags);
38 
39   NS_DECL_ISUPPORTS_INHERITED
40   NS_DECL_NSISSLSOCKETCONTROL
41   NS_DECL_NSICLIENTAUTHUSERDECISION
42 
43   void SetForSTARTTLS(bool aForSTARTTLS);
44   bool GetForSTARTTLS();
45 
46   nsresult GetFileDescPtr(PRFileDesc** aFilePtr);
47   nsresult SetFileDescPtr(PRFileDesc* aFilePtr);
48 
IsHandshakePending()49   bool IsHandshakePending() const { return mHandshakePending; }
SetHandshakeNotPending()50   void SetHandshakeNotPending() { mHandshakePending = false; }
51 
SetTLSVersionRange(SSLVersionRange range)52   void SetTLSVersionRange(SSLVersionRange range) { mTLSVersionRange = range; }
GetTLSVersionRange()53   SSLVersionRange GetTLSVersionRange() const { return mTLSVersionRange; };
54 
55   PRStatus CloseSocketAndDestroy(
56                 const nsNSSShutDownPreventionLock& proofOfLock);
57 
58   void SetNegotiatedNPN(const char* value, uint32_t length);
59   void SetEarlyDataAccepted(bool aAccepted);
60 
61   void SetHandshakeCompleted();
62   void NoteTimeUntilReady();
63 
64 
SetFalseStartCallbackCalled()65   void SetFalseStartCallbackCalled() { mFalseStartCallbackCalled = true; }
SetFalseStarted()66   void SetFalseStarted() { mFalseStarted = true; }
67 
68   // Note that this is only valid *during* a handshake; at the end of the handshake,
69   // it gets reset back to false.
SetFullHandshake()70   void SetFullHandshake() { mIsFullHandshake = true; }
IsFullHandshake()71   bool IsFullHandshake() const { return mIsFullHandshake; }
72 
GetJoined()73   bool GetJoined() { return mJoined; }
SetSentClientCert()74   void SetSentClientCert() { mSentClientCert = true; }
75 
GetProviderFlags()76   uint32_t GetProviderFlags() const { return mProviderFlags; }
77 
78   mozilla::psm::SharedSSLState& SharedState();
79 
80   // XXX: These are only used on for diagnostic purposes
81   enum CertVerificationState {
82     before_cert_verification,
83     waiting_for_cert_verification,
84     after_cert_verification
85   };
86   void SetCertVerificationWaiting();
87   // Use errorCode == 0 to indicate success; in that case, errorMessageType is
88   // ignored.
89   void SetCertVerificationResult(PRErrorCode errorCode,
90               ::mozilla::psm::SSLErrorMessageType errorMessageType);
91 
92   // for logging only
IsWaitingForCertVerification()93   PRBool IsWaitingForCertVerification() const
94   {
95     return mCertVerificationState == waiting_for_cert_verification;
96   }
AddPlaintextBytesRead(uint64_t val)97   void AddPlaintextBytesRead(uint64_t val) { mPlaintextBytesRead += val; }
98 
IsPreliminaryHandshakeDone()99   bool IsPreliminaryHandshakeDone() const { return mPreliminaryHandshakeDone; }
SetPreliminaryHandshakeDone()100   void SetPreliminaryHandshakeDone() { mPreliminaryHandshakeDone = true; }
101 
SetKEAUsed(uint16_t kea)102   void SetKEAUsed(uint16_t kea) { mKEAUsed = kea; }
103 
SetKEAKeyBits(uint32_t keaBits)104   void SetKEAKeyBits(uint32_t keaBits) { mKEAKeyBits = keaBits; }
105 
SetBypassAuthentication(bool val)106   void SetBypassAuthentication(bool val)
107   {
108     if (!mHandshakeCompleted) {
109       mBypassAuthentication = val;
110     }
111   }
112 
SetSSLVersionUsed(int16_t version)113   void SetSSLVersionUsed(int16_t version)
114   {
115     mSSLVersionUsed = version;
116   }
117 
SetMACAlgorithmUsed(int16_t mac)118   void SetMACAlgorithmUsed(int16_t mac) { mMACAlgorithmUsed = mac; }
119 
120 protected:
121   virtual ~nsNSSSocketInfo();
122 
123 private:
124   PRFileDesc* mFd;
125 
126   CertVerificationState mCertVerificationState;
127 
128   mozilla::psm::SharedSSLState& mSharedState;
129   bool mForSTARTTLS;
130   SSLVersionRange mTLSVersionRange;
131   bool mHandshakePending;
132   bool mRememberClientAuthCertificate;
133   bool mPreliminaryHandshakeDone; // after false start items are complete
134 
135   nsresult ActivateSSL();
136 
137   nsCString mNegotiatedNPN;
138   bool      mNPNCompleted;
139   bool      mEarlyDataAccepted;
140   bool      mFalseStartCallbackCalled;
141   bool      mFalseStarted;
142   bool      mIsFullHandshake;
143   bool      mHandshakeCompleted;
144   bool      mJoined;
145   bool      mSentClientCert;
146   bool      mNotedTimeUntilReady;
147   bool      mFailedVerification;
148 
149   // mKEA* are used in false start and http/2 detetermination
150   // Values are from nsISSLSocketControl
151   int16_t mKEAUsed;
152   uint32_t mKEAKeyBits;
153   int16_t mSSLVersionUsed;
154   int16_t mMACAlgorithmUsed;
155   bool    mBypassAuthentication;
156 
157   uint32_t mProviderFlags;
158   mozilla::TimeStamp mSocketCreationTimestamp;
159   uint64_t mPlaintextBytesRead;
160 
161   nsCOMPtr<nsIX509Cert> mClientCert;
162 };
163 
164 enum StrongCipherStatus {
165   StrongCipherStatusUnknown,
166   StrongCiphersWorked,
167   StrongCiphersFailed
168 };
169 
170 class nsSSLIOLayerHelpers
171 {
172 public:
173   nsSSLIOLayerHelpers();
174   ~nsSSLIOLayerHelpers();
175 
176   nsresult Init();
177   void Cleanup();
178 
179   static bool nsSSLIOLayerInitialized;
180   static PRDescIdentity nsSSLIOLayerIdentity;
181   static PRDescIdentity nsSSLPlaintextLayerIdentity;
182   static PRIOMethods nsSSLIOLayerMethods;
183   static PRIOMethods nsSSLPlaintextLayerMethods;
184 
185   bool mTreatUnsafeNegotiationAsBroken;
186 
187   void setTreatUnsafeNegotiationAsBroken(bool broken);
188   bool treatUnsafeNegotiationAsBroken();
189 
190 private:
191   struct IntoleranceEntry
192   {
193     uint16_t tolerant;
194     uint16_t intolerant;
195     PRErrorCode intoleranceReason;
196     StrongCipherStatus strongCipherStatus;
197 
AssertInvariantIntoleranceEntry198     void AssertInvariant() const
199     {
200       MOZ_ASSERT(intolerant == 0 || tolerant < intolerant);
201     }
202   };
203   nsDataHashtable<nsCStringHashKey, IntoleranceEntry> mTLSIntoleranceInfo;
204   // Sites that require insecure fallback to TLS 1.0, set by the pref
205   // security.tls.insecure_fallback_hosts, which is a comma-delimited
206   // list of domain names.
207   nsTHashtable<nsCStringHashKey> mInsecureFallbackSites;
208 public:
209   void rememberTolerantAtVersion(const nsACString& hostname, int16_t port,
210                                  uint16_t tolerant);
211   bool fallbackLimitReached(const nsACString& hostname, uint16_t intolerant);
212   bool rememberIntolerantAtVersion(const nsACString& hostname, int16_t port,
213                                    uint16_t intolerant, uint16_t minVersion,
214                                    PRErrorCode intoleranceReason);
215   bool rememberStrongCiphersFailed(const nsACString& hostName, int16_t port,
216                                    PRErrorCode intoleranceReason);
217   void forgetIntolerance(const nsACString& hostname, int16_t port);
218   void adjustForTLSIntolerance(const nsACString& hostname, int16_t port,
219                                /*in/out*/ SSLVersionRange& range,
220                                /*out*/ StrongCipherStatus& strongCipherStatus);
221   PRErrorCode getIntoleranceReason(const nsACString& hostname, int16_t port);
222 
223   void clearStoredData();
224   void loadVersionFallbackLimit();
225   void setInsecureFallbackSites(const nsCString& str);
226   void initInsecureFallbackSites();
227   bool isPublic() const;
228   void addInsecureFallbackSite(const nsCString& hostname, bool temporary);
229   void removeInsecureFallbackSite(const nsACString& hostname, uint16_t port);
230   bool isInsecureFallbackSite(const nsACString& hostname);
231 
232   bool mFalseStartRequireNPN;
233   bool mUnrestrictedRC4Fallback;
234   uint16_t mVersionFallbackLimit;
235 private:
236   mozilla::Mutex mutex;
237   nsCOMPtr<nsIObserver> mPrefObserver;
238 };
239 
240 nsresult nsSSLIOLayerNewSocket(int32_t family,
241                                const char* host,
242                                int32_t port,
243                                nsIProxyInfo *proxy,
244                                const NeckoOriginAttributes& originAttributes,
245                                PRFileDesc** fd,
246                                nsISupports** securityInfo,
247                                bool forSTARTTLS,
248                                uint32_t flags);
249 
250 nsresult nsSSLIOLayerAddToSocket(int32_t family,
251                                  const char* host,
252                                  int32_t port,
253                                  nsIProxyInfo *proxy,
254                                  const NeckoOriginAttributes& originAttributes,
255                                  PRFileDesc* fd,
256                                  nsISupports** securityInfo,
257                                  bool forSTARTTLS,
258                                  uint32_t flags);
259 
260 nsresult nsSSLIOLayerFreeTLSIntolerantSites();
261 nsresult displayUnknownCertErrorAlert(nsNSSSocketInfo* infoObject, int error);
262 
263 #endif // nsNSSIOLayer_h
264