Source code

Revision control

Other Tools

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