Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / security / manager / ssl / SSLServerCertVerification.cpp
blobdee770652ca1c4bc3d9577652e5550f79e430fad
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 "VerifySSLServerCertChild.h"
107 #include "cert.h"
108 #include "mozilla/Assertions.h"
109 #include "mozilla/Casting.h"
110 #include "mozilla/RefPtr.h"
111 #include "mozilla/StaticPrefs_security.h"
112 #include "mozilla/Telemetry.h"
113 #include "mozilla/UniquePtr.h"
114 #include "mozilla/Unused.h"
115 #include "mozilla/glean/GleanMetrics.h"
116 #include "nsComponentManagerUtils.h"
117 #include "nsContentUtils.h"
118 #include "nsICertOverrideService.h"
119 #include "nsIPublicKeyPinningService.h"
120 #include "nsISiteSecurityService.h"
121 #include "nsISocketProvider.h"
122 #include "nsThreadPool.h"
123 #include "nsNetUtil.h"
124 #include "nsNSSCertificate.h"
125 #include "nsNSSComponent.h"
126 #include "nsNSSIOLayer.h"
127 #include "nsServiceManagerUtils.h"
128 #include "nsString.h"
129 #include "nsURLHelper.h"
130 #include "nsXPCOMCIDInternal.h"
131 #include "mozpkix/pkix.h"
132 #include "mozpkix/pkixcheck.h"
133 #include "mozpkix/pkixnss.h"
134 #include "mozpkix/pkixutil.h"
135 #include "secerr.h"
136 #include "secport.h"
137 #include "ssl.h"
138 #include "sslerr.h"
139 #include "sslexp.h"
141 extern mozilla::LazyLogModule gPIPNSSLog;
143 using namespace mozilla::pkix;
145 namespace mozilla {
146 namespace psm {
148 // do not use a nsCOMPtr to avoid static initializer/destructor
149 nsIThreadPool* gCertVerificationThreadPool = nullptr;
151 // Called when the socket transport thread starts, to initialize the SSL cert
152 // verification thread pool. By tying the thread pool startup/shutdown directly
153 // to the STS thread's lifetime, we ensure that they are *always* available for
154 // SSL connections and that there are no races during startup and especially
155 // shutdown. (Previously, we have had multiple problems with races in PSM
156 // background threads, and the race-prevention/shutdown logic used there is
157 // brittle. Since this service is critical to things like downloading updates,
158 // we take no chances.) Also, by doing things this way, we avoid the need for
159 // locks, since gCertVerificationThreadPool is only ever accessed on the socket
160 // transport thread.
161 void InitializeSSLServerCertVerificationThreads() {
162 // TODO: tuning, make parameters preferences
163 gCertVerificationThreadPool = new nsThreadPool();
164 NS_ADDREF(gCertVerificationThreadPool);
166 (void)gCertVerificationThreadPool->SetThreadLimit(5);
167 (void)gCertVerificationThreadPool->SetIdleThreadLimit(1);
168 (void)gCertVerificationThreadPool->SetIdleThreadMaximumTimeout(30 * 1000);
169 (void)gCertVerificationThreadPool->SetIdleThreadGraceTimeout(500);
170 (void)gCertVerificationThreadPool->SetName("SSL Cert"_ns);
173 // Called when the socket transport thread finishes, to destroy the thread
174 // pool. Since the socket transport service has stopped processing events, it
175 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
176 // down the SSL cert verification infrastructure. Also, the STS will not
177 // dispatch many SSL verification result events at this point, so any pending
178 // cert verifications will (correctly) fail at the point they are dispatched.
180 // The other shutdown race condition that is possible is a race condition with
181 // shutdown of the nsNSSComponent service. We use the
182 // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
183 void StopSSLServerCertVerificationThreads() {
184 if (gCertVerificationThreadPool) {
185 gCertVerificationThreadPool->Shutdown();
186 NS_RELEASE(gCertVerificationThreadPool);
190 // A probe value of 1 means "no error".
191 uint32_t MapOverridableErrorToProbeValue(PRErrorCode errorCode) {
192 switch (errorCode) {
193 case SEC_ERROR_UNKNOWN_ISSUER:
194 return 2;
195 case SEC_ERROR_CA_CERT_INVALID:
196 return 3;
197 case SEC_ERROR_UNTRUSTED_ISSUER:
198 return 4;
199 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
200 return 5;
201 case SEC_ERROR_UNTRUSTED_CERT:
202 return 6;
203 case SEC_ERROR_INADEQUATE_KEY_USAGE:
204 return 7;
205 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
206 return 8;
207 case SSL_ERROR_BAD_CERT_DOMAIN:
208 return 9;
209 case SEC_ERROR_EXPIRED_CERTIFICATE:
210 return 10;
211 case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
212 return 11;
213 case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
214 return 12;
215 case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
216 return 13;
217 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
218 return 14;
219 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
220 return 15;
221 case SEC_ERROR_INVALID_TIME:
222 return 16;
223 case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
224 return 17;
225 case mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED:
226 return 18;
227 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
228 return 19;
229 case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
230 return 20;
231 case mozilla::pkix::
232 MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY:
233 return 21;
235 NS_WARNING(
236 "Unknown certificate error code. Does MapOverridableErrorToProbeValue "
237 "handle everything in CategorizeCertificateError?");
238 return 0;
241 static uint32_t MapCertErrorToProbeValue(PRErrorCode errorCode) {
242 uint32_t probeValue;
243 switch (errorCode) {
244 // see security/pkix/include/pkix/Result.h
245 #define MOZILLA_PKIX_MAP(name, value, nss_name) \
246 case nss_name: \
247 probeValue = value; \
248 break;
249 MOZILLA_PKIX_MAP_LIST
250 #undef MOZILLA_PKIX_MAP
251 default:
252 return 0;
255 // Since FATAL_ERROR_FLAG is 0x800, fatal error values are much larger than
256 // non-fatal error values. To conserve space, we remap these so they start at
257 // (decimal) 90 instead of 0x800. Currently there are ~50 non-fatal errors
258 // mozilla::pkix might return, so saving space for 90 should be sufficient
259 // (similarly, there are 4 fatal errors, so saving space for 10 should also
260 // be sufficient).
261 static_assert(
262 FATAL_ERROR_FLAG == 0x800,
263 "mozilla::pkix::FATAL_ERROR_FLAG is not what we were expecting");
264 if (probeValue & FATAL_ERROR_FLAG) {
265 probeValue ^= FATAL_ERROR_FLAG;
266 probeValue += 90;
268 return probeValue;
271 // If the given PRErrorCode is an overridable certificate error, return which
272 // category (trust, time, domain mismatch) it falls in. If it is not
273 // overridable, return Nothing.
274 Maybe<nsITransportSecurityInfo::OverridableErrorCategory>
275 CategorizeCertificateError(PRErrorCode certificateError) {
276 switch (certificateError) {
277 case SEC_ERROR_CA_CERT_INVALID:
278 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
279 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
280 case SEC_ERROR_UNKNOWN_ISSUER:
281 case mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED:
282 case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
283 case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME:
284 case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
285 case mozilla::pkix::
286 MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY:
287 case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED:
288 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
289 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
290 case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
291 return Some(
292 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST);
294 case SSL_ERROR_BAD_CERT_DOMAIN:
295 return Some(
296 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_DOMAIN);
298 case SEC_ERROR_EXPIRED_CERTIFICATE:
299 case SEC_ERROR_INVALID_TIME:
300 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
301 return Some(
302 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME);
304 default:
305 break;
307 return Nothing();
310 // Helper function to determine if overrides are allowed for this host.
311 // Overrides are not allowed for known HSTS hosts or hosts with pinning
312 // information. However, IP addresses can never be HSTS hosts and don't have
313 // pinning information.
314 static nsresult OverrideAllowedForHost(
315 uint64_t aPtrForLog, const nsACString& aHostname,
316 const OriginAttributes& aOriginAttributes, /*out*/ bool& aOverrideAllowed) {
317 aOverrideAllowed = false;
319 // If this is an IP address, overrides are allowed, because an IP address is
320 // never an HSTS host. nsISiteSecurityService takes this into account
321 // already, but the real problem here is that calling NS_NewURI with an IPv6
322 // address fails. We do this to avoid that. A more comprehensive fix would be
323 // to have Necko provide an nsIURI to PSM and to use that here (and
324 // everywhere). However, that would be a wide-spanning change.
325 if (net_IsValidIPv6Addr(aHostname)) {
326 aOverrideAllowed = true;
327 return NS_OK;
330 // If this is an HTTP Strict Transport Security host or a pinned host and the
331 // certificate is bad, don't allow overrides (RFC 6797 section 12.1).
332 bool strictTransportSecurityEnabled = false;
333 bool isStaticallyPinned = false;
334 nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID));
335 if (!sss) {
336 MOZ_LOG(
337 gPIPNSSLog, LogLevel::Debug,
338 ("[0x%" PRIx64 "] Couldn't get nsISiteSecurityService to check HSTS",
339 aPtrForLog));
340 return NS_ERROR_FAILURE;
343 nsCOMPtr<nsIURI> uri;
344 nsresult rv = NS_NewURI(getter_AddRefs(uri), "https://"_ns + aHostname);
345 if (NS_FAILED(rv)) {
346 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
347 ("[0x%" PRIx64 "] Creating new URI failed", aPtrForLog));
348 return rv;
351 rv =
352 sss->IsSecureURI(uri, aOriginAttributes, &strictTransportSecurityEnabled);
353 if (NS_FAILED(rv)) {
354 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
355 ("[0x%" PRIx64 "] checking for HSTS failed", aPtrForLog));
356 return rv;
359 nsCOMPtr<nsIPublicKeyPinningService> pkps =
360 do_GetService(NS_PKPSERVICE_CONTRACTID, &rv);
361 if (!pkps) {
362 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
363 ("[0x%" PRIx64
364 "] Couldn't get nsIPublicKeyPinningService to check pinning",
365 aPtrForLog));
366 return NS_ERROR_FAILURE;
368 rv = pkps->HostHasPins(uri, &isStaticallyPinned);
369 if (NS_FAILED(rv)) {
370 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
371 ("[0x%" PRIx64 "] checking for static pin failed", aPtrForLog));
372 return rv;
375 aOverrideAllowed = !strictTransportSecurityEnabled && !isStaticallyPinned;
376 return NS_OK;
379 // This function assumes that we will only use the SPDY connection coalescing
380 // feature on connections where we have negotiated SPDY using NPN. If we ever
381 // talk SPDY without having negotiated it with SPDY, this code will give wrong
382 // and perhaps unsafe results.
384 // Returns SECSuccess on the initial handshake of all connections, on
385 // renegotiations for any connections where we did not negotiate SPDY, or on any
386 // SPDY connection where the server's certificate did not change.
388 // Prohibit changing the server cert only if we negotiated SPDY,
389 // in order to support SPDY's cross-origin connection pooling.
390 static SECStatus BlockServerCertChangeForSpdy(
391 NSSSocketControl* socketControl, const UniqueCERTCertificate& serverCert) {
392 if (!socketControl->IsHandshakeCompleted()) {
393 // first handshake on this connection, not a
394 // renegotiation.
395 return SECSuccess;
398 // Filter out sockets that did not neogtiate SPDY via NPN
399 nsCOMPtr<nsITransportSecurityInfo> securityInfo;
400 nsresult rv = socketControl->GetSecurityInfo(getter_AddRefs(securityInfo));
401 MOZ_ASSERT(NS_SUCCEEDED(rv), "GetSecurityInfo() failed during renegotiation");
402 if (NS_FAILED(rv) || !securityInfo) {
403 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
404 return SECFailure;
406 nsAutoCString negotiatedNPN;
407 rv = securityInfo->GetNegotiatedNPN(negotiatedNPN);
408 MOZ_ASSERT(NS_SUCCEEDED(rv),
409 "GetNegotiatedNPN() failed during renegotiation");
411 if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN, "spdy/"_ns)) {
412 return SECSuccess;
414 // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
415 if (NS_FAILED(rv)) {
416 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
417 ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
418 " Assuming spdy."));
421 // Check to see if the cert has actually changed
422 nsCOMPtr<nsIX509Cert> cert(socketControl->GetServerCert());
423 if (!cert) {
424 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
425 return SECFailure;
427 nsTArray<uint8_t> certDER;
428 if (NS_FAILED(cert->GetRawDER(certDER))) {
429 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
430 return SECFailure;
432 if (certDER.Length() == serverCert->derCert.len &&
433 memcmp(certDER.Elements(), serverCert->derCert.data, certDER.Length()) ==
434 0) {
435 return SECSuccess;
438 // Report an error - changed cert is confirmed
439 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
440 ("SPDY refused to allow new cert during renegotiation"));
441 PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
442 return SECFailure;
445 void GatherTelemetryForSingleSCT(const ct::VerifiedSCT& verifiedSct) {
446 // See SSL_SCTS_VERIFICATION_STATUS in Histograms.json.
447 uint32_t verificationStatus = 0;
448 switch (verifiedSct.logState) {
449 case ct::CTLogState::Admissible:
450 verificationStatus = 1;
451 break;
452 case ct::CTLogState::Retired:
453 verificationStatus = 5;
454 break;
456 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS,
457 verificationStatus);
460 void GatherCertificateTransparencyTelemetry(
461 const nsTArray<uint8_t>& rootCert,
462 const CertificateTransparencyInfo& info) {
463 if (!info.enabled) {
464 // No telemetry is gathered when CT is disabled.
465 return;
468 for (const ct::VerifiedSCT& sct : info.verifyResult.verifiedScts) {
469 GatherTelemetryForSingleSCT(sct);
472 // See SSL_SCTS_VERIFICATION_STATUS in Histograms.json.
473 for (size_t i = 0; i < info.verifyResult.decodingErrors; ++i) {
474 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 0);
476 for (size_t i = 0; i < info.verifyResult.sctsFromUnknownLogs; ++i) {
477 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 2);
479 for (size_t i = 0; i < info.verifyResult.sctsWithInvalidSignatures; ++i) {
480 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 3);
482 for (size_t i = 0; i < info.verifyResult.sctsWithInvalidTimestamps; ++i) {
483 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS, 4);
486 // See SSL_SCTS_ORIGIN in Histograms.json.
487 for (size_t i = 0; i < info.verifyResult.embeddedSCTs; ++i) {
488 Telemetry::Accumulate(Telemetry::SSL_SCTS_ORIGIN, 1);
490 for (size_t i = 0; i < info.verifyResult.sctsFromTLSHandshake; ++i) {
491 Telemetry::Accumulate(Telemetry::SSL_SCTS_ORIGIN, 2);
493 for (size_t i = 0; i < info.verifyResult.sctsFromOCSP; ++i) {
494 Telemetry::Accumulate(Telemetry::SSL_SCTS_ORIGIN, 3);
497 // Handle the histogram of SCTs counts.
498 uint32_t sctsCount =
499 static_cast<uint32_t>(info.verifyResult.verifiedScts.size());
500 // Note that sctsCount can also be 0 in case we've received SCT binary data,
501 // but it failed to parse (e.g. due to unsupported CT protocol version).
502 Telemetry::Accumulate(Telemetry::SSL_SCTS_PER_CONNECTION, sctsCount);
504 // Report CT Policy compliance by CA.
505 if (info.policyCompliance.isSome() &&
506 *info.policyCompliance != ct::CTPolicyCompliance::Compliant) {
507 AccumulateTelemetryForRootCA(
508 Telemetry::SSL_CT_POLICY_NON_COMPLIANT_CONNECTIONS_BY_CA_2, rootCert);
512 // This function collects telemetry about certs. It will be called on one of
513 // CertVerificationThread. When the socket process is used this will be called
514 // on the parent process.
515 static void CollectCertTelemetry(
516 mozilla::pkix::Result aCertVerificationResult, EVStatus aEVStatus,
517 CertVerifier::OCSPStaplingStatus aOcspStaplingStatus,
518 KeySizeStatus aKeySizeStatus,
519 const PinningTelemetryInfo& aPinningTelemetryInfo,
520 const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain,
521 const CertificateTransparencyInfo& aCertificateTransparencyInfo,
522 const IssuerSources& issuerSources) {
523 uint32_t evStatus = (aCertVerificationResult != Success) ? 0 // 0 = Failure
524 : (aEVStatus != EVStatus::EV) ? 1 // 1 = DV
525 : 2; // 2 = EV
526 Telemetry::Accumulate(Telemetry::CERT_EV_STATUS, evStatus);
528 if (aOcspStaplingStatus != CertVerifier::OCSP_STAPLING_NEVER_CHECKED) {
529 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, aOcspStaplingStatus);
532 if (aKeySizeStatus != KeySizeStatus::NeverChecked) {
533 Telemetry::Accumulate(Telemetry::CERT_CHAIN_KEY_SIZE_STATUS,
534 static_cast<uint32_t>(aKeySizeStatus));
537 if (aPinningTelemetryInfo.accumulateForRoot) {
538 Telemetry::Accumulate(Telemetry::CERT_PINNING_FAILURES_BY_CA_2,
539 aPinningTelemetryInfo.rootBucket);
542 if (aPinningTelemetryInfo.accumulateResult) {
543 MOZ_ASSERT(aPinningTelemetryInfo.certPinningResultHistogram.isSome());
544 Telemetry::Accumulate(
545 aPinningTelemetryInfo.certPinningResultHistogram.value(),
546 aPinningTelemetryInfo.certPinningResultBucket);
549 if (aCertVerificationResult == Success && aBuiltCertChain.Length() > 0) {
550 const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement();
551 AccumulateTelemetryForRootCA(Telemetry::CERT_VALIDATION_SUCCESS_BY_CA_2,
552 rootCert);
554 mozilla::glean::tls::certificate_verifications.Add(1);
555 if (issuerSources.contains(IssuerSource::TLSHandshake)) {
556 mozilla::glean::verification_used_cert_from::tls_handshake.AddToNumerator(
559 if (issuerSources.contains(IssuerSource::PreloadedIntermediates)) {
560 mozilla::glean::verification_used_cert_from::preloaded_intermediates
561 .AddToNumerator(1);
563 if (issuerSources.contains(IssuerSource::ThirdPartyCertificates)) {
564 mozilla::glean::verification_used_cert_from::third_party_certificates
565 .AddToNumerator(1);
567 if (issuerSources.contains(IssuerSource::NSSCertDB)) {
568 mozilla::glean::verification_used_cert_from::nss_cert_db.AddToNumerator(
571 if (issuerSources.contains(IssuerSource::BuiltInRootsModule)) {
572 mozilla::glean::verification_used_cert_from::built_in_roots_module
573 .AddToNumerator(1);
577 if ((aCertVerificationResult == Success ||
578 aCertVerificationResult ==
579 Result::ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY) &&
580 aBuiltCertChain.Length() > 0) {
581 const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement();
582 GatherCertificateTransparencyTelemetry(rootCert,
583 aCertificateTransparencyInfo);
587 // Note: Takes ownership of |peerCertChain| if SECSuccess is not returned.
588 Result AuthCertificate(
589 CertVerifier& certVerifier, void* aPinArg,
590 const nsTArray<uint8_t>& certBytes,
591 const nsTArray<nsTArray<uint8_t>>& peerCertChain,
592 const nsACString& aHostName, const OriginAttributes& aOriginAttributes,
593 const Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
594 const Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
595 const Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
596 Time time, uint32_t certVerifierFlags,
597 /*out*/ nsTArray<nsTArray<uint8_t>>& builtCertChain,
598 /*out*/ EVStatus& evStatus,
599 /*out*/ CertificateTransparencyInfo& certificateTransparencyInfo,
600 /*out*/ bool& aIsBuiltCertChainRootBuiltInRoot,
601 /*out*/ bool& aMadeOCSPRequests) {
602 CertVerifier::OCSPStaplingStatus ocspStaplingStatus =
603 CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
604 KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked;
605 PinningTelemetryInfo pinningTelemetryInfo;
607 nsTArray<nsTArray<uint8_t>> peerCertsBytes;
608 // Don't include the end-entity certificate.
609 if (!peerCertChain.IsEmpty()) {
610 std::transform(
611 peerCertChain.cbegin() + 1, peerCertChain.cend(),
612 MakeBackInserter(peerCertsBytes),
613 [](const auto& elementArray) { return elementArray.Clone(); });
616 IssuerSources issuerSources;
617 Result rv = certVerifier.VerifySSLServerCert(
618 certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags,
619 Some(std::move(peerCertsBytes)), stapledOCSPResponse,
620 sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus,
621 &ocspStaplingStatus, &keySizeStatus, &pinningTelemetryInfo,
622 &certificateTransparencyInfo, &aIsBuiltCertChainRootBuiltInRoot,
623 &aMadeOCSPRequests, &issuerSources);
625 CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus,
626 pinningTelemetryInfo, builtCertChain,
627 certificateTransparencyInfo, issuerSources);
629 return rv;
632 PRErrorCode AuthCertificateParseResults(
633 uint64_t aPtrForLog, const nsACString& aHostName, int32_t aPort,
634 const OriginAttributes& aOriginAttributes,
635 const nsCOMPtr<nsIX509Cert>& aCert, mozilla::pkix::Time aTime,
636 PRErrorCode aCertVerificationError,
637 /* out */
638 nsITransportSecurityInfo::OverridableErrorCategory&
639 aOverridableErrorCategory) {
640 uint32_t probeValue = MapCertErrorToProbeValue(aCertVerificationError);
641 Telemetry::Accumulate(Telemetry::SSL_CERT_VERIFICATION_ERRORS, probeValue);
643 Maybe<nsITransportSecurityInfo::OverridableErrorCategory>
644 maybeOverridableErrorCategory =
645 CategorizeCertificateError(aCertVerificationError);
646 // If this isn't an overridable error, return it now. This will stop the
647 // connection and report the given error.
648 if (!maybeOverridableErrorCategory.isSome()) {
649 return aCertVerificationError;
651 aOverridableErrorCategory = *maybeOverridableErrorCategory;
653 bool overrideAllowed = false;
654 nsresult rv = OverrideAllowedForHost(aPtrForLog, aHostName, aOriginAttributes,
655 overrideAllowed);
656 if (NS_FAILED(rv)) {
657 return aCertVerificationError;
660 if (!overrideAllowed) {
661 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
662 ("[0x%" PRIx64 "] HSTS or pinned host - no overrides allowed",
663 aPtrForLog));
664 return aCertVerificationError;
667 nsCOMPtr<nsICertOverrideService> overrideService =
668 do_GetService(NS_CERTOVERRIDE_CONTRACTID);
669 if (!overrideService) {
670 return aCertVerificationError;
672 bool haveOverride;
673 bool isTemporaryOverride;
674 rv = overrideService->HasMatchingOverride(aHostName, aPort, aOriginAttributes,
675 aCert, &isTemporaryOverride,
676 &haveOverride);
677 if (NS_FAILED(rv)) {
678 return aCertVerificationError;
680 Unused << isTemporaryOverride;
681 if (haveOverride) {
682 uint32_t probeValue =
683 MapOverridableErrorToProbeValue(aCertVerificationError);
684 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
685 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
686 ("[0x%" PRIx64 "] certificate error overridden", aPtrForLog));
687 return 0;
690 return aCertVerificationError;
693 static nsTArray<nsTArray<uint8_t>> CreateCertBytesArray(
694 const UniqueSECItemArray& aCertChain) {
695 nsTArray<nsTArray<uint8_t>> certsBytes;
696 for (size_t i = 0; i < aCertChain->len; i++) {
697 nsTArray<uint8_t> certBytes;
698 certBytes.AppendElements(aCertChain->items[i].data,
699 aCertChain->items[i].len);
700 certsBytes.AppendElement(std::move(certBytes));
702 return certsBytes;
705 /*static*/
706 SECStatus SSLServerCertVerificationJob::Dispatch(
707 uint64_t addrForLogging, void* aPinArg,
708 nsTArray<nsTArray<uint8_t>>&& peerCertChain, const nsACString& aHostName,
709 int32_t aPort, const OriginAttributes& aOriginAttributes,
710 Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
711 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
712 Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, Time time,
713 uint32_t certVerifierFlags,
714 BaseSSLServerCertVerificationResult* aResultTask) {
715 // Runs on the socket transport thread
716 if (!aResultTask || peerCertChain.IsEmpty()) {
717 MOZ_ASSERT_UNREACHABLE(
718 "must have result task and non-empty peer cert chain");
719 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
720 return SECFailure;
723 if (!gCertVerificationThreadPool) {
724 PR_SetError(PR_INVALID_STATE_ERROR, 0);
725 return SECFailure;
728 RefPtr<SSLServerCertVerificationJob> job(new SSLServerCertVerificationJob(
729 addrForLogging, aPinArg, std::move(peerCertChain), aHostName, aPort,
730 aOriginAttributes, stapledOCSPResponse, sctsFromTLSExtension, dcInfo,
731 providerFlags, time, certVerifierFlags, aResultTask));
733 nsresult nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
734 if (NS_FAILED(nrv)) {
735 // We can't call SetCertVerificationResult here to change
736 // mCertVerificationState because SetCertVerificationResult will call
737 // libssl functions that acquire SSL locks that are already being held at
738 // this point. However, we can set an error with PR_SetError and return
739 // SECFailure, and the correct thing will happen (the error will be
740 // propagated and this connection will be terminated).
741 PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY ? PR_OUT_OF_MEMORY_ERROR
742 : PR_INVALID_STATE_ERROR;
743 PR_SetError(error, 0);
744 return SECFailure;
747 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
748 return SECWouldBlock;
751 NS_IMETHODIMP
752 SSLServerCertVerificationJob::Run() {
753 // Runs on a cert verification thread and only on parent process.
754 MOZ_ASSERT(XRE_IsParentProcess());
756 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
757 ("[%" PRIx64 "] SSLServerCertVerificationJob::Run", mAddrForLogging));
759 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
760 if (!certVerifier) {
761 // We can't release this off the STS thread because some parts of it
762 // are not threadsafe. Just leak mResultTask.
763 Unused << mResultTask.forget();
764 return NS_ERROR_FAILURE;
767 TimeStamp jobStartTime = TimeStamp::Now();
768 EVStatus evStatus;
769 CertificateTransparencyInfo certificateTransparencyInfo;
770 bool isCertChainRootBuiltInRoot = false;
771 bool madeOCSPRequests = false;
772 nsTArray<nsTArray<uint8_t>> builtChainBytesArray;
773 nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
774 Result result = AuthCertificate(
775 *certVerifier, mPinArg, certBytes, mPeerCertChain, mHostName,
776 mOriginAttributes, mStapledOCSPResponse, mSCTsFromTLSExtension, mDCInfo,
777 mProviderFlags, mTime, mCertVerifierFlags, builtChainBytesArray, evStatus,
778 certificateTransparencyInfo, isCertChainRootBuiltInRoot,
779 madeOCSPRequests);
781 TimeDuration elapsed = TimeStamp::Now() - jobStartTime;
782 if (result == Success) {
783 mozilla::glean::cert_verification_time::success.AccumulateRawDuration(
784 elapsed);
785 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
787 nsresult rv = mResultTask->Dispatch(
788 std::move(builtChainBytesArray), std::move(mPeerCertChain),
789 TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
790 certificateTransparencyInfo),
791 evStatus, true, 0,
792 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET,
793 isCertChainRootBuiltInRoot, mProviderFlags, madeOCSPRequests);
794 if (NS_FAILED(rv)) {
795 // We can't release this off the STS thread because some parts of it
796 // are not threadsafe. Just leak mResultTask.
797 Unused << mResultTask.forget();
799 return rv;
802 mozilla::glean::cert_verification_time::failure.AccumulateRawDuration(
803 elapsed);
805 PRErrorCode error = MapResultToPRErrorCode(result);
806 nsITransportSecurityInfo::OverridableErrorCategory overridableErrorCategory =
807 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET;
808 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
809 PRErrorCode finalError = AuthCertificateParseResults(
810 mAddrForLogging, mHostName, mPort, mOriginAttributes, cert, mTime, error,
811 overridableErrorCategory);
813 // NB: finalError may be 0 here, in which the connection will continue.
814 nsresult rv = mResultTask->Dispatch(
815 std::move(builtChainBytesArray), std::move(mPeerCertChain),
816 TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
817 certificateTransparencyInfo),
818 EVStatus::NotEV, false, finalError, overridableErrorCategory,
819 // If the certificate verifier returned Result::ERROR_BAD_CERT_DOMAIN,
820 // a chain was built, so isCertChainRootBuiltInRoot is valid and
821 // potentially useful. Otherwise, assume no chain was built.
822 result == Result::ERROR_BAD_CERT_DOMAIN ? isCertChainRootBuiltInRoot
823 : false,
824 mProviderFlags, madeOCSPRequests);
825 if (NS_FAILED(rv)) {
826 // We can't release this off the STS thread because some parts of it
827 // are not threadsafe. Just leak mResultTask.
828 Unused << mResultTask.forget();
830 return rv;
833 // Takes information needed for cert verification, does some consistency
834 // checks and calls SSLServerCertVerificationJob::Dispatch.
835 SECStatus AuthCertificateHookInternal(
836 CommonSocketControl* socketControl, const void* aPtrForLogging,
837 const nsACString& hostName, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
838 Maybe<nsTArray<uint8_t>>& stapledOCSPResponse,
839 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension,
840 Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags,
841 uint32_t certVerifierFlags) {
842 // Runs on the socket transport thread
844 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
845 ("[%p] starting AuthCertificateHookInternal\n", aPtrForLogging));
847 if (!socketControl || peerCertChain.IsEmpty()) {
848 PR_SetError(PR_INVALID_STATE_ERROR, 0);
849 return SECFailure;
852 bool onSTSThread;
853 nsresult nrv;
854 nsCOMPtr<nsIEventTarget> sts =
855 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
856 if (NS_SUCCEEDED(nrv)) {
857 nrv = sts->IsOnCurrentThread(&onSTSThread);
860 if (NS_FAILED(nrv)) {
861 NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
862 PR_SetError(PR_UNKNOWN_ERROR, 0);
863 return SECFailure;
866 MOZ_ASSERT(onSTSThread);
868 if (!onSTSThread) {
869 PR_SetError(PR_INVALID_STATE_ERROR, 0);
870 return SECFailure;
873 uint64_t addr = reinterpret_cast<uintptr_t>(aPtrForLogging);
874 RefPtr<SSLServerCertVerificationResult> resultTask =
875 new SSLServerCertVerificationResult(socketControl);
877 if (XRE_IsSocketProcess()) {
878 return RemoteProcessCertVerification(
879 std::move(peerCertChain), hostName, socketControl->GetPort(),
880 socketControl->GetOriginAttributes(), stapledOCSPResponse,
881 sctsFromTLSExtension, dcInfo, providerFlags, certVerifierFlags,
882 resultTask);
885 // We *must* do certificate verification on a background thread because
886 // we need the socket transport thread to be free for our OCSP requests,
887 // and we *want* to do certificate verification on a background thread
888 // because of the performance benefits of doing so.
889 return SSLServerCertVerificationJob::Dispatch(
890 addr, socketControl, std::move(peerCertChain), hostName,
891 socketControl->GetPort(), socketControl->GetOriginAttributes(),
892 stapledOCSPResponse, sctsFromTLSExtension, dcInfo, providerFlags, Now(),
893 certVerifierFlags, resultTask);
896 // Extracts whatever information we need out of fd (using SSL_*) and passes it
897 // to AuthCertificateHookInternal. AuthCertificateHookInternal will call
898 // SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob
899 // should never do anything with fd except logging.
900 SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig,
901 PRBool isServer) {
902 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
903 ("[%p] starting AuthCertificateHook\n", fd));
905 // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
906 // doing verification without checking signatures.
907 MOZ_ASSERT(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
909 // PSM never causes libssl to call this function with PR_TRUE for isServer,
910 // and many things in PSM assume that we are a client.
911 MOZ_ASSERT(!isServer, "AuthCertificateHook: isServer unexpectedly true");
913 NSSSocketControl* socketInfo = static_cast<NSSSocketControl*>(arg);
915 UniqueCERTCertificate serverCert(SSL_PeerCertificate(fd));
917 if (!checkSig || isServer || !socketInfo || !serverCert) {
918 PR_SetError(PR_INVALID_STATE_ERROR, 0);
919 return SECFailure;
921 socketInfo->SetFullHandshake();
923 if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess) {
924 return SECFailure;
927 UniqueSECItemArray peerCertChain;
928 SECStatus rv =
929 SSL_PeerCertificateChainDER(fd, TempPtrToSetter(&peerCertChain));
930 if (rv != SECSuccess) {
931 PR_SetError(PR_INVALID_STATE_ERROR, 0);
932 return SECFailure;
934 MOZ_ASSERT(peerCertChain,
935 "AuthCertificateHook: peerCertChain unexpectedly null");
937 nsTArray<nsTArray<uint8_t>> peerCertsBytes =
938 CreateCertBytesArray(peerCertChain);
940 // SSL_PeerStapledOCSPResponses will never return a non-empty response if
941 // OCSP stapling wasn't enabled because libssl wouldn't have let the server
942 // return a stapled OCSP response.
943 // We don't own these pointers.
944 const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
945 Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
946 // we currently only support single stapled responses
947 if (csa && csa->len == 1) {
948 stapledOCSPResponse.emplace();
949 stapledOCSPResponse->SetCapacity(csa->items[0].len);
950 stapledOCSPResponse->AppendElements(csa->items[0].data, csa->items[0].len);
953 Maybe<nsTArray<uint8_t>> sctsFromTLSExtension;
954 const SECItem* sctsFromTLSExtensionSECItem = SSL_PeerSignedCertTimestamps(fd);
955 if (sctsFromTLSExtensionSECItem) {
956 sctsFromTLSExtension.emplace();
957 sctsFromTLSExtension->SetCapacity(sctsFromTLSExtensionSECItem->len);
958 sctsFromTLSExtension->AppendElements(sctsFromTLSExtensionSECItem->data,
959 sctsFromTLSExtensionSECItem->len);
962 uint32_t providerFlags = 0;
963 socketInfo->GetProviderFlags(&providerFlags);
965 uint32_t certVerifierFlags = 0;
966 if (!StaticPrefs::security_ssl_enable_ocsp_stapling() ||
967 !StaticPrefs::security_ssl_enable_ocsp_must_staple()) {
968 certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
971 // Get DC information
972 Maybe<DelegatedCredentialInfo> dcInfo;
973 SSLPreliminaryChannelInfo channelPreInfo;
974 rv = SSL_GetPreliminaryChannelInfo(fd, &channelPreInfo,
975 sizeof(channelPreInfo));
976 if (rv != SECSuccess) {
977 PR_SetError(PR_INVALID_STATE_ERROR, 0);
978 return SECFailure;
980 if (channelPreInfo.peerDelegCred) {
981 dcInfo.emplace(DelegatedCredentialInfo(channelPreInfo.signatureScheme,
982 channelPreInfo.authKeyBits));
985 // If we configured an ECHConfig and NSS returned the public name
986 // for verification, ECH was rejected. Proceed, verifying to the
987 // public name. The result determines how NSS will fail (i.e. with
988 // any provided retry_configs if successful). See draft-ietf-tls-esni-08.
989 nsCString echConfig;
990 nsresult nsrv = socketInfo->GetEchConfig(echConfig);
991 bool verifyToEchPublicName =
992 NS_SUCCEEDED(nsrv) && echConfig.Length() && channelPreInfo.echPublicName;
994 const nsCString echPublicName(channelPreInfo.echPublicName);
995 const nsACString& hostname =
996 verifyToEchPublicName ? echPublicName : socketInfo->GetHostName();
997 socketInfo->SetCertVerificationWaiting();
998 rv = AuthCertificateHookInternal(socketInfo, static_cast<const void*>(fd),
999 hostname, std::move(peerCertsBytes),
1000 stapledOCSPResponse, sctsFromTLSExtension,
1001 dcInfo, providerFlags, certVerifierFlags);
1002 return rv;
1005 // Takes information needed for cert verification, does some consistency
1006 // checks and calls SSLServerCertVerificationJob::Dispatch.
1007 // This function is used for Quic.
1008 SECStatus AuthCertificateHookWithInfo(
1009 CommonSocketControl* socketControl, const nsACString& aHostName,
1010 const void* aPtrForLogging, nsTArray<nsTArray<uint8_t>>&& peerCertChain,
1011 Maybe<nsTArray<nsTArray<uint8_t>>>& stapledOCSPResponses,
1012 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, uint32_t providerFlags) {
1013 if (peerCertChain.IsEmpty()) {
1014 PR_SetError(PR_INVALID_STATE_ERROR, 0);
1015 return SECFailure;
1018 // we currently only support single stapled responses
1019 Maybe<nsTArray<uint8_t>> stapledOCSPResponse;
1020 if (stapledOCSPResponses && (stapledOCSPResponses->Length() == 1)) {
1021 stapledOCSPResponse.emplace(stapledOCSPResponses->ElementAt(0).Clone());
1024 uint32_t certVerifierFlags = 0;
1025 if (!StaticPrefs::security_ssl_enable_ocsp_stapling() ||
1026 !StaticPrefs::security_ssl_enable_ocsp_must_staple()) {
1027 certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
1030 // Need to update Quic stack to reflect the PreliminaryInfo fields
1031 // for Delegated Credentials.
1032 Maybe<DelegatedCredentialInfo> dcInfo;
1034 return AuthCertificateHookInternal(socketControl, aPtrForLogging, aHostName,
1035 std::move(peerCertChain),
1036 stapledOCSPResponse, sctsFromTLSExtension,
1037 dcInfo, providerFlags, certVerifierFlags);
1040 NS_IMPL_ISUPPORTS_INHERITED0(SSLServerCertVerificationResult, Runnable)
1042 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
1043 CommonSocketControl* socketControl)
1044 : Runnable("psm::SSLServerCertVerificationResult"),
1045 mSocketControl(socketControl),
1046 mCertificateTransparencyStatus(0),
1047 mEVStatus(EVStatus::NotEV),
1048 mSucceeded(false),
1049 mFinalError(0),
1050 mOverridableErrorCategory(
1051 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET),
1052 mProviderFlags(0) {}
1054 nsresult SSLServerCertVerificationResult::Dispatch(
1055 nsTArray<nsTArray<uint8_t>>&& aBuiltChain,
1056 nsTArray<nsTArray<uint8_t>>&& aPeerCertChain,
1057 uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus,
1058 bool aSucceeded, PRErrorCode aFinalError,
1059 nsITransportSecurityInfo::OverridableErrorCategory
1060 aOverridableErrorCategory,
1061 bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags,
1062 bool aMadeOCSPRequests) {
1063 mBuiltChain = std::move(aBuiltChain);
1064 mPeerCertChain = std::move(aPeerCertChain);
1065 mCertificateTransparencyStatus = aCertificateTransparencyStatus;
1066 mEVStatus = aEVStatus;
1067 mSucceeded = aSucceeded;
1068 mFinalError = aFinalError;
1069 mOverridableErrorCategory = aOverridableErrorCategory;
1070 mIsBuiltCertChainRootBuiltInRoot = aIsBuiltCertChainRootBuiltInRoot;
1071 mProviderFlags = aProviderFlags;
1072 mMadeOCSPRequests = aMadeOCSPRequests;
1074 if (mSucceeded &&
1075 (mBuiltChain.IsEmpty() || mFinalError != 0 ||
1076 mOverridableErrorCategory !=
1077 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET)) {
1078 MOZ_ASSERT_UNREACHABLE(
1079 "if certificate verification succeeded without overridden errors, the "
1080 "built chain shouldn't be empty and any error bits should be unset");
1081 mSucceeded = false;
1082 mFinalError = SEC_ERROR_LIBRARY_FAILURE;
1084 // Note that mSucceeded can be false while mFinalError is 0, in which case
1085 // the connection will proceed.
1086 if (!mSucceeded && mPeerCertChain.IsEmpty()) {
1087 MOZ_ASSERT_UNREACHABLE(
1088 "if certificate verification failed, the peer chain shouldn't be "
1089 "empty");
1090 mFinalError = SEC_ERROR_LIBRARY_FAILURE;
1093 nsresult rv;
1094 nsCOMPtr<nsIEventTarget> stsTarget =
1095 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
1096 MOZ_ASSERT(stsTarget, "Failed to get socket transport service event target");
1097 if (!stsTarget) {
1098 // This has to be released on STS; just leak it
1099 Unused << mSocketControl.forget();
1100 return NS_ERROR_FAILURE;
1102 rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
1103 MOZ_ASSERT(NS_SUCCEEDED(rv),
1104 "Failed to dispatch SSLServerCertVerificationResult");
1105 return rv;
1108 NS_IMETHODIMP
1109 SSLServerCertVerificationResult::Run() {
1110 #ifdef DEBUG
1111 bool onSTSThread = false;
1112 nsresult nrv;
1113 nsCOMPtr<nsIEventTarget> sts =
1114 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
1115 if (NS_SUCCEEDED(nrv)) {
1116 nrv = sts->IsOnCurrentThread(&onSTSThread);
1119 MOZ_ASSERT(onSTSThread);
1120 #endif
1122 mSocketControl->SetMadeOCSPRequests(mMadeOCSPRequests);
1123 mSocketControl->SetIsBuiltCertChainRootBuiltInRoot(
1124 mIsBuiltCertChainRootBuiltInRoot);
1125 mSocketControl->SetCertificateTransparencyStatus(
1126 mCertificateTransparencyStatus);
1128 if (mSucceeded) {
1129 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1130 ("SSLServerCertVerificationResult::Run setting NEW cert"));
1131 nsTArray<uint8_t> certBytes(mBuiltChain.ElementAt(0).Clone());
1132 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
1133 mSocketControl->SetServerCert(cert, mEVStatus);
1134 mSocketControl->SetSucceededCertChain(std::move(mBuiltChain));
1135 } else {
1136 nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone());
1137 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes)));
1138 // Certificate validation failed; store the peer certificate chain on
1139 // mSocketControl so it can be used for error reporting.
1140 mSocketControl->SetFailedCertChain(std::move(mPeerCertChain));
1141 if (mOverridableErrorCategory !=
1142 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET) {
1143 mSocketControl->SetStatusErrorBits(cert, mOverridableErrorCategory);
1147 mSocketControl->SetCertVerificationResult(mFinalError);
1148 return NS_OK;
1151 } // namespace psm
1152 } // namespace mozilla