tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TLSServerSocket.cpp (13513B)


      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 "mozilla/Components.h"
     10 #include "nsComponentManagerUtils.h"
     11 #include "nsDependentSubstring.h"
     12 #include "nsIServerSocket.h"
     13 #include "nsIX509Cert.h"
     14 #include "nsIX509CertDB.h"
     15 #include "nsNetCID.h"
     16 #include "nsProxyRelease.h"
     17 #include "nsServiceManagerUtils.h"
     18 #include "nsSocketTransport2.h"
     19 #include "nsThreadUtils.h"
     20 #include "ScopedNSSTypes.h"
     21 #include "ssl.h"
     22 
     23 namespace mozilla {
     24 namespace net {
     25 
     26 //-----------------------------------------------------------------------------
     27 // TLSServerSocket
     28 //-----------------------------------------------------------------------------
     29 
     30 NS_IMPL_ISUPPORTS_INHERITED(TLSServerSocket, nsServerSocket, nsITLSServerSocket)
     31 
     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());
     37  }
     38 
     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);
     43 
     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);
     47 
     48  SetSessionTickets(true);
     49  SetRequestClientCertificate(REQUEST_NEVER);
     50 
     51  return NS_OK;
     52 }
     53 
     54 void TLSServerSocket::CreateClientTransport(PRFileDesc* aClientFD,
     55                                            const NetAddr& aClientAddr) {
     56  MOZ_ASSERT(OnSocketThread(), "not on socket thread");
     57  nsresult rv;
     58 
     59  RefPtr<nsSocketTransport> trans = new nsSocketTransport;
     60  if (NS_WARN_IF(!trans)) {
     61    mCondition = NS_ERROR_OUT_OF_MEMORY;
     62    return;
     63  }
     64 
     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))) {
     72    mCondition = rv;
     73    return;
     74  }
     75 
     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,
     84                        info);
     85 
     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);
     92 }
     93 
     94 nsresult TLSServerSocket::OnSocketListen() {
     95  if (NS_WARN_IF(!mServerCert)) {
     96    return NS_ERROR_NOT_INITIALIZED;
     97  }
     98 
     99  UniqueCERTCertificate cert(mServerCert->GetCert());
    100  if (NS_WARN_IF(!cert)) {
    101    return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    102  }
    103 
    104  UniqueSECKEYPrivateKey key(PK11_FindKeyByAnyCert(cert.get(), nullptr));
    105  if (NS_WARN_IF(!key)) {
    106    return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    107  }
    108 
    109  SSLKEAType certKEA = NSS_FindCertKEAType(cert.get());
    110 
    111  nsresult rv =
    112      MapSECStatus(SSL_ConfigSecureServer(mFD, cert.get(), key.get(), certKEA));
    113  if (NS_WARN_IF(NS_FAILED(rv))) {
    114    return rv;
    115  }
    116 
    117  return NS_OK;
    118 }
    119 
    120 // static
    121 SECStatus TLSServerSocket::AuthCertificateHook(void* arg, PRFileDesc* fd,
    122                                               PRBool checksig,
    123                                               PRBool isServer) {
    124  // Allow any client cert here, server consumer code can decide whether it's
    125  // okay after being notified of the new client socket.
    126  return SECSuccess;
    127 }
    128 
    129 //-----------------------------------------------------------------------------
    130 // TLSServerSocket::nsITLSServerSocket
    131 //-----------------------------------------------------------------------------
    132 
    133 NS_IMETHODIMP
    134 TLSServerSocket::GetServerCert(nsIX509Cert** aCert) {
    135  if (NS_WARN_IF(!aCert)) {
    136    return NS_ERROR_INVALID_POINTER;
    137  }
    138  *aCert = do_AddRef(mServerCert).take();
    139  return NS_OK;
    140 }
    141 
    142 NS_IMETHODIMP
    143 TLSServerSocket::SetServerCert(nsIX509Cert* aCert) {
    144  // If AsyncListen was already called (and set mListener), it's too late to set
    145  // this.
    146  if (NS_WARN_IF(mListener)) {
    147    return NS_ERROR_IN_PROGRESS;
    148  }
    149  mServerCert = aCert;
    150  return NS_OK;
    151 }
    152 
    153 NS_IMETHODIMP
    154 TLSServerSocket::SetSessionTickets(bool aEnabled) {
    155  // If AsyncListen was already called (and set mListener), it's too late to set
    156  // this.
    157  if (NS_WARN_IF(mListener)) {
    158    return NS_ERROR_IN_PROGRESS;
    159  }
    160  SSL_OptionSet(mFD, SSL_ENABLE_SESSION_TICKETS, aEnabled);
    161  return NS_OK;
    162 }
    163 
    164 NS_IMETHODIMP
    165 TLSServerSocket::SetRequestClientCertificate(uint32_t aMode) {
    166  // If AsyncListen was already called (and set mListener), it's too late to set
    167  // this.
    168  if (NS_WARN_IF(mListener)) {
    169    return NS_ERROR_IN_PROGRESS;
    170  }
    171  SSL_OptionSet(mFD, SSL_REQUEST_CERTIFICATE, aMode != REQUEST_NEVER);
    172 
    173  switch (aMode) {
    174    case REQUEST_ALWAYS:
    175      SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NO_ERROR);
    176      break;
    177    case REQUIRE_FIRST_HANDSHAKE:
    178      SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_FIRST_HANDSHAKE);
    179      break;
    180    case REQUIRE_ALWAYS:
    181      SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_ALWAYS);
    182      break;
    183    default:
    184      SSL_OptionSet(mFD, SSL_REQUIRE_CERTIFICATE, SSL_REQUIRE_NEVER);
    185  }
    186  return NS_OK;
    187 }
    188 
    189 NS_IMETHODIMP
    190 TLSServerSocket::SetVersionRange(uint16_t aMinVersion, uint16_t aMaxVersion) {
    191  // If AsyncListen was already called (and set mListener), it's too late to set
    192  // this.
    193  if (NS_WARN_IF(mListener)) {
    194    return NS_ERROR_IN_PROGRESS;
    195  }
    196 
    197  SSLVersionRange range = {aMinVersion, aMaxVersion};
    198  if (SSL_VersionRangeSet(mFD, &range) != SECSuccess) {
    199    return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
    200  }
    201 
    202  return NS_OK;
    203 }
    204 
    205 //-----------------------------------------------------------------------------
    206 // TLSServerConnectionInfo
    207 //-----------------------------------------------------------------------------
    208 
    209 namespace {
    210 
    211 class TLSServerSecurityObserverProxy final
    212    : public nsITLSServerSecurityObserver {
    213  ~TLSServerSecurityObserverProxy() = default;
    214 
    215 public:
    216  explicit TLSServerSecurityObserverProxy(
    217      nsITLSServerSecurityObserver* aListener)
    218      : mListener(new nsMainThreadPtrHolder<nsITLSServerSecurityObserver>(
    219            "TLSServerSecurityObserverProxy::mListener", aListener)) {}
    220 
    221  NS_DECL_THREADSAFE_ISUPPORTS
    222  NS_DECL_NSITLSSERVERSECURITYOBSERVER
    223 
    224  class OnHandshakeDoneRunnable : public Runnable {
    225   public:
    226    OnHandshakeDoneRunnable(
    227        const nsMainThreadPtrHandle<nsITLSServerSecurityObserver>& aListener,
    228        nsITLSServerSocket* aServer, nsITLSClientStatus* aStatus)
    229        : Runnable(
    230              "net::TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable"),
    231          mListener(aListener),
    232          mServer(aServer),
    233          mStatus(aStatus) {}
    234 
    235    NS_DECL_NSIRUNNABLE
    236 
    237   private:
    238    nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
    239    nsCOMPtr<nsITLSServerSocket> mServer;
    240    nsCOMPtr<nsITLSClientStatus> mStatus;
    241  };
    242 
    243 private:
    244  nsMainThreadPtrHandle<nsITLSServerSecurityObserver> mListener;
    245 };
    246 
    247 NS_IMPL_ISUPPORTS(TLSServerSecurityObserverProxy, nsITLSServerSecurityObserver)
    248 
    249 NS_IMETHODIMP
    250 TLSServerSecurityObserverProxy::OnHandshakeDone(nsITLSServerSocket* aServer,
    251                                                nsITLSClientStatus* aStatus) {
    252  RefPtr<OnHandshakeDoneRunnable> r =
    253      new OnHandshakeDoneRunnable(mListener, aServer, aStatus);
    254  return NS_DispatchToMainThread(r);
    255 }
    256 
    257 NS_IMETHODIMP
    258 TLSServerSecurityObserverProxy::OnHandshakeDoneRunnable::Run() {
    259  mListener->OnHandshakeDone(mServer, mStatus);
    260  return NS_OK;
    261 }
    262 
    263 }  // namespace
    264 
    265 NS_IMPL_ISUPPORTS(TLSServerConnectionInfo, nsITLSServerConnectionInfo,
    266                  nsITLSClientStatus, nsIInterfaceRequestor)
    267 
    268 TLSServerConnectionInfo::~TLSServerConnectionInfo() {
    269  RefPtr<nsITLSServerSecurityObserver> observer;
    270  {
    271    MutexAutoLock lock(mLock);
    272    observer = ToRefPtr(std::move(mSecurityObserver));
    273  }
    274 
    275  if (observer) {
    276    NS_ReleaseOnMainThread("TLSServerConnectionInfo::mSecurityObserver",
    277                           observer.forget());
    278  }
    279 }
    280 
    281 NS_IMETHODIMP
    282 TLSServerConnectionInfo::SetSecurityObserver(
    283    nsITLSServerSecurityObserver* aObserver) {
    284  {
    285    MutexAutoLock lock(mLock);
    286    if (!aObserver) {
    287      mSecurityObserver = nullptr;
    288      return NS_OK;
    289    }
    290 
    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;
    298    }
    299  }
    300  return NS_OK;
    301 }
    302 
    303 NS_IMETHODIMP
    304 TLSServerConnectionInfo::GetServerSocket(nsITLSServerSocket** aSocket) {
    305  if (NS_WARN_IF(!aSocket)) {
    306    return NS_ERROR_INVALID_POINTER;
    307  }
    308  *aSocket = do_AddRef(mServerSocket).take();
    309  return NS_OK;
    310 }
    311 
    312 NS_IMETHODIMP
    313 TLSServerConnectionInfo::GetStatus(nsITLSClientStatus** aStatus) {
    314  if (NS_WARN_IF(!aStatus)) {
    315    return NS_ERROR_INVALID_POINTER;
    316  }
    317  *aStatus = do_AddRef(this).take();
    318  return NS_OK;
    319 }
    320 
    321 NS_IMETHODIMP
    322 TLSServerConnectionInfo::GetPeerCert(nsIX509Cert** aCert) {
    323  if (NS_WARN_IF(!aCert)) {
    324    return NS_ERROR_INVALID_POINTER;
    325  }
    326  *aCert = do_AddRef(mPeerCert).take();
    327  return NS_OK;
    328 }
    329 
    330 NS_IMETHODIMP
    331 TLSServerConnectionInfo::GetTlsVersionUsed(int16_t* aTlsVersionUsed) {
    332  if (NS_WARN_IF(!aTlsVersionUsed)) {
    333    return NS_ERROR_INVALID_POINTER;
    334  }
    335  *aTlsVersionUsed = mTlsVersionUsed;
    336  return NS_OK;
    337 }
    338 
    339 NS_IMETHODIMP
    340 TLSServerConnectionInfo::GetCipherName(nsACString& aCipherName) {
    341  aCipherName.Assign(mCipherName);
    342  return NS_OK;
    343 }
    344 
    345 NS_IMETHODIMP
    346 TLSServerConnectionInfo::GetKeyLength(uint32_t* aKeyLength) {
    347  if (NS_WARN_IF(!aKeyLength)) {
    348    return NS_ERROR_INVALID_POINTER;
    349  }
    350  *aKeyLength = mKeyLength;
    351  return NS_OK;
    352 }
    353 
    354 NS_IMETHODIMP
    355 TLSServerConnectionInfo::GetMacLength(uint32_t* aMacLength) {
    356  if (NS_WARN_IF(!aMacLength)) {
    357    return NS_ERROR_INVALID_POINTER;
    358  }
    359  *aMacLength = mMacLength;
    360  return NS_OK;
    361 }
    362 
    363 NS_IMETHODIMP
    364 TLSServerConnectionInfo::GetInterface(const nsIID& aIID, void** aResult) {
    365  NS_ENSURE_ARG_POINTER(aResult);
    366  *aResult = nullptr;
    367 
    368  if (aIID.Equals(NS_GET_IID(nsITLSServerConnectionInfo))) {
    369    *aResult = static_cast<nsITLSServerConnectionInfo*>(this);
    370    NS_ADDREF_THIS();
    371    return NS_OK;
    372  }
    373 
    374  return NS_NOINTERFACE;
    375 }
    376 
    377 // static
    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);
    387  }
    388 }
    389 
    390 nsresult TLSServerConnectionInfo::HandshakeCallback(PRFileDesc* aFD) {
    391  nsresult rv;
    392 
    393  UniqueCERTCertificate clientCert(SSL_PeerCertificate(aFD));
    394  if (clientCert) {
    395    nsCOMPtr<nsIX509CertDB> certDB;
    396    certDB = mozilla::components::NSSCertificateDB::Service(&rv);
    397    if (NS_FAILED(rv)) {
    398      return rv;
    399    }
    400 
    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));
    406    if (NS_FAILED(rv)) {
    407      return rv;
    408    }
    409 
    410    mPeerCert = clientCertPSM;
    411  }
    412 
    413  SSLChannelInfo channelInfo;
    414  rv = MapSECStatus(SSL_GetChannelInfo(aFD, &channelInfo, sizeof(channelInfo)));
    415  if (NS_FAILED(rv)) {
    416    return rv;
    417  }
    418 
    419  SSLCipherSuiteInfo cipherInfo;
    420  rv = MapSECStatus(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
    421                                           sizeof(cipherInfo)));
    422  if (NS_FAILED(rv)) {
    423    return rv;
    424  }
    425  mCipherName.Assign(cipherInfo.cipherSuiteName);
    426  mKeyLength = cipherInfo.effectiveKeyBits;
    427  mMacLength = cipherInfo.macBits;
    428 
    429  // Notify consumer code that handshake is complete
    430  nsCOMPtr<nsITLSServerSecurityObserver> observer;
    431  {
    432    MutexAutoLock lock(mLock);
    433    mTlsVersionUsed = channelInfo.protocolVersion;
    434    if (!mSecurityObserver) {
    435      return NS_OK;
    436    }
    437    mSecurityObserver.swap(observer);
    438  }
    439  nsCOMPtr<nsITLSServerSocket> serverSocket;
    440  GetServerSocket(getter_AddRefs(serverSocket));
    441  observer->OnHandshakeDone(serverSocket, this);
    442 
    443  return NS_OK;
    444 }
    445 
    446 }  // namespace net
    447 }  // namespace mozilla