tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

tortls_nss.c (20996B)


      1 /* Copyright (c) 2003, Roger Dingledine.
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file tortls_nss.c
      8 * \brief Wrapper functions to present a consistent interface to
      9 * TLS and SSL X.509 functions from NSS.
     10 **/
     11 
     12 #include "orconfig.h"
     13 
     14 #define TORTLS_PRIVATE
     15 #define TOR_X509_PRIVATE
     16 
     17 #ifdef _WIN32
     18  #include <winsock2.h>
     19  #include <ws2tcpip.h>
     20 #endif
     21 
     22 #include "lib/crypt_ops/crypto_cipher.h"
     23 #include "lib/crypt_ops/crypto_rand.h"
     24 #include "lib/crypt_ops/crypto_dh.h"
     25 #include "lib/crypt_ops/crypto_util.h"
     26 #include "lib/crypt_ops/crypto_nss_mgt.h"
     27 #include "lib/string/printf.h"
     28 
     29 #include "lib/tls/x509.h"
     30 #include "lib/tls/x509_internal.h"
     31 #include "lib/tls/tortls.h"
     32 #include "lib/tls/tortls_st.h"
     33 #include "lib/tls/tortls_internal.h"
     34 #include "lib/tls/nss_countbytes.h"
     35 #include "lib/log/util_bug.h"
     36 
     37 DISABLE_GCC_WARNING("-Wstrict-prototypes")
     38 #include <prio.h>
     39 // For access to rar sockets.
     40 #include <private/pprio.h>
     41 #include <ssl.h>
     42 #include <sslt.h>
     43 #include <sslproto.h>
     44 #include <certt.h>
     45 ENABLE_GCC_WARNING("-Wstrict-prototypes")
     46 
     47 static SECStatus always_accept_cert_cb(void *, PRFileDesc *, PRBool, PRBool);
     48 
     49 static bool
     50 we_like_ssl_cipher(SSLCipherAlgorithm ca)
     51 {
     52  switch (ca) {
     53    case ssl_calg_null: return false;
     54    case ssl_calg_rc4: return false;
     55    case ssl_calg_rc2: return false;
     56    case ssl_calg_des: return false;
     57    case ssl_calg_3des: return false; /* ???? */
     58    case ssl_calg_idea: return false;
     59    case ssl_calg_fortezza: return false;
     60    case ssl_calg_camellia: return false;
     61    case ssl_calg_seed: return false;
     62 
     63    case ssl_calg_aes: return true;
     64    case ssl_calg_aes_gcm: return true;
     65    case ssl_calg_chacha20: return true;
     66    default: return true;
     67  }
     68 }
     69 static bool
     70 we_like_ssl_kea(SSLKEAType kt)
     71 {
     72  switch (kt) {
     73    case ssl_kea_null: return false;
     74    case ssl_kea_rsa: return false; /* ??? */
     75    case ssl_kea_fortezza: return false;
     76    case ssl_kea_ecdh_psk: return false;
     77    case ssl_kea_dh_psk: return false;
     78 
     79 #ifdef NSS_HAS_ECDH_HYBRID
     80    case ssl_kea_ecdh_hybrid_psk: return false;
     81    case ssl_kea_ecdh_hybrid: return true;
     82 #endif
     83 
     84    case ssl_kea_dh: return true;
     85    case ssl_kea_ecdh: return true;
     86    case ssl_kea_tls13_any: return true;
     87 
     88    case ssl_kea_size: return true; /* prevent a warning. */
     89    default: return true;
     90  }
     91 }
     92 
     93 static bool
     94 we_like_mac_algorithm(SSLMACAlgorithm ma)
     95 {
     96  switch (ma) {
     97    case ssl_mac_null: return false;
     98    case ssl_mac_md5: return false;
     99    case ssl_hmac_md5: return false;
    100 
    101    case ssl_mac_sha: return true;
    102    case ssl_hmac_sha: return true;
    103    case ssl_hmac_sha256: return true;
    104    case ssl_mac_aead: return true;
    105    case ssl_hmac_sha384: return true;
    106    default: return true;
    107  }
    108 }
    109 
    110 static bool
    111 we_like_auth_type(SSLAuthType at)
    112 {
    113  switch (at) {
    114    case ssl_auth_null: return false;
    115    case ssl_auth_rsa_decrypt: return false;
    116    case ssl_auth_dsa: return false;
    117    case ssl_auth_kea: return false;
    118 
    119    case ssl_auth_ecdsa: return true;
    120    case ssl_auth_ecdh_rsa: return true;
    121    case ssl_auth_ecdh_ecdsa: return true;
    122    case ssl_auth_rsa_sign: return true;
    123    case ssl_auth_rsa_pss: return true;
    124    case ssl_auth_psk: return true;
    125    case ssl_auth_tls13_any: return true;
    126 
    127    case ssl_auth_size: return true; /* prevent a warning. */
    128    default: return true;
    129  }
    130 }
    131 
    132 /**
    133 * Return true iff this ciphersuite will be hit by a mozilla bug 1312976,
    134 * which makes TLS key exporters not work with TLS 1.2 non-SHA256
    135 * ciphersuites.
    136 **/
    137 static bool
    138 ciphersuite_has_nss_export_bug(const SSLCipherSuiteInfo *info)
    139 {
    140  /* For more information on the bug, see
    141     https://bugzilla.mozilla.org/show_bug.cgi?id=1312976 */
    142 
    143  /* This bug only exists in TLS 1.2. */
    144  if (info->authType == ssl_auth_tls13_any)
    145    return false;
    146 
    147  /* Sadly, there's no way to get this information from the
    148   * CipherSuiteInfo object itself other than by looking at the
    149   * name.  */
    150  if (strstr(info->cipherSuiteName, "_SHA384") ||
    151      strstr(info->cipherSuiteName, "_SHA512")) {
    152    return true;
    153  }
    154 
    155  return false;
    156 }
    157 
    158 tor_tls_context_t *
    159 tor_tls_context_new(crypto_pk_t *identity,
    160                    unsigned int key_lifetime, unsigned flags, int is_client)
    161 {
    162  SECStatus s;
    163  tor_assert(identity);
    164 
    165  tor_tls_init();
    166 
    167  tor_tls_context_t *ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
    168  ctx->refcnt = 1;
    169 
    170  if (! is_client) {
    171    if (tor_tls_context_init_certificates(ctx, identity,
    172                                          key_lifetime, flags) < 0) {
    173      goto err;
    174    }
    175  }
    176 
    177  {
    178    /* Create the "model" PRFileDesc that we will use to base others on. */
    179    PRFileDesc *tcp = PR_NewTCPSocket();
    180    if (!tcp)
    181      goto err;
    182 
    183    ctx->ctx = SSL_ImportFD(NULL, tcp);
    184    if (!ctx->ctx) {
    185      PR_Close(tcp);
    186      goto err;
    187    }
    188  }
    189 
    190  // Configure the certificate.
    191  if (!is_client) {
    192    s = SSL_ConfigServerCert(ctx->ctx,
    193                             ctx->my_link_cert->cert,
    194                             (SECKEYPrivateKey *)
    195                               crypto_pk_get_nss_privkey(ctx->link_key),
    196                             NULL, /* ExtraServerCertData */
    197                             0 /* DataLen */);
    198    if (s != SECSuccess)
    199      goto err;
    200  }
    201 
    202  // We need a certificate from the other side.
    203  if (is_client) {
    204    // XXXX does this do anything?
    205    s = SSL_OptionSet(ctx->ctx, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
    206    if (s != SECSuccess)
    207      goto err;
    208  }
    209 
    210  // Always accept other side's cert; we'll check it ourselves in goofy
    211  // tor ways.
    212  s = SSL_AuthCertificateHook(ctx->ctx, always_accept_cert_cb, NULL);
    213 
    214  // We allow simultaneous read and write.
    215  s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_FDX, PR_TRUE);
    216  if (s != SECSuccess)
    217    goto err;
    218  // XXXX SSL_ROLLBACK_DETECTION??
    219  // XXXX SSL_ENABLE_ALPN??
    220 
    221  // Force client-mode or server_mode.
    222  s = SSL_OptionSet(ctx->ctx,
    223                is_client ? SSL_HANDSHAKE_AS_CLIENT : SSL_HANDSHAKE_AS_SERVER,
    224                PR_TRUE);
    225  if (s != SECSuccess)
    226    goto err;
    227 
    228  // Disable everything before TLS 1.0; support everything else.
    229  {
    230    SSLVersionRange vrange;
    231    memset(&vrange, 0, sizeof(vrange));
    232    s = SSL_VersionRangeGetSupported(ssl_variant_stream, &vrange);
    233    if (s != SECSuccess)
    234      goto err;
    235    if (vrange.min < SSL_LIBRARY_VERSION_TLS_1_0)
    236      vrange.min = SSL_LIBRARY_VERSION_TLS_1_0;
    237    s = SSL_VersionRangeSet(ctx->ctx, &vrange);
    238    if (s != SECSuccess)
    239      goto err;
    240  }
    241 
    242  // Only support strong ciphers.
    243  {
    244    const PRUint16 *ciphers = SSL_GetImplementedCiphers();
    245    const PRUint16 n_ciphers = SSL_GetNumImplementedCiphers();
    246    PRUint16 i;
    247    for (i = 0; i < n_ciphers; ++i) {
    248      SSLCipherSuiteInfo info;
    249      memset(&info, 0, sizeof(info));
    250      s = SSL_GetCipherSuiteInfo(ciphers[i], &info, sizeof(info));
    251      if (s != SECSuccess)
    252        goto err;
    253      if (BUG(info.cipherSuite != ciphers[i]))
    254        goto err;
    255      int disable = info.effectiveKeyBits < 128 ||
    256        info.macBits < 128 ||
    257        !we_like_ssl_cipher(info.symCipher) ||
    258        !we_like_ssl_kea(info.keaType) ||
    259        !we_like_mac_algorithm(info.macAlgorithm) ||
    260        !we_like_auth_type(info.authType)/* Requires NSS 3.24 */;
    261 
    262      if (ciphersuite_has_nss_export_bug(&info)) {
    263        /* SSL_ExportKeyingMaterial will fail; we can't use this cipher.
    264         */
    265        disable = 1;
    266      }
    267 
    268      s = SSL_CipherPrefSet(ctx->ctx, ciphers[i],
    269                            disable ? PR_FALSE : PR_TRUE);
    270      if (s != SECSuccess)
    271        goto err;
    272    }
    273  }
    274 
    275  // Only use DH and ECDH keys once.
    276  s = SSL_OptionSet(ctx->ctx, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
    277  if (s != SECSuccess)
    278    goto err;
    279 
    280  // don't cache sessions.
    281  s = SSL_OptionSet(ctx->ctx, SSL_NO_CACHE, PR_TRUE);
    282  if (s != SECSuccess)
    283    goto err;
    284 
    285  // Enable DH.
    286  s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_SERVER_DHE, PR_TRUE);
    287  if (s != SECSuccess)
    288    goto err;
    289 
    290  // Set DH and ECDH groups.
    291  SSLNamedGroup groups[] = {
    292      ssl_grp_ec_curve25519,
    293      ssl_grp_ec_secp256r1,
    294      ssl_grp_ec_secp224r1,
    295      ssl_grp_ffdhe_2048,
    296  };
    297  s = SSL_NamedGroupConfig(ctx->ctx, groups, ARRAY_LENGTH(groups));
    298  if (s != SECSuccess)
    299    goto err;
    300 
    301  // These features are off by default, so we don't need to disable them:
    302  //   Session tickets
    303  //   Renegotiation
    304  //   Compression
    305 
    306  goto done;
    307 err:
    308  tor_tls_context_decref(ctx);
    309  ctx = NULL;
    310 done:
    311  return ctx;
    312 }
    313 
    314 void
    315 tor_tls_context_impl_free_(tor_tls_context_impl_t *ctx)
    316 {
    317  if (!ctx)
    318    return;
    319  PR_Close(ctx);
    320 }
    321 
    322 void
    323 tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
    324 {
    325  (void)tls;
    326  (void)buf;
    327  (void)sz;
    328  // AFAICT, NSS doesn't expose its internal state.
    329  buf[0]=0;
    330 }
    331 
    332 void
    333 tor_tls_init(void)
    334 {
    335  tor_nss_countbytes_init();
    336 }
    337 
    338 void
    339 tls_log_errors(tor_tls_t *tls, int severity, int domain,
    340               const char *doing)
    341 {
    342  /* This implementation is a little different for NSS than it is for OpenSSL
    343     -- it logs the last error whether anything actually failed or not. So we
    344     have to only call it when something has gone wrong and we have a real
    345     error to report. */
    346 
    347  (void)tls;
    348  PRErrorCode code = PORT_GetError();
    349  if (tls)
    350    tls->last_error = code;
    351 
    352  const char *addr = tls ? tls->address : NULL;
    353  const char *string = PORT_ErrorToString(code);
    354  const char *name = PORT_ErrorToName(code);
    355  char buf[16];
    356  if (!string)
    357    string = "<unrecognized>";
    358  if (!name) {
    359    tor_snprintf(buf, sizeof(buf), "%d", code);
    360    name = buf;
    361  }
    362 
    363  const char *with = addr ? " with " : "";
    364  addr = addr ? addr : "";
    365  if (doing) {
    366    log_fn(severity, domain, "TLS error %s while %s%s%s: %s",
    367           name, doing, with, addr, string);
    368  } else {
    369    log_fn(severity, domain, "TLS error %s%s%s: %s", name, string,
    370           with, addr);
    371  }
    372 }
    373 const char *
    374 tor_tls_get_last_error_msg(const tor_tls_t *tls)
    375 {
    376  IF_BUG_ONCE(!tls) {
    377    return NULL;
    378  }
    379  if (tls->last_error == 0) {
    380    return NULL;
    381  }
    382  return PORT_ErrorToString((PRErrorCode)tls->last_error);
    383 }
    384 
    385 tor_tls_t *
    386 tor_tls_new(tor_socket_t sock, int is_server)
    387 {
    388  (void)sock;
    389  tor_tls_context_t *ctx = tor_tls_context_get(is_server);
    390 
    391  PRFileDesc *tcp = NULL;
    392  if (SOCKET_OK(sock)) {
    393    tcp = PR_ImportTCPSocket(sock);
    394  } else {
    395    tcp = PR_NewTCPSocket();
    396  }
    397 
    398  if (!tcp)
    399    return NULL;
    400 
    401  PRFileDesc *count = tor_wrap_prfiledesc_with_byte_counter(tcp);
    402  if (! count)
    403    return NULL;
    404 
    405  PRFileDesc *ssl = SSL_ImportFD(ctx->ctx, count);
    406  if (!ssl) {
    407    PR_Close(tcp);
    408    return NULL;
    409  }
    410 
    411  /* even if though the socket is already nonblocking, we need to tell NSS
    412   * about the fact, so that it knows what to do when it says EAGAIN. */
    413  PRSocketOptionData data;
    414  data.option = PR_SockOpt_Nonblocking;
    415  data.value.non_blocking = 1;
    416  if (PR_SetSocketOption(ssl, &data) != PR_SUCCESS) {
    417    PR_Close(ssl);
    418    return NULL;
    419  }
    420 
    421  tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t));
    422  tls->magic = TOR_TLS_MAGIC;
    423  tls->context = ctx;
    424  tor_tls_context_incref(ctx);
    425  tls->ssl = ssl;
    426  tls->socket = sock;
    427  tls->state = TOR_TLS_ST_HANDSHAKE;
    428  tls->isServer = !!is_server;
    429 
    430  if (!is_server) {
    431    /* Set a random SNI */
    432    char *fake_hostname = crypto_random_hostname(4,25, "www.",".com");
    433    SSL_SetURL(tls->ssl, fake_hostname);
    434    tor_free(fake_hostname);
    435  }
    436  SECStatus s = SSL_ResetHandshake(ssl, is_server ? PR_TRUE : PR_FALSE);
    437  if (s != SECSuccess) {
    438    tls_log_errors(tls, LOG_WARN, LD_CRYPTO, "resetting handshake state");
    439  }
    440 
    441  return tls;
    442 }
    443 
    444 /**
    445 * Tell the TLS library that the underlying socket for <b>tls</b> has been
    446 * closed, and the library should not attempt to free that socket itself.
    447 */
    448 void
    449 tor_tls_release_socket(tor_tls_t *tls)
    450 {
    451  if (! tls)
    452    return;
    453 
    454  /* NSS doesn't have the equivalent of BIO_NO_CLOSE.  If you replace the
    455   * fd with something that's invalid, it causes a memory leak in PR_Close.
    456   *
    457   * If there were a way to put the PRFileDesc into the CLOSED state, that
    458   * would prevent it from closing its fd -- but there doesn't seem to be a
    459   * supported way to do that either.
    460   *
    461   * So instead: we make a new sacrificial socket, and replace the original
    462   * socket with that one. This seems to be the best we can do, until we
    463   * redesign the mainloop code enough to make this function unnecessary.
    464   */
    465  tor_socket_t sock =
    466    tor_open_socket_nonblocking(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    467  if (! SOCKET_OK(sock)) {
    468    log_warn(LD_NET, "Out of sockets when trying to shut down an NSS "
    469             "connection");
    470    return;
    471  }
    472 
    473  PRFileDesc *tcp = PR_GetIdentitiesLayer(tls->ssl, PR_NSPR_IO_LAYER);
    474  if (BUG(! tcp)) {
    475    tor_close_socket(sock);
    476    return;
    477  }
    478 
    479  PR_ChangeFileDescNativeHandle(tcp, sock);
    480  /* Tell our socket accounting layer that we don't own this socket any more:
    481   * NSS is about to free it for us. */
    482  tor_release_socket_ownership(sock);
    483 }
    484 
    485 void
    486 tor_tls_impl_free_(tor_tls_impl_t *tls)
    487 {
    488  // XXXX This will close the underlying fd, which our OpenSSL version does
    489  // not do!
    490  if (!tls)
    491    return;
    492 
    493  PR_Close(tls);
    494 }
    495 
    496 int
    497 tor_tls_peer_has_cert(tor_tls_t *tls)
    498 {
    499  CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
    500  int result = (cert != NULL);
    501  CERT_DestroyCertificate(cert);
    502  return result;
    503 }
    504 
    505 MOCK_IMPL(tor_x509_cert_t *,
    506 tor_tls_get_peer_cert,(tor_tls_t *tls))
    507 {
    508  CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
    509  if (cert)
    510    return tor_x509_cert_new(cert);
    511  else
    512    return NULL;
    513 }
    514 
    515 MOCK_IMPL(tor_x509_cert_t *,
    516 tor_tls_get_own_cert,(tor_tls_t *tls))
    517 {
    518  tor_assert(tls);
    519  CERTCertificate *cert = SSL_LocalCertificate(tls->ssl);
    520  if (cert)
    521    return tor_x509_cert_new(cert);
    522  else
    523    return NULL;
    524 }
    525 
    526 MOCK_IMPL(int,
    527 tor_tls_read, (tor_tls_t *tls, char *cp, size_t len))
    528 {
    529  tor_assert(tls);
    530  tor_assert(cp);
    531  tor_assert(len < INT_MAX);
    532 
    533  PRInt32 rv = PR_Read(tls->ssl, cp, (int)len);
    534  // log_debug(LD_NET, "PR_Read(%zu) returned %d", n, (int)rv);
    535  if (rv > 0) {
    536    return rv;
    537  }
    538  if (rv == 0)
    539    return TOR_TLS_CLOSE;
    540  PRErrorCode err = PORT_GetError();
    541  if (err == PR_WOULD_BLOCK_ERROR) {
    542    return TOR_TLS_WANTREAD; // XXXX ????
    543  } else {
    544    tls_log_errors(tls, LOG_NOTICE, LD_CRYPTO, "reading"); // XXXX
    545    return TOR_TLS_ERROR_MISC; // ????
    546  }
    547 }
    548 
    549 int
    550 tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
    551 {
    552  tor_assert(tls);
    553  tor_assert(cp || n == 0);
    554  tor_assert(n < INT_MAX);
    555 
    556  if (n == 0) {
    557    return 0;
    558  }
    559 
    560  PRInt32 rv = PR_Write(tls->ssl, cp, (int)n);
    561  // log_debug(LD_NET, "PR_Write(%zu) returned %d", n, (int)rv);
    562  if (rv > 0) {
    563    return rv;
    564  }
    565  if (rv == 0)
    566    return TOR_TLS_ERROR_MISC;
    567  PRErrorCode err = PORT_GetError();
    568 
    569  if (err == PR_WOULD_BLOCK_ERROR) {
    570    return TOR_TLS_WANTWRITE; // XXXX ????
    571  } else {
    572    tls_log_errors(tls, LOG_NOTICE, LD_CRYPTO, "writing"); // XXXX
    573    return TOR_TLS_ERROR_MISC; // ????
    574  }
    575 }
    576 
    577 int
    578 tor_tls_handshake(tor_tls_t *tls)
    579 {
    580  tor_assert(tls);
    581  tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);
    582 
    583  SECStatus s = SSL_ForceHandshake(tls->ssl);
    584  if (s == SECSuccess) {
    585    tls->state = TOR_TLS_ST_OPEN;
    586    log_debug(LD_NET, "SSL handshake is supposedly complete.");
    587    return TOR_TLS_DONE;
    588  }
    589  if (PORT_GetError() == PR_WOULD_BLOCK_ERROR)
    590    return TOR_TLS_WANTREAD; /* XXXX What about wantwrite? */
    591 
    592  return TOR_TLS_ERROR_MISC; // XXXX
    593 }
    594 
    595 int
    596 tor_tls_get_pending_bytes(tor_tls_t *tls)
    597 {
    598  tor_assert(tls);
    599  int n = SSL_DataPending(tls->ssl);
    600  if (n < 0) {
    601    tls_log_errors(tls, LOG_WARN, LD_CRYPTO, "looking up pending bytes");
    602    return 0;
    603  }
    604  return (int)n;
    605 }
    606 
    607 size_t
    608 tor_tls_get_forced_write_size(tor_tls_t *tls)
    609 {
    610  tor_assert(tls);
    611  /* NSS doesn't have the same "forced write" restriction as openssl. */
    612  return 0;
    613 }
    614 
    615 void
    616 tor_tls_get_n_raw_bytes(tor_tls_t *tls,
    617                        size_t *n_read, size_t *n_written)
    618 {
    619  tor_assert(tls);
    620  tor_assert(n_read);
    621  tor_assert(n_written);
    622  uint64_t r, w;
    623  if (tor_get_prfiledesc_byte_counts(tls->ssl, &r, &w) < 0) {
    624    *n_read = *n_written = 0;
    625    return;
    626  }
    627 
    628  *n_read = (size_t)(r - tls->last_read_count);
    629  *n_written = (size_t)(w - tls->last_write_count);
    630 
    631  tls->last_read_count = r;
    632  tls->last_write_count = w;
    633 }
    634 
    635 int
    636 tor_tls_get_buffer_sizes(tor_tls_t *tls,
    637                         size_t *rbuf_capacity, size_t *rbuf_bytes,
    638                         size_t *wbuf_capacity, size_t *wbuf_bytes)
    639 {
    640  tor_assert(tls);
    641  tor_assert(rbuf_capacity);
    642  tor_assert(rbuf_bytes);
    643  tor_assert(wbuf_capacity);
    644  tor_assert(wbuf_bytes);
    645 
    646  /* This is an acceptable way to say "we can't measure this." */
    647  return -1;
    648 }
    649 
    650 MOCK_IMPL(double,
    651 tls_get_write_overhead_ratio, (void))
    652 {
    653  /* XXX We don't currently have a way to measure this in NSS; we could do that
    654   * XXX with a PRIO layer, but it'll take a little coding. */
    655  return 0.95;
    656 }
    657 
    658 MOCK_IMPL(int,
    659 tor_tls_cert_matches_key,(const tor_tls_t *tls,
    660                          const struct tor_x509_cert_t *cert))
    661 {
    662  tor_assert(cert);
    663  tor_assert(cert->cert);
    664 
    665  int rv = 0;
    666 
    667  tor_x509_cert_t *peercert = tor_tls_get_peer_cert((tor_tls_t *)tls);
    668 
    669  if (!peercert || !peercert->cert)
    670    goto done;
    671 
    672  CERTSubjectPublicKeyInfo *peer_info = &peercert->cert->subjectPublicKeyInfo;
    673  CERTSubjectPublicKeyInfo *cert_info = &cert->cert->subjectPublicKeyInfo;
    674 
    675  /* NSS stores the `len` field in bits, instead of bytes, for the
    676   * `subjectPublicKey` field in CERTSubjectPublicKeyInfo, but
    677   * `SECITEM_ItemsAreEqual()` compares the two bitstrings using a length field
    678   * defined in bytes.
    679   *
    680   * We convert the `len` field from bits to bytes, do our comparison with
    681   * `SECITEM_ItemsAreEqual()`, and reset the length field from bytes to bits
    682   * again.
    683   *
    684   * See also NSS's own implementation of `SECKEY_CopySubjectPublicKeyInfo()`
    685   * in seckey.c in the NSS source tree. This function also does the conversion
    686   * between bits and bytes.
    687   */
    688  const unsigned int peer_info_orig_len = peer_info->subjectPublicKey.len;
    689  const unsigned int cert_info_orig_len = cert_info->subjectPublicKey.len;
    690 
    691  /* We convert the length from bits to bytes, but instead of using NSS's
    692   * `DER_ConvertBitString()` macro on both of peer_info->subjectPublicKey and
    693   * cert_info->subjectPublicKey, we have to do the conversion explicitly since
    694   * both of the two subjectPublicKey fields are allowed to point to the same
    695   * memory address. Otherwise, the bits to bytes conversion would potentially
    696   * be applied twice, which would lead to us comparing too few of the bytes
    697   * when we call SECITEM_ItemsAreEqual(), which would be catastrophic.
    698   */
    699  peer_info->subjectPublicKey.len = ((peer_info_orig_len + 7) >> 3);
    700  cert_info->subjectPublicKey.len = ((cert_info_orig_len + 7) >> 3);
    701 
    702  rv = SECOID_CompareAlgorithmID(&peer_info->algorithm,
    703                                 &cert_info->algorithm) == 0 &&
    704       SECITEM_ItemsAreEqual(&peer_info->subjectPublicKey,
    705                             &cert_info->subjectPublicKey);
    706 
    707  /* Convert from bytes back to bits. */
    708  peer_info->subjectPublicKey.len = peer_info_orig_len;
    709  cert_info->subjectPublicKey.len = cert_info_orig_len;
    710 
    711 done:
    712  tor_x509_cert_free(peercert);
    713 
    714  return rv;
    715 }
    716 
    717 MOCK_IMPL(int,
    718 tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
    719                             const uint8_t *context,
    720                             size_t context_len,
    721                             const char *label))
    722 {
    723  tor_assert(tls);
    724  tor_assert(secrets_out);
    725  tor_assert(context);
    726  tor_assert(label);
    727  tor_assert(strlen(label) <= UINT_MAX);
    728  tor_assert(context_len <= UINT_MAX);
    729 
    730  SECStatus s;
    731  /* Make sure that the error code is set here, so that we can be sure that
    732   * any error code set after a failure was in fact caused by
    733   * SSL_ExportKeyingMaterial. */
    734  PR_SetError(PR_UNKNOWN_ERROR, 0);
    735  s = SSL_ExportKeyingMaterial(tls->ssl,
    736                               label, (unsigned)strlen(label),
    737                               PR_TRUE, context, (unsigned)context_len,
    738                               secrets_out, DIGEST256_LEN);
    739  if (s != SECSuccess) {
    740    tls_log_errors(tls, LOG_WARN, LD_CRYPTO,
    741                   "exporting key material for a TLS handshake");
    742  }
    743 
    744  return (s == SECSuccess) ? 0 : -1;
    745 }
    746 
    747 /** The group we should use for ecdhe when none was selected. */
    748 #define SEC_OID_TOR_DEFAULT_ECDHE_GROUP SEC_OID_ANSIX962_EC_PRIME256V1
    749 
    750 int
    751 evaluate_ecgroup_for_tls(const char *ecgroup)
    752 {
    753  SECOidTag tag;
    754 
    755  if (!ecgroup)
    756    tag = SEC_OID_TOR_DEFAULT_ECDHE_GROUP;
    757  else if (!strcasecmp(ecgroup, "P256"))
    758    tag = SEC_OID_ANSIX962_EC_PRIME256V1;
    759  else if (!strcasecmp(ecgroup, "P224"))
    760    tag = SEC_OID_SECG_EC_SECP224R1;
    761  else
    762    return 0;
    763 
    764  /* I don't think we need any additional tests here for NSS */
    765  (void) tag;
    766 
    767  return 1;
    768 }
    769 
    770 static SECStatus
    771 always_accept_cert_cb(void *arg, PRFileDesc *ssl, PRBool checkSig,
    772                      PRBool isServer)
    773 {
    774  (void)arg;
    775  (void)ssl;
    776  (void)checkSig;
    777  (void)isServer;
    778  return SECSuccess;
    779 }