mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-09-19 20:02:15 +02:00
Merge branch 'tap-out-phase-1' into 'main'
Implement phase 1 of Proposal 350 (remove TAP onion keys) See merge request tpo/core/tor!822
This commit is contained in:
commit
8bb8ac2d9a
12
changes/tap-out-part-1
Normal file
12
changes/tap-out-part-1
Normal file
@ -0,0 +1,12 @@
|
||||
o Removed features (obsolete):
|
||||
- Relays no longer support the obsolete TAP circuit extension
|
||||
protocol. (For backward compatibility, however, relays still continue to
|
||||
include TAP keys in their descriptors.) Implements part
|
||||
of proposal 350.
|
||||
- Removed some vestigial code for selecting the TAP circuit extension
|
||||
protocol.
|
||||
|
||||
o Minor features (forward-compatibility):
|
||||
- We now correctly parse microdescriptors and router descriptors
|
||||
that do not include TAP onion keys. (For backward compatibility,
|
||||
authorities continue to require these keys.) Implements part of proposal 350.
|
@ -6,7 +6,6 @@ LIBTOR_APP_A_SOURCES += \
|
||||
src/core/crypto/onion_fast.c \
|
||||
src/core/crypto/onion_ntor.c \
|
||||
src/core/crypto/onion_ntor_v3.c \
|
||||
src/core/crypto/onion_tap.c \
|
||||
src/core/crypto/relay_crypto.c
|
||||
|
||||
# ADD_C_FILE: INSERT HEADERS HERE.
|
||||
@ -16,5 +15,4 @@ noinst_HEADERS += \
|
||||
src/core/crypto/onion_fast.h \
|
||||
src/core/crypto/onion_ntor.h \
|
||||
src/core/crypto/onion_ntor_v3.h \
|
||||
src/core/crypto/onion_tap.h \
|
||||
src/core/crypto/relay_crypto.h
|
||||
|
@ -9,9 +9,9 @@
|
||||
* \brief Functions to handle different kinds of circuit extension crypto.
|
||||
*
|
||||
* In this module, we provide a set of abstractions to create a uniform
|
||||
* interface over the three circuit extension handshakes that Tor has used
|
||||
* over the years (TAP, CREATE_FAST, and ntor). These handshakes are
|
||||
* implemented in onion_tap.c, onion_fast.c, and onion_ntor.c respectively.
|
||||
* interface over the circuit extension handshakes that Tor has used
|
||||
* over the years (CREATE_FAST, ntor, hs_ntor, and ntorv3).
|
||||
* These handshakes are implemented in the onion_*.c modules.
|
||||
*
|
||||
* All[*] of these handshakes follow a similar pattern: a client, knowing
|
||||
* some key from the relay it wants to extend through, generates the
|
||||
@ -36,7 +36,6 @@
|
||||
#include "core/crypto/onion_fast.h"
|
||||
#include "core/crypto/onion_ntor.h"
|
||||
#include "core/crypto/onion_ntor_v3.h"
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "feature/relay/router.h"
|
||||
#include "lib/crypt_ops/crypto_dh.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
@ -98,8 +97,6 @@ onion_handshake_state_release(onion_handshake_state_t *state)
|
||||
{
|
||||
switch (state->tag) {
|
||||
case ONION_HANDSHAKE_TYPE_TAP:
|
||||
crypto_dh_free(state->u.tap);
|
||||
state->u.tap = NULL;
|
||||
break;
|
||||
case ONION_HANDSHAKE_TYPE_FAST:
|
||||
fast_handshake_state_free(state->u.fast);
|
||||
@ -139,18 +136,7 @@ onion_skin_create(int type,
|
||||
|
||||
switch (type) {
|
||||
case ONION_HANDSHAKE_TYPE_TAP:
|
||||
if (onion_skin_out_maxlen < TAP_ONIONSKIN_CHALLENGE_LEN)
|
||||
return -1;
|
||||
if (!node->onion_key)
|
||||
return -1;
|
||||
|
||||
if (onion_skin_TAP_create(node->onion_key,
|
||||
&state_out->u.tap,
|
||||
(char*)onion_skin_out) < 0)
|
||||
return -1;
|
||||
|
||||
r = TAP_ONIONSKIN_CHALLENGE_LEN;
|
||||
break;
|
||||
return -1;
|
||||
case ONION_HANDSHAKE_TYPE_FAST:
|
||||
if (fast_onionskin_create(&state_out->u.fast, onion_skin_out) < 0)
|
||||
return -1;
|
||||
@ -288,18 +274,7 @@ onion_skin_server_handshake(int type,
|
||||
|
||||
switch (type) {
|
||||
case ONION_HANDSHAKE_TYPE_TAP:
|
||||
if (reply_out_maxlen < TAP_ONIONSKIN_REPLY_LEN)
|
||||
return -1;
|
||||
if (onionskin_len != TAP_ONIONSKIN_CHALLENGE_LEN)
|
||||
return -1;
|
||||
if (onion_skin_TAP_server_handshake((const char*)onion_skin,
|
||||
keys->onion_key, keys->last_onion_key,
|
||||
(char*)reply_out,
|
||||
(char*)keys_out, keys_out_len)<0)
|
||||
return -1;
|
||||
r = TAP_ONIONSKIN_REPLY_LEN;
|
||||
memcpy(rend_nonce_out, reply_out+DH1024_KEY_LEN, DIGEST_LEN);
|
||||
break;
|
||||
return -1;
|
||||
case ONION_HANDSHAKE_TYPE_FAST:
|
||||
if (reply_out_maxlen < CREATED_FAST_LEN)
|
||||
return -1;
|
||||
@ -474,20 +449,7 @@ onion_skin_client_handshake(int type,
|
||||
|
||||
switch (type) {
|
||||
case ONION_HANDSHAKE_TYPE_TAP:
|
||||
if (reply_len != TAP_ONIONSKIN_REPLY_LEN) {
|
||||
if (msg_out)
|
||||
*msg_out = "TAP reply was not of the correct length.";
|
||||
return -1;
|
||||
}
|
||||
if (onion_skin_TAP_client_handshake(handshake_state->u.tap,
|
||||
(const char*)reply,
|
||||
(char *)keys_out, keys_out_len,
|
||||
msg_out) < 0)
|
||||
return -1;
|
||||
|
||||
memcpy(rend_authenticator_out, reply+DH1024_KEY_LEN, DIGEST_LEN);
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
case ONION_HANDSHAKE_TYPE_FAST:
|
||||
if (reply_len != CREATED_FAST_LEN) {
|
||||
if (msg_out)
|
||||
|
@ -1,246 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2021, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file onion_tap.c
|
||||
* \brief Functions to implement the original Tor circuit extension handshake
|
||||
* (a.k.a TAP).
|
||||
*
|
||||
* The "TAP" handshake is the first one that was widely used in Tor: It
|
||||
* combines RSA1024-OAEP and AES128-CTR to perform a hybrid encryption over
|
||||
* the first message DH1024 key exchange. (The RSA-encrypted part of the
|
||||
* encryption is authenticated; the AES-encrypted part isn't. This was
|
||||
* not a smart choice.)
|
||||
*
|
||||
* We didn't call it "TAP" ourselves -- Ian Goldberg named it in "On the
|
||||
* Security of the Tor Authentication Protocol". (Spoiler: it's secure, but
|
||||
* its security is kind of fragile and implementation dependent. Never modify
|
||||
* this implementation without reading and understanding that paper at least.)
|
||||
*
|
||||
* We have deprecated TAP since the ntor handshake came into general use. It
|
||||
* is still used for hidden service IP and RP connections, however.
|
||||
*
|
||||
* This handshake, like the other circuit-extension handshakes, is
|
||||
* invoked from onion.c.
|
||||
**/
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "app/config/config.h"
|
||||
#include "lib/crypt_ops/crypto_dh.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/crypt_ops/crypto_util.h"
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "feature/stats/rephist.h"
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/** Given a router's 128 byte public key,
|
||||
* stores the following in onion_skin_out:
|
||||
* - [42 bytes] OAEP padding
|
||||
* - [16 bytes] Symmetric key for encrypting blob past RSA
|
||||
* - [70 bytes] g^x part 1 (inside the RSA)
|
||||
* - [58 bytes] g^x part 2 (symmetrically encrypted)
|
||||
*
|
||||
* Stores the DH private key into handshake_state_out for later completion
|
||||
* of the handshake.
|
||||
*
|
||||
* The meeting point/cookies and auth are zeroed out for now.
|
||||
*/
|
||||
int
|
||||
onion_skin_TAP_create(crypto_pk_t *dest_router_key,
|
||||
crypto_dh_t **handshake_state_out,
|
||||
char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
|
||||
{
|
||||
char challenge[DH1024_KEY_LEN];
|
||||
crypto_dh_t *dh = NULL;
|
||||
int dhbytes, pkbytes;
|
||||
|
||||
tor_assert(dest_router_key);
|
||||
tor_assert(handshake_state_out);
|
||||
tor_assert(onion_skin_out);
|
||||
*handshake_state_out = NULL;
|
||||
memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
|
||||
if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
|
||||
goto err;
|
||||
|
||||
dhbytes = crypto_dh_get_bytes(dh);
|
||||
pkbytes = (int) crypto_pk_keysize(dest_router_key);
|
||||
tor_assert(dhbytes == 128);
|
||||
tor_assert(pkbytes == 128);
|
||||
|
||||
if (crypto_dh_get_public(dh, challenge, dhbytes))
|
||||
goto err;
|
||||
|
||||
/* set meeting point, meeting cookie, etc here. Leave zero for now. */
|
||||
if (crypto_pk_obsolete_public_hybrid_encrypt(dest_router_key, onion_skin_out,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN,
|
||||
challenge, DH1024_KEY_LEN,
|
||||
PK_PKCS1_OAEP_PADDING, 1)<0)
|
||||
goto err;
|
||||
|
||||
memwipe(challenge, 0, sizeof(challenge));
|
||||
*handshake_state_out = dh;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
/* LCOV_EXCL_START
|
||||
* We only get here if RSA encryption fails or DH keygen fails. Those
|
||||
* shouldn't be possible. */
|
||||
memwipe(challenge, 0, sizeof(challenge));
|
||||
if (dh) crypto_dh_free(dh);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/** Given an encrypted DH public key as generated by onion_skin_create,
|
||||
* and the private key for this onion router, generate the reply (128-byte
|
||||
* DH plus the first 20 bytes of shared key material), and store the
|
||||
* next key_out_len bytes of key material in key_out.
|
||||
*/
|
||||
int
|
||||
onion_skin_TAP_server_handshake(
|
||||
/*TAP_ONIONSKIN_CHALLENGE_LEN*/
|
||||
const char *onion_skin,
|
||||
crypto_pk_t *private_key,
|
||||
crypto_pk_t *prev_private_key,
|
||||
/*TAP_ONIONSKIN_REPLY_LEN*/
|
||||
char *handshake_reply_out,
|
||||
char *key_out,
|
||||
size_t key_out_len)
|
||||
{
|
||||
char challenge[TAP_ONIONSKIN_CHALLENGE_LEN];
|
||||
crypto_dh_t *dh = NULL;
|
||||
ssize_t len;
|
||||
char *key_material=NULL;
|
||||
size_t key_material_len=0;
|
||||
int i;
|
||||
crypto_pk_t *k;
|
||||
|
||||
len = -1;
|
||||
for (i=0;i<2;++i) {
|
||||
k = i==0?private_key:prev_private_key;
|
||||
if (!k)
|
||||
break;
|
||||
len = crypto_pk_obsolete_private_hybrid_decrypt(k, challenge,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN,
|
||||
onion_skin,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN,
|
||||
PK_PKCS1_OAEP_PADDING,0);
|
||||
if (len>0)
|
||||
break;
|
||||
}
|
||||
if (len<0) {
|
||||
log_info(LD_PROTOCOL,
|
||||
"Couldn't decrypt onionskin: client may be using old onion key");
|
||||
goto err;
|
||||
} else if (len != DH1024_KEY_LEN) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Unexpected onionskin length after decryption: %ld",
|
||||
(long)len);
|
||||
goto err;
|
||||
}
|
||||
|
||||
dh = crypto_dh_new(DH_TYPE_CIRCUIT);
|
||||
if (!dh) {
|
||||
/* LCOV_EXCL_START
|
||||
* Failure to allocate a DH key should be impossible.
|
||||
*/
|
||||
log_warn(LD_BUG, "Couldn't allocate DH key");
|
||||
goto err;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
if (crypto_dh_get_public(dh, handshake_reply_out, DH1024_KEY_LEN)) {
|
||||
/* LCOV_EXCL_START
|
||||
* This can only fail if the length of the key we just allocated is too
|
||||
* big. That should be impossible. */
|
||||
log_info(LD_GENERAL, "crypto_dh_get_public failed.");
|
||||
goto err;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
key_material_len = DIGEST_LEN+key_out_len;
|
||||
key_material = tor_malloc(key_material_len);
|
||||
len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge,
|
||||
DH1024_KEY_LEN, key_material,
|
||||
key_material_len);
|
||||
if (len < 0) {
|
||||
log_info(LD_GENERAL, "crypto_dh_compute_secret failed.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* send back H(K|0) as proof that we learned K. */
|
||||
memcpy(handshake_reply_out+DH1024_KEY_LEN, key_material, DIGEST_LEN);
|
||||
|
||||
/* use the rest of the key material for our shared keys, digests, etc */
|
||||
memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
|
||||
|
||||
memwipe(challenge, 0, sizeof(challenge));
|
||||
memwipe(key_material, 0, key_material_len);
|
||||
tor_free(key_material);
|
||||
crypto_dh_free(dh);
|
||||
return 0;
|
||||
err:
|
||||
memwipe(challenge, 0, sizeof(challenge));
|
||||
if (key_material) {
|
||||
memwipe(key_material, 0, key_material_len);
|
||||
tor_free(key_material);
|
||||
}
|
||||
if (dh) crypto_dh_free(dh);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Finish the client side of the DH handshake.
|
||||
* Given the 128 byte DH reply + 20 byte hash as generated by
|
||||
* onion_skin_server_handshake and the handshake state generated by
|
||||
* onion_skin_create, verify H(K) with the first 20 bytes of shared
|
||||
* key material, then generate key_out_len more bytes of shared key
|
||||
* material and store them in key_out.
|
||||
*
|
||||
* After the invocation, call crypto_dh_free on handshake_state.
|
||||
*/
|
||||
int
|
||||
onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
|
||||
const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
|
||||
char *key_out,
|
||||
size_t key_out_len,
|
||||
const char **msg_out)
|
||||
{
|
||||
ssize_t len;
|
||||
char *key_material=NULL;
|
||||
size_t key_material_len;
|
||||
tor_assert(crypto_dh_get_bytes(handshake_state) == DH1024_KEY_LEN);
|
||||
|
||||
key_material_len = DIGEST_LEN + key_out_len;
|
||||
key_material = tor_malloc(key_material_len);
|
||||
len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state,
|
||||
handshake_reply, DH1024_KEY_LEN, key_material,
|
||||
key_material_len);
|
||||
if (len < 0) {
|
||||
if (msg_out)
|
||||
*msg_out = "DH computation failed.";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (tor_memneq(key_material, handshake_reply+DH1024_KEY_LEN, DIGEST_LEN)) {
|
||||
/* H(K) does *not* match. Something fishy. */
|
||||
if (msg_out)
|
||||
*msg_out = "Digest DOES NOT MATCH on onion handshake. Bug or attack.";
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* use the rest of the key material for our shared keys, digests, etc */
|
||||
memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
|
||||
|
||||
memwipe(key_material, 0, key_material_len);
|
||||
tor_free(key_material);
|
||||
return 0;
|
||||
err:
|
||||
memwipe(key_material, 0, key_material_len);
|
||||
tor_free(key_material);
|
||||
return -1;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2021, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file onion_tap.h
|
||||
* \brief Header file for onion_tap.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_ONION_TAP_H
|
||||
#define TOR_ONION_TAP_H
|
||||
|
||||
#define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\
|
||||
CIPHER_KEY_LEN+\
|
||||
DH1024_KEY_LEN)
|
||||
#define TAP_ONIONSKIN_REPLY_LEN (DH1024_KEY_LEN+DIGEST_LEN)
|
||||
|
||||
struct crypto_dh_t;
|
||||
struct crypto_pk_t;
|
||||
|
||||
int onion_skin_TAP_create(struct crypto_pk_t *router_key,
|
||||
struct crypto_dh_t **handshake_state_out,
|
||||
char *onion_skin_out);
|
||||
|
||||
int onion_skin_TAP_server_handshake(const char *onion_skin,
|
||||
struct crypto_pk_t *private_key,
|
||||
struct crypto_pk_t *prev_private_key,
|
||||
char *handshake_reply_out,
|
||||
char *key_out,
|
||||
size_t key_out_len);
|
||||
|
||||
int onion_skin_TAP_client_handshake(struct crypto_dh_t *handshake_state,
|
||||
const char *handshake_reply,
|
||||
char *key_out,
|
||||
size_t key_out_len,
|
||||
const char **msg_out);
|
||||
|
||||
#endif /* !defined(TOR_ONION_TAP_H) */
|
@ -33,7 +33,6 @@
|
||||
#include "core/crypto/hs_ntor.h"
|
||||
#include "core/crypto/onion_crypto.h"
|
||||
#include "core/crypto/onion_fast.h"
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "core/or/channel.h"
|
||||
@ -412,13 +411,6 @@ onion_populate_cpath(origin_circuit_t *circ)
|
||||
/* We would like every path to support ntor, but we have to allow for some
|
||||
* edge cases. */
|
||||
tor_assert(circuit_get_cpath_len(circ));
|
||||
if (circuit_can_use_tap(circ)) {
|
||||
/* Circuits from clients to intro points, and hidden services to rend
|
||||
* points do not support ntor, because the hidden service protocol does
|
||||
* not include ntor onion keys. This is also true for Single Onion
|
||||
* Services. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (circuit_get_cpath_len(circ) == 1) {
|
||||
/* Allow for bootstrapping: when we're fetching directly from a fallback,
|
||||
@ -890,20 +882,14 @@ circuit_pick_create_handshake(uint8_t *cell_type_out,
|
||||
{
|
||||
/* torspec says: In general, clients SHOULD use CREATE whenever they are
|
||||
* using the TAP handshake, and CREATE2 otherwise. */
|
||||
if (extend_info_supports_ntor(ei)) {
|
||||
*cell_type_out = CELL_CREATE2;
|
||||
/* Only use ntor v3 with exits that support congestion control,
|
||||
* and only when it is enabled. */
|
||||
if (ei->exit_supports_congestion_control &&
|
||||
congestion_control_enabled())
|
||||
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3;
|
||||
else
|
||||
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
|
||||
} else {
|
||||
/* XXXX030 Remove support for deciding to use TAP and EXTEND. */
|
||||
*cell_type_out = CELL_CREATE;
|
||||
*handshake_type_out = ONION_HANDSHAKE_TYPE_TAP;
|
||||
}
|
||||
*cell_type_out = CELL_CREATE2;
|
||||
/* Only use ntor v3 with exits that support congestion control,
|
||||
* and only when it is enabled. */
|
||||
if (ei->exit_supports_congestion_control &&
|
||||
congestion_control_enabled())
|
||||
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR_V3;
|
||||
else
|
||||
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
|
||||
}
|
||||
|
||||
/** Decide whether to use a TAP or ntor handshake for extending to <b>ei</b>
|
||||
@ -924,16 +910,8 @@ circuit_pick_extend_handshake(uint8_t *cell_type_out,
|
||||
uint8_t t;
|
||||
circuit_pick_create_handshake(&t, handshake_type_out, ei);
|
||||
|
||||
/* torspec says: Clients SHOULD use the EXTEND format whenever sending a TAP
|
||||
* handshake... In other cases, clients SHOULD use EXTEND2. */
|
||||
if (*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP) {
|
||||
*cell_type_out = RELAY_COMMAND_EXTEND2;
|
||||
*create_cell_type_out = CELL_CREATE2;
|
||||
} else {
|
||||
/* XXXX030 Remove support for deciding to use TAP and EXTEND. */
|
||||
*cell_type_out = RELAY_COMMAND_EXTEND;
|
||||
*create_cell_type_out = CELL_CREATE;
|
||||
}
|
||||
*cell_type_out = RELAY_COMMAND_EXTEND2;
|
||||
*create_cell_type_out = CELL_CREATE2;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2641,29 +2619,6 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
|
||||
return state->chosen_exit->nickname;
|
||||
}
|
||||
|
||||
/* Is circuit purpose allowed to use the deprecated TAP encryption protocol?
|
||||
* The hidden service protocol still uses TAP for some connections, because
|
||||
* ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
|
||||
static int
|
||||
circuit_purpose_can_use_tap_impl(uint8_t purpose)
|
||||
{
|
||||
return (purpose == CIRCUIT_PURPOSE_S_CONNECT_REND ||
|
||||
purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
|
||||
}
|
||||
|
||||
/* Is circ allowed to use the deprecated TAP encryption protocol?
|
||||
* The hidden service protocol still uses TAP for some connections, because
|
||||
* ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
|
||||
int
|
||||
circuit_can_use_tap(const origin_circuit_t *circ)
|
||||
{
|
||||
tor_assert(circ);
|
||||
tor_assert(circ->cpath);
|
||||
tor_assert(circ->cpath->extend_info);
|
||||
return (circuit_purpose_can_use_tap_impl(circ->base_.purpose) &&
|
||||
extend_info_supports_tap(circ->cpath->extend_info));
|
||||
}
|
||||
|
||||
/* Does circ have an onion key which it's allowed to use? */
|
||||
int
|
||||
circuit_has_usable_onion_key(const origin_circuit_t *circ)
|
||||
@ -2671,8 +2626,7 @@ circuit_has_usable_onion_key(const origin_circuit_t *circ)
|
||||
tor_assert(circ);
|
||||
tor_assert(circ->cpath);
|
||||
tor_assert(circ->cpath->extend_info);
|
||||
return (extend_info_supports_ntor(circ->cpath->extend_info) ||
|
||||
circuit_can_use_tap(circ));
|
||||
return extend_info_supports_ntor(circ->cpath->extend_info);
|
||||
}
|
||||
|
||||
/** Find the circuits that are waiting to find out whether their guards are
|
||||
|
@ -48,7 +48,6 @@ MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
|
||||
|
||||
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
|
||||
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
|
||||
int circuit_can_use_tap(const origin_circuit_t *circ);
|
||||
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
|
||||
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
|
||||
MOCK_DECL(const node_t *,
|
||||
|
@ -2473,7 +2473,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
|
||||
extend_info = extend_info_new(conn->chosen_exit_name+1,
|
||||
digest,
|
||||
NULL, /* Ed25519 ID */
|
||||
NULL, NULL, /* onion keys */
|
||||
NULL, /* onion keys */
|
||||
&addr, conn->socks_request->port,
|
||||
NULL,
|
||||
false);
|
||||
|
@ -331,6 +331,14 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
|
||||
return;
|
||||
}
|
||||
|
||||
/* We no longer accept TAP, for any reason. */
|
||||
if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_TAP) {
|
||||
tor_free(create_cell);
|
||||
/* TODO: Should we collect statistics here? Should we log? */
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mark whether this circuit used TAP in case we need to use this
|
||||
* information for onion service statistics later on. */
|
||||
if (create_cell->handshake_type == ONION_HANDSHAKE_TYPE_FAST ||
|
||||
|
@ -26,7 +26,6 @@ struct onion_handshake_state_t {
|
||||
uint16_t tag;
|
||||
union {
|
||||
struct fast_handshake_state_t *fast;
|
||||
struct crypto_dh_t *tap;
|
||||
struct ntor_handshake_state_t *ntor;
|
||||
struct ntor3_handshake_state_t *ntor3;
|
||||
} u;
|
||||
|
@ -34,8 +34,6 @@ struct extend_info_t {
|
||||
/** IP/Port values for this hop's ORPort(s). Any unused values are set
|
||||
* to a null address. */
|
||||
tor_addr_port_t orports[EXTEND_INFO_MAX_ADDRS];
|
||||
/** TAP onion key for this hop. */
|
||||
crypto_pk_t *onion_key;
|
||||
/** Ntor onion key for this hop. */
|
||||
curve25519_public_key_t curve25519_onion_key;
|
||||
/** True if this hop is to be used as an _exit_,
|
||||
|
@ -33,7 +33,6 @@ extend_info_t *
|
||||
extend_info_new(const char *nickname,
|
||||
const char *rsa_id_digest,
|
||||
const ed25519_public_key_t *ed_id,
|
||||
crypto_pk_t *onion_key,
|
||||
const curve25519_public_key_t *ntor_key,
|
||||
const tor_addr_t *addr, uint16_t port,
|
||||
const protover_summary_flags_t *pv,
|
||||
@ -46,8 +45,6 @@ extend_info_new(const char *nickname,
|
||||
memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t));
|
||||
if (nickname)
|
||||
strlcpy(info->nickname, nickname, sizeof(info->nickname));
|
||||
if (onion_key)
|
||||
info->onion_key = crypto_pk_dup_key(onion_key);
|
||||
if (ntor_key)
|
||||
memcpy(&info->curve25519_onion_key, ntor_key,
|
||||
sizeof(curve25519_public_key_t));
|
||||
@ -100,7 +97,6 @@ extend_info_t *
|
||||
extend_info_from_node(const node_t *node, int for_direct_connect,
|
||||
bool for_exit)
|
||||
{
|
||||
crypto_pk_t *rsa_pubkey = NULL;
|
||||
extend_info_t *info = NULL;
|
||||
tor_addr_port_t ap;
|
||||
int valid_addr = 0;
|
||||
@ -149,13 +145,11 @@ extend_info_from_node(const node_t *node, int for_direct_connect,
|
||||
/* Retrieve the curve25519 pubkey. */
|
||||
const curve25519_public_key_t *curve_pubkey =
|
||||
node_get_curve25519_onion_key(node);
|
||||
rsa_pubkey = node_get_rsa_onion_key(node);
|
||||
|
||||
if (valid_addr && node->ri) {
|
||||
info = extend_info_new(node->ri->nickname,
|
||||
node->identity,
|
||||
ed_pubkey,
|
||||
rsa_pubkey,
|
||||
curve_pubkey,
|
||||
&ap.addr,
|
||||
ap.port,
|
||||
@ -165,7 +159,6 @@ extend_info_from_node(const node_t *node, int for_direct_connect,
|
||||
info = extend_info_new(node->rs->nickname,
|
||||
node->identity,
|
||||
ed_pubkey,
|
||||
rsa_pubkey,
|
||||
curve_pubkey,
|
||||
&ap.addr,
|
||||
ap.port,
|
||||
@ -173,7 +166,6 @@ extend_info_from_node(const node_t *node, int for_direct_connect,
|
||||
for_exit);
|
||||
}
|
||||
|
||||
crypto_pk_free(rsa_pubkey);
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -183,7 +175,6 @@ extend_info_free_(extend_info_t *info)
|
||||
{
|
||||
if (!info)
|
||||
return;
|
||||
crypto_pk_free(info->onion_key);
|
||||
tor_free(info);
|
||||
}
|
||||
|
||||
@ -196,22 +187,9 @@ extend_info_dup(extend_info_t *info)
|
||||
tor_assert(info);
|
||||
newinfo = tor_malloc(sizeof(extend_info_t));
|
||||
memcpy(newinfo, info, sizeof(extend_info_t));
|
||||
if (info->onion_key)
|
||||
newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
|
||||
else
|
||||
newinfo->onion_key = NULL;
|
||||
return newinfo;
|
||||
}
|
||||
|
||||
/* Does ei have a valid TAP key? */
|
||||
int
|
||||
extend_info_supports_tap(const extend_info_t* ei)
|
||||
{
|
||||
tor_assert(ei);
|
||||
/* Valid TAP keys are not NULL */
|
||||
return ei->onion_key != NULL;
|
||||
}
|
||||
|
||||
/* Does ei have a valid ntor key? */
|
||||
int
|
||||
extend_info_supports_ntor(const extend_info_t* ei)
|
||||
|
@ -15,7 +15,6 @@
|
||||
extend_info_t *extend_info_new(const char *nickname,
|
||||
const char *rsa_id_digest,
|
||||
const struct ed25519_public_key_t *ed_id,
|
||||
crypto_pk_t *onion_key,
|
||||
const struct curve25519_public_key_t *ntor_key,
|
||||
const tor_addr_t *addr, uint16_t port,
|
||||
const struct protover_summary_flags_t *pv,
|
||||
@ -27,7 +26,6 @@ void extend_info_free_(extend_info_t *info);
|
||||
#define extend_info_free(info) \
|
||||
FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
|
||||
int extend_info_addr_is_allowed(const tor_addr_t *addr);
|
||||
int extend_info_supports_tap(const extend_info_t* ei);
|
||||
int extend_info_supports_ntor(const extend_info_t* ei);
|
||||
int extend_info_supports_ntor_v3(const extend_info_t *ei);
|
||||
int extend_info_has_preferred_onion_key(const extend_info_t* ei);
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "core/crypto/onion_crypto.h"
|
||||
#include "core/crypto/onion_fast.h"
|
||||
#include "core/crypto/onion_ntor.h"
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "core/or/onion.h"
|
||||
#include "feature/nodelist/networkstatus.h"
|
||||
|
||||
@ -61,10 +60,7 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
|
||||
{
|
||||
switch (cell->cell_type) {
|
||||
case CELL_CREATE:
|
||||
if (cell->handshake_type != ONION_HANDSHAKE_TYPE_TAP &&
|
||||
cell->handshake_type != ONION_HANDSHAKE_TYPE_NTOR)
|
||||
return -1;
|
||||
break;
|
||||
return -1;
|
||||
case CELL_CREATE_FAST:
|
||||
if (cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST)
|
||||
return -1;
|
||||
@ -77,9 +73,7 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
|
||||
|
||||
switch (cell->handshake_type) {
|
||||
case ONION_HANDSHAKE_TYPE_TAP:
|
||||
if (cell->handshake_len != TAP_ONIONSKIN_CHALLENGE_LEN)
|
||||
return -1;
|
||||
break;
|
||||
return -1;
|
||||
case ONION_HANDSHAKE_TYPE_FAST:
|
||||
if (cell->handshake_len != CREATE_FAST_LEN)
|
||||
return -1;
|
||||
@ -160,14 +154,7 @@ create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in)
|
||||
{
|
||||
switch (cell_in->command) {
|
||||
case CELL_CREATE:
|
||||
if (tor_memeq(cell_in->payload, NTOR_CREATE_MAGIC, 16)) {
|
||||
create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
|
||||
NTOR_ONIONSKIN_LEN, cell_in->payload+16);
|
||||
} else {
|
||||
create_cell_init(cell_out, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->payload);
|
||||
}
|
||||
break;
|
||||
return -1;
|
||||
case CELL_CREATE_FAST:
|
||||
create_cell_init(cell_out, CELL_CREATE_FAST, ONION_HANDSHAKE_TYPE_FAST,
|
||||
CREATE_FAST_LEN, cell_in->payload);
|
||||
@ -190,10 +177,7 @@ check_created_cell(const created_cell_t *cell)
|
||||
{
|
||||
switch (cell->cell_type) {
|
||||
case CELL_CREATED:
|
||||
if (cell->handshake_len != TAP_ONIONSKIN_REPLY_LEN &&
|
||||
cell->handshake_len != NTOR_REPLY_LEN)
|
||||
return -1;
|
||||
break;
|
||||
return -1;
|
||||
case CELL_CREATED_FAST:
|
||||
if (cell->handshake_len != CREATED_FAST_LEN)
|
||||
return -1;
|
||||
@ -216,10 +200,7 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
|
||||
|
||||
switch (cell_in->command) {
|
||||
case CELL_CREATED:
|
||||
cell_out->cell_type = CELL_CREATED;
|
||||
cell_out->handshake_len = TAP_ONIONSKIN_REPLY_LEN;
|
||||
memcpy(cell_out->reply, cell_in->payload, TAP_ONIONSKIN_REPLY_LEN);
|
||||
break;
|
||||
return -1;
|
||||
case CELL_CREATED_FAST:
|
||||
cell_out->cell_type = CELL_CREATED_FAST;
|
||||
cell_out->handshake_len = CREATED_FAST_LEN;
|
||||
@ -260,52 +241,21 @@ check_extend_cell(const extend_cell_t *cell)
|
||||
}
|
||||
}
|
||||
if (cell->create_cell.cell_type == CELL_CREATE) {
|
||||
if (cell->cell_type != RELAY_COMMAND_EXTEND)
|
||||
return -1;
|
||||
return -1;
|
||||
} else if (cell->create_cell.cell_type == CELL_CREATE2) {
|
||||
if (cell->cell_type != RELAY_COMMAND_EXTEND2 &&
|
||||
cell->cell_type != RELAY_COMMAND_EXTEND)
|
||||
if (cell->cell_type != RELAY_COMMAND_EXTEND2)
|
||||
return -1;
|
||||
} else {
|
||||
/* In particular, no CREATE_FAST cells are allowed */
|
||||
return -1;
|
||||
}
|
||||
if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST)
|
||||
if (cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_FAST ||
|
||||
cell->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_TAP)
|
||||
return -1;
|
||||
|
||||
return check_create_cell(&cell->create_cell, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
extend_cell_from_extend1_cell_body(extend_cell_t *cell_out,
|
||||
const extend1_cell_body_t *cell)
|
||||
{
|
||||
tor_assert(cell_out);
|
||||
tor_assert(cell);
|
||||
memset(cell_out, 0, sizeof(*cell_out));
|
||||
tor_addr_make_unspec(&cell_out->orport_ipv4.addr);
|
||||
tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
|
||||
|
||||
cell_out->cell_type = RELAY_COMMAND_EXTEND;
|
||||
tor_addr_from_ipv4h(&cell_out->orport_ipv4.addr, cell->ipv4addr);
|
||||
cell_out->orport_ipv4.port = cell->port;
|
||||
if (tor_memeq(cell->onionskin, NTOR_CREATE_MAGIC, 16)) {
|
||||
cell_out->create_cell.cell_type = CELL_CREATE2;
|
||||
cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
|
||||
cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN;
|
||||
memcpy(cell_out->create_cell.onionskin, cell->onionskin + 16,
|
||||
NTOR_ONIONSKIN_LEN);
|
||||
} else {
|
||||
cell_out->create_cell.cell_type = CELL_CREATE;
|
||||
cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
|
||||
cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
|
||||
memcpy(cell_out->create_cell.onionskin, cell->onionskin,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
}
|
||||
memcpy(cell_out->node_id, cell->identity, DIGEST_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
create_cell_from_create2_cell_body(create_cell_t *cell_out,
|
||||
const create2_cell_body_t *cell)
|
||||
@ -408,19 +358,7 @@ extend_cell_parse,(extend_cell_t *cell_out,
|
||||
|
||||
switch (command) {
|
||||
case RELAY_COMMAND_EXTEND:
|
||||
{
|
||||
extend1_cell_body_t *cell = NULL;
|
||||
if (extend1_cell_body_parse(&cell, payload, payload_length)<0 ||
|
||||
cell == NULL) {
|
||||
if (cell)
|
||||
extend1_cell_body_free(cell);
|
||||
return -1;
|
||||
}
|
||||
int r = extend_cell_from_extend1_cell_body(cell_out, cell);
|
||||
extend1_cell_body_free(cell);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
return -1;
|
||||
break;
|
||||
case RELAY_COMMAND_EXTEND2:
|
||||
{
|
||||
@ -479,13 +417,7 @@ extended_cell_parse(extended_cell_t *cell_out,
|
||||
|
||||
switch (command) {
|
||||
case RELAY_COMMAND_EXTENDED:
|
||||
if (payload_len != TAP_ONIONSKIN_REPLY_LEN)
|
||||
return -1;
|
||||
cell_out->cell_type = RELAY_COMMAND_EXTENDED;
|
||||
cell_out->created_cell.cell_type = CELL_CREATED;
|
||||
cell_out->created_cell.handshake_len = TAP_ONIONSKIN_REPLY_LEN;
|
||||
memcpy(cell_out->created_cell.reply, payload, TAP_ONIONSKIN_REPLY_LEN);
|
||||
break;
|
||||
return -1;
|
||||
case RELAY_COMMAND_EXTENDED2:
|
||||
{
|
||||
cell_out->cell_type = RELAY_COMMAND_EXTENDED2;
|
||||
@ -627,26 +559,7 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
|
||||
|
||||
switch (cell_in->cell_type) {
|
||||
case RELAY_COMMAND_EXTEND:
|
||||
{
|
||||
if (BUG(cell_in->create_cell.handshake_type ==
|
||||
ONION_HANDSHAKE_TYPE_NTOR_V3)) {
|
||||
log_warn(LD_BUG, "Extend cells cannot contain ntorv3!");
|
||||
return -1;
|
||||
}
|
||||
*command_out = RELAY_COMMAND_EXTEND;
|
||||
*len_out = 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN;
|
||||
set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
|
||||
set_uint16(p+4, htons(cell_in->orport_ipv4.port));
|
||||
if (cell_in->create_cell.handshake_type == ONION_HANDSHAKE_TYPE_NTOR) {
|
||||
memcpy(p+6, NTOR_CREATE_MAGIC, 16);
|
||||
memcpy(p+22, cell_in->create_cell.onionskin, NTOR_ONIONSKIN_LEN);
|
||||
} else {
|
||||
memcpy(p+6, cell_in->create_cell.onionskin,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
}
|
||||
memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, cell_in->node_id, DIGEST_LEN);
|
||||
}
|
||||
break;
|
||||
return -1;
|
||||
case RELAY_COMMAND_EXTEND2:
|
||||
{
|
||||
uint8_t n_specifiers = 1;
|
||||
@ -737,13 +650,7 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out,
|
||||
|
||||
switch (cell_in->cell_type) {
|
||||
case RELAY_COMMAND_EXTENDED:
|
||||
{
|
||||
*command_out = RELAY_COMMAND_EXTENDED;
|
||||
*len_out = TAP_ONIONSKIN_REPLY_LEN;
|
||||
memcpy(payload_out, cell_in->created_cell.reply,
|
||||
TAP_ONIONSKIN_REPLY_LEN);
|
||||
}
|
||||
break;
|
||||
return -1;
|
||||
case RELAY_COMMAND_EXTENDED2:
|
||||
{
|
||||
*command_out = RELAY_COMMAND_EXTENDED2;
|
||||
|
@ -389,7 +389,7 @@ protocol_list_supports_protocol_or_later(const char *list,
|
||||
/* All protocol version that this relay version supports. */
|
||||
#define PR_CONFLUX_V "1"
|
||||
#define PR_CONS_V "1-2"
|
||||
#define PR_DESC_V "1-2"
|
||||
#define PR_DESC_V "1-3"
|
||||
#define PR_DIRCACHE_V "2"
|
||||
#define PR_FLOWCTRL_V "1-2"
|
||||
#define PR_HSDIR_V "2"
|
||||
@ -401,9 +401,9 @@ protocol_list_supports_protocol_or_later(const char *list,
|
||||
#else
|
||||
#define PR_LINKAUTH_V "3"
|
||||
#endif
|
||||
#define PR_MICRODESC_V "1-2"
|
||||
#define PR_MICRODESC_V "1-3"
|
||||
#define PR_PADDING_V "2"
|
||||
#define PR_RELAY_V "1-4"
|
||||
#define PR_RELAY_V "2-4"
|
||||
|
||||
/** Return the string containing the supported version for the given protocol
|
||||
* type. */
|
||||
|
@ -316,7 +316,8 @@ addr_is_a_configured_bridge(const tor_addr_t *addr,
|
||||
/** If we have a bridge configured whose digest matches
|
||||
* <b>ei->identity_digest</b>, or a bridge with no known digest whose address
|
||||
* matches <b>ei->addr</b>:<b>ei->port</b>, return 1. Else return 0.
|
||||
* If <b>ei->onion_key</b> is NULL, check for address/port matches only.
|
||||
* If <b>ei</b> has no onion key configured, check for address/port matches
|
||||
* only.
|
||||
*
|
||||
* Note that if the extend_info_t contains multiple addresses, we return true
|
||||
* only if _every_ address is a bridge.
|
||||
@ -324,7 +325,8 @@ addr_is_a_configured_bridge(const tor_addr_t *addr,
|
||||
int
|
||||
extend_info_is_a_configured_bridge(const extend_info_t *ei)
|
||||
{
|
||||
const char *digest = ei->onion_key ? ei->identity_digest : NULL;
|
||||
const char *digest = curve25519_public_key_is_ok(&ei->curve25519_onion_key)
|
||||
? ei->identity_digest : NULL;
|
||||
const tor_addr_port_t *ap1 = NULL, *ap2 = NULL;
|
||||
if (! tor_addr_is_null(&ei->orports[0].addr))
|
||||
ap1 = &ei->orports[0];
|
||||
|
@ -3870,8 +3870,12 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
|
||||
size_t keylen;
|
||||
smartlist_t *chunks = smartlist_new();
|
||||
char *output = NULL;
|
||||
crypto_pk_t *rsa_pubkey = router_get_rsa_onion_pkey(ri->onion_pkey,
|
||||
ri->onion_pkey_len);
|
||||
crypto_pk_t *rsa_pubkey = router_get_rsa_onion_pkey(ri->tap_onion_pkey,
|
||||
ri->tap_onion_pkey_len);
|
||||
if (!rsa_pubkey) {
|
||||
/* We do not yet support creating MDs for relays without TAP onion keys. */
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (crypto_pk_write_public_key_to_string(rsa_pubkey, &key, &keylen)<0)
|
||||
goto done;
|
||||
|
@ -762,6 +762,16 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
|
||||
log_info(LD_DIR, "Assessing new descriptor: %s: %s",
|
||||
ri->nickname, ri->platform);
|
||||
|
||||
/* For now, TAP keys are still required. */
|
||||
if (! ri->tap_onion_pkey) {
|
||||
log_info(LD_DIRSERV, "Rejecting descriptor from %s (source: %s); "
|
||||
"it has no TAP key.",
|
||||
router_describe(ri), source);
|
||||
*msg = "Missing TAP key in descriptor.";
|
||||
r = ROUTER_AUTHDIR_REJECTS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Check whether this descriptor is semantically identical to the last one
|
||||
* from this server. (We do this here and not in router_add_to_routerlist
|
||||
* because we want to be able to accept the newest router descriptor that
|
||||
|
@ -30,7 +30,7 @@
|
||||
/** List of tokens recognized in microdescriptors */
|
||||
// clang-format off
|
||||
static token_rule_t microdesc_token_table[] = {
|
||||
T1_START("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024),
|
||||
T1_START("onion-key", K_ONION_KEY, NO_ARGS, OPT_KEY_1024),
|
||||
T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
|
||||
T0N("id", K_ID, GE(2), NO_OBJ ),
|
||||
T0N("a", K_A, GE(1), NO_OBJ ),
|
||||
@ -200,14 +200,11 @@ microdesc_parse_fields(microdesc_t *md,
|
||||
}
|
||||
|
||||
tok = find_by_keyword(tokens, K_ONION_KEY);
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
if (tok && tok->key && !crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_DIR,
|
||||
"Relay's onion key had invalid exponent.");
|
||||
goto err;
|
||||
}
|
||||
md->onion_pkey = tor_memdup(tok->object_body, tok->object_size);
|
||||
md->onion_pkey_len = tok->object_size;
|
||||
crypto_pk_free(tok->key);
|
||||
|
||||
if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
|
||||
curve25519_public_key_t k;
|
||||
|
@ -215,6 +215,16 @@ token_check_object(memarea_t *area, const char *kwd,
|
||||
RET_ERR(ebuf);
|
||||
}
|
||||
break;
|
||||
case OPT_KEY_1024:
|
||||
/* If there is anything, it must be a 1024-bit RSA key. */
|
||||
if (tok->object_body && !tok->key) {
|
||||
tor_snprintf(ebuf, sizeof(ebuf), "Unexpected object for %s", kwd);
|
||||
RET_ERR(ebuf);
|
||||
}
|
||||
if (!tok->key) {
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case NEED_KEY_1024: /* There must be a 1024-bit public key. */
|
||||
if (tok->key && crypto_pk_num_bits(tok->key) != PK_BYTES*8) {
|
||||
tor_snprintf(ebuf, sizeof(ebuf), "Wrong size on key for %s: %d bits",
|
||||
@ -395,7 +405,8 @@ get_next_token(memarea_t *area,
|
||||
}
|
||||
|
||||
if (!strcmp(tok->object_type, "RSA PUBLIC KEY")) { /* If it's a public key */
|
||||
if (o_syn != NEED_KEY && o_syn != NEED_KEY_1024 && o_syn != OBJ_OK) {
|
||||
if (o_syn != OPT_KEY_1024 && o_syn != NEED_KEY &&
|
||||
o_syn != NEED_KEY_1024 && o_syn != OBJ_OK) {
|
||||
RET_ERR("Unexpected public key.");
|
||||
}
|
||||
tok->key = crypto_pk_asn1_decode(tok->object_body, tok->object_size);
|
||||
|
@ -220,6 +220,7 @@ typedef struct directory_token_t {
|
||||
typedef enum {
|
||||
NO_OBJ, /**< No object, ever. */
|
||||
NEED_OBJ, /**< Object is required. */
|
||||
OPT_KEY_1024, /**< If object is present, it must be a 1024 bit public key */
|
||||
NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
|
||||
NEED_KEY, /**< Object is required, and must be a public key. */
|
||||
OBJ_OK, /**< Object is optional. */
|
||||
|
@ -90,7 +90,7 @@ const token_rule_t routerdesc_token_table[] = {
|
||||
T1_START( "router", K_ROUTER, GE(5), NO_OBJ ),
|
||||
T01("ipv6-policy", K_IPV6_POLICY, CONCAT_ARGS, NO_OBJ),
|
||||
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
|
||||
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
|
||||
T01("onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
|
||||
T1("ntor-onion-key", K_ONION_KEY_NTOR, GE(1), NO_OBJ ),
|
||||
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
|
||||
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
|
||||
@ -107,7 +107,7 @@ const token_rule_t routerdesc_token_table[] = {
|
||||
T1("identity-ed25519", K_IDENTITY_ED25519, NO_ARGS, NEED_OBJ ),
|
||||
T1("master-key-ed25519", K_MASTER_KEY_ED25519, GE(1), NO_OBJ ),
|
||||
T1("router-sig-ed25519", K_ROUTER_SIG_ED25519, GE(1), NO_OBJ ),
|
||||
T1("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
|
||||
T01("onion-key-crosscert", K_ONION_KEY_CROSSCERT, NO_ARGS, NEED_OBJ ),
|
||||
T1("ntor-onion-key-crosscert", K_NTOR_ONION_KEY_CROSSCERT,
|
||||
EQ(1), NEED_OBJ ),
|
||||
|
||||
@ -595,15 +595,17 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
if (parse_iso_time(tok->args[0], &router->cache_info.published_on) < 0)
|
||||
goto err;
|
||||
|
||||
tok = find_by_keyword(tokens, K_ONION_KEY);
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_DIR,
|
||||
"Relay's onion key had invalid exponent.");
|
||||
goto err;
|
||||
tok = find_opt_by_keyword(tokens, K_ONION_KEY);
|
||||
if (tok) {
|
||||
if (!crypto_pk_public_exponent_ok(tok->key)) {
|
||||
log_warn(LD_DIR,
|
||||
"Relay's onion key had invalid exponent.");
|
||||
goto err;
|
||||
}
|
||||
router->tap_onion_pkey = tor_memdup(tok->object_body, tok->object_size);
|
||||
router->tap_onion_pkey_len = tok->object_size;
|
||||
crypto_pk_free(tok->key);
|
||||
}
|
||||
router->onion_pkey = tor_memdup(tok->object_body, tok->object_size);
|
||||
router->onion_pkey_len = tok->object_size;
|
||||
crypto_pk_free(tok->key);
|
||||
|
||||
if ((tok = find_opt_by_keyword(tokens, K_ONION_KEY_NTOR))) {
|
||||
curve25519_public_key_t k;
|
||||
@ -627,26 +629,68 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
{
|
||||
directory_token_t *ed_sig_tok, *ed_cert_tok, *cc_tap_tok, *cc_ntor_tok,
|
||||
*master_key_tok;
|
||||
ed_sig_tok = find_opt_by_keyword(tokens, K_ROUTER_SIG_ED25519);
|
||||
ed_cert_tok = find_opt_by_keyword(tokens, K_IDENTITY_ED25519);
|
||||
master_key_tok = find_opt_by_keyword(tokens, K_MASTER_KEY_ED25519);
|
||||
ed_sig_tok = find_by_keyword(tokens, K_ROUTER_SIG_ED25519);
|
||||
ed_cert_tok = find_by_keyword(tokens, K_IDENTITY_ED25519);
|
||||
master_key_tok = find_by_keyword(tokens, K_MASTER_KEY_ED25519);
|
||||
cc_ntor_tok = find_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT);
|
||||
/* This, and only this, is optional. */
|
||||
cc_tap_tok = find_opt_by_keyword(tokens, K_ONION_KEY_CROSSCERT);
|
||||
cc_ntor_tok = find_opt_by_keyword(tokens, K_NTOR_ONION_KEY_CROSSCERT);
|
||||
int n_ed_toks = !!ed_sig_tok + !!ed_cert_tok +
|
||||
!!cc_tap_tok + !!cc_ntor_tok;
|
||||
if ((n_ed_toks != 0 && n_ed_toks != 4) ||
|
||||
(n_ed_toks == 4 && !router->onion_curve25519_pkey)) {
|
||||
log_warn(LD_DIR, "Router descriptor with only partial ed25519/"
|
||||
"cross-certification support");
|
||||
|
||||
if (bool_neq(cc_tap_tok==NULL, router->tap_onion_pkey==NULL)) {
|
||||
log_warn(LD_DIR, "Router descriptor had only one of (onion-key, "
|
||||
"onion-key-crosscert).");
|
||||
goto err;
|
||||
}
|
||||
if (master_key_tok && !ed_sig_tok) {
|
||||
log_warn(LD_DIR, "Router descriptor has ed25519 master key but no "
|
||||
"certificate");
|
||||
|
||||
IF_BUG_ONCE(! (ed_sig_tok && ed_cert_tok&& cc_ntor_tok &&master_key_tok)) {
|
||||
goto err;
|
||||
}
|
||||
if (ed_sig_tok) {
|
||||
tor_assert(ed_cert_tok && cc_tap_tok && cc_ntor_tok);
|
||||
|
||||
tor_cert_t *cert;
|
||||
{
|
||||
/* Parse the identity certificate */
|
||||
cert = tor_cert_parse(
|
||||
(const uint8_t*)ed_cert_tok->object_body,
|
||||
ed_cert_tok->object_size);
|
||||
if (! cert) {
|
||||
log_warn(LD_DIR, "Couldn't parse ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
/* makes sure it gets freed. */
|
||||
router->cache_info.signing_key_cert = cert;
|
||||
|
||||
if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
|
||||
! cert->signing_key_included) {
|
||||
log_warn(LD_DIR, "Invalid form for ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (cc_tap_tok) {
|
||||
rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey,
|
||||
router->tap_onion_pkey_len);
|
||||
if (rsa_pubkey == NULL) {
|
||||
log_warn(LD_DIR, "No pubkey for TAP cross-verification.");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) {
|
||||
log_warn(LD_DIR, "Wrong object type on onion-key-crosscert "
|
||||
"in descriptor");
|
||||
goto err;
|
||||
}
|
||||
if (check_tap_onion_key_crosscert(
|
||||
(const uint8_t*)cc_tap_tok->object_body,
|
||||
(int)cc_tap_tok->object_size,
|
||||
rsa_pubkey,
|
||||
&cert->signing_key,
|
||||
(const uint8_t*)router->cache_info.identity_digest)<0) {
|
||||
log_warn(LD_DIR, "Incorrect TAP cross-verification");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
tor_assert(ed_sig_tok && ed_cert_tok && cc_ntor_tok);
|
||||
const int ed_cert_token_pos = smartlist_pos(tokens, ed_cert_tok);
|
||||
if (ed_cert_token_pos == -1 || router_token_pos == -1 ||
|
||||
(ed_cert_token_pos != router_token_pos + 1 &&
|
||||
@ -668,35 +712,14 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
"in descriptor");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(cc_tap_tok->object_type, "CROSSCERT")) {
|
||||
log_warn(LD_DIR, "Wrong object type on onion-key-crosscert "
|
||||
"in descriptor");
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(cc_ntor_tok->args[0], "0") &&
|
||||
strcmp(cc_ntor_tok->args[0], "1")) {
|
||||
log_warn(LD_DIR, "Bad sign bit on ntor-onion-key-crosscert");
|
||||
goto err;
|
||||
}
|
||||
int ntor_cc_sign_bit = !strcmp(cc_ntor_tok->args[0], "1");
|
||||
|
||||
uint8_t d256[DIGEST256_LEN];
|
||||
const char *signed_start, *signed_end;
|
||||
tor_cert_t *cert = tor_cert_parse(
|
||||
(const uint8_t*)ed_cert_tok->object_body,
|
||||
ed_cert_tok->object_size);
|
||||
if (! cert) {
|
||||
log_warn(LD_DIR, "Couldn't parse ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
/* makes sure it gets freed. */
|
||||
router->cache_info.signing_key_cert = cert;
|
||||
|
||||
if (cert->cert_type != CERT_TYPE_ID_SIGNING ||
|
||||
! cert->signing_key_included) {
|
||||
log_warn(LD_DIR, "Invalid form for ed25519 cert");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (master_key_tok) {
|
||||
/* This token is optional, but if it's present, it must match
|
||||
@ -746,6 +769,7 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
crypto_digest_add_bytes(d, ED_DESC_SIGNATURE_PREFIX,
|
||||
strlen(ED_DESC_SIGNATURE_PREFIX));
|
||||
crypto_digest_add_bytes(d, signed_start, signed_end-signed_start);
|
||||
|
||||
crypto_digest_get_digest(d, (char*)d256, sizeof(d256));
|
||||
crypto_digest_free(d);
|
||||
|
||||
@ -776,18 +800,6 @@ router_parse_entry_from_string(const char *s, const char *end,
|
||||
goto err;
|
||||
}
|
||||
|
||||
rsa_pubkey = router_get_rsa_onion_pkey(router->onion_pkey,
|
||||
router->onion_pkey_len);
|
||||
if (check_tap_onion_key_crosscert(
|
||||
(const uint8_t*)cc_tap_tok->object_body,
|
||||
(int)cc_tap_tok->object_size,
|
||||
rsa_pubkey,
|
||||
&cert->signing_key,
|
||||
(const uint8_t*)router->cache_info.identity_digest)<0) {
|
||||
log_warn(LD_DIR, "Incorrect TAP cross-verification");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* We check this before adding it to the routerlist. */
|
||||
router->cert_expiration_time = expires;
|
||||
}
|
||||
|
@ -1686,7 +1686,7 @@ hs_get_extend_info_from_lspecs(const smartlist_t *lspecs,
|
||||
|
||||
/* We do have everything for which we think we can connect successfully. */
|
||||
info = extend_info_new(NULL, legacy_id,
|
||||
(have_ed25519_id) ? &ed25519_pk : NULL, NULL,
|
||||
(have_ed25519_id) ? &ed25519_pk : NULL,
|
||||
onion_key, &ap.addr, ap.port, NULL, false);
|
||||
done:
|
||||
return info;
|
||||
|
@ -909,8 +909,6 @@ microdesc_free_(microdesc_t *md, const char *fname, int lineno)
|
||||
//tor_assert(md->held_in_map == 0);
|
||||
//tor_assert(md->held_by_nodes == 0);
|
||||
|
||||
if (md->onion_pkey)
|
||||
tor_free(md->onion_pkey);
|
||||
tor_free(md->onion_curve25519_pkey);
|
||||
tor_free(md->ed25519_identity_pkey);
|
||||
if (md->body && md->saved_location != SAVED_IN_CACHE)
|
||||
|
@ -63,14 +63,6 @@ struct microdesc_t {
|
||||
|
||||
/* Fields in the microdescriptor. */
|
||||
|
||||
/**
|
||||
* Public RSA TAP key for onions, ASN.1 encoded. We store this
|
||||
* in its encoded format since storing it as a crypto_pk_t uses
|
||||
* significantly more memory. */
|
||||
char *onion_pkey;
|
||||
/** Length of onion_pkey, in bytes. */
|
||||
size_t onion_pkey_len;
|
||||
|
||||
/** As routerinfo_t.onion_curve25519_pkey */
|
||||
struct curve25519_public_key_t *onion_curve25519_pkey;
|
||||
/** Ed25519 identity key, if included. */
|
||||
|
@ -2034,37 +2034,6 @@ node_get_curve25519_onion_key(const node_t *node)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return a newly allocacted RSA onion public key taken from the given node.
|
||||
*
|
||||
* Return NULL if node is NULL or no RSA onion public key can be found. It is
|
||||
* the caller responsibility to free the returned object. */
|
||||
crypto_pk_t *
|
||||
node_get_rsa_onion_key(const node_t *node)
|
||||
{
|
||||
crypto_pk_t *pk = NULL;
|
||||
const char *onion_pkey;
|
||||
size_t onion_pkey_len;
|
||||
|
||||
if (!node) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (node->ri) {
|
||||
onion_pkey = node->ri->onion_pkey;
|
||||
onion_pkey_len = node->ri->onion_pkey_len;
|
||||
} else if (node->rs && node->md) {
|
||||
onion_pkey = node->md->onion_pkey;
|
||||
onion_pkey_len = node->md->onion_pkey_len;
|
||||
} else {
|
||||
/* No descriptor or microdescriptor. */
|
||||
goto end;
|
||||
}
|
||||
pk = router_get_rsa_onion_pkey(onion_pkey, onion_pkey_len);
|
||||
|
||||
end:
|
||||
return pk;
|
||||
}
|
||||
|
||||
/** Refresh the country code of <b>ri</b>. This function MUST be called on
|
||||
* each router when the GeoIP database is reloaded, and on all new routers. */
|
||||
void
|
||||
|
@ -109,7 +109,6 @@ void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out);
|
||||
int node_has_curve25519_onion_key(const node_t *node);
|
||||
const struct curve25519_public_key_t *node_get_curve25519_onion_key(
|
||||
const node_t *node);
|
||||
crypto_pk_t *node_get_rsa_onion_key(const node_t *node);
|
||||
|
||||
MOCK_DECL(const smartlist_t *, nodelist_get_list, (void));
|
||||
|
||||
|
@ -33,10 +33,13 @@ struct routerinfo_t {
|
||||
/**
|
||||
* Public RSA TAP key for onions, ASN.1 encoded. We store this
|
||||
* in its encoded format since storing it as a crypto_pk_t uses
|
||||
* significantly more memory. */
|
||||
char *onion_pkey;
|
||||
* significantly more memory.
|
||||
*
|
||||
* This may be absent.
|
||||
*/
|
||||
char *tap_onion_pkey;
|
||||
/** Length of onion_pkey, in bytes. */
|
||||
size_t onion_pkey_len;
|
||||
size_t tap_onion_pkey_len;
|
||||
|
||||
crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */
|
||||
/** Public curve25519 key for onions */
|
||||
|
@ -930,8 +930,8 @@ routerinfo_free_(routerinfo_t *router)
|
||||
tor_free(router->platform);
|
||||
tor_free(router->protocol_list);
|
||||
tor_free(router->contact_info);
|
||||
if (router->onion_pkey)
|
||||
tor_free(router->onion_pkey);
|
||||
if (router->tap_onion_pkey)
|
||||
tor_free(router->tap_onion_pkey);
|
||||
tor_free(router->onion_curve25519_pkey);
|
||||
if (router->identity_pkey)
|
||||
crypto_pk_free(router->identity_pkey);
|
||||
@ -2957,6 +2957,24 @@ router_reset_descriptor_download_failures(void)
|
||||
/** We allow uptime to vary from how much it ought to be by this much. */
|
||||
#define ROUTER_ALLOW_UPTIME_DRIFT (6*60*60)
|
||||
|
||||
/** Return true iff r1 and r2 have the same TAP onion keys. */
|
||||
static int
|
||||
router_tap_onion_keys_eq(const routerinfo_t *r1, const routerinfo_t *r2)
|
||||
{
|
||||
if (r1->tap_onion_pkey_len != r2->tap_onion_pkey_len)
|
||||
return 0;
|
||||
|
||||
if ((r1->tap_onion_pkey == NULL) && (r2->tap_onion_pkey == NULL)) {
|
||||
return 1;
|
||||
} else if ((r1->tap_onion_pkey != NULL) && (r2->tap_onion_pkey != NULL)) {
|
||||
return tor_memeq(r1->tap_onion_pkey, r2->tap_onion_pkey,
|
||||
r1->tap_onion_pkey_len);
|
||||
} else {
|
||||
/* One is NULL; one is not. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true iff the only differences between r1 and r2 are such that
|
||||
* would not cause a recent (post 0.1.1.6) dirserver to republish.
|
||||
*/
|
||||
@ -2982,8 +3000,7 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2)
|
||||
r1->ipv6_orport != r2->ipv6_orport ||
|
||||
r1->ipv4_dirport != r2->ipv4_dirport ||
|
||||
r1->purpose != r2->purpose ||
|
||||
r1->onion_pkey_len != r2->onion_pkey_len ||
|
||||
!tor_memeq(r1->onion_pkey, r2->onion_pkey, r1->onion_pkey_len) ||
|
||||
!router_tap_onion_keys_eq(r1,r2) ||
|
||||
!crypto_pk_eq_keys(r1->identity_pkey, r2->identity_pkey) ||
|
||||
strcasecmp(r1->platform, r2->platform) ||
|
||||
(r1->contact_info && !r2->contact_info) || /* contact_info is optional */
|
||||
|
@ -389,7 +389,6 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
|
||||
circ->n_hop = extend_info_new(NULL /*nickname*/,
|
||||
(const char*)ec->node_id,
|
||||
&ec->ed_pubkey,
|
||||
NULL, /*onion_key*/
|
||||
NULL, /*curve25519_key*/
|
||||
&chosen_ap->addr,
|
||||
chosen_ap->port,
|
||||
@ -443,6 +442,12 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ)
|
||||
|
||||
relay_header_unpack(&rh, cell->payload);
|
||||
|
||||
/* We no longer accept EXTEND messages; only EXTEND2. */
|
||||
if (rh.command == RELAY_COMMAND_EXTEND) {
|
||||
/* TODO: Should we log this? */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (extend_cell_parse(&ec, rh.command,
|
||||
cell->payload+RELAY_HEADER_SIZE,
|
||||
rh.length) < 0) {
|
||||
|
@ -50,10 +50,6 @@
|
||||
#define ONION_QUEUE_MAX_DELAY_MIN 1
|
||||
#define ONION_QUEUE_MAX_DELAY_MAX INT32_MAX
|
||||
|
||||
#define NUM_NTORS_PER_TAP_DEFAULT 10
|
||||
#define NUM_NTORS_PER_TAP_MIN 1
|
||||
#define NUM_NTORS_PER_TAP_MAX 100000
|
||||
|
||||
/** Type for a linked list of circuits that are waiting for a free CPU worker
|
||||
* to process a waiting onion handshake. */
|
||||
typedef struct onion_queue_t {
|
||||
@ -84,17 +80,9 @@ static int ol_entries[MAX_QUEUE_IDX+1];
|
||||
static void onion_queue_entry_remove(onion_queue_t *victim);
|
||||
|
||||
/** Consensus parameters. */
|
||||
static int32_t ns_num_ntors_per_tap = NUM_NTORS_PER_TAP_DEFAULT;
|
||||
static time_t ns_onion_queue_wait_cutoff = ONION_QUEUE_WAIT_CUTOFF_DEFAULT;
|
||||
static uint32_t ns_onion_queue_max_delay = ONION_QUEUE_MAX_DELAY_DEFAULT;
|
||||
|
||||
/** Return the number of ntors per tap from the cached parameter. */
|
||||
static inline int32_t
|
||||
get_num_ntors_per_tap(void)
|
||||
{
|
||||
return ns_num_ntors_per_tap;
|
||||
}
|
||||
|
||||
/** Return the onion queue wait cutoff value from the cached parameter. */
|
||||
static inline time_t
|
||||
get_onion_queue_wait_cutoff(void)
|
||||
@ -146,8 +134,12 @@ have_room_for_onionskin(uint16_t type)
|
||||
const or_options_t *options = get_options();
|
||||
int num_cpus;
|
||||
uint64_t max_onion_queue_delay;
|
||||
uint64_t tap_usec, ntor_usec;
|
||||
uint64_t ntor_during_tap_usec, tap_during_ntor_usec;
|
||||
uint64_t ntor_usec;
|
||||
|
||||
/* We never allow TAP. */
|
||||
if (type == ONION_HANDSHAKE_TYPE_TAP) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we've got fewer than 50 entries, we always have room for one more. */
|
||||
if (ol_entries[type] < 50)
|
||||
@ -164,44 +156,15 @@ have_room_for_onionskin(uint16_t type)
|
||||
/* Compute how many microseconds we'd expect to need to clear all
|
||||
* onionskins in various combinations of the queues. */
|
||||
|
||||
/* How long would it take to process all the TAP cells in the queue? */
|
||||
tap_usec = estimated_usec_for_onionskins(
|
||||
ol_entries[ONION_HANDSHAKE_TYPE_TAP],
|
||||
ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
|
||||
|
||||
/* How long would it take to process all the NTor cells in the queue? */
|
||||
ntor_usec = estimated_usec_for_onionskins(
|
||||
ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
|
||||
ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
|
||||
|
||||
/* How long would it take to process the tap cells that we expect to
|
||||
* process while draining the ntor queue? */
|
||||
tap_during_ntor_usec = estimated_usec_for_onionskins(
|
||||
MIN(ol_entries[ONION_HANDSHAKE_TYPE_TAP],
|
||||
ol_entries[ONION_HANDSHAKE_TYPE_NTOR] / get_num_ntors_per_tap()),
|
||||
ONION_HANDSHAKE_TYPE_TAP) / num_cpus;
|
||||
|
||||
/* How long would it take to process the ntor cells that we expect to
|
||||
* process while draining the tap queue? */
|
||||
ntor_during_tap_usec = estimated_usec_for_onionskins(
|
||||
MIN(ol_entries[ONION_HANDSHAKE_TYPE_NTOR],
|
||||
ol_entries[ONION_HANDSHAKE_TYPE_TAP] * get_num_ntors_per_tap()),
|
||||
ONION_HANDSHAKE_TYPE_NTOR) / num_cpus;
|
||||
|
||||
/* See whether that exceeds MaxOnionQueueDelay. If so, we can't queue
|
||||
* this. */
|
||||
if (type == ONION_HANDSHAKE_TYPE_NTOR &&
|
||||
(ntor_usec + tap_during_ntor_usec) / 1000 > max_onion_queue_delay)
|
||||
return 0;
|
||||
|
||||
if (type == ONION_HANDSHAKE_TYPE_TAP &&
|
||||
(tap_usec + ntor_during_tap_usec) / 1000 > max_onion_queue_delay)
|
||||
return 0;
|
||||
|
||||
/* If we support the ntor handshake, then don't let TAP handshakes use
|
||||
* more than 2/3 of the space on the queue. */
|
||||
if (type == ONION_HANDSHAKE_TYPE_TAP &&
|
||||
tap_usec / 1000 > max_onion_queue_delay * 2 / 3)
|
||||
(ntor_usec / 1000) > max_onion_queue_delay)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@ -292,38 +255,7 @@ onion_pending_add(or_circuit_t *circ, create_cell_t *onionskin)
|
||||
static uint16_t
|
||||
decide_next_handshake_type(void)
|
||||
{
|
||||
/* The number of times we've chosen ntor lately when both were available. */
|
||||
static int recently_chosen_ntors = 0;
|
||||
|
||||
if (!ol_entries[ONION_HANDSHAKE_TYPE_NTOR])
|
||||
return ONION_HANDSHAKE_TYPE_TAP; /* no ntors? try tap */
|
||||
|
||||
if (!ol_entries[ONION_HANDSHAKE_TYPE_TAP]) {
|
||||
|
||||
/* Nick wants us to prioritize new tap requests when there aren't
|
||||
* any in the queue and we've processed k ntor cells since the last
|
||||
* tap cell. This strategy is maybe a good idea, since it starves tap
|
||||
* less in the case where tap is rare, or maybe a poor idea, since it
|
||||
* makes the new tap cell unfairly jump in front of ntor cells that
|
||||
* got here first. In any case this edge case will only become relevant
|
||||
* once tap is rare. We should reevaluate whether we like this decision
|
||||
* once tap gets more rare. */
|
||||
if (ol_entries[ONION_HANDSHAKE_TYPE_NTOR] &&
|
||||
recently_chosen_ntors <= get_num_ntors_per_tap())
|
||||
++recently_chosen_ntors;
|
||||
|
||||
return ONION_HANDSHAKE_TYPE_NTOR; /* no taps? try ntor */
|
||||
}
|
||||
|
||||
/* They both have something queued. Pick ntor if we haven't done that
|
||||
* too much lately. */
|
||||
if (++recently_chosen_ntors <= get_num_ntors_per_tap()) {
|
||||
return ONION_HANDSHAKE_TYPE_NTOR;
|
||||
}
|
||||
|
||||
/* Else, it's time to let tap have its turn. */
|
||||
recently_chosen_ntors = 0;
|
||||
return ONION_HANDSHAKE_TYPE_TAP;
|
||||
return ONION_HANDSHAKE_TYPE_NTOR;
|
||||
}
|
||||
|
||||
/** Remove the highest priority item from ol_list[] and return it, or
|
||||
@ -445,10 +377,4 @@ onion_consensus_has_changed(const networkstatus_t *ns)
|
||||
ONION_QUEUE_WAIT_CUTOFF_DEFAULT,
|
||||
ONION_QUEUE_WAIT_CUTOFF_MIN,
|
||||
ONION_QUEUE_WAIT_CUTOFF_MAX);
|
||||
|
||||
ns_num_ntors_per_tap =
|
||||
networkstatus_get_param(ns, "NumNTorsPerTAP",
|
||||
NUM_NTORS_PER_TAP_DEFAULT,
|
||||
NUM_NTORS_PER_TAP_MIN,
|
||||
NUM_NTORS_PER_TAP_MAX);
|
||||
}
|
||||
|
@ -211,8 +211,13 @@ set_onion_key(crypto_pk_t *k)
|
||||
mark_my_descriptor_dirty("set onion key");
|
||||
}
|
||||
|
||||
/** Return the current onion key. Requires that the onion key has been
|
||||
* loaded or generated. */
|
||||
/** Return the current TAP onion key. Requires that the onion key has been
|
||||
* loaded or generated.
|
||||
*
|
||||
* Note that this key is no longer used for anything; we only keep it around
|
||||
* because (as of June 2024) other Tor instances all expect to find it in
|
||||
* our routerdescs.
|
||||
**/
|
||||
MOCK_IMPL(crypto_pk_t *,
|
||||
get_onion_key,(void))
|
||||
{
|
||||
@ -220,6 +225,25 @@ get_onion_key,(void))
|
||||
return onionkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true iff we should include our TAP onion key in our router
|
||||
* descriptor.
|
||||
*/
|
||||
static int
|
||||
should_publish_tap_onion_key(void)
|
||||
{
|
||||
#define SHOULD_PUBLISH_TAP_MIN 0
|
||||
#define SHOULD_PUBLISH_TAP_MAX 1
|
||||
/* Note that we err on the side of publishing. */
|
||||
#define SHOULD_PUBLISH_TAP_DFLT 1
|
||||
|
||||
return networkstatus_get_param(NULL,
|
||||
"publish-dummy-tap-key",
|
||||
SHOULD_PUBLISH_TAP_DFLT,
|
||||
SHOULD_PUBLISH_TAP_MIN,
|
||||
SHOULD_PUBLISH_TAP_MAX);
|
||||
}
|
||||
|
||||
/** Store a full copy of the current onion key into *<b>key</b>, and a full
|
||||
* copy of the most recent onion key into *<b>last</b>. Store NULL into
|
||||
* a pointer if the corresponding key does not exist.
|
||||
@ -2138,9 +2162,12 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
|
||||
ri->supports_tunnelled_dir_requests =
|
||||
directory_permits_begindir_requests(options);
|
||||
ri->cache_info.published_on = time(NULL);
|
||||
/* get_onion_key() must invoke from main thread */
|
||||
router_set_rsa_onion_pkey(get_onion_key(), &ri->onion_pkey,
|
||||
&ri->onion_pkey_len);
|
||||
|
||||
if (should_publish_tap_onion_key()) {
|
||||
/* get_onion_key() must invoke from main thread */
|
||||
router_set_rsa_onion_pkey(get_onion_key(), &ri->tap_onion_pkey,
|
||||
&ri->tap_onion_pkey_len);
|
||||
}
|
||||
|
||||
ri->onion_curve25519_pkey =
|
||||
tor_memdup(&get_current_curve25519_keypair()->pubkey,
|
||||
@ -2777,7 +2804,7 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
char published[ISO_TIME_LEN+1];
|
||||
char fingerprint[FINGERPRINT_LEN+1];
|
||||
char *extra_info_line = NULL;
|
||||
size_t onion_pkeylen, identity_pkeylen;
|
||||
size_t onion_pkeylen=0, identity_pkeylen;
|
||||
char *family_line = NULL;
|
||||
char *extra_or_address = NULL;
|
||||
const or_options_t *options = get_options();
|
||||
@ -2835,12 +2862,14 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
}
|
||||
|
||||
/* PEM-encode the onion key */
|
||||
rsa_pubkey = router_get_rsa_onion_pkey(router->onion_pkey,
|
||||
router->onion_pkey_len);
|
||||
if (crypto_pk_write_public_key_to_string(rsa_pubkey,
|
||||
&onion_pkey,&onion_pkeylen)<0) {
|
||||
log_warn(LD_BUG,"write onion_pkey to string failed!");
|
||||
goto err;
|
||||
rsa_pubkey = router_get_rsa_onion_pkey(router->tap_onion_pkey,
|
||||
router->tap_onion_pkey_len);
|
||||
if (rsa_pubkey) {
|
||||
if (crypto_pk_write_public_key_to_string(rsa_pubkey,
|
||||
&onion_pkey,&onion_pkeylen)<0) {
|
||||
log_warn(LD_BUG,"write onion_pkey to string failed!");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* PEM-encode the identity key */
|
||||
@ -2851,7 +2880,7 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
}
|
||||
|
||||
/* Cross-certify with RSA key */
|
||||
if (tap_key && router->cache_info.signing_key_cert &&
|
||||
if (tap_key && rsa_pubkey && router->cache_info.signing_key_cert &&
|
||||
router->cache_info.signing_key_cert->signing_key_included) {
|
||||
char buf[256];
|
||||
int tap_cc_len = 0;
|
||||
@ -2976,7 +3005,7 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
"uptime %ld\n"
|
||||
"bandwidth %d %d %d\n"
|
||||
"%s%s"
|
||||
"onion-key\n%s"
|
||||
"%s%s"
|
||||
"signing-key\n%s"
|
||||
"%s%s"
|
||||
"%s%s%s",
|
||||
@ -2997,7 +3026,8 @@ router_dump_router_to_string(routerinfo_t *router,
|
||||
extra_info_line ? extra_info_line : "",
|
||||
(options->DownloadExtraInfo || options->V3AuthoritativeDir) ?
|
||||
"caches-extra-info\n" : "",
|
||||
onion_pkey, identity_pkey,
|
||||
onion_pkey?"onion-key\n":"", onion_pkey?onion_pkey:"",
|
||||
identity_pkey,
|
||||
rsa_tap_cc_line ? rsa_tap_cc_line : "",
|
||||
ntor_cc_line ? ntor_cc_line : "",
|
||||
family_line,
|
||||
|
@ -201,7 +201,6 @@ have_orport_for_family(int family)
|
||||
static extend_info_t *
|
||||
extend_info_from_router(const routerinfo_t *r, int family)
|
||||
{
|
||||
crypto_pk_t *rsa_pubkey;
|
||||
extend_info_t *info;
|
||||
tor_addr_port_t ap;
|
||||
|
||||
@ -224,15 +223,14 @@ extend_info_from_router(const routerinfo_t *r, int family)
|
||||
/* We don't have an ORPort for the requested family. */
|
||||
return NULL;
|
||||
}
|
||||
rsa_pubkey = router_get_rsa_onion_pkey(r->onion_pkey, r->onion_pkey_len);
|
||||
info = extend_info_new(r->nickname, r->cache_info.identity_digest,
|
||||
ed_id_key,
|
||||
rsa_pubkey, r->onion_curve25519_pkey,
|
||||
r->onion_curve25519_pkey,
|
||||
&ap.addr, ap.port,
|
||||
/* TODO-324: Should self-test circuits use
|
||||
* congestion control? */
|
||||
NULL, false);
|
||||
crypto_pk_free(rsa_pubkey);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "orconfig.h"
|
||||
|
||||
#include "core/or/or.h"
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "core/crypto/relay_crypto.h"
|
||||
|
||||
#include "lib/intmath/weakrng.h"
|
||||
@ -126,75 +125,6 @@ bench_aes(void)
|
||||
crypto_cipher_free(c);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_onion_TAP(void)
|
||||
{
|
||||
const int iters = 1<<9;
|
||||
int i;
|
||||
crypto_pk_t *key, *key2;
|
||||
uint64_t start, end;
|
||||
char os[TAP_ONIONSKIN_CHALLENGE_LEN];
|
||||
char or[TAP_ONIONSKIN_REPLY_LEN];
|
||||
crypto_dh_t *dh_out = NULL;
|
||||
|
||||
key = crypto_pk_new();
|
||||
key2 = crypto_pk_new();
|
||||
if (crypto_pk_generate_key_with_bits(key, 1024) < 0)
|
||||
goto done;
|
||||
if (crypto_pk_generate_key_with_bits(key2, 1024) < 0)
|
||||
goto done;
|
||||
|
||||
reset_perftime();
|
||||
start = perftime();
|
||||
for (i = 0; i < iters; ++i) {
|
||||
onion_skin_TAP_create(key, &dh_out, os);
|
||||
crypto_dh_free(dh_out);
|
||||
}
|
||||
end = perftime();
|
||||
printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
|
||||
|
||||
onion_skin_TAP_create(key, &dh_out, os);
|
||||
start = perftime();
|
||||
for (i = 0; i < iters; ++i) {
|
||||
char key_out[CPATH_KEY_MATERIAL_LEN];
|
||||
onion_skin_TAP_server_handshake(os, key, NULL, or,
|
||||
key_out, sizeof(key_out));
|
||||
}
|
||||
end = perftime();
|
||||
printf("Server-side, key guessed right: %f usec\n",
|
||||
NANOCOUNT(start, end, iters)/1e3);
|
||||
|
||||
start = perftime();
|
||||
for (i = 0; i < iters; ++i) {
|
||||
char key_out[CPATH_KEY_MATERIAL_LEN];
|
||||
onion_skin_TAP_server_handshake(os, key2, key, or,
|
||||
key_out, sizeof(key_out));
|
||||
}
|
||||
end = perftime();
|
||||
printf("Server-side, key guessed wrong: %f usec.\n",
|
||||
NANOCOUNT(start, end, iters)/1e3);
|
||||
|
||||
start = perftime();
|
||||
for (i = 0; i < iters; ++i) {
|
||||
crypto_dh_t *dh;
|
||||
char key_out[CPATH_KEY_MATERIAL_LEN];
|
||||
int s;
|
||||
dh = crypto_dh_dup(dh_out);
|
||||
s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out),
|
||||
NULL);
|
||||
crypto_dh_free(dh);
|
||||
tor_assert(s == 0);
|
||||
}
|
||||
end = perftime();
|
||||
printf("Client-side, part 2: %f usec.\n",
|
||||
NANOCOUNT(start, end, iters)/1e3);
|
||||
|
||||
done:
|
||||
crypto_dh_free(dh_out);
|
||||
crypto_pk_free(key);
|
||||
crypto_pk_free(key2);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_onion_ntor_impl(void)
|
||||
{
|
||||
@ -754,7 +684,6 @@ static struct benchmark_t benchmarks[] = {
|
||||
ENT(siphash),
|
||||
ENT(digest),
|
||||
ENT(aes),
|
||||
ENT(onion_TAP),
|
||||
ENT(onion_ntor),
|
||||
ENT(ed25519),
|
||||
ENT(rand),
|
||||
|
211
src/test/test.c
211
src/test/test.c
@ -50,7 +50,6 @@
|
||||
#include "core/or/onion.h"
|
||||
#include "core/crypto/onion_ntor.h"
|
||||
#include "core/crypto/onion_fast.h"
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "core/or/policies.h"
|
||||
#include "lib/sandbox/sandbox.h"
|
||||
#include "app/config/statefile.h"
|
||||
@ -61,150 +60,6 @@
|
||||
#include "core/or/or_circuit_st.h"
|
||||
#include "feature/relay/onion_queue.h"
|
||||
|
||||
/** Run unit tests for the onion handshake code. */
|
||||
static void
|
||||
test_onion_handshake(void *arg)
|
||||
{
|
||||
/* client-side */
|
||||
crypto_dh_t *c_dh = NULL;
|
||||
char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
|
||||
char c_keys[40];
|
||||
/* server-side */
|
||||
char s_buf[TAP_ONIONSKIN_REPLY_LEN];
|
||||
char s_keys[40];
|
||||
int i;
|
||||
/* shared */
|
||||
crypto_pk_t *pk = NULL, *pk2 = NULL;
|
||||
|
||||
(void)arg;
|
||||
pk = pk_generate(0);
|
||||
pk2 = pk_generate(1);
|
||||
|
||||
/* client handshake 1. */
|
||||
memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
|
||||
|
||||
for (i = 1; i <= 3; ++i) {
|
||||
crypto_pk_t *k1, *k2;
|
||||
if (i==1) {
|
||||
/* server handshake: only one key known. */
|
||||
k1 = pk; k2 = NULL;
|
||||
} else if (i==2) {
|
||||
/* server handshake: try the right key first. */
|
||||
k1 = pk; k2 = pk2;
|
||||
} else {
|
||||
/* server handshake: try the right key second. */
|
||||
k1 = pk2; k2 = pk;
|
||||
}
|
||||
|
||||
memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
|
||||
memset(s_keys, 0, 40);
|
||||
tt_assert(! onion_skin_TAP_server_handshake(c_buf, k1, k2,
|
||||
s_buf, s_keys, 40));
|
||||
|
||||
/* client handshake 2 */
|
||||
memset(c_keys, 0, 40);
|
||||
tt_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys,
|
||||
40, NULL));
|
||||
|
||||
tt_mem_op(c_keys,OP_EQ, s_keys, 40);
|
||||
memset(s_buf, 0, 40);
|
||||
tt_mem_op(c_keys,OP_NE, s_buf, 40);
|
||||
}
|
||||
done:
|
||||
crypto_dh_free(c_dh);
|
||||
crypto_pk_free(pk);
|
||||
crypto_pk_free(pk2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bad_onion_handshake(void *arg)
|
||||
{
|
||||
char junk_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
|
||||
char junk_buf2[TAP_ONIONSKIN_CHALLENGE_LEN];
|
||||
/* client-side */
|
||||
crypto_dh_t *c_dh = NULL;
|
||||
char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
|
||||
char c_keys[40];
|
||||
/* server-side */
|
||||
char s_buf[TAP_ONIONSKIN_REPLY_LEN];
|
||||
char s_keys[40];
|
||||
/* shared */
|
||||
crypto_pk_t *pk = NULL, *pk2 = NULL;
|
||||
|
||||
(void)arg;
|
||||
|
||||
pk = pk_generate(0);
|
||||
pk2 = pk_generate(1);
|
||||
|
||||
/* Server: Case 1: the encrypted data is degenerate. */
|
||||
memset(junk_buf, 0, sizeof(junk_buf));
|
||||
crypto_pk_obsolete_public_hybrid_encrypt(pk,
|
||||
junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN,
|
||||
junk_buf, DH1024_KEY_LEN,
|
||||
PK_PKCS1_OAEP_PADDING, 1);
|
||||
tt_int_op(-1, OP_EQ,
|
||||
onion_skin_TAP_server_handshake(junk_buf2, pk, NULL,
|
||||
s_buf, s_keys, 40));
|
||||
|
||||
/* Server: Case 2: the encrypted data is not long enough. */
|
||||
memset(junk_buf, 0, sizeof(junk_buf));
|
||||
memset(junk_buf2, 0, sizeof(junk_buf2));
|
||||
crypto_pk_public_encrypt(pk, junk_buf2, sizeof(junk_buf2),
|
||||
junk_buf, 48, PK_PKCS1_OAEP_PADDING);
|
||||
tt_int_op(-1, OP_EQ,
|
||||
onion_skin_TAP_server_handshake(junk_buf2, pk, NULL,
|
||||
s_buf, s_keys, 40));
|
||||
|
||||
/* client handshake 1: do it straight. */
|
||||
memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
|
||||
|
||||
/* Server: Case 3: we just don't have the right key. */
|
||||
tt_int_op(-1, OP_EQ,
|
||||
onion_skin_TAP_server_handshake(c_buf, pk2, NULL,
|
||||
s_buf, s_keys, 40));
|
||||
|
||||
/* Server: Case 4: The RSA-encrypted portion is corrupt. */
|
||||
c_buf[64] ^= 33;
|
||||
tt_int_op(-1, OP_EQ,
|
||||
onion_skin_TAP_server_handshake(c_buf, pk, NULL,
|
||||
s_buf, s_keys, 40));
|
||||
c_buf[64] ^= 33;
|
||||
|
||||
/* (Let the server proceed) */
|
||||
tt_int_op(0, OP_EQ,
|
||||
onion_skin_TAP_server_handshake(c_buf, pk, NULL,
|
||||
s_buf, s_keys, 40));
|
||||
|
||||
/* Client: Case 1: The server sent back junk. */
|
||||
const char *msg = NULL;
|
||||
s_buf[64] ^= 33;
|
||||
tt_int_op(-1, OP_EQ,
|
||||
onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg));
|
||||
s_buf[64] ^= 33;
|
||||
tt_str_op(msg, OP_EQ, "Digest DOES NOT MATCH on onion handshake. "
|
||||
"Bug or attack.");
|
||||
|
||||
/* Let the client finish; make sure it can. */
|
||||
msg = NULL;
|
||||
tt_int_op(0, OP_EQ,
|
||||
onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg));
|
||||
tt_mem_op(s_keys,OP_EQ, c_keys, 40);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
|
||||
/* Client: Case 2: The server sent back a degenerate DH. */
|
||||
memset(s_buf, 0, sizeof(s_buf));
|
||||
tt_int_op(-1, OP_EQ,
|
||||
onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg));
|
||||
tt_str_op(msg, OP_EQ, "DH computation failed.");
|
||||
|
||||
done:
|
||||
crypto_dh_free(c_dh);
|
||||
crypto_pk_free(pk);
|
||||
crypto_pk_free(pk2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ntor_handshake(void *arg)
|
||||
{
|
||||
@ -306,37 +161,35 @@ test_fast_handshake(void *arg)
|
||||
static void
|
||||
test_onion_queues(void *arg)
|
||||
{
|
||||
uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
|
||||
uint8_t buf1[NTOR_ONIONSKIN_LEN] = {0};
|
||||
uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0};
|
||||
|
||||
or_circuit_t *circ1 = or_circuit_new(0, NULL);
|
||||
or_circuit_t *circ2 = or_circuit_new(0, NULL);
|
||||
|
||||
create_cell_t *onionskin = NULL, *create2_ptr;
|
||||
create_cell_t *onionskin = NULL, *create1_ptr;
|
||||
create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t));
|
||||
create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
|
||||
(void)arg;
|
||||
create2_ptr = create2; /* remember, but do not free */
|
||||
create1_ptr = create1; /* remember, but do not free */
|
||||
|
||||
create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN, buf1);
|
||||
create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
|
||||
NTOR_ONIONSKIN_LEN, buf1);
|
||||
create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
|
||||
NTOR_ONIONSKIN_LEN, buf2);
|
||||
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ1, create1));
|
||||
create1 = NULL;
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ2, create2));
|
||||
create2 = NULL;
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
|
||||
tt_ptr_op(circ2,OP_EQ, onion_next_task(&onionskin));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_ptr_op(onionskin, OP_EQ, create2_ptr);
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ2, create2));
|
||||
create2 = NULL;
|
||||
tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
|
||||
tt_ptr_op(circ1,OP_EQ, onion_next_task(&onionskin));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_ptr_op(onionskin, OP_EQ, create1_ptr);
|
||||
|
||||
clear_pending_onions();
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
@ -365,24 +218,19 @@ test_onion_queues(void *arg)
|
||||
static void
|
||||
test_onion_queue_order(void *arg)
|
||||
{
|
||||
uint8_t buf_tap[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
|
||||
uint8_t buf_ntor[NTOR_ONIONSKIN_LEN] = {0};
|
||||
uint8_t buf_ntor3[CELL_PAYLOAD_SIZE] = {0};
|
||||
|
||||
or_circuit_t *circ_tap = or_circuit_new(0, NULL);
|
||||
or_circuit_t *circ_ntor = or_circuit_new(0, NULL);
|
||||
or_circuit_t *circ_ntor3 = or_circuit_new(0, NULL);
|
||||
|
||||
create_cell_t *onionskin = NULL;
|
||||
create_cell_t *create_tap1 = tor_malloc_zero(sizeof(create_cell_t));
|
||||
create_cell_t *create_ntor1 = tor_malloc_zero(sizeof(create_cell_t));
|
||||
create_cell_t *create_ntor2 = tor_malloc_zero(sizeof(create_cell_t));
|
||||
create_cell_t *create_v3ntor1 = tor_malloc_zero(sizeof(create_cell_t));
|
||||
create_cell_t *create_v3ntor2 = tor_malloc_zero(sizeof(create_cell_t));
|
||||
(void)arg;
|
||||
|
||||
create_cell_init(create_tap1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
|
||||
TAP_ONIONSKIN_CHALLENGE_LEN, buf_tap);
|
||||
create_cell_init(create_ntor1, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
|
||||
NTOR_ONIONSKIN_LEN, buf_ntor);
|
||||
create_cell_init(create_ntor2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
|
||||
@ -393,78 +241,63 @@ test_onion_queue_order(void *arg)
|
||||
NTOR_ONIONSKIN_LEN, buf_ntor3);
|
||||
|
||||
/* sanity check queue init */
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
|
||||
/* Add tap first so we can ensure it comes out last */
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ_tap, create_tap1));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
|
||||
/* Now add interleaving ntor2 and ntor3, to ensure they share
|
||||
* the same queue and come out in this order */
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor1));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor1));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor, create_ntor2));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
|
||||
tt_int_op(0,OP_EQ, onion_pending_add(circ_ntor3, create_v3ntor2));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(4,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
|
||||
/* Now remove 5 tasks, ensuring order and queue sizes */
|
||||
tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(3,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
tt_ptr_op(onionskin, OP_EQ, create_ntor1);
|
||||
|
||||
tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(2,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
tt_ptr_op(onionskin, OP_EQ, create_v3ntor1);
|
||||
|
||||
tt_ptr_op(circ_ntor, OP_EQ, onion_next_task(&onionskin));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
tt_ptr_op(onionskin, OP_EQ, create_ntor2);
|
||||
|
||||
tt_ptr_op(circ_ntor3, OP_EQ, onion_next_task(&onionskin));
|
||||
tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
tt_ptr_op(onionskin, OP_EQ, create_v3ntor2);
|
||||
|
||||
tt_ptr_op(circ_tap, OP_EQ, onion_next_task(&onionskin));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR_V3));
|
||||
tt_ptr_op(onionskin, OP_EQ, create_tap1);
|
||||
tt_ptr_op(onionskin, OP_EQ, create_v3ntor2);
|
||||
|
||||
clear_pending_onions();
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
|
||||
tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
|
||||
|
||||
done:
|
||||
circuit_free_(TO_CIRCUIT(circ_tap));
|
||||
circuit_free_(TO_CIRCUIT(circ_ntor));
|
||||
circuit_free_(TO_CIRCUIT(circ_ntor3));
|
||||
tor_free(create_tap1);
|
||||
tor_free(create_ntor1);
|
||||
tor_free(create_ntor2);
|
||||
tor_free(create_v3ntor1);
|
||||
@ -740,8 +573,6 @@ test_circuit_timeout(void *arg)
|
||||
{ #name, test_ ## name , TT_FORK, NULL, NULL }
|
||||
|
||||
static struct testcase_t test_array[] = {
|
||||
ENT(onion_handshake),
|
||||
{ "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL },
|
||||
ENT(onion_queues),
|
||||
ENT(onion_queue_order),
|
||||
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "app/config/config.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "core/or/onion.h"
|
||||
#include "core/crypto/onion_tap.h"
|
||||
#include "core/crypto/onion_fast.h"
|
||||
#include "core/crypto/onion_ntor.h"
|
||||
#include "core/or/relay.h"
|
||||
@ -399,21 +398,6 @@ test_cfmt_create_cells(void *arg)
|
||||
|
||||
/* === Let's try parsing some good cells! */
|
||||
|
||||
/* A valid create cell. */
|
||||
memset(&cell, 0, sizeof(cell));
|
||||
memset(b, 0, sizeof(b));
|
||||
crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
cell.command = CELL_CREATE;
|
||||
memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
|
||||
tt_int_op(CELL_CREATE, OP_EQ, cc.cell_type);
|
||||
tt_int_op(ONION_HANDSHAKE_TYPE_TAP, OP_EQ, cc.handshake_type);
|
||||
tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, OP_EQ, cc.handshake_len);
|
||||
tt_mem_op(cc.onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
|
||||
tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
|
||||
tt_int_op(cell.command, OP_EQ, cell2.command);
|
||||
tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* A valid create_fast cell. */
|
||||
memset(&cell, 0, sizeof(cell));
|
||||
memset(b, 0, sizeof(b));
|
||||
@ -429,22 +413,6 @@ test_cfmt_create_cells(void *arg)
|
||||
tt_int_op(cell.command, OP_EQ, cell2.command);
|
||||
tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* A valid create2 cell with a TAP payload */
|
||||
memset(&cell, 0, sizeof(cell));
|
||||
memset(b, 0, sizeof(b));
|
||||
crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
cell.command = CELL_CREATE2;
|
||||
memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */
|
||||
memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
|
||||
tt_int_op(CELL_CREATE2, OP_EQ, cc.cell_type);
|
||||
tt_int_op(ONION_HANDSHAKE_TYPE_TAP, OP_EQ, cc.handshake_type);
|
||||
tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, OP_EQ, cc.handshake_len);
|
||||
tt_mem_op(cc.onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
|
||||
tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
|
||||
tt_int_op(cell.command, OP_EQ, cell2.command);
|
||||
tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* A valid create2 cell with an ntor payload */
|
||||
memset(&cell, 0, sizeof(cell));
|
||||
memset(b, 0, sizeof(b));
|
||||
@ -461,22 +429,6 @@ test_cfmt_create_cells(void *arg)
|
||||
tt_int_op(cell.command, OP_EQ, cell2.command);
|
||||
tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* A valid create cell with an ntor payload, in legacy format. */
|
||||
memset(&cell, 0, sizeof(cell));
|
||||
memset(b, 0, sizeof(b));
|
||||
crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
|
||||
cell.command = CELL_CREATE;
|
||||
memcpy(cell.payload, "ntorNTORntorNTOR", 16);
|
||||
memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN);
|
||||
tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
|
||||
tt_int_op(CELL_CREATE, OP_EQ, cc.cell_type);
|
||||
tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, OP_EQ, cc.handshake_type);
|
||||
tt_int_op(NTOR_ONIONSKIN_LEN, OP_EQ, cc.handshake_len);
|
||||
tt_mem_op(cc.onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN + 10);
|
||||
tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
|
||||
tt_int_op(cell.command, OP_EQ, cell2.command);
|
||||
tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* == Okay, now let's try to parse some impossible stuff. */
|
||||
|
||||
/* It has to be some kind of a create cell! */
|
||||
@ -517,20 +469,6 @@ test_cfmt_created_cells(void *arg)
|
||||
|
||||
(void)arg;
|
||||
|
||||
/* A good CREATED cell */
|
||||
memset(&cell, 0, sizeof(cell));
|
||||
memset(b, 0, sizeof(b));
|
||||
crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
|
||||
cell.command = CELL_CREATED;
|
||||
memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN);
|
||||
tt_int_op(0, OP_EQ, created_cell_parse(&cc, &cell));
|
||||
tt_int_op(CELL_CREATED, OP_EQ, cc.cell_type);
|
||||
tt_int_op(TAP_ONIONSKIN_REPLY_LEN, OP_EQ, cc.handshake_len);
|
||||
tt_mem_op(cc.reply,OP_EQ, b, TAP_ONIONSKIN_REPLY_LEN + 10);
|
||||
tt_int_op(0, OP_EQ, created_cell_format(&cell2, &cc));
|
||||
tt_int_op(cell.command, OP_EQ, cell2.command);
|
||||
tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
|
||||
|
||||
/* A good CREATED_FAST cell */
|
||||
memset(&cell, 0, sizeof(cell));
|
||||
memset(b, 0, sizeof(b));
|
||||
@ -606,54 +544,6 @@ test_cfmt_extend_cells(void *arg)
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* Let's start with a simple EXTEND cell. */
|
||||
memset(p, 0, sizeof(p));
|
||||
memset(b, 0, sizeof(b));
|
||||
crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
|
||||
memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
|
||||
tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
|
||||
p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
|
||||
tt_int_op(RELAY_COMMAND_EXTEND, OP_EQ, ec.cell_type);
|
||||
tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr));
|
||||
tt_int_op(258, OP_EQ, ec.orport_ipv4.port);
|
||||
tt_int_op(AF_UNSPEC, OP_EQ, tor_addr_family(&ec.orport_ipv6.addr));
|
||||
tt_mem_op(ec.node_id,OP_EQ, "electroencephalogram", 20);
|
||||
tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE);
|
||||
tt_int_op(cc->handshake_type, OP_EQ, ONION_HANDSHAKE_TYPE_TAP);
|
||||
tt_int_op(cc->handshake_len, OP_EQ, TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
tt_mem_op(cc->onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN+20);
|
||||
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
|
||||
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND);
|
||||
tt_int_op(p2_len, OP_EQ, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
tt_mem_op(p2,OP_EQ, p, RELAY_PAYLOAD_SIZE);
|
||||
|
||||
/* Let's do an ntor stuffed in a legacy EXTEND cell */
|
||||
memset(p, 0, sizeof(p));
|
||||
memset(b, 0, sizeof(b));
|
||||
crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
|
||||
memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
|
||||
memcpy(p+6,"ntorNTORntorNTOR", 16);
|
||||
memcpy(p+22, b, NTOR_ONIONSKIN_LEN);
|
||||
memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
|
||||
tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
|
||||
p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
|
||||
tt_int_op(RELAY_COMMAND_EXTEND, OP_EQ, ec.cell_type);
|
||||
tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr));
|
||||
tt_int_op(258, OP_EQ, ec.orport_ipv4.port);
|
||||
tt_int_op(AF_UNSPEC, OP_EQ, tor_addr_family(&ec.orport_ipv6.addr));
|
||||
tt_mem_op(ec.node_id,OP_EQ, "electroencephalogram", 20);
|
||||
tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
|
||||
tt_int_op(cc->handshake_type, OP_EQ, ONION_HANDSHAKE_TYPE_NTOR);
|
||||
tt_int_op(cc->handshake_len, OP_EQ, NTOR_ONIONSKIN_LEN);
|
||||
tt_mem_op(cc->onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN+20);
|
||||
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
|
||||
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND);
|
||||
tt_int_op(p2_len, OP_EQ, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
|
||||
tt_mem_op(p2,OP_EQ, p, RELAY_PAYLOAD_SIZE);
|
||||
tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
|
||||
|
||||
/* Now let's do a minimal ntor EXTEND2 cell. */
|
||||
memset(&ec, 0xff, sizeof(ec));
|
||||
memset(p, 0, sizeof(p));
|
||||
@ -896,23 +786,6 @@ test_cfmt_extended_cells(void *arg)
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* Try a regular EXTENDED cell. */
|
||||
memset(&ec, 0xff, sizeof(ec));
|
||||
memset(p, 0, sizeof(p));
|
||||
memset(b, 0, sizeof(b));
|
||||
crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
|
||||
memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN);
|
||||
tt_int_op(0, OP_EQ, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p,
|
||||
TAP_ONIONSKIN_REPLY_LEN));
|
||||
tt_int_op(RELAY_COMMAND_EXTENDED, OP_EQ, ec.cell_type);
|
||||
tt_int_op(cc->cell_type, OP_EQ, CELL_CREATED);
|
||||
tt_int_op(cc->handshake_len, OP_EQ, TAP_ONIONSKIN_REPLY_LEN);
|
||||
tt_mem_op(cc->reply,OP_EQ, b, TAP_ONIONSKIN_REPLY_LEN);
|
||||
tt_int_op(0, OP_EQ, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
|
||||
tt_int_op(RELAY_COMMAND_EXTENDED, OP_EQ, p2_cmd);
|
||||
tt_int_op(TAP_ONIONSKIN_REPLY_LEN, OP_EQ, p2_len);
|
||||
tt_mem_op(p2,OP_EQ, p, sizeof(p2));
|
||||
|
||||
/* Try an EXTENDED2 cell */
|
||||
memset(&ec, 0xff, sizeof(ec));
|
||||
memset(p, 0, sizeof(p));
|
||||
|
@ -1608,7 +1608,7 @@ simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
|
||||
|
||||
hop->extend_info = extend_info_new(
|
||||
padding ? "padding" : "non-padding",
|
||||
digest, NULL, NULL, NULL,
|
||||
digest, NULL, NULL,
|
||||
&addr, padding, NULL, false);
|
||||
|
||||
cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
|
||||
|
@ -349,7 +349,7 @@ simulate_single_hop_extend(origin_circuit_t *client, int exit)
|
||||
|
||||
hop->extend_info = extend_info_new(
|
||||
exit ? "exit" : "non-exit",
|
||||
digest, NULL, NULL, NULL,
|
||||
digest, NULL, NULL,
|
||||
&addr, exit, NULL, exit);
|
||||
|
||||
cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
|
||||
|
@ -217,7 +217,7 @@ basic_routerinfo_new(const char *nickname, uint32_t ipv4_addr,
|
||||
r1->ipv4_dirport = dir_port;
|
||||
r1->supports_tunnelled_dir_requests = 1;
|
||||
|
||||
router_set_rsa_onion_pkey(pk1, &r1->onion_pkey, &r1->onion_pkey_len);
|
||||
router_set_rsa_onion_pkey(pk1, &r1->tap_onion_pkey, &r1->tap_onion_pkey_len);
|
||||
r1->identity_pkey = pk2;
|
||||
|
||||
r1->bandwidthrate = bandwidthrate;
|
||||
@ -382,8 +382,8 @@ get_new_onion_key_block(const routerinfo_t *r1)
|
||||
{
|
||||
char *block = NULL;
|
||||
tor_assert(r1);
|
||||
crypto_pk_t *pk_tmp = router_get_rsa_onion_pkey(r1->onion_pkey,
|
||||
r1->onion_pkey_len);
|
||||
crypto_pk_t *pk_tmp = router_get_rsa_onion_pkey(r1->tap_onion_pkey,
|
||||
r1->tap_onion_pkey_len);
|
||||
block = get_new_rsa_key_block("onion-key", pk_tmp);
|
||||
crypto_pk_free(pk_tmp);
|
||||
return block;
|
||||
@ -587,8 +587,8 @@ setup_mocks_for_fresh_descriptor(const routerinfo_t *r1,
|
||||
if (rsa_onion_keypair) {
|
||||
mocked_onionkey = crypto_pk_dup_key(rsa_onion_keypair);
|
||||
} else {
|
||||
mocked_onionkey = router_get_rsa_onion_pkey(r1->onion_pkey,
|
||||
r1->onion_pkey_len);
|
||||
mocked_onionkey = router_get_rsa_onion_pkey(r1->tap_onion_pkey,
|
||||
r1->tap_onion_pkey_len);
|
||||
}
|
||||
MOCK(get_onion_key, mock_get_onion_key);
|
||||
}
|
||||
@ -643,10 +643,12 @@ STMT_BEGIN \
|
||||
tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate); \
|
||||
tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst); \
|
||||
tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity); \
|
||||
crypto_pk_t *rp1_onion_pkey = router_get_rsa_onion_pkey(rp1->onion_pkey, \
|
||||
rp1->onion_pkey_len); \
|
||||
crypto_pk_t *r1_onion_pkey = router_get_rsa_onion_pkey(r1->onion_pkey, \
|
||||
r1->onion_pkey_len); \
|
||||
crypto_pk_t *rp1_onion_pkey = router_get_rsa_onion_pkey( \
|
||||
rp1->tap_onion_pkey, \
|
||||
rp1->tap_onion_pkey_len); \
|
||||
crypto_pk_t *r1_onion_pkey = router_get_rsa_onion_pkey( \
|
||||
r1->tap_onion_pkey, \
|
||||
r1->tap_onion_pkey_len); \
|
||||
tt_int_op(crypto_pk_cmp_keys(rp1_onion_pkey, r1_onion_pkey), OP_EQ, 0); \
|
||||
crypto_pk_free(rp1_onion_pkey); \
|
||||
crypto_pk_free(r1_onion_pkey); \
|
||||
@ -1303,6 +1305,72 @@ test_dir_parse_router_list(void *arg)
|
||||
#undef ADD
|
||||
}
|
||||
|
||||
/* Made with chutney and a patched tor: Has no onion-key or
|
||||
* onion-key-crosscert */
|
||||
static const char ROUTERDESC_NO_ONION_KEY[] =
|
||||
"router test001a 127.0.0.1 5001 0 7001\n"
|
||||
"identity-ed25519\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQQAB0xWARbCJfDrX0OTtpM0fDxU9cLweMnZeUq/KBfAN1wwWHtMAQAgBADBQJ1o\n"
|
||||
"ClrXUenWC90FYEUQDpMSdxdxKlrR83rYy+keGe61WQHYP0ebowJC19UvPnYryLeA\n"
|
||||
"Gnhko2WwmbUDGicdnY4j2VSFU15oxBjln65IznZJyiZM4zGE1GkNZzKGmQY=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"master-key-ed25519 wUCdaApa11Hp1gvdBWBFEA6TEncXcSpa0fN62MvpHhk\n"
|
||||
"or-address [::]:5001\n"
|
||||
"platform Tor 0.4.9.0-alpha-dev on Linux\n"
|
||||
"proto Conflux=1 Cons=1-2 Desc=1-2 DirCache=2 FlowCtrl=1-2 HSDir=2 "
|
||||
"HSIntro=4-5 HSRend=1-2 Link=1-5 LinkAuth=1,3 Microdesc=1-2 Padding=2 "
|
||||
"Relay=1-4\n"
|
||||
"published 2024-06-24 21:34:22\n"
|
||||
"fingerprint FD3A 6FA4 E716 C379 3CBA FEC3 39EA 01C8 B49D 7189\n"
|
||||
"uptime 0\n"
|
||||
"bandwidth 1073741824 1073741824 0\n"
|
||||
"extra-info-digest 9946CAC41485EDFFDD83F7DAF1A088C30563126C "
|
||||
"lpAMRlRTy9QR2xVCu1nnnxOHA2I05TTKvCSPPcr1geo\n"
|
||||
"caches-extra-info\n"
|
||||
"signing-key\n"
|
||||
"-----BEGIN RSA PUBLIC KEY-----\n"
|
||||
"MIGJAoGBALcIIij7gNpvSZPvaCLDDNyyQZq7fR0aXiHgmiIc5hYVcBl+zF5sTX6a\n"
|
||||
"jQF+GQdbSHcRzA1IMWPXnA7+nGOxSNayrQwExuf7ESsBaQHU81/dmV+rgTwtcd3K\n"
|
||||
"9lobTQUm+idLvGjVF5P1XJkduPvURIgpIfXT1ZHJUQhwxWSw8MmnAgMBAAE=\n"
|
||||
"-----END RSA PUBLIC KEY-----\n"
|
||||
"ntor-onion-key-crosscert 1\n"
|
||||
"-----BEGIN ED25519 CERT-----\n"
|
||||
"AQoAB0wmAcFAnWgKWtdR6dYL3QVgRRAOkxJ3F3EqWtHzetjL6R4ZAFPSCMLyQ82v\n"
|
||||
"dvcpZDa7C/qp8TsJn2Z8v77RjRc2QD1KYDzGfg5euwlB1lu8+IR38l3mmC1PXXhe\n"
|
||||
"ZB84q4aUdAA=\n"
|
||||
"-----END ED25519 CERT-----\n"
|
||||
"hidden-service-dir\n"
|
||||
"contact auth1@test.test\n"
|
||||
"ntor-onion-key m0dedSB2vjtvz08bNu+LCdIApVuspRlzXbsphXZ62zQ\n"
|
||||
"reject *:*\n"
|
||||
"tunnelled-dir-server\n"
|
||||
"router-sig-ed25519 VMwmiN9KhWWFSFSuVZxG1g46mb2QhMhv0UlatvPKyAV+1jPl"
|
||||
"EbDFaO1Qur0335Rn0ToysC6UqB1p78pefX67Aw\n"
|
||||
"router-signature\n"
|
||||
"-----BEGIN SIGNATURE-----\n"
|
||||
"q9Hxy4FJVIK2ks/ByBv8P1p7Pc68ie/TTlDN+tce9opPlijy9+ze9/Gd2SKonRm1\n"
|
||||
"J+WBj/kKYKw+YoUExIT0qMfa6QTCOe/ecp1sNmgeW0YfloP4Nv8goi3S0k4yrPk/\n"
|
||||
"qw6TIXGYJpvrdR1Qe7+MEl2K1Okqsy5amtOU400lYRA=\n"
|
||||
"-----END SIGNATURE-----\n"
|
||||
;
|
||||
|
||||
static void
|
||||
test_dir_parse_no_onion_keyrouter_list(void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
routerinfo_t *ri =
|
||||
router_parse_entry_from_string(ROUTERDESC_NO_ONION_KEY, NULL,
|
||||
0, 1, 0, NULL);
|
||||
|
||||
tt_assert(ri);
|
||||
tt_assert(ri->tap_onion_pkey == NULL);
|
||||
|
||||
done:
|
||||
routerinfo_free(ri);
|
||||
}
|
||||
|
||||
static download_status_t dls_minimal;
|
||||
static download_status_t dls_maximal;
|
||||
static download_status_t dls_bad_fingerprint;
|
||||
@ -7227,6 +7295,7 @@ struct testcase_t dir_tests[] = {
|
||||
DIR(routerinfo_parsing, 0),
|
||||
DIR(extrainfo_parsing, 0),
|
||||
DIR(parse_router_list, TT_FORK),
|
||||
DIR(parse_no_onion_keyrouter_list, TT_FORK),
|
||||
DIR(load_routers, TT_FORK),
|
||||
DIR(load_extrainfo, TT_FORK),
|
||||
DIR(getinfo_extra, 0),
|
||||
|
@ -1192,7 +1192,7 @@ test_socks_hs_errors(void *arg)
|
||||
ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
|
||||
/* Code path will log this exit so build it. */
|
||||
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
|
||||
NULL, NULL, NULL, &addr,
|
||||
NULL, NULL, &addr,
|
||||
4242, NULL, false);
|
||||
/* Attach socks connection to this rendezvous circuit. */
|
||||
ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn);
|
||||
@ -1287,7 +1287,7 @@ test_close_intro_circuit_failure(void *arg)
|
||||
ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
|
||||
/* Code path will log this exit so build it. */
|
||||
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
|
||||
NULL, NULL, NULL, &addr,
|
||||
NULL, NULL, &addr,
|
||||
4242, NULL, false);
|
||||
ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey);
|
||||
|
||||
@ -1314,7 +1314,7 @@ test_close_intro_circuit_failure(void *arg)
|
||||
ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
|
||||
/* Code path will log this exit so build it. */
|
||||
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
|
||||
NULL, NULL, NULL, &addr,
|
||||
NULL, NULL, &addr,
|
||||
4242, NULL, false);
|
||||
ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey);
|
||||
|
||||
@ -1337,7 +1337,7 @@ test_close_intro_circuit_failure(void *arg)
|
||||
ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
|
||||
/* Code path will log this exit so build it. */
|
||||
ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
|
||||
NULL, NULL, NULL, &addr,
|
||||
NULL, NULL, &addr,
|
||||
4242, NULL, false);
|
||||
ed25519_pubkey_copy(ô->hs_ident->intro_auth_pk, &intro_kp.pubkey);
|
||||
|
||||
|
@ -1605,7 +1605,6 @@ test_build_update_descriptors(void *arg)
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
ri.onion_curve25519_pkey =
|
||||
tor_malloc_zero(sizeof(curve25519_public_key_t));
|
||||
ri.onion_pkey = tor_malloc_zero(140);
|
||||
curve25519_public_key_generate(ri.onion_curve25519_pkey,
|
||||
&curve25519_secret_key);
|
||||
memset(ri.cache_info.identity_digest, 'A', DIGEST_LEN);
|
||||
@ -1631,7 +1630,6 @@ test_build_update_descriptors(void *arg)
|
||||
update_all_descriptors_intro_points(now);
|
||||
tor_free(node->ri->onion_curve25519_pkey); /* Avoid memleak. */
|
||||
tor_free(node->ri->cache_info.signing_key_cert);
|
||||
tor_free(node->ri->onion_pkey);
|
||||
expect_log_msg_containing("just picked 1 intro points and wanted 3 for next "
|
||||
"descriptor. It currently has 0 intro points. "
|
||||
"Launching ESTABLISH_INTRO circuit shortly.");
|
||||
|
@ -760,6 +760,35 @@ test_md_parse_id_ed25519(void *arg)
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
static void
|
||||
test_md_parse_no_onion_key(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
/* A correct MD with no onion key. */
|
||||
const char GOOD_MD[] =
|
||||
"onion-key\n"
|
||||
"ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
|
||||
"id ed25519 VGhpcyBpc24ndCBhY3R1YWxseSBhIHB1YmxpYyBrZXk\n";
|
||||
|
||||
smartlist_t *mds = NULL;
|
||||
|
||||
mds = microdescs_parse_from_string(GOOD_MD,
|
||||
NULL, 1, SAVED_NOWHERE, NULL);
|
||||
tt_assert(mds);
|
||||
tt_int_op(smartlist_len(mds), OP_EQ, 1);
|
||||
const microdesc_t *md = smartlist_get(mds, 0);
|
||||
tt_mem_op(md->ed25519_identity_pkey, OP_EQ,
|
||||
"This isn't actually a public key", ED25519_PUBKEY_LEN);
|
||||
|
||||
done:
|
||||
if (mds) {
|
||||
SMARTLIST_FOREACH(mds, microdesc_t *, m, microdesc_free(m));
|
||||
smartlist_free(mds);
|
||||
}
|
||||
teardown_capture_of_logs();
|
||||
}
|
||||
|
||||
static int mock_rgsbd_called = 0;
|
||||
static routerstatus_t *mock_rgsbd_val_a = NULL;
|
||||
static routerstatus_t *mock_rgsbd_val_b = NULL;
|
||||
@ -894,6 +923,7 @@ struct testcase_t microdesc_tests[] = {
|
||||
{ "generate", test_md_generate, 0, NULL, NULL },
|
||||
{ "parse", test_md_parse, 0, NULL, NULL },
|
||||
{ "parse_id_ed25519", test_md_parse_id_ed25519, 0, NULL, NULL },
|
||||
{ "parse_no_onion_key", test_md_parse_no_onion_key, 0, NULL, NULL },
|
||||
{ "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL },
|
||||
{ "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL },
|
||||
END_OF_TESTCASES
|
||||
|
@ -329,7 +329,7 @@ test_protover_supports_version(void *arg)
|
||||
* headers. */
|
||||
#define PROTOVER_LINKAUTH_V1 1
|
||||
#define PROTOVER_LINKAUTH_V2 2
|
||||
#define PROTOVER_RELAY_V1 1
|
||||
#define PROTOVER_RELAY_V2 2
|
||||
|
||||
/* Deprecated HSIntro versions */
|
||||
#define PROTOVER_HS_INTRO_DEPRECATED_1 1
|
||||
@ -397,7 +397,7 @@ test_protover_supported_protocols(void *arg)
|
||||
/* Relay protovers do not appear anywhere in the code. */
|
||||
tt_assert(protocol_list_supports_protocol(supported_protocols,
|
||||
PRT_RELAY,
|
||||
PROTOVER_RELAY_V1));
|
||||
PROTOVER_RELAY_V2));
|
||||
tt_assert(protocol_list_supports_protocol(supported_protocols,
|
||||
PRT_RELAY,
|
||||
PROTOVER_RELAY_EXTEND2));
|
||||
|
@ -60,8 +60,8 @@ rtr_tests_gen_routerinfo(crypto_pk_t *ident_key, crypto_pk_t *tap_key)
|
||||
mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key);
|
||||
mock_routerinfo->protocol_list =
|
||||
tor_strdup("Cons=1-2 Desc=1-2 DirCache=1-2");
|
||||
router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->onion_pkey,
|
||||
&mock_routerinfo->onion_pkey_len);
|
||||
router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->tap_onion_pkey,
|
||||
&mock_routerinfo->tap_onion_pkey_len);
|
||||
mock_routerinfo->bandwidthrate = 9001;
|
||||
mock_routerinfo->bandwidthburst = 9002;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user