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