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