GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

tortls_nss.c 21.9 KB
Newer Older
1 2
/* Copyright (c) 2003, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
Nick Mathewson's avatar
Nick Mathewson committed
3
 * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 5 6 7 8 9 10 11 12 13 14
/* See LICENSE for licensing information */

/**
 * \file tortls_nss.c
 * \brief Wrapper functions to present a consistent interface to
 * TLS and SSL X.509 functions from NSS.
 **/

#include "orconfig.h"

#define TORTLS_PRIVATE
Nick Mathewson's avatar
Nick Mathewson committed
15
#define TOR_X509_PRIVATE
16

17
#ifdef _WIN32
18 19 20 21 22 23 24 25
  #include <winsock2.h>
  #include <ws2tcpip.h>
#endif

#include "lib/crypt_ops/crypto_cipher.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
Nick Mathewson's avatar
Nick Mathewson committed
26 27 28
#include "lib/crypt_ops/crypto_nss_mgt.h"
#include "lib/string/printf.h"

29
#include "lib/tls/x509.h"
Nick Mathewson's avatar
Nick Mathewson committed
30
#include "lib/tls/x509_internal.h"
31
#include "lib/tls/tortls.h"
Nick Mathewson's avatar
Nick Mathewson committed
32
#include "lib/tls/tortls_st.h"
33
#include "lib/tls/tortls_internal.h"
34
#include "lib/tls/nss_countbytes.h"
35 36
#include "lib/log/util_bug.h"

37
DISABLE_GCC_WARNING(strict-prototypes)
Nick Mathewson's avatar
Nick Mathewson committed
38
#include <prio.h>
39
// For access to rar sockets.
Nick Mathewson's avatar
Nick Mathewson committed
40 41 42 43 44
#include <private/pprio.h>
#include <ssl.h>
#include <sslt.h>
#include <sslproto.h>
#include <certt.h>
45
ENABLE_GCC_WARNING(strict-prototypes)
Nick Mathewson's avatar
Nick Mathewson committed
46 47 48

static SECStatus always_accept_cert_cb(void *, PRFileDesc *, PRBool, PRBool);

49 50 51 52 53 54 55 56
MOCK_IMPL(void,
try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls,
                               tor_x509_cert_impl_t **cert_out,
                               tor_x509_cert_impl_t **id_cert_out))
{
  tor_assert(tls);
  tor_assert(cert_out);
  tor_assert(id_cert_out);
Nick Mathewson's avatar
Nick Mathewson committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
  (void) severity;

  *cert_out = *id_cert_out = NULL;

  CERTCertificate *peer = SSL_PeerCertificate(tls->ssl);
  if (!peer)
    return;
  *cert_out = peer; /* Now owns pointer. */

  CERTCertList *chain = SSL_PeerCertificateChain(tls->ssl);
  CERTCertListNode *c = CERT_LIST_HEAD(chain);
  for (; !CERT_LIST_END(c, chain); c = CERT_LIST_NEXT(c)) {
    if (CERT_CompareCerts(c->cert, peer) == PR_FALSE) {
      *id_cert_out = CERT_DupCertificate(c->cert);
      break;
    }
  }
  CERT_DestroyCertList(chain);
}

static bool
we_like_ssl_cipher(SSLCipherAlgorithm ca)
{
  switch (ca) {
    case ssl_calg_null: return false;
    case ssl_calg_rc4: return false;
    case ssl_calg_rc2: return false;
    case ssl_calg_des: return false;
    case ssl_calg_3des: return false; /* ???? */
    case ssl_calg_idea: return false;
    case ssl_calg_fortezza: return false;
    case ssl_calg_camellia: return false;
    case ssl_calg_seed: return false;

    case ssl_calg_aes: return true;
    case ssl_calg_aes_gcm: return true;
    case ssl_calg_chacha20: return true;
    default: return true;
  }
}
static bool
we_like_ssl_kea(SSLKEAType kt)
{
  switch (kt) {
    case ssl_kea_null: return false;
    case ssl_kea_rsa: return false; /* ??? */
    case ssl_kea_fortezza: return false;
    case ssl_kea_ecdh_psk: return false;
    case ssl_kea_dh_psk: return false;

    case ssl_kea_dh: return true;
    case ssl_kea_ecdh: return true;
    case ssl_kea_tls13_any: return true;

    case ssl_kea_size: return true; /* prevent a warning. */
    default: return true;
  }
}

static bool
we_like_mac_algorithm(SSLMACAlgorithm ma)
{
  switch (ma) {
    case ssl_mac_null: return false;
    case ssl_mac_md5: return false;
    case ssl_hmac_md5: return false;

    case ssl_mac_sha: return true;
    case ssl_hmac_sha: return true;
    case ssl_hmac_sha256: return true;
    case ssl_mac_aead: return true;
    case ssl_hmac_sha384: return true;
    default: return true;
  }
}

static bool
we_like_auth_type(SSLAuthType at)
{
  switch (at) {
    case ssl_auth_null: return false;
    case ssl_auth_rsa_decrypt: return false;
    case ssl_auth_dsa: return false;
    case ssl_auth_kea: return false;

    case ssl_auth_ecdsa: return true;
    case ssl_auth_ecdh_rsa: return true;
    case ssl_auth_ecdh_ecdsa: return true;
    case ssl_auth_rsa_sign: return true;
    case ssl_auth_rsa_pss: return true;
    case ssl_auth_psk: return true;
    case ssl_auth_tls13_any: return true;

    case ssl_auth_size: return true; /* prevent a warning. */
    default: return true;
  }
153 154
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
/**
 * Return true iff this ciphersuite will be hit by a mozilla bug 1312976,
 * which makes TLS key exporters not work with TLS 1.2 non-SHA256
 * ciphersuites.
 **/
static bool
ciphersuite_has_nss_export_bug(const SSLCipherSuiteInfo *info)
{
  /* For more information on the bug, see
     https://bugzilla.mozilla.org/show_bug.cgi?id=1312976 */

  /* This bug only exists in TLS 1.2. */
  if (info->authType == ssl_auth_tls13_any)
    return false;

  /* Sadly, there's no way to get this information from the
   * CipherSuiteInfo object itself other than by looking at the
   * name.  */
  if (strstr(info->cipherSuiteName, "_SHA384") ||
      strstr(info->cipherSuiteName, "_SHA512")) {
    return true;
  }

  return false;
}

181 182 183 184
tor_tls_context_t *
tor_tls_context_new(crypto_pk_t *identity,
                    unsigned int key_lifetime, unsigned flags, int is_client)
{
Nick Mathewson's avatar
Nick Mathewson committed
185
  SECStatus s;
186
  tor_assert(identity);
Nick Mathewson's avatar
Nick Mathewson committed
187

188 189
  tor_tls_init();

Nick Mathewson's avatar
Nick Mathewson committed
190 191 192 193 194 195 196 197 198 199
  tor_tls_context_t *ctx = tor_malloc_zero(sizeof(tor_tls_context_t));
  ctx->refcnt = 1;

  if (! is_client) {
    if (tor_tls_context_init_certificates(ctx, identity,
                                          key_lifetime, flags) < 0) {
      goto err;
    }
  }

Nick Mathewson's avatar
Nick Mathewson committed
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
  {
    /* Create the "model" PRFileDesc that we will use to base others on. */
    PRFileDesc *tcp = PR_NewTCPSocket();
    if (!tcp)
      goto err;

    ctx->ctx = SSL_ImportFD(NULL, tcp);
    if (!ctx->ctx) {
      PR_Close(tcp);
      goto err;
    }
  }

  // Configure the certificate.
  if (!is_client) {
    s = SSL_ConfigServerCert(ctx->ctx,
                             ctx->my_link_cert->cert,
                             (SECKEYPrivateKey *)
                               crypto_pk_get_nss_privkey(ctx->link_key),
                             NULL, /* ExtraServerCertData */
                             0 /* DataLen */);
    if (s != SECSuccess)
      goto err;
  }

  // We need a certificate from the other side.
  if (is_client) {
    // XXXX does this do anything?
    s = SSL_OptionSet(ctx->ctx, SSL_REQUIRE_CERTIFICATE, PR_TRUE);
    if (s != SECSuccess)
      goto err;
  }

  // Always accept other side's cert; we'll check it ourselves in goofy
  // tor ways.
  s = SSL_AuthCertificateHook(ctx->ctx, always_accept_cert_cb, NULL);

  // We allow simultaneous read and write.
  s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_FDX, PR_TRUE);
  if (s != SECSuccess)
    goto err;
  // XXXX SSL_ROLLBACK_DETECTION??
  // XXXX SSL_ENABLE_ALPN??

  // Force client-mode or server_mode.
  s = SSL_OptionSet(ctx->ctx,
                is_client ? SSL_HANDSHAKE_AS_CLIENT : SSL_HANDSHAKE_AS_SERVER,
                PR_TRUE);
  if (s != SECSuccess)
    goto err;

  // Disable everything before TLS 1.0; support everything else.
  {
    SSLVersionRange vrange;
    memset(&vrange, 0, sizeof(vrange));
    s = SSL_VersionRangeGetSupported(ssl_variant_stream, &vrange);
    if (s != SECSuccess)
      goto err;
    if (vrange.min < SSL_LIBRARY_VERSION_TLS_1_0)
      vrange.min = SSL_LIBRARY_VERSION_TLS_1_0;
    s = SSL_VersionRangeSet(ctx->ctx, &vrange);
    if (s != SECSuccess)
      goto err;
  }

  // Only support strong ciphers.
  {
    const PRUint16 *ciphers = SSL_GetImplementedCiphers();
    const PRUint16 n_ciphers = SSL_GetNumImplementedCiphers();
    PRUint16 i;
    for (i = 0; i < n_ciphers; ++i) {
      SSLCipherSuiteInfo info;
      memset(&info, 0, sizeof(info));
      s = SSL_GetCipherSuiteInfo(ciphers[i], &info, sizeof(info));
      if (s != SECSuccess)
        goto err;
      if (BUG(info.cipherSuite != ciphers[i]))
        goto err;
      int disable = info.effectiveKeyBits < 128 ||
        info.macBits < 128 ||
        !we_like_ssl_cipher(info.symCipher) ||
        !we_like_ssl_kea(info.keaType) ||
        !we_like_mac_algorithm(info.macAlgorithm) ||
        !we_like_auth_type(info.authType)/* Requires NSS 3.24 */;

285 286 287 288 289 290
      if (ciphersuite_has_nss_export_bug(&info)) {
        /* SSL_ExportKeyingMaterial will fail; we can't use this cipher.
         */
        disable = 1;
      }

Nick Mathewson's avatar
Nick Mathewson committed
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
      s = SSL_CipherPrefSet(ctx->ctx, ciphers[i],
                            disable ? PR_FALSE : PR_TRUE);
      if (s != SECSuccess)
        goto err;
    }
  }

  // Only use DH and ECDH keys once.
  s = SSL_OptionSet(ctx->ctx, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
  if (s != SECSuccess)
    goto err;

  // don't cache sessions.
  s = SSL_OptionSet(ctx->ctx, SSL_NO_CACHE, PR_TRUE);
  if (s != SECSuccess)
    goto err;

  // Enable DH.
  s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_SERVER_DHE, PR_TRUE);
  if (s != SECSuccess)
    goto err;

  // Set DH and ECDH groups.
  SSLNamedGroup groups[] = {
      ssl_grp_ec_curve25519,
      ssl_grp_ec_secp256r1,
      ssl_grp_ec_secp224r1,
      ssl_grp_ffdhe_2048,
  };
  s = SSL_NamedGroupConfig(ctx->ctx, groups, ARRAY_LENGTH(groups));
  if (s != SECSuccess)
    goto err;

  // These features are off by default, so we don't need to disable them:
  //   Session tickets
  //   Renegotiation
  //   Compression
Nick Mathewson's avatar
Nick Mathewson committed
328 329 330 331 332 333 334

  goto done;
 err:
  tor_tls_context_decref(ctx);
  ctx = NULL;
 done:
  return ctx;
335
}
Nick Mathewson's avatar
Nick Mathewson committed
336

337
void
338
tor_tls_context_impl_free_(tor_tls_context_impl_t *ctx)
339
{
340 341
  if (!ctx)
    return;
Nick Mathewson's avatar
Nick Mathewson committed
342
  PR_Close(ctx);
343
}
344 345 346 347 348 349 350

void
tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz)
{
  (void)tls;
  (void)buf;
  (void)sz;
Nick Mathewson's avatar
Nick Mathewson committed
351 352
  // AFAICT, NSS doesn't expose its internal state.
  buf[0]=0;
353 354 355 356 357
}

void
tor_tls_init(void)
{
358
  tor_nss_countbytes_init();
359
}
Nick Mathewson's avatar
Nick Mathewson committed
360

361 362 363 364
void
tls_log_errors(tor_tls_t *tls, int severity, int domain,
               const char *doing)
{
365 366 367 368
  /* This implementation is a little different for NSS than it is for OpenSSL
     -- it logs the last error whether anything actually failed or not. So we
     have to only call it when something has gone wrong and we have a real
     error to report. */
Nick Mathewson's avatar
Nick Mathewson committed
369

370
  (void)tls;
Nick Mathewson's avatar
Nick Mathewson committed
371 372
  PRErrorCode code = PORT_GetError();

373
  const char *addr = tls ? tls->address : NULL;
Nick Mathewson's avatar
Nick Mathewson committed
374 375 376 377 378 379 380 381 382 383
  const char *string = PORT_ErrorToString(code);
  const char *name = PORT_ErrorToName(code);
  char buf[16];
  if (!string)
    string = "<unrecognized>";
  if (!name) {
    tor_snprintf(buf, sizeof(buf), "%d", code);
    name = buf;
  }

384 385
  const char *with = addr ? " with " : "";
  addr = addr ? addr : "";
Nick Mathewson's avatar
Nick Mathewson committed
386
  if (doing) {
387 388
    log_fn(severity, domain, "TLS error %s while %s%s%s: %s",
           name, doing, with, addr, string);
Nick Mathewson's avatar
Nick Mathewson committed
389
  } else {
390 391
    log_fn(severity, domain, "TLS error %s%s%s: %s", name, string,
           with, addr);
Nick Mathewson's avatar
Nick Mathewson committed
392
  }
393 394 395
}

tor_tls_t *
Nick Mathewson's avatar
Nick Mathewson committed
396
tor_tls_new(tor_socket_t sock, int is_server)
397 398
{
  (void)sock;
Nick Mathewson's avatar
Nick Mathewson committed
399 400
  tor_tls_context_t *ctx = tor_tls_context_get(is_server);

401 402 403 404 405 406 407
  PRFileDesc *tcp = NULL;
  if (SOCKET_OK(sock)) {
    tcp = PR_ImportTCPSocket(sock);
  } else {
    tcp = PR_NewTCPSocket();
  }

Nick Mathewson's avatar
Nick Mathewson committed
408 409 410
  if (!tcp)
    return NULL;

411 412 413 414 415
  PRFileDesc *count = tor_wrap_prfiledesc_with_byte_counter(tcp);
  if (! count)
    return NULL;

  PRFileDesc *ssl = SSL_ImportFD(ctx->ctx, count);
Nick Mathewson's avatar
Nick Mathewson committed
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
  if (!ssl) {
    PR_Close(tcp);
    return NULL;
  }

  tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t));
  tls->magic = TOR_TLS_MAGIC;
  tls->context = ctx;
  tor_tls_context_incref(ctx);
  tls->ssl = ssl;
  tls->socket = sock;
  tls->state = TOR_TLS_ST_HANDSHAKE;
  tls->isServer = !!is_server;

  if (!is_server) {
    /* Set a random SNI */
    char *fake_hostname = crypto_random_hostname(4,25, "www.",".com");
    SSL_SetURL(tls->ssl, fake_hostname);
    tor_free(fake_hostname);
  }
  SECStatus s = SSL_ResetHandshake(ssl, is_server ? PR_TRUE : PR_FALSE);
  if (s != SECSuccess) {
438
    tls_log_errors(tls, LOG_WARN, LD_CRYPTO, "resetting handshake state");
Nick Mathewson's avatar
Nick Mathewson committed
439 440 441
  }

  return tls;
442
}
Nick Mathewson's avatar
Nick Mathewson committed
443

444 445 446 447 448 449 450 451
void
tor_tls_set_renegotiate_callback(tor_tls_t *tls,
                                 void (*cb)(tor_tls_t *, void *arg),
                                 void *arg)
{
  tor_assert(tls);
  (void)cb;
  (void)arg;
Nick Mathewson's avatar
Nick Mathewson committed
452 453

  /* We don't support renegotiation-based TLS with NSS. */
454 455
}

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
/**
 * Tell the TLS library that the underlying socket for <b>tls</b> has been
 * closed, and the library should not attempt to free that socket itself.
 */
void
tor_tls_release_socket(tor_tls_t *tls)
{
  if (! tls)
    return;

  /* NSS doesn't have the equivalent of BIO_NO_CLOSE.  If you replace the
   * fd with something that's invalid, it causes a memory leak in PR_Close.
   *
   * If there were a way to put the PRFileDesc into the CLOSED state, that
   * would prevent it from closing its fd -- but there doesn't seem to be a
   * supported way to do that either.
   *
   * So instead: we make a new sacrificial socket, and replace the original
   * socket with that one. This seems to be the best we can do, until we
   * redesign the mainloop code enough to make this function unnecessary.
   */
  tor_socket_t sock =
    tor_open_socket_nonblocking(AF_INET, SOCK_STREAM, IPPROTO_TCP);
479
  if (! SOCKET_OK(sock)) {
480 481 482 483 484 485 486
    log_warn(LD_NET, "Out of sockets when trying to shut down an NSS "
             "connection");
    return;
  }

  PRFileDesc *tcp = PR_GetIdentitiesLayer(tls->ssl, PR_NSPR_IO_LAYER);
  if (BUG(! tcp)) {
487
    tor_close_socket(sock);
488 489 490 491
    return;
  }

  PR_ChangeFileDescNativeHandle(tcp, sock);
492 493 494
  /* Tell our socket accounting layer that we don't own this socket any more:
   * NSS is about to free it for us. */
  tor_release_socket_ownership(sock);
495 496
}

497
void
Nick Mathewson's avatar
Nick Mathewson committed
498
tor_tls_impl_free_(tor_tls_impl_t *tls)
499
{
Nick Mathewson's avatar
Nick Mathewson committed
500 501
  // XXXX This will close the underlying fd, which our OpenSSL version does
  // not do!
502 503
  if (!tls)
    return;
Nick Mathewson's avatar
Nick Mathewson committed
504 505

  PR_Close(tls);
506 507 508 509 510
}

int
tor_tls_peer_has_cert(tor_tls_t *tls)
{
Nick Mathewson's avatar
Nick Mathewson committed
511 512 513 514
  CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
  int result = (cert != NULL);
  CERT_DestroyCertificate(cert);
  return result;
515
}
Nick Mathewson's avatar
Nick Mathewson committed
516

517 518 519
MOCK_IMPL(tor_x509_cert_t *,
tor_tls_get_peer_cert,(tor_tls_t *tls))
{
Nick Mathewson's avatar
Nick Mathewson committed
520 521 522 523 524
  CERTCertificate *cert = SSL_PeerCertificate(tls->ssl);
  if (cert)
    return tor_x509_cert_new(cert);
  else
    return NULL;
525
}
Nick Mathewson's avatar
Nick Mathewson committed
526

527 528 529 530
MOCK_IMPL(tor_x509_cert_t *,
tor_tls_get_own_cert,(tor_tls_t *tls))
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
531 532 533 534 535
  CERTCertificate *cert = SSL_LocalCertificate(tls->ssl);
  if (cert)
    return tor_x509_cert_new(cert);
  else
    return NULL;
536
}
Nick Mathewson's avatar
Nick Mathewson committed
537

538 539 540 541 542
MOCK_IMPL(int,
tor_tls_read, (tor_tls_t *tls, char *cp, size_t len))
{
  tor_assert(tls);
  tor_assert(cp);
Nick Mathewson's avatar
Nick Mathewson committed
543 544 545 546 547 548 549 550 551 552 553 554 555
  tor_assert(len < INT_MAX);

  PRInt32 rv = PR_Read(tls->ssl, cp, (int)len);
  // log_debug(LD_NET, "PR_Read(%zu) returned %d", n, (int)rv);
  if (rv > 0) {
    return rv;
  }
  if (rv == 0)
    return TOR_TLS_CLOSE;
  PRErrorCode err = PORT_GetError();
  if (err == PR_WOULD_BLOCK_ERROR) {
    return TOR_TLS_WANTREAD; // XXXX ????
  } else {
556
    tls_log_errors(tls, LOG_NOTICE, LD_CRYPTO, "reading"); // XXXX
Nick Mathewson's avatar
Nick Mathewson committed
557 558
    return TOR_TLS_ERROR_MISC; // ????
  }
559
}
Nick Mathewson's avatar
Nick Mathewson committed
560

561 562 563 564
int
tor_tls_write(tor_tls_t *tls, const char *cp, size_t n)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
  tor_assert(cp || n == 0);
  tor_assert(n < INT_MAX);

  PRInt32 rv = PR_Write(tls->ssl, cp, (int)n);
  // log_debug(LD_NET, "PR_Write(%zu) returned %d", n, (int)rv);
  if (rv > 0) {
    return rv;
  }
  if (rv == 0)
    return TOR_TLS_ERROR_MISC;
  PRErrorCode err = PORT_GetError();

  if (err == PR_WOULD_BLOCK_ERROR) {
    return TOR_TLS_WANTWRITE; // XXXX ????
  } else {
580
    tls_log_errors(tls, LOG_NOTICE, LD_CRYPTO, "writing"); // XXXX
Nick Mathewson's avatar
Nick Mathewson committed
581 582
    return TOR_TLS_ERROR_MISC; // ????
  }
583
}
Nick Mathewson's avatar
Nick Mathewson committed
584

585 586 587 588
int
tor_tls_handshake(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
589 590 591 592 593 594 595 596 597 598 599 600
  tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE);

  SECStatus s = SSL_ForceHandshake(tls->ssl);
  if (s == SECSuccess) {
    tls->state = TOR_TLS_ST_OPEN;
    log_debug(LD_NET, "SSL handshake is supposedly complete.");
    return tor_tls_finish_handshake(tls);
  }
  if (PORT_GetError() == PR_WOULD_BLOCK_ERROR)
    return TOR_TLS_WANTREAD; /* XXXX What about wantwrite? */

  return TOR_TLS_ERROR_MISC; // XXXX
601
}
Nick Mathewson's avatar
Nick Mathewson committed
602

603 604 605 606
int
tor_tls_finish_handshake(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
607 608 609
  // We don't need to do any of the weird handshake nonsense stuff on NSS,
  // since we only support recent handshakes.
  return TOR_TLS_DONE;
610
}
Nick Mathewson's avatar
Nick Mathewson committed
611

612 613 614 615
void
tor_tls_unblock_renegotiation(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
616
  /* We don't support renegotiation with NSS. */
617
}
Nick Mathewson's avatar
Nick Mathewson committed
618

619 620 621 622
void
tor_tls_block_renegotiation(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
623
  /* We don't support renegotiation with NSS. */
624
}
Nick Mathewson's avatar
Nick Mathewson committed
625

626 627 628 629
void
tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
630
  /* We don't support renegotiation with NSS. */
631
}
Nick Mathewson's avatar
Nick Mathewson committed
632

633 634 635 636
int
tor_tls_get_pending_bytes(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
637 638
  int n = SSL_DataPending(tls->ssl);
  if (n < 0) {
639
    tls_log_errors(tls, LOG_WARN, LD_CRYPTO, "looking up pending bytes");
Nick Mathewson's avatar
Nick Mathewson committed
640 641 642
    return 0;
  }
  return (int)n;
643
}
Nick Mathewson's avatar
Nick Mathewson committed
644

645 646 647 648
size_t
tor_tls_get_forced_write_size(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
649
  /* NSS doesn't have the same "forced write" restriction as openssl. */
650 651
  return 0;
}
Nick Mathewson's avatar
Nick Mathewson committed
652

653 654 655 656 657 658 659
void
tor_tls_get_n_raw_bytes(tor_tls_t *tls,
                        size_t *n_read, size_t *n_written)
{
  tor_assert(tls);
  tor_assert(n_read);
  tor_assert(n_written);
660 661 662 663 664 665 666 667 668 669 670
  uint64_t r, w;
  if (tor_get_prfiledesc_byte_counts(tls->ssl, &r, &w) < 0) {
    *n_read = *n_written = 0;
    return;
  }

  *n_read = (size_t)(r - tls->last_read_count);
  *n_written = (size_t)(w - tls->last_write_count);

  tls->last_read_count = r;
  tls->last_write_count = w;
671 672 673 674 675 676 677 678 679 680 681 682
}

int
tor_tls_get_buffer_sizes(tor_tls_t *tls,
                         size_t *rbuf_capacity, size_t *rbuf_bytes,
                         size_t *wbuf_capacity, size_t *wbuf_bytes)
{
  tor_assert(tls);
  tor_assert(rbuf_capacity);
  tor_assert(rbuf_bytes);
  tor_assert(wbuf_capacity);
  tor_assert(wbuf_bytes);
Nick Mathewson's avatar
Nick Mathewson committed
683 684

  /* This is an acceptable way to say "we can't measure this." */
685 686
  return -1;
}
Nick Mathewson's avatar
Nick Mathewson committed
687

688 689 690
MOCK_IMPL(double,
tls_get_write_overhead_ratio, (void))
{
Nick Mathewson's avatar
Nick Mathewson committed
691 692 693
  /* XXX We don't currently have a way to measure this in NSS; we could do that
   * XXX with a PRIO layer, but it'll take a little coding. */
  return 0.95;
694 695 696 697 698 699
}

int
tor_tls_used_v1_handshake(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
700 701 702
  /* We don't support or allow the V1 handshake with NSS.
   */
  return 0;
703
}
Nick Mathewson's avatar
Nick Mathewson committed
704

705 706 707 708
int
tor_tls_server_got_renegotiate(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
709
  return 0; /* We don't support renegotiation with NSS */
710
}
Nick Mathewson's avatar
Nick Mathewson committed
711

712 713 714 715 716
MOCK_IMPL(int,
tor_tls_cert_matches_key,(const tor_tls_t *tls,
                          const struct tor_x509_cert_t *cert))
{
  tor_assert(cert);
717 718
  tor_assert(cert->cert);

Nick Mathewson's avatar
Nick Mathewson committed
719 720
  int rv = 0;

721 722 723
  tor_x509_cert_t *peercert = tor_tls_get_peer_cert((tor_tls_t *)tls);

  if (!peercert || !peercert->cert)
Nick Mathewson's avatar
Nick Mathewson committed
724
    goto done;
725 726

  CERTSubjectPublicKeyInfo *peer_info = &peercert->cert->subjectPublicKeyInfo;
Nick Mathewson's avatar
Nick Mathewson committed
727
  CERTSubjectPublicKeyInfo *cert_info = &cert->cert->subjectPublicKeyInfo;
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747

  /* NSS stores the `len` field in bits, instead of bytes, for the
   * `subjectPublicKey` field in CERTSubjectPublicKeyInfo, but
   * `SECITEM_ItemsAreEqual()` compares the two bitstrings using a length field
   * defined in bytes.
   *
   * We convert the `len` field from bits to bytes, do our comparison with
   * `SECITEM_ItemsAreEqual()`, and reset the length field from bytes to bits
   * again.
   *
   * See also NSS's own implementation of `SECKEY_CopySubjectPublicKeyInfo()`
   * in seckey.c in the NSS source tree. This function also does the conversion
   * between bits and bytes.
   */
  unsigned int peer_info_orig_len = peer_info->subjectPublicKey.len;
  unsigned int cert_info_orig_len = cert_info->subjectPublicKey.len;

  peer_info->subjectPublicKey.len = (peer_info_orig_len >> 3);
  cert_info->subjectPublicKey.len = (cert_info_orig_len >> 3);

Nick Mathewson's avatar
Nick Mathewson committed
748 749 750 751 752
  rv = SECOID_CompareAlgorithmID(&peer_info->algorithm,
                                 &cert_info->algorithm) == 0 &&
       SECITEM_ItemsAreEqual(&peer_info->subjectPublicKey,
                             &cert_info->subjectPublicKey);

753 754 755
  peer_info->subjectPublicKey.len = peer_info_orig_len;
  cert_info->subjectPublicKey.len = cert_info_orig_len;

Nick Mathewson's avatar
Nick Mathewson committed
756
 done:
757 758
  tor_x509_cert_free(peercert);

Nick Mathewson's avatar
Nick Mathewson committed
759
  return rv;
760
}
Nick Mathewson's avatar
Nick Mathewson committed
761

762 763 764 765 766
MOCK_IMPL(int,
tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
{
  tor_assert(tls);
  tor_assert(secrets_out);
Nick Mathewson's avatar
Nick Mathewson committed
767 768 769

  /* There's no way to get this information out of NSS. */

770 771
  return -1;
}
Nick Mathewson's avatar
Nick Mathewson committed
772

773 774 775 776 777 778 779 780 781 782
MOCK_IMPL(int,
tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
                             const uint8_t *context,
                             size_t context_len,
                             const char *label))
{
  tor_assert(tls);
  tor_assert(secrets_out);
  tor_assert(context);
  tor_assert(label);
Nick Mathewson's avatar
Nick Mathewson committed
783 784
  tor_assert(strlen(label) <= UINT_MAX);
  tor_assert(context_len <= UINT_MAX);
785

Nick Mathewson's avatar
Nick Mathewson committed
786
  SECStatus s;
787 788 789 790
  /* Make sure that the error code is set here, so that we can be sure that
   * any error code set after a failure was in fact caused by
   * SSL_ExportKeyingMaterial. */
  PR_SetError(PR_UNKNOWN_ERROR, 0);
Nick Mathewson's avatar
Nick Mathewson committed
791 792 793 794
  s = SSL_ExportKeyingMaterial(tls->ssl,
                               label, (unsigned)strlen(label),
                               PR_TRUE, context, (unsigned)context_len,
                               secrets_out, DIGEST256_LEN);
795 796 797 798
  if (s != SECSuccess) {
    tls_log_errors(tls, LOG_WARN, LD_CRYPTO,
                   "exporting key material for a TLS handshake");
  }
Nick Mathewson's avatar
Nick Mathewson committed
799 800

  return (s == SECSuccess) ? 0 : -1;
801 802 803 804 805 806
}

const char *
tor_tls_get_ciphersuite_name(tor_tls_t *tls)
{
  tor_assert(tls);
Nick Mathewson's avatar
Nick Mathewson committed
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824

  SSLChannelInfo channel_info;
  SSLCipherSuiteInfo cipher_info;

  memset(&channel_info, 0, sizeof(channel_info));
  memset(&cipher_info, 0, sizeof(cipher_info));

  SECStatus s = SSL_GetChannelInfo(tls->ssl,
                                   &channel_info, sizeof(channel_info));
  if (s != SECSuccess)
    return NULL;

  s = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
                             &cipher_info, sizeof(cipher_info));
  if (s != SECSuccess)
    return NULL;

  return cipher_info.cipherSuiteName;
825 826
}

Nick Mathewson's avatar
Nick Mathewson committed
827 828 829
/** The group we should use for ecdhe when none was selected. */
#define SEC_OID_TOR_DEFAULT_ECDHE_GROUP SEC_OID_ANSIX962_EC_PRIME256V1

830 831 832
int
evaluate_ecgroup_for_tls(const char *ecgroup)
{
Nick Mathewson's avatar
Nick Mathewson committed
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
  SECOidTag tag;

  if (!ecgroup)
    tag = SEC_OID_TOR_DEFAULT_ECDHE_GROUP;
  else if (!strcasecmp(ecgroup, "P256"))
    tag = SEC_OID_ANSIX962_EC_PRIME256V1;
  else if (!strcasecmp(ecgroup, "P224"))
    tag = SEC_OID_SECG_EC_SECP224R1;
  else
    return 0;

  /* I don't think we need any additional tests here for NSS */
  (void) tag;

  return 1;
}

static SECStatus
always_accept_cert_cb(void *arg, PRFileDesc *ssl, PRBool checkSig,
                      PRBool isServer)
{
  (void)arg;
  (void)ssl;
  (void)checkSig;
  (void)isServer;
  return SECSuccess;
859
}