LCOV - code coverage report
Current view: top level - netwerk/base - TLSServerSocket.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 215 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 43 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13