diff --git a/src/core/or/congestion_control_common.c b/src/core/or/congestion_control_common.c index 7e38510814..bd0383e06c 100644 --- a/src/core/or/congestion_control_common.c +++ b/src/core/or/congestion_control_common.c @@ -78,6 +78,8 @@ static bool congestion_control_update_circuit_bdp(congestion_control_t *, const circuit_t *, const crypt_path_t *, uint64_t, uint64_t); +/* For unit tests */ +void congestion_control_set_cc_enabled(void); /* Consensus parameters cached. The non static ones are extern. */ static uint32_t cwnd_max = CWND_MAX_DFLT; @@ -299,6 +301,16 @@ congestion_control_enabled(void) return cc_alg != CC_ALG_SENDME; } +/** + * For unit tests only: set the cached consensus cc alg to + * specified value. + */ +void +congestion_control_set_cc_enabled(void) +{ + cc_alg = CC_ALG_VEGAS; +} + /** * Allocate and initialize fields in congestion control object. * diff --git a/src/core/or/congestion_control_common.h b/src/core/or/congestion_control_common.h index c8f6b1c35e..4fd404a1cc 100644 --- a/src/core/or/congestion_control_common.h +++ b/src/core/or/congestion_control_common.h @@ -118,6 +118,8 @@ n_count_ewma(uint64_t curr, uint64_t prev, uint64_t N) */ #ifdef TOR_UNIT_TESTS +void congestion_control_set_cc_enabled(void); + #endif /* defined(TOR_UNIT_TESTS) */ #endif /* defined(TOR_CONGESTION_CONTROL_PRIVATE) */ diff --git a/src/test/test_ntor_v3.c b/src/test/test_ntor_v3.c index 096ac6668f..1d06403076 100644 --- a/src/test/test_ntor_v3.c +++ b/src/test/test_ntor_v3.c @@ -10,6 +10,12 @@ #include "lib/crypt_ops/crypto_curve25519.h" #include "lib/crypt_ops/crypto_ed25519.h" #include "core/crypto/onion_ntor_v3.h" +#include "core/crypto/onion_crypto.h" +#include "core/or/extend_info_st.h" +#include "core/or/crypt_path_st.h" +#define TOR_CONGESTION_CONTROL_PRIVATE +#include "core/or/congestion_control_common.h" +#include "app/config/config.h" #define unhex(arry, s) \ { tt_int_op(sizeof(arry), OP_EQ, \ @@ -166,7 +172,140 @@ test_ntor3_testvecs(void *arg) dimap_free(private_keys, NULL); } +static void +run_full_handshake(circuit_params_t *serv_params_in, + circuit_params_t *client_params_out, + circuit_params_t *serv_params_out) +{ + extend_info_t info = {0}; + uint8_t onionskin[CELL_PAYLOAD_SIZE]; + int onionskin_len = 0; + int reply_len = 0; + onion_handshake_state_t handshake_state = {0}; + server_onion_keys_t server_keys = {0}; + curve25519_keypair_t relay_onion_key; + uint8_t serv_reply[CELL_PAYLOAD_SIZE]; + uint8_t serv_keys[100]; + uint8_t rend_nonce[DIGEST_LEN]; + uint8_t client_keys[CELL_PAYLOAD_SIZE]; + uint8_t rend_auth[DIGEST_LEN]; + + info.exit_supports_congestion_control = 1; + + unhex(relay_onion_key.seckey.secret_key, + "4051daa5921cfa2a1c27b08451324919538e79e788a81b38cbed097a5dff454a"); + unhex(relay_onion_key.pubkey.public_key, + "f8307a2bc1870b00b828bb74dbb8fd88e632a6375ab3bcd1ae706aaa8b6cdd1d"); + + memcpy(&info.curve25519_onion_key, + &relay_onion_key.pubkey, sizeof(info.curve25519_onion_key)); + unhex(info.ed_identity.pubkey, + "9fad2af287ef942632833d21f946c6260c33fae6172b60006e86e4a6911753a2"); + + memcpy(&server_keys.my_ed_identity, &info.ed_identity, + sizeof(server_keys.my_ed_identity)); + + dimap_add_entry(&server_keys.curve25519_key_map, + relay_onion_key.pubkey.public_key, + &relay_onion_key); + + onionskin_len = onion_skin_create(ONION_HANDSHAKE_TYPE_NTOR_V3, &info, + &handshake_state, onionskin, + sizeof(onionskin)); + tt_int_op(onionskin_len, OP_NE, -1); + + server_keys.junk_keypair = &handshake_state.u.ntor3->client_keypair; + + reply_len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3, + onionskin, onionskin_len, + &server_keys, serv_params_in, + serv_reply, sizeof(serv_reply), + serv_keys, sizeof(serv_keys), + rend_nonce, serv_params_out); + tt_int_op(reply_len, OP_NE, -1); + + tt_int_op(onion_skin_client_handshake(ONION_HANDSHAKE_TYPE_NTOR_V3, + &handshake_state, + serv_reply, reply_len, + client_keys, sizeof(client_keys), + rend_auth, client_params_out, + NULL), OP_EQ, 0); + + done: + dimap_free(server_keys.curve25519_key_map, NULL); + ntor3_handshake_state_free(handshake_state.u.ntor3); + + return; +} + +/** + * Test congestion control negotiation logic. + * + * This tests that congestion control is only enabled when both + * client and server agree, via consensus param or torrc. + * + * It also tests that when they agree, they agree on the server's + * version of sendme_inc. + */ +static void +test_ntor3_handshake(void *arg) +{ + (void)arg; + circuit_params_t client_params, serv_params, serv_ns_params; + + serv_ns_params.sendme_inc_cells = congestion_control_sendme_inc(); + + /* client off, serv off -> off */ + serv_ns_params.cc_enabled = 0; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 0); + tt_int_op(serv_params.cc_enabled, OP_EQ, 0); + + /* client off, serv on -> off */ + serv_ns_params.cc_enabled = 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 0); + tt_int_op(serv_params.cc_enabled, OP_EQ, 0); + + /* client off + param, serv on -> on */ + serv_ns_params.cc_enabled = 1; + get_options_mutable()->AlwaysCongestionControl = 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.cc_enabled, OP_EQ, 1); + + /* client on, serv off -> off */ + serv_ns_params.cc_enabled = 0; + congestion_control_set_cc_enabled(); + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 0); + tt_int_op(serv_params.cc_enabled, OP_EQ, 0); + + /* client on, serv on -> on */ + serv_ns_params.cc_enabled = 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.cc_enabled, OP_EQ, 1); + + /* client on, serv on, sendme_inc diff -> serv sendme_inc */ + serv_ns_params.cc_enabled = 1; + serv_ns_params.sendme_inc_cells += 1; + run_full_handshake(&serv_ns_params, &client_params, &serv_params); + tt_int_op(client_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.cc_enabled, OP_EQ, 1); + tt_int_op(serv_params.sendme_inc_cells, OP_EQ, + client_params.sendme_inc_cells); + tt_int_op(client_params.sendme_inc_cells, OP_EQ, + serv_ns_params.sendme_inc_cells); + tt_int_op(client_params.sendme_inc_cells, OP_NE, + congestion_control_sendme_inc()); + + done: + return; +} + struct testcase_t ntor_v3_tests[] = { { "testvecs", test_ntor3_testvecs, 0, NULL, NULL, }, + { "handshake_negtotiation", test_ntor3_handshake, 0, NULL, NULL, }, END_OF_TESTCASES, };