tor-browser

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

nss_bogo_shim.cc (39899B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 #include "config.h"
      7 
      8 #include <algorithm>
      9 #include <cstdlib>
     10 #include <iostream>
     11 #include <memory>
     12 #include "nspr.h"
     13 #include "nss.h"
     14 #include "prio.h"
     15 #include "prnetdb.h"
     16 #include "secerr.h"
     17 #include "ssl.h"
     18 #include "ssl3prot.h"
     19 #include "sslerr.h"
     20 #include "sslproto.h"
     21 #include "nss_scoped_ptrs.h"
     22 #include "sslimpl.h"
     23 #include "tls13ech.h"
     24 #include "base64.h"
     25 
     26 #include "nsskeys.h"
     27 
     28 static const char* kVersionDisableFlags[] = {"no-ssl3", "no-tls1", "no-tls11",
     29                                             "no-tls12", "no-tls13"};
     30 
     31 /* Default EarlyData dummy data determined by Bogo implementation. */
     32 const unsigned char kBogoDummyData[] = {'h', 'e', 'l', 'l', 'o'};
     33 
     34 bool exitCodeUnimplemented = false;
     35 
     36 std::string FormatError(PRErrorCode code) {
     37  return std::string(":") + PORT_ErrorToName(code) + ":" + ":" +
     38         PORT_ErrorToString(code);
     39 }
     40 
     41 static void StringRemoveNewlines(std::string& str) {
     42  str.erase(std::remove(str.begin(), str.end(), '\n'), str.cend());
     43  str.erase(std::remove(str.begin(), str.end(), '\r'), str.cend());
     44 }
     45 
     46 class TestAgent {
     47 public:
     48  TestAgent(const Config& cfg) : cfg_(cfg) {}
     49 
     50  ~TestAgent() {}
     51 
     52  static std::unique_ptr<TestAgent> Create(const Config& cfg) {
     53    std::unique_ptr<TestAgent> agent(new TestAgent(cfg));
     54 
     55    if (!agent->Init()) return nullptr;
     56 
     57    return agent;
     58  }
     59 
     60  bool Init() {
     61    if (!ConnectTcp()) {
     62      return false;
     63    }
     64 
     65    if (!SetupKeys()) {
     66      std::cerr << "Couldn't set up keys/certs\n";
     67      return false;
     68    }
     69 
     70    if (!SetupOptions()) {
     71      std::cerr << "Couldn't configure socket\n";
     72      return false;
     73    }
     74 
     75    SECStatus rv = SSL_ResetHandshake(ssl_fd_.get(), cfg_.get<bool>("server"));
     76    if (rv != SECSuccess) return false;
     77 
     78    return true;
     79  }
     80 
     81  bool ConnectTcp() {
     82    if (!(cfg_.get<bool>("ipv6") && OpenConnection("::1")) &&
     83        !OpenConnection("127.0.0.1")) {
     84      return false;
     85    }
     86 
     87    ssl_fd_ = ScopedPRFileDesc(SSL_ImportFD(NULL, pr_fd_.get()));
     88    if (!ssl_fd_) {
     89      return false;
     90    }
     91    pr_fd_.release();
     92 
     93    return true;
     94  }
     95 
     96  bool OpenConnection(const char* ip) {
     97    PRStatus prv;
     98    PRNetAddr addr;
     99 
    100    prv = PR_StringToNetAddr(ip, &addr);
    101 
    102    if (prv != PR_SUCCESS) {
    103      return false;
    104    }
    105 
    106    addr.inet.port = PR_htons(cfg_.get<int>("port"));
    107 
    108    pr_fd_ = ScopedPRFileDesc(PR_OpenTCPSocket(addr.raw.family));
    109    if (!pr_fd_) return false;
    110 
    111    prv = PR_Connect(pr_fd_.get(), &addr, PR_INTERVAL_NO_TIMEOUT);
    112    if (prv != PR_SUCCESS) {
    113      return false;
    114    }
    115 
    116    uint64_t shim_id = cfg_.get<int>("shim-id");
    117    uint8_t buf[8] = {0};
    118    for (size_t i = 0; i < 8; i++) {
    119      buf[i] = shim_id & 0xff;
    120      shim_id >>= 8;
    121    }
    122    int sent = PR_Write(pr_fd_.get(), buf, sizeof(buf));
    123    if (sent != sizeof(buf)) {
    124      return false;
    125    }
    126 
    127    return true;
    128  }
    129 
    130  bool SetupKeys() {
    131    SECStatus rv;
    132 
    133    if (cfg_.get<std::string>("key-file") != "") {
    134      key_ = ScopedSECKEYPrivateKey(
    135          ReadPrivateKey(cfg_.get<std::string>("key-file")));
    136      if (!key_) return false;
    137    }
    138    if (cfg_.get<std::string>("cert-file") != "") {
    139      cert_ = ScopedCERTCertificate(
    140          ReadCertificate(cfg_.get<std::string>("cert-file")));
    141      if (!cert_) return false;
    142    }
    143 
    144    // Needed because certs are not entirely valid.
    145    rv = SSL_AuthCertificateHook(ssl_fd_.get(), AuthCertificateHook, this);
    146    if (rv != SECSuccess) return false;
    147 
    148    if (cfg_.get<bool>("server")) {
    149      // Server
    150      rv = SSL_ConfigServerCert(ssl_fd_.get(), cert_.get(), key_.get(), nullptr,
    151                                0);
    152      if (rv != SECSuccess) {
    153        std::cerr << "Couldn't configure server cert\n";
    154        return false;
    155      }
    156 
    157    } else if (key_ && cert_) {
    158      // Client.
    159      rv =
    160          SSL_GetClientAuthDataHook(ssl_fd_.get(), GetClientAuthDataHook, this);
    161      if (rv != SECSuccess) return false;
    162    }
    163 
    164    return true;
    165  }
    166 
    167  static bool ConvertFromWireVersion(SSLProtocolVariant variant,
    168                                     int wire_version, uint16_t* lib_version) {
    169    // These default values are used when {min,max}-version isn't given.
    170    if (wire_version == 0 || wire_version == 0xffff) {
    171      *lib_version = static_cast<uint16_t>(wire_version);
    172      return true;
    173    }
    174 
    175 #ifdef TLS_1_3_DRAFT_VERSION
    176    if (wire_version == (0x7f00 | TLS_1_3_DRAFT_VERSION)) {
    177      // N.B. SSL_LIBRARY_VERSION_DTLS_1_3_WIRE == SSL_LIBRARY_VERSION_TLS_1_3
    178      wire_version = SSL_LIBRARY_VERSION_TLS_1_3;
    179    }
    180 #endif
    181 
    182    if (variant == ssl_variant_datagram) {
    183      switch (wire_version) {
    184        case SSL_LIBRARY_VERSION_DTLS_1_0_WIRE:
    185          *lib_version = SSL_LIBRARY_VERSION_DTLS_1_0;
    186          break;
    187        case SSL_LIBRARY_VERSION_DTLS_1_2_WIRE:
    188          *lib_version = SSL_LIBRARY_VERSION_DTLS_1_2;
    189          break;
    190        case SSL_LIBRARY_VERSION_DTLS_1_3_WIRE:
    191          *lib_version = SSL_LIBRARY_VERSION_DTLS_1_3;
    192          break;
    193        default:
    194          std::cerr << "Unrecognized DTLS version " << wire_version << ".\n";
    195          return false;
    196      }
    197    } else {
    198      if (wire_version < SSL_LIBRARY_VERSION_3_0 ||
    199          wire_version > SSL_LIBRARY_VERSION_TLS_1_3) {
    200        std::cerr << "Unrecognized TLS version " << wire_version << ".\n";
    201        return false;
    202      }
    203      *lib_version = static_cast<uint16_t>(wire_version);
    204    }
    205    return true;
    206  }
    207 
    208  bool GetVersionRange(SSLVersionRange* range_out, SSLProtocolVariant variant) {
    209    SSLVersionRange supported;
    210    if (SSL_VersionRangeGetSupported(variant, &supported) != SECSuccess) {
    211      return false;
    212    }
    213 
    214    uint16_t min_allowed;
    215    uint16_t max_allowed;
    216    if (!ConvertFromWireVersion(variant, cfg_.get<int>("min-version"),
    217                                &min_allowed)) {
    218      return false;
    219    }
    220    if (!ConvertFromWireVersion(variant, cfg_.get<int>("max-version"),
    221                                &max_allowed)) {
    222      return false;
    223    }
    224 
    225    min_allowed = std::max(min_allowed, supported.min);
    226    max_allowed = std::min(max_allowed, supported.max);
    227 
    228    bool found_min = false;
    229    bool found_max = false;
    230    // Ignore -no-ssl3, because SSLv3 is never supported.
    231    for (size_t i = 1; i < PR_ARRAY_SIZE(kVersionDisableFlags); ++i) {
    232      auto version =
    233          static_cast<uint16_t>(SSL_LIBRARY_VERSION_TLS_1_0 + (i - 1));
    234      if (variant == ssl_variant_datagram) {
    235        // In DTLS mode, the -no-tlsN flags refer to DTLS versions,
    236        // but NSS wants the corresponding TLS versions.
    237        if (version == SSL_LIBRARY_VERSION_TLS_1_1) {
    238          // DTLS 1.1 doesn't exist.
    239          continue;
    240        }
    241        if (version == SSL_LIBRARY_VERSION_TLS_1_0) {
    242          version = SSL_LIBRARY_VERSION_DTLS_1_0;
    243        }
    244      }
    245 
    246      if (version < min_allowed) {
    247        continue;
    248      }
    249      if (version > max_allowed) {
    250        break;
    251      }
    252 
    253      const bool allowed = !cfg_.get<bool>(kVersionDisableFlags[i]);
    254 
    255      if (!found_min && allowed) {
    256        found_min = true;
    257        range_out->min = version;
    258      }
    259      if (found_min && !found_max) {
    260        if (allowed) {
    261          range_out->max = version;
    262        } else {
    263          found_max = true;
    264        }
    265      }
    266      if (found_max && allowed) {
    267        std::cerr << "Discontiguous version range.\n";
    268        return false;
    269      }
    270    }
    271 
    272    if (!found_min) {
    273      std::cerr << "All versions disabled.\n";
    274    }
    275    return found_min;
    276  }
    277 
    278  bool SetupOptions() {
    279    SECStatus rv =
    280        SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_TLS13_COMPAT_MODE, PR_TRUE);
    281    if (rv != SECSuccess) return false;
    282 
    283    rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
    284    if (rv != SECSuccess) return false;
    285 
    286    SSLVersionRange vrange;
    287    if (!GetVersionRange(&vrange, ssl_variant_stream)) return false;
    288 
    289    rv = SSL_VersionRangeSet(ssl_fd_.get(), &vrange);
    290    if (rv != SECSuccess) return false;
    291 
    292    SSLVersionRange verify_vrange;
    293    rv = SSL_VersionRangeGet(ssl_fd_.get(), &verify_vrange);
    294    if (rv != SECSuccess) return false;
    295    if (vrange.min != verify_vrange.min || vrange.max != verify_vrange.max)
    296      return false;
    297 
    298    rv = SSL_OptionSet(ssl_fd_.get(), SSL_NO_CACHE, false);
    299    if (rv != SECSuccess) return false;
    300 
    301    auto alpn = cfg_.get<std::string>("advertise-alpn");
    302    if (!alpn.empty()) {
    303      assert(!cfg_.get<bool>("server"));
    304 
    305      rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_ALPN, PR_TRUE);
    306      if (rv != SECSuccess) return false;
    307 
    308      rv = SSL_SetNextProtoNego(
    309          ssl_fd_.get(), reinterpret_cast<const unsigned char*>(alpn.c_str()),
    310          alpn.size());
    311      if (rv != SECSuccess) return false;
    312    }
    313 
    314    // Set supported signature schemes.
    315    auto sign_prefs = cfg_.get<std::vector<int>>("signing-prefs");
    316    auto verify_prefs = cfg_.get<std::vector<int>>("verify-prefs");
    317    if (sign_prefs.empty()) {
    318      sign_prefs = verify_prefs;
    319    } else if (!verify_prefs.empty()) {
    320      return false;  // Both shouldn't be set.
    321    }
    322    if (!sign_prefs.empty()) {
    323      std::vector<SSLSignatureScheme> sig_schemes;
    324      std::transform(
    325          sign_prefs.begin(), sign_prefs.end(), std::back_inserter(sig_schemes),
    326          [](int scheme) { return static_cast<SSLSignatureScheme>(scheme); });
    327 
    328      rv = SSL_SignatureSchemePrefSet(
    329          ssl_fd_.get(), sig_schemes.data(),
    330          static_cast<unsigned int>(sig_schemes.size()));
    331      if (rv != SECSuccess) return false;
    332    }
    333 
    334    if (cfg_.get<bool>("fallback-scsv")) {
    335      rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
    336      if (rv != SECSuccess) return false;
    337    }
    338 
    339    if (cfg_.get<bool>("false-start")) {
    340      rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_FALSE_START, PR_TRUE);
    341      if (rv != SECSuccess) return false;
    342    }
    343 
    344    if (cfg_.get<bool>("enable-ocsp-stapling")) {
    345      rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_OCSP_STAPLING, PR_TRUE);
    346      if (rv != SECSuccess) return false;
    347    }
    348 
    349    bool requireClientCert = cfg_.get<bool>("require-any-client-certificate");
    350    if (requireClientCert || cfg_.get<bool>("verify-peer")) {
    351      assert(cfg_.get<bool>("server"));
    352 
    353      rv = SSL_OptionSet(ssl_fd_.get(), SSL_REQUEST_CERTIFICATE, PR_TRUE);
    354      if (rv != SECSuccess) return false;
    355 
    356      rv = SSL_OptionSet(
    357          ssl_fd_.get(), SSL_REQUIRE_CERTIFICATE,
    358          requireClientCert ? SSL_REQUIRE_ALWAYS : SSL_REQUIRE_NO_ERROR);
    359      if (rv != SECSuccess) return false;
    360    }
    361 
    362    if (!cfg_.get<bool>("server")) {
    363      auto hostname = cfg_.get<std::string>("host-name");
    364      if (!hostname.empty()) {
    365        rv = SSL_SetURL(ssl_fd_.get(), hostname.c_str());
    366      } else {
    367        // Needed to make resumption work.
    368        rv = SSL_SetURL(ssl_fd_.get(), "server");
    369      }
    370      if (rv != SECSuccess) return false;
    371 
    372      // Setup ECH configs on client if provided
    373      auto echConfigList = cfg_.get<std::string>("ech-config-list");
    374      if (!echConfigList.empty()) {
    375        unsigned int binLen;
    376        auto bin = ATOB_AsciiToData(echConfigList.c_str(), &binLen);
    377        rv = SSLExp_SetClientEchConfigs(ssl_fd_.get(), bin, binLen);
    378        if (rv != SECSuccess) return false;
    379        free(bin);
    380      }
    381 
    382      if (cfg_.get<bool>("enable-grease")) {
    383        rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_GREASE, PR_TRUE);
    384        if (rv != SECSuccess) return false;
    385      }
    386 
    387      if (cfg_.get<bool>("permute-extensions")) {
    388        rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_CH_EXTENSION_PERMUTATION,
    389                           PR_TRUE);
    390        if (rv != SECSuccess) return false;
    391      }
    392 
    393    } else {
    394      // GREASE - BoGo expects servers to enable GREASE by default
    395      rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_GREASE, PR_TRUE);
    396      if (rv != SECSuccess) return false;
    397    }
    398 
    399    rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_EXTENDED_MASTER_SECRET,
    400                       PR_TRUE);
    401    if (rv != SECSuccess) return false;
    402 
    403    if (cfg_.get<bool>("server")) {
    404      // BoGo expects servers to enable ECH (backend) by default
    405      rv = SSLExp_EnableTls13BackendEch(ssl_fd_.get(), true);
    406      if (rv != SECSuccess) return false;
    407    }
    408 
    409    if (cfg_.get<bool>("enable-ech-grease")) {
    410      rv = SSLExp_EnableTls13GreaseEch(ssl_fd_.get(), true);
    411      if (rv != SECSuccess) return false;
    412    }
    413 
    414    if (cfg_.get<bool>("enable-early-data")) {
    415      rv = SSL_OptionSet(ssl_fd_.get(), SSL_ENABLE_0RTT_DATA, PR_TRUE);
    416      if (rv != SECSuccess) return false;
    417    }
    418 
    419    if (!ConfigureGroups()) return false;
    420 
    421    if (!ConfigureCiphers()) return false;
    422 
    423    return true;
    424  }
    425 
    426  bool ConfigureGroups() {
    427    auto curves = cfg_.get<std::vector<int>>("curves");
    428    if (curves.size() > 0) {
    429      std::vector<SSLNamedGroup> groups;
    430      std::transform(
    431          curves.begin(), curves.end(), std::back_inserter(groups),
    432          [](int curve) { return static_cast<SSLNamedGroup>(curve); });
    433      SECStatus rv =
    434          SSL_NamedGroupConfig(ssl_fd_.get(), &groups[0], groups.size());
    435      if (rv != SECSuccess) {
    436        return false;
    437      }
    438      // Xyber768 is disabled by policy by default, so if it's requested
    439      // we need to update the policy flags as well.
    440      for (auto group : groups) {
    441        if (group == ssl_grp_kem_xyber768d00) {
    442          NSS_SetAlgorithmPolicy(SEC_OID_XYBER768D00, NSS_USE_ALG_IN_SSL_KX, 0);
    443        }
    444      }
    445    }
    446 
    447    return true;
    448  }
    449 
    450  bool ConfigureCiphers() {
    451    auto cipherList = cfg_.get<std::string>("nss-cipher");
    452 
    453    if (cipherList.empty()) {
    454      return EnableNonExportCiphers();
    455    }
    456 
    457    for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
    458      SSLCipherSuiteInfo csinfo;
    459      std::string::size_type n;
    460      SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i], &csinfo,
    461                                            sizeof(csinfo));
    462      if (rv != SECSuccess) {
    463        return false;
    464      }
    465 
    466      // Check if cipherList contains the name of the Cipher Suite and
    467      // enable/disable accordingly.
    468      n = cipherList.find(csinfo.cipherSuiteName, 0);
    469      if (std::string::npos == n) {
    470        rv = SSL_CipherPrefSet(ssl_fd_.get(), SSL_ImplementedCiphers[i],
    471                               PR_FALSE);
    472      } else {
    473        rv = SSL_CipherPrefSet(ssl_fd_.get(), SSL_ImplementedCiphers[i],
    474                               PR_TRUE);
    475      }
    476      if (rv != SECSuccess) {
    477        return false;
    478      }
    479    }
    480    return true;
    481  }
    482 
    483  bool EnableNonExportCiphers() {
    484    for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
    485      SSLCipherSuiteInfo csinfo;
    486 
    487      SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i], &csinfo,
    488                                            sizeof(csinfo));
    489      if (rv != SECSuccess) {
    490        return false;
    491      }
    492 
    493      rv = SSL_CipherPrefSet(ssl_fd_.get(), SSL_ImplementedCiphers[i], PR_TRUE);
    494      if (rv != SECSuccess) {
    495        return false;
    496      }
    497    }
    498    return true;
    499  }
    500 
    501  // Dummy auth certificate hook.
    502  static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd,
    503                                       PRBool checksig, PRBool isServer) {
    504    return SECSuccess;
    505  }
    506 
    507  static SECStatus GetClientAuthDataHook(void* self, PRFileDesc* fd,
    508                                         CERTDistNames* caNames,
    509                                         CERTCertificate** cert,
    510                                         SECKEYPrivateKey** privKey) {
    511    TestAgent* a = static_cast<TestAgent*>(self);
    512    *cert = CERT_DupCertificate(a->cert_.get());
    513    *privKey = SECKEY_CopyPrivateKey(a->key_.get());
    514    return SECSuccess;
    515  }
    516 
    517  SECStatus Handshake() { return SSL_ForceHandshake(ssl_fd_.get()); }
    518 
    519  // Implement a trivial echo client/server. Read bytes from the other side,
    520  // flip all the bits, and send them back.
    521  SECStatus ReadWrite() {
    522    for (;;) {
    523      uint8_t block[512];
    524      int32_t rv = PR_Read(ssl_fd_.get(), block, sizeof(block));
    525      if (rv < 0) {
    526        std::cerr << "Failure reading\n";
    527        return SECFailure;
    528      }
    529      if (rv == 0) return SECSuccess;
    530 
    531      int32_t len = rv;
    532      for (int32_t i = 0; i < len; ++i) {
    533        block[i] ^= 0xff;
    534      }
    535 
    536      rv = PR_Write(ssl_fd_.get(), block, len);
    537      if (rv != len) {
    538        std::cerr << "Write failure\n";
    539        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    540        return SECFailure;
    541      }
    542    }
    543  }
    544 
    545  // Write bytes to the other side then read them back and check
    546  // that they were correctly XORed as in ReadWrite.
    547  SECStatus WriteRead() {
    548    static const uint8_t ch = 'E';
    549 
    550    // We do 600-byte blocks to provide mis-alignment of the
    551    // reader and writer.
    552    uint8_t block[600];
    553    memset(block, ch, sizeof(block));
    554    int32_t rv = PR_Write(ssl_fd_.get(), block, sizeof(block));
    555    if (rv != sizeof(block)) {
    556      std::cerr << "Write failure\n";
    557      PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    558      return SECFailure;
    559    }
    560 
    561    size_t left = sizeof(block);
    562    while (left) {
    563      rv = PR_Read(ssl_fd_.get(), block, left);
    564      if (rv < 0) {
    565        std::cerr << "Failure reading\n";
    566        return SECFailure;
    567      }
    568      if (rv == 0) {
    569        PORT_SetError(SEC_ERROR_INPUT_LEN);
    570        return SECFailure;
    571      }
    572 
    573      int32_t len = rv;
    574      for (int32_t i = 0; i < len; ++i) {
    575        if (block[i] != (ch ^ 0xff)) {
    576          PORT_SetError(SEC_ERROR_BAD_DATA);
    577          return SECFailure;
    578        }
    579      }
    580      left -= len;
    581    }
    582    return SECSuccess;
    583  }
    584 
    585  SECStatus CheckALPN(std::string expectedALPN) {
    586    SECStatus rv;
    587    SSLNextProtoState state;
    588    char chosen[256];
    589    unsigned int chosen_len;
    590 
    591    rv = SSL_GetNextProto(ssl_fd_.get(), &state,
    592                          reinterpret_cast<unsigned char*>(chosen), &chosen_len,
    593                          sizeof(chosen));
    594    if (rv != SECSuccess) {
    595      PRErrorCode err = PR_GetError();
    596      std::cerr << "SSL_GetNextProto failed with error=" << FormatError(err)
    597                << std::endl;
    598      return SECFailure;
    599    }
    600 
    601    assert(chosen_len <= sizeof(chosen));
    602    if (std::string(chosen, chosen_len) != expectedALPN) {
    603      std::cerr << "Expexted ALPN (" << expectedALPN << ") != Choosen ALPN ("
    604                << std::string(chosen, chosen_len) << ")" << std::endl;
    605      return SECFailure;
    606    }
    607 
    608    return SECSuccess;
    609  }
    610 
    611  SECStatus AdvertiseALPN(std::string alpn) {
    612    return SSL_SetNextProtoNego(
    613        ssl_fd_.get(), reinterpret_cast<const unsigned char*>(alpn.c_str()),
    614        alpn.size());
    615  }
    616 
    617  /* Certificate Encoding/Decoding Shrinking functions
    618   * See
    619   * https://boringssl.googlesource.com/boringssl/+/master/ssl/test/runner/runner.go#16168
    620   */
    621  static SECStatus certCompressionShrinkEncode(const SECItem* input,
    622                                               SECItem* output) {
    623    if (input == NULL || input->data == NULL) {
    624      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    625      return SECFailure;
    626    }
    627 
    628    if (input->len < 2) {
    629      std::cerr << "Certificate is too short. " << std::endl;
    630      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    631      return SECFailure;
    632    }
    633 
    634    SECITEM_AllocItem(NULL, output, input->len - 2);
    635    if (output == NULL || output->data == NULL) {
    636      return SECFailure;
    637    }
    638 
    639    /* The shrinking encoding primitive expects the first two bytes of a
    640     * certificate to be equal to 0. */
    641    if (input->data[0] != 0 || input->data[1] != 0) {
    642      std::cerr << "Cannot compress certificate message." << std::endl;
    643      return SECFailure;
    644    }
    645 
    646    for (size_t i = 0; i < output->len; i++) {
    647      output->data[i] = input->data[i + 2];
    648    }
    649    return SECSuccess;
    650  }
    651 
    652  static SECStatus certCompressionShrinkDecode(const SECItem* input,
    653                                               unsigned char* output,
    654                                               size_t outputLen,
    655                                               size_t* usedLen) {
    656    if (input == NULL || input->data == NULL) {
    657      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    658      return SECFailure;
    659    }
    660 
    661    if (output == NULL || outputLen != input->len + 2) {
    662      return SECFailure;
    663    }
    664 
    665    output[0] = 0;
    666    output[1] = 0;
    667    for (size_t i = 0; i < input->len; i++) {
    668      output[i + 2] = input->data[i];
    669    }
    670 
    671    *usedLen = outputLen;
    672    return SECSuccess;
    673  }
    674 
    675  /* Certificate Encoding/Decoding Expanding functions
    676   * See
    677   * https://boringssl.googlesource.com/boringssl/+/master/ssl/test/runner/runner.go#16186
    678   */
    679  static SECStatus certCompressionExpandEncode(const SECItem* input,
    680                                               SECItem* output) {
    681    if (input == NULL || input->data == NULL) {
    682      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    683      return SECFailure;
    684    }
    685 
    686    SECITEM_AllocItem(NULL, output, input->len + 4);
    687 
    688    if (output == NULL || output->data == NULL) {
    689      return SECFailure;
    690    }
    691 
    692    output->data[0] = 1;
    693    output->data[1] = 2;
    694    output->data[2] = 3;
    695    output->data[3] = 4;
    696    for (size_t i = 0; i < input->len; i++) {
    697      output->data[i + 4] = input->data[i];
    698    }
    699 
    700    return SECSuccess;
    701  }
    702 
    703  static SECStatus certCompressionExpandDecode(const SECItem* input,
    704                                               unsigned char* output,
    705                                               size_t outputLen,
    706                                               size_t* usedLen) {
    707    if (input == NULL || input->data == NULL) {
    708      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    709      return SECFailure;
    710    }
    711 
    712    if (input->len < 4) {
    713      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    714      std::cerr << "Certificate is too short. " << std::endl;
    715      return SECFailure;
    716    }
    717 
    718    if (output == NULL || outputLen != input->len - 4) {
    719      return SECFailure;
    720    }
    721 
    722    /* See the corresponding compression function. */
    723    if (input->data[0] != 1 || input->data[1] != 2 || input->data[2] != 3 ||
    724        input->data[3] != 4) {
    725      std::cerr << "Cannot decompress certificate message." << std::endl;
    726      return SECFailure;
    727    }
    728 
    729    for (size_t i = 0; i < outputLen; i++) {
    730      output[i] = input->data[i + 4];
    731    }
    732 
    733    *usedLen = outputLen;
    734    return SECSuccess;
    735  }
    736 
    737  /* Certificate Encoding/Decoding Random functions
    738   * See
    739   * https://boringssl.googlesource.com/boringssl/+/master/ssl/test/runner/runner.go#16201
    740   */
    741  static SECStatus certCompressionRandomEncode(const SECItem* input,
    742                                               SECItem* output) {
    743    if (input == NULL || input->data == NULL) {
    744      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    745      return SECFailure;
    746    }
    747 
    748    SECITEM_AllocItem(NULL, output, input->len + 1);
    749 
    750    if (output == NULL || output->data == NULL) {
    751      return SECFailure;
    752    }
    753 
    754    SECStatus rv = PK11_GenerateRandom(output->data, 1);
    755 
    756    if (rv != SECSuccess) {
    757      std::cerr << "Failed to generate randomness. " << std::endl;
    758      return SECFailure;
    759    }
    760 
    761    for (size_t i = 0; i < input->len; i++) {
    762      output->data[i + 1] = input->data[i];
    763    }
    764    return SECSuccess;
    765  }
    766 
    767  static SECStatus certCompressionRandomDecode(const SECItem* input,
    768                                               unsigned char* output,
    769                                               size_t outputLen,
    770                                               size_t* usedLen) {
    771    if (input == NULL || input->data == NULL) {
    772      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    773      return SECFailure;
    774    }
    775 
    776    if (input->len < 1) {
    777      PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    778      std::cerr << "Certificate is too short. " << std::endl;
    779      return SECFailure;
    780    }
    781 
    782    if (output == NULL || outputLen != input->len - 1) {
    783      return SECFailure;
    784    }
    785 
    786    for (size_t i = 0; i < outputLen; i++) {
    787      output[i] = input->data[i + 1];
    788    }
    789 
    790    *usedLen = outputLen;
    791    return SECSuccess;
    792  }
    793 
    794  SECStatus DoExchange(bool resuming) {
    795    SECStatus rv;
    796    int earlyDataSent = 0;
    797    std::string str;
    798    sslSocket* ss = ssl_FindSocket(ssl_fd_.get());
    799    if (!ss) {
    800      return SECFailure;
    801    }
    802    if (cfg_.get<bool>("install-cert-compression-algs")) {
    803      SSLCertificateCompressionAlgorithm t = {
    804          (SSLCertificateCompressionAlgorithmID)0xff01,
    805          "shrinkingCompressionAlg", certCompressionShrinkEncode,
    806          certCompressionShrinkDecode};
    807 
    808      SSLCertificateCompressionAlgorithm t1 = {
    809          (SSLCertificateCompressionAlgorithmID)0xff02,
    810          "expandingCompressionAlg", certCompressionExpandEncode,
    811          certCompressionExpandDecode};
    812 
    813      SSLCertificateCompressionAlgorithm t2 = {
    814          (SSLCertificateCompressionAlgorithmID)0xff03, "randomCompressionAlg",
    815          certCompressionRandomEncode, certCompressionRandomDecode};
    816 
    817      SSLExp_SetCertificateCompressionAlgorithm(ssl_fd_.get(), t);
    818      SSLExp_SetCertificateCompressionAlgorithm(ssl_fd_.get(), t1);
    819      SSLExp_SetCertificateCompressionAlgorithm(ssl_fd_.get(), t2);
    820    }
    821 
    822    /* Apply resumption SSL options (if any). */
    823    if (resuming) {
    824      /* Client options */
    825      if (!cfg_.get<bool>("server")) {
    826        auto resumeEchConfigList =
    827            cfg_.get<std::string>("on-resume-ech-config-list");
    828        if (!resumeEchConfigList.empty()) {
    829          unsigned int binLen;
    830          auto bin = ATOB_AsciiToData(resumeEchConfigList.c_str(), &binLen);
    831          rv = SSLExp_SetClientEchConfigs(ssl_fd_.get(), bin, binLen);
    832          if (rv != SECSuccess) {
    833            PRErrorCode err = PR_GetError();
    834            std::cerr << "Setting up resumption ECH configs failed with error="
    835                      << err << FormatError(err) << std::endl;
    836          }
    837          free(bin);
    838        }
    839 
    840        str = cfg_.get<std::string>("on-resume-advertise-alpn");
    841        if (!str.empty()) {
    842          if (AdvertiseALPN(str) != SECSuccess) {
    843            PRErrorCode err = PR_GetError();
    844            std::cerr << "Setting up resumption ALPN failed with error=" << err
    845                      << FormatError(err) << std::endl;
    846          }
    847        }
    848      }
    849 
    850    } else { /* Explicitly not on resume (on initial) */
    851      /* Client options */
    852      if (!cfg_.get<bool>("server")) {
    853        str = cfg_.get<std::string>("on-initial-advertise-alpn");
    854        if (!str.empty()) {
    855          if (AdvertiseALPN(str) != SECSuccess) {
    856            PRErrorCode err = PR_GetError();
    857            std::cerr << "Setting up initial ALPN failed with error=" << err
    858                      << FormatError(err) << std::endl;
    859          }
    860        }
    861      }
    862    }
    863 
    864    /* If client send ClientHello. */
    865    if (!cfg_.get<bool>("server")) {
    866      ssl_Get1stHandshakeLock(ss);
    867      rv = ssl_BeginClientHandshake(ss);
    868      ssl_Release1stHandshakeLock(ss);
    869      if (rv != SECSuccess) {
    870        PRErrorCode err = PR_GetError();
    871        std::cerr << "Handshake failed with error=" << err << FormatError(err)
    872                  << std::endl;
    873        return SECFailure;
    874      }
    875 
    876      /* If the client is resuming. */
    877      if (ss->statelessResume) {
    878        SSLPreliminaryChannelInfo pinfo;
    879        rv = SSL_GetPreliminaryChannelInfo(ssl_fd_.get(), &pinfo,
    880                                           sizeof(SSLPreliminaryChannelInfo));
    881        if (rv != SECSuccess) {
    882          PRErrorCode err = PR_GetError();
    883          std::cerr << "SSL_GetPreliminaryChannelInfo failed with " << err
    884                    << std::endl;
    885          return SECFailure;
    886        }
    887 
    888        /* Check that the used ticket supports early data. */
    889        if (cfg_.get<bool>("expect-ticket-supports-early-data")) {
    890          if (!pinfo.ticketSupportsEarlyData) {
    891            std::cerr << "Expected ticket to support EarlyData" << std::endl;
    892            return SECFailure;
    893          }
    894        }
    895 
    896        /* If the client should send EarlyData. */
    897        if (cfg_.get<bool>("on-resume-shim-writes-first")) {
    898          earlyDataSent =
    899              ssl_SecureWrite(ss, kBogoDummyData, sizeof(kBogoDummyData));
    900          if (earlyDataSent < 0) {
    901            std::cerr << "Sending of EarlyData failed" << std::endl;
    902            return SECFailure;
    903          }
    904        }
    905 
    906        if (cfg_.get<bool>("expect-no-offer-early-data")) {
    907          if (earlyDataSent) {
    908            std::cerr << "Unexpectedly offered EarlyData" << std::endl;
    909            return SECFailure;
    910          }
    911        }
    912      }
    913    }
    914 
    915    /* As server start, as client continue handshake. */
    916    rv = Handshake();
    917 
    918    /* Retry config evaluation must be done before error handling since
    919     * handshake failure is intended on ech_required tests. */
    920    if (cfg_.get<bool>("expect-no-ech-retry-configs")) {
    921      if (ss->xtnData.ech && ss->xtnData.ech->retryConfigsValid) {
    922        std::cerr << "Unexpectedly received ECH retry configs" << std::endl;
    923        return SECFailure;
    924      }
    925    }
    926 
    927    /* If given, verify received retry configs before error handling. */
    928    std::string expectedRCs64 =
    929        cfg_.get<std::string>("expect-ech-retry-configs");
    930    if (!expectedRCs64.empty()) {
    931      SECItem receivedRCs;
    932 
    933      /* Get received RetryConfigs. */
    934      if (SSLExp_GetEchRetryConfigs(ssl_fd_.get(), &receivedRCs) !=
    935          SECSuccess) {
    936        std::cerr << "Failed to get ECH retry configs." << std::endl;
    937        return SECFailure;
    938      }
    939 
    940      /* (Re-)Encode received configs to compare with expected ASCII string. */
    941      std::string receivedRCs64(
    942          BTOA_DataToAscii(receivedRCs.data, receivedRCs.len));
    943      /* Remove newlines (for unknown reasons) added during b64 encoding. */
    944      StringRemoveNewlines(receivedRCs64);
    945 
    946      if (receivedRCs64 != expectedRCs64) {
    947        std::cerr << "Received ECH retry configs did not match expected retry "
    948                     "configs."
    949                  << std::endl;
    950        return SECFailure;
    951      }
    952    }
    953 
    954    /* Check if handshake succeeded. */
    955    if (rv != SECSuccess) {
    956      PRErrorCode err = PR_GetError();
    957      std::cerr << "Handshake failed with error=" << err << FormatError(err)
    958                << std::endl;
    959      return SECFailure;
    960    }
    961 
    962    /* If parts of data was sent as EarlyData make sure to send possibly
    963     * unsent rest. This is required to pass bogo resumption tests. */
    964    if (earlyDataSent && earlyDataSent < int(sizeof(kBogoDummyData))) {
    965      int toSend = sizeof(kBogoDummyData) - earlyDataSent;
    966      earlyDataSent =
    967          ssl_SecureWrite(ss, &kBogoDummyData[earlyDataSent], toSend);
    968      if (earlyDataSent != toSend) {
    969        std::cerr
    970            << "Could not send rest of EarlyData after handshake completion"
    971            << std::endl;
    972        return SECFailure;
    973      }
    974    }
    975 
    976    if (cfg_.get<bool>("write-then-read")) {
    977      rv = WriteRead();
    978      if (rv != SECSuccess) {
    979        PRErrorCode err = PR_GetError();
    980        std::cerr << "WriteRead failed with error=" << FormatError(err)
    981                  << std::endl;
    982        return SECFailure;
    983      }
    984    } else {
    985      rv = ReadWrite();
    986      if (rv != SECSuccess) {
    987        PRErrorCode err = PR_GetError();
    988        std::cerr << "ReadWrite failed with error=" << FormatError(err)
    989                  << std::endl;
    990        return SECFailure;
    991      }
    992    }
    993 
    994    SSLChannelInfo info;
    995    rv = SSL_GetChannelInfo(ssl_fd_.get(), &info, sizeof(info));
    996    if (rv != SECSuccess) {
    997      PRErrorCode err = PR_GetError();
    998      std::cerr << "SSL_GetChannelInfo failed with error=" << FormatError(err)
    999                << std::endl;
   1000      return SECFailure;
   1001    }
   1002 
   1003    auto sig_alg = cfg_.get<int>("expect-peer-signature-algorithm");
   1004    if (sig_alg) {
   1005      auto expected = static_cast<SSLSignatureScheme>(sig_alg);
   1006      if (info.signatureScheme != expected) {
   1007        std::cerr << "Unexpected signature scheme" << std::endl;
   1008        return SECFailure;
   1009      }
   1010    }
   1011 
   1012    auto curve_id = cfg_.get<int>("expect-curve-id");
   1013    if (curve_id) {
   1014      auto expected = static_cast<SSLNamedGroup>(curve_id);
   1015      if (info.keaGroup != expected && !(info.keaGroup == ssl_grp_none &&
   1016                                         info.originalKeaGroup == expected)) {
   1017        std::cerr << "Unexpected named group" << std::endl;
   1018        return SECFailure;
   1019      }
   1020    }
   1021 
   1022    if (cfg_.get<bool>("expect-ech-accept")) {
   1023      if (!info.echAccepted) {
   1024        std::cerr << "Expected ECH" << std::endl;
   1025        return SECFailure;
   1026      }
   1027    }
   1028 
   1029    if (cfg_.get<bool>("expect-hrr")) {
   1030      if (!ss->ssl3.hs.helloRetry) {
   1031        std::cerr << "Expected HRR" << std::endl;
   1032        return SECFailure;
   1033      }
   1034    }
   1035 
   1036    str = cfg_.get<std::string>("expect-alpn");
   1037    if (!str.empty()) {
   1038      if (CheckALPN(str) != SECSuccess) {
   1039        std::cerr << "Unexpected ALPN" << std::endl;
   1040        return SECFailure;
   1041      }
   1042    }
   1043 
   1044    /* if resumed */
   1045    if (info.resumed) {
   1046      if (cfg_.get<bool>("expect-session-miss")) {
   1047        std::cerr << "Expected reject Resume" << std::endl;
   1048        return SECFailure;
   1049      }
   1050 
   1051      if (cfg_.get<bool>("on-resume-expect-ech-accept")) {
   1052        if (!info.echAccepted) {
   1053          std::cerr << "Expected ECH on Resume" << std::endl;
   1054          return SECFailure;
   1055        }
   1056      }
   1057 
   1058      if (cfg_.get<bool>("on-resume-expect-reject-early-data")) {
   1059        if (info.earlyDataAccepted) {
   1060          std::cerr << "Expected reject EarlyData" << std::endl;
   1061          return SECFailure;
   1062        }
   1063      }
   1064      if (cfg_.get<bool>("on-resume-expect-accept-early-data")) {
   1065        if (!info.earlyDataAccepted) {
   1066          std::cerr << "Expected accept EarlyData" << std::endl;
   1067          return SECFailure;
   1068        }
   1069      }
   1070 
   1071      /* On successfully resumed connection. */
   1072      if (info.earlyDataAccepted) {
   1073        str = cfg_.get<std::string>("on-resume-expect-alpn");
   1074        if (!str.empty()) {
   1075          if (CheckALPN(str) != SECSuccess) {
   1076            std::cerr << "Unexpected ALPN on Resume" << std::endl;
   1077            return SECFailure;
   1078          }
   1079        } else { /* No real resume but new handshake on EarlyData rejection. */
   1080          /* On Retry... */
   1081          str = cfg_.get<std::string>("on-retry-expect-alpn");
   1082          if (!str.empty()) {
   1083            if (CheckALPN(str) != SECSuccess) {
   1084              std::cerr << "Unexpected ALPN on HRR" << std::endl;
   1085              return SECFailure;
   1086            }
   1087          }
   1088        }
   1089      }
   1090 
   1091    } else { /* Explicitly not on resume */
   1092      if (cfg_.get<bool>("on-initial-expect-ech-accept")) {
   1093        if (!info.echAccepted) {
   1094          std::cerr << "Expected ECH accept on initial connection" << std::endl;
   1095          return SECFailure;
   1096        }
   1097      }
   1098 
   1099      str = cfg_.get<std::string>("on-initial-expect-alpn");
   1100      if (!str.empty()) {
   1101        if (CheckALPN(str) != SECSuccess) {
   1102          std::cerr << "Unexpected ALPN on Initial" << std::endl;
   1103          return SECFailure;
   1104        }
   1105      }
   1106    }
   1107 
   1108    return SECSuccess;
   1109  }
   1110 
   1111 private:
   1112  const Config& cfg_;
   1113  ScopedPRFileDesc pr_fd_;
   1114  ScopedPRFileDesc ssl_fd_;
   1115  ScopedCERTCertificate cert_;
   1116  ScopedSECKEYPrivateKey key_;
   1117 };
   1118 
   1119 std::unique_ptr<const Config> ReadConfig(int argc, char** argv) {
   1120  std::unique_ptr<Config> cfg(new Config());
   1121 
   1122  cfg->AddEntry<int>("port", 0);
   1123  cfg->AddEntry<bool>("ipv6", false);
   1124  cfg->AddEntry<int>("shim-id", 0);
   1125  cfg->AddEntry<bool>("server", false);
   1126  cfg->AddEntry<int>("resume-count", 0);
   1127  cfg->AddEntry<std::string>("key-file", "");
   1128  cfg->AddEntry<std::string>("cert-file", "");
   1129  cfg->AddEntry<int>("min-version", 0);
   1130  cfg->AddEntry<int>("max-version", 0xffff);
   1131  for (auto flag : kVersionDisableFlags) {
   1132    cfg->AddEntry<bool>(flag, false);
   1133  }
   1134  cfg->AddEntry<bool>("fallback-scsv", false);
   1135  cfg->AddEntry<bool>("false-start", false);
   1136  cfg->AddEntry<bool>("enable-ocsp-stapling", false);
   1137  cfg->AddEntry<bool>("write-then-read", false);
   1138  cfg->AddEntry<bool>("require-any-client-certificate", false);
   1139  cfg->AddEntry<bool>("verify-peer", false);
   1140  cfg->AddEntry<bool>("is-handshaker-supported", false);
   1141  cfg->AddEntry<std::string>("handshaker-path", "");  // Ignore this
   1142  cfg->AddEntry<std::string>("advertise-alpn", "");
   1143  cfg->AddEntry<std::string>("on-initial-advertise-alpn", "");
   1144  cfg->AddEntry<std::string>("on-resume-advertise-alpn", "");
   1145  cfg->AddEntry<std::string>("expect-alpn", "");
   1146  cfg->AddEntry<std::string>("on-initial-expect-alpn", "");
   1147  cfg->AddEntry<std::string>("on-resume-expect-alpn", "");
   1148  cfg->AddEntry<std::string>("on-retry-expect-alpn", "");
   1149  cfg->AddEntry<std::vector<int>>("signing-prefs", std::vector<int>());
   1150  cfg->AddEntry<std::vector<int>>("verify-prefs", std::vector<int>());
   1151  cfg->AddEntry<int>("expect-peer-signature-algorithm", 0);
   1152  cfg->AddEntry<std::string>("nss-cipher", "");
   1153  cfg->AddEntry<std::string>("host-name", "");
   1154  cfg->AddEntry<std::string>("ech-config-list", "");
   1155  cfg->AddEntry<std::string>("on-resume-ech-config-list", "");
   1156  cfg->AddEntry<bool>("expect-ech-accept", false);
   1157  cfg->AddEntry<bool>("expect-hrr", false);
   1158  cfg->AddEntry<bool>("enable-ech-grease", false);
   1159  cfg->AddEntry<bool>("enable-early-data", false);
   1160  cfg->AddEntry<bool>("enable-grease", false);
   1161  cfg->AddEntry<bool>("permute-extensions", false);
   1162  cfg->AddEntry<bool>("on-resume-expect-reject-early-data", false);
   1163  cfg->AddEntry<bool>("on-resume-expect-accept-early-data", false);
   1164  cfg->AddEntry<bool>("expect-ticket-supports-early-data", false);
   1165  cfg->AddEntry<bool>("on-resume-shim-writes-first",
   1166                      false);  // Always means 0Rtt write
   1167  cfg->AddEntry<bool>("shim-writes-first",
   1168                      false);  // Unimplemented since not required so far
   1169  cfg->AddEntry<bool>("expect-session-miss", false);
   1170  cfg->AddEntry<std::string>("expect-ech-retry-configs", "");
   1171  cfg->AddEntry<bool>("expect-no-ech-retry-configs", false);
   1172  cfg->AddEntry<bool>("on-initial-expect-ech-accept", false);
   1173  cfg->AddEntry<bool>("on-resume-expect-ech-accept", false);
   1174  cfg->AddEntry<bool>("expect-no-offer-early-data", false);
   1175  /* NSS does not support earlydata rejection reason logging => Ignore. */
   1176  cfg->AddEntry<std::string>("on-resume-expect-early-data-reason", "none");
   1177  cfg->AddEntry<std::string>("on-retry-expect-early-data-reason", "none");
   1178  cfg->AddEntry<std::vector<int>>("curves", std::vector<int>());
   1179  cfg->AddEntry<int>("expect-curve-id", 0);
   1180  cfg->AddEntry<bool>("install-cert-compression-algs", false);
   1181 
   1182  auto rv = cfg->ParseArgs(argc, argv);
   1183  switch (rv) {
   1184    case Config::kOK:
   1185      break;
   1186    case Config::kUnknownFlag:
   1187      exitCodeUnimplemented = true;
   1188    default:
   1189      return nullptr;
   1190  }
   1191 
   1192  // Needed to change to std::unique_ptr<const Config>
   1193  return std::move(cfg);
   1194 }
   1195 
   1196 bool RunCycle(std::unique_ptr<const Config>& cfg, bool resuming = false) {
   1197  std::unique_ptr<TestAgent> agent(TestAgent::Create(*cfg));
   1198  return agent && agent->DoExchange(resuming) == SECSuccess;
   1199 }
   1200 
   1201 int GetExitCode(bool success) {
   1202  if (exitCodeUnimplemented) {
   1203    return 89;
   1204  }
   1205 
   1206  if (success) {
   1207    return 0;
   1208  }
   1209 
   1210  return 1;
   1211 }
   1212 
   1213 int main(int argc, char** argv) {
   1214  std::unique_ptr<const Config> cfg = ReadConfig(argc, argv);
   1215  if (!cfg) {
   1216    return GetExitCode(false);
   1217  }
   1218 
   1219  if (cfg->get<bool>("is-handshaker-supported")) {
   1220    std::cout << "No\n";
   1221    return 0;
   1222  }
   1223 
   1224  if (cfg->get<bool>("server")) {
   1225    if (SSL_ConfigServerSessionIDCache(1024, 0, 0, ".") != SECSuccess) {
   1226      std::cerr << "Couldn't configure session cache\n";
   1227      return 1;
   1228    }
   1229  }
   1230 
   1231  if (NSS_NoDB_Init(nullptr) != SECSuccess) {
   1232    return 1;
   1233  }
   1234 
   1235  // Run a single test cycle.
   1236  bool success = RunCycle(cfg);
   1237 
   1238  int resume_count = cfg->get<int>("resume-count");
   1239  while (success && resume_count-- > 0) {
   1240    std::cout << "Resuming" << std::endl;
   1241    success = RunCycle(cfg, true);
   1242  }
   1243 
   1244  SSL_ClearSessionCache();
   1245 
   1246  if (cfg->get<bool>("server")) {
   1247    SSL_ShutdownServerSessionIDCache();
   1248  }
   1249 
   1250  if (NSS_Shutdown() != SECSuccess) {
   1251    success = false;
   1252  }
   1253 
   1254  return GetExitCode(success);
   1255 }