diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:29:21 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 02:29:21 +0000 |
commit | f34df9db04b7adaff418b61c35fb1346c1c2fccd (patch) | |
tree | ca9b0e61a1c03f0246b0371423bbbe570193e2f1 /netwerk | |
parent | Adding upstream version 115.8.0esr. (diff) | |
download | firefox-esr-f34df9db04b7adaff418b61c35fb1346c1c2fccd.tar.xz firefox-esr-f34df9db04b7adaff418b61c35fb1346c1c2fccd.zip |
Adding upstream version 115.9.0esr.upstream/115.9.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'netwerk')
-rw-r--r-- | netwerk/dns/effective_tld_names.dat | 111 | ||||
-rw-r--r-- | netwerk/protocol/http/Http2Compression.cpp | 33 | ||||
-rw-r--r-- | netwerk/protocol/http/Http2Compression.h | 9 | ||||
-rw-r--r-- | netwerk/protocol/http/HttpChannelChild.cpp | 49 | ||||
-rw-r--r-- | netwerk/protocol/http/HttpChannelChild.h | 10 | ||||
-rw-r--r-- | netwerk/protocol/http/TlsHandshaker.cpp | 18 | ||||
-rw-r--r-- | netwerk/protocol/http/nsITlsHandshakeListener.idl | 2 | ||||
-rw-r--r-- | netwerk/test/unit/test_client_auth_with_proxy.js | 185 | ||||
-rw-r--r-- | netwerk/test/unit/xpcshell.ini | 2 |
9 files changed, 367 insertions, 52 deletions
diff --git a/netwerk/dns/effective_tld_names.dat b/netwerk/dns/effective_tld_names.dat index be79353f30..c2b813fa68 100644 --- a/netwerk/dns/effective_tld_names.dat +++ b/netwerk/dns/effective_tld_names.dat @@ -6710,7 +6710,7 @@ org.zw // newGTLDs -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2024-01-24T15:14:29Z +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2024-03-06T15:14:58Z // This list is auto-generated, don't edit it manually. // aaa : American Automobile Association, Inc. // https://www.iana.org/domains/root/db/aaa.html @@ -7540,10 +7540,6 @@ college // https://www.iana.org/domains/root/db/cologne.html cologne -// comcast : Comcast IP Holdings I, LLC -// https://www.iana.org/domains/root/db/comcast.html -comcast - // commbank : COMMONWEALTH BANK OF AUSTRALIA // https://www.iana.org/domains/root/db/commbank.html commbank @@ -8360,10 +8356,6 @@ grocery // https://www.iana.org/domains/root/db/group.html group -// guardian : The Guardian Life Insurance Company of America -// https://www.iana.org/domains/root/db/guardian.html -guardian - // gucci : Guccio Gucci S.p.a. // https://www.iana.org/domains/root/db/gucci.html gucci @@ -10756,10 +10748,6 @@ xbox // https://www.iana.org/domains/root/db/xerox.html xerox -// xfinity : Comcast IP Holdings I, LLC -// https://www.iana.org/domains/root/db/xfinity.html -xfinity - // xihuan : Beijing Qihu Keji Co., Ltd. // https://www.iana.org/domains/root/db/xihuan.html xihuan @@ -11237,6 +11225,10 @@ graphox.us // Submitted by Ofer Kalaora <postmaster@activetrail.com> activetrail.biz +// Adaptable.io : https://adaptable.io +// Submitted by Mark Terrel <support@adaptable.io> +adaptable.app + // Adobe : https://www.adobe.com/ // Submitted by Ian Boston <boston@adobe.com> and Lars Trieloff <trieloff@adobe.com> adobeaemcloud.com @@ -12049,6 +12041,10 @@ appudo.net // Submitted by Thomas Orozco <thomas@aptible.com> on-aptible.com +// Aquapal : https://aquapal.net/ +// Submitted by Aki Ueno <admin@aquapal.net> +f5.si + // ASEINet : https://www.aseinet.com/ // Submitted by Asei SEKIGUCHI <mail@aseinet.com> user.aseinet.ne.jp @@ -12221,7 +12217,9 @@ mycd.eu // Canva Pty Ltd : https://canva.com/ // Submitted by Joel Aquilina <publicsuffixlist@canva.com> canva-apps.cn +*.my.canvasite.cn canva-apps.com +*.my.canva.site // Carrd : https://carrd.co // Submitted by AJ <aj@carrd.co> @@ -12413,6 +12411,10 @@ co.no webhosting.be hosting-cluster.nl +// Convex : https://convex.dev/ +// Submitted by James Cowling <security@convex.dev> +convex.site + // Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/ // Submitted by George Georgievsky <gug@cctld.ru> ac.ru @@ -12434,10 +12436,18 @@ feste-ip.net knx-server.net static-access.net +// cPanel L.L.C. : https://www.cpanel.net/ +// Submitted by Dustin Scherer <public.suffix@cpanel.net> +*.cprapid.com + // Craynic, s.r.o. : http://www.craynic.com/ // Submitted by Ales Krajnik <ales.krajnik@craynic.com> realm.cz +// Crisp IM SAS : https://crisp.chat/ +// Submitted by Baptiste Jamin <hostmaster@crisp.chat> +on.crisp.email + // Cryptonomic : https://cryptonomic.net/ // Submitted by Andrew Cady <public-suffix-list@cryptonomic.net> *.cryptonomic.net @@ -12945,6 +12955,10 @@ e4.cz easypanel.app easypanel.host +// EasyWP : https://www.easywp.com +// Submitted by <infracloudteam@namecheap.com> +*.ewp.live + // Elementor : Elementor Ltd. // Submitted by Anton Barkan <antonb@elementor.com> elementor.cloud @@ -14163,6 +14177,10 @@ mintere.site // Submitted by Grayson Martin <grayson.martin@mobileeducation.us> forte.id +// MODX Systems LLC : https://modx.com +// Submitted by Elizabeth Southwell <elizabeth@modx.com> +modx.dev + // Mozilla Corporation : https://mozilla.com // Submitted by Ben Francis <bfrancis@mozilla.com> mozilla-iot.org @@ -14224,6 +14242,7 @@ jp.ngrok.io sa.ngrok.io us.ngrok.io ngrok.pizza +ngrok.pro // Nicolaus Copernicus University in Torun - MSK TORMAN (https://www.man.torun.pl) torun.pl @@ -14639,6 +14658,8 @@ qbuser.com // Rad Web Hosting: https://radwebhosting.com // Submitted by Scott Claeys <s.claeys@radwebhosting.com> cloudsite.builders +myradweb.net +servername.us // Redgate Software: https://red-gate.com // Submitted by Andrew Farries <andrew.farries@red-gate.com> @@ -14705,11 +14726,40 @@ app.render.com onrender.com // Repl.it : https://repl.it -// Submitted by Lincoln Bergeson <lincoln@replit.com> +// Submitted by Lincoln Bergeson <psl@repl.it> +replit.app +id.replit.app firewalledreplit.co id.firewalledreplit.co repl.co id.repl.co +replit.dev +archer.replit.dev +bones.replit.dev +canary.replit.dev +global.replit.dev +hacker.replit.dev +id.replit.dev +janeway.replit.dev +kim.replit.dev +kira.replit.dev +kirk.replit.dev +odo.replit.dev +paris.replit.dev +picard.replit.dev +pike.replit.dev +prerelease.replit.dev +reed.replit.dev +riker.replit.dev +sisko.replit.dev +spock.replit.dev +staging.replit.dev +sulu.replit.dev +tarpit.replit.dev +teams.replit.dev +tucker.replit.dev +wesley.replit.dev +worf.replit.dev repl.run // Resin.io : https://resin.io @@ -14992,6 +15042,14 @@ srht.site // Submitted by Adrien Gillon <adrien+public-suffix-list@stackhero.io> stackhero-network.com +// STACKIT : https://www.stackit.de/en/ +// Submitted by STACKIT-DNS Team (Simon Stier) <stackit-dns@mail.schwarz> +runs.onstackit.cloud +stackit.gg +stackit.rocks +stackit.run +stackit.zone + // Staclar : https://staclar.com // Submitted by Q Misell <q@staclar.com> musician.io @@ -15058,6 +15116,19 @@ myspreadshop.co.uk // Submitted by Jacob Lee <jacob@stdlib.com> api.stdlib.com +// stereosense GmbH : https://www.involve.me +// Submitted by Florian Burmann <publicsuffix@involve.me> +feedback.ac +forms.ac +assessments.cx +calculators.cx +funnels.cx +paynow.cx +quizzes.cx +researched.cx +tests.cx +surveys.so + // Storipress : https://storipress.com // Submitted by Benno Liu <benno@storipress.com> storipress.app @@ -15066,6 +15137,12 @@ storipress.app // Submitted by Philip Hutchins <hostmaster@storj.io> storj.farm +// Streak : https://streak.com +// Submitted by Blake Kadatz <eng@streak.com> +streak-link.com +streaklinks.com +streakusercontent.com + // Studenten Net Twente : http://www.snt.utwente.nl/ // Submitted by Silke Hofstra <syscom@snt.utwente.nl> utwente.io @@ -15128,6 +15205,7 @@ taifun-dns.de // Submitted by David Anderson <danderson@tailscale.com> beta.tailscale.net ts.net +*.c.ts.net // TASK geographical domains (www.task.gda.pl/uslugi/dns) gda.pl @@ -15363,6 +15441,11 @@ v.ua // Submitted by Masayuki Note <masa@blade.wafflecell.com> wafflecell.com +// Webflow, Inc. : https://www.webflow.com +// Submitted by Webflow Security Team <security@webflow.com> +webflow.io +webflowtest.io + // WebHare bv: https://www.webhare.com/ // Submitted by Arnold Hendriks <info@webhare.com> *.webhare.dev diff --git a/netwerk/protocol/http/Http2Compression.cpp b/netwerk/protocol/http/Http2Compression.cpp index 4d16e9e532..b95883f13f 100644 --- a/netwerk/protocol/http/Http2Compression.cpp +++ b/netwerk/protocol/http/Http2Compression.cpp @@ -61,6 +61,7 @@ class HpackDynamicTableReporter final : public nsIMemoryReporter { NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) override { + MutexAutoLock lock(mMutex); if (mCompressor) { MOZ_COLLECT_REPORT("explicit/network/hpack/dynamic-tables", KIND_HEAP, UNITS_BYTES, @@ -75,7 +76,8 @@ class HpackDynamicTableReporter final : public nsIMemoryReporter { ~HpackDynamicTableReporter() = default; - Http2BaseCompressor* mCompressor; + Mutex mMutex{"HpackDynamicTableReporter"}; + Http2BaseCompressor* mCompressor MOZ_GUARDED_BY(mMutex); friend class Http2BaseCompressor; }; @@ -187,13 +189,18 @@ nvFIFO::~nvFIFO() { Clear(); } void nvFIFO::AddElement(const nsCString& name, const nsCString& value) { nvPair* pair = new nvPair(name, value); mByteCount += pair->Size(); + MutexAutoLock lock(mMutex); mTable.PushFront(pair); } void nvFIFO::AddElement(const nsCString& name) { AddElement(name, ""_ns); } void nvFIFO::RemoveElement() { - nvPair* pair = mTable.Pop(); + nvPair* pair = nullptr; + { + MutexAutoLock lock(mMutex); + pair = mTable.Pop(); + } if (pair) { mByteCount -= pair->Size(); delete pair; @@ -212,6 +219,7 @@ size_t nvFIFO::StaticLength() const { return gStaticHeaders->GetSize(); } void nvFIFO::Clear() { mByteCount = 0; + MutexAutoLock lock(mMutex); while (mTable.GetSize()) { delete mTable.Pop(); } @@ -244,20 +252,27 @@ Http2BaseCompressor::~Http2BaseCompressor() { Telemetry::Accumulate(mPeakCountID, mPeakCount); } UnregisterStrongMemoryReporter(mDynamicReporter); - mDynamicReporter->mCompressor = nullptr; + { + MutexAutoLock lock(mDynamicReporter->mMutex); + mDynamicReporter->mCompressor = nullptr; + } mDynamicReporter = nullptr; } +size_t nvFIFO::SizeOfDynamicTable(mozilla::MallocSizeOf aMallocSizeOf) const { + size_t size = 0; + MutexAutoLock lock(mMutex); + for (const auto elem : mTable) { + size += elem->SizeOfIncludingThis(aMallocSizeOf); + } + return size; +} + void Http2BaseCompressor::ClearHeaderTable() { mHeaderTable.Clear(); } size_t Http2BaseCompressor::SizeOfExcludingThis( mozilla::MallocSizeOf aMallocSizeOf) const { - size_t size = 0; - for (uint32_t i = mHeaderTable.StaticLength(); i < mHeaderTable.Length(); - ++i) { - size += mHeaderTable[i]->SizeOfIncludingThis(aMallocSizeOf); - } - return size; + return mHeaderTable.SizeOfDynamicTable(aMallocSizeOf); } void Http2BaseCompressor::MakeRoom(uint32_t amount, const char* direction) { diff --git a/netwerk/protocol/http/Http2Compression.h b/netwerk/protocol/http/Http2Compression.h index dd98584607..ad47949938 100644 --- a/netwerk/protocol/http/Http2Compression.h +++ b/netwerk/protocol/http/Http2Compression.h @@ -13,6 +13,7 @@ #include "nsDeque.h" #include "nsString.h" #include "mozilla/Telemetry.h" +#include "mozilla/Mutex.h" namespace mozilla { namespace net { @@ -47,10 +48,18 @@ class nvFIFO { size_t StaticLength() const; void Clear(); const nvPair* operator[](size_t index) const; + size_t SizeOfDynamicTable(mozilla::MallocSizeOf aMallocSizeOf) const; private: uint32_t mByteCount{0}; nsDeque<nvPair> mTable; + + // This mutex is held when adding or removing elements in the table + // and when accessing the table from the main thread (in SizeOfDynamicTable) + // Since the operator[] and other const methods are always called + // on the socket thread, they don't need to lock the mutex. + // Mutable so it can be locked in SizeOfDynamicTable which is const + mutable Mutex mMutex MOZ_UNANNOTATED{"nvFIFO"}; }; class HpackDynamicTableReporter; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index 34e7a2cf0d..240bb14433 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -87,7 +87,8 @@ HttpChannelChild::HttpChannelChild() mIsLastPartOfMultiPart(false), mSuspendForWaitCompleteRedirectSetup(false), mRecvOnStartRequestSentCalled(false), - mSuspendedByWaitingForPermissionCookie(false) { + mSuspendedByWaitingForPermissionCookie(false), + mAlreadyReleased(false) { LOG(("Creating HttpChannelChild @%p\n", this)); mChannelCreationTime = PR_Now(); @@ -199,12 +200,16 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() { // We don't have a listener when AsyncOpen has failed or when this channel // has been sucessfully redirected. if (MOZ_LIKELY(LoadOnStartRequestCalled() && LoadOnStopRequestCalled()) || - !mListener) { + !mListener || mAlreadyReleased) { NS_LOG_RELEASE(this, 0, "HttpChannelChild"); delete this; return 0; } + // This ensures that when the refcount goes to 0 again, we don't dispatch + // yet another runnable and get in a loop. + mAlreadyReleased = true; + // This makes sure we fulfill the stream listener contract all the time. if (NS_SUCCEEDED(mStatus)) { mStatus = NS_ERROR_ABORT; @@ -223,27 +228,11 @@ NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release() { // 3) Finally, we turn the reference into a regular smart pointer. RefPtr<HttpChannelChild> channel = dont_AddRef(this); - - // This runnable will create a strong reference to |this|. - NS_DispatchToMainThread( - NewRunnableMethod("~HttpChannelChild>DoNotifyListener", channel, - &HttpChannelChild::DoNotifyListener)); - + NS_DispatchToMainThread(NS_NewRunnableFunction( + "~HttpChannelChild>DoNotifyListener", + [chan = std::move(channel)] { chan->DoNotifyListener(false); })); // If NS_DispatchToMainThread failed then we're going to leak the runnable, // and thus the channel, so there's no need to do anything else. - - // We should have already done any special handling for the refcount = 1 - // case when the refcount first went from 2 to 1. We don't want it to happen - // when |channel| is destroyed. - MOZ_ASSERT(!mKeptAlive || !CanSend()); - - // XXX If std::move(channel) is allowed, then we don't have to have extra - // checks for the refcount going from 2 to 1. See bug 1680217. - - // This will release the stabilization refcount, which is necessary to avoid - // a leak. - channel = nullptr; - return mRefCnt; } @@ -1233,7 +1222,7 @@ void HttpChannelChild::NotifyOrReleaseListeners(nsresult rv) { DoNotifyListener(); } -void HttpChannelChild::DoNotifyListener() { +void HttpChannelChild::DoNotifyListener(bool aUseEventQueue) { LOG(("HttpChannelChild::DoNotifyListener this=%p", this)); MOZ_ASSERT(NS_IsMainThread()); @@ -1246,16 +1235,20 @@ void HttpChannelChild::DoNotifyListener() { if (mListener && !LoadOnStartRequestCalled()) { nsCOMPtr<nsIStreamListener> listener = mListener; - StoreOnStartRequestCalled( - true); // avoid reentrancy bugs by setting this now + // avoid reentrancy bugs by setting this now + StoreOnStartRequestCalled(true); listener->OnStartRequest(this); } StoreOnStartRequestCalled(true); - mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( - this, [self = UnsafePtr<HttpChannelChild>(this)] { - self->ContinueDoNotifyListener(); - })); + if (aUseEventQueue) { + mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( + this, [self = UnsafePtr<HttpChannelChild>(this)] { + self->ContinueDoNotifyListener(); + })); + } else { + ContinueDoNotifyListener(); + } } void HttpChannelChild::ContinueDoNotifyListener() { diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index c88d30023c..6a54ce390a 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -395,6 +395,12 @@ class HttpChannelChild final : public PHttpChannelChild, // permission or cookie. That is, RecvOnStartRequestSent is received. uint8_t mSuspendedByWaitingForPermissionCookie : 1; + // HttpChannelChild::Release has some special logic that makes sure + // OnStart/OnStop are always called when releasing the channel. + // But we have to make sure we only do this once - otherwise we could + // get stuck in a loop. + uint8_t mAlreadyReleased : 1; + void CleanupRedirectingChannel(nsresult rv); // Calls OnStartRequest and/or OnStopRequest on our listener in case we didn't @@ -427,7 +433,9 @@ class HttpChannelChild final : public PHttpChannelChild, const ResourceTimingStructArgs& timing); void Redirect3Complete(); void DeleteSelf(); - void DoNotifyListener(); + // aUseEventQueue should only be false when called from + // HttpChannelChild::Release to make sure OnStopRequest is called syncly. + void DoNotifyListener(bool aUseEventQueue = true); void ContinueDoNotifyListener(); void OnAfterLastPart(const nsresult& aStatus); void MaybeConnectToSocketProcess(); diff --git a/netwerk/protocol/http/TlsHandshaker.cpp b/netwerk/protocol/http/TlsHandshaker.cpp index 88f0062516..56fe011920 100644 --- a/netwerk/protocol/http/TlsHandshaker.cpp +++ b/netwerk/protocol/http/TlsHandshaker.cpp @@ -31,6 +31,24 @@ TlsHandshaker::TlsHandshaker(nsHttpConnectionInfo* aInfo, TlsHandshaker::~TlsHandshaker() { LOG(("TlsHandshaker dtor %p", this)); } NS_IMETHODIMP +TlsHandshaker::CertVerificationDone() { + LOG(("TlsHandshaker::CertVerificationDone mOwner=%p", mOwner.get())); + if (mOwner) { + Unused << mOwner->ResumeSend(); + } + return NS_OK; +} + +NS_IMETHODIMP +TlsHandshaker::ClientAuthCertificateSelected() { + LOG(("TlsHandshaker::ClientAuthCertificateSelected mOwner=%p", mOwner.get())); + if (mOwner) { + Unused << mOwner->ResumeSend(); + } + return NS_OK; +} + +NS_IMETHODIMP TlsHandshaker::HandshakeDone() { LOG(("TlsHandshaker::HandshakeDone mOwner=%p", mOwner.get())); if (mOwner) { diff --git a/netwerk/protocol/http/nsITlsHandshakeListener.idl b/netwerk/protocol/http/nsITlsHandshakeListener.idl index cb5444f6d7..0d5806be24 100644 --- a/netwerk/protocol/http/nsITlsHandshakeListener.idl +++ b/netwerk/protocol/http/nsITlsHandshakeListener.idl @@ -9,4 +9,6 @@ [uuid(b4bbe824-ec4c-48be-9a40-6a7339347f40)] interface nsITlsHandshakeCallbackListener : nsISupports { [noscript] void handshakeDone(); + [noscript] void certVerificationDone(); + [noscript] void clientAuthCertificateSelected(); }; diff --git a/netwerk/test/unit/test_client_auth_with_proxy.js b/netwerk/test/unit/test_client_auth_with_proxy.js new file mode 100644 index 0000000000..0584dba69d --- /dev/null +++ b/netwerk/test/unit/test_client_auth_with_proxy.js @@ -0,0 +1,185 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +/* import-globals-from head_cache.js */ +/* import-globals-from head_cookies.js */ +/* import-globals-from head_channels.js */ +/* import-globals-from head_servers.js */ + +const { MockRegistrar } = ChromeUtils.importESModule( + "resource://testing-common/MockRegistrar.sys.mjs" +); + +const certOverrideService = Cc[ + "@mozilla.org/security/certoverride;1" +].getService(Ci.nsICertOverrideService); + +function makeChan(uri) { + let chan = NetUtil.newChannel({ + uri, + loadUsingSystemPrincipal: true, + }).QueryInterface(Ci.nsIHttpChannel); + chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; + return chan; +} + +function channelOpenPromise(chan, flags) { + return new Promise(resolve => { + function finish(req, buffer) { + resolve([req, buffer]); + } + chan.asyncOpen(new ChannelListener(finish, null, flags)); + }); +} + +class SecurityObserver { + constructor(input, output) { + this.input = input; + this.output = output; + } + + onHandshakeDone(socket, status) { + info("TLS handshake done"); + + let output = this.output; + this.input.asyncWait( + { + onInputStreamReady(readyInput) { + let request = NetUtil.readInputStreamToString( + readyInput, + readyInput.available() + ); + ok( + request.startsWith("GET /") && request.includes("HTTP/1.1"), + "expecting an HTTP/1.1 GET request" + ); + let response = + "HTTP/1.1 200 OK\r\nContent-Type:text/plain\r\n" + + "Connection:Close\r\nContent-Length:2\r\n\r\nOK"; + output.write(response, response.length); + }, + }, + 0, + 0, + Services.tm.currentThread + ); + } +} + +function startServer(cert) { + let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance( + Ci.nsITLSServerSocket + ); + tlsServer.init(-1, true, -1); + tlsServer.serverCert = cert; + + let securityObservers = []; + + let listener = { + onSocketAccepted(socket, transport) { + info("Accepted TLS client connection"); + let connectionInfo = transport.securityCallbacks.getInterface( + Ci.nsITLSServerConnectionInfo + ); + let input = transport.openInputStream(0, 0, 0); + let output = transport.openOutputStream(0, 0, 0); + connectionInfo.setSecurityObserver(new SecurityObserver(input, output)); + }, + + onStopListening() { + info("onStopListening"); + for (let securityObserver of securityObservers) { + securityObserver.input.close(); + securityObserver.output.close(); + } + }, + }; + + tlsServer.setSessionTickets(false); + tlsServer.setRequestClientCertificate(Ci.nsITLSServerSocket.REQUEST_ALWAYS); + + tlsServer.asyncListen(listener); + + return tlsServer; +} + +// Replace the UI dialog that prompts the user to pick a client certificate. +const gClientAuthDialogs = { + chooseCertificate( + hostname, + port, + organization, + issuerOrg, + certList, + selectedIndex, + rememberClientAuthCertificate + ) { + return true; + }, + + QueryInterface: ChromeUtils.generateQI(["nsIClientAuthDialogs"]), +}; + +let server; +add_setup(async function setup() { + do_get_profile(); + + let clientAuthDialogsCID = MockRegistrar.register( + "@mozilla.org/nsClientAuthDialogs;1", + gClientAuthDialogs + ); + + let cert = getTestServerCertificate(); + ok(!!cert, "Got self-signed cert"); + server = startServer(cert); + + certOverrideService.rememberValidityOverride( + "localhost", + server.port, + {}, + cert, + true + ); + + registerCleanupFunction(async function () { + MockRegistrar.unregister(clientAuthDialogsCID); + certOverrideService.clearValidityOverride("localhost", server.port, {}); + server.close(); + }); +}); + +add_task(async function test_client_auth_with_proxy() { + let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); + addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u"); + + let proxies = [ + NodeHTTPProxyServer, + NodeHTTPSProxyServer, + NodeHTTP2ProxyServer, + ]; + + for (let p of proxies) { + info(`Test with proxy:${p.name}`); + let proxy = new p(); + await proxy.start(); + registerCleanupFunction(async () => { + await proxy.stop(); + }); + + let chan = makeChan(`https://localhost:${server.port}`); + let [req, buff] = await channelOpenPromise(chan, CL_ALLOW_UNKNOWN_CL); + equal(req.status, Cr.NS_OK); + equal(req.QueryInterface(Ci.nsIHttpChannel).responseStatus, 200); + equal(buff, "OK"); + req.QueryInterface(Ci.nsIProxiedChannel); + ok(!!req.proxyInfo); + notEqual(req.proxyInfo.type, "direct"); + await proxy.stop(); + } +}); diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index ed69ad2627..52433261bc 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -775,3 +775,5 @@ skip-if = os == 'win' && msix true run-sequentially = node server exceptions dont replay well +[test_client_auth_with_proxy.js] +skip-if = os == "android" |