tor-browser

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

EncryptedClientHelloServer.cpp (6070B)


      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 that offers TLS 1.3 Encrypted
      6 // Client Hello support.
      7 
      8 #include <stdio.h>
      9 
     10 #include "nspr.h"
     11 #include "ScopedNSSTypes.h"
     12 #include "ssl.h"
     13 #include "sslexp.h"
     14 #include "TLSServer.h"
     15 #include <pk11pub.h>
     16 #include <vector>
     17 
     18 using namespace mozilla;
     19 using namespace mozilla::test;
     20 
     21 struct EchHost {
     22  const char* mHostName;
     23  const char* mCertName;
     24 };
     25 
     26 MOZ_RUNINIT const std::vector<uint32_t> kSuiteChaCha = {
     27    (static_cast<uint32_t>(HpkeKdfHkdfSha256) << 16) |
     28    HpkeAeadChaCha20Poly1305};
     29 
     30 // Hostname, cert nickname pairs.
     31 const EchHost sEchHosts[] = {{"ech-public.example.com", "default-ee"},
     32                             {"ech-private.example.com", "private-ee"},
     33                             {"selfsigned.example.com", "selfsigned"},
     34                             {nullptr, nullptr}};
     35 
     36 int32_t DoSNISocketConfigBySubjectCN(PRFileDesc* aFd,
     37                                     const SECItem* aSrvNameArr,
     38                                     uint32_t aSrvNameArrSize) {
     39  for (uint32_t i = 0; i < aSrvNameArrSize; i++) {
     40    UniquePORTString name(
     41        static_cast<char*>(PORT_ZAlloc(aSrvNameArr[i].len + 1)));
     42    if (name) {
     43      PORT_Memcpy(name.get(), aSrvNameArr[i].data, aSrvNameArr[i].len);
     44      if (ConfigSecureServerWithNamedCert(aFd, name.get(), nullptr, nullptr,
     45                                          nullptr) == SECSuccess) {
     46        return 0;
     47      }
     48    }
     49  }
     50 
     51  return SSL_SNI_SEND_ALERT;
     52 }
     53 
     54 int32_t DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
     55                          uint32_t aSrvNameArrSize, void* aArg) {
     56  const EchHost* host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize, sEchHosts);
     57  if (!host) {
     58    PrintPRError("No cert found for hostname");
     59    return SSL_SNI_SEND_ALERT;
     60  }
     61 
     62  if (gDebugLevel >= DEBUG_VERBOSE) {
     63    fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
     64  }
     65 
     66  UniqueCERTCertificate cert;
     67  SSLKEAType certKEA;
     68  if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, host->mCertName, &cert,
     69                                                    &certKEA, nullptr)) {
     70    return SSL_SNI_SEND_ALERT;
     71  }
     72 
     73  return 0;
     74 }
     75 
     76 int32_t SetAlpnOptions(PRFileDesc* aFd, uint8_t flags) {
     77  const std::vector<uint8_t> http1 = {0x08, 0x68, 0x74, 0x74, 0x70,
     78                                      0x2f, 0x31, 0x2e, 0x31};
     79  const std::vector<uint8_t> http2 = {0x02, 0x68, 0x32};
     80  const std::vector<uint8_t> http3 = {0x02, 0x68, 0x33};
     81  std::vector<uint8_t> alpnVec = {};
     82  if (flags & 0b001) {
     83    alpnVec.insert(alpnVec.end(), http1.begin(), http1.end());
     84  }
     85  if (flags & 0b010) {
     86    alpnVec.insert(alpnVec.end(), http2.begin(), http2.end());
     87  }
     88  if (flags & 0b100) {
     89    alpnVec.insert(alpnVec.end(), http3.begin(), http3.end());
     90  }
     91  fprintf(stderr, "ALPN Flags: %u\n", flags);
     92  fprintf(stderr, "ALPN length: %zu\n", alpnVec.size());
     93  if (SSL_SetNextProtoNego(aFd, alpnVec.data(), alpnVec.size()) != SECSuccess) {
     94    fprintf(stderr, "Setting ALPN failed!\n");
     95    return 1;
     96  }
     97 
     98  return 0;
     99 }
    100 
    101 SECStatus ConfigureServer(PRFileDesc* aFd) {
    102  const char* alpnFlag = PR_GetEnv("MOZ_TLS_ECH_ALPN_FLAG");
    103  if (alpnFlag) {
    104    uint8_t flag = atoi(alpnFlag);
    105    SetAlpnOptions(aFd, flag);
    106  }
    107 
    108  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
    109  if (!slot) {
    110    PrintPRError("PK11_GetInternalKeySlot failed");
    111    return SECFailure;
    112  }
    113 
    114  UniqueSECKEYPublicKey pubKey;
    115  UniqueSECKEYPrivateKey privKey;
    116  SECKEYPublicKey* tmpPubKey = nullptr;
    117  SECKEYPrivateKey* tmpPrivKey = nullptr;
    118 
    119  static const std::vector<uint8_t> pkcs8{
    120      0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48,
    121      0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda,
    122      0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20,
    123      0x8c, 0x49, 0x0e, 0x5b, 0x0c, 0x7d, 0xbe, 0x0c, 0x6d, 0x21, 0x92, 0x48,
    124      0x4d, 0x2b, 0x7a, 0x04, 0x23, 0xb3, 0xb4, 0x54, 0x4f, 0x24, 0x81, 0x09,
    125      0x5a, 0x99, 0xdb, 0xf2, 0x38, 0xfb, 0x35, 0x0f, 0xa1, 0x23, 0x03, 0x21,
    126      0x00, 0x8a, 0x07, 0x56, 0x39, 0x49, 0xfa, 0xc6, 0x23, 0x29, 0x36, 0xed,
    127      0x6f, 0x36, 0xc4, 0xfa, 0x73, 0x59, 0x30, 0xec, 0xde, 0xae, 0xf6, 0x73,
    128      0x4e, 0x31, 0x4a, 0xea, 0xc3, 0x5a, 0x56, 0xfd, 0x0a};
    129 
    130  SECItem pkcs8Item = {siBuffer, const_cast<uint8_t*>(pkcs8.data()),
    131                       static_cast<unsigned int>(pkcs8.size())};
    132  SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
    133      slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL,
    134      &tmpPrivKey, nullptr);
    135 
    136  if (rv != SECSuccess) {
    137    PrintPRError("PK11_ImportDERPrivateKeyInfoAndReturnKey failed");
    138    return SECFailure;
    139  }
    140  privKey.reset(tmpPrivKey);
    141  tmpPubKey = SECKEY_ConvertToPublicKey(privKey.get());
    142  pubKey.reset(tmpPubKey);
    143 
    144  if (!privKey || !pubKey) {
    145    PrintPRError("ECH/HPKE Public or Private key is null!");
    146    return SECFailure;
    147  }
    148 
    149  std::vector<uint8_t> echConfig(1000, 0);
    150  unsigned int len = 0;
    151  const PRUint8 configId = 77;
    152  const HpkeSymmetricSuite echCipherSuite = {HpkeKdfHkdfSha256,
    153                                             HpkeAeadChaCha20Poly1305};
    154  rv = SSL_EncodeEchConfigId(configId, "ech-public.example.com", 100,
    155                             HpkeDhKemX25519Sha256, pubKey.get(),
    156                             &echCipherSuite, 1, echConfig.data(), &len,
    157                             echConfig.size());
    158  if (rv != SECSuccess) {
    159    PrintPRError("SSL_EncodeEchConfig failed");
    160    return rv;
    161  }
    162 
    163  rv = SSL_SetServerEchConfigs(aFd, pubKey.get(), privKey.get(),
    164                               echConfig.data(), len);
    165  if (rv != SECSuccess) {
    166    PrintPRError("SSL_SetServerEchConfigs failed");
    167    return rv;
    168  }
    169 
    170  return SECSuccess;
    171 }
    172 
    173 int main(int argc, char* argv[]) {
    174  int rv = StartServer(argc, argv, DoSNISocketConfig, nullptr, ConfigureServer);
    175  if (rv < 0) {
    176    return rv;
    177  }
    178 }