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