|
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 // For connections that are not processed on the socket transport thread, we do |
|
8 // NOT use the async logic described below. Instead, we authenticate the |
|
9 // certificate on the thread that the connection's I/O happens on, |
|
10 // synchronously. This allows us to do certificate verification for blocking |
|
11 // (not non-blocking) sockets and sockets that have their I/O processed on a |
|
12 // thread other than the socket transport service thread. Also, we DO NOT |
|
13 // support blocking sockets on the socket transport service thread at all. |
|
14 // |
|
15 // During certificate authentication, we call CERT_PKIXVerifyCert or |
|
16 // CERT_VerifyCert. These functions may make zero or more HTTP requests |
|
17 // for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic |
|
18 // for these requests processes them on the socket transport service thread. |
|
19 // |
|
20 // If the connection for which we are verifying the certificate is happening |
|
21 // on the socket transport thread (the usually case, at least for HTTP), then |
|
22 // if our cert auth hook were to call the CERT_*Verify* functions directly, |
|
23 // there would be a deadlock: The CERT_*Verify* function would cause an event |
|
24 // to be asynchronously posted to the socket transport thread, and then it |
|
25 // would block the socket transport thread waiting to be notified of the HTTP |
|
26 // response. However, the HTTP request would never actually be processed |
|
27 // because the socket transport thread would be blocked and so it wouldn't be |
|
28 // able process HTTP requests. (i.e. Deadlock.) |
|
29 // |
|
30 // Consequently, when we are asked to verify a certificate on the socket |
|
31 // transport service thread, we must always call the CERT_*Verify* cert |
|
32 // functions on another thread. To accomplish this, our auth cert hook |
|
33 // dispatches a SSLServerCertVerificationJob to a pool of background threads, |
|
34 // and then immediatley return SECWouldBlock to libssl. These jobs are where |
|
35 // the CERT_*Verify* functions are actually called. |
|
36 // |
|
37 // When our auth cert hook returns SECWouldBlock, libssl will carry on the |
|
38 // handshake while we validate the certificate. This will free up the socket |
|
39 // transport thread so that HTTP requests--in particular, the OCSP/CRL/cert |
|
40 // requests needed for cert verification as mentioned above--can be processed. |
|
41 // |
|
42 // Once the CERT_*Verify* function returns, the cert verification job |
|
43 // dispatches a SSLServerCertVerificationResult to the socket transport thread; |
|
44 // the SSLServerCertVerificationResult will notify libssl that the certificate |
|
45 // authentication is complete. Once libssl is notified that the authentication |
|
46 // is complete, it will continue the SSL handshake (if it hasn't already |
|
47 // finished) and it will begin allowing us to send/receive data on the |
|
48 // connection. |
|
49 // |
|
50 // Timeline of events (for connections managed by the socket transport service): |
|
51 // |
|
52 // * libssl calls SSLServerCertVerificationJob::Dispatch on the socket |
|
53 // transport thread. |
|
54 // * SSLServerCertVerificationJob::Dispatch queues a job |
|
55 // (instance of SSLServerCertVerificationJob) to its background thread |
|
56 // pool and returns. |
|
57 // * One of the background threads calls CERT_*Verify*, which may enqueue |
|
58 // some HTTP request(s) onto the socket transport thread, and then |
|
59 // blocks that background thread waiting for the responses and/or timeouts |
|
60 // or errors for those requests. |
|
61 // * Once those HTTP responses have all come back or failed, the |
|
62 // CERT_*Verify* function returns a result indicating that the validation |
|
63 // succeeded or failed. |
|
64 // * If the validation succeeded, then a SSLServerCertVerificationResult |
|
65 // event is posted to the socket transport thread, and the cert |
|
66 // verification thread becomes free to verify other certificates. |
|
67 // * Otherwise, a CertErrorRunnable is posted to the socket transport thread |
|
68 // and then to the main thread (blocking both, see CertErrorRunnable) to |
|
69 // do cert override processing and bad cert listener notification. Then |
|
70 // the cert verification thread becomes free to verify other certificates. |
|
71 // * After processing cert overrides, the CertErrorRunnable will dispatch a |
|
72 // SSLServerCertVerificationResult event to the socket transport thread to |
|
73 // notify it of the result of the override processing; then it returns, |
|
74 // freeing up the main thread. |
|
75 // * The SSLServerCertVerificationResult event will either wake up the |
|
76 // socket (using SSL_RestartHandshakeAfterServerCert) if validation |
|
77 // succeeded or there was an error override, or it will set an error flag |
|
78 // so that the next I/O operation on the socket will fail, causing the |
|
79 // socket transport thread to close the connection. |
|
80 // |
|
81 // Cert override processing must happen on the main thread because it accesses |
|
82 // the nsICertOverrideService, and that service must be accessed on the main |
|
83 // thread because some extensions (Selenium, in particular) replace it with a |
|
84 // Javascript implementation, and chrome JS must always be run on the main |
|
85 // thread. |
|
86 // |
|
87 // SSLServerCertVerificationResult must be dispatched to the socket transport |
|
88 // thread because we must only call SSL_* functions on the socket transport |
|
89 // thread since they may do I/O, because many parts of nsNSSSocketInfo (the |
|
90 // subclass of TransportSecurityInfo used when validating certificates during |
|
91 // an SSL handshake) and the PSM NSS I/O layer are not thread-safe, and because |
|
92 // we need the event to interrupt the PR_Poll that may waiting for I/O on the |
|
93 // socket for which we are validating the cert. |
|
94 |
|
95 #include "SSLServerCertVerification.h" |
|
96 |
|
97 #include <cstring> |
|
98 |
|
99 #include "pkix/pkixtypes.h" |
|
100 #include "CertVerifier.h" |
|
101 #include "CryptoTask.h" |
|
102 #include "ExtendedValidation.h" |
|
103 #include "NSSCertDBTrustDomain.h" |
|
104 #include "nsIBadCertListener2.h" |
|
105 #include "nsICertOverrideService.h" |
|
106 #include "nsISiteSecurityService.h" |
|
107 #include "nsNSSComponent.h" |
|
108 #include "nsNSSCleaner.h" |
|
109 #include "nsRecentBadCerts.h" |
|
110 #include "nsNSSIOLayer.h" |
|
111 #include "nsNSSShutDown.h" |
|
112 |
|
113 #include "mozilla/Assertions.h" |
|
114 #include "mozilla/Mutex.h" |
|
115 #include "mozilla/Telemetry.h" |
|
116 #include "mozilla/unused.h" |
|
117 #include "nsIThreadPool.h" |
|
118 #include "nsNetUtil.h" |
|
119 #include "nsXPCOMCIDInternal.h" |
|
120 #include "nsComponentManagerUtils.h" |
|
121 #include "nsServiceManagerUtils.h" |
|
122 #include "PSMRunnable.h" |
|
123 #include "SharedSSLState.h" |
|
124 #include "nsContentUtils.h" |
|
125 |
|
126 #include "ssl.h" |
|
127 #include "secerr.h" |
|
128 #include "secport.h" |
|
129 #include "sslerr.h" |
|
130 #include "ocsp.h" |
|
131 |
|
132 #ifdef PR_LOGGING |
|
133 extern PRLogModuleInfo* gPIPNSSLog; |
|
134 #endif |
|
135 |
|
136 namespace mozilla { namespace psm { |
|
137 |
|
138 namespace { |
|
139 |
|
140 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); |
|
141 |
|
142 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate) |
|
143 NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false) |
|
144 |
|
145 // do not use a nsCOMPtr to avoid static initializer/destructor |
|
146 nsIThreadPool* gCertVerificationThreadPool = nullptr; |
|
147 |
|
148 // We avoid using a mutex for the success case to avoid lock-related |
|
149 // performance issues. However, we do use a lock in the error case to simplify |
|
150 // the code, since performance in the error case is not important. |
|
151 Mutex* gSSLVerificationTelemetryMutex = nullptr; |
|
152 |
|
153 // We add a mutex to serialize PKCS11 database operations |
|
154 Mutex* gSSLVerificationPK11Mutex = nullptr; |
|
155 |
|
156 } // unnamed namespace |
|
157 |
|
158 // Called when the socket transport thread starts, to initialize the SSL cert |
|
159 // verification thread pool. By tying the thread pool startup/shutdown directly |
|
160 // to the STS thread's lifetime, we ensure that they are *always* available for |
|
161 // SSL connections and that there are no races during startup and especially |
|
162 // shutdown. (Previously, we have had multiple problems with races in PSM |
|
163 // background threads, and the race-prevention/shutdown logic used there is |
|
164 // brittle. Since this service is critical to things like downloading updates, |
|
165 // we take no chances.) Also, by doing things this way, we avoid the need for |
|
166 // locks, since gCertVerificationThreadPool is only ever accessed on the socket |
|
167 // transport thread. |
|
168 void |
|
169 InitializeSSLServerCertVerificationThreads() |
|
170 { |
|
171 gSSLVerificationTelemetryMutex = new Mutex("SSLVerificationTelemetryMutex"); |
|
172 gSSLVerificationPK11Mutex = new Mutex("SSLVerificationPK11Mutex"); |
|
173 // TODO: tuning, make parameters preferences |
|
174 // XXX: instantiate nsThreadPool directly, to make this more bulletproof. |
|
175 // Currently, the nsThreadPool.h header isn't exported for us to do so. |
|
176 nsresult rv = CallCreateInstance(NS_THREADPOOL_CONTRACTID, |
|
177 &gCertVerificationThreadPool); |
|
178 if (NS_FAILED(rv)) { |
|
179 NS_WARNING("Failed to create SSL cert verification threads."); |
|
180 return; |
|
181 } |
|
182 |
|
183 (void) gCertVerificationThreadPool->SetIdleThreadLimit(5); |
|
184 (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000); |
|
185 (void) gCertVerificationThreadPool->SetThreadLimit(5); |
|
186 (void) gCertVerificationThreadPool->SetName(NS_LITERAL_CSTRING("SSL Cert")); |
|
187 } |
|
188 |
|
189 // Called when the socket transport thread finishes, to destroy the thread |
|
190 // pool. Since the socket transport service has stopped processing events, it |
|
191 // will not attempt any more SSL I/O operations, so it is clearly safe to shut |
|
192 // down the SSL cert verification infrastructure. Also, the STS will not |
|
193 // dispatch many SSL verification result events at this point, so any pending |
|
194 // cert verifications will (correctly) fail at the point they are dispatched. |
|
195 // |
|
196 // The other shutdown race condition that is possible is a race condition with |
|
197 // shutdown of the nsNSSComponent service. We use the |
|
198 // nsNSSShutdownPreventionLock where needed (not here) to prevent that. |
|
199 void StopSSLServerCertVerificationThreads() |
|
200 { |
|
201 if (gCertVerificationThreadPool) { |
|
202 gCertVerificationThreadPool->Shutdown(); |
|
203 NS_RELEASE(gCertVerificationThreadPool); |
|
204 } |
|
205 if (gSSLVerificationTelemetryMutex) { |
|
206 delete gSSLVerificationTelemetryMutex; |
|
207 gSSLVerificationTelemetryMutex = nullptr; |
|
208 } |
|
209 if (gSSLVerificationPK11Mutex) { |
|
210 delete gSSLVerificationPK11Mutex; |
|
211 gSSLVerificationPK11Mutex = nullptr; |
|
212 } |
|
213 } |
|
214 |
|
215 namespace { |
|
216 |
|
217 void |
|
218 LogInvalidCertError(TransportSecurityInfo* socketInfo, |
|
219 PRErrorCode errorCode, |
|
220 ::mozilla::psm::SSLErrorMessageType errorMessageType) |
|
221 { |
|
222 nsString message; |
|
223 socketInfo->GetErrorLogMessage(errorCode, errorMessageType, message); |
|
224 if (!message.IsEmpty()) { |
|
225 nsContentUtils::LogSimpleConsoleError(message, "SSL"); |
|
226 } |
|
227 } |
|
228 |
|
229 // Dispatched to the STS thread to notify the infoObject of the verification |
|
230 // result. |
|
231 // |
|
232 // This will cause the PR_Poll in the STS thread to return, so things work |
|
233 // correctly even if the STS thread is blocked polling (only) on the file |
|
234 // descriptor that is waiting for this result. |
|
235 class SSLServerCertVerificationResult : public nsRunnable |
|
236 { |
|
237 public: |
|
238 NS_DECL_NSIRUNNABLE |
|
239 |
|
240 SSLServerCertVerificationResult(TransportSecurityInfo* infoObject, |
|
241 PRErrorCode errorCode, |
|
242 Telemetry::ID telemetryID = Telemetry::HistogramCount, |
|
243 uint32_t telemetryValue = -1, |
|
244 SSLErrorMessageType errorMessageType = |
|
245 PlainErrorMessage); |
|
246 |
|
247 void Dispatch(); |
|
248 private: |
|
249 const RefPtr<TransportSecurityInfo> mInfoObject; |
|
250 public: |
|
251 const PRErrorCode mErrorCode; |
|
252 const SSLErrorMessageType mErrorMessageType; |
|
253 const Telemetry::ID mTelemetryID; |
|
254 const uint32_t mTelemetryValue; |
|
255 }; |
|
256 |
|
257 class CertErrorRunnable : public SyncRunnableBase |
|
258 { |
|
259 public: |
|
260 CertErrorRunnable(const void* fdForLogging, |
|
261 nsIX509Cert* cert, |
|
262 TransportSecurityInfo* infoObject, |
|
263 PRErrorCode defaultErrorCodeToReport, |
|
264 uint32_t collectedErrors, |
|
265 PRErrorCode errorCodeTrust, |
|
266 PRErrorCode errorCodeMismatch, |
|
267 PRErrorCode errorCodeExpired, |
|
268 uint32_t providerFlags) |
|
269 : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject), |
|
270 mDefaultErrorCodeToReport(defaultErrorCodeToReport), |
|
271 mCollectedErrors(collectedErrors), |
|
272 mErrorCodeTrust(errorCodeTrust), |
|
273 mErrorCodeMismatch(errorCodeMismatch), |
|
274 mErrorCodeExpired(errorCodeExpired), |
|
275 mProviderFlags(providerFlags) |
|
276 { |
|
277 } |
|
278 |
|
279 virtual void RunOnTargetThread(); |
|
280 RefPtr<SSLServerCertVerificationResult> mResult; // out |
|
281 private: |
|
282 SSLServerCertVerificationResult* CheckCertOverrides(); |
|
283 |
|
284 const void* const mFdForLogging; // may become an invalid pointer; do not dereference |
|
285 const nsCOMPtr<nsIX509Cert> mCert; |
|
286 const RefPtr<TransportSecurityInfo> mInfoObject; |
|
287 const PRErrorCode mDefaultErrorCodeToReport; |
|
288 const uint32_t mCollectedErrors; |
|
289 const PRErrorCode mErrorCodeTrust; |
|
290 const PRErrorCode mErrorCodeMismatch; |
|
291 const PRErrorCode mErrorCodeExpired; |
|
292 const uint32_t mProviderFlags; |
|
293 }; |
|
294 |
|
295 // A probe value of 1 means "no error". |
|
296 uint32_t |
|
297 MapCertErrorToProbeValue(PRErrorCode errorCode) |
|
298 { |
|
299 switch (errorCode) |
|
300 { |
|
301 case SEC_ERROR_UNKNOWN_ISSUER: return 2; |
|
302 case SEC_ERROR_CA_CERT_INVALID: return 3; |
|
303 case SEC_ERROR_UNTRUSTED_ISSUER: return 4; |
|
304 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: return 5; |
|
305 case SEC_ERROR_UNTRUSTED_CERT: return 6; |
|
306 case SEC_ERROR_INADEQUATE_KEY_USAGE: return 7; |
|
307 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: return 8; |
|
308 case SSL_ERROR_BAD_CERT_DOMAIN: return 9; |
|
309 case SEC_ERROR_EXPIRED_CERTIFICATE: return 10; |
|
310 } |
|
311 NS_WARNING("Unknown certificate error code. Does MapCertErrorToProbeValue " |
|
312 "handle everything in PRErrorCodeToOverrideType?"); |
|
313 return 0; |
|
314 } |
|
315 |
|
316 SECStatus |
|
317 MozillaPKIXDetermineCertOverrideErrors(CERTCertificate* cert, |
|
318 const char* hostName, PRTime now, |
|
319 PRErrorCode defaultErrorCodeToReport, |
|
320 /*out*/ uint32_t& collectedErrors, |
|
321 /*out*/ PRErrorCode& errorCodeTrust, |
|
322 /*out*/ PRErrorCode& errorCodeMismatch, |
|
323 /*out*/ PRErrorCode& errorCodeExpired) |
|
324 { |
|
325 MOZ_ASSERT(cert); |
|
326 MOZ_ASSERT(hostName); |
|
327 MOZ_ASSERT(collectedErrors == 0); |
|
328 MOZ_ASSERT(errorCodeTrust == 0); |
|
329 MOZ_ASSERT(errorCodeMismatch == 0); |
|
330 MOZ_ASSERT(errorCodeExpired == 0); |
|
331 |
|
332 // Assumes the error prioritization described in mozilla::pkix's |
|
333 // BuildForward function. Also assumes that CERT_VerifyCertName was only |
|
334 // called if CertVerifier::VerifyCert succeeded. |
|
335 switch (defaultErrorCodeToReport) { |
|
336 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: |
|
337 case SEC_ERROR_CA_CERT_INVALID: |
|
338 case SEC_ERROR_UNKNOWN_ISSUER: |
|
339 { |
|
340 collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED; |
|
341 errorCodeTrust = defaultErrorCodeToReport; |
|
342 |
|
343 SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, now, false); |
|
344 if (validity == secCertTimeUndetermined) { |
|
345 PR_SetError(defaultErrorCodeToReport, 0); |
|
346 return SECFailure; |
|
347 } |
|
348 if (validity != secCertTimeValid) { |
|
349 collectedErrors |= nsICertOverrideService::ERROR_TIME; |
|
350 errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE; |
|
351 } |
|
352 break; |
|
353 } |
|
354 |
|
355 case SEC_ERROR_EXPIRED_CERTIFICATE: |
|
356 collectedErrors = nsICertOverrideService::ERROR_TIME; |
|
357 errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE; |
|
358 break; |
|
359 |
|
360 case SSL_ERROR_BAD_CERT_DOMAIN: |
|
361 collectedErrors = nsICertOverrideService::ERROR_MISMATCH; |
|
362 errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN; |
|
363 break; |
|
364 |
|
365 case 0: |
|
366 NS_ERROR("No error code set during certificate validation failure."); |
|
367 PR_SetError(PR_INVALID_STATE_ERROR, 0); |
|
368 return SECFailure; |
|
369 |
|
370 default: |
|
371 PR_SetError(defaultErrorCodeToReport, 0); |
|
372 return SECFailure; |
|
373 } |
|
374 |
|
375 if (defaultErrorCodeToReport != SSL_ERROR_BAD_CERT_DOMAIN) { |
|
376 if (CERT_VerifyCertName(cert, hostName) != SECSuccess) { |
|
377 if (PR_GetError() != SSL_ERROR_BAD_CERT_DOMAIN) { |
|
378 PR_SetError(defaultErrorCodeToReport, 0); |
|
379 return SECFailure; |
|
380 } |
|
381 |
|
382 collectedErrors |= nsICertOverrideService::ERROR_MISMATCH; |
|
383 errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN; |
|
384 } |
|
385 } |
|
386 |
|
387 return SECSuccess; |
|
388 } |
|
389 |
|
390 SSLServerCertVerificationResult* |
|
391 CertErrorRunnable::CheckCertOverrides() |
|
392 { |
|
393 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n", |
|
394 mFdForLogging, this)); |
|
395 // "Use" mFdForLogging in non-PR_LOGGING builds, too, to suppress |
|
396 // clang's -Wunused-private-field build warning for this variable: |
|
397 unused << mFdForLogging; |
|
398 |
|
399 if (!NS_IsMainThread()) { |
|
400 NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread"); |
|
401 return new SSLServerCertVerificationResult(mInfoObject, |
|
402 mDefaultErrorCodeToReport); |
|
403 } |
|
404 |
|
405 int32_t port; |
|
406 mInfoObject->GetPort(&port); |
|
407 |
|
408 nsCString hostWithPortString; |
|
409 hostWithPortString.AppendASCII(mInfoObject->GetHostNameRaw()); |
|
410 hostWithPortString.AppendLiteral(":"); |
|
411 hostWithPortString.AppendInt(port); |
|
412 |
|
413 uint32_t remaining_display_errors = mCollectedErrors; |
|
414 |
|
415 nsresult nsrv; |
|
416 |
|
417 // Enforce Strict-Transport-Security for hosts that are "STS" hosts: |
|
418 // connections must be dropped when there are any certificate errors |
|
419 // (STS Spec section 7.3). |
|
420 bool strictTransportSecurityEnabled = false; |
|
421 nsCOMPtr<nsISiteSecurityService> sss |
|
422 = do_GetService(NS_SSSERVICE_CONTRACTID, &nsrv); |
|
423 if (NS_SUCCEEDED(nsrv)) { |
|
424 nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS, |
|
425 mInfoObject->GetHostNameRaw(), |
|
426 mProviderFlags, |
|
427 &strictTransportSecurityEnabled); |
|
428 } |
|
429 if (NS_FAILED(nsrv)) { |
|
430 return new SSLServerCertVerificationResult(mInfoObject, |
|
431 mDefaultErrorCodeToReport); |
|
432 } |
|
433 |
|
434 if (!strictTransportSecurityEnabled) { |
|
435 nsCOMPtr<nsICertOverrideService> overrideService = |
|
436 do_GetService(NS_CERTOVERRIDE_CONTRACTID); |
|
437 // it is fine to continue without the nsICertOverrideService |
|
438 |
|
439 uint32_t overrideBits = 0; |
|
440 |
|
441 if (overrideService) |
|
442 { |
|
443 bool haveOverride; |
|
444 bool isTemporaryOverride; // we don't care |
|
445 nsCString hostString(mInfoObject->GetHostName()); |
|
446 nsrv = overrideService->HasMatchingOverride(hostString, port, |
|
447 mCert, |
|
448 &overrideBits, |
|
449 &isTemporaryOverride, |
|
450 &haveOverride); |
|
451 if (NS_SUCCEEDED(nsrv) && haveOverride) |
|
452 { |
|
453 // remove the errors that are already overriden |
|
454 remaining_display_errors &= ~overrideBits; |
|
455 } |
|
456 } |
|
457 |
|
458 if (!remaining_display_errors) { |
|
459 // This can double- or triple-count one certificate with multiple |
|
460 // different types of errors. Since this is telemetry and we just |
|
461 // want a ballpark answer, we don't care. |
|
462 if (mErrorCodeTrust != 0) { |
|
463 uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeTrust); |
|
464 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue); |
|
465 } |
|
466 if (mErrorCodeMismatch != 0) { |
|
467 uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeMismatch); |
|
468 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue); |
|
469 } |
|
470 if (mErrorCodeExpired != 0) { |
|
471 uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeExpired); |
|
472 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue); |
|
473 } |
|
474 |
|
475 // all errors are covered by override rules, so let's accept the cert |
|
476 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
477 ("[%p][%p] All errors covered by override rules\n", |
|
478 mFdForLogging, this)); |
|
479 return new SSLServerCertVerificationResult(mInfoObject, 0); |
|
480 } |
|
481 } else { |
|
482 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
483 ("[%p][%p] Strict-Transport-Security is violated: untrusted " |
|
484 "transport layer\n", mFdForLogging, this)); |
|
485 } |
|
486 |
|
487 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
488 ("[%p][%p] Certificate error was not overridden\n", |
|
489 mFdForLogging, this)); |
|
490 |
|
491 // Ok, this is a full stop. |
|
492 // First, deliver the technical details of the broken SSL status. |
|
493 |
|
494 // Try to get a nsIBadCertListener2 implementation from the socket consumer. |
|
495 nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface( |
|
496 NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject)); |
|
497 if (sslSocketControl) { |
|
498 nsCOMPtr<nsIInterfaceRequestor> cb; |
|
499 sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb)); |
|
500 if (cb) { |
|
501 nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb); |
|
502 if (bcl) { |
|
503 nsIInterfaceRequestor* csi |
|
504 = static_cast<nsIInterfaceRequestor*>(mInfoObject); |
|
505 bool suppressMessage = false; // obsolete, ignored |
|
506 nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(), |
|
507 hostWithPortString, &suppressMessage); |
|
508 } |
|
509 } |
|
510 } |
|
511 |
|
512 nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID); |
|
513 nsCOMPtr<nsIRecentBadCerts> recentBadCertsService; |
|
514 if (certdb) { |
|
515 bool isPrivate = mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE; |
|
516 certdb->GetRecentBadCerts(isPrivate, getter_AddRefs(recentBadCertsService)); |
|
517 } |
|
518 |
|
519 if (recentBadCertsService) { |
|
520 NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString); |
|
521 recentBadCertsService->AddBadCert(hostWithPortStringUTF16, |
|
522 mInfoObject->SSLStatus()); |
|
523 } |
|
524 |
|
525 // pick the error code to report by priority |
|
526 PRErrorCode errorCodeToReport = mErrorCodeTrust ? mErrorCodeTrust |
|
527 : mErrorCodeMismatch ? mErrorCodeMismatch |
|
528 : mErrorCodeExpired ? mErrorCodeExpired |
|
529 : mDefaultErrorCodeToReport; |
|
530 |
|
531 SSLServerCertVerificationResult* result = |
|
532 new SSLServerCertVerificationResult(mInfoObject, |
|
533 errorCodeToReport, |
|
534 Telemetry::HistogramCount, |
|
535 -1, |
|
536 OverridableCertErrorMessage); |
|
537 |
|
538 LogInvalidCertError(mInfoObject, |
|
539 result->mErrorCode, |
|
540 result->mErrorMessageType); |
|
541 |
|
542 return result; |
|
543 } |
|
544 |
|
545 void |
|
546 CertErrorRunnable::RunOnTargetThread() |
|
547 { |
|
548 MOZ_ASSERT(NS_IsMainThread()); |
|
549 |
|
550 mResult = CheckCertOverrides(); |
|
551 |
|
552 MOZ_ASSERT(mResult); |
|
553 } |
|
554 |
|
555 // Converts a PRErrorCode into one of |
|
556 // nsICertOverrideService::ERROR_UNTRUSTED, |
|
557 // nsICertOverrideService::ERROR_MISMATCH, |
|
558 // nsICertOverrideService::ERROR_TIME |
|
559 // if the given error code is an overridable error. |
|
560 // If it is not, then 0 is returned. |
|
561 uint32_t |
|
562 PRErrorCodeToOverrideType(PRErrorCode errorCode) |
|
563 { |
|
564 switch (errorCode) |
|
565 { |
|
566 case SEC_ERROR_UNKNOWN_ISSUER: |
|
567 case SEC_ERROR_UNTRUSTED_ISSUER: |
|
568 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: |
|
569 case SEC_ERROR_UNTRUSTED_CERT: |
|
570 case SEC_ERROR_INADEQUATE_KEY_USAGE: |
|
571 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: |
|
572 case SEC_ERROR_CA_CERT_INVALID: |
|
573 // We group all these errors as "cert not trusted" |
|
574 return nsICertOverrideService::ERROR_UNTRUSTED; |
|
575 case SSL_ERROR_BAD_CERT_DOMAIN: |
|
576 return nsICertOverrideService::ERROR_MISMATCH; |
|
577 case SEC_ERROR_EXPIRED_CERTIFICATE: |
|
578 return nsICertOverrideService::ERROR_TIME; |
|
579 default: |
|
580 return 0; |
|
581 } |
|
582 } |
|
583 |
|
584 SECStatus |
|
585 NSSDetermineCertOverrideErrors(CertVerifier& certVerifier, |
|
586 CERTCertificate* cert, |
|
587 const SECItem* stapledOCSPResponse, |
|
588 TransportSecurityInfo* infoObject, |
|
589 PRTime now, |
|
590 PRErrorCode defaultErrorCodeToReport, |
|
591 /*out*/ uint32_t& collectedErrors, |
|
592 /*out*/ PRErrorCode& errorCodeTrust, |
|
593 /*out*/ PRErrorCode& errorCodeMismatch, |
|
594 /*out*/ PRErrorCode& errorCodeExpired) |
|
595 { |
|
596 MOZ_ASSERT(cert); |
|
597 MOZ_ASSERT(infoObject); |
|
598 MOZ_ASSERT(defaultErrorCodeToReport != 0); |
|
599 MOZ_ASSERT(collectedErrors == 0); |
|
600 MOZ_ASSERT(errorCodeTrust == 0); |
|
601 MOZ_ASSERT(errorCodeMismatch == 0); |
|
602 MOZ_ASSERT(errorCodeExpired == 0); |
|
603 |
|
604 if (defaultErrorCodeToReport == 0) { |
|
605 NS_ERROR("No error code set during certificate validation failure."); |
|
606 PR_SetError(PR_INVALID_STATE_ERROR, 0); |
|
607 return SECFailure; |
|
608 } |
|
609 |
|
610 // We only allow overrides for certain errors. Return early if the error |
|
611 // is not one of them. This is to avoid doing revocation fetching in the |
|
612 // case of OCSP stapling and probably for other reasons. |
|
613 if (PRErrorCodeToOverrideType(defaultErrorCodeToReport) == 0) { |
|
614 PR_SetError(defaultErrorCodeToReport, 0); |
|
615 return SECFailure; |
|
616 } |
|
617 |
|
618 PLArenaPool* log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
619 PLArenaPoolCleanerFalseParam log_arena_cleaner(log_arena); |
|
620 if (!log_arena) { |
|
621 NS_ERROR("PORT_NewArena failed"); |
|
622 return SECFailure; // PORT_NewArena set error code |
|
623 } |
|
624 |
|
625 CERTVerifyLog* verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog); |
|
626 if (!verify_log) { |
|
627 NS_ERROR("PORT_ArenaZNew failed"); |
|
628 return SECFailure; // PORT_ArenaZNew set error code |
|
629 } |
|
630 CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log); |
|
631 verify_log->arena = log_arena; |
|
632 |
|
633 // We ignore the result code of the cert verification (i.e. VerifyCert's rv) |
|
634 // Either it is a failure, which is expected, and we'll process the |
|
635 // verify log below. |
|
636 // Or it is a success, then a domain mismatch is the only |
|
637 // possible failure. |
|
638 // XXX TODO: convert to VerifySSLServerCert |
|
639 // XXX TODO: get rid of error log |
|
640 certVerifier.VerifyCert(cert, certificateUsageSSLServer, |
|
641 now, infoObject, infoObject->GetHostNameRaw(), |
|
642 0, stapledOCSPResponse, nullptr, nullptr, verify_log); |
|
643 |
|
644 // Check the name field against the desired hostname. |
|
645 if (CERT_VerifyCertName(cert, infoObject->GetHostNameRaw()) != SECSuccess) { |
|
646 collectedErrors |= nsICertOverrideService::ERROR_MISMATCH; |
|
647 errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN; |
|
648 } |
|
649 |
|
650 CERTVerifyLogNode* i_node; |
|
651 for (i_node = verify_log->head; i_node; i_node = i_node->next) { |
|
652 uint32_t overrideType = PRErrorCodeToOverrideType(i_node->error); |
|
653 // If this isn't an overridable error, set the error and return. |
|
654 if (overrideType == 0) { |
|
655 PR_SetError(i_node->error, 0); |
|
656 return SECFailure; |
|
657 } |
|
658 collectedErrors |= overrideType; |
|
659 if (overrideType == nsICertOverrideService::ERROR_UNTRUSTED) { |
|
660 if (errorCodeTrust == 0) { |
|
661 errorCodeTrust = i_node->error; |
|
662 } |
|
663 } else if (overrideType == nsICertOverrideService::ERROR_MISMATCH) { |
|
664 if (errorCodeMismatch == 0) { |
|
665 errorCodeMismatch = i_node->error; |
|
666 } |
|
667 } else if (overrideType == nsICertOverrideService::ERROR_TIME) { |
|
668 if (errorCodeExpired == 0) { |
|
669 errorCodeExpired = i_node->error; |
|
670 } |
|
671 } else { |
|
672 MOZ_CRASH("unexpected return value from PRErrorCodeToOverrideType"); |
|
673 } |
|
674 } |
|
675 |
|
676 return SECSuccess; |
|
677 } |
|
678 |
|
679 // Returns null with the error code (PR_GetError()) set if it does not create |
|
680 // the CertErrorRunnable. |
|
681 CertErrorRunnable* |
|
682 CreateCertErrorRunnable(CertVerifier& certVerifier, |
|
683 PRErrorCode defaultErrorCodeToReport, |
|
684 TransportSecurityInfo* infoObject, |
|
685 CERTCertificate* cert, |
|
686 const SECItem* stapledOCSPResponse, |
|
687 const void* fdForLogging, |
|
688 uint32_t providerFlags, |
|
689 PRTime now) |
|
690 { |
|
691 MOZ_ASSERT(infoObject); |
|
692 MOZ_ASSERT(cert); |
|
693 |
|
694 uint32_t collected_errors = 0; |
|
695 PRErrorCode errorCodeTrust = 0; |
|
696 PRErrorCode errorCodeMismatch = 0; |
|
697 PRErrorCode errorCodeExpired = 0; |
|
698 |
|
699 SECStatus rv; |
|
700 switch (certVerifier.mImplementation) { |
|
701 case CertVerifier::classic: |
|
702 #ifndef NSS_NO_LIBPKIX |
|
703 case CertVerifier::libpkix: |
|
704 #endif |
|
705 rv = NSSDetermineCertOverrideErrors(certVerifier, cert, stapledOCSPResponse, |
|
706 infoObject, now, |
|
707 defaultErrorCodeToReport, |
|
708 collected_errors, errorCodeTrust, |
|
709 errorCodeMismatch, errorCodeExpired); |
|
710 break; |
|
711 |
|
712 case CertVerifier::mozillapkix: |
|
713 rv = MozillaPKIXDetermineCertOverrideErrors(cert, |
|
714 infoObject->GetHostNameRaw(), |
|
715 now, defaultErrorCodeToReport, |
|
716 collected_errors, |
|
717 errorCodeTrust, |
|
718 errorCodeMismatch, |
|
719 errorCodeExpired); |
|
720 break; |
|
721 |
|
722 default: |
|
723 MOZ_CRASH("unexpected CertVerifier implementation"); |
|
724 PR_SetError(defaultErrorCodeToReport, 0); |
|
725 return nullptr; |
|
726 |
|
727 } |
|
728 if (rv != SECSuccess) { |
|
729 return nullptr; |
|
730 } |
|
731 |
|
732 RefPtr<nsNSSCertificate> nssCert(nsNSSCertificate::Create(cert)); |
|
733 if (!nssCert) { |
|
734 NS_ERROR("nsNSSCertificate::Create failed"); |
|
735 PR_SetError(SEC_ERROR_NO_MEMORY, 0); |
|
736 return nullptr; |
|
737 } |
|
738 |
|
739 if (!collected_errors) { |
|
740 // This will happen when CERT_*Verify* only returned error(s) that are |
|
741 // not on our whitelist of overridable certificate errors. |
|
742 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n", |
|
743 fdForLogging, static_cast<int>(defaultErrorCodeToReport))); |
|
744 PR_SetError(defaultErrorCodeToReport, 0); |
|
745 return nullptr; |
|
746 } |
|
747 |
|
748 infoObject->SetStatusErrorBits(*nssCert, collected_errors); |
|
749 |
|
750 return new CertErrorRunnable(fdForLogging, |
|
751 static_cast<nsIX509Cert*>(nssCert.get()), |
|
752 infoObject, defaultErrorCodeToReport, |
|
753 collected_errors, errorCodeTrust, |
|
754 errorCodeMismatch, errorCodeExpired, |
|
755 providerFlags); |
|
756 } |
|
757 |
|
758 // When doing async cert processing, we dispatch one of these runnables to the |
|
759 // socket transport service thread, which blocks the socket transport |
|
760 // service thread while it waits for the inner CertErrorRunnable to execute |
|
761 // CheckCertOverrides on the main thread. CheckCertOverrides must block events |
|
762 // on both of these threads because it calls TransportSecurityInfo::GetInterface(), |
|
763 // which may call nsHttpConnection::GetInterface() through |
|
764 // TransportSecurityInfo::mCallbacks. nsHttpConnection::GetInterface must always |
|
765 // execute on the main thread, with the socket transport service thread |
|
766 // blocked. |
|
767 class CertErrorRunnableRunnable : public nsRunnable |
|
768 { |
|
769 public: |
|
770 CertErrorRunnableRunnable(CertErrorRunnable* certErrorRunnable) |
|
771 : mCertErrorRunnable(certErrorRunnable) |
|
772 { |
|
773 } |
|
774 private: |
|
775 NS_IMETHOD Run() |
|
776 { |
|
777 nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait(); |
|
778 // The result must run on the socket transport thread, which we are already |
|
779 // on, so we can just run it directly, instead of dispatching it. |
|
780 if (NS_SUCCEEDED(rv)) { |
|
781 rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run() |
|
782 : NS_ERROR_UNEXPECTED; |
|
783 } |
|
784 return rv; |
|
785 } |
|
786 RefPtr<CertErrorRunnable> mCertErrorRunnable; |
|
787 }; |
|
788 |
|
789 class SSLServerCertVerificationJob : public nsRunnable |
|
790 { |
|
791 public: |
|
792 // Must be called only on the socket transport thread |
|
793 static SECStatus Dispatch(const RefPtr<SharedCertVerifier>& certVerifier, |
|
794 const void* fdForLogging, |
|
795 TransportSecurityInfo* infoObject, |
|
796 CERTCertificate* serverCert, |
|
797 SECItem* stapledOCSPResponse, |
|
798 uint32_t providerFlags, |
|
799 PRTime time); |
|
800 private: |
|
801 NS_DECL_NSIRUNNABLE |
|
802 |
|
803 // Must be called only on the socket transport thread |
|
804 SSLServerCertVerificationJob(const RefPtr<SharedCertVerifier>& certVerifier, |
|
805 const void* fdForLogging, |
|
806 TransportSecurityInfo* infoObject, |
|
807 CERTCertificate* cert, |
|
808 SECItem* stapledOCSPResponse, |
|
809 uint32_t providerFlags, |
|
810 PRTime time); |
|
811 const RefPtr<SharedCertVerifier> mCertVerifier; |
|
812 const void* const mFdForLogging; |
|
813 const RefPtr<TransportSecurityInfo> mInfoObject; |
|
814 const mozilla::pkix::ScopedCERTCertificate mCert; |
|
815 const uint32_t mProviderFlags; |
|
816 const PRTime mTime; |
|
817 const TimeStamp mJobStartTime; |
|
818 const ScopedSECItem mStapledOCSPResponse; |
|
819 }; |
|
820 |
|
821 SSLServerCertVerificationJob::SSLServerCertVerificationJob( |
|
822 const RefPtr<SharedCertVerifier>& certVerifier, const void* fdForLogging, |
|
823 TransportSecurityInfo* infoObject, CERTCertificate* cert, |
|
824 SECItem* stapledOCSPResponse, uint32_t providerFlags, PRTime time) |
|
825 : mCertVerifier(certVerifier) |
|
826 , mFdForLogging(fdForLogging) |
|
827 , mInfoObject(infoObject) |
|
828 , mCert(CERT_DupCertificate(cert)) |
|
829 , mProviderFlags(providerFlags) |
|
830 , mTime(time) |
|
831 , mJobStartTime(TimeStamp::Now()) |
|
832 , mStapledOCSPResponse(SECITEM_DupItem(stapledOCSPResponse)) |
|
833 { |
|
834 } |
|
835 |
|
836 // This function assumes that we will only use the SPDY connection coalescing |
|
837 // feature on connections where we have negotiated SPDY using NPN. If we ever |
|
838 // talk SPDY without having negotiated it with SPDY, this code will give wrong |
|
839 // and perhaps unsafe results. |
|
840 // |
|
841 // Returns SECSuccess on the initial handshake of all connections, on |
|
842 // renegotiations for any connections where we did not negotiate SPDY, or on any |
|
843 // SPDY connection where the server's certificate did not change. |
|
844 // |
|
845 // Prohibit changing the server cert only if we negotiated SPDY, |
|
846 // in order to support SPDY's cross-origin connection pooling. |
|
847 static SECStatus |
|
848 BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject, |
|
849 CERTCertificate* serverCert) |
|
850 { |
|
851 // Get the existing cert. If there isn't one, then there is |
|
852 // no cert change to worry about. |
|
853 nsCOMPtr<nsIX509Cert> cert; |
|
854 nsCOMPtr<nsIX509Cert2> cert2; |
|
855 |
|
856 RefPtr<nsSSLStatus> status(infoObject->SSLStatus()); |
|
857 if (!status) { |
|
858 // If we didn't have a status, then this is the |
|
859 // first handshake on this connection, not a |
|
860 // renegotiation. |
|
861 return SECSuccess; |
|
862 } |
|
863 |
|
864 status->GetServerCert(getter_AddRefs(cert)); |
|
865 cert2 = do_QueryInterface(cert); |
|
866 if (!cert2) { |
|
867 NS_NOTREACHED("every nsSSLStatus must have a cert" |
|
868 "that implements nsIX509Cert2"); |
|
869 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); |
|
870 return SECFailure; |
|
871 } |
|
872 |
|
873 // Filter out sockets that did not neogtiate SPDY via NPN |
|
874 nsAutoCString negotiatedNPN; |
|
875 nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN); |
|
876 NS_ASSERTION(NS_SUCCEEDED(rv), |
|
877 "GetNegotiatedNPN() failed during renegotiation"); |
|
878 |
|
879 if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN, |
|
880 NS_LITERAL_CSTRING("spdy/"))) |
|
881 return SECSuccess; |
|
882 |
|
883 // If GetNegotiatedNPN() failed we will assume spdy for safety's safe |
|
884 if (NS_FAILED(rv)) { |
|
885 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
886 ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call." |
|
887 " Assuming spdy.\n")); |
|
888 } |
|
889 |
|
890 // Check to see if the cert has actually changed |
|
891 ScopedCERTCertificate c(cert2->GetCert()); |
|
892 NS_ASSERTION(c, "very bad and hopefully impossible state"); |
|
893 bool sameCert = CERT_CompareCerts(c, serverCert); |
|
894 if (sameCert) |
|
895 return SECSuccess; |
|
896 |
|
897 // Report an error - changed cert is confirmed |
|
898 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
899 ("SPDY Refused to allow new cert during renegotiation\n")); |
|
900 PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0); |
|
901 return SECFailure; |
|
902 } |
|
903 |
|
904 SECStatus |
|
905 AuthCertificate(CertVerifier& certVerifier, TransportSecurityInfo* infoObject, |
|
906 CERTCertificate* cert, SECItem* stapledOCSPResponse, |
|
907 uint32_t providerFlags, PRTime time) |
|
908 { |
|
909 MOZ_ASSERT(infoObject); |
|
910 MOZ_ASSERT(cert); |
|
911 |
|
912 SECStatus rv; |
|
913 |
|
914 // TODO: Remove this after we switch to mozilla::pkix as the |
|
915 // only option |
|
916 if (certVerifier.mImplementation == CertVerifier::classic) { |
|
917 if (stapledOCSPResponse) { |
|
918 CERTCertDBHandle* handle = CERT_GetDefaultCertDB(); |
|
919 rv = CERT_CacheOCSPResponseFromSideChannel(handle, cert, PR_Now(), |
|
920 stapledOCSPResponse, |
|
921 infoObject); |
|
922 if (rv != SECSuccess) { |
|
923 // Due to buggy servers that will staple expired OCSP responses |
|
924 // (see for example http://trac.nginx.org/nginx/ticket/425), |
|
925 // don't terminate the connection if the stapled response is expired. |
|
926 // We will fall back to fetching revocation information. |
|
927 PRErrorCode ocspErrorCode = PR_GetError(); |
|
928 if (ocspErrorCode != SEC_ERROR_OCSP_OLD_RESPONSE) { |
|
929 // stapled OCSP response present but invalid for some reason |
|
930 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 4); |
|
931 return rv; |
|
932 } else { |
|
933 // stapled OCSP response present but expired |
|
934 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 3); |
|
935 } |
|
936 } else { |
|
937 // stapled OCSP response present and good |
|
938 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 1); |
|
939 } |
|
940 } else { |
|
941 // no stapled OCSP response |
|
942 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 2); |
|
943 |
|
944 uint32_t reasonsForNotFetching = 0; |
|
945 |
|
946 char* ocspURI = CERT_GetOCSPAuthorityInfoAccessLocation(cert); |
|
947 if (!ocspURI) { |
|
948 reasonsForNotFetching |= 1; // invalid/missing OCSP URI |
|
949 } else { |
|
950 if (std::strncmp(ocspURI, "http://", 7)) { // approximation |
|
951 reasonsForNotFetching |= 1; // invalid/missing OCSP URI |
|
952 } |
|
953 PORT_Free(ocspURI); |
|
954 } |
|
955 |
|
956 if (!certVerifier.mOCSPDownloadEnabled) { |
|
957 reasonsForNotFetching |= 2; |
|
958 } |
|
959 |
|
960 Telemetry::Accumulate(Telemetry::SSL_OCSP_MAY_FETCH, |
|
961 reasonsForNotFetching); |
|
962 } |
|
963 } |
|
964 |
|
965 // We want to avoid storing any intermediate cert information when browsing |
|
966 // in private, transient contexts. |
|
967 bool saveIntermediates = |
|
968 !(providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE); |
|
969 |
|
970 mozilla::pkix::ScopedCERTCertList certList; |
|
971 SECOidTag evOidPolicy; |
|
972 rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse, |
|
973 time, infoObject, |
|
974 infoObject->GetHostNameRaw(), |
|
975 saveIntermediates, nullptr, |
|
976 &evOidPolicy); |
|
977 |
|
978 // We want to remember the CA certs in the temp db, so that the application can find the |
|
979 // complete chain at any time it might need it. |
|
980 // But we keep only those CA certs in the temp db, that we didn't already know. |
|
981 |
|
982 RefPtr<nsSSLStatus> status(infoObject->SSLStatus()); |
|
983 RefPtr<nsNSSCertificate> nsc; |
|
984 |
|
985 if (!status || !status->mServerCert) { |
|
986 if( rv == SECSuccess ){ |
|
987 nsc = nsNSSCertificate::Create(cert, &evOidPolicy); |
|
988 } |
|
989 else { |
|
990 nsc = nsNSSCertificate::Create(cert); |
|
991 } |
|
992 } |
|
993 |
|
994 if (rv == SECSuccess) { |
|
995 // The connection may get terminated, for example, if the server requires |
|
996 // a client cert. Let's provide a minimal SSLStatus |
|
997 // to the caller that contains at least the cert and its status. |
|
998 if (!status) { |
|
999 status = new nsSSLStatus(); |
|
1000 infoObject->SetSSLStatus(status); |
|
1001 } |
|
1002 |
|
1003 if (rv == SECSuccess) { |
|
1004 // Certificate verification succeeded delete any potential record |
|
1005 // of certificate error bits. |
|
1006 RememberCertErrorsTable::GetInstance().RememberCertHasError(infoObject, |
|
1007 nullptr, rv); |
|
1008 } |
|
1009 else { |
|
1010 // Certificate verification failed, update the status' bits. |
|
1011 RememberCertErrorsTable::GetInstance().LookupCertErrorBits( |
|
1012 infoObject, status); |
|
1013 } |
|
1014 |
|
1015 if (status && !status->mServerCert) { |
|
1016 status->mServerCert = nsc; |
|
1017 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
1018 ("AuthCertificate setting NEW cert %p\n", status->mServerCert.get())); |
|
1019 } |
|
1020 } |
|
1021 |
|
1022 return rv; |
|
1023 } |
|
1024 |
|
1025 /*static*/ SECStatus |
|
1026 SSLServerCertVerificationJob::Dispatch( |
|
1027 const RefPtr<SharedCertVerifier>& certVerifier, |
|
1028 const void* fdForLogging, |
|
1029 TransportSecurityInfo* infoObject, |
|
1030 CERTCertificate* serverCert, |
|
1031 SECItem* stapledOCSPResponse, |
|
1032 uint32_t providerFlags, |
|
1033 PRTime time) |
|
1034 { |
|
1035 // Runs on the socket transport thread |
|
1036 if (!certVerifier || !infoObject || !serverCert) { |
|
1037 NS_ERROR("Invalid parameters for SSL server cert validation"); |
|
1038 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); |
|
1039 return SECFailure; |
|
1040 } |
|
1041 |
|
1042 RefPtr<SSLServerCertVerificationJob> job( |
|
1043 new SSLServerCertVerificationJob(certVerifier, fdForLogging, infoObject, |
|
1044 serverCert, stapledOCSPResponse, |
|
1045 providerFlags, time)); |
|
1046 |
|
1047 nsresult nrv; |
|
1048 if (!gCertVerificationThreadPool) { |
|
1049 nrv = NS_ERROR_NOT_INITIALIZED; |
|
1050 } else { |
|
1051 nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL); |
|
1052 } |
|
1053 if (NS_FAILED(nrv)) { |
|
1054 // We can't call SetCertVerificationResult here to change |
|
1055 // mCertVerificationState because SetCertVerificationResult will call |
|
1056 // libssl functions that acquire SSL locks that are already being held at |
|
1057 // this point. infoObject->mCertVerificationState will be stuck at |
|
1058 // waiting_for_cert_verification here, but that is OK because we already |
|
1059 // have to be able to handle cases where we encounter non-cert errors while |
|
1060 // in that state. |
|
1061 PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY |
|
1062 ? SEC_ERROR_NO_MEMORY |
|
1063 : PR_INVALID_STATE_ERROR; |
|
1064 PORT_SetError(error); |
|
1065 return SECFailure; |
|
1066 } |
|
1067 |
|
1068 PORT_SetError(PR_WOULD_BLOCK_ERROR); |
|
1069 return SECWouldBlock; |
|
1070 } |
|
1071 |
|
1072 NS_IMETHODIMP |
|
1073 SSLServerCertVerificationJob::Run() |
|
1074 { |
|
1075 // Runs on a cert verification thread |
|
1076 |
|
1077 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
1078 ("[%p] SSLServerCertVerificationJob::Run\n", mInfoObject.get())); |
|
1079 |
|
1080 PRErrorCode error; |
|
1081 |
|
1082 nsNSSShutDownPreventionLock nssShutdownPrevention; |
|
1083 if (mInfoObject->isAlreadyShutDown()) { |
|
1084 error = SEC_ERROR_USER_CANCELLED; |
|
1085 } else { |
|
1086 Telemetry::ID successTelemetry; |
|
1087 Telemetry::ID failureTelemetry; |
|
1088 switch (mCertVerifier->mImplementation) { |
|
1089 case CertVerifier::classic: |
|
1090 successTelemetry |
|
1091 = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_CLASSIC; |
|
1092 failureTelemetry |
|
1093 = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_CLASSIC; |
|
1094 break; |
|
1095 case CertVerifier::mozillapkix: |
|
1096 successTelemetry |
|
1097 = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX; |
|
1098 failureTelemetry |
|
1099 = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX; |
|
1100 break; |
|
1101 #ifndef NSS_NO_LIBPKIX |
|
1102 case CertVerifier::libpkix: |
|
1103 successTelemetry |
|
1104 = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_LIBPKIX; |
|
1105 failureTelemetry |
|
1106 = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_LIBPKIX; |
|
1107 break; |
|
1108 #endif |
|
1109 default: |
|
1110 MOZ_CRASH("Unknown CertVerifier mode"); |
|
1111 } |
|
1112 |
|
1113 // XXX |
|
1114 // Reset the error code here so we can detect if AuthCertificate fails to |
|
1115 // set the error code if/when it fails. |
|
1116 PR_SetError(0, 0); |
|
1117 SECStatus rv = AuthCertificate(*mCertVerifier, mInfoObject, mCert.get(), |
|
1118 mStapledOCSPResponse, mProviderFlags, |
|
1119 mTime); |
|
1120 if (rv == SECSuccess) { |
|
1121 uint32_t interval = (uint32_t) ((TimeStamp::Now() - mJobStartTime).ToMilliseconds()); |
|
1122 RefPtr<SSLServerCertVerificationResult> restart( |
|
1123 new SSLServerCertVerificationResult(mInfoObject, 0, |
|
1124 successTelemetry, interval)); |
|
1125 restart->Dispatch(); |
|
1126 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1); |
|
1127 return NS_OK; |
|
1128 } |
|
1129 |
|
1130 // Note: the interval is not calculated once as PR_GetError MUST be called |
|
1131 // before any other function call |
|
1132 error = PR_GetError(); |
|
1133 { |
|
1134 TimeStamp now = TimeStamp::Now(); |
|
1135 MutexAutoLock telemetryMutex(*gSSLVerificationTelemetryMutex); |
|
1136 Telemetry::AccumulateTimeDelta(failureTelemetry, mJobStartTime, now); |
|
1137 } |
|
1138 if (error != 0) { |
|
1139 RefPtr<CertErrorRunnable> runnable( |
|
1140 CreateCertErrorRunnable(*mCertVerifier, error, mInfoObject, |
|
1141 mCert.get(), mStapledOCSPResponse, |
|
1142 mFdForLogging, mProviderFlags, mTime)); |
|
1143 if (!runnable) { |
|
1144 // CreateCertErrorRunnable set a new error code |
|
1145 error = PR_GetError(); |
|
1146 } else { |
|
1147 // We must block the the socket transport service thread while the |
|
1148 // main thread executes the CertErrorRunnable. The CertErrorRunnable |
|
1149 // will dispatch the result asynchronously, so we don't have to block |
|
1150 // this thread waiting for it. |
|
1151 |
|
1152 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
1153 ("[%p][%p] Before dispatching CertErrorRunnable\n", |
|
1154 mFdForLogging, runnable.get())); |
|
1155 |
|
1156 nsresult nrv; |
|
1157 nsCOMPtr<nsIEventTarget> stsTarget |
|
1158 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv); |
|
1159 if (NS_SUCCEEDED(nrv)) { |
|
1160 nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable), |
|
1161 NS_DISPATCH_NORMAL); |
|
1162 } |
|
1163 if (NS_SUCCEEDED(nrv)) { |
|
1164 return NS_OK; |
|
1165 } |
|
1166 |
|
1167 NS_ERROR("Failed to dispatch CertErrorRunnable"); |
|
1168 error = PR_INVALID_STATE_ERROR; |
|
1169 } |
|
1170 } |
|
1171 } |
|
1172 |
|
1173 if (error == 0) { |
|
1174 NS_NOTREACHED("no error set during certificate validation failure"); |
|
1175 error = PR_INVALID_STATE_ERROR; |
|
1176 } |
|
1177 |
|
1178 RefPtr<SSLServerCertVerificationResult> failure( |
|
1179 new SSLServerCertVerificationResult(mInfoObject, error)); |
|
1180 failure->Dispatch(); |
|
1181 return NS_OK; |
|
1182 } |
|
1183 |
|
1184 } // unnamed namespace |
|
1185 |
|
1186 // Extracts whatever information we need out of fd (using SSL_*) and passes it |
|
1187 // to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should |
|
1188 // never do anything with fd except logging. |
|
1189 SECStatus |
|
1190 AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer) |
|
1191 { |
|
1192 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); |
|
1193 if (!certVerifier) { |
|
1194 PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0); |
|
1195 return SECFailure; |
|
1196 } |
|
1197 |
|
1198 // Runs on the socket transport thread |
|
1199 |
|
1200 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, |
|
1201 ("[%p] starting AuthCertificateHook\n", fd)); |
|
1202 |
|
1203 // Modern libssl always passes PR_TRUE for checkSig, and we have no means of |
|
1204 // doing verification without checking signatures. |
|
1205 NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false"); |
|
1206 |
|
1207 // PSM never causes libssl to call this function with PR_TRUE for isServer, |
|
1208 // and many things in PSM assume that we are a client. |
|
1209 NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true"); |
|
1210 |
|
1211 nsNSSSocketInfo* socketInfo = static_cast<nsNSSSocketInfo*>(arg); |
|
1212 |
|
1213 ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd)); |
|
1214 |
|
1215 if (!checkSig || isServer || !socketInfo || !serverCert) { |
|
1216 PR_SetError(PR_INVALID_STATE_ERROR, 0); |
|
1217 return SECFailure; |
|
1218 } |
|
1219 |
|
1220 socketInfo->SetFullHandshake(); |
|
1221 |
|
1222 // This value of "now" is used both here for OCSP stapling and later |
|
1223 // when calling CreateCertErrorRunnable. |
|
1224 PRTime now = PR_Now(); |
|
1225 |
|
1226 if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess) |
|
1227 return SECFailure; |
|
1228 |
|
1229 bool onSTSThread; |
|
1230 nsresult nrv; |
|
1231 nsCOMPtr<nsIEventTarget> sts |
|
1232 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv); |
|
1233 if (NS_SUCCEEDED(nrv)) { |
|
1234 nrv = sts->IsOnCurrentThread(&onSTSThread); |
|
1235 } |
|
1236 |
|
1237 if (NS_FAILED(nrv)) { |
|
1238 NS_ERROR("Could not get STS service or IsOnCurrentThread failed"); |
|
1239 PR_SetError(PR_UNKNOWN_ERROR, 0); |
|
1240 return SECFailure; |
|
1241 } |
|
1242 |
|
1243 // SSL_PeerStapledOCSPResponses will never return a non-empty response if |
|
1244 // OCSP stapling wasn't enabled because libssl wouldn't have let the server |
|
1245 // return a stapled OCSP response. |
|
1246 // We don't own these pointers. |
|
1247 const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd); |
|
1248 SECItem* stapledOCSPResponse = nullptr; |
|
1249 // we currently only support single stapled responses |
|
1250 if (csa && csa->len == 1) { |
|
1251 stapledOCSPResponse = &csa->items[0]; |
|
1252 } |
|
1253 |
|
1254 uint32_t providerFlags = 0; |
|
1255 socketInfo->GetProviderFlags(&providerFlags); |
|
1256 |
|
1257 if (onSTSThread) { |
|
1258 |
|
1259 // We *must* do certificate verification on a background thread because |
|
1260 // we need the socket transport thread to be free for our OCSP requests, |
|
1261 // and we *want* to do certificate verification on a background thread |
|
1262 // because of the performance benefits of doing so. |
|
1263 socketInfo->SetCertVerificationWaiting(); |
|
1264 SECStatus rv = SSLServerCertVerificationJob::Dispatch( |
|
1265 certVerifier, static_cast<const void*>(fd), socketInfo, |
|
1266 serverCert, stapledOCSPResponse, providerFlags, now); |
|
1267 return rv; |
|
1268 } |
|
1269 |
|
1270 // We can't do certificate verification on a background thread, because the |
|
1271 // thread doing the network I/O may not interrupt its network I/O on receipt |
|
1272 // of our SSLServerCertVerificationResult event, and/or it might not even be |
|
1273 // a non-blocking socket. |
|
1274 |
|
1275 SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert, |
|
1276 stapledOCSPResponse, providerFlags, now); |
|
1277 if (rv == SECSuccess) { |
|
1278 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1); |
|
1279 return SECSuccess; |
|
1280 } |
|
1281 |
|
1282 PRErrorCode error = PR_GetError(); |
|
1283 if (error != 0) { |
|
1284 RefPtr<CertErrorRunnable> runnable( |
|
1285 CreateCertErrorRunnable(*certVerifier, error, socketInfo, serverCert, |
|
1286 stapledOCSPResponse, |
|
1287 static_cast<const void*>(fd), providerFlags, |
|
1288 now)); |
|
1289 if (!runnable) { |
|
1290 // CreateCertErrorRunnable sets a new error code when it fails |
|
1291 error = PR_GetError(); |
|
1292 } else { |
|
1293 // We have to return SECSuccess or SECFailure based on the result of the |
|
1294 // override processing, so we must block this thread waiting for it. The |
|
1295 // CertErrorRunnable will NOT dispatch the result at all, since we passed |
|
1296 // false for CreateCertErrorRunnable's async parameter |
|
1297 nrv = runnable->DispatchToMainThreadAndWait(); |
|
1298 if (NS_FAILED(nrv)) { |
|
1299 NS_ERROR("Failed to dispatch CertErrorRunnable"); |
|
1300 PR_SetError(PR_INVALID_STATE_ERROR, 0); |
|
1301 return SECFailure; |
|
1302 } |
|
1303 |
|
1304 if (!runnable->mResult) { |
|
1305 NS_ERROR("CertErrorRunnable did not set result"); |
|
1306 PR_SetError(PR_INVALID_STATE_ERROR, 0); |
|
1307 return SECFailure; |
|
1308 } |
|
1309 |
|
1310 if (runnable->mResult->mErrorCode == 0) { |
|
1311 return SECSuccess; // cert error override occurred. |
|
1312 } |
|
1313 |
|
1314 // We must call SetCanceled here to set the error message type |
|
1315 // in case it isn't PlainErrorMessage, which is what we would |
|
1316 // default to if we just called |
|
1317 // PR_SetError(runnable->mResult->mErrorCode, 0) and returned |
|
1318 // SECFailure without doing this. |
|
1319 socketInfo->SetCanceled(runnable->mResult->mErrorCode, |
|
1320 runnable->mResult->mErrorMessageType); |
|
1321 error = runnable->mResult->mErrorCode; |
|
1322 } |
|
1323 } |
|
1324 |
|
1325 if (error == 0) { |
|
1326 NS_ERROR("error code not set"); |
|
1327 error = PR_UNKNOWN_ERROR; |
|
1328 } |
|
1329 |
|
1330 PR_SetError(error, 0); |
|
1331 return SECFailure; |
|
1332 } |
|
1333 |
|
1334 #ifndef MOZ_NO_EV_CERTS |
|
1335 class InitializeIdentityInfo : public CryptoTask |
|
1336 { |
|
1337 virtual nsresult CalculateResult() MOZ_OVERRIDE |
|
1338 { |
|
1339 EnsureIdentityInfoLoaded(); |
|
1340 return NS_OK; |
|
1341 } |
|
1342 |
|
1343 virtual void ReleaseNSSResources() MOZ_OVERRIDE { } // no-op |
|
1344 virtual void CallCallback(nsresult rv) MOZ_OVERRIDE { } // no-op |
|
1345 }; |
|
1346 #endif |
|
1347 |
|
1348 void EnsureServerVerificationInitialized() |
|
1349 { |
|
1350 #ifndef MOZ_NO_EV_CERTS |
|
1351 // Should only be called from socket transport thread due to the static |
|
1352 // variable and the reference to gCertVerificationThreadPool |
|
1353 |
|
1354 static bool triggeredCertVerifierInit = false; |
|
1355 if (triggeredCertVerifierInit) |
|
1356 return; |
|
1357 triggeredCertVerifierInit = true; |
|
1358 |
|
1359 RefPtr<InitializeIdentityInfo> initJob = new InitializeIdentityInfo(); |
|
1360 if (gCertVerificationThreadPool) |
|
1361 gCertVerificationThreadPool->Dispatch(initJob, NS_DISPATCH_NORMAL); |
|
1362 #endif |
|
1363 } |
|
1364 |
|
1365 SSLServerCertVerificationResult::SSLServerCertVerificationResult( |
|
1366 TransportSecurityInfo* infoObject, PRErrorCode errorCode, |
|
1367 Telemetry::ID telemetryID, uint32_t telemetryValue, |
|
1368 SSLErrorMessageType errorMessageType) |
|
1369 : mInfoObject(infoObject) |
|
1370 , mErrorCode(errorCode) |
|
1371 , mErrorMessageType(errorMessageType) |
|
1372 , mTelemetryID(telemetryID) |
|
1373 , mTelemetryValue(telemetryValue) |
|
1374 { |
|
1375 // We accumulate telemetry for (only) successful validations on the main thread |
|
1376 // to avoid adversely affecting performance by acquiring the mutex that we use |
|
1377 // when accumulating the telemetry for unsuccessful validations. Unsuccessful |
|
1378 // validations times are accumulated elsewhere. |
|
1379 MOZ_ASSERT(telemetryID == Telemetry::HistogramCount || errorCode == 0); |
|
1380 } |
|
1381 |
|
1382 void |
|
1383 SSLServerCertVerificationResult::Dispatch() |
|
1384 { |
|
1385 nsresult rv; |
|
1386 nsCOMPtr<nsIEventTarget> stsTarget |
|
1387 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
|
1388 NS_ASSERTION(stsTarget, |
|
1389 "Failed to get socket transport service event target"); |
|
1390 rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL); |
|
1391 NS_ASSERTION(NS_SUCCEEDED(rv), |
|
1392 "Failed to dispatch SSLServerCertVerificationResult"); |
|
1393 } |
|
1394 |
|
1395 NS_IMETHODIMP |
|
1396 SSLServerCertVerificationResult::Run() |
|
1397 { |
|
1398 // TODO: Assert that we're on the socket transport thread |
|
1399 if (mTelemetryID != Telemetry::HistogramCount) { |
|
1400 Telemetry::Accumulate(mTelemetryID, mTelemetryValue); |
|
1401 } |
|
1402 // XXX: This cast will be removed by the next patch |
|
1403 ((nsNSSSocketInfo*) mInfoObject.get()) |
|
1404 ->SetCertVerificationResult(mErrorCode, mErrorMessageType); |
|
1405 return NS_OK; |
|
1406 } |
|
1407 |
|
1408 } } // namespace mozilla::psm |