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/. */
5 
6 #include "TLSServerSocket.h"
7 
8 #include "mozilla/net/DNS.h"
9 #include "nsComponentManagerUtils.h"
10 #include "nsDependentSubstring.h"
11 #include "nsIServerSocket.h"
12 #include "nsIX509Cert.h"
13 #include "nsIX509CertDB.h"
14 #include "nsNetCID.h"
15 #include "nsProxyRelease.h"
16 #include "nsServiceManagerUtils.h"
17 #include "nsSocketTransport2.h"
18 #include "nsThreadUtils.h"
19 #include "ScopedNSSTypes.h"
20 #include "ssl.h"
21 
22 namespace mozilla {
23 namespace net {
24 
25 //-----------------------------------------------------------------------------
26 // TLSServerSocket
27 //-----------------------------------------------------------------------------
28 
TLSServerSocket()29 TLSServerSocket::TLSServerSocket() : mServerCert(nullptr) {}
30 
NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket,nsServerSocket,nsITLSServerSocket)31 NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket, nsServerSocket, nsITLSServerSocket)
32 
33 nsresult TLSServerSocket::SetSocketDefaults() {
34   // Set TLS options on the listening socket
35   mFD = SSL_ImportFD(nullptr, mFD);
36   if (NS_WARN_IF(!mFD)) {
37     return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
38   }
39 
40   SSL_OptionSet(mFD, SSL_SECURITY, true);
41   SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_CLIENT, false);
42   SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_SERVER, true);
43   SSL_OptionSet(mFD, SSL_NO_CACHE, true);
44 
45   // We don't currently notify the server API consumer of renegotiation events
46   // (to revalidate peer certs, etc.), so disable it for now.
47   SSL_OptionSet(mFD, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER);
48 
49   SetSessionTickets(true);
50   SetRequestClientCertificate(REQUEST_NEVER);
51 
52   return NS_OK;
53 }
54 
CreateClientTransport(PRFileDesc * aClientFD,const NetAddr & aClientAddr)55 void TLSServerSocket::CreateClientTransport(PRFileDesc* aClientFD,
56                                             const NetAddr& aClientAddr) {
57   MOZ_ASSERT(OnSocketThread(), "not on socket thread");
58   nsresult rv;
59 
60   RefPtr<nsSocketTransport> trans = new nsSocketTransport;
61   if (NS_WARN_IF(!trans)) {
62     mCondition = NS_ERROR_OUT_OF_MEMORY;
63     return;
64   }
65 
66   RefPtr<TLSServerConnectionInfo> info = new TLSServerConnectionInfo();
67   info->mServerSocket = this;
68   info->mTransport = trans;
69   nsCOMPtr<nsISupports> infoSupports =
70       NS_ISUPPORTS_CAST(nsITLSServerConnectionInfo*, info);
71   rv = trans->InitWithConnectedSocket(aClientFD, &aClientAddr, infoSupports);
72   if (NS_WARN_IF(NS_FAILED(rv))) {
73     mCondition = rv;
74     return;
75   }
76 
77   // Override the default peer certificate validation, so that server consumers
78   // can make their own choice after the handshake completes.
79   SSL_AuthCertificateHook(aClientFD, AuthCertificateHook, nullptr);
80   // Once the TLS handshake has completed, the server consumer is notified and
81   // has access to various TLS state details.
82   // It's safe to pass info here because the socket transport holds it as
83   // |mSecInfo| which keeps it alive for the lifetime of the socket.
84   SSL_HandshakeCallback(aClientFD, TLSServerConnectionInfo::HandshakeCallback,
85                         info);
86 
87   // Notify the consumer of the new client so it can manage the streams.
88   // Security details aren't known yet.  The security observer will be notified
89   // later when they are ready.
90   nsCOMPtr<nsIServerSocket> serverSocket =
91       do_QueryInterface(NS_ISUPPORTS_CAST(nsITLSServerSocket*, this));
92   mListener->OnSocketAccepted(serverSocket, trans);
93 }
94 
OnSocketListen()95 nsresult TLSServerSocket::OnSocketListen() {
96   if (NS_WARN_IF(!mServerCert)) {
97     return NS_ERROR_NOT_INITIALIZED;
98   }
99 
100   UniqueCERTCertificate cert(mServerCert->GetCert());
101   if (NS_WARN_IF(!cert)) {
102     return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
103   }
104 
105   UniqueSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert.get(), nullptr));
106   if (NS_WARN_IF(!key)) {
107     return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
108   }
109 
110   SSLKEAType certKEA = NSS_FindCertKEAType(cert.get());
111 
112   nsresult rv =
113       MapSECStatus(SSL_ConfigSecureServer(mFD, cert.get(), key.get(), certKEA));
114   if (NS_WARN_IF(NS_FAILED(rv))) {
115     return rv;
116   }
117 
118   return NS_OK;
119 }
120 
121 // static
AuthCertificateHook(void * arg,PRFileDesc * fd,PRBool checksig,PRBool isServer)122 SECStatus TLSServerSocket::AuthCertificateHook(void* arg, PRFileDesc* fd,
123                                                PRBool checksig,
124                                                PRBool isServer) {
125   // Allow any client cert here, server consumer code can decide whether it's
126   // okay after being notified of the new client socket.
127   return SECSuccess;
128 }
129 
130 //-----------------------------------------------------------------------------
131 // TLSServerSocket::nsITLSServerSocket
132 //-----------------------------------------------------------------------------
133 
134 NS_IMETHODIMP
GetServerCert(nsIX509Cert ** aCert)135 TLSServerSocket::GetServerCert(nsIX509Cert** aCert) {
136   if (NS_WARN_IF(!aCert)) {
137     return NS_ERROR_INVALID_POINTER;
138   }
139   *aCert = mServerCert;
140   NS_IF_ADDREF(*aCert);
141   return NS_OK;
142 }
143 
144 NS_IMETHODIMP
SetServerCert(nsIX509Cert * aCert)145 TLSServerSocket::SetServerCert(nsIX509Cert* aCert) {
146   // If AsyncListen was already called (and set mListener), it's too late to set
147   // this.
148   if (NS_WARN_IF(mListener)) {
149     return NS_ERROR_IN_PROGRESS;
150   }
151   mServerCert = aCert;
152   return NS_OK;
153 }
154 
155 NS_IMETHODIMP
SetSessionTickets(bool aEnabled)156 TLSServerSocket::SetSessionTickets(bool aEnabled) {
157   // If AsyncListen was already called (and set mListener), it's too late to set
158   // this.
159   if (NS_WARN_IF(mListener)) {
160     return NS_ERROR_IN_PROGRESS;
161   }
162   SSL_OptionSet(mFD, SSL_ENABLE_SESSION_TICKETS, aEnabled);
163   return NS_OK;
164 }
165 
166 NS_IMETHODIMP
SetRequestClientCertificate(uint32_t aMode)167 TLSServerSocket::SetRequestClientCertificate(uint32_t aMode) {
168   // If AsyncListen was already called (and set mListener), it's too late to set
169   // this.
170   if (NS_WARN_IF(mListener)) {
171     return NS_ERROR_IN_PROGRESS;
172   }
173   SSL_OptionSet(mFD, SSL_REQUEST_CERTIFICATE, aMode != REQUEST_NEVER);
174 
175   switch (aMode) {
176     case REQUEST_ALWAYS:
177       SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NO_ERROR);
178       break;
179     case REQUIRE_FIRST_HANDSHAKE:
180       SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_FIRST_HANDSHAKE);
181       break;
182     case REQUIRE_ALWAYS:
183       SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS);
184       break;
185     default:
186       SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
187   }
188   return NS_OK;
189 }
190 
191 NS_IMETHODIMP
SetVersionRange(uint16_t aMinVersion,uint16_t aMaxVersion)192 TLSServerSocket::SetVersionRange(uint16_t aMinVersion, uint16_t aMaxVersion) {
193   // If AsyncListen was already called (and set mListener), it's too late to set
194   // this.
195   if (NS_WARN_IF(mListener)) {
196     return NS_ERROR_IN_PROGRESS;
197   }
198 
199   SSLVersionRange range = {aMinVersion, aMaxVersion};
200   if (SSL_VersionRangeSet(mFD, &range) != SECSuccess) {
201     return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
202   }
203 
204   return NS_OK;
205 }
206 
207 //-----------------------------------------------------------------------------
208 // TLSServerConnectionInfo
209 //-----------------------------------------------------------------------------
210 
211 namespace {
212 
213 class TLSServerSecurityObserverProxy final
214     : public nsITLSServerSecurityObserver {
215   ~TLSServerSecurityObserverProxy() = default;
216 
217  public:
TLSServerSecurityObserverProxy(nsITLSServerSecurityObserver * aListener)218   explicit TLSServerSecurityObserverProxy(
219       nsITLSServerSecurityObserver* aListener)
220       : mListener(new nsMainThreadPtrHolder<nsITLSServerSecurityObserver>(
221             "TLSServerSecurityObserverProxy::mListener", aListener)) {}
222 
223   NS_DECL_THREADSAFE_ISUPPORTS
224   NS_DECL_NSITLSSERVERSECURITYOBSERVER
225 
226   class OnHandshakeDoneRunnable : public Runnable {
227    public:
OnHandshakeDoneRunnable(const nsMainThreadPtrHandle<nsITLSServerSecurityObserver> & aListener,nsITLSServerSocket * aServer,nsITLSClientStatus * aStatus)228     OnHandshakeDoneRunnable(
229         const nsMainThreadPtrHandle<nsITLSServerSecurityObserver>& aListener,
230         nsITLSServerSocket* aServer, nsITLSClientStatus* aStatus)
231         : Runnable(
232               "net::TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable"),
233           mListener(aListener),
234           mServer(aServer),
235           mStatus(aStatus) {}
236 
237     NS_DECL_NSIRUNNABLE
238 
239    private:
240     nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
241     nsCOMPtr<nsITLSServerSocket> mServer;
242     nsCOMPtr<nsITLSClientStatus> mStatus;
243   };
244 
245  private:
246   nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
247 };
248 
NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy,nsITLSServerSecurityObserver)249 NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy, nsITLSServerSecurityObserver)
250 
251 NS_IMETHODIMP
252 TLSServerSecurityObserverProxy::OnHandshakeDone(nsITLSServerSocket* aServer,
253                                                 nsITLSClientStatus* aStatus) {
254   RefPtr<OnHandshakeDoneRunnable> r =
255       new OnHandshakeDoneRunnable(mListener, aServer, aStatus);
256   return NS_DispatchToMainThread(r);
257 }
258 
259 NS_IMETHODIMP
Run()260 TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable::Run() {
261   mListener->OnHandshakeDone(mServer, mStatus);
262   return NS_OK;
263 }
264 
265 }  // namespace
266 
NS_IMPL_ISUPPORTS(TLSServerConnectionInfo,nsITLSServerConnectionInfo,nsITLSClientStatus)267 NS_IMPL_ISUPPORTS(TLSServerConnectionInfo, nsITLSServerConnectionInfo,
268                   nsITLSClientStatus)
269 
270 TLSServerConnectionInfo::TLSServerConnectionInfo()
271     : mServerSocket(nullptr),
272       mTransport(nullptr),
273       mPeerCert(nullptr),
274       mTlsVersionUsed(TLS_VERSION_UNKNOWN),
275       mKeyLength(0),
276       mMacLength(0),
277       mLock("TLSServerConnectionInfo.mLock"),
278       mSecurityObserver(nullptr) {}
279 
~TLSServerConnectionInfo()280 TLSServerConnectionInfo::~TLSServerConnectionInfo() {
281   RefPtr<nsITLSServerSecurityObserver> observer;
282   {
283     MutexAutoLock lock(mLock);
284     observer = ToRefPtr(std::move(mSecurityObserver));
285   }
286 
287   if (observer) {
288     NS_ReleaseOnMainThread("TLSServerConnectionInfo::mSecurityObserver",
289                            observer.forget());
290   }
291 }
292 
293 NS_IMETHODIMP
SetSecurityObserver(nsITLSServerSecurityObserver * aObserver)294 TLSServerConnectionInfo::SetSecurityObserver(
295     nsITLSServerSecurityObserver* aObserver) {
296   {
297     MutexAutoLock lock(mLock);
298     if (!aObserver) {
299       mSecurityObserver = nullptr;
300       return NS_OK;
301     }
302 
303     mSecurityObserver = new TLSServerSecurityObserverProxy(aObserver);
304     // Call `OnHandshakeDone` if TLS handshake is already completed.
305     if (mTlsVersionUsed != TLS_VERSION_UNKNOWN) {
306       nsCOMPtr<nsITLSServerSocket> serverSocket;
307       GetServerSocket(getter_AddRefs(serverSocket));
308       mSecurityObserver->OnHandshakeDone(serverSocket, this);
309       mSecurityObserver = nullptr;
310     }
311   }
312   return NS_OK;
313 }
314 
315 NS_IMETHODIMP
GetServerSocket(nsITLSServerSocket ** aSocket)316 TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket** aSocket) {
317   if (NS_WARN_IF(!aSocket)) {
318     return NS_ERROR_INVALID_POINTER;
319   }
320   *aSocket = mServerSocket;
321   NS_IF_ADDREF(*aSocket);
322   return NS_OK;
323 }
324 
325 NS_IMETHODIMP
GetStatus(nsITLSClientStatus ** aStatus)326 TLSServerConnectionInfo::GetStatus(nsITLSClientStatus** aStatus) {
327   if (NS_WARN_IF(!aStatus)) {
328     return NS_ERROR_INVALID_POINTER;
329   }
330   *aStatus = this;
331   NS_IF_ADDREF(*aStatus);
332   return NS_OK;
333 }
334 
335 NS_IMETHODIMP
GetPeerCert(nsIX509Cert ** aCert)336 TLSServerConnectionInfo::GetPeerCert(nsIX509Cert** aCert) {
337   if (NS_WARN_IF(!aCert)) {
338     return NS_ERROR_INVALID_POINTER;
339   }
340   *aCert = mPeerCert;
341   NS_IF_ADDREF(*aCert);
342   return NS_OK;
343 }
344 
345 NS_IMETHODIMP
GetTlsVersionUsed(int16_t * aTlsVersionUsed)346 TLSServerConnectionInfo::GetTlsVersionUsed(int16_t* aTlsVersionUsed) {
347   if (NS_WARN_IF(!aTlsVersionUsed)) {
348     return NS_ERROR_INVALID_POINTER;
349   }
350   *aTlsVersionUsed = mTlsVersionUsed;
351   return NS_OK;
352 }
353 
354 NS_IMETHODIMP
GetCipherName(nsACString & aCipherName)355 TLSServerConnectionInfo::GetCipherName(nsACString& aCipherName) {
356   aCipherName.Assign(mCipherName);
357   return NS_OK;
358 }
359 
360 NS_IMETHODIMP
GetKeyLength(uint32_t * aKeyLength)361 TLSServerConnectionInfo::GetKeyLength(uint32_t* aKeyLength) {
362   if (NS_WARN_IF(!aKeyLength)) {
363     return NS_ERROR_INVALID_POINTER;
364   }
365   *aKeyLength = mKeyLength;
366   return NS_OK;
367 }
368 
369 NS_IMETHODIMP
GetMacLength(uint32_t * aMacLength)370 TLSServerConnectionInfo::GetMacLength(uint32_t* aMacLength) {
371   if (NS_WARN_IF(!aMacLength)) {
372     return NS_ERROR_INVALID_POINTER;
373   }
374   *aMacLength = mMacLength;
375   return NS_OK;
376 }
377 
378 // static
HandshakeCallback(PRFileDesc * aFD,void * aArg)379 void TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD, void* aArg) {
380   RefPtr<TLSServerConnectionInfo> info =
381       static_cast<TLSServerConnectionInfo*>(aArg);
382   nsISocketTransport* transport = info->mTransport;
383   // No longer needed outside this function, so clear the weak ref
384   info->mTransport = nullptr;
385   nsresult rv = info->HandshakeCallback(aFD);
386   if (NS_WARN_IF(NS_FAILED(rv))) {
387     transport->Close(rv);
388   }
389 }
390 
HandshakeCallback(PRFileDesc * aFD)391 nsresult TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD) {
392   nsresult rv;
393 
394   UniqueCERTCertificate clientCert(SSL_PeerCertificate(aFD));
395   if (clientCert) {
396     nsCOMPtr<nsIX509CertDB> certDB =
397         do_GetService(NS_X509CERTDB_CONTRACTID, &rv);
398     if (NS_FAILED(rv)) {
399       return rv;
400     }
401 
402     nsCOMPtr<nsIX509Cert> clientCertPSM;
403     nsTArray<uint8_t> clientCertBytes;
404     clientCertBytes.AppendElements(clientCert->derCert.data,
405                                    clientCert->derCert.len);
406     rv = certDB->ConstructX509(clientCertBytes, getter_AddRefs(clientCertPSM));
407     if (NS_FAILED(rv)) {
408       return rv;
409     }
410 
411     mPeerCert = clientCertPSM;
412   }
413 
414   SSLChannelInfo channelInfo;
415   rv = MapSECStatus(SSL_GetChannelInfo(aFD, &channelInfo, sizeof(channelInfo)));
416   if (NS_FAILED(rv)) {
417     return rv;
418   }
419 
420   SSLCipherSuiteInfo cipherInfo;
421   rv = MapSECStatus(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
422                                            sizeof(cipherInfo)));
423   if (NS_FAILED(rv)) {
424     return rv;
425   }
426   mCipherName.Assign(cipherInfo.cipherSuiteName);
427   mKeyLength = cipherInfo.effectiveKeyBits;
428   mMacLength = cipherInfo.macBits;
429 
430   // Notify consumer code that handshake is complete
431   nsCOMPtr<nsITLSServerSecurityObserver> observer;
432   {
433     MutexAutoLock lock(mLock);
434     mTlsVersionUsed = channelInfo.protocolVersion;
435     if (!mSecurityObserver) {
436       return NS_OK;
437     }
438     mSecurityObserver.swap(observer);
439   }
440   nsCOMPtr<nsITLSServerSocket> serverSocket;
441   GetServerSocket(getter_AddRefs(serverSocket));
442   observer->OnHandshakeDone(serverSocket, this);
443 
444   return NS_OK;
445 }
446 
447 }  // namespace net
448 }  // namespace mozilla
449