tor-browser

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

DelegatedCredentialsServer.cpp (4998B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // This is a standalone server used to test Delegated Credentials
      6 // (see: https://tools.ietf.org/html/draft-ietf-tls-subcerts-03).
      7 //
      8 // The client is expected to connect, initiate an SSL handshake (with SNI
      9 // to indicate which "server" to connect to), and verify the certificate.
     10 // If all is good, the client then sends one encrypted byte and receives that
     11 // same byte back.
     12 // This server also has the ability to "call back" another process waiting on
     13 // it. That is, when the server is all set up and ready to receive connections,
     14 // it will connect to a specified port and issue a simple HTTP request.
     15 
     16 #include <iostream>
     17 
     18 #include "TLSServer.h"
     19 
     20 #include "sslexp.h"
     21 
     22 using namespace mozilla;
     23 using namespace mozilla::test;
     24 
     25 struct DelegatedCertHost {
     26  const char* mHostName;
     27  const char* mCertName;
     28  const char* mDCKeyNick;
     29  bool mEnableDelegatedCredentials;
     30 };
     31 
     32 const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds) */;
     33 
     34 // {host, eeCert, dcCert, enableDC}
     35 const DelegatedCertHost sDelegatedCertHosts[] = {
     36    {"delegated-enabled.example.com", "delegated-ee", "delegated.key", true},
     37    {"standard-enabled.example.com", "default-ee", "delegated.key", true},
     38    {"delegated-disabled.example.com", "delegated-ee",
     39     /* anything non-null */ "delegated.key", false},
     40    {nullptr, nullptr, nullptr, false}};
     41 
     42 int32_t DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
     43                          uint32_t aSrvNameArrSize, void* aArg) {
     44  const DelegatedCertHost* host =
     45      GetHostForSNI(aSrvNameArr, aSrvNameArrSize, sDelegatedCertHosts);
     46  if (!host) {
     47    return SSL_SNI_SEND_ALERT;
     48  }
     49 
     50  if (gDebugLevel >= DEBUG_VERBOSE) {
     51    std::cerr << "Identified host " << host->mHostName << '\n';
     52  }
     53 
     54  UniqueCERTCertificate delegatorCert(
     55      PK11_FindCertFromNickname(host->mCertName, nullptr));
     56  if (!delegatorCert) {
     57    PrintPRError("PK11_FindCertFromNickname failed");
     58    return SSL_SNI_SEND_ALERT;
     59  }
     60 
     61  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
     62  if (!slot) {
     63    PrintPRError("PK11_GetInternalKeySlot failed");
     64    return SSL_SNI_SEND_ALERT;
     65  }
     66 
     67  SSLExtraServerCertData extra_data = {ssl_auth_null,
     68                                       /* Filled in by callee */ nullptr,
     69                                       nullptr,
     70                                       nullptr,
     71                                       /* DC */ nullptr,
     72                                       /* DC PrivKey */ nullptr};
     73 
     74  UniqueSECKEYPrivateKey delegatorPriv(
     75      PK11_FindKeyByDERCert(slot.get(), delegatorCert.get(), nullptr));
     76  if (!delegatorPriv) {
     77    PrintPRError("PK11_FindKeyByDERCert failed");
     78    return SSL_SNI_SEND_ALERT;
     79  }
     80 
     81  // Find the DC keypair by the file (nick) name.
     82  ScopedAutoSECItem dc;
     83  UniqueSECKEYPrivateKey dcPriv;
     84  if (host->mEnableDelegatedCredentials) {
     85    if (gDebugLevel >= DEBUG_VERBOSE) {
     86      std::cerr << "Enabling a delegated credential for host "
     87                << host->mHostName << '\n';
     88    }
     89 
     90    if (PK11_NeedLogin(slot.get())) {
     91      SECStatus rv = PK11_Authenticate(slot.get(), PR_TRUE, nullptr);
     92      if (rv != SECSuccess) {
     93        PrintPRError("PK11_Authenticate failed");
     94        return SSL_SNI_SEND_ALERT;
     95      }
     96    }
     97    UniqueSECKEYPrivateKeyList list(PK11_ListPrivKeysInSlot(
     98        slot.get(), const_cast<char*>(host->mDCKeyNick), nullptr));
     99    if (!list) {
    100      PrintPRError("PK11_ListPrivKeysInSlot failed");
    101      return SSL_SNI_SEND_ALERT;
    102    }
    103    SECKEYPrivateKeyListNode* node = PRIVKEY_LIST_HEAD(list);
    104 
    105    dcPriv.reset(SECKEY_CopyPrivateKey(node->key));
    106    if (!dcPriv) {
    107      PrintPRError("PK11_ListPrivKeysInSlot could not find dcPriv");
    108      return SSL_SNI_SEND_ALERT;
    109    }
    110 
    111    UniqueSECKEYPublicKey dcPub(SECKEY_ConvertToPublicKey(dcPriv.get()));
    112    if (!dcPub) {
    113      PrintPRError("SECKEY_ConvertToPublicKey failed");
    114      return SSL_SNI_SEND_ALERT;
    115    }
    116 
    117    // Create and set the DC.
    118    if (SSL_DelegateCredential(delegatorCert.get(), delegatorPriv.get(),
    119                               dcPub.get(), ssl_sig_ecdsa_secp384r1_sha384,
    120                               kDCValidFor, PR_Now(), &dc) != SECSuccess) {
    121      PrintPRError("SSL_DelegateCredential failed");
    122      return SSL_SNI_SEND_ALERT;
    123    }
    124    extra_data.delegCred = &dc;
    125    extra_data.delegCredPrivKey = dcPriv.get();
    126 
    127    // The list should only have a single key.
    128    PORT_Assert(PRIVKEY_LIST_END(PRIVKEY_LIST_NEXT(node), list));
    129  }
    130 
    131  if (ConfigSecureServerWithNamedCert(aFd, host->mCertName, nullptr, nullptr,
    132                                      &extra_data) != SECSuccess) {
    133    PrintPRError("ConfigSecureServerWithNamedCert failed");
    134    return SSL_SNI_SEND_ALERT;
    135  }
    136 
    137  return 0;
    138 }
    139 
    140 int main(int argc, char* argv[]) {
    141  return StartServer(argc, argv, DoSNISocketConfig, nullptr);
    142 }