/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 |