/src/mozilla-central/security/manager/ssl/nsNSSIOLayer.h
Line | Count | Source (jump to first uncovered line) |
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/Assertions.h" |
12 | | #include "mozilla/TimeStamp.h" |
13 | | #include "mozilla/UniquePtr.h" |
14 | | #include "nsCOMPtr.h" |
15 | | #include "nsDataHashtable.h" |
16 | | #include "nsIClientAuthDialogs.h" |
17 | | #include "nsIProxyInfo.h" |
18 | | #include "nsISSLSocketControl.h" |
19 | | #include "nsNSSCertificate.h" |
20 | | #include "nsTHashtable.h" |
21 | | #include "sslt.h" |
22 | | |
23 | | namespace mozilla { |
24 | | class OriginAttributes; |
25 | | namespace psm { |
26 | | class SharedSSLState; |
27 | | } // namespace psm |
28 | | } // namespace mozilla |
29 | | |
30 | | using mozilla::OriginAttributes; |
31 | | |
32 | | class nsIObserver; |
33 | | |
34 | | class nsNSSSocketInfo final : public mozilla::psm::TransportSecurityInfo, |
35 | | public nsISSLSocketControl, |
36 | | public nsIClientAuthUserDecision |
37 | | { |
38 | | public: |
39 | | nsNSSSocketInfo(mozilla::psm::SharedSSLState& aState, uint32_t providerFlags, |
40 | | uint32_t providerTlsFlags); |
41 | | |
42 | | NS_DECL_ISUPPORTS_INHERITED |
43 | | NS_DECL_NSISSLSOCKETCONTROL |
44 | | NS_DECL_NSICLIENTAUTHUSERDECISION |
45 | | |
46 | | void SetForSTARTTLS(bool aForSTARTTLS); |
47 | | bool GetForSTARTTLS(); |
48 | | |
49 | | nsresult GetFileDescPtr(PRFileDesc** aFilePtr); |
50 | | nsresult SetFileDescPtr(PRFileDesc* aFilePtr); |
51 | | |
52 | 0 | bool IsHandshakePending() const { return mHandshakePending; } |
53 | 0 | void SetHandshakeNotPending() { mHandshakePending = false; } |
54 | | |
55 | 0 | void SetTLSVersionRange(SSLVersionRange range) { mTLSVersionRange = range; } |
56 | 0 | SSLVersionRange GetTLSVersionRange() const { return mTLSVersionRange; }; |
57 | | |
58 | | PRStatus CloseSocketAndDestroy(); |
59 | | |
60 | | void SetNegotiatedNPN(const char* value, uint32_t length); |
61 | | void SetEarlyDataAccepted(bool aAccepted); |
62 | | |
63 | | void SetHandshakeCompleted(); |
64 | 0 | bool IsHandshakeCompleted() const { return mHandshakeCompleted; } |
65 | | void NoteTimeUntilReady(); |
66 | | |
67 | | |
68 | 0 | void SetFalseStartCallbackCalled() { mFalseStartCallbackCalled = true; } |
69 | 0 | void SetFalseStarted() { mFalseStarted = true; } |
70 | | |
71 | | // Note that this is only valid *during* a handshake; at the end of the handshake, |
72 | | // it gets reset back to false. |
73 | 0 | void SetFullHandshake() { mIsFullHandshake = true; } |
74 | 0 | bool IsFullHandshake() const { return mIsFullHandshake; } |
75 | | |
76 | 0 | bool GetJoined() { return mJoined; } |
77 | 0 | bool GetDenyClientCert() { return mDenyClientCert; } |
78 | 0 | void SetSentClientCert() { mSentClientCert = true; } |
79 | | |
80 | 0 | uint32_t GetProviderFlags() const { return mProviderFlags; } |
81 | 0 | uint32_t GetProviderTlsFlags() const { return mProviderTlsFlags; } |
82 | | |
83 | | mozilla::psm::SharedSSLState& SharedState(); |
84 | | |
85 | | // XXX: These are only used on for diagnostic purposes |
86 | | enum CertVerificationState { |
87 | | before_cert_verification, |
88 | | waiting_for_cert_verification, |
89 | | after_cert_verification |
90 | | }; |
91 | | void SetCertVerificationWaiting(); |
92 | | // Use errorCode == 0 to indicate success; |
93 | | void SetCertVerificationResult(PRErrorCode errorCode); |
94 | | |
95 | | // for logging only |
96 | | PRBool IsWaitingForCertVerification() const |
97 | 0 | { |
98 | 0 | return mCertVerificationState == waiting_for_cert_verification; |
99 | 0 | } |
100 | 0 | void AddPlaintextBytesRead(uint64_t val) { mPlaintextBytesRead += val; } |
101 | | |
102 | 0 | bool IsPreliminaryHandshakeDone() const { return mPreliminaryHandshakeDone; } |
103 | 0 | void SetPreliminaryHandshakeDone() { mPreliminaryHandshakeDone = true; } |
104 | | |
105 | 0 | void SetKEAUsed(uint16_t kea) { mKEAUsed = kea; } |
106 | | |
107 | 0 | void SetKEAKeyBits(uint32_t keaBits) { mKEAKeyBits = keaBits; } |
108 | | |
109 | | void SetBypassAuthentication(bool val) |
110 | 0 | { |
111 | 0 | if (!mHandshakeCompleted) { |
112 | 0 | mBypassAuthentication = val; |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | void SetSSLVersionUsed(int16_t version) |
117 | 0 | { |
118 | 0 | mSSLVersionUsed = version; |
119 | 0 | } |
120 | | |
121 | 0 | void SetMACAlgorithmUsed(int16_t mac) { mMACAlgorithmUsed = mac; } |
122 | | |
123 | | void SetShortWritePending(int32_t amount, unsigned char data) |
124 | 0 | { |
125 | 0 | mIsShortWritePending = true; |
126 | 0 | mShortWriteOriginalAmount = amount; |
127 | 0 | mShortWritePendingByte = data; |
128 | 0 | } |
129 | | |
130 | | bool IsShortWritePending() |
131 | 0 | { |
132 | 0 | return mIsShortWritePending; |
133 | 0 | } |
134 | | |
135 | | unsigned char const* GetShortWritePendingByteRef() |
136 | 0 | { |
137 | 0 | return &mShortWritePendingByte; |
138 | 0 | } |
139 | | |
140 | | int32_t ResetShortWritePending() |
141 | 0 | { |
142 | 0 | mIsShortWritePending = false; |
143 | 0 | return mShortWriteOriginalAmount; |
144 | 0 | } |
145 | | |
146 | | #ifdef DEBUG |
147 | | // These helpers assert that the caller does try to send the same data |
148 | | // as it was previously when we hit the short-write. This is a measure |
149 | | // to make sure we communicate correctly to the consumer. |
150 | | void RememberShortWrittenBuffer(const unsigned char *data) |
151 | | { |
152 | | mShortWriteBufferCheck = mozilla::MakeUnique<char[]>(mShortWriteOriginalAmount); |
153 | | memcpy(mShortWriteBufferCheck.get(), data, mShortWriteOriginalAmount); |
154 | | } |
155 | | void CheckShortWrittenBuffer(const unsigned char *data, int32_t amount) |
156 | | { |
157 | | if (!mShortWriteBufferCheck) return; |
158 | | MOZ_ASSERT(amount >= mShortWriteOriginalAmount, |
159 | | "unexpected amount length after short write"); |
160 | | MOZ_ASSERT(!memcmp(mShortWriteBufferCheck.get(), data, mShortWriteOriginalAmount), |
161 | | "unexpected buffer content after short write"); |
162 | | mShortWriteBufferCheck = nullptr; |
163 | | } |
164 | | #endif |
165 | | |
166 | | void SetSharedOwningReference(mozilla::psm::SharedSSLState* ref); |
167 | | |
168 | | protected: |
169 | | virtual ~nsNSSSocketInfo(); |
170 | | |
171 | | private: |
172 | | PRFileDesc* mFd; |
173 | | |
174 | | CertVerificationState mCertVerificationState; |
175 | | |
176 | | mozilla::psm::SharedSSLState& mSharedState; |
177 | | bool mForSTARTTLS; |
178 | | SSLVersionRange mTLSVersionRange; |
179 | | bool mHandshakePending; |
180 | | bool mRememberClientAuthCertificate; |
181 | | bool mPreliminaryHandshakeDone; // after false start items are complete |
182 | | |
183 | | nsresult ActivateSSL(); |
184 | | |
185 | | nsCString mNegotiatedNPN; |
186 | | nsCString mEsniTxt; |
187 | | bool mNPNCompleted; |
188 | | bool mEarlyDataAccepted; |
189 | | bool mDenyClientCert; |
190 | | bool mFalseStartCallbackCalled; |
191 | | bool mFalseStarted; |
192 | | bool mIsFullHandshake; |
193 | | bool mHandshakeCompleted; |
194 | | bool mJoined; |
195 | | bool mSentClientCert; |
196 | | bool mNotedTimeUntilReady; |
197 | | bool mFailedVerification; |
198 | | |
199 | | // True when SSL layer has indicated an "SSL short write", i.e. need |
200 | | // to call on send one or more times to push all pending data to write. |
201 | | bool mIsShortWritePending; |
202 | | |
203 | | // These are only valid if mIsShortWritePending is true. |
204 | | // |
205 | | // Value of the last byte pending from the SSL short write that needs |
206 | | // to be passed to subsequent calls to send to perform the flush. |
207 | | unsigned char mShortWritePendingByte; |
208 | | |
209 | | // Original amount of data the upper layer has requested to write to |
210 | | // return after the successful flush. |
211 | | int32_t mShortWriteOriginalAmount; |
212 | | |
213 | | #ifdef DEBUG |
214 | | mozilla::UniquePtr<char[]> mShortWriteBufferCheck; |
215 | | #endif |
216 | | |
217 | | // mKEA* are used in false start and http/2 detetermination |
218 | | // Values are from nsISSLSocketControl |
219 | | int16_t mKEAUsed; |
220 | | uint32_t mKEAKeyBits; |
221 | | int16_t mSSLVersionUsed; |
222 | | int16_t mMACAlgorithmUsed; |
223 | | bool mBypassAuthentication; |
224 | | |
225 | | uint32_t mProviderFlags; |
226 | | uint32_t mProviderTlsFlags; |
227 | | mozilla::TimeStamp mSocketCreationTimestamp; |
228 | | uint64_t mPlaintextBytesRead; |
229 | | |
230 | | nsCOMPtr<nsIX509Cert> mClientCert; |
231 | | |
232 | | // if non-null this is a reference to the mSharedState (which is |
233 | | // not an owning reference). If this is used, the info has a private |
234 | | // state that does not share things like intolerance lists with the |
235 | | // rest of the session. This is normally used when you have per |
236 | | // socket tls flags overriding session wide defaults. |
237 | | RefPtr<mozilla::psm::SharedSSLState> mOwningSharedRef; |
238 | | }; |
239 | | |
240 | | class nsSSLIOLayerHelpers |
241 | | { |
242 | | public: |
243 | | explicit nsSSLIOLayerHelpers(uint32_t aTlsFlags = 0); |
244 | | ~nsSSLIOLayerHelpers(); |
245 | | |
246 | | nsresult Init(); |
247 | | void Cleanup(); |
248 | | |
249 | | static bool nsSSLIOLayerInitialized; |
250 | | static PRDescIdentity nsSSLIOLayerIdentity; |
251 | | static PRDescIdentity nsSSLPlaintextLayerIdentity; |
252 | | static PRIOMethods nsSSLIOLayerMethods; |
253 | | static PRIOMethods nsSSLPlaintextLayerMethods; |
254 | | |
255 | | bool mTreatUnsafeNegotiationAsBroken; |
256 | | |
257 | | void setTreatUnsafeNegotiationAsBroken(bool broken); |
258 | | bool treatUnsafeNegotiationAsBroken(); |
259 | | |
260 | | private: |
261 | | struct IntoleranceEntry |
262 | | { |
263 | | uint16_t tolerant; |
264 | | uint16_t intolerant; |
265 | | PRErrorCode intoleranceReason; |
266 | | |
267 | | void AssertInvariant() const |
268 | 0 | { |
269 | 0 | MOZ_ASSERT(intolerant == 0 || tolerant < intolerant); |
270 | 0 | } |
271 | | }; |
272 | | nsDataHashtable<nsCStringHashKey, IntoleranceEntry> mTLSIntoleranceInfo; |
273 | | // Sites that require insecure fallback to TLS 1.0, set by the pref |
274 | | // security.tls.insecure_fallback_hosts, which is a comma-delimited |
275 | | // list of domain names. |
276 | | nsTHashtable<nsCStringHashKey> mInsecureFallbackSites; |
277 | | public: |
278 | | void rememberTolerantAtVersion(const nsACString& hostname, int16_t port, |
279 | | uint16_t tolerant); |
280 | | bool fallbackLimitReached(const nsACString& hostname, uint16_t intolerant); |
281 | | bool rememberIntolerantAtVersion(const nsACString& hostname, int16_t port, |
282 | | uint16_t intolerant, uint16_t minVersion, |
283 | | PRErrorCode intoleranceReason); |
284 | | void forgetIntolerance(const nsACString& hostname, int16_t port); |
285 | | void adjustForTLSIntolerance(const nsACString& hostname, int16_t port, |
286 | | /*in/out*/ SSLVersionRange& range); |
287 | | PRErrorCode getIntoleranceReason(const nsACString& hostname, int16_t port); |
288 | | |
289 | | void clearStoredData(); |
290 | | void loadVersionFallbackLimit(); |
291 | | void setInsecureFallbackSites(const nsCString& str); |
292 | | void initInsecureFallbackSites(); |
293 | | bool isPublic() const; |
294 | | void removeInsecureFallbackSite(const nsACString& hostname, uint16_t port); |
295 | | bool isInsecureFallbackSite(const nsACString& hostname); |
296 | | |
297 | | uint16_t mVersionFallbackLimit; |
298 | | private: |
299 | | mozilla::Mutex mutex; |
300 | | nsCOMPtr<nsIObserver> mPrefObserver; |
301 | | uint32_t mTlsFlags; |
302 | | }; |
303 | | |
304 | | nsresult nsSSLIOLayerNewSocket(int32_t family, |
305 | | const char* host, |
306 | | int32_t port, |
307 | | nsIProxyInfo *proxy, |
308 | | const OriginAttributes& originAttributes, |
309 | | PRFileDesc** fd, |
310 | | nsISupports** securityInfo, |
311 | | bool forSTARTTLS, |
312 | | uint32_t flags, |
313 | | uint32_t tlsFlags); |
314 | | |
315 | | nsresult nsSSLIOLayerAddToSocket(int32_t family, |
316 | | const char* host, |
317 | | int32_t port, |
318 | | nsIProxyInfo *proxy, |
319 | | const OriginAttributes& originAttributes, |
320 | | PRFileDesc* fd, |
321 | | nsISupports** securityInfo, |
322 | | bool forSTARTTLS, |
323 | | uint32_t flags, |
324 | | uint32_t tlsFlags); |
325 | | |
326 | | nsresult nsSSLIOLayerFreeTLSIntolerantSites(); |
327 | | |
328 | | #endif // nsNSSIOLayer_h |