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