Backed out changeset 2bbc01486e2f (bug 1910796) for causing multiple failures. CLOSED...
[gecko.git] / netwerk / base / TLSServerSocket.cpp
blob8887a8090d043ce76a3a5fd490ec24760f70e651
1 /* vim:set ts=2 sw=2 et cindent: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "TLSServerSocket.h"
8 #include "mozilla/net/DNS.h"
9 #include "mozilla/Components.h"
10 #include "nsComponentManagerUtils.h"
11 #include "nsDependentSubstring.h"
12 #include "nsIServerSocket.h"
13 #include "nsIX509Cert.h"
14 #include "nsIX509CertDB.h"
15 #include "nsNetCID.h"
16 #include "nsProxyRelease.h"
17 #include "nsServiceManagerUtils.h"
18 #include "nsSocketTransport2.h"
19 #include "nsThreadUtils.h"
20 #include "ScopedNSSTypes.h"
21 #include "ssl.h"
23 namespace mozilla {
24 namespace net {
26 //-----------------------------------------------------------------------------
27 // TLSServerSocket
28 //-----------------------------------------------------------------------------
30 NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket, nsServerSocket, nsITLSServerSocket)
32 nsresult TLSServerSocket::SetSocketDefaults() {
33 // Set TLS options on the listening socket
34 mFD = SSL_ImportFD(nullptr, mFD);
35 if (NS_WARN_IF(!mFD)) {
36 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
39 SSL_OptionSet(mFD, SSL_SECURITY, true);
40 SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_CLIENT, false);
41 SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_SERVER, true);
42 SSL_OptionSet(mFD, SSL_NO_CACHE, true);
44 // We don't currently notify the server API consumer of renegotiation events
45 // (to revalidate peer certs, etc.), so disable it for now.
46 SSL_OptionSet(mFD, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER);
48 SetSessionTickets(true);
49 SetRequestClientCertificate(REQUEST_NEVER);
51 return NS_OK;
54 void TLSServerSocket::CreateClientTransport(PRFileDesc* aClientFD,
55 const NetAddr& aClientAddr) {
56 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
57 nsresult rv;
59 RefPtr<nsSocketTransport> trans = new nsSocketTransport;
60 if (NS_WARN_IF(!trans)) {
61 mCondition = NS_ERROR_OUT_OF_MEMORY;
62 return;
65 RefPtr<TLSServerConnectionInfo> info = new TLSServerConnectionInfo();
66 info->mServerSocket = this;
67 info->mTransport = trans;
68 nsCOMPtr<nsIInterfaceRequestor> infoInterfaceRequestor(info);
69 rv = trans->InitWithConnectedSocket(aClientFD, &aClientAddr,
70 infoInterfaceRequestor);
71 if (NS_WARN_IF(NS_FAILED(rv))) {
72 mCondition = rv;
73 return;
76 // Override the default peer certificate validation, so that server consumers
77 // can make their own choice after the handshake completes.
78 SSL_AuthCertificateHook(aClientFD, AuthCertificateHook, nullptr);
79 // Once the TLS handshake has completed, the server consumer is notified and
80 // has access to various TLS state details.
81 // It's safe to pass info here because the socket transport holds it as
82 // |mSecInfo| which keeps it alive for the lifetime of the socket.
83 SSL_HandshakeCallback(aClientFD, TLSServerConnectionInfo::HandshakeCallback,
84 info);
86 // Notify the consumer of the new client so it can manage the streams.
87 // Security details aren't known yet. The security observer will be notified
88 // later when they are ready.
89 nsCOMPtr<nsIServerSocket> serverSocket =
90 do_QueryInterface(NS_ISUPPORTS_CAST(nsITLSServerSocket*, this));
91 mListener->OnSocketAccepted(serverSocket, trans);
94 nsresult TLSServerSocket::OnSocketListen() {
95 if (NS_WARN_IF(!mServerCert)) {
96 return NS_ERROR_NOT_INITIALIZED;
99 UniqueCERTCertificate cert(mServerCert->GetCert());
100 if (NS_WARN_IF(!cert)) {
101 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
104 UniqueSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert.get(), nullptr));
105 if (NS_WARN_IF(!key)) {
106 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
109 SSLKEAType certKEA = NSS_FindCertKEAType(cert.get());
111 nsresult rv =
112 MapSECStatus(SSL_ConfigSecureServer(mFD, cert.get(), key.get(), certKEA));
113 if (NS_WARN_IF(NS_FAILED(rv))) {
114 return rv;
117 return NS_OK;
120 // static
121 SECStatus TLSServerSocket::AuthCertificateHook(void* arg, PRFileDesc* fd,
122 PRBool checksig,
123 PRBool isServer) {
124 // Allow any client cert here, server consumer code can decide whether it's
125 // okay after being notified of the new client socket.
126 return SECSuccess;
129 //-----------------------------------------------------------------------------
130 // TLSServerSocket::nsITLSServerSocket
131 //-----------------------------------------------------------------------------
133 NS_IMETHODIMP
134 TLSServerSocket::GetServerCert(nsIX509Cert** aCert) {
135 if (NS_WARN_IF(!aCert)) {
136 return NS_ERROR_INVALID_POINTER;
138 *aCert = do_AddRef(mServerCert).take();
139 return NS_OK;
142 NS_IMETHODIMP
143 TLSServerSocket::SetServerCert(nsIX509Cert* aCert) {
144 // If AsyncListen was already called (and set mListener), it's too late to set
145 // this.
146 if (NS_WARN_IF(mListener)) {
147 return NS_ERROR_IN_PROGRESS;
149 mServerCert = aCert;
150 return NS_OK;
153 NS_IMETHODIMP
154 TLSServerSocket::SetSessionTickets(bool aEnabled) {
155 // If AsyncListen was already called (and set mListener), it's too late to set
156 // this.
157 if (NS_WARN_IF(mListener)) {
158 return NS_ERROR_IN_PROGRESS;
160 SSL_OptionSet(mFD, SSL_ENABLE_SESSION_TICKETS, aEnabled);
161 return NS_OK;
164 NS_IMETHODIMP
165 TLSServerSocket::SetRequestClientCertificate(uint32_t aMode) {
166 // If AsyncListen was already called (and set mListener), it's too late to set
167 // this.
168 if (NS_WARN_IF(mListener)) {
169 return NS_ERROR_IN_PROGRESS;
171 SSL_OptionSet(mFD, SSL_REQUEST_CERTIFICATE, aMode != REQUEST_NEVER);
173 switch (aMode) {
174 case REQUEST_ALWAYS:
175 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NO_ERROR);
176 break;
177 case REQUIRE_FIRST_HANDSHAKE:
178 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_FIRST_HANDSHAKE);
179 break;
180 case REQUIRE_ALWAYS:
181 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS);
182 break;
183 default:
184 SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
186 return NS_OK;
189 NS_IMETHODIMP
190 TLSServerSocket::SetVersionRange(uint16_t aMinVersion, uint16_t aMaxVersion) {
191 // If AsyncListen was already called (and set mListener), it's too late to set
192 // this.
193 if (NS_WARN_IF(mListener)) {
194 return NS_ERROR_IN_PROGRESS;
197 SSLVersionRange range = {aMinVersion, aMaxVersion};
198 if (SSL_VersionRangeSet(mFD, &range) != SECSuccess) {
199 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
202 return NS_OK;
205 //-----------------------------------------------------------------------------
206 // TLSServerConnectionInfo
207 //-----------------------------------------------------------------------------
209 namespace {
211 class TLSServerSecurityObserverProxy final
212 : public nsITLSServerSecurityObserver {
213 ~TLSServerSecurityObserverProxy() = default;
215 public:
216 explicit TLSServerSecurityObserverProxy(
217 nsITLSServerSecurityObserver* aListener)
218 : mListener(new nsMainThreadPtrHolder<nsITLSServerSecurityObserver>(
219 "TLSServerSecurityObserverProxy::mListener", aListener)) {}
221 NS_DECL_THREADSAFE_ISUPPORTS
222 NS_DECL_NSITLSSERVERSECURITYOBSERVER
224 class OnHandshakeDoneRunnable : public Runnable {
225 public:
226 OnHandshakeDoneRunnable(
227 const nsMainThreadPtrHandle<nsITLSServerSecurityObserver>& aListener,
228 nsITLSServerSocket* aServer, nsITLSClientStatus* aStatus)
229 : Runnable(
230 "net::TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable"),
231 mListener(aListener),
232 mServer(aServer),
233 mStatus(aStatus) {}
235 NS_DECL_NSIRUNNABLE
237 private:
238 nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
239 nsCOMPtr<nsITLSServerSocket> mServer;
240 nsCOMPtr<nsITLSClientStatus> mStatus;
243 private:
244 nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
247 NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy, nsITLSServerSecurityObserver)
249 NS_IMETHODIMP
250 TLSServerSecurityObserverProxy::OnHandshakeDone(nsITLSServerSocket* aServer,
251 nsITLSClientStatus* aStatus) {
252 RefPtr<OnHandshakeDoneRunnable> r =
253 new OnHandshakeDoneRunnable(mListener, aServer, aStatus);
254 return NS_DispatchToMainThread(r);
257 NS_IMETHODIMP
258 TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable::Run() {
259 mListener->OnHandshakeDone(mServer, mStatus);
260 return NS_OK;
263 } // namespace
265 NS_IMPL_ISUPPORTS(TLSServerConnectionInfo, nsITLSServerConnectionInfo,
266 nsITLSClientStatus, nsIInterfaceRequestor)
268 TLSServerConnectionInfo::~TLSServerConnectionInfo() {
269 RefPtr<nsITLSServerSecurityObserver> observer;
271 MutexAutoLock lock(mLock);
272 observer = ToRefPtr(std::move(mSecurityObserver));
275 if (observer) {
276 NS_ReleaseOnMainThread("TLSServerConnectionInfo::mSecurityObserver",
277 observer.forget());
281 NS_IMETHODIMP
282 TLSServerConnectionInfo::SetSecurityObserver(
283 nsITLSServerSecurityObserver* aObserver) {
285 MutexAutoLock lock(mLock);
286 if (!aObserver) {
287 mSecurityObserver = nullptr;
288 return NS_OK;
291 mSecurityObserver = new TLSServerSecurityObserverProxy(aObserver);
292 // Call `OnHandshakeDone` if TLS handshake is already completed.
293 if (mTlsVersionUsed != TLS_VERSION_UNKNOWN) {
294 nsCOMPtr<nsITLSServerSocket> serverSocket;
295 GetServerSocket(getter_AddRefs(serverSocket));
296 mSecurityObserver->OnHandshakeDone(serverSocket, this);
297 mSecurityObserver = nullptr;
300 return NS_OK;
303 NS_IMETHODIMP
304 TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket** aSocket) {
305 if (NS_WARN_IF(!aSocket)) {
306 return NS_ERROR_INVALID_POINTER;
308 *aSocket = do_AddRef(mServerSocket).take();
309 return NS_OK;
312 NS_IMETHODIMP
313 TLSServerConnectionInfo::GetStatus(nsITLSClientStatus** aStatus) {
314 if (NS_WARN_IF(!aStatus)) {
315 return NS_ERROR_INVALID_POINTER;
317 *aStatus = do_AddRef(this).take();
318 return NS_OK;
321 NS_IMETHODIMP
322 TLSServerConnectionInfo::GetPeerCert(nsIX509Cert** aCert) {
323 if (NS_WARN_IF(!aCert)) {
324 return NS_ERROR_INVALID_POINTER;
326 *aCert = do_AddRef(mPeerCert).take();
327 return NS_OK;
330 NS_IMETHODIMP
331 TLSServerConnectionInfo::GetTlsVersionUsed(int16_t* aTlsVersionUsed) {
332 if (NS_WARN_IF(!aTlsVersionUsed)) {
333 return NS_ERROR_INVALID_POINTER;
335 *aTlsVersionUsed = mTlsVersionUsed;
336 return NS_OK;
339 NS_IMETHODIMP
340 TLSServerConnectionInfo::GetCipherName(nsACString& aCipherName) {
341 aCipherName.Assign(mCipherName);
342 return NS_OK;
345 NS_IMETHODIMP
346 TLSServerConnectionInfo::GetKeyLength(uint32_t* aKeyLength) {
347 if (NS_WARN_IF(!aKeyLength)) {
348 return NS_ERROR_INVALID_POINTER;
350 *aKeyLength = mKeyLength;
351 return NS_OK;
354 NS_IMETHODIMP
355 TLSServerConnectionInfo::GetMacLength(uint32_t* aMacLength) {
356 if (NS_WARN_IF(!aMacLength)) {
357 return NS_ERROR_INVALID_POINTER;
359 *aMacLength = mMacLength;
360 return NS_OK;
363 NS_IMETHODIMP
364 TLSServerConnectionInfo::GetInterface(const nsIID& aIID, void** aResult) {
365 NS_ENSURE_ARG_POINTER(aResult);
366 *aResult = nullptr;
368 if (aIID.Equals(NS_GET_IID(nsITLSServerConnectionInfo))) {
369 *aResult = static_cast<nsITLSServerConnectionInfo*>(this);
370 NS_ADDREF_THIS();
371 return NS_OK;
374 return NS_NOINTERFACE;
377 // static
378 void TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD, void* aArg) {
379 RefPtr<TLSServerConnectionInfo> info =
380 static_cast<TLSServerConnectionInfo*>(aArg);
381 nsISocketTransport* transport = info->mTransport;
382 // No longer needed outside this function, so clear the weak ref
383 info->mTransport = nullptr;
384 nsresult rv = info->HandshakeCallback(aFD);
385 if (NS_WARN_IF(NS_FAILED(rv))) {
386 transport->Close(rv);
390 nsresult TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD) {
391 nsresult rv;
393 UniqueCERTCertificate clientCert(SSL_PeerCertificate(aFD));
394 if (clientCert) {
395 nsCOMPtr<nsIX509CertDB> certDB;
396 certDB = mozilla::components::NSSCertificateDB::Service(&rv);
397 if (NS_FAILED(rv)) {
398 return rv;
401 nsCOMPtr<nsIX509Cert> clientCertPSM;
402 nsTArray<uint8_t> clientCertBytes;
403 clientCertBytes.AppendElements(clientCert->derCert.data,
404 clientCert->derCert.len);
405 rv = certDB->ConstructX509(clientCertBytes, getter_AddRefs(clientCertPSM));
406 if (NS_FAILED(rv)) {
407 return rv;
410 mPeerCert = clientCertPSM;
413 SSLChannelInfo channelInfo;
414 rv = MapSECStatus(SSL_GetChannelInfo(aFD, &channelInfo, sizeof(channelInfo)));
415 if (NS_FAILED(rv)) {
416 return rv;
419 SSLCipherSuiteInfo cipherInfo;
420 rv = MapSECStatus(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
421 sizeof(cipherInfo)));
422 if (NS_FAILED(rv)) {
423 return rv;
425 mCipherName.Assign(cipherInfo.cipherSuiteName);
426 mKeyLength = cipherInfo.effectiveKeyBits;
427 mMacLength = cipherInfo.macBits;
429 // Notify consumer code that handshake is complete
430 nsCOMPtr<nsITLSServerSecurityObserver> observer;
432 MutexAutoLock lock(mLock);
433 mTlsVersionUsed = channelInfo.protocolVersion;
434 if (!mSecurityObserver) {
435 return NS_OK;
437 mSecurityObserver.swap(observer);
439 nsCOMPtr<nsITLSServerSocket> serverSocket;
440 GetServerSocket(getter_AddRefs(serverSocket));
441 observer->OnHandshakeDone(serverSocket, this);
443 return NS_OK;
446 } // namespace net
447 } // namespace mozilla