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/. */
6 #include "TLSServerSocket.h"
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"
15 #include "nsProxyRelease.h"
16 #include "nsServiceManagerUtils.h"
17 #include "nsSocketTransport2.h"
18 #include "nsThreadUtils.h"
19 #include "ScopedNSSTypes.h"
25 //-----------------------------------------------------------------------------
27 //-----------------------------------------------------------------------------
29 NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket
, nsServerSocket
, nsITLSServerSocket
)
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());
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);
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
);
47 SetSessionTickets(true);
48 SetRequestClientCertificate(REQUEST_NEVER
);
53 void TLSServerSocket::CreateClientTransport(PRFileDesc
* aClientFD
,
54 const NetAddr
& aClientAddr
) {
55 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
58 RefPtr
<nsSocketTransport
> trans
= new nsSocketTransport
;
59 if (NS_WARN_IF(!trans
)) {
60 mCondition
= NS_ERROR_OUT_OF_MEMORY
;
64 RefPtr
<TLSServerConnectionInfo
> info
= new TLSServerConnectionInfo();
65 info
->mServerSocket
= this;
66 info
->mTransport
= trans
;
67 nsCOMPtr
<nsIInterfaceRequestor
> infoInterfaceRequestor(info
);
68 rv
= trans
->InitWithConnectedSocket(aClientFD
, &aClientAddr
,
69 infoInterfaceRequestor
);
70 if (NS_WARN_IF(NS_FAILED(rv
))) {
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
,
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
);
93 nsresult
TLSServerSocket::OnSocketListen() {
94 if (NS_WARN_IF(!mServerCert
)) {
95 return NS_ERROR_NOT_INITIALIZED
;
98 UniqueCERTCertificate
cert(mServerCert
->GetCert());
99 if (NS_WARN_IF(!cert
)) {
100 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
103 UniqueSECKEYPrivateKey
key(PK11_FindKeyByAnyCert(cert
.get(), nullptr));
104 if (NS_WARN_IF(!key
)) {
105 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
108 SSLKEAType certKEA
= NSS_FindCertKEAType(cert
.get());
111 MapSECStatus(SSL_ConfigSecureServer(mFD
, cert
.get(), key
.get(), certKEA
));
112 if (NS_WARN_IF(NS_FAILED(rv
))) {
120 SECStatus
TLSServerSocket::AuthCertificateHook(void* arg
, PRFileDesc
* fd
,
123 // Allow any client cert here, server consumer code can decide whether it's
124 // okay after being notified of the new client socket.
128 //-----------------------------------------------------------------------------
129 // TLSServerSocket::nsITLSServerSocket
130 //-----------------------------------------------------------------------------
133 TLSServerSocket::GetServerCert(nsIX509Cert
** aCert
) {
134 if (NS_WARN_IF(!aCert
)) {
135 return NS_ERROR_INVALID_POINTER
;
137 *aCert
= do_AddRef(mServerCert
).take();
142 TLSServerSocket::SetServerCert(nsIX509Cert
* aCert
) {
143 // If AsyncListen was already called (and set mListener), it's too late to set
145 if (NS_WARN_IF(mListener
)) {
146 return NS_ERROR_IN_PROGRESS
;
153 TLSServerSocket::SetSessionTickets(bool aEnabled
) {
154 // If AsyncListen was already called (and set mListener), it's too late to set
156 if (NS_WARN_IF(mListener
)) {
157 return NS_ERROR_IN_PROGRESS
;
159 SSL_OptionSet(mFD
, SSL_ENABLE_SESSION_TICKETS
, aEnabled
);
164 TLSServerSocket::SetRequestClientCertificate(uint32_t aMode
) {
165 // If AsyncListen was already called (and set mListener), it's too late to set
167 if (NS_WARN_IF(mListener
)) {
168 return NS_ERROR_IN_PROGRESS
;
170 SSL_OptionSet(mFD
, SSL_REQUEST_CERTIFICATE
, aMode
!= REQUEST_NEVER
);
174 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_NO_ERROR
);
176 case REQUIRE_FIRST_HANDSHAKE
:
177 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_FIRST_HANDSHAKE
);
180 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_ALWAYS
);
183 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_NEVER
);
189 TLSServerSocket::SetVersionRange(uint16_t aMinVersion
, uint16_t aMaxVersion
) {
190 // If AsyncListen was already called (and set mListener), it's too late to set
192 if (NS_WARN_IF(mListener
)) {
193 return NS_ERROR_IN_PROGRESS
;
196 SSLVersionRange range
= {aMinVersion
, aMaxVersion
};
197 if (SSL_VersionRangeSet(mFD
, &range
) != SECSuccess
) {
198 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
204 //-----------------------------------------------------------------------------
205 // TLSServerConnectionInfo
206 //-----------------------------------------------------------------------------
210 class TLSServerSecurityObserverProxy final
211 : public nsITLSServerSecurityObserver
{
212 ~TLSServerSecurityObserverProxy() = default;
215 explicit TLSServerSecurityObserverProxy(
216 nsITLSServerSecurityObserver
* aListener
)
217 : mListener(new nsMainThreadPtrHolder
<nsITLSServerSecurityObserver
>(
218 "TLSServerSecurityObserverProxy::mListener", aListener
)) {}
220 NS_DECL_THREADSAFE_ISUPPORTS
221 NS_DECL_NSITLSSERVERSECURITYOBSERVER
223 class OnHandshakeDoneRunnable
: public Runnable
{
225 OnHandshakeDoneRunnable(
226 const nsMainThreadPtrHandle
<nsITLSServerSecurityObserver
>& aListener
,
227 nsITLSServerSocket
* aServer
, nsITLSClientStatus
* aStatus
)
229 "net::TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable"),
230 mListener(aListener
),
237 nsMainThreadPtrHandle
<nsITLSServerSecurityObserver
> mListener
;
238 nsCOMPtr
<nsITLSServerSocket
> mServer
;
239 nsCOMPtr
<nsITLSClientStatus
> mStatus
;
243 nsMainThreadPtrHandle
<nsITLSServerSecurityObserver
> mListener
;
246 NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy
, nsITLSServerSecurityObserver
)
249 TLSServerSecurityObserverProxy::OnHandshakeDone(nsITLSServerSocket
* aServer
,
250 nsITLSClientStatus
* aStatus
) {
251 RefPtr
<OnHandshakeDoneRunnable
> r
=
252 new OnHandshakeDoneRunnable(mListener
, aServer
, aStatus
);
253 return NS_DispatchToMainThread(r
);
257 TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable::Run() {
258 mListener
->OnHandshakeDone(mServer
, mStatus
);
264 NS_IMPL_ISUPPORTS(TLSServerConnectionInfo
, nsITLSServerConnectionInfo
,
265 nsITLSClientStatus
, nsIInterfaceRequestor
)
267 TLSServerConnectionInfo::~TLSServerConnectionInfo() {
268 RefPtr
<nsITLSServerSecurityObserver
> observer
;
270 MutexAutoLock
lock(mLock
);
271 observer
= ToRefPtr(std::move(mSecurityObserver
));
275 NS_ReleaseOnMainThread("TLSServerConnectionInfo::mSecurityObserver",
281 TLSServerConnectionInfo::SetSecurityObserver(
282 nsITLSServerSecurityObserver
* aObserver
) {
284 MutexAutoLock
lock(mLock
);
286 mSecurityObserver
= nullptr;
290 mSecurityObserver
= new TLSServerSecurityObserverProxy(aObserver
);
291 // Call `OnHandshakeDone` if TLS handshake is already completed.
292 if (mTlsVersionUsed
!= TLS_VERSION_UNKNOWN
) {
293 nsCOMPtr
<nsITLSServerSocket
> serverSocket
;
294 GetServerSocket(getter_AddRefs(serverSocket
));
295 mSecurityObserver
->OnHandshakeDone(serverSocket
, this);
296 mSecurityObserver
= nullptr;
303 TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket
** aSocket
) {
304 if (NS_WARN_IF(!aSocket
)) {
305 return NS_ERROR_INVALID_POINTER
;
307 *aSocket
= do_AddRef(mServerSocket
).take();
312 TLSServerConnectionInfo::GetStatus(nsITLSClientStatus
** aStatus
) {
313 if (NS_WARN_IF(!aStatus
)) {
314 return NS_ERROR_INVALID_POINTER
;
316 *aStatus
= do_AddRef(this).take();
321 TLSServerConnectionInfo::GetPeerCert(nsIX509Cert
** aCert
) {
322 if (NS_WARN_IF(!aCert
)) {
323 return NS_ERROR_INVALID_POINTER
;
325 *aCert
= do_AddRef(mPeerCert
).take();
330 TLSServerConnectionInfo::GetTlsVersionUsed(int16_t* aTlsVersionUsed
) {
331 if (NS_WARN_IF(!aTlsVersionUsed
)) {
332 return NS_ERROR_INVALID_POINTER
;
334 *aTlsVersionUsed
= mTlsVersionUsed
;
339 TLSServerConnectionInfo::GetCipherName(nsACString
& aCipherName
) {
340 aCipherName
.Assign(mCipherName
);
345 TLSServerConnectionInfo::GetKeyLength(uint32_t* aKeyLength
) {
346 if (NS_WARN_IF(!aKeyLength
)) {
347 return NS_ERROR_INVALID_POINTER
;
349 *aKeyLength
= mKeyLength
;
354 TLSServerConnectionInfo::GetMacLength(uint32_t* aMacLength
) {
355 if (NS_WARN_IF(!aMacLength
)) {
356 return NS_ERROR_INVALID_POINTER
;
358 *aMacLength
= mMacLength
;
363 TLSServerConnectionInfo::GetInterface(const nsIID
& aIID
, void** aResult
) {
364 NS_ENSURE_ARG_POINTER(aResult
);
367 if (aIID
.Equals(NS_GET_IID(nsITLSServerConnectionInfo
))) {
368 *aResult
= static_cast<nsITLSServerConnectionInfo
*>(this);
373 return NS_NOINTERFACE
;
377 void TLSServerConnectionInfo::HandshakeCallback(PRFileDesc
* aFD
, void* aArg
) {
378 RefPtr
<TLSServerConnectionInfo
> info
=
379 static_cast<TLSServerConnectionInfo
*>(aArg
);
380 nsISocketTransport
* transport
= info
->mTransport
;
381 // No longer needed outside this function, so clear the weak ref
382 info
->mTransport
= nullptr;
383 nsresult rv
= info
->HandshakeCallback(aFD
);
384 if (NS_WARN_IF(NS_FAILED(rv
))) {
385 transport
->Close(rv
);
389 nsresult
TLSServerConnectionInfo::HandshakeCallback(PRFileDesc
* aFD
) {
392 UniqueCERTCertificate
clientCert(SSL_PeerCertificate(aFD
));
394 nsCOMPtr
<nsIX509CertDB
> certDB
=
395 do_GetService(NS_X509CERTDB_CONTRACTID
, &rv
);
400 nsCOMPtr
<nsIX509Cert
> clientCertPSM
;
401 nsTArray
<uint8_t> clientCertBytes
;
402 clientCertBytes
.AppendElements(clientCert
->derCert
.data
,
403 clientCert
->derCert
.len
);
404 rv
= certDB
->ConstructX509(clientCertBytes
, getter_AddRefs(clientCertPSM
));
409 mPeerCert
= clientCertPSM
;
412 SSLChannelInfo channelInfo
;
413 rv
= MapSECStatus(SSL_GetChannelInfo(aFD
, &channelInfo
, sizeof(channelInfo
)));
418 SSLCipherSuiteInfo cipherInfo
;
419 rv
= MapSECStatus(SSL_GetCipherSuiteInfo(channelInfo
.cipherSuite
, &cipherInfo
,
420 sizeof(cipherInfo
)));
424 mCipherName
.Assign(cipherInfo
.cipherSuiteName
);
425 mKeyLength
= cipherInfo
.effectiveKeyBits
;
426 mMacLength
= cipherInfo
.macBits
;
428 // Notify consumer code that handshake is complete
429 nsCOMPtr
<nsITLSServerSecurityObserver
> observer
;
431 MutexAutoLock
lock(mLock
);
432 mTlsVersionUsed
= channelInfo
.protocolVersion
;
433 if (!mSecurityObserver
) {
436 mSecurityObserver
.swap(observer
);
438 nsCOMPtr
<nsITLSServerSocket
> serverSocket
;
439 GetServerSocket(getter_AddRefs(serverSocket
));
440 observer
->OnHandshakeDone(serverSocket
, this);
446 } // namespace mozilla