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
40 // Timeline of events (for connections managed by the socket transport service):
42 // * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
44 // * SSLServerCertVerificationJob::Dispatch queues a job
45 // (instance of SSLServerCertVerificationJob) to its background thread
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
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"
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"
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"
141 extern mozilla::LazyLogModule gPIPNSSLog
;
143 using namespace mozilla::pkix
;
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
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
) {
193 case SEC_ERROR_UNKNOWN_ISSUER
:
195 case SEC_ERROR_CA_CERT_INVALID
:
197 case SEC_ERROR_UNTRUSTED_ISSUER
:
199 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE
:
201 case SEC_ERROR_UNTRUSTED_CERT
:
203 case SEC_ERROR_INADEQUATE_KEY_USAGE
:
205 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
:
207 case SSL_ERROR_BAD_CERT_DOMAIN
:
209 case SEC_ERROR_EXPIRED_CERTIFICATE
:
211 case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY
:
213 case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA
:
215 case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE
:
217 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE
:
219 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE
:
221 case SEC_ERROR_INVALID_TIME
:
223 case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME
:
225 case mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED
:
227 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT
:
229 case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED
:
232 MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY
:
236 "Unknown certificate error code. Does MapOverridableErrorToProbeValue "
237 "handle everything in CategorizeCertificateError?");
241 static uint32_t MapCertErrorToProbeValue(PRErrorCode errorCode
) {
244 // see security/pkix/include/pkix/Result.h
245 #define MOZILLA_PKIX_MAP(name, value, nss_name) \
247 probeValue = value; \
249 MOZILLA_PKIX_MAP_LIST
250 #undef MOZILLA_PKIX_MAP
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
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
;
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
:
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
:
292 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST
);
294 case SSL_ERROR_BAD_CERT_DOMAIN
:
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
:
302 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME
);
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;
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
));
337 gPIPNSSLog
, LogLevel::Debug
,
338 ("[0x%" PRIx64
"] Couldn't get nsISiteSecurityService to check HSTS",
340 return NS_ERROR_FAILURE
;
343 nsCOMPtr
<nsIURI
> uri
;
344 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), "https://"_ns
+ aHostname
);
346 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
347 ("[0x%" PRIx64
"] Creating new URI failed", aPtrForLog
));
352 sss
->IsSecureURI(uri
, aOriginAttributes
, &strictTransportSecurityEnabled
);
354 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
355 ("[0x%" PRIx64
"] checking for HSTS failed", aPtrForLog
));
359 nsCOMPtr
<nsIPublicKeyPinningService
> pkps
=
360 do_GetService(NS_PKPSERVICE_CONTRACTID
, &rv
);
362 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
364 "] Couldn't get nsIPublicKeyPinningService to check pinning",
366 return NS_ERROR_FAILURE
;
368 rv
= pkps
->HostHasPins(uri
, &isStaticallyPinned
);
370 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
371 ("[0x%" PRIx64
"] checking for static pin failed", aPtrForLog
));
375 aOverrideAllowed
= !strictTransportSecurityEnabled
&& !isStaticallyPinned
;
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
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);
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
)) {
414 // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
416 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
417 ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
421 // Check to see if the cert has actually changed
422 nsCOMPtr
<nsIX509Cert
> cert(socketControl
->GetServerCert());
424 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
427 nsTArray
<uint8_t> certDER
;
428 if (NS_FAILED(cert
->GetRawDER(certDER
))) {
429 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
432 if (certDER
.Length() == serverCert
->derCert
.len
&&
433 memcmp(certDER
.Elements(), serverCert
->derCert
.data
, certDER
.Length()) ==
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);
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;
452 case ct::CTLogState::Retired
:
453 verificationStatus
= 5;
456 Telemetry::Accumulate(Telemetry::SSL_SCTS_VERIFICATION_STATUS
,
460 void GatherCertificateTransparencyTelemetry(
461 const nsTArray
<uint8_t>& rootCert
,
462 const CertificateTransparencyInfo
& info
) {
464 // No telemetry is gathered when CT is disabled.
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.
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
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
,
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
563 if (issuerSources
.contains(IssuerSource::ThirdPartyCertificates
)) {
564 mozilla::glean::verification_used_cert_from::third_party_certificates
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
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()) {
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
);
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
,
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
,
657 return aCertVerificationError
;
660 if (!overrideAllowed
) {
661 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
662 ("[0x%" PRIx64
"] HSTS or pinned host - no overrides allowed",
664 return aCertVerificationError
;
667 nsCOMPtr
<nsICertOverrideService
> overrideService
=
668 do_GetService(NS_CERTOVERRIDE_CONTRACTID
);
669 if (!overrideService
) {
670 return aCertVerificationError
;
673 bool isTemporaryOverride
;
674 rv
= overrideService
->HasMatchingOverride(aHostName
, aPort
, aOriginAttributes
,
675 aCert
, &isTemporaryOverride
,
678 return aCertVerificationError
;
680 Unused
<< isTemporaryOverride
;
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
));
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
));
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);
723 if (!gCertVerificationThreadPool
) {
724 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
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);
747 PR_SetError(PR_WOULD_BLOCK_ERROR
, 0);
748 return SECWouldBlock
;
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());
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();
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
,
781 TimeDuration elapsed
= TimeStamp::Now() - jobStartTime
;
782 if (result
== Success
) {
783 mozilla::glean::cert_verification_time::success
.AccumulateRawDuration(
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
),
792 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET
,
793 isCertChainRootBuiltInRoot
, mProviderFlags
, madeOCSPRequests
);
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();
802 mozilla::glean::cert_verification_time::failure
.AccumulateRawDuration(
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
824 mProviderFlags
, madeOCSPRequests
);
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();
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);
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);
866 MOZ_ASSERT(onSTSThread
);
869 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
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
,
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
,
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);
921 socketInfo
->SetFullHandshake();
923 if (BlockServerCertChangeForSpdy(socketInfo
, serverCert
) != SECSuccess
) {
927 UniqueSECItemArray peerCertChain
;
929 SSL_PeerCertificateChainDER(fd
, TempPtrToSetter(&peerCertChain
));
930 if (rv
!= SECSuccess
) {
931 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
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);
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.
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
);
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);
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
),
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
;
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");
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 "
1090 mFinalError
= SEC_ERROR_LIBRARY_FAILURE
;
1094 nsCOMPtr
<nsIEventTarget
> stsTarget
=
1095 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
, &rv
);
1096 MOZ_ASSERT(stsTarget
, "Failed to get socket transport service event target");
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");
1109 SSLServerCertVerificationResult::Run() {
1111 bool onSTSThread
= false;
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
);
1122 mSocketControl
->SetMadeOCSPRequests(mMadeOCSPRequests
);
1123 mSocketControl
->SetIsBuiltCertChainRootBuiltInRoot(
1124 mIsBuiltCertChainRootBuiltInRoot
);
1125 mSocketControl
->SetCertificateTransparencyStatus(
1126 mCertificateTransparencyStatus
);
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
));
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
);
1152 } // namespace mozilla