Coverage Report

Created: 2018-09-25 14:53

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