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