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 "mozilla/Components.h"
10 #include "nsComponentManagerUtils.h"
11 #include "nsDependentSubstring.h"
12 #include "nsIServerSocket.h"
13 #include "nsIX509Cert.h"
14 #include "nsIX509CertDB.h"
16 #include "nsProxyRelease.h"
17 #include "nsServiceManagerUtils.h"
18 #include "nsSocketTransport2.h"
19 #include "nsThreadUtils.h"
20 #include "ScopedNSSTypes.h"
26 //-----------------------------------------------------------------------------
28 //-----------------------------------------------------------------------------
30 NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket
, nsServerSocket
, nsITLSServerSocket
)
32 nsresult
TLSServerSocket::SetSocketDefaults() {
33 // Set TLS options on the listening socket
34 mFD
= SSL_ImportFD(nullptr, mFD
);
35 if (NS_WARN_IF(!mFD
)) {
36 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
39 SSL_OptionSet(mFD
, SSL_SECURITY
, true);
40 SSL_OptionSet(mFD
, SSL_HANDSHAKE_AS_CLIENT
, false);
41 SSL_OptionSet(mFD
, SSL_HANDSHAKE_AS_SERVER
, true);
42 SSL_OptionSet(mFD
, SSL_NO_CACHE
, true);
44 // We don't currently notify the server API consumer of renegotiation events
45 // (to revalidate peer certs, etc.), so disable it for now.
46 SSL_OptionSet(mFD
, SSL_ENABLE_RENEGOTIATION
, SSL_RENEGOTIATE_NEVER
);
48 SetSessionTickets(true);
49 SetRequestClientCertificate(REQUEST_NEVER
);
54 void TLSServerSocket::CreateClientTransport(PRFileDesc
* aClientFD
,
55 const NetAddr
& aClientAddr
) {
56 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
59 RefPtr
<nsSocketTransport
> trans
= new nsSocketTransport
;
60 if (NS_WARN_IF(!trans
)) {
61 mCondition
= NS_ERROR_OUT_OF_MEMORY
;
65 RefPtr
<TLSServerConnectionInfo
> info
= new TLSServerConnectionInfo();
66 info
->mServerSocket
= this;
67 info
->mTransport
= trans
;
68 nsCOMPtr
<nsIInterfaceRequestor
> infoInterfaceRequestor(info
);
69 rv
= trans
->InitWithConnectedSocket(aClientFD
, &aClientAddr
,
70 infoInterfaceRequestor
);
71 if (NS_WARN_IF(NS_FAILED(rv
))) {
76 // Override the default peer certificate validation, so that server consumers
77 // can make their own choice after the handshake completes.
78 SSL_AuthCertificateHook(aClientFD
, AuthCertificateHook
, nullptr);
79 // Once the TLS handshake has completed, the server consumer is notified and
80 // has access to various TLS state details.
81 // It's safe to pass info here because the socket transport holds it as
82 // |mSecInfo| which keeps it alive for the lifetime of the socket.
83 SSL_HandshakeCallback(aClientFD
, TLSServerConnectionInfo::HandshakeCallback
,
86 // Notify the consumer of the new client so it can manage the streams.
87 // Security details aren't known yet. The security observer will be notified
88 // later when they are ready.
89 nsCOMPtr
<nsIServerSocket
> serverSocket
=
90 do_QueryInterface(NS_ISUPPORTS_CAST(nsITLSServerSocket
*, this));
91 mListener
->OnSocketAccepted(serverSocket
, trans
);
94 nsresult
TLSServerSocket::OnSocketListen() {
95 if (NS_WARN_IF(!mServerCert
)) {
96 return NS_ERROR_NOT_INITIALIZED
;
99 UniqueCERTCertificate
cert(mServerCert
->GetCert());
100 if (NS_WARN_IF(!cert
)) {
101 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
104 UniqueSECKEYPrivateKey
key(PK11_FindKeyByAnyCert(cert
.get(), nullptr));
105 if (NS_WARN_IF(!key
)) {
106 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
109 SSLKEAType certKEA
= NSS_FindCertKEAType(cert
.get());
112 MapSECStatus(SSL_ConfigSecureServer(mFD
, cert
.get(), key
.get(), certKEA
));
113 if (NS_WARN_IF(NS_FAILED(rv
))) {
121 SECStatus
TLSServerSocket::AuthCertificateHook(void* arg
, PRFileDesc
* fd
,
124 // Allow any client cert here, server consumer code can decide whether it's
125 // okay after being notified of the new client socket.
129 //-----------------------------------------------------------------------------
130 // TLSServerSocket::nsITLSServerSocket
131 //-----------------------------------------------------------------------------
134 TLSServerSocket::GetServerCert(nsIX509Cert
** aCert
) {
135 if (NS_WARN_IF(!aCert
)) {
136 return NS_ERROR_INVALID_POINTER
;
138 *aCert
= do_AddRef(mServerCert
).take();
143 TLSServerSocket::SetServerCert(nsIX509Cert
* aCert
) {
144 // If AsyncListen was already called (and set mListener), it's too late to set
146 if (NS_WARN_IF(mListener
)) {
147 return NS_ERROR_IN_PROGRESS
;
154 TLSServerSocket::SetSessionTickets(bool aEnabled
) {
155 // If AsyncListen was already called (and set mListener), it's too late to set
157 if (NS_WARN_IF(mListener
)) {
158 return NS_ERROR_IN_PROGRESS
;
160 SSL_OptionSet(mFD
, SSL_ENABLE_SESSION_TICKETS
, aEnabled
);
165 TLSServerSocket::SetRequestClientCertificate(uint32_t aMode
) {
166 // If AsyncListen was already called (and set mListener), it's too late to set
168 if (NS_WARN_IF(mListener
)) {
169 return NS_ERROR_IN_PROGRESS
;
171 SSL_OptionSet(mFD
, SSL_REQUEST_CERTIFICATE
, aMode
!= REQUEST_NEVER
);
175 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_NO_ERROR
);
177 case REQUIRE_FIRST_HANDSHAKE
:
178 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_FIRST_HANDSHAKE
);
181 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_ALWAYS
);
184 SSL_OptionSet(mFD
, SSL_REQUIRE_CERTIFICATE
, SSL_REQUIRE_NEVER
);
190 TLSServerSocket::SetVersionRange(uint16_t aMinVersion
, uint16_t aMaxVersion
) {
191 // If AsyncListen was already called (and set mListener), it's too late to set
193 if (NS_WARN_IF(mListener
)) {
194 return NS_ERROR_IN_PROGRESS
;
197 SSLVersionRange range
= {aMinVersion
, aMaxVersion
};
198 if (SSL_VersionRangeSet(mFD
, &range
) != SECSuccess
) {
199 return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
205 //-----------------------------------------------------------------------------
206 // TLSServerConnectionInfo
207 //-----------------------------------------------------------------------------
211 class TLSServerSecurityObserverProxy final
212 : public nsITLSServerSecurityObserver
{
213 ~TLSServerSecurityObserverProxy() = default;
216 explicit TLSServerSecurityObserverProxy(
217 nsITLSServerSecurityObserver
* aListener
)
218 : mListener(new nsMainThreadPtrHolder
<nsITLSServerSecurityObserver
>(
219 "TLSServerSecurityObserverProxy::mListener", aListener
)) {}
221 NS_DECL_THREADSAFE_ISUPPORTS
222 NS_DECL_NSITLSSERVERSECURITYOBSERVER
224 class OnHandshakeDoneRunnable
: public Runnable
{
226 OnHandshakeDoneRunnable(
227 const nsMainThreadPtrHandle
<nsITLSServerSecurityObserver
>& aListener
,
228 nsITLSServerSocket
* aServer
, nsITLSClientStatus
* aStatus
)
230 "net::TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable"),
231 mListener(aListener
),
238 nsMainThreadPtrHandle
<nsITLSServerSecurityObserver
> mListener
;
239 nsCOMPtr
<nsITLSServerSocket
> mServer
;
240 nsCOMPtr
<nsITLSClientStatus
> mStatus
;
244 nsMainThreadPtrHandle
<nsITLSServerSecurityObserver
> mListener
;
247 NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy
, nsITLSServerSecurityObserver
)
250 TLSServerSecurityObserverProxy::OnHandshakeDone(nsITLSServerSocket
* aServer
,
251 nsITLSClientStatus
* aStatus
) {
252 RefPtr
<OnHandshakeDoneRunnable
> r
=
253 new OnHandshakeDoneRunnable(mListener
, aServer
, aStatus
);
254 return NS_DispatchToMainThread(r
);
258 TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable::Run() {
259 mListener
->OnHandshakeDone(mServer
, mStatus
);
265 NS_IMPL_ISUPPORTS(TLSServerConnectionInfo
, nsITLSServerConnectionInfo
,
266 nsITLSClientStatus
, nsIInterfaceRequestor
)
268 TLSServerConnectionInfo::~TLSServerConnectionInfo() {
269 RefPtr
<nsITLSServerSecurityObserver
> observer
;
271 MutexAutoLock
lock(mLock
);
272 observer
= ToRefPtr(std::move(mSecurityObserver
));
276 NS_ReleaseOnMainThread("TLSServerConnectionInfo::mSecurityObserver",
282 TLSServerConnectionInfo::SetSecurityObserver(
283 nsITLSServerSecurityObserver
* aObserver
) {
285 MutexAutoLock
lock(mLock
);
287 mSecurityObserver
= nullptr;
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;
304 TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket
** aSocket
) {
305 if (NS_WARN_IF(!aSocket
)) {
306 return NS_ERROR_INVALID_POINTER
;
308 *aSocket
= do_AddRef(mServerSocket
).take();
313 TLSServerConnectionInfo::GetStatus(nsITLSClientStatus
** aStatus
) {
314 if (NS_WARN_IF(!aStatus
)) {
315 return NS_ERROR_INVALID_POINTER
;
317 *aStatus
= do_AddRef(this).take();
322 TLSServerConnectionInfo::GetPeerCert(nsIX509Cert
** aCert
) {
323 if (NS_WARN_IF(!aCert
)) {
324 return NS_ERROR_INVALID_POINTER
;
326 *aCert
= do_AddRef(mPeerCert
).take();
331 TLSServerConnectionInfo::GetTlsVersionUsed(int16_t* aTlsVersionUsed
) {
332 if (NS_WARN_IF(!aTlsVersionUsed
)) {
333 return NS_ERROR_INVALID_POINTER
;
335 *aTlsVersionUsed
= mTlsVersionUsed
;
340 TLSServerConnectionInfo::GetCipherName(nsACString
& aCipherName
) {
341 aCipherName
.Assign(mCipherName
);
346 TLSServerConnectionInfo::GetKeyLength(uint32_t* aKeyLength
) {
347 if (NS_WARN_IF(!aKeyLength
)) {
348 return NS_ERROR_INVALID_POINTER
;
350 *aKeyLength
= mKeyLength
;
355 TLSServerConnectionInfo::GetMacLength(uint32_t* aMacLength
) {
356 if (NS_WARN_IF(!aMacLength
)) {
357 return NS_ERROR_INVALID_POINTER
;
359 *aMacLength
= mMacLength
;
364 TLSServerConnectionInfo::GetInterface(const nsIID
& aIID
, void** aResult
) {
365 NS_ENSURE_ARG_POINTER(aResult
);
368 if (aIID
.Equals(NS_GET_IID(nsITLSServerConnectionInfo
))) {
369 *aResult
= static_cast<nsITLSServerConnectionInfo
*>(this);
374 return NS_NOINTERFACE
;
378 void TLSServerConnectionInfo::HandshakeCallback(PRFileDesc
* aFD
, void* aArg
) {
379 RefPtr
<TLSServerConnectionInfo
> info
=
380 static_cast<TLSServerConnectionInfo
*>(aArg
);
381 nsISocketTransport
* transport
= info
->mTransport
;
382 // No longer needed outside this function, so clear the weak ref
383 info
->mTransport
= nullptr;
384 nsresult rv
= info
->HandshakeCallback(aFD
);
385 if (NS_WARN_IF(NS_FAILED(rv
))) {
386 transport
->Close(rv
);
390 nsresult
TLSServerConnectionInfo::HandshakeCallback(PRFileDesc
* aFD
) {
393 UniqueCERTCertificate
clientCert(SSL_PeerCertificate(aFD
));
395 nsCOMPtr
<nsIX509CertDB
> certDB
;
396 certDB
= mozilla::components::NSSCertificateDB::Service(&rv
);
401 nsCOMPtr
<nsIX509Cert
> clientCertPSM
;
402 nsTArray
<uint8_t> clientCertBytes
;
403 clientCertBytes
.AppendElements(clientCert
->derCert
.data
,
404 clientCert
->derCert
.len
);
405 rv
= certDB
->ConstructX509(clientCertBytes
, getter_AddRefs(clientCertPSM
));
410 mPeerCert
= clientCertPSM
;
413 SSLChannelInfo channelInfo
;
414 rv
= MapSECStatus(SSL_GetChannelInfo(aFD
, &channelInfo
, sizeof(channelInfo
)));
419 SSLCipherSuiteInfo cipherInfo
;
420 rv
= MapSECStatus(SSL_GetCipherSuiteInfo(channelInfo
.cipherSuite
, &cipherInfo
,
421 sizeof(cipherInfo
)));
425 mCipherName
.Assign(cipherInfo
.cipherSuiteName
);
426 mKeyLength
= cipherInfo
.effectiveKeyBits
;
427 mMacLength
= cipherInfo
.macBits
;
429 // Notify consumer code that handshake is complete
430 nsCOMPtr
<nsITLSServerSecurityObserver
> observer
;
432 MutexAutoLock
lock(mLock
);
433 mTlsVersionUsed
= channelInfo
.protocolVersion
;
434 if (!mSecurityObserver
) {
437 mSecurityObserver
.swap(observer
);
439 nsCOMPtr
<nsITLSServerSocket
> serverSocket
;
440 GetServerSocket(getter_AddRefs(serverSocket
));
441 observer
->OnHandshakeDone(serverSocket
, this);
447 } // namespace mozilla