Bug 1605894 reduce the proliferation of DefaultLoopbackTone to only AudioStreamFlowin...
[gecko.git] / security / manager / ssl / SSLServerCertVerification.cpp
bloba5afaea7c498c074f5561bd0e0406391441c82ac
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
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.
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.
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.
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.
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.
40 // Timeline of events (for connections managed by the socket transport service):
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.
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 NSSSocketControl and the
69 // PSM NSS I/O layer are not thread-safe, and because we need the event to
70 // interrupt the PR_Poll that may waiting for I/O on the socket for which we
71 // are validating the cert.
73 // When socket process is enabled, libssl is running on socket process. To
74 // perform certificate authentication with CertVerifier, we have to send all
75 // needed information to parent process and send the result back to socket
76 // process via IPC. The workflow is described below.
77 // 1. In AuthCertificateHookInternal(), we call RemoteProcessCertVerification()
78 // instead of SSLServerCertVerificationJob::Dispatch when we are on socket
79 // process.
80 // 2. In RemoteProcessCertVerification(), PVerifySSLServerCert actors will be
81 // created on IPDL background thread for carrying needed information via IPC.
82 // 3. On parent process, VerifySSLServerCertParent is created and it calls
83 // SSLServerCertVerificationJob::Dispatch for doing certificate verification
84 // on one of CertVerificationThreads.
85 // 4. When validation is done, OnVerifiedSSLServerCertSuccess IPC message is
86 // sent through the IPDL background thread when
87 // CertVerifier::VerifySSLServerCert returns Success. Otherwise,
88 // OnVerifiedSSLServerCertFailure is sent.
89 // 5. After setp 4, PVerifySSLServerCert actors will be released. The
90 // verification result will be dispatched via
91 // SSLServerCertVerificationResult.
93 #include "SSLServerCertVerification.h"
95 #include <cstring>
97 #include "CertVerifier.h"
98 #include "CryptoTask.h"
99 #include "ExtendedValidation.h"
100 #include "NSSCertDBTrustDomain.h"
101 #include "NSSSocketControl.h"
102 #include "PSMRunnable.h"
103 #include "RootCertificateTelemetryUtils.h"
104 #include "ScopedNSSTypes.h"
105 #include "SharedCertVerifier.h"
106 #include "SharedSSLState.h"
107 #include "VerifySSLServerCertChild.h"
108 #include "cert.h"
109 #include "mozilla/Assertions.h"
110 #include "mozilla/Casting.h"
111 #include "mozilla/RefPtr.h"
112 #include "mozilla/Telemetry.h"
113 #include "mozilla/UniquePtr.h"
114 #include "mozilla/Unused.h"
115 #include "nsComponentManagerUtils.h"
116 #include "nsContentUtils.h"
117 #include "nsICertOverrideService.h"
118 #include "nsIPublicKeyPinningService.h"
119 #include "nsISiteSecurityService.h"
120 #include "nsISocketProvider.h"
121 #include "nsThreadPool.h"
122 #include "nsNetUtil.h"
123 #include "nsNSSCertificate.h"
124 #include "nsNSSComponent.h"
125 #include "nsNSSIOLayer.h"
126 #include "nsServiceManagerUtils.h"
127 #include "nsString.h"
128 #include "nsURLHelper.h"
129 #include "nsXPCOMCIDInternal.h"
130 #include "mozpkix/pkix.h"
131 #include "mozpkix/pkixcheck.h"
132 #include "mozpkix/pkixnss.h"
133 #include "mozpkix/pkixutil.h"
134 #include "secerr.h"
135 #include "secport.h"
136 #include "ssl.h"
137 #include "sslerr.h"
138 #include "sslexp.h"
140 extern mozilla::LazyLogModule gPIPNSSLog;
142 using namespace mozilla::pkix;
144 namespace mozilla {
145 namespace psm {
147 // do not use a nsCOMPtr to avoid static initializer/destructor
148 nsIThreadPool* gCertVerificationThreadPool = nullptr;
150 // Called when the socket transport thread starts, to initialize the SSL cert
151 // verification thread pool. By tying the thread pool startup/shutdown directly
152 // to the STS thread's lifetime, we ensure that they are *always* available for
153 // SSL connections and that there are no races during startup and especially
154 // shutdown. (Previously, we have had multiple problems with races in PSM
155 // background threads, and the race-prevention/shutdown logic used there is
156 // brittle. Since this service is critical to things like downloading updates,
157 // we take no chances.) Also, by doing things this way, we avoid the need for
158 // locks, since gCertVerificationThreadPool is only ever accessed on the socket
159 // transport thread.
160 void InitializeSSLServerCertVerificationThreads() {
161 // TODO: tuning, make parameters preferences
162 gCertVerificationThreadPool = new nsThreadPool();
163 NS_ADDREF(gCertVerificationThreadPool);
165 (void)gCertVerificationThreadPool->SetIdleThreadLimit(5);
166 (void)gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
167 (void)gCertVerificationThreadPool->SetThreadLimit(5);
168 (void)gCertVerificationThreadPool->SetName("SSL Cert"_ns);
171 // Called when the socket transport thread finishes, to destroy the thread
172 // pool. Since the socket transport service has stopped processing events, it
173 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
174 // down the SSL cert verification infrastructure. Also, the STS will not
175 // dispatch many SSL verification result events at this point, so any pending
176 // cert verifications will (correctly) fail at the point they are dispatched.
178 // The other shutdown race condition that is possible is a race condition with
179 // shutdown of the nsNSSComponent service. We use the
180 // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
181 void StopSSLServerCertVerificationThreads() {
182 if (gCertVerificationThreadPool) {
183 gCertVerificationThreadPool->Shutdown();
184 NS_RELEASE(gCertVerificationThreadPool);
188 // A probe value of 1 means "no error".
189 uint32_t MapOverridableErrorToProbeValue(PRErrorCode errorCode) {
190 switch (errorCode) {
191 case SEC_ERROR_UNKNOWN_ISSUER:
192 return 2;
193 case SEC_ERROR_CA_CERT_INVALID:
194 return 3;
195 case SEC_ERROR_UNTRUSTED_ISSUER:
196 return 4;
197 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
198 return 5;
199 case SEC_ERROR_UNTRUSTED_CERT:
200 return 6;
201 case SEC_ERROR_INADEQUATE_KEY_USAGE:
202 return 7;
203 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
204 return 8;
205 case SSL_ERROR_BAD_CERT_DOMAIN:
206 return 9;
207 case SEC_ERROR_EXPIRED_CERTIFICATE:
208 return 10;
209 case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
210 return 11;
211 case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
212 return 12;
213 case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
214 return 13;
215 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
216 return 14;
217 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
218 return 15;
219 case SEC_ERROR_INVALID_TIME:
220 return 16;
221 case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
222 return 17;
223 case mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED:
224 return 18;
225 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
226 return 19;
227 case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
228 return 20;
230 NS_WARNING(
231 "Unknown certificate error code. Does MapOverridableErrorToProbeValue "
232 "handle everything in CategorizeCertificateError?");
233 return 0;
236 static uint32_t MapCertErrorToProbeValue(PRErrorCode errorCode) {
237 uint32_t probeValue;
238 switch (errorCode) {
239 // see security/pkix/include/pkix/Result.h
240 #define MOZILLA_PKIX_MAP(name, value, nss_name) \
241 case nss_name: \
242 probeValue = value; \
243 break;
244 MOZILLA_PKIX_MAP_LIST
245 #undef MOZILLA_PKIX_MAP
246 default:
247 return 0;
250 // Since FATAL_ERROR_FLAG is 0x800, fatal error values are much larger than
251 // non-fatal error values. To conserve space, we remap these so they start at
252 // (decimal) 90 instead of 0x800. Currently there are ~50 non-fatal errors
253 // mozilla::pkix might return, so saving space for 90 should be sufficient
254 // (similarly, there are 4 fatal errors, so saving space for 10 should also
255 // be sufficient).
256 static_assert(
257 FATAL_ERROR_FLAG == 0x800,
258 "mozilla::pkix::FATAL_ERROR_FLAG is not what we were expecting");
259 if (probeValue & FATAL_ERROR_FLAG) {
260 probeValue ^= FATAL_ERROR_FLAG;
261 probeValue += 90;
263 return probeValue;
266 // If the given PRErrorCode is an overridable certificate error, return which
267 // category (trust, time, domain mismatch) it falls in. If it is not
268 // overridable, return Nothing.
269 Maybe<nsITransportSecurityInfo::OverridableErrorCategory>
270 CategorizeCertificateError(PRErrorCode certificateError) {
271 switch (certificateError) {
272 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
273 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
274 case SEC_ERROR_UNKNOWN_ISSUER:
275 case SEC_ERROR_CA_CERT_INVALID:
276 case mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED:
277 case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
278 case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
279 case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
280 case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
281 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
282 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
283 case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
284 return Some(
285 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST);
287 case SSL_ERROR_BAD_CERT_DOMAIN:
288 return Some(
289 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_DOMAIN);
291 case SEC_ERROR_INVALID_TIME:
292 case SEC_ERROR_EXPIRED_CERTIFICATE:
293 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
294 return Some(
295 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME);
297 default:
298 break;
300 return Nothing();
303 // Helper function to determine if overrides are allowed for this host.
304 // Overrides are not allowed for known HSTS hosts or hosts with pinning
305 // information. However, IP addresses can never be HSTS hosts and don't have
306 // pinning information.
307 static nsresult OverrideAllowedForHost(
308 uint64_t aPtrForLog, const nsACString& aHostname,
309 const OriginAttributes& aOriginAttributes, /*out*/ bool& aOverrideAllowed) {
310 aOverrideAllowed = false;
312 // If this is an IP address, overrides are allowed, because an IP address is
313 // never an HSTS host. nsISiteSecurityService takes this into account
314 // already, but the real problem here is that calling NS_NewURI with an IPv6
315 // address fails. We do this to avoid that. A more comprehensive fix would be
316 // to have Necko provide an nsIURI to PSM and to use that here (and
317 // everywhere). However, that would be a wide-spanning change.
318 if (net_IsValidIPv6Addr(aHostname)) {
319 aOverrideAllowed = true;
320 return NS_OK;
323 // If this is an HTTP Strict Transport Security host or a pinned host and the
324 // certificate is bad, don't allow overrides (RFC 6797 section 12.1).
325 bool strictTransportSecurityEnabled = false;
326 bool isStaticallyPinned = false;
327 nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
328 if (!sss) {
329 MOZ_LOG(
330 gPIPNSSLog, LogLevel::Debug,
331 ("[0x%" PRIx64 "] Couldn't get nsISiteSecurityService to check HSTS",
332 aPtrForLog));
333 return NS_ERROR_FAILURE;
336 nsCOMPtr<nsIURI> uri;
337 nsresult rv = NS_NewURI(getter_AddRefs(uri), "https://"_ns + aHostname);
338 if (NS_FAILED(rv)) {
339 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
340 ("[0x%" PRIx64 "] Creating new URI failed", aPtrForLog));
341 return rv;
344 rv =
345 sss->IsSecureURI(uri, aOriginAttributes, &strictTransportSecurityEnabled);
346 if (NS_FAILED(rv)) {
347 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
348 ("[0x%" PRIx64 "] checking for HSTS failed", aPtrForLog));
349 return rv;
352 nsCOMPtr<nsIPublicKeyPinningService> pkps =
353 do_GetService(NS_PKPSERVICE_CONTRACTID, &rv);
354 if (!pkps) {
355 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
356 ("[0x%" PRIx64
357 "] Couldn't get nsIPublicKeyPinningService to check pinning",
358 aPtrForLog));
359 return NS_ERROR_FAILURE;
361 rv = pkps->HostHasPins(uri, &isStaticallyPinned);
362 if (NS_FAILED(rv)) {
363 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
364 ("[0x%" PRIx64 "] checking for static pin failed", aPtrForLog));
365 return rv;
368 aOverrideAllowed = !strictTransportSecurityEnabled && !isStaticallyPinned;
369 return NS_OK;
372 // This function assumes that we will only use the SPDY connection coalescing
373 // feature on connections where we have negotiated SPDY using NPN. If we ever
374 // talk SPDY without having negotiated it with SPDY, this code will give wrong
375 // and perhaps unsafe results.
377 // Returns SECSuccess on the initial handshake of all connections, on
378 // renegotiations for any connections where we did not negotiate SPDY, or on any
379 // SPDY connection where the server's certificate did not change.
381 // Prohibit changing the server cert only if we negotiated SPDY,
382 // in order to support SPDY's cross-origin connection pooling.
383 static SECStatus BlockServerCertChangeForSpdy(
384 NSSSocketControl* socketControl, const UniqueCERTCertificate& serverCert) {
385 if (!socketControl->IsHandshakeCompleted()) {
386 // first handshake on this connection, not a
387 // renegotiation.
388 return SECSuccess;
391 // Filter out sockets that did not neogtiate SPDY via NPN
392 nsCOMPtr<nsITransportSecurityInfo> securityInfo;
393 nsresult rv = socketControl->GetSecurityInfo(getter_AddRefs(securityInfo));
394 MOZ_ASSERT(NS_SUCCEEDED(rv), "GetSecurityInfo() failed during renegotiation");
395 if (NS_FAILED(rv) || !securityInfo) {
396 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
397 return SECFailure;
399 nsAutoCString negotiatedNPN;
400 rv = securityInfo->GetNegotiatedNPN(negotiatedNPN);
401 MOZ_ASSERT(NS_SUCCEEDED(rv),
402 "GetNegotiatedNPN() failed during renegotiation");
404 if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN, "spdy/"_ns)) {
405 return SECSuccess;
407 // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
408 if (NS_FAILED(rv)) {
409 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
410 ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
411 " Assuming spdy."));
414 // Check to see if the cert has actually changed
415 nsCOMPtr<nsIX509Cert> cert(socketControl->GetServerCert());
416 if (!cert) {
417 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
418 return SECFailure;
420 nsTArray<uint8_t> certDER;
421 if (NS_FAILED(cert->GetRawDER(certDER))) {
422 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
423 return SECFailure;
425 if (certDER.Length() == serverCert->derCert.len &&
426 memcmp(certDER.Elements(), serverCert->derCert.data, certDER.Length()) ==
427 0) {
428 return SECSuccess;
431 // Report an error - changed cert is confirmed
432 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
433 ("SPDY refused to allow new cert during renegotiation"));
434 PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
435 return SECFailure;
438 void GatherTelemetryForSingleSCT(const ct::VerifiedSCT& verifiedSct) {
439 // See SSL_SCTS_ORIGIN in Histograms.json.
440 uint32_t origin = 0;
441 switch (verifiedSct.origin) {
442 case ct::VerifiedSCT::Origin::Embedded:
443 origin = 1;
444 break;
445 case ct::VerifiedSCT::Origin::TLSExtension:
446 origin = 2;
447 break;
448 case ct::VerifiedSCT::Origin::OCSPResponse:
449 origin = 3;
450 break;
451 default:
452 MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Origin type");
454 Telemetry::Accumulate(Telemetry::SSL_SCTS_ORIGIN, origin);
456 // See SSL_SCTS_VERIFICATION_STATUS in Histograms.json.
457 uint32_t verificationStatus = 0;
458 switch (verifiedSct.status) {
459 case ct::VerifiedSCT::Status::Valid:
460 verificationStatus = 1;
461 break;
462 case ct::VerifiedSCT::Status::UnknownLog:
463 verificationStatus = 2;
464 break;
465 case ct::VerifiedSCT::Status::InvalidSignature:
466 verificationStatus = 3;
467 break;
468 case ct::VerifiedSCT::Status::InvalidTimestamp:
469 verificationStatus = 4;
470 break;
471 case ct::VerifiedSCT::Status::ValidFromDisqualifiedLog:
472 verificationStatus = 5;
473 break;
474 default:
475 MOZ_ASSERT_UNREACHABLE("Unexpected VerifiedSCT::Status type");
477 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS,
478 verificationStatus);
481 void GatherCertificateTransparencyTelemetry(
482 const nsTArray<uint8_t>& rootCert, bool isEV,
483 const CertificateTransparencyInfo& info) {
484 if (!info.enabled) {
485 // No telemetry is gathered when CT is disabled.
486 return;
489 for (const ct::VerifiedSCT& sct : info.verifyResult.verifiedScts) {
490 GatherTelemetryForSingleSCT(sct);
493 // Decoding errors are reported to the 0th bucket
494 // of the SSL_SCTS_VERIFICATION_STATUS enumerated probe.
495 for (size_t i = 0; i < info.verifyResult.decodingErrors; ++i) {
496 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 0);
499 // Handle the histogram of SCTs counts.
500 uint32_t sctsCount =
501 static_cast<uint32_t>(info.verifyResult.verifiedScts.size());
502 // Note that sctsCount can also be 0 in case we've received SCT binary data,
503 // but it failed to parse (e.g. due to unsupported CT protocol version).
504 Telemetry::Accumulate(Telemetry::SSL_SCTS_PER_CONNECTION, sctsCount);
506 // Report CT Policy compliance by CA.
507 switch (info.policyCompliance) {
508 case ct::CTPolicyCompliance::Compliant:
509 AccumulateTelemetryForRootCA(
510 Telemetry::SSL_CT_POLICY_COMPLIANT_CONNECTIONS_BY_CA, rootCert);
511 break;
512 case ct::CTPolicyCompliance::NotEnoughScts:
513 case ct::CTPolicyCompliance::NotDiverseScts:
514 AccumulateTelemetryForRootCA(
515 Telemetry::SSL_CT_POLICY_NON_COMPLIANT_CONNECTIONS_BY_CA, rootCert);
516 break;
517 case ct::CTPolicyCompliance::Unknown:
518 default:
519 MOZ_ASSERT_UNREACHABLE("Unexpected CTPolicyCompliance type");
523 // This function collects telemetry about certs. It will be called on one of
524 // CertVerificationThread. When the socket process is used this will be called
525 // on the parent process.
526 static void CollectCertTelemetry(
527 mozilla::pkix::Result aCertVerificationResult, EVStatus aEVStatus,
528 CertVerifier::OCSPStaplingStatus aOcspStaplingStatus,
529 KeySizeStatus aKeySizeStatus,
530 const PinningTelemetryInfo& aPinningTelemetryInfo,
531 const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain,
532 const CertificateTransparencyInfo& aCertificateTransparencyInfo) {
533 uint32_t evStatus = (aCertVerificationResult != Success) ? 0 // 0 = Failure
534 : (aEVStatus != EVStatus::EV) ? 1 // 1 = DV
535 : 2; // 2 = EV
536 Telemetry::Accumulate(Telemetry::CERT_EV_STATUS, evStatus);
538 if (aOcspStaplingStatus != CertVerifier::OCSP_STAPLING_NEVER_CHECKED) {
539 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, aOcspStaplingStatus);
542 if (aKeySizeStatus != KeySizeStatus::NeverChecked) {
543 Telemetry::Accumulate(Telemetry::CERT_CHAIN_KEY_SIZE_STATUS,
544 static_cast<uint32_t>(aKeySizeStatus));
547 if (aPinningTelemetryInfo.accumulateForRoot) {
548 Telemetry::Accumulate(Telemetry::CERT_PINNING_FAILURES_BY_CA,
549 aPinningTelemetryInfo.rootBucket);
552 if (aPinningTelemetryInfo.accumulateResult) {
553 MOZ_ASSERT(aPinningTelemetryInfo.certPinningResultHistogram.isSome());
554 Telemetry::Accumulate(
555 aPinningTelemetryInfo.certPinningResultHistogram.value(),
556 aPinningTelemetryInfo.certPinningResultBucket);
559 if (aCertVerificationResult == Success && aBuiltCertChain.Length() > 0) {
560 const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement();
561 AccumulateTelemetryForRootCA(Telemetry::CERT_VALIDATION_SUCCESS_BY_CA,
562 rootCert);
563 GatherCertificateTransparencyTelemetry(rootCert, aEVStatus == EVStatus::EV,
564 aCertificateTransparencyInfo);
568 // Note: Takes ownership of |peerCertChain| if SECSuccess is not returned.
569 Result AuthCertificate(
570 CertVerifier& certVerifier, void* aPinArg,
571 const nsTArray<uint8_t>& certBytes,
572 const nsTArray<nsTArray<uint8_t>>& peerCertChain,
573 const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
574 const Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
575 const Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
576 const Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
577 Time time, uint32_t certVerifierFlags,
578 /*out*/ nsTArray<nsTArray<uint8_t>>& builtCertChain,
579 /*out*/ EVStatus& evStatus,
580 /*out*/ CertificateTransparencyInfo& certificateTransparencyInfo,
581 /*out*/ bool& aIsBuiltCertChainRootBuiltInRoot,
582 /*out*/ bool& aMadeOCSPRequests) {
583 CertVerifier::OCSPStaplingStatus ocspStaplingStatus =
584 CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
585 KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked;
586 PinningTelemetryInfo pinningTelemetryInfo;
588 nsTArray<nsTArray<uint8_t>> peerCertsBytes;
589 // Don't include the end-entity certificate.
590 if (!peerCertChain.IsEmpty()) {
591 std::transform(
592 peerCertChain.cbegin() + 1, peerCertChain.cend(),
593 MakeBackInserter(peerCertsBytes),
594 [](const auto& elementArray) { return elementArray.Clone(); });
597 Result rv = certVerifier.VerifySSLServerCert(
598 certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags,
599 Some(std::move(peerCertsBytes)), stapledOCSPResponse,
600 sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus,
601 &ocspStaplingStatus, &keySizeStatus, &pinningTelemetryInfo,
602 &certificateTransparencyInfo, &aIsBuiltCertChainRootBuiltInRoot,
603 &aMadeOCSPRequests);
605 CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus,
606 pinningTelemetryInfo, builtCertChain,
607 certificateTransparencyInfo);
609 return rv;
612 PRErrorCode AuthCertificateParseResults(
613 uint64_t aPtrForLog, const nsACString& aHostName, int32_t aPort,
614 const OriginAttributes& aOriginAttributes,
615 const nsCOMPtr<nsIX509Cert>& aCert, mozilla::pkix::Time aTime,
616 PRErrorCode aCertVerificationError,
617 /* out */
618 nsITransportSecurityInfo::OverridableErrorCategory&
619 aOverridableErrorCategory) {
620 uint32_t probeValue = MapCertErrorToProbeValue(aCertVerificationError);
621 Telemetry::Accumulate(Telemetry::SSL_CERT_VERIFICATION_ERRORS, probeValue);
623 Maybe<nsITransportSecurityInfo::OverridableErrorCategory>
624 maybeOverridableErrorCategory =
625 CategorizeCertificateError(aCertVerificationError);
626 // If this isn't an overridable error, return it now. This will stop the
627 // connection and report the given error.
628 if (!maybeOverridableErrorCategory.isSome()) {
629 return aCertVerificationError;
631 aOverridableErrorCategory = *maybeOverridableErrorCategory;
633 bool overrideAllowed = false;
634 nsresult rv = OverrideAllowedForHost(aPtrForLog, aHostName, aOriginAttributes,
635 overrideAllowed);
636 if (NS_FAILED(rv)) {
637 return aCertVerificationError;
640 if (!overrideAllowed) {
641 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
642 ("[0x%" PRIx64 "] HSTS or pinned host - no overrides allowed",
643 aPtrForLog));
644 return aCertVerificationError;
647 nsCOMPtr<nsICertOverrideService> overrideService =
648 do_GetService(NS_CERTOVERRIDE_CONTRACTID);
649 if (!overrideService) {
650 return aCertVerificationError;
652 bool haveOverride;
653 bool isTemporaryOverride;
654 rv = overrideService->HasMatchingOverride(aHostName, aPort, aOriginAttributes,
655 aCert, &isTemporaryOverride,
656 &haveOverride);
657 if (NS_FAILED(rv)) {
658 return aCertVerificationError;
660 Unused << isTemporaryOverride;
661 if (haveOverride) {
662 uint32_t probeValue =
663 MapOverridableErrorToProbeValue(aCertVerificationError);
664 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
665 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
666 ("[0x%" PRIx64 "] certificate error overridden", aPtrForLog));
667 return 0;
670 return aCertVerificationError;
673 static nsTArray<nsTArray<uint8_t>> CreateCertBytesArray(
674 const UniqueCERTCertList& aCertChain) {
675 nsTArray<nsTArray<uint8_t>> certsBytes;
676 for (CERTCertListNode* n = CERT_LIST_HEAD(aCertChain);
677 !CERT_LIST_END(n, aCertChain); n = CERT_LIST_NEXT(n)) {
678 nsTArray<uint8_t> certBytes;
679 certBytes.AppendElements(n->cert->derCert.data, n->cert->derCert.len);
680 certsBytes.AppendElement(std::move(certBytes));
682 return certsBytes;
685 /*static*/
686 SECStatus SSLServerCertVerificationJob::Dispatch(
687 uint64_t addrForLogging, void* aPinArg,
688 nsTArray<nsTArray<uint8_t>>&& peerCertChain, const nsACString& aHostName,
689 int32_t aPort, const OriginAttributes& aOriginAttributes,
690 Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
691 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
692 Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, Time time,
693 uint32_t certVerifierFlags,
694 BaseSSLServerCertVerificationResult* aResultTask) {
695 // Runs on the socket transport thread
696 if (!aResultTask || peerCertChain.IsEmpty()) {
697 MOZ_ASSERT_UNREACHABLE(
698 "must have result task and non-empty peer cert chain");
699 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
700 return SECFailure;
703 if (!gCertVerificationThreadPool) {
704 PR_SetError(PR_INVALID_STATE_ERROR, 0);
705 return SECFailure;
708 RefPtr<SSLServerCertVerificationJob> job(new SSLServerCertVerificationJob(
709 addrForLogging, aPinArg, std::move(peerCertChain), aHostName, aPort,
710 aOriginAttributes, stapledOCSPResponse, sctsFromTLSExtension, dcInfo,
711 providerFlags, time, certVerifierFlags, aResultTask));
713 nsresult nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
714 if (NS_FAILED(nrv)) {
715 // We can't call SetCertVerificationResult here to change
716 // mCertVerificationState because SetCertVerificationResult will call
717 // libssl functions that acquire SSL locks that are already being held at
718 // this point. However, we can set an error with PR_SetError and return
719 // SECFailure, and the correct thing will happen (the error will be
720 // propagated and this connection will be terminated).
721 PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY ? PR_OUT_OF_MEMORY_ERROR
722 : PR_INVALID_STATE_ERROR;
723 PR_SetError(error, 0);
724 return SECFailure;
727 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
728 return SECWouldBlock;
731 NS_IMETHODIMP
732 SSLServerCertVerificationJob::Run() {
733 // Runs on a cert verification thread and only on parent process.
734 MOZ_ASSERT(XRE_IsParentProcess());
736 MOZ_LOG(
737 gPIPNSSLog, LogLevel::Debug,
738 ("[%" PRIx64 "] SSLServerCertVerificationJob::Run\n", mAddrForLogging));
740 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
741 if (!certVerifier) {
742 PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
743 return NS_OK;
746 TimeStamp jobStartTime = TimeStamp::Now();
747 EVStatus evStatus;
748 CertificateTransparencyInfo certificateTransparencyInfo;
749 bool isCertChainRootBuiltInRoot = false;
750 bool madeOCSPRequests = false;
751 nsTArray<nsTArray<uint8_t>> builtChainBytesArray;
752 nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
753 Result rv = AuthCertificate(
754 *certVerifier, mPinArg, certBytes, mPeerCertChain, mHostName,
755 mOriginAttributes, mStapledOCSPResponse, mSCTsFromTLSExtension, mDCInfo,
756 mProviderFlags, mTime, mCertVerifierFlags, builtChainBytesArray, evStatus,
757 certificateTransparencyInfo, isCertChainRootBuiltInRoot,
758 madeOCSPRequests);
760 if (rv == Success) {
761 Telemetry::AccumulateTimeDelta(
762 Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX, jobStartTime,
763 TimeStamp::Now());
764 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
766 mResultTask->Dispatch(
767 std::move(builtChainBytesArray), std::move(mPeerCertChain),
768 TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
769 certificateTransparencyInfo),
770 evStatus, true, 0,
771 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET,
772 isCertChainRootBuiltInRoot, mProviderFlags, madeOCSPRequests);
773 return NS_OK;
776 Telemetry::AccumulateTimeDelta(
777 Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX,
778 jobStartTime, TimeStamp::Now());
780 PRErrorCode error = MapResultToPRErrorCode(rv);
781 nsITransportSecurityInfo::OverridableErrorCategory overridableErrorCategory =
782 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET;
783 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
784 PRErrorCode finalError = AuthCertificateParseResults(
785 mAddrForLogging, mHostName, mPort, mOriginAttributes, cert, mTime, error,
786 overridableErrorCategory);
788 // NB: finalError may be 0 here, in which the connection will continue.
789 mResultTask->Dispatch(
790 std::move(builtChainBytesArray), std::move(mPeerCertChain),
791 nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE,
792 EVStatus::NotEV, false, finalError, overridableErrorCategory, false,
793 mProviderFlags, madeOCSPRequests);
794 return NS_OK;
797 // Takes information needed for cert verification, does some consistency
798 // checks and calls SSLServerCertVerificationJob::Dispatch.
799 SECStatus AuthCertificateHookInternal(
800 CommonSocketControl* socketControl, const void* aPtrForLogging,
801 const nsACString& hostName, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
802 Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
803 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
804 Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
805 uint32_t certVerifierFlags) {
806 // Runs on the socket transport thread
808 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
809 ("[%p] starting AuthCertificateHookInternal\n", aPtrForLogging));
811 if (!socketControl || peerCertChain.IsEmpty()) {
812 PR_SetError(PR_INVALID_STATE_ERROR, 0);
813 return SECFailure;
816 bool onSTSThread;
817 nsresult nrv;
818 nsCOMPtr<nsIEventTarget> sts =
819 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
820 if (NS_SUCCEEDED(nrv)) {
821 nrv = sts->IsOnCurrentThread(&onSTSThread);
824 if (NS_FAILED(nrv)) {
825 NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
826 PR_SetError(PR_UNKNOWN_ERROR, 0);
827 return SECFailure;
830 MOZ_ASSERT(onSTSThread);
832 if (!onSTSThread) {
833 PR_SetError(PR_INVALID_STATE_ERROR, 0);
834 return SECFailure;
837 uint64_t addr = reinterpret_cast<uintptr_t>(aPtrForLogging);
838 RefPtr<SSLServerCertVerificationResult> resultTask =
839 new SSLServerCertVerificationResult(socketControl);
841 if (XRE_IsSocketProcess()) {
842 return RemoteProcessCertVerification(
843 std::move(peerCertChain), hostName, socketControl->GetPort(),
844 socketControl->GetOriginAttributes(), stapledOCSPResponse,
845 sctsFromTLSExtension, dcInfo, providerFlags, certVerifierFlags,
846 resultTask);
849 // We *must* do certificate verification on a background thread because
850 // we need the socket transport thread to be free for our OCSP requests,
851 // and we *want* to do certificate verification on a background thread
852 // because of the performance benefits of doing so.
853 return SSLServerCertVerificationJob::Dispatch(
854 addr, socketControl, std::move(peerCertChain), hostName,
855 socketControl->GetPort(), socketControl->GetOriginAttributes(),
856 stapledOCSPResponse, sctsFromTLSExtension, dcInfo, providerFlags, Now(),
857 certVerifierFlags, resultTask);
860 // Extracts whatever information we need out of fd (using SSL_*) and passes it
861 // to AuthCertificateHookInternal. AuthCertificateHookInternal will call
862 // SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob
863 // should never do anything with fd except logging.
864 SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig,
865 PRBool isServer) {
866 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
867 ("[%p] starting AuthCertificateHook\n", fd));
869 // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
870 // doing verification without checking signatures.
871 MOZ_ASSERT(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
873 // PSM never causes libssl to call this function with PR_TRUE for isServer,
874 // and many things in PSM assume that we are a client.
875 MOZ_ASSERT(!isServer, "AuthCertificateHook: isServer unexpectedly true");
877 NSSSocketControl* socketInfo = static_cast<NSSSocketControl*>(arg);
879 UniqueCERTCertificate serverCert(SSL_PeerCertificate(fd));
881 if (!checkSig || isServer || !socketInfo || !serverCert) {
882 PR_SetError(PR_INVALID_STATE_ERROR, 0);
883 return SECFailure;
885 socketInfo->SetFullHandshake();
887 if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess) {
888 return SECFailure;
891 UniqueCERTCertList peerCertChain(SSL_PeerCertificateChain(fd));
892 if (!peerCertChain) {
893 PR_SetError(PR_INVALID_STATE_ERROR, 0);
894 return SECFailure;
897 nsTArray<nsTArray<uint8_t>> peerCertsBytes =
898 CreateCertBytesArray(peerCertChain);
900 // SSL_PeerStapledOCSPResponses will never return a non-empty response if
901 // OCSP stapling wasn't enabled because libssl wouldn't have let the server
902 // return a stapled OCSP response.
903 // We don't own these pointers.
904 const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
905 Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
906 // we currently only support single stapled responses
907 if (csa && csa->len == 1) {
908 stapledOCSPResponse.emplace();
909 stapledOCSPResponse->SetCapacity(csa->items[0].len);
910 stapledOCSPResponse->AppendElements(csa->items[0].data, csa->items[0].len);
913 Maybe<nsTArray<uint8_t>> sctsFromTLSExtension;
914 const SECItem* sctsFromTLSExtensionSECItem = SSL_PeerSignedCertTimestamps(fd);
915 if (sctsFromTLSExtensionSECItem) {
916 sctsFromTLSExtension.emplace();
917 sctsFromTLSExtension->SetCapacity(sctsFromTLSExtensionSECItem->len);
918 sctsFromTLSExtension->AppendElements(sctsFromTLSExtensionSECItem->data,
919 sctsFromTLSExtensionSECItem->len);
922 uint32_t providerFlags = 0;
923 socketInfo->GetProviderFlags(&providerFlags);
925 uint32_t certVerifierFlags = 0;
926 if (!socketInfo->SharedState().IsOCSPStaplingEnabled() ||
927 !socketInfo->SharedState().IsOCSPMustStapleEnabled()) {
928 certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
931 // Get DC information
932 Maybe<DelegatedCredentialInfo> dcInfo;
933 SSLPreliminaryChannelInfo channelPreInfo;
934 SECStatus rv = SSL_GetPreliminaryChannelInfo(fd, &channelPreInfo,
935 sizeof(channelPreInfo));
936 if (rv != SECSuccess) {
937 PR_SetError(PR_INVALID_STATE_ERROR, 0);
938 return SECFailure;
940 if (channelPreInfo.peerDelegCred) {
941 dcInfo.emplace(DelegatedCredentialInfo(channelPreInfo.signatureScheme,
942 channelPreInfo.authKeyBits));
945 // If we configured an ECHConfig and NSS returned the public name
946 // for verification, ECH was rejected. Proceed, verifying to the
947 // public name. The result determines how NSS will fail (i.e. with
948 // any provided retry_configs if successful). See draft-ietf-tls-esni-08.
949 nsCString echConfig;
950 nsresult nsrv = socketInfo->GetEchConfig(echConfig);
951 bool verifyToEchPublicName =
952 NS_SUCCEEDED(nsrv) && echConfig.Length() && channelPreInfo.echPublicName;
954 const nsCString echPublicName(channelPreInfo.echPublicName);
955 const nsACString& hostname =
956 verifyToEchPublicName ? echPublicName : socketInfo->GetHostName();
957 socketInfo->SetCertVerificationWaiting();
958 rv = AuthCertificateHookInternal(socketInfo, static_cast<const void*>(fd),
959 hostname, std::move(peerCertsBytes),
960 stapledOCSPResponse, sctsFromTLSExtension,
961 dcInfo, providerFlags, certVerifierFlags);
962 return rv;
965 // Takes information needed for cert verification, does some consistency
966 // checks and calls SSLServerCertVerificationJob::Dispatch.
967 // This function is used for Quic.
968 SECStatus AuthCertificateHookWithInfo(
969 CommonSocketControl* socketControl, const nsACString& aHostName,
970 const void* aPtrForLogging, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
971 Maybe<nsTArray<nsTArray<uint8_t>>>& stapledOCSPResponses,
972 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, uint32_t providerFlags) {
973 if (peerCertChain.IsEmpty()) {
974 PR_SetError(PR_INVALID_STATE_ERROR, 0);
975 return SECFailure;
978 // we currently only support single stapled responses
979 Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
980 if (stapledOCSPResponses && (stapledOCSPResponses->Length() == 1)) {
981 stapledOCSPResponse.emplace(stapledOCSPResponses->ElementAt(0).Clone());
984 uint32_t certVerifierFlags = 0;
985 // QuicSocketControl does not have a SharedState as NSSSocketControl.
986 // Here we need prefs for ocsp. This are prefs they are the same for
987 // PublicSSLState and PrivateSSLState, just take them from one of them.
988 if (!PublicSSLState()->IsOCSPStaplingEnabled() ||
989 !PublicSSLState()->IsOCSPMustStapleEnabled()) {
990 certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
993 // Need to update Quic stack to reflect the PreliminaryInfo fields
994 // for Delegated Credentials.
995 Maybe<DelegatedCredentialInfo> dcInfo;
997 return AuthCertificateHookInternal(socketControl, aPtrForLogging, aHostName,
998 std::move(peerCertChain),
999 stapledOCSPResponse, sctsFromTLSExtension,
1000 dcInfo, providerFlags, certVerifierFlags);
1003 NS_IMPL_ISUPPORTS_INHERITED0(SSLServerCertVerificationResult, Runnable)
1005 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
1006 CommonSocketControl* socketControl)
1007 : Runnable("psm::SSLServerCertVerificationResult"),
1008 mSocketControl(socketControl),
1009 mCertificateTransparencyStatus(0),
1010 mEVStatus(EVStatus::NotEV),
1011 mSucceeded(false),
1012 mFinalError(0),
1013 mOverridableErrorCategory(
1014 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET),
1015 mProviderFlags(0) {}
1017 void SSLServerCertVerificationResult::Dispatch(
1018 nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
1019 nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
1020 uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
1021 bool aSucceeded, PRErrorCode aFinalError,
1022 nsITransportSecurityInfo::OverridableErrorCategory
1023 aOverridableErrorCategory,
1024 bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
1025 bool aMadeOCSPRequests) {
1026 mBuiltChain = std::move(aBuiltChain);
1027 mPeerCertChain = std::move(aPeerCertChain);
1028 mCertificateTransparencyStatus = aCertificateTransparencyStatus;
1029 mEVStatus = aEVStatus;
1030 mSucceeded = aSucceeded;
1031 mFinalError = aFinalError;
1032 mOverridableErrorCategory = aOverridableErrorCategory;
1033 mIsBuiltCertChainRootBuiltInRoot = aIsBuiltCertChainRootBuiltInRoot;
1034 mProviderFlags = aProviderFlags;
1035 mMadeOCSPRequests = aMadeOCSPRequests;
1037 if (mSucceeded && mBuiltChain.IsEmpty()) {
1038 MOZ_ASSERT_UNREACHABLE(
1039 "if the handshake succeeded, the built chain shouldn't be empty");
1040 mSucceeded = false;
1041 mFinalError = SEC_ERROR_LIBRARY_FAILURE;
1043 if (!mSucceeded && mPeerCertChain.IsEmpty()) {
1044 MOZ_ASSERT_UNREACHABLE(
1045 "if the handshake failed, the peer chain shouldn't be empty");
1046 mFinalError = SEC_ERROR_LIBRARY_FAILURE;
1049 nsresult rv;
1050 nsCOMPtr<nsIEventTarget> stsTarget =
1051 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
1052 MOZ_ASSERT(stsTarget, "Failed to get socket transport service event target");
1053 rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
1054 MOZ_ASSERT(NS_SUCCEEDED(rv),
1055 "Failed to dispatch SSLServerCertVerificationResult");
1058 NS_IMETHODIMP
1059 SSLServerCertVerificationResult::Run() {
1060 #ifdef DEBUG
1061 bool onSTSThread = false;
1062 nsresult nrv;
1063 nsCOMPtr<nsIEventTarget> sts =
1064 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
1065 if (NS_SUCCEEDED(nrv)) {
1066 nrv = sts->IsOnCurrentThread(&onSTSThread);
1069 MOZ_ASSERT(onSTSThread);
1070 #endif
1072 if (mSucceeded && !XRE_IsSocketProcess() &&
1073 !(mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE)) {
1074 // This dispatches an event that will run when the socket thread is idle.
1075 SaveIntermediateCerts(mBuiltChain);
1078 mSocketControl->SetMadeOCSPRequests(mMadeOCSPRequests);
1080 if (mSucceeded) {
1081 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1082 ("SSLServerCertVerificationResult::Run setting NEW cert"));
1083 nsTArray<uint8_t> certBytes(mBuiltChain.ElementAt(0).Clone());
1084 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
1085 mSocketControl->SetServerCert(cert, mEVStatus);
1086 mSocketControl->SetSucceededCertChain(std::move(mBuiltChain));
1088 mSocketControl->SetIsBuiltCertChainRootBuiltInRoot(
1089 mIsBuiltCertChainRootBuiltInRoot);
1090 mSocketControl->SetCertificateTransparencyStatus(
1091 mCertificateTransparencyStatus);
1092 } else {
1093 nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
1094 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
1095 // Certificate validation failed; store the peer certificate chain on
1096 // mSocketControl so it can be used for error reporting.
1097 mSocketControl->SetFailedCertChain(std::move(mPeerCertChain));
1098 if (mOverridableErrorCategory !=
1099 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET) {
1100 mSocketControl->SetStatusErrorBits(cert, mOverridableErrorCategory);
1104 mSocketControl->SetCertVerificationResult(mFinalError);
1105 return NS_OK;
1108 } // namespace psm
1109 } // namespace mozilla