Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / security / manager / ssl / CommonSocketControl.cpp
blob8a8e985aaabfe99a494b7b7605225c3fb4657086
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 #include "CommonSocketControl.h"
9 #include "PublicKeyPinningService.h"
10 #include "SharedCertVerifier.h"
11 #include "mozilla/ErrorResult.h"
12 #include "mozilla/StaticPrefs_network.h"
13 #include "mozilla/dom/Promise.h"
14 #include "nsICertOverrideService.h"
15 #include "nsISocketProvider.h"
16 #include "nsITlsHandshakeListener.h"
17 #include "nsNSSCertificate.h"
18 #include "nsNSSComponent.h"
19 #include "nsNSSHelper.h"
20 #include "secerr.h"
21 #include "ssl.h"
22 #include "sslt.h"
24 using namespace mozilla;
26 extern LazyLogModule gPIPNSSLog;
28 NS_IMPL_ISUPPORTS(CommonSocketControl, nsITLSSocketControl)
30 CommonSocketControl::CommonSocketControl(const nsCString& aHostName,
31 int32_t aPort, uint32_t aProviderFlags)
32 : mHostName(aHostName),
33 mPort(aPort),
34 mCanceled(false),
35 mHandshakeCompleted(false),
36 mJoined(false),
37 mSentClientCert(false),
38 mFailedVerification(false),
39 mSSLVersionUsed(nsITLSSocketControl::SSL_VERSION_UNKNOWN),
40 mProviderFlags(aProviderFlags),
41 mSecurityState(0),
42 mErrorCode(0),
43 mServerCert(nullptr),
44 mCertificateTransparencyStatus(0),
45 mMadeOCSPRequests(false),
46 mUsedPrivateDNS(false),
47 mNPNCompleted(false),
48 mResumed(false),
49 mIsBuiltCertChainRootBuiltInRoot(false) {
50 #if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
51 mOwningThread = PR_GetCurrentThread();
52 #endif
55 void CommonSocketControl::SetStatusErrorBits(
56 const nsCOMPtr<nsIX509Cert>& cert,
57 nsITransportSecurityInfo::OverridableErrorCategory
58 overridableErrorCategory) {
59 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
60 SetServerCert(cert, mozilla::psm::EVStatus::NotEV);
61 mOverridableErrorCategory = Some(overridableErrorCategory);
64 static void CreateCertChain(nsTArray<RefPtr<nsIX509Cert>>& aOutput,
65 nsTArray<nsTArray<uint8_t>>&& aCertList) {
66 nsTArray<nsTArray<uint8_t>> certList = std::move(aCertList);
67 aOutput.Clear();
68 for (auto& certBytes : certList) {
69 RefPtr<nsIX509Cert> cert = new nsNSSCertificate(std::move(certBytes));
70 aOutput.AppendElement(cert);
74 void CommonSocketControl::SetServerCert(
75 const nsCOMPtr<nsIX509Cert>& aServerCert,
76 mozilla::psm::EVStatus aEVStatus) {
77 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
78 mServerCert = aServerCert;
79 mIsEV = Some(aEVStatus == mozilla::psm::EVStatus::EV);
82 void CommonSocketControl::SetSucceededCertChain(
83 nsTArray<nsTArray<uint8_t>>&& aCertList) {
84 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
85 return CreateCertChain(mSucceededCertChain, std::move(aCertList));
88 void CommonSocketControl::SetFailedCertChain(
89 nsTArray<nsTArray<uint8_t>>&& aCertList) {
90 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
91 return CreateCertChain(mFailedCertChain, std::move(aCertList));
94 void CommonSocketControl::SetCanceled(PRErrorCode errorCode) {
95 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
96 MOZ_ASSERT(errorCode != 0);
97 if (errorCode == 0) {
98 errorCode = SEC_ERROR_LIBRARY_FAILURE;
101 mErrorCode = errorCode;
102 mCanceled = true;
105 // NB: GetErrorCode may be called before an error code is set (if ever). In that
106 // case, this returns 0, which is treated as a successful value.
107 int32_t CommonSocketControl::GetErrorCode() {
108 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
109 // We're in an inconsistent state if we think we've been canceled but no error
110 // code was set or we haven't been canceled but an error code was set.
111 MOZ_ASSERT(
112 !((mCanceled && mErrorCode == 0) || (!mCanceled && mErrorCode != 0)));
113 if ((mCanceled && mErrorCode == 0) || (!mCanceled && mErrorCode != 0)) {
114 mCanceled = true;
115 mErrorCode = SEC_ERROR_LIBRARY_FAILURE;
118 return mErrorCode;
121 NS_IMETHODIMP
122 CommonSocketControl::ProxyStartSSL(void) { return NS_ERROR_NOT_IMPLEMENTED; }
124 NS_IMETHODIMP
125 CommonSocketControl::StartTLS(void) { return NS_ERROR_NOT_IMPLEMENTED; }
127 NS_IMETHODIMP
128 CommonSocketControl::AsyncStartTLS(JSContext* aCx,
129 mozilla::dom::Promise** aPromise) {
130 return NS_ERROR_NOT_IMPLEMENTED;
133 NS_IMETHODIMP
134 CommonSocketControl::SetNPNList(nsTArray<nsCString>& aNPNList) {
135 return NS_ERROR_NOT_IMPLEMENTED;
138 NS_IMETHODIMP
139 CommonSocketControl::GetAlpnEarlySelection(nsACString& _retval) {
140 return NS_ERROR_NOT_IMPLEMENTED;
143 NS_IMETHODIMP
144 CommonSocketControl::GetEarlyDataAccepted(bool* aEarlyDataAccepted) {
145 return NS_ERROR_NOT_IMPLEMENTED;
148 NS_IMETHODIMP
149 CommonSocketControl::DriveHandshake(void) { return NS_ERROR_NOT_IMPLEMENTED; }
151 NS_IMETHODIMP
152 CommonSocketControl::JoinConnection(const nsACString& npnProtocol,
153 const nsACString& hostname, int32_t port,
154 bool* _retval) {
155 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
156 nsresult rv = TestJoinConnection(npnProtocol, hostname, port, _retval);
157 if (NS_SUCCEEDED(rv) && *_retval) {
158 // All tests pass - this is joinable
159 mJoined = true;
161 return rv;
164 NS_IMETHODIMP
165 CommonSocketControl::TestJoinConnection(const nsACString& npnProtocol,
166 const nsACString& hostname,
167 int32_t port, bool* _retval) {
168 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
169 *_retval = false;
171 // Different ports may not be joined together
172 if (port != GetPort()) return NS_OK;
174 // Make sure NPN has been completed and matches requested npnProtocol
175 if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol)) {
176 return NS_OK;
179 IsAcceptableForHost(hostname, _retval); // sets _retval
180 return NS_OK;
183 NS_IMETHODIMP
184 CommonSocketControl::IsAcceptableForHost(const nsACString& hostname,
185 bool* _retval) {
186 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
187 NS_ENSURE_ARG(_retval);
189 *_retval = false;
191 // If this is the same hostname then the certicate status does not
192 // need to be considered. They are joinable.
193 if (hostname.Equals(GetHostName())) {
194 *_retval = true;
195 return NS_OK;
198 // Before checking the server certificate we need to make sure the
199 // handshake has completed.
200 if (!mHandshakeCompleted || !HasServerCert()) {
201 return NS_OK;
204 // Security checks can only be skipped when running xpcshell tests.
205 if (PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
206 nsCOMPtr<nsICertOverrideService> overrideService =
207 do_GetService(NS_CERTOVERRIDE_CONTRACTID);
208 if (overrideService) {
209 bool securityCheckDisabled = false;
210 overrideService->GetSecurityCheckDisabled(&securityCheckDisabled);
211 if (securityCheckDisabled) {
212 *_retval = true;
213 return NS_OK;
218 // If the cert has error bits (e.g. it is untrusted) then do not join.
219 if (mOverridableErrorCategory.isSome()) {
220 return NS_OK;
223 // If the connection is using client certificates then do not join
224 // because the user decides on whether to send client certs to hosts on a
225 // per-domain basis.
226 if (mSentClientCert) return NS_OK;
228 // Ensure that the server certificate covers the hostname that would
229 // like to join this connection
231 nsCOMPtr<nsIX509Cert> cert(GetServerCert());
232 if (!cert) {
233 return NS_OK;
235 nsTArray<uint8_t> certDER;
236 if (NS_FAILED(cert->GetRawDER(certDER))) {
237 return NS_OK;
240 // An empty mSucceededCertChain means the server certificate verification
241 // failed before, so don't join in this case.
242 if (mSucceededCertChain.IsEmpty()) {
243 return NS_OK;
246 // See where CheckCertHostname() is called in
247 // CertVerifier::VerifySSLServerCert. We are doing the same hostname-specific
248 // checks here. If any hostname-specific checks are added to
249 // CertVerifier::VerifySSLServerCert we need to add them here too.
250 pkix::Input serverCertInput;
251 mozilla::pkix::Result rv =
252 serverCertInput.Init(certDER.Elements(), certDER.Length());
253 if (rv != pkix::Success) {
254 return NS_OK;
257 pkix::Input hostnameInput;
258 rv = hostnameInput.Init(
259 BitwiseCast<const uint8_t*, const char*>(hostname.BeginReading()),
260 hostname.Length());
261 if (rv != pkix::Success) {
262 return NS_OK;
265 rv = CheckCertHostname(serverCertInput, hostnameInput);
266 if (rv != pkix::Success) {
267 return NS_OK;
270 nsTArray<nsTArray<uint8_t>> rawDerCertList;
271 nsTArray<Span<const uint8_t>> derCertSpanList;
272 for (const auto& cert : mSucceededCertChain) {
273 rawDerCertList.EmplaceBack();
274 nsresult nsrv = cert->GetRawDER(rawDerCertList.LastElement());
275 if (NS_FAILED(nsrv)) {
276 return nsrv;
278 derCertSpanList.EmplaceBack(rawDerCertList.LastElement());
280 bool chainHasValidPins;
281 nsresult nsrv = mozilla::psm::PublicKeyPinningService::ChainHasValidPins(
282 derCertSpanList, PromiseFlatCString(hostname).BeginReading(), pkix::Now(),
283 mIsBuiltCertChainRootBuiltInRoot, chainHasValidPins, nullptr);
284 if (NS_FAILED(nsrv)) {
285 return NS_OK;
288 if (!chainHasValidPins) {
289 return NS_OK;
292 // All tests pass
293 *_retval = true;
294 return NS_OK;
297 void CommonSocketControl::RebuildCertificateInfoFromSSLTokenCache() {
298 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
299 if (!mSessionCacheInfo) {
300 MOZ_LOG(
301 gPIPNSSLog, LogLevel::Debug,
302 ("CommonSocketControl::RebuildCertificateInfoFromSSLTokenCache cannot "
303 "find cached info."));
304 return;
307 mozilla::net::SessionCacheInfo& info = *mSessionCacheInfo;
308 nsCOMPtr<nsIX509Cert> cert(
309 new nsNSSCertificate(std::move(info.mServerCertBytes)));
310 if (info.mOverridableErrorCategory ==
311 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET) {
312 SetServerCert(cert, info.mEVStatus);
313 } else {
314 SetStatusErrorBits(cert, info.mOverridableErrorCategory);
316 SetCertificateTransparencyStatus(info.mCertificateTransparencyStatus);
317 if (info.mSucceededCertChainBytes) {
318 SetSucceededCertChain(std::move(*info.mSucceededCertChainBytes));
321 if (info.mIsBuiltCertChainRootBuiltInRoot) {
322 SetIsBuiltCertChainRootBuiltInRoot(*info.mIsBuiltCertChainRootBuiltInRoot);
325 if (info.mFailedCertChainBytes) {
326 SetFailedCertChain(std::move(*info.mFailedCertChainBytes));
330 NS_IMETHODIMP
331 CommonSocketControl::GetKEAUsed(int16_t* aKEAUsed) {
332 return NS_ERROR_NOT_IMPLEMENTED;
335 NS_IMETHODIMP
336 CommonSocketControl::GetKEAKeyBits(uint32_t* aKEAKeyBits) {
337 return NS_ERROR_NOT_IMPLEMENTED;
340 NS_IMETHODIMP
341 CommonSocketControl::GetProviderFlags(uint32_t* aProviderFlags) {
342 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
343 *aProviderFlags = mProviderFlags;
344 return NS_OK;
347 NS_IMETHODIMP
348 CommonSocketControl::GetSSLVersionUsed(int16_t* aSSLVersionUsed) {
349 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
350 *aSSLVersionUsed = mSSLVersionUsed;
351 return NS_OK;
354 NS_IMETHODIMP
355 CommonSocketControl::GetSSLVersionOffered(int16_t* aSSLVersionOffered) {
356 return NS_ERROR_NOT_IMPLEMENTED;
359 NS_IMETHODIMP
360 CommonSocketControl::GetMACAlgorithmUsed(int16_t* aMACAlgorithmUsed) {
361 return NS_ERROR_NOT_IMPLEMENTED;
364 bool CommonSocketControl::GetDenyClientCert() { return true; }
366 void CommonSocketControl::SetDenyClientCert(bool aDenyClientCert) {}
368 NS_IMETHODIMP
369 CommonSocketControl::GetClientCertSent(bool* arg) {
370 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
371 *arg = mSentClientCert;
372 return NS_OK;
375 NS_IMETHODIMP
376 CommonSocketControl::GetFailedVerification(bool* arg) {
377 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
378 *arg = mFailedVerification;
379 return NS_OK;
382 NS_IMETHODIMP
383 CommonSocketControl::GetEsniTxt(nsACString& aEsniTxt) {
384 return NS_ERROR_NOT_IMPLEMENTED;
387 NS_IMETHODIMP
388 CommonSocketControl::SetEsniTxt(const nsACString& aEsniTxt) {
389 return NS_ERROR_NOT_IMPLEMENTED;
392 NS_IMETHODIMP
393 CommonSocketControl::GetEchConfig(nsACString& aEchConfig) {
394 return NS_ERROR_NOT_IMPLEMENTED;
397 NS_IMETHODIMP
398 CommonSocketControl::SetEchConfig(const nsACString& aEchConfig) {
399 return NS_ERROR_NOT_IMPLEMENTED;
402 NS_IMETHODIMP
403 CommonSocketControl::GetRetryEchConfig(nsACString& aEchConfig) {
404 return NS_ERROR_NOT_IMPLEMENTED;
407 NS_IMETHODIMP
408 CommonSocketControl::SetHandshakeCallbackListener(
409 nsITlsHandshakeCallbackListener* callback) {
410 return NS_ERROR_NOT_IMPLEMENTED;
413 NS_IMETHODIMP
414 CommonSocketControl::DisableEarlyData(void) { return NS_ERROR_NOT_IMPLEMENTED; }
416 NS_IMETHODIMP
417 CommonSocketControl::GetPeerId(nsACString& aResult) {
418 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
419 if (!mPeerId.IsEmpty()) {
420 aResult.Assign(mPeerId);
421 return NS_OK;
424 if (mProviderFlags &
425 nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
426 mPeerId.AppendLiteral("anon:");
428 if (mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE) {
429 mPeerId.AppendLiteral("private:");
431 if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) {
432 mPeerId.AppendLiteral("beConservative:");
435 mPeerId.Append(mHostName);
436 mPeerId.Append(':');
437 mPeerId.AppendInt(GetPort());
438 nsAutoCString suffix;
439 mOriginAttributes.CreateSuffix(suffix);
440 mPeerId.Append(suffix);
442 aResult.Assign(mPeerId);
443 return NS_OK;
446 NS_IMETHODIMP
447 CommonSocketControl::GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) {
448 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
449 // Make sure peerId is set.
450 nsAutoCString unused;
451 nsresult rv = GetPeerId(unused);
452 if (NS_FAILED(rv)) {
453 return rv;
455 nsCOMPtr<nsITransportSecurityInfo> securityInfo(
456 new psm::TransportSecurityInfo(
457 mSecurityState, mErrorCode, mFailedCertChain.Clone(), mServerCert,
458 mSucceededCertChain.Clone(), mCipherSuite, mKeaGroupName,
459 mSignatureSchemeName, mProtocolVersion,
460 mCertificateTransparencyStatus, mIsAcceptedEch,
461 mIsDelegatedCredential, mOverridableErrorCategory, mMadeOCSPRequests,
462 mUsedPrivateDNS, mIsEV, mNPNCompleted, mNegotiatedNPN, mResumed,
463 mIsBuiltCertChainRootBuiltInRoot, mPeerId));
464 securityInfo.forget(aSecurityInfo);
465 return NS_OK;
468 NS_IMETHODIMP
469 CommonSocketControl::AsyncGetSecurityInfo(JSContext* aCx,
470 mozilla::dom::Promise** aPromise) {
471 MOZ_RELEASE_ASSERT(NS_IsMainThread());
472 NS_ENSURE_ARG_POINTER(aCx);
473 NS_ENSURE_ARG_POINTER(aPromise);
475 nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
476 if (!globalObject) {
477 return NS_ERROR_UNEXPECTED;
480 ErrorResult result;
481 RefPtr<mozilla::dom::Promise> promise =
482 mozilla::dom::Promise::Create(globalObject, result);
483 if (result.Failed()) {
484 return result.StealNSResult();
486 nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
487 "CommonSocketControl::AsyncGetSecurityInfo",
488 [promise, self = RefPtr{this}]() mutable {
489 nsCOMPtr<nsITransportSecurityInfo> securityInfo;
490 nsresult rv = self->GetSecurityInfo(getter_AddRefs(securityInfo));
491 nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
492 "CommonSocketControl::AsyncGetSecurityInfoResolve",
493 [rv, promise = std::move(promise),
494 securityInfo = std::move(securityInfo)]() {
495 if (NS_FAILED(rv)) {
496 promise->MaybeReject(rv);
497 } else {
498 promise->MaybeResolve(securityInfo);
500 }));
501 NS_DispatchToMainThread(runnable.forget());
502 }));
503 nsCOMPtr<nsIEventTarget> target(
504 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID));
505 if (!target) {
506 return NS_ERROR_FAILURE;
508 nsresult rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
509 if (NS_FAILED(rv)) {
510 return rv;
513 promise.forget(aPromise);
514 return NS_OK;
517 NS_IMETHODIMP CommonSocketControl::Claim() { return NS_ERROR_NOT_IMPLEMENTED; }
519 NS_IMETHODIMP CommonSocketControl::SetBrowserId(uint64_t) {
520 return NS_ERROR_NOT_IMPLEMENTED;
523 NS_IMETHODIMP CommonSocketControl::GetBrowserId(uint64_t*) {
524 return NS_ERROR_NOT_IMPLEMENTED;