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