Commit b1bdecd7 authored by Nick Mathewson's avatar Nick Mathewson 🥔
Browse files

Merge branch 'ntor-resquashed'

Conflicts:
	src/or/cpuworker.c
	src/or/or.h
	src/test/bench.c
parents ee418261 d3de0b91
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@
.dirstamp
# Stuff made by our makefiles
*.bak
# Python droppings
*.pyc

# /
/Makefile
@@ -130,6 +132,8 @@
/src/common/libor-crypto.lib
/src/common/libor-event.a
/src/common/libor-event.lib
/src/common/libcurve25519_donna.a
/src/common/libcurve25519_donna.lib

# /src/config/
/src/config/Makefile
@@ -154,9 +158,10 @@
/src/test/bench.exe
/src/test/test
/src/test/test-child
/src/test/test-ntor-cl
/src/test/test.exe
/src/test/test-child.exe

/src/test/test-ntor-cl.exe

# /src/tools/
/src/tools/tor-checkkey

changes/ntor

0 → 100644
+40 −0
Original line number Diff line number Diff line
  o Major features:

    - Tor now supports a new circuit extension handshake designed by Ian
      Goldberg, Douglas Stebila, and Berkant Ustaoglu. Our original
      circuit extension handshake, later called "TAP", was a bit slow
      (especially on the server side), had a fragile security proof, and
      used weaker keys than we'd now prefer. The new circuit handshake
      uses Dan Bernstein's "curve25519" elliptic-curve Diffie-Hellman
      function, making it significantly more secure than the older
      handshake, and significantly faster. Tor can either use one of two
      built-in pure-C curve25519-donna implementations by Adam Langley,
      or link against the "nacl" library for a tuned version if present.

      The built-in version is very fast for 64-bit systems building with
      GCC. (About 10-14x faster on the server side, and about 7x faster
      on the client side.) The built-in 32-bit version is still faster
      than the old TAP protocol (about 3x), but using libnacl would be
      better on most 32-bit x86 hosts.

      Clients don't currently use this protocol by default, since
      comparatively few clients support it so far. To try it, set
      UseNTorHandshake to 1.

      Implements proposal 216; closes ticket #7202.

    - Tor servers and clients now support a better CREATE/EXTEND cell
      format, allowing the sender to specify multiple address, identity,
      and handshake types.  Implements Robert Ransom's proposal 200;
      closes ticket #7199.

  o Code simplification and refactoring:
    - Split the onion.c file into separate modules for the onion queue
      and the different handshakes it supports.
    - Remove the marshalling/unmarshalling code for sending requests to
      cpuworkers over a socket, and instead just send structs.  The
      recipient will always be the same Tor binary as the sender, so
      any encoding is overkill.

  o Testing:
    - Add benchmark functions to test onion handshake performance.
+99 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ AC_ARG_ENABLE(static-zlib,
   AS_HELP_STRING(--enable-static-zlib, Link against a static zlib library. Requires --with-zlib-dir))
AC_ARG_ENABLE(static-tor,
   AS_HELP_STRING(--enable-static-tor, Create an entirely static Tor binary. Requires --with-openssl-dir and --with-libevent-dir and --with-zlib-dir))
AC_ARG_ENABLE(curve25519,
   AS_HELP_STRING(--disable-curve25519, Build Tor with no curve25519 elliptic-curve crypto support))

if test "$enable_static_tor" = "yes"; then
  enable_static_libevent="yes";
@@ -639,6 +641,103 @@ if test "$upnp" = "true"; then
    fi
fi

dnl ============================================================
dnl We need an implementation of curve25519.

dnl set these defaults.
have_a_curve25519=no
build_curve25519_donna=no
build_curve25519_donna_c64=no
use_curve25519_donna=no
use_curve25519_nacl=no
CURVE25519_LIBS=

if test x$enable_curve25519 != xno; then

  dnl The best choice is using curve25519-donna-c64, but that requires
  dnl that we
  AC_CACHE_CHECK([whether we can use curve25519-donna-c64],
    tor_cv_can_use_curve25519_donna_c64,
    [AC_RUN_IFELSE(
      [AC_LANG_PROGRAM([dnl
        #include <stdint.h>
        typedef unsigned uint128_t __attribute__((mode(TI)));
	], [dnl
          uint64_t a = ((uint64_t)2000000000) * 1000000000;
	  uint64_t b = ((uint64_t)1234567890) << 24;
	  uint128_t c = ((uint128_t)a) * b;
	  return ((uint64_t)(c>>96)) == 522859 &&
	         ((uint64_t)(c>>64))&0xffffffffL == 3604448702L &&
                 ((uint64_t)(c>>32))&0xffffffffL == 2351960064L &&
                 ((uint64_t)(c))&0xffffffffL == 0;
        ])],
	[tor_cv_can_use_curve25519_donna_c64=yes],
        [tor_cv_can_use_curve25519_donna_c64=no],
	[AC_COMPILE_IFELSE(
          [AC_LANG_PROGRAM([dnl
            #include <stdint.h>
            typedef unsigned uint128_t __attribute__((mode(TI)));
            ], [dnl
              uint64_t a = ((uint64_t)2000000000) * 1000000000;
	      uint64_t b = ((uint64_t)1234567890) << 24;
	      uint128_t c = ((uint128_t)a) * b;
	      return ((uint64_t)(c>>96)) == 522859 &&
	             ((uint64_t)(c>>64))&0xffffffffL == 3604448702L &&
                     ((uint64_t)(c>>32))&0xffffffffL == 2351960064L &&
                     ((uint64_t)(c))&0xffffffffL == 0;
            ])],
            [tor_cv_can_use_curve25519_donna_c64=cross],
	    [tor_cv_can_use_curve25519_donna_c64=no])])])

  AC_CACHE_CHECK([whether we can use curve25519 from nacl],
    tor_cv_can_use_curve25519_nacl,
    [tor_saved_LIBS="$LIBS"
     LIBS="$LIBS -lnacl"
     AC_LINK_IFELSE(
       [AC_LANG_PROGRAM([dnl
         #include <crypto_scalarmult_curve25519.h>
         #ifdef crypto_scalarmult_curve25519_ref_BYTES
	 #error Hey, this is the reference implementation!
	 #endif
       ], [
	 unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c);
       ])], [tor_cv_can_use_curve25519_nacl=yes],
       [tor_cv_can_use_curve25519_nacl=no])
     LIBS="$tor_saved_LIBS" ])

   dnl Okay, now we need to figure out which one to actually use. Fall back
   dnl to curve25519-donna.c

   if test x$tor_cv_can_use_curve25519_donna_c64 != xno; then
     build_curve25519_donna_c64=yes
     use_curve25519_donna=yes
   elif test x$tor_cv_can_use_curve25519_nacl = xyes; then
     use_curve25519_nacl=yes
     CURVE25519_LIBS=-lnacl
   else
     build_curve25519_donna=yes
     use_curve25519_donna=yes
   fi
   have_a_curve25519=yes
fi

if test x$have_a_curve25519 = xyes; then
  AC_DEFINE(CURVE25519_ENABLED, 1,
            [Defined if we have a curve25519 implementation])
fi
if test x$use_curve25519_donna = xyes; then
  AC_DEFINE(USE_CURVE25519_DONNA, 1,
            [Defined if we should use an internal curve25519_donna{,_c64} implementation])
fi
if test x$use_curve25519_nacl = xyes; then
  AC_DEFINE(USE_CURVE25519_NACL, 1,
            [Defined if we should use a curve25519 from nacl])
fi
AM_CONDITIONAL(BUILD_CURVE25519_DONNA, test x$build_curve25519_donna = xyes)
AM_CONDITIONAL(BUILD_CURVE25519_DONNA_C64, test x$build_curve25519_donna_c64 = xyes)
AM_CONDITIONAL(CURVE25519_ENABLED, test x$have_a_curve25519 = xyes)
AC_SUBST(CURVE25519_LIBS)

dnl Make sure to enable support for large off_t if available.
AC_SYS_LARGEFILE

+10 −0
Original line number Diff line number Diff line
@@ -1218,6 +1218,16 @@ The following options are useful only for clients (that is, if
    "auto" (recommended) then it is on for all clients that do not set
    FetchUselessDescriptors. (Default: auto)

**UseNTorHandshake** **0**|**1**|**auto**::
    The "ntor" circuit-creation handshake is faster and (we think) more
    secure than the original ("TAP") circuit handshake, but starting to use
    it too early might make your client stand out. If this option is 0, your
    Tor client won't use the ntor handshake. If it's 1, your Tor client
    will use the ntor handshake to extend circuits through servers that
    support it. If this option is "auto" (recommended), then your client
    will use the ntor handshake once enough directory authorities recommend
    it. (Default: auto)

**PathBiasCircThreshold** __NUM__ +

**PathBiasNoticeRate** __NUM__ +
+124 −39
Original line number Diff line number Diff line
@@ -2036,6 +2036,16 @@ crypto_dh_new(int dh_type)
  return NULL;
}

/** Return a copy of <b>dh</b>, sharing its internal state. */
crypto_dh_t *
crypto_dh_dup(const crypto_dh_t *dh)
{
  crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t));
  dh_new->dh = dh->dh;
  DH_up_ref(dh->dh);
  return dh_new;
}

/** Return the length of the DH key in <b>dh</b>, in bytes.
 */
int
@@ -2174,8 +2184,8 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
    goto error;
  }
  secret_len = result;
  if (crypto_expand_key_material(secret_tmp, secret_len,
                                 secret_out, secret_bytes_out)<0)
  if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len,
                                     (uint8_t*)secret_out, secret_bytes_out)<0)
    goto error;
  secret_len = secret_bytes_out;

@@ -2201,15 +2211,18 @@ crypto_dh_compute_secret(int severity, crypto_dh_t *dh,
 * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of
 *    H(K | [00]) | H(K | [01]) | ....
 *
 * This is the key expansion algorithm used in the "TAP" circuit extension
 * mechanism; it shouldn't be used for new protocols.
 *
 * Return 0 on success, -1 on failure.
 */
int
crypto_expand_key_material(const char *key_in, size_t key_in_len,
                           char *key_out, size_t key_out_len)
crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len,
                               uint8_t *key_out, size_t key_out_len)
{
  int i;
  char *cp, *tmp = tor_malloc(key_in_len+1);
  char digest[DIGEST_LEN];
  uint8_t *cp, *tmp = tor_malloc(key_in_len+1);
  uint8_t digest[DIGEST_LEN];

  /* If we try to get more than this amount of key data, we'll repeat blocks.*/
  tor_assert(key_out_len <= DIGEST_LEN*256);
@@ -2218,7 +2231,7 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
  for (cp = key_out, i=0; cp < key_out+key_out_len;
       ++i, cp += DIGEST_LEN) {
    tmp[key_in_len] = i;
    if (crypto_digest(digest, tmp, key_in_len+1))
    if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1))
      goto err;
    memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out)));
  }
@@ -2234,6 +2247,65 @@ crypto_expand_key_material(const char *key_in, size_t key_in_len,
  return -1;
}

/** Expand some secret key material according to RFC5869, using SHA256 as the
 * underlying hash.  The <b>key_in_len</b> bytes at <b>key_in</b> are the
 * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the
 * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt"
 * and "info" parameters respectively.  On success, write <b>key_out_len</b>
 * bytes to <b>key_out</b> and return 0.  On failure, return -1.
 */
int
crypto_expand_key_material_rfc5869_sha256(
                                    const uint8_t *key_in, size_t key_in_len,
                                    const uint8_t *salt_in, size_t salt_in_len,
                                    const uint8_t *info_in, size_t info_in_len,
                                    uint8_t *key_out, size_t key_out_len)
{
  uint8_t prk[DIGEST256_LEN];
  uint8_t tmp[DIGEST256_LEN + 128 + 1];
  uint8_t mac[DIGEST256_LEN];
  int i;
  uint8_t *outp;
  size_t tmp_len;

  crypto_hmac_sha256((char*)prk,
                     (const char*)salt_in, salt_in_len,
                     (const char*)key_in, key_in_len);

  /* If we try to get more than this amount of key data, we'll repeat blocks.*/
  tor_assert(key_out_len <= DIGEST256_LEN * 256);
  tor_assert(info_in_len <= 128);
  memset(tmp, 0, sizeof(tmp));
  outp = key_out;
  i = 1;

  while (key_out_len) {
    size_t n;
    if (i > 1) {
      memcpy(tmp, mac, DIGEST256_LEN);
      memcpy(tmp+DIGEST256_LEN, info_in, info_in_len);
      tmp[DIGEST256_LEN+info_in_len] = i;
      tmp_len = DIGEST256_LEN + info_in_len + 1;
    } else {
      memcpy(tmp, info_in, info_in_len);
      tmp[info_in_len] = i;
      tmp_len = info_in_len + 1;
    }
    crypto_hmac_sha256((char*)mac,
                       (const char*)prk, DIGEST256_LEN,
                       (const char*)tmp, tmp_len);
    n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN;
    memcpy(outp, mac, n);
    key_out_len -= n;
    outp += n;
    ++i;
  }

  memwipe(tmp, 0, sizeof(tmp));
  memwipe(mac, 0, sizeof(mac));
  return 0;
}

/** Free a DH key exchange object.
 */
void
@@ -2272,22 +2344,16 @@ seed_weak_rng(void)
  tor_init_weak_random(seed);
}

/** Seed OpenSSL's random number generator with bytes from the operating
 * system.  <b>startup</b> should be true iff we have just started Tor and
 * have not yet allocated a bunch of fds.  Return 0 on success, -1 on failure.
/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
 * storing it into <b>out</b>.
 */
int
crypto_seed_rng(int startup)
crypto_strongest_rand(uint8_t *out, size_t out_len)
{
  int rand_poll_status = 0;

  /* local variables */
#ifdef _WIN32
  unsigned char buf[ADD_ENTROPY];
  static int provider_set = 0;
  static HCRYPTPROV provider;
#else
  char buf[ADD_ENTROPY];
  static const char *filenames[] = {
    "/dev/srandom", "/dev/urandom", "/dev/random", NULL
  };
@@ -2295,58 +2361,77 @@ crypto_seed_rng(int startup)
  size_t n;
#endif

  /* OpenSSL has a RAND_poll function that knows about more kinds of
   * entropy than we do.  We'll try calling that, *and* calling our own entropy
   * functions.  If one succeeds, we'll accept the RNG as seeded. */
  if (startup || RAND_POLL_IS_SAFE) {
    rand_poll_status = RAND_poll();
    if (rand_poll_status == 0)
      log_warn(LD_CRYPTO, "RAND_poll() failed.");
  }

#ifdef _WIN32
  if (!provider_set) {
    if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
                             CRYPT_VERIFYCONTEXT)) {
      if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
        log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
        return rand_poll_status ? 0 : -1;
        return -1;
      }
    }
    provider_set = 1;
  }
  if (!CryptGenRandom(provider, sizeof(buf), buf)) {
  if (!CryptGenRandom(provider, out_len, out)) {
    log_warn(LD_CRYPTO, "Can't get entropy from CryptoAPI.");
    return rand_poll_status ? 0 : -1;
    return -1;
  }
  RAND_seed(buf, sizeof(buf));
  memwipe(buf, 0, sizeof(buf));
  seed_weak_rng();

  return 0;
#else
  for (i = 0; filenames[i]; ++i) {
    fd = open(filenames[i], O_RDONLY, 0);
    if (fd<0) continue;
    log_info(LD_CRYPTO, "Seeding RNG from \"%s\"", filenames[i]);
    n = read_all(fd, buf, sizeof(buf), 0);
    log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]);
    n = read_all(fd, (char*)out, out_len, 0);
    close(fd);
    if (n != sizeof(buf)) {
    if (n != out_len) {
      log_warn(LD_CRYPTO,
               "Error reading from entropy source (read only %lu bytes).",
               (unsigned long)n);
      return -1;
    }
    RAND_seed(buf, (int)sizeof(buf));
    memwipe(buf, 0, sizeof(buf));
    seed_weak_rng();

    return 0;
  }

  log_warn(LD_CRYPTO, "Cannot seed RNG -- no entropy source found.");
  return rand_poll_status ? 0 : -1;
  log_warn(LD_CRYPTO, "Cannot get strong entropy: no entropy source found.");
  return -1;
#endif
}

/** Seed OpenSSL's random number generator with bytes from the operating
 * system.  <b>startup</b> should be true iff we have just started Tor and
 * have not yet allocated a bunch of fds.  Return 0 on success, -1 on failure.
 */
int
crypto_seed_rng(int startup)
{
  int rand_poll_ok = 0, load_entropy_ok = 0;
  uint8_t buf[ADD_ENTROPY];

  /* OpenSSL has a RAND_poll function that knows about more kinds of
   * entropy than we do.  We'll try calling that, *and* calling our own entropy
   * functions.  If one succeeds, we'll accept the RNG as seeded. */
  if (startup || RAND_POLL_IS_SAFE) {
    rand_poll_ok = RAND_poll();
    if (rand_poll_ok == 0)
      log_warn(LD_CRYPTO, "RAND_poll() failed.");
  }

  load_entropy_ok = !crypto_strongest_rand(buf, sizeof(buf));
  if (load_entropy_ok) {
    RAND_seed(buf, sizeof(buf));
  }

  memwipe(buf, 0, sizeof(buf));
  seed_weak_rng();
  if (rand_poll_ok || load_entropy_ok)
    return 0;
  else
    return -1;
}

/** Write <b>n</b> bytes of strong random data to <b>to</b>. Return 0 on
 * success, -1 on failure.
 */
Loading