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 // During certificate authentication, we call CertVerifier::VerifySSLServerCert.
8 // This function may make zero or more HTTP requests (e.g. to gather revocation
9 // information). Our fetching logic for these requests processes them on the
10 // socket transport service thread.
11 //
12 // Because the connection for which we are verifying the certificate is
13 // happening on the socket transport thread, if our cert auth hook were to call
14 // VerifySSLServerCert directly, there would be a deadlock: VerifySSLServerCert
15 // would cause an event to be asynchronously posted to the socket transport
16 // thread, and then it would block the socket transport thread waiting to be
17 // notified of the HTTP response. However, the HTTP request would never actually
18 // be processed because the socket transport thread would be blocked and so it
19 // wouldn't be able process HTTP requests.
20 //
21 // Consequently, when we are asked to verify a certificate, we must always call
22 // VerifySSLServerCert on another thread. To accomplish this, our auth cert hook
23 // dispatches a SSLServerCertVerificationJob to a pool of background threads,
24 // and then immediately returns SECWouldBlock to libssl. These jobs are where
25 // VerifySSLServerCert is actually called.
26 //
27 // When our auth cert hook returns SECWouldBlock, libssl will carry on the
28 // handshake while we validate the certificate. This will free up the socket
29 // transport thread so that HTTP requests--including the OCSP requests needed
30 // for cert verification as mentioned above--can be processed.
31 //
32 // Once VerifySSLServerCert returns, the cert verification job dispatches a
33 // SSLServerCertVerificationResult to the socket transport thread; the
34 // SSLServerCertVerificationResult will notify libssl that the certificate
35 // authentication is complete. Once libssl is notified that the authentication
36 // is complete, it will continue the TLS handshake (if it hasn't already
37 // finished) and it will begin allowing us to send/receive data on the
38 // connection.
39 //
40 // Timeline of events (for connections managed by the socket transport service):
41 //
42 //    * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
43 //      transport thread.
44 //    * SSLServerCertVerificationJob::Dispatch queues a job
45 //      (instance of SSLServerCertVerificationJob) to its background thread
46 //      pool and returns.
47 //    * One of the background threads calls CertVerifier::VerifySSLServerCert,
48 //      which may enqueue some HTTP request(s) onto the socket transport thread,
49 //      and then blocks that background thread waiting for the responses and/or
50 //      timeouts or errors for those requests.
51 //    * Once those HTTP responses have all come back or failed, the
52 //      CertVerifier::VerifySSLServerCert function returns a result indicating
53 //      that the validation succeeded or failed.
54 //    * If the validation succeeded, then a SSLServerCertVerificationResult
55 //      event is posted to the socket transport thread, and the cert
56 //      verification thread becomes free to verify other certificates.
57 //    * Otherwise, we do cert override processing to see if the validation
58 //      error can be convered by override rules. The result of this processing
59 //      is similarly dispatched in a SSLServerCertVerificationResult.
60 //    * The SSLServerCertVerificationResult event will either wake up the
61 //      socket (using SSL_AuthCertificateComplete) if validation succeeded or
62 //      there was an error override, or it will set an error flag so that the
63 //      next I/O operation on the socket will fail, causing the socket transport
64 //      thread to close the connection.
65 //
66 // SSLServerCertVerificationResult must be dispatched to the socket transport
67 // thread because we must only call SSL_* functions on the socket transport
68 // thread since they may do I/O, because many parts of nsNSSSocketInfo (the
69 // subclass of TransportSecurityInfo used when validating certificates during
70 // an SSL handshake) and the PSM NSS I/O layer are not thread-safe, and because
71 // we need the event to interrupt the PR_Poll that may waiting for I/O on the
72 // socket for which we are validating the cert.
73 //
74 // When socket process is enabled, libssl is running on socket process. To
75 // perform certificate authentication with CertVerifier, we have to send all
76 // needed information to parent process and send the result back to socket
77 // process via IPC. The workflow is described below.
78 // 1. In AuthCertificateHookInternal(), we call RemoteProcessCertVerification()
79 //    instead of SSLServerCertVerificationJob::Dispatch when we are on socket
80 //    process.
81 // 2. In RemoteProcessCertVerification(), PVerifySSLServerCert actors will be
82 //    created on IPDL background thread for carrying needed information via IPC.
83 // 3. On parent process, VerifySSLServerCertParent is created and it calls
84 //    SSLServerCertVerificationJob::Dispatch for doing certificate verification
85 //    on one of CertVerificationThreads.
86 // 4. When validation is done, OnVerifiedSSLServerCertSuccess IPC message is
87 //    sent through the IPDL background thread when
88 //    CertVerifier::VerifySSLServerCert returns Success. Otherwise,
89 //    OnVerifiedSSLServerCertFailure is sent.
90 // 5. After setp 4, PVerifySSLServerCert actors will be released. The
91 //    verification result will be dispatched via
92 //    SSLServerCertVerificationResult.
93 
94 #include "SSLServerCertVerification.h"
95 
96 #include <cstring>
97 
98 #include "BRNameMatchingPolicy.h"
99 #include "CertVerifier.h"
100 #include "CryptoTask.h"
101 #include "ExtendedValidation.h"
102 #include "NSSCertDBTrustDomain.h"
103 #include "PSMRunnable.h"
104 #include "RootCertificateTelemetryUtils.h"
105 #include "ScopedNSSTypes.h"
106 #include "SharedCertVerifier.h"
107 #include "SharedSSLState.h"
108 #include "TransportSecurityInfo.h"  // For RememberCertErrorsTable
109 #include "VerifySSLServerCertChild.h"
110 #include "cert.h"
111 #include "mozilla/Assertions.h"
112 #include "mozilla/Casting.h"
113 #include "mozilla/RefPtr.h"
114 #include "mozilla/Telemetry.h"
115 #include "mozilla/UniquePtr.h"
116 #include "mozilla/Unused.h"
117 #include "nsComponentManagerUtils.h"
118 #include "nsContentUtils.h"
119 #include "nsICertOverrideService.h"
120 #include "nsIPublicKeyPinningService.h"
121 #include "nsISiteSecurityService.h"
122 #include "nsISocketProvider.h"
123 #include "nsThreadPool.h"
124 #include "nsNetUtil.h"
125 #include "nsNSSCertificate.h"
126 #include "nsNSSComponent.h"
127 #include "nsNSSIOLayer.h"
128 #include "nsServiceManagerUtils.h"
129 #include "nsString.h"
130 #include "nsURLHelper.h"
131 #include "nsXPCOMCIDInternal.h"
132 #include "mozpkix/pkix.h"
133 #include "mozpkix/pkixcheck.h"
134 #include "mozpkix/pkixnss.h"
135 #include "secerr.h"
136 #include "secport.h"
137 #include "ssl.h"
138 #include "sslerr.h"
139 #include "sslexp.h"
140 
141 extern mozilla::LazyLogModule gPIPNSSLog;
142 
143 using namespace mozilla::pkix;
144 
145 namespace mozilla {
146 namespace psm {
147 
148 namespace {
149 
150 // do not use a nsCOMPtr to avoid static initializer/destructor
151 nsIThreadPool* gCertVerificationThreadPool = nullptr;
152 
153 }  // unnamed namespace
154 
155 // Called when the socket transport thread starts, to initialize the SSL cert
156 // verification thread pool. By tying the thread pool startup/shutdown directly
157 // to the STS thread's lifetime, we ensure that they are *always* available for
158 // SSL connections and that there are no races during startup and especially
159 // shutdown. (Previously, we have had multiple problems with races in PSM
160 // background threads, and the race-prevention/shutdown logic used there is
161 // brittle. Since this service is critical to things like downloading updates,
162 // we take no chances.) Also, by doing things this way, we avoid the need for
163 // locks, since gCertVerificationThreadPool is only ever accessed on the socket
164 // transport thread.
InitializeSSLServerCertVerificationThreads()165 void InitializeSSLServerCertVerificationThreads() {
166   // TODO: tuning, make parameters preferences
167   gCertVerificationThreadPool = new nsThreadPool();
168   NS_ADDREF(gCertVerificationThreadPool);
169 
170   (void)gCertVerificationThreadPool->SetIdleThreadLimit(5);
171   (void)gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
172   (void)gCertVerificationThreadPool->SetThreadLimit(5);
173   (void)gCertVerificationThreadPool->SetName("SSL Cert"_ns);
174 }
175 
176 // Called when the socket transport thread finishes, to destroy the thread
177 // pool. Since the socket transport service has stopped processing events, it
178 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
179 // down the SSL cert verification infrastructure. Also, the STS will not
180 // dispatch many SSL verification result events at this point, so any pending
181 // cert verifications will (correctly) fail at the point they are dispatched.
182 //
183 // The other shutdown race condition that is possible is a race condition with
184 // shutdown of the nsNSSComponent service. We use the
185 // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
StopSSLServerCertVerificationThreads()186 void StopSSLServerCertVerificationThreads() {
187   if (gCertVerificationThreadPool) {
188     gCertVerificationThreadPool->Shutdown();
189     NS_RELEASE(gCertVerificationThreadPool);
190   }
191 }
192 
193 namespace {
194 
195 // A probe value of 1 means "no error".
MapOverridableErrorToProbeValue(PRErrorCode errorCode)196 uint32_t MapOverridableErrorToProbeValue(PRErrorCode errorCode) {
197   switch (errorCode) {
198     case SEC_ERROR_UNKNOWN_ISSUER:
199       return 2;
200     case SEC_ERROR_CA_CERT_INVALID:
201       return 3;
202     case SEC_ERROR_UNTRUSTED_ISSUER:
203       return 4;
204     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
205       return 5;
206     case SEC_ERROR_UNTRUSTED_CERT:
207       return 6;
208     case SEC_ERROR_INADEQUATE_KEY_USAGE:
209       return 7;
210     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
211       return 8;
212     case SSL_ERROR_BAD_CERT_DOMAIN:
213       return 9;
214     case SEC_ERROR_EXPIRED_CERTIFICATE:
215       return 10;
216     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
217       return 11;
218     case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
219       return 12;
220     case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
221       return 13;
222     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
223       return 14;
224     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
225       return 15;
226     case SEC_ERROR_INVALID_TIME:
227       return 16;
228     case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
229       return 17;
230     case mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED:
231       return 18;
232     case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
233       return 19;
234     case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
235       return 20;
236   }
237   NS_WARNING(
238       "Unknown certificate error code. Does MapOverridableErrorToProbeValue "
239       "handle everything in DetermineCertOverrideErrors?");
240   return 0;
241 }
242 
MapCertErrorToProbeValue(PRErrorCode errorCode)243 static uint32_t MapCertErrorToProbeValue(PRErrorCode errorCode) {
244   uint32_t probeValue;
245   switch (errorCode) {
246     // see security/pkix/include/pkix/Result.h
247 #define MOZILLA_PKIX_MAP(name, value, nss_name) \
248   case nss_name:                                \
249     probeValue = value;                         \
250     break;
251     MOZILLA_PKIX_MAP_LIST
252 #undef MOZILLA_PKIX_MAP
253     default:
254       return 0;
255   }
256 
257   // Since FATAL_ERROR_FLAG is 0x800, fatal error values are much larger than
258   // non-fatal error values. To conserve space, we remap these so they start at
259   // (decimal) 90 instead of 0x800. Currently there are ~50 non-fatal errors
260   // mozilla::pkix might return, so saving space for 90 should be sufficient
261   // (similarly, there are 4 fatal errors, so saving space for 10 should also
262   // be sufficient).
263   static_assert(
264       FATAL_ERROR_FLAG == 0x800,
265       "mozilla::pkix::FATAL_ERROR_FLAG is not what we were expecting");
266   if (probeValue & FATAL_ERROR_FLAG) {
267     probeValue ^= FATAL_ERROR_FLAG;
268     probeValue += 90;
269   }
270   return probeValue;
271 }
272 
DetermineCertOverrideErrors(const nsCOMPtr<nsIX509Cert> & cert,const nsACString & hostName,mozilla::pkix::Time now,PRErrorCode defaultErrorCodeToReport,uint32_t & collectedErrors,PRErrorCode & errorCodeTrust,PRErrorCode & errorCodeMismatch,PRErrorCode & errorCodeTime)273 SECStatus DetermineCertOverrideErrors(const nsCOMPtr<nsIX509Cert>& cert,
274                                       const nsACString& hostName,
275                                       mozilla::pkix::Time now,
276                                       PRErrorCode defaultErrorCodeToReport,
277                                       /*out*/ uint32_t& collectedErrors,
278                                       /*out*/ PRErrorCode& errorCodeTrust,
279                                       /*out*/ PRErrorCode& errorCodeMismatch,
280                                       /*out*/ PRErrorCode& errorCodeTime) {
281   MOZ_ASSERT(cert);
282   MOZ_ASSERT(collectedErrors == 0);
283   MOZ_ASSERT(errorCodeTrust == 0);
284   MOZ_ASSERT(errorCodeMismatch == 0);
285   MOZ_ASSERT(errorCodeTime == 0);
286 
287   nsTArray<uint8_t> certDER;
288   if (NS_FAILED(cert->GetRawDER(certDER))) {
289     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
290     return SECFailure;
291   }
292   mozilla::pkix::Input certInput;
293   if (certInput.Init(certDER.Elements(), certDER.Length()) != Success) {
294     PR_SetError(SEC_ERROR_BAD_DER, 0);
295     return SECFailure;
296   }
297 
298   // Assumes the error prioritization described in mozilla::pkix's
299   // BuildForward function. Also assumes that CheckCertHostname was only
300   // called if CertVerifier::VerifyCert succeeded.
301   switch (defaultErrorCodeToReport) {
302     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
303     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
304     case SEC_ERROR_UNKNOWN_ISSUER:
305     case SEC_ERROR_CA_CERT_INVALID:
306     case mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED:
307     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
308     case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
309     case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
310     case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
311     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
312     case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
313     case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA: {
314       collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED;
315       errorCodeTrust = defaultErrorCodeToReport;
316 
317       mozilla::pkix::BackCert backCert(
318           certInput, mozilla::pkix::EndEntityOrCA::MustBeEndEntity, nullptr);
319       Result rv = backCert.Init();
320       if (rv != Success) {
321         MapResultToPRErrorCode(rv);
322         return SECFailure;
323       }
324       mozilla::pkix::Time notBefore(mozilla::pkix::Time::uninitialized);
325       mozilla::pkix::Time notAfter(mozilla::pkix::Time::uninitialized);
326       rv = mozilla::pkix::ParseValidity(backCert.GetValidity(), &notBefore,
327                                         &notAfter);
328       if (rv != Success) {
329         MapResultToPRErrorCode(rv);
330         return SECFailure;
331       }
332       // If `now` is outside of the certificate's validity period,
333       // CheckValidity will return Result::ERROR_NOT_YET_VALID_CERTIFICATE or
334       // Result::ERROR_EXPIRED_CERTIFICATE, as appropriate, and Success
335       // otherwise.
336       rv = mozilla::pkix::CheckValidity(now, notBefore, notAfter);
337       if (rv != Success) {
338         collectedErrors |= nsICertOverrideService::ERROR_TIME;
339         errorCodeTime = MapResultToPRErrorCode(rv);
340       }
341       break;
342     }
343 
344     case SEC_ERROR_INVALID_TIME:
345     case SEC_ERROR_EXPIRED_CERTIFICATE:
346     case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
347       collectedErrors = nsICertOverrideService::ERROR_TIME;
348       errorCodeTime = defaultErrorCodeToReport;
349       break;
350 
351     case SSL_ERROR_BAD_CERT_DOMAIN:
352       collectedErrors = nsICertOverrideService::ERROR_MISMATCH;
353       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
354       break;
355 
356     case 0:
357       NS_ERROR("No error code set during certificate validation failure.");
358       PR_SetError(PR_INVALID_STATE_ERROR, 0);
359       return SECFailure;
360 
361     default:
362       PR_SetError(defaultErrorCodeToReport, 0);
363       return SECFailure;
364   }
365 
366   if (defaultErrorCodeToReport != SSL_ERROR_BAD_CERT_DOMAIN) {
367     Input hostnameInput;
368     Result result = hostnameInput.Init(
369         BitwiseCast<const uint8_t*, const char*>(hostName.BeginReading()),
370         hostName.Length());
371     if (result != Success) {
372       PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
373       return SECFailure;
374     }
375     // Use a lax policy so as to not generate potentially spurious name
376     // mismatch "hints".
377     BRNameMatchingPolicy nameMatchingPolicy(
378         BRNameMatchingPolicy::Mode::DoNotEnforce);
379     // CheckCertHostname expects that its input represents a certificate that
380     // has already been successfully validated by BuildCertChain. This is
381     // obviously not the case, however, because we're in the error path of
382     // certificate verification. Thus, this is problematic. In the future, it
383     // would be nice to remove this optimistic additional error checking and
384     // simply punt to the front-end, which can more easily (and safely) perform
385     // extra checks to give the user hints as to why verification failed.
386     result = CheckCertHostname(certInput, hostnameInput, nameMatchingPolicy);
387     // Treat malformed name information as a domain mismatch.
388     if (result == Result::ERROR_BAD_DER ||
389         result == Result::ERROR_BAD_CERT_DOMAIN) {
390       collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
391       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
392     } else if (IsFatalError(result)) {
393       // Because its input has not been validated by BuildCertChain,
394       // CheckCertHostname can return an error that is less important than the
395       // original certificate verification error. Only return an error result
396       // from this function if we've encountered a fatal error.
397       PR_SetError(MapResultToPRErrorCode(result), 0);
398       return SECFailure;
399     }
400   }
401 
402   return SECSuccess;
403 }
404 
405 // Helper function to determine if overrides are allowed for this host.
406 // Overrides are not allowed for known HSTS hosts or hosts with pinning
407 // information. However, IP addresses can never be HSTS hosts and don't have
408 // pinning information.
OverrideAllowedForHost(uint64_t aPtrForLog,const nsACString & aHostname,const OriginAttributes & aOriginAttributes,uint32_t aProviderFlags,bool & aOverrideAllowed)409 static nsresult OverrideAllowedForHost(
410     uint64_t aPtrForLog, const nsACString& aHostname,
411     const OriginAttributes& aOriginAttributes, uint32_t aProviderFlags,
412     /*out*/ bool& aOverrideAllowed) {
413   aOverrideAllowed = false;
414 
415   // If this is an IP address, overrides are allowed, because an IP address is
416   // never an HSTS host. nsISiteSecurityService takes this into account
417   // already, but the real problem here is that calling NS_NewURI with an IPv6
418   // address fails. We do this to avoid that. A more comprehensive fix would be
419   // to have Necko provide an nsIURI to PSM and to use that here (and
420   // everywhere). However, that would be a wide-spanning change.
421   if (net_IsValidIPv6Addr(aHostname)) {
422     aOverrideAllowed = true;
423     return NS_OK;
424   }
425 
426   // If this is an HTTP Strict Transport Security host or a pinned host and the
427   // certificate is bad, don't allow overrides (RFC 6797 section 12.1).
428   bool strictTransportSecurityEnabled = false;
429   bool isStaticallyPinned = false;
430   nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
431   if (!sss) {
432     MOZ_LOG(
433         gPIPNSSLog, LogLevel::Debug,
434         ("[0x%" PRIx64 "] Couldn't get nsISiteSecurityService to check HSTS",
435          aPtrForLog));
436     return NS_ERROR_FAILURE;
437   }
438 
439   nsCOMPtr<nsIURI> uri;
440   nsresult rv = NS_NewURI(getter_AddRefs(uri), "https://"_ns + aHostname);
441   if (NS_FAILED(rv)) {
442     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
443             ("[0x%" PRIx64 "] Creating new URI failed", aPtrForLog));
444     return rv;
445   }
446 
447   rv = sss->IsSecureURI(uri, aProviderFlags, aOriginAttributes, nullptr,
448                         nullptr, &strictTransportSecurityEnabled);
449   if (NS_FAILED(rv)) {
450     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
451             ("[0x%" PRIx64 "] checking for HSTS failed", aPtrForLog));
452     return rv;
453   }
454 
455   nsCOMPtr<nsIPublicKeyPinningService> pkps =
456       do_GetService(NS_PKPSERVICE_CONTRACTID, &rv);
457   if (!pkps) {
458     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
459             ("[0x%" PRIx64
460              "] Couldn't get nsIPublicKeyPinningService to check pinning",
461              aPtrForLog));
462     return NS_ERROR_FAILURE;
463   }
464   rv = pkps->HostHasPins(uri, &isStaticallyPinned);
465   if (NS_FAILED(rv)) {
466     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
467             ("[0x%" PRIx64 "] checking for static pin failed", aPtrForLog));
468     return rv;
469   }
470 
471   aOverrideAllowed = !strictTransportSecurityEnabled && !isStaticallyPinned;
472   return NS_OK;
473 }
474 
475 // This function assumes that we will only use the SPDY connection coalescing
476 // feature on connections where we have negotiated SPDY using NPN. If we ever
477 // talk SPDY without having negotiated it with SPDY, this code will give wrong
478 // and perhaps unsafe results.
479 //
480 // Returns SECSuccess on the initial handshake of all connections, on
481 // renegotiations for any connections where we did not negotiate SPDY, or on any
482 // SPDY connection where the server's certificate did not change.
483 //
484 // Prohibit changing the server cert only if we negotiated SPDY,
485 // in order to support SPDY's cross-origin connection pooling.
BlockServerCertChangeForSpdy(nsNSSSocketInfo * infoObject,const UniqueCERTCertificate & serverCert)486 static SECStatus BlockServerCertChangeForSpdy(
487     nsNSSSocketInfo* infoObject, const UniqueCERTCertificate& serverCert) {
488   if (!infoObject->IsHandshakeCompleted()) {
489     // first handshake on this connection, not a
490     // renegotiation.
491     return SECSuccess;
492   }
493 
494   // Filter out sockets that did not neogtiate SPDY via NPN
495   nsAutoCString negotiatedNPN;
496   nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN);
497   MOZ_ASSERT(NS_SUCCEEDED(rv),
498              "GetNegotiatedNPN() failed during renegotiation");
499 
500   if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN, "spdy/"_ns)) {
501     return SECSuccess;
502   }
503   // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
504   if (NS_FAILED(rv)) {
505     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
506             ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
507              " Assuming spdy."));
508   }
509 
510   // Check to see if the cert has actually changed
511   nsCOMPtr<nsIX509Cert> cert;
512   infoObject->GetServerCert(getter_AddRefs(cert));
513   if (!cert) {
514     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
515     return SECFailure;
516   }
517   nsTArray<uint8_t> certDER;
518   if (NS_FAILED(cert->GetRawDER(certDER))) {
519     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
520     return SECFailure;
521   }
522   if (certDER.Length() == serverCert->derCert.len &&
523       memcmp(certDER.Elements(), serverCert->derCert.data, certDER.Length()) ==
524           0) {
525     return SECSuccess;
526   }
527 
528   // Report an error - changed cert is confirmed
529   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
530           ("SPDY refused to allow new cert during renegotiation"));
531   PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
532   return SECFailure;
533 }
534 
GatherTelemetryForSingleSCT(const ct::VerifiedSCT & verifiedSct)535 void GatherTelemetryForSingleSCT(const ct::VerifiedSCT& verifiedSct) {
536   // See SSL_SCTS_ORIGIN in Histograms.json.
537   uint32_t origin = 0;
538   switch (verifiedSct.origin) {
539     case ct::VerifiedSCT::Origin::Embedded:
540       origin = 1;
541       break;
542     case ct::VerifiedSCT::Origin::TLSExtension:
543       origin = 2;
544       break;
545     case ct::VerifiedSCT::Origin::OCSPResponse:
546       origin = 3;
547       break;
548     default:
549       MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Origin type");
550   }
551   Telemetry::Accumulate(Telemetry::SSL_SCTS_ORIGIN, origin);
552 
553   // See SSL_SCTS_VERIFICATION_STATUS in Histograms.json.
554   uint32_t verificationStatus = 0;
555   switch (verifiedSct.status) {
556     case ct::VerifiedSCT::Status::Valid:
557       verificationStatus = 1;
558       break;
559     case ct::VerifiedSCT::Status::UnknownLog:
560       verificationStatus = 2;
561       break;
562     case ct::VerifiedSCT::Status::InvalidSignature:
563       verificationStatus = 3;
564       break;
565     case ct::VerifiedSCT::Status::InvalidTimestamp:
566       verificationStatus = 4;
567       break;
568     case ct::VerifiedSCT::Status::ValidFromDisqualifiedLog:
569       verificationStatus = 5;
570       break;
571     default:
572       MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Status type");
573   }
574   Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS,
575                         verificationStatus);
576 }
577 
GatherCertificateTransparencyTelemetry(const nsTArray<uint8_t> & rootCert,bool isEV,const CertificateTransparencyInfo & info)578 void GatherCertificateTransparencyTelemetry(
579     const nsTArray<uint8_t>& rootCert, bool isEV,
580     const CertificateTransparencyInfo& info) {
581   if (!info.enabled) {
582     // No telemetry is gathered when CT is disabled.
583     return;
584   }
585 
586   for (const ct::VerifiedSCT& sct : info.verifyResult.verifiedScts) {
587     GatherTelemetryForSingleSCT(sct);
588   }
589 
590   // Decoding errors are reported to the 0th bucket
591   // of the SSL_SCTS_VERIFICATION_STATUS enumerated probe.
592   for (size_t i = 0; i < info.verifyResult.decodingErrors; ++i) {
593     Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 0);
594   }
595 
596   // Handle the histogram of SCTs counts.
597   uint32_t sctsCount =
598       static_cast<uint32_t>(info.verifyResult.verifiedScts.size());
599   // Note that sctsCount can also be 0 in case we've received SCT binary data,
600   // but it failed to parse (e.g. due to unsupported CT protocol version).
601   Telemetry::Accumulate(Telemetry::SSL_SCTS_PER_CONNECTION, sctsCount);
602 
603   // Report CT Policy compliance of EV certificates.
604   if (isEV) {
605     uint32_t evCompliance = 0;
606     switch (info.policyCompliance) {
607       case ct::CTPolicyCompliance::Compliant:
608         evCompliance = 1;
609         break;
610       case ct::CTPolicyCompliance::NotEnoughScts:
611         evCompliance = 2;
612         break;
613       case ct::CTPolicyCompliance::NotDiverseScts:
614         evCompliance = 3;
615         break;
616       case ct::CTPolicyCompliance::Unknown:
617       default:
618         MOZ_ASSERT_UNREACHABLE("Unexpected CTPolicyCompliance type");
619     }
620     Telemetry::Accumulate(Telemetry::SSL_CT_POLICY_COMPLIANCE_OF_EV_CERTS,
621                           evCompliance);
622   }
623 
624   // Report CT Policy compliance by CA.
625   switch (info.policyCompliance) {
626     case ct::CTPolicyCompliance::Compliant:
627       AccumulateTelemetryForRootCA(
628           Telemetry::SSL_CT_POLICY_COMPLIANT_CONNECTIONS_BY_CA, rootCert);
629       break;
630     case ct::CTPolicyCompliance::NotEnoughScts:
631     case ct::CTPolicyCompliance::NotDiverseScts:
632       AccumulateTelemetryForRootCA(
633           Telemetry::SSL_CT_POLICY_NON_COMPLIANT_CONNECTIONS_BY_CA, rootCert);
634       break;
635     case ct::CTPolicyCompliance::Unknown:
636     default:
637       MOZ_ASSERT_UNREACHABLE("Unexpected CTPolicyCompliance type");
638   }
639 }
640 
641 // This function collects telemetry about certs. It will be called on one of
642 // CertVerificationThread. When the socket process is used this will be called
643 // on the parent process.
CollectCertTelemetry(mozilla::pkix::Result aCertVerificationResult,EVStatus aEVStatus,CertVerifier::OCSPStaplingStatus aOcspStaplingStatus,KeySizeStatus aKeySizeStatus,SHA1ModeResult aSha1ModeResult,const PinningTelemetryInfo & aPinningTelemetryInfo,const nsTArray<nsTArray<uint8_t>> & aBuiltCertChain,const CertificateTransparencyInfo & aCertificateTransparencyInfo)644 static void CollectCertTelemetry(
645     mozilla::pkix::Result aCertVerificationResult, EVStatus aEVStatus,
646     CertVerifier::OCSPStaplingStatus aOcspStaplingStatus,
647     KeySizeStatus aKeySizeStatus, SHA1ModeResult aSha1ModeResult,
648     const PinningTelemetryInfo& aPinningTelemetryInfo,
649     const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain,
650     const CertificateTransparencyInfo& aCertificateTransparencyInfo) {
651   uint32_t evStatus = (aCertVerificationResult != Success) ? 0  // 0 = Failure
652                       : (aEVStatus != EVStatus::EV)        ? 1  // 1 = DV
653                                                            : 2;        // 2 = EV
654   Telemetry::Accumulate(Telemetry::CERT_EV_STATUS, evStatus);
655 
656   if (aOcspStaplingStatus != CertVerifier::OCSP_STAPLING_NEVER_CHECKED) {
657     Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, aOcspStaplingStatus);
658   }
659 
660   if (aKeySizeStatus != KeySizeStatus::NeverChecked) {
661     Telemetry::Accumulate(Telemetry::CERT_CHAIN_KEY_SIZE_STATUS,
662                           static_cast<uint32_t>(aKeySizeStatus));
663   }
664 
665   if (aSha1ModeResult != SHA1ModeResult::NeverChecked) {
666     Telemetry::Accumulate(Telemetry::CERT_CHAIN_SHA1_POLICY_STATUS,
667                           static_cast<uint32_t>(aSha1ModeResult));
668   }
669 
670   if (aPinningTelemetryInfo.accumulateForRoot) {
671     Telemetry::Accumulate(Telemetry::CERT_PINNING_FAILURES_BY_CA,
672                           aPinningTelemetryInfo.rootBucket);
673   }
674 
675   if (aPinningTelemetryInfo.accumulateResult) {
676     MOZ_ASSERT(aPinningTelemetryInfo.certPinningResultHistogram.isSome());
677     Telemetry::Accumulate(
678         aPinningTelemetryInfo.certPinningResultHistogram.value(),
679         aPinningTelemetryInfo.certPinningResultBucket);
680   }
681 
682   if (aCertVerificationResult == Success && aBuiltCertChain.Length() > 0) {
683     const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement();
684     AccumulateTelemetryForRootCA(Telemetry::CERT_VALIDATION_SUCCESS_BY_CA,
685                                  rootCert);
686     GatherCertificateTransparencyTelemetry(rootCert, aEVStatus == EVStatus::EV,
687                                            aCertificateTransparencyInfo);
688   }
689 }
690 
691 // Note: Takes ownership of |peerCertChain| if SECSuccess is not returned.
AuthCertificate(CertVerifier & certVerifier,void * aPinArg,const nsTArray<uint8_t> & certBytes,const nsTArray<nsTArray<uint8_t>> & peerCertChain,const nsACString & aHostName,const OriginAttributes & aOriginAttributes,const Maybe<nsTArray<uint8_t>> & stapledOCSPResponse,const Maybe<nsTArray<uint8_t>> & sctsFromTLSExtension,const Maybe<DelegatedCredentialInfo> & dcInfo,uint32_t providerFlags,Time time,uint32_t certVerifierFlags,nsTArray<nsTArray<uint8_t>> & builtCertChain,EVStatus & evStatus,CertificateTransparencyInfo & certificateTransparencyInfo,bool & aIsBuiltCertChainRootBuiltInRoot)692 Result AuthCertificate(
693     CertVerifier& certVerifier, void* aPinArg,
694     const nsTArray<uint8_t>& certBytes,
695     const nsTArray<nsTArray<uint8_t>>& peerCertChain,
696     const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
697     const Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
698     const Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
699     const Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
700     Time time, uint32_t certVerifierFlags,
701     /*out*/ nsTArray<nsTArray<uint8_t>>& builtCertChain,
702     /*out*/ EVStatus& evStatus,
703     /*out*/ CertificateTransparencyInfo& certificateTransparencyInfo,
704     /*out*/ bool& aIsBuiltCertChainRootBuiltInRoot) {
705   CertVerifier::OCSPStaplingStatus ocspStaplingStatus =
706       CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
707   KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked;
708   SHA1ModeResult sha1ModeResult = SHA1ModeResult::NeverChecked;
709   PinningTelemetryInfo pinningTelemetryInfo;
710 
711   nsTArray<nsTArray<uint8_t>> peerCertsBytes;
712   // Don't include the end-entity certificate.
713   if (!peerCertChain.IsEmpty()) {
714     std::transform(
715         peerCertChain.cbegin() + 1, peerCertChain.cend(),
716         MakeBackInserter(peerCertsBytes),
717         [](const auto& elementArray) { return elementArray.Clone(); });
718   }
719 
720   Result rv = certVerifier.VerifySSLServerCert(
721       certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags,
722       Some(std::move(peerCertsBytes)), stapledOCSPResponse,
723       sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus,
724       &ocspStaplingStatus, &keySizeStatus, &sha1ModeResult,
725       &pinningTelemetryInfo, &certificateTransparencyInfo,
726       &aIsBuiltCertChainRootBuiltInRoot);
727 
728   CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus,
729                        sha1ModeResult, pinningTelemetryInfo, builtCertChain,
730                        certificateTransparencyInfo);
731 
732   return rv;
733 }
734 
AuthCertificateParseResults(uint64_t aPtrForLog,const nsACString & aHostName,int32_t aPort,const OriginAttributes & aOriginAttributes,const nsCOMPtr<nsIX509Cert> & aCert,uint32_t aProviderFlags,mozilla::pkix::Time aTime,PRErrorCode aDefaultErrorCodeToReport,uint32_t & aCollectedErrors)735 PRErrorCode AuthCertificateParseResults(
736     uint64_t aPtrForLog, const nsACString& aHostName, int32_t aPort,
737     const OriginAttributes& aOriginAttributes,
738     const nsCOMPtr<nsIX509Cert>& aCert, uint32_t aProviderFlags,
739     mozilla::pkix::Time aTime, PRErrorCode aDefaultErrorCodeToReport,
740     /* out */ uint32_t& aCollectedErrors) {
741   if (aDefaultErrorCodeToReport == 0) {
742     MOZ_ASSERT_UNREACHABLE(
743         "No error set during certificate validation failure");
744     return SEC_ERROR_LIBRARY_FAILURE;
745   }
746 
747   uint32_t probeValue = MapCertErrorToProbeValue(aDefaultErrorCodeToReport);
748   Telemetry::Accumulate(Telemetry::SSL_CERT_VERIFICATION_ERRORS, probeValue);
749 
750   aCollectedErrors = 0;
751   PRErrorCode errorCodeTrust = 0;
752   PRErrorCode errorCodeMismatch = 0;
753   PRErrorCode errorCodeTime = 0;
754   if (DetermineCertOverrideErrors(
755           aCert, aHostName, aTime, aDefaultErrorCodeToReport, aCollectedErrors,
756           errorCodeTrust, errorCodeMismatch, errorCodeTime) != SECSuccess) {
757     PRErrorCode errorCode = PR_GetError();
758     MOZ_ASSERT(!ErrorIsOverridable(errorCode));
759     if (errorCode == 0) {
760       MOZ_ASSERT_UNREACHABLE(
761           "No error set during DetermineCertOverrideErrors failure");
762       return SEC_ERROR_LIBRARY_FAILURE;
763     }
764     return errorCode;
765   }
766 
767   if (!aCollectedErrors) {
768     MOZ_ASSERT_UNREACHABLE("aCollectedErrors should not be 0");
769     return SEC_ERROR_LIBRARY_FAILURE;
770   }
771 
772   bool overrideAllowed = false;
773   if (NS_FAILED(OverrideAllowedForHost(aPtrForLog, aHostName, aOriginAttributes,
774                                        aProviderFlags, overrideAllowed))) {
775     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
776             ("[0x%" PRIx64 "] AuthCertificateParseResults - "
777              "OverrideAllowedForHost failed\n",
778              aPtrForLog));
779     return aDefaultErrorCodeToReport;
780   }
781 
782   if (overrideAllowed) {
783     nsCOMPtr<nsICertOverrideService> overrideService =
784         do_GetService(NS_CERTOVERRIDE_CONTRACTID);
785 
786     uint32_t overrideBits = 0;
787     uint32_t remainingDisplayErrors = aCollectedErrors;
788 
789     // it is fine to continue without the nsICertOverrideService
790     if (overrideService) {
791       bool haveOverride;
792       bool isTemporaryOverride;  // we don't care
793       nsresult rv = overrideService->HasMatchingOverride(
794           aHostName, aPort, aOriginAttributes, aCert, &overrideBits,
795           &isTemporaryOverride, &haveOverride);
796       if (NS_SUCCEEDED(rv) && haveOverride) {
797         // remove the errors that are already overriden
798         remainingDisplayErrors &= ~overrideBits;
799       }
800     }
801 
802     if (!remainingDisplayErrors) {
803       // This can double- or triple-count one certificate with multiple
804       // different types of errors. Since this is telemetry and we just
805       // want a ballpark answer, we don't care.
806       if (errorCodeTrust != 0) {
807         uint32_t probeValue = MapOverridableErrorToProbeValue(errorCodeTrust);
808         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
809       }
810       if (errorCodeMismatch != 0) {
811         uint32_t probeValue =
812             MapOverridableErrorToProbeValue(errorCodeMismatch);
813         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
814       }
815       if (errorCodeTime != 0) {
816         uint32_t probeValue = MapOverridableErrorToProbeValue(errorCodeTime);
817         Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
818       }
819 
820       // all errors are covered by override rules, so let's accept the cert
821       MOZ_LOG(
822           gPIPNSSLog, LogLevel::Debug,
823           ("[0x%" PRIx64 "] All errors covered by override rules", aPtrForLog));
824       return 0;
825     }
826   } else {
827     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
828             ("[0x%" PRIx64 "] HSTS or pinned host - no overrides allowed\n",
829              aPtrForLog));
830   }
831 
832   MOZ_LOG(
833       gPIPNSSLog, LogLevel::Debug,
834       ("[0x%" PRIx64 "] Certificate error was not overridden\n", aPtrForLog));
835 
836   // pick the error code to report by priority
837   return errorCodeTrust      ? errorCodeTrust
838          : errorCodeMismatch ? errorCodeMismatch
839          : errorCodeTime     ? errorCodeTime
840                              : aDefaultErrorCodeToReport;
841 }
842 
843 }  // unnamed namespace
844 
CreateCertBytesArray(const UniqueCERTCertList & aCertChain)845 static nsTArray<nsTArray<uint8_t>> CreateCertBytesArray(
846     const UniqueCERTCertList& aCertChain) {
847   nsTArray<nsTArray<uint8_t>> certsBytes;
848   for (CERTCertListNode* n = CERT_LIST_HEAD(aCertChain);
849        !CERT_LIST_END(n, aCertChain); n = CERT_LIST_NEXT(n)) {
850     nsTArray<uint8_t> certBytes;
851     certBytes.AppendElements(n->cert->derCert.data, n->cert->derCert.len);
852     certsBytes.AppendElement(std::move(certBytes));
853   }
854   return certsBytes;
855 }
856 
857 /*static*/
Dispatch(uint64_t addrForLogging,void * aPinArg,nsTArray<nsTArray<uint8_t>> && peerCertChain,const nsACString & aHostName,int32_t aPort,const OriginAttributes & aOriginAttributes,Maybe<nsTArray<uint8_t>> & stapledOCSPResponse,Maybe<nsTArray<uint8_t>> & sctsFromTLSExtension,Maybe<DelegatedCredentialInfo> & dcInfo,uint32_t providerFlags,Time time,uint32_t certVerifierFlags,BaseSSLServerCertVerificationResult * aResultTask)858 SECStatus SSLServerCertVerificationJob::Dispatch(
859     uint64_t addrForLogging, void* aPinArg,
860     nsTArray<nsTArray<uint8_t>>&& peerCertChain, const nsACString& aHostName,
861     int32_t aPort, const OriginAttributes& aOriginAttributes,
862     Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
863     Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
864     Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, Time time,
865     uint32_t certVerifierFlags,
866     BaseSSLServerCertVerificationResult* aResultTask) {
867   // Runs on the socket transport thread
868   if (!aResultTask || peerCertChain.IsEmpty()) {
869     MOZ_ASSERT_UNREACHABLE(
870         "must have result task and non-empty peer cert chain");
871     PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
872     return SECFailure;
873   }
874 
875   if (!gCertVerificationThreadPool) {
876     PR_SetError(PR_INVALID_STATE_ERROR, 0);
877     return SECFailure;
878   }
879 
880   RefPtr<SSLServerCertVerificationJob> job(new SSLServerCertVerificationJob(
881       addrForLogging, aPinArg, std::move(peerCertChain), aHostName, aPort,
882       aOriginAttributes, stapledOCSPResponse, sctsFromTLSExtension, dcInfo,
883       providerFlags, time, certVerifierFlags, aResultTask));
884 
885   nsresult nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
886   if (NS_FAILED(nrv)) {
887     // We can't call SetCertVerificationResult here to change
888     // mCertVerificationState because SetCertVerificationResult will call
889     // libssl functions that acquire SSL locks that are already being held at
890     // this point. However, we can set an error with PR_SetError and return
891     // SECFailure, and the correct thing will happen (the error will be
892     // propagated and this connection will be terminated).
893     PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY ? PR_OUT_OF_MEMORY_ERROR
894                                                       : PR_INVALID_STATE_ERROR;
895     PR_SetError(error, 0);
896     return SECFailure;
897   }
898 
899   PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
900   return SECWouldBlock;
901 }
902 
903 NS_IMETHODIMP
Run()904 SSLServerCertVerificationJob::Run() {
905   // Runs on a cert verification thread and only on parent process.
906   MOZ_ASSERT(XRE_IsParentProcess());
907 
908   MOZ_LOG(
909       gPIPNSSLog, LogLevel::Debug,
910       ("[%" PRIx64 "] SSLServerCertVerificationJob::Run\n", mAddrForLogging));
911 
912   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
913   if (!certVerifier) {
914     PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
915     return NS_OK;
916   }
917 
918   TimeStamp jobStartTime = TimeStamp::Now();
919   EVStatus evStatus;
920   CertificateTransparencyInfo certificateTransparencyInfo;
921   bool isCertChainRootBuiltInRoot = false;
922   nsTArray<nsTArray<uint8_t>> builtChainBytesArray;
923   nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
924   Result rv = AuthCertificate(
925       *certVerifier, mPinArg, certBytes, mPeerCertChain, mHostName,
926       mOriginAttributes, mStapledOCSPResponse, mSCTsFromTLSExtension, mDCInfo,
927       mProviderFlags, mTime, mCertVerifierFlags, builtChainBytesArray, evStatus,
928       certificateTransparencyInfo, isCertChainRootBuiltInRoot);
929 
930   if (rv == Success) {
931     Telemetry::AccumulateTimeDelta(
932         Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX, jobStartTime,
933         TimeStamp::Now());
934     Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
935 
936     mResultTask->Dispatch(
937         std::move(builtChainBytesArray), std::move(mPeerCertChain),
938         TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
939             certificateTransparencyInfo),
940         evStatus, true, 0, 0, isCertChainRootBuiltInRoot, mProviderFlags);
941     return NS_OK;
942   }
943 
944   Telemetry::AccumulateTimeDelta(
945       Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX,
946       jobStartTime, TimeStamp::Now());
947 
948   PRErrorCode error = MapResultToPRErrorCode(rv);
949   uint32_t collectedErrors = 0;
950   nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
951   PRErrorCode finalError = AuthCertificateParseResults(
952       mAddrForLogging, mHostName, mPort, mOriginAttributes, cert,
953       mProviderFlags, mTime, error, collectedErrors);
954 
955   // NB: finalError may be 0 here, in which the connection will continue.
956   mResultTask->Dispatch(
957       std::move(builtChainBytesArray), std::move(mPeerCertChain),
958       nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE,
959       EVStatus::NotEV, false, finalError, collectedErrors, false,
960       mProviderFlags);
961   return NS_OK;
962 }
963 
964 // Takes information needed for cert verification, does some consistency
965 //  checks and calls SSLServerCertVerificationJob::Dispatch.
AuthCertificateHookInternal(TransportSecurityInfo * infoObject,const void * aPtrForLogging,const nsACString & hostName,nsTArray<nsTArray<uint8_t>> && peerCertChain,Maybe<nsTArray<uint8_t>> & stapledOCSPResponse,Maybe<nsTArray<uint8_t>> & sctsFromTLSExtension,Maybe<DelegatedCredentialInfo> & dcInfo,uint32_t providerFlags,uint32_t certVerifierFlags)966 SECStatus AuthCertificateHookInternal(
967     TransportSecurityInfo* infoObject, const void* aPtrForLogging,
968     const nsACString& hostName, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
969     Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
970     Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
971     Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
972     uint32_t certVerifierFlags) {
973   // Runs on the socket transport thread
974 
975   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
976           ("[%p] starting AuthCertificateHookInternal\n", aPtrForLogging));
977 
978   if (!infoObject || peerCertChain.IsEmpty()) {
979     PR_SetError(PR_INVALID_STATE_ERROR, 0);
980     return SECFailure;
981   }
982 
983   bool onSTSThread;
984   nsresult nrv;
985   nsCOMPtr<nsIEventTarget> sts =
986       do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
987   if (NS_SUCCEEDED(nrv)) {
988     nrv = sts->IsOnCurrentThread(&onSTSThread);
989   }
990 
991   if (NS_FAILED(nrv)) {
992     NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
993     PR_SetError(PR_UNKNOWN_ERROR, 0);
994     return SECFailure;
995   }
996 
997   MOZ_ASSERT(onSTSThread);
998 
999   if (!onSTSThread) {
1000     PR_SetError(PR_INVALID_STATE_ERROR, 0);
1001     return SECFailure;
1002   }
1003 
1004   uint64_t addr = reinterpret_cast<uintptr_t>(aPtrForLogging);
1005   RefPtr<SSLServerCertVerificationResult> resultTask =
1006       new SSLServerCertVerificationResult(infoObject);
1007 
1008   if (XRE_IsSocketProcess()) {
1009     return RemoteProcessCertVerification(
1010         std::move(peerCertChain), hostName, infoObject->GetPort(),
1011         infoObject->GetOriginAttributes(), stapledOCSPResponse,
1012         sctsFromTLSExtension, dcInfo, providerFlags, certVerifierFlags,
1013         resultTask);
1014   }
1015 
1016   // We *must* do certificate verification on a background thread because
1017   // we need the socket transport thread to be free for our OCSP requests,
1018   // and we *want* to do certificate verification on a background thread
1019   // because of the performance benefits of doing so.
1020   return SSLServerCertVerificationJob::Dispatch(
1021       addr, infoObject, std::move(peerCertChain), hostName,
1022       infoObject->GetPort(), infoObject->GetOriginAttributes(),
1023       stapledOCSPResponse, sctsFromTLSExtension, dcInfo, providerFlags, Now(),
1024       certVerifierFlags, resultTask);
1025 }
1026 
1027 // Extracts whatever information we need out of fd (using SSL_*) and passes it
1028 // to AuthCertificateHookInternal. AuthCertificateHookInternal will call
1029 // SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob
1030 // should never do anything with fd except logging.
AuthCertificateHook(void * arg,PRFileDesc * fd,PRBool checkSig,PRBool isServer)1031 SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig,
1032                               PRBool isServer) {
1033   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1034           ("[%p] starting AuthCertificateHook\n", fd));
1035 
1036   // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
1037   // doing verification without checking signatures.
1038   MOZ_ASSERT(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
1039 
1040   // PSM never causes libssl to call this function with PR_TRUE for isServer,
1041   // and many things in PSM assume that we are a client.
1042   MOZ_ASSERT(!isServer, "AuthCertificateHook: isServer unexpectedly true");
1043 
1044   nsNSSSocketInfo* socketInfo = static_cast<nsNSSSocketInfo*>(arg);
1045 
1046   UniqueCERTCertificate serverCert(SSL_PeerCertificate(fd));
1047 
1048   if (!checkSig || isServer || !socketInfo || !serverCert) {
1049     PR_SetError(PR_INVALID_STATE_ERROR, 0);
1050     return SECFailure;
1051   }
1052   socketInfo->SetFullHandshake();
1053 
1054   if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess) {
1055     return SECFailure;
1056   }
1057 
1058   UniqueCERTCertList peerCertChain(SSL_PeerCertificateChain(fd));
1059   if (!peerCertChain) {
1060     PR_SetError(PR_INVALID_STATE_ERROR, 0);
1061     return SECFailure;
1062   }
1063 
1064   nsTArray<nsTArray<uint8_t>> peerCertsBytes =
1065       CreateCertBytesArray(peerCertChain);
1066 
1067   // SSL_PeerStapledOCSPResponses will never return a non-empty response if
1068   // OCSP stapling wasn't enabled because libssl wouldn't have let the server
1069   // return a stapled OCSP response.
1070   // We don't own these pointers.
1071   const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
1072   Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
1073   // we currently only support single stapled responses
1074   if (csa && csa->len == 1) {
1075     stapledOCSPResponse.emplace();
1076     stapledOCSPResponse->SetCapacity(csa->items[0].len);
1077     stapledOCSPResponse->AppendElements(csa->items[0].data, csa->items[0].len);
1078   }
1079 
1080   Maybe<nsTArray<uint8_t>> sctsFromTLSExtension;
1081   const SECItem* sctsFromTLSExtensionSECItem = SSL_PeerSignedCertTimestamps(fd);
1082   if (sctsFromTLSExtensionSECItem) {
1083     sctsFromTLSExtension.emplace();
1084     sctsFromTLSExtension->SetCapacity(sctsFromTLSExtensionSECItem->len);
1085     sctsFromTLSExtension->AppendElements(sctsFromTLSExtensionSECItem->data,
1086                                          sctsFromTLSExtensionSECItem->len);
1087   }
1088 
1089   uint32_t providerFlags = 0;
1090   socketInfo->GetProviderFlags(&providerFlags);
1091 
1092   uint32_t certVerifierFlags = 0;
1093   if (!socketInfo->SharedState().IsOCSPStaplingEnabled() ||
1094       !socketInfo->SharedState().IsOCSPMustStapleEnabled()) {
1095     certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
1096   }
1097 
1098   // Get DC information
1099   Maybe<DelegatedCredentialInfo> dcInfo;
1100   SSLPreliminaryChannelInfo channelPreInfo;
1101   SECStatus rv = SSL_GetPreliminaryChannelInfo(fd, &channelPreInfo,
1102                                                sizeof(channelPreInfo));
1103   if (rv != SECSuccess) {
1104     PR_SetError(PR_INVALID_STATE_ERROR, 0);
1105     return SECFailure;
1106   }
1107   if (channelPreInfo.peerDelegCred) {
1108     dcInfo.emplace(DelegatedCredentialInfo(channelPreInfo.signatureScheme,
1109                                            channelPreInfo.authKeyBits));
1110   }
1111 
1112   // If we configured an ECHConfig and NSS returned the public name
1113   // for verification, ECH was rejected. Proceed, verifying to the
1114   // public name. The result determines how NSS will fail (i.e. with
1115   // any provided retry_configs if successful). See draft-ietf-tls-esni-08.
1116   nsCString echConfig;
1117   nsresult nsrv = socketInfo->GetEchConfig(echConfig);
1118   bool verifyToEchPublicName =
1119       NS_SUCCEEDED(nsrv) && echConfig.Length() && channelPreInfo.echPublicName;
1120 
1121   const nsCString echPublicName(channelPreInfo.echPublicName);
1122   const nsACString& hostname =
1123       verifyToEchPublicName ? echPublicName : socketInfo->GetHostName();
1124   socketInfo->SetCertVerificationWaiting();
1125   rv = AuthCertificateHookInternal(socketInfo, static_cast<const void*>(fd),
1126                                    hostname, std::move(peerCertsBytes),
1127                                    stapledOCSPResponse, sctsFromTLSExtension,
1128                                    dcInfo, providerFlags, certVerifierFlags);
1129   return rv;
1130 }
1131 
1132 // Takes information needed for cert verification, does some consistency
1133 // checks and calls SSLServerCertVerificationJob::Dispatch.
1134 // This function is used for Quic.
AuthCertificateHookWithInfo(TransportSecurityInfo * infoObject,const nsACString & aHostName,const void * aPtrForLogging,nsTArray<nsTArray<uint8_t>> && peerCertChain,Maybe<nsTArray<nsTArray<uint8_t>>> & stapledOCSPResponses,Maybe<nsTArray<uint8_t>> & sctsFromTLSExtension,uint32_t providerFlags)1135 SECStatus AuthCertificateHookWithInfo(
1136     TransportSecurityInfo* infoObject, const nsACString& aHostName,
1137     const void* aPtrForLogging, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
1138     Maybe<nsTArray<nsTArray<uint8_t>>>& stapledOCSPResponses,
1139     Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, uint32_t providerFlags) {
1140   if (peerCertChain.IsEmpty()) {
1141     PR_SetError(PR_INVALID_STATE_ERROR, 0);
1142     return SECFailure;
1143   }
1144 
1145   // we currently only support single stapled responses
1146   Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
1147   if (stapledOCSPResponses && (stapledOCSPResponses->Length() == 1)) {
1148     stapledOCSPResponse.emplace(stapledOCSPResponses->ElementAt(0).Clone());
1149   }
1150 
1151   uint32_t certVerifierFlags = 0;
1152   // QuicTransportSecInfo does not have a SharedState as nsNSSSocketInfo.
1153   // Here we need prefs for ocsp. This are prefs they are the same for
1154   // PublicSSLState and PrivateSSLState, just take them from one of them.
1155   if (!PublicSSLState()->IsOCSPStaplingEnabled() ||
1156       !PublicSSLState()->IsOCSPMustStapleEnabled()) {
1157     certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
1158   }
1159 
1160   // Need to update Quic stack to reflect the PreliminaryInfo fields
1161   // for Delegated Credentials.
1162   Maybe<DelegatedCredentialInfo> dcInfo;
1163 
1164   return AuthCertificateHookInternal(infoObject, aPtrForLogging, aHostName,
1165                                      std::move(peerCertChain),
1166                                      stapledOCSPResponse, sctsFromTLSExtension,
1167                                      dcInfo, providerFlags, certVerifierFlags);
1168 }
1169 
NS_IMPL_ISUPPORTS_INHERITED0(SSLServerCertVerificationResult,Runnable)1170 NS_IMPL_ISUPPORTS_INHERITED0(SSLServerCertVerificationResult, Runnable)
1171 
1172 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
1173     TransportSecurityInfo* infoObject)
1174     : Runnable("psm::SSLServerCertVerificationResult"),
1175       mInfoObject(infoObject),
1176       mCertificateTransparencyStatus(0),
1177       mEVStatus(EVStatus::NotEV),
1178       mSucceeded(false),
1179       mFinalError(0),
1180       mCollectedErrors(0),
1181       mProviderFlags(0) {}
1182 
Dispatch(nsTArray<nsTArray<uint8_t>> && aBuiltChain,nsTArray<nsTArray<uint8_t>> && aPeerCertChain,uint16_t aCertificateTransparencyStatus,EVStatus aEVStatus,bool aSucceeded,PRErrorCode aFinalError,uint32_t aCollectedErrors,bool aIsBuiltCertChainRootBuiltInRoot,uint32_t aProviderFlags)1183 void SSLServerCertVerificationResult::Dispatch(
1184     nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
1185     nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
1186     uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
1187     bool aSucceeded, PRErrorCode aFinalError, uint32_t aCollectedErrors,
1188     bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags) {
1189   mBuiltChain = std::move(aBuiltChain);
1190   mPeerCertChain = std::move(aPeerCertChain);
1191   mCertificateTransparencyStatus = aCertificateTransparencyStatus;
1192   mEVStatus = aEVStatus;
1193   mSucceeded = aSucceeded;
1194   mFinalError = aFinalError;
1195   mCollectedErrors = aCollectedErrors;
1196   mIsBuiltCertChainRootBuiltInRoot = aIsBuiltCertChainRootBuiltInRoot;
1197   mProviderFlags = aProviderFlags;
1198 
1199   if (mSucceeded && mBuiltChain.IsEmpty()) {
1200     MOZ_ASSERT_UNREACHABLE(
1201         "if the handshake succeeded, the built chain shouldn't be empty");
1202     mSucceeded = false;
1203     mFinalError = SEC_ERROR_LIBRARY_FAILURE;
1204   }
1205   if (!mSucceeded && mPeerCertChain.IsEmpty()) {
1206     MOZ_ASSERT_UNREACHABLE(
1207         "if the handshake failed, the peer chain shouldn't be empty");
1208     mFinalError = SEC_ERROR_LIBRARY_FAILURE;
1209   }
1210 
1211   nsresult rv;
1212   nsCOMPtr<nsIEventTarget> stsTarget =
1213       do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
1214   MOZ_ASSERT(stsTarget, "Failed to get socket transport service event target");
1215   rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
1216   MOZ_ASSERT(NS_SUCCEEDED(rv),
1217              "Failed to dispatch SSLServerCertVerificationResult");
1218 }
1219 
1220 NS_IMETHODIMP
Run()1221 SSLServerCertVerificationResult::Run() {
1222 #ifdef DEBUG
1223   bool onSTSThread = false;
1224   nsresult nrv;
1225   nsCOMPtr<nsIEventTarget> sts =
1226       do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
1227   if (NS_SUCCEEDED(nrv)) {
1228     nrv = sts->IsOnCurrentThread(&onSTSThread);
1229   }
1230 
1231   MOZ_ASSERT(onSTSThread);
1232 #endif
1233 
1234   if (mSucceeded && !XRE_IsSocketProcess() &&
1235       !(mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE)) {
1236     // This dispatches an event that will run when the socket thread is idle.
1237     SaveIntermediateCerts(mBuiltChain);
1238   }
1239 
1240   if (mSucceeded) {
1241     // Certificate verification succeeded. Delete any potential record of
1242     // certificate error bits.
1243     RememberCertErrorsTable::GetInstance().RememberCertHasError(mInfoObject,
1244                                                                 SECSuccess);
1245 
1246     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1247             ("SSLServerCertVerificationResult::Run setting NEW cert"));
1248     nsTArray<uint8_t> certBytes(mBuiltChain.ElementAt(0).Clone());
1249     nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
1250     mInfoObject->SetServerCert(cert, mEVStatus);
1251     mInfoObject->SetSucceededCertChain(std::move(mBuiltChain));
1252 
1253     mInfoObject->SetIsBuiltCertChainRootBuiltInRoot(
1254         mIsBuiltCertChainRootBuiltInRoot);
1255     mInfoObject->SetCertificateTransparencyStatus(
1256         mCertificateTransparencyStatus);
1257   } else {
1258     nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
1259     nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
1260     // Certificate validation failed; store the peer certificate chain on
1261     // infoObject so it can be used for error reporting.
1262     mInfoObject->SetFailedCertChain(std::move(mPeerCertChain));
1263     if (mCollectedErrors != 0) {
1264       mInfoObject->SetStatusErrorBits(cert, mCollectedErrors);
1265     }
1266   }
1267 
1268   mInfoObject->SetCertVerificationResult(mFinalError);
1269   return NS_OK;
1270 }
1271 
1272 }  // namespace psm
1273 }  // namespace mozilla
1274