test_hs_cell.c (7863B)
1 /* Copyright (c) 2017-2021, The Tor Project, Inc. */ 2 /* See LICENSE for licensing information */ 3 4 /** 5 * \file test_hs_cell.c 6 * \brief Test hidden service cell functionality. 7 */ 8 9 #define HS_INTROPOINT_PRIVATE 10 #define HS_SERVICE_PRIVATE 11 12 #include "test/test.h" 13 #include "test/test_helpers.h" 14 #include "test/log_test_helpers.h" 15 16 #include "lib/crypt_ops/crypto_ed25519.h" 17 #include "lib/crypt_ops/crypto_rand.h" 18 #include "feature/hs/hs_cell.h" 19 #include "feature/hs/hs_intropoint.h" 20 #include "feature/hs/hs_service.h" 21 22 /* Trunnel. */ 23 #include "trunnel/extension.h" 24 #include "trunnel/hs/cell_establish_intro.h" 25 26 /** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we 27 * parse it from the receiver side. */ 28 static void 29 test_gen_establish_intro_cell(void *arg) 30 { 31 (void) arg; 32 ssize_t ret; 33 char circ_nonce[DIGEST_LEN] = {0}; 34 uint8_t buf[RELAY_PAYLOAD_SIZE]; 35 trn_cell_establish_intro_t *cell_in = NULL; 36 37 crypto_rand(circ_nonce, sizeof(circ_nonce)); 38 39 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we 40 attempt to parse it. */ 41 { 42 hs_service_config_t config; 43 memset(&config, 0, sizeof(config)); 44 /* We only need the auth key pair here. */ 45 hs_service_intro_point_t *ip = service_intro_point_new(NULL); 46 /* Auth key pair is generated in the constructor so we are all set for 47 * using this IP object. */ 48 ret = hs_cell_build_establish_intro(circ_nonce, &config, ip, buf); 49 service_intro_point_free(ip); 50 tt_u64_op(ret, OP_GT, 0); 51 } 52 53 /* Check the contents of the cell */ 54 { 55 /* First byte is the auth key type: make sure its correct */ 56 tt_int_op(buf[0], OP_EQ, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519); 57 /* Next two bytes is auth key len */ 58 tt_int_op(ntohs(get_uint16(buf+1)), OP_EQ, ED25519_PUBKEY_LEN); 59 /* Skip to the number of extensions: no extensions */ 60 tt_int_op(buf[35], OP_EQ, 0); 61 /* Skip to the sig len. Make sure it's the size of an ed25519 sig */ 62 tt_int_op(ntohs(get_uint16(buf+35+1+32)), OP_EQ, ED25519_SIG_LEN); 63 } 64 65 /* Parse it as the receiver */ 66 { 67 ret = trn_cell_establish_intro_parse(&cell_in, buf, sizeof(buf)); 68 tt_u64_op(ret, OP_GT, 0); 69 70 ret = verify_establish_intro_cell(cell_in, 71 (const uint8_t *) circ_nonce, 72 sizeof(circ_nonce)); 73 tt_u64_op(ret, OP_EQ, 0); 74 } 75 76 done: 77 trn_cell_establish_intro_free(cell_in); 78 } 79 80 /* Mocked ed25519_sign_prefixed() function that always fails :) */ 81 static int 82 mock_ed25519_sign_prefixed(ed25519_signature_t *signature_out, 83 const uint8_t *msg, size_t msg_len, 84 const char *prefix_str, 85 const ed25519_keypair_t *keypair) { 86 (void) signature_out; 87 (void) msg; 88 (void) msg_len; 89 (void) prefix_str; 90 (void) keypair; 91 return -1; 92 } 93 94 /** We simulate a failure to create an ESTABLISH_INTRO cell */ 95 static void 96 test_gen_establish_intro_cell_bad(void *arg) 97 { 98 (void) arg; 99 ssize_t cell_len = 0; 100 trn_cell_establish_intro_t *cell = NULL; 101 char circ_nonce[DIGEST_LEN] = {0}; 102 hs_service_intro_point_t *ip = NULL; 103 hs_service_config_t config; 104 105 memset(&config, 0, sizeof(config)); 106 107 MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed); 108 109 crypto_rand(circ_nonce, sizeof(circ_nonce)); 110 111 setup_full_capture_of_logs(LOG_WARN); 112 /* Easiest way to make that function fail is to mock the 113 ed25519_sign_prefixed() function and make it fail. */ 114 cell = trn_cell_establish_intro_new(); 115 tt_assert(cell); 116 ip = service_intro_point_new(NULL); 117 cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, NULL); 118 service_intro_point_free(ip); 119 expect_log_msg_containing("Unable to make signature for " 120 "ESTABLISH_INTRO cell."); 121 teardown_capture_of_logs(); 122 tt_i64_op(cell_len, OP_EQ, -1); 123 124 done: 125 trn_cell_establish_intro_free(cell); 126 UNMOCK(ed25519_sign_prefixed); 127 } 128 129 static void 130 test_gen_establish_intro_dos_ext(void *arg) 131 { 132 ssize_t ret; 133 hs_service_config_t config; 134 hs_service_intro_point_t *ip = NULL; 135 trn_extension_t *extensions = NULL; 136 trn_cell_extension_dos_t *dos = NULL; 137 138 (void) arg; 139 140 memset(&config, 0, sizeof(config)); 141 ip = service_intro_point_new(NULL); 142 tt_assert(ip); 143 ip->support_intro2_dos_defense = 1; 144 145 /* Case 1: No DoS parameters so no extension to be built. */ 146 extensions = build_establish_intro_extensions(&config, ip); 147 tt_int_op(trn_extension_get_num(extensions), OP_EQ, 0); 148 trn_extension_free(extensions); 149 extensions = NULL; 150 151 /* Case 2: Enable the DoS extension. Parameter set to 0 should indicate to 152 * disable the defense on the intro point but there should be an extension 153 * nonetheless in the cell. */ 154 config.has_dos_defense_enabled = 1; 155 extensions = build_establish_intro_extensions(&config, ip); 156 tt_int_op(trn_extension_get_num(extensions), OP_EQ, 1); 157 /* Validate the extension. */ 158 const trn_extension_field_t *field = 159 trn_extension_getconst_fields(extensions, 0); 160 tt_int_op(trn_extension_field_get_field_type(field), OP_EQ, 161 TRUNNEL_CELL_EXTENSION_TYPE_DOS); 162 ret = trn_cell_extension_dos_parse(&dos, 163 trn_extension_field_getconstarray_field(field), 164 trn_extension_field_getlen_field(field)); 165 tt_int_op(ret, OP_EQ, 19); 166 /* Rate per sec param. */ 167 const trn_cell_extension_dos_param_t *param = 168 trn_cell_extension_dos_getconst_params(dos, 0); 169 tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ, 170 TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC); 171 tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0); 172 /* Burst per sec param. */ 173 param = trn_cell_extension_dos_getconst_params(dos, 1); 174 tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ, 175 TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC); 176 tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0); 177 trn_cell_extension_dos_free(dos); dos = NULL; 178 trn_extension_free(extensions); extensions = NULL; 179 180 /* Case 3: Enable the DoS extension. Parameter set to some normal values. */ 181 config.has_dos_defense_enabled = 1; 182 config.intro_dos_rate_per_sec = 42; 183 config.intro_dos_burst_per_sec = 250; 184 extensions = build_establish_intro_extensions(&config, ip); 185 tt_int_op(trn_extension_get_num(extensions), OP_EQ, 1); 186 /* Validate the extension. */ 187 field = trn_extension_getconst_fields(extensions, 0); 188 tt_int_op(trn_extension_field_get_field_type(field), OP_EQ, 189 TRUNNEL_CELL_EXTENSION_TYPE_DOS); 190 ret = trn_cell_extension_dos_parse(&dos, 191 trn_extension_field_getconstarray_field(field), 192 trn_extension_field_getlen_field(field)); 193 tt_int_op(ret, OP_EQ, 19); 194 /* Rate per sec param. */ 195 param = trn_cell_extension_dos_getconst_params(dos, 0); 196 tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ, 197 TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC); 198 tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 42); 199 /* Burst per sec param. */ 200 param = trn_cell_extension_dos_getconst_params(dos, 1); 201 tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ, 202 TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC); 203 tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 250); 204 trn_cell_extension_dos_free(dos); dos = NULL; 205 trn_extension_free(extensions); extensions = NULL; 206 207 done: 208 service_intro_point_free(ip); 209 trn_cell_extension_dos_free(dos); 210 trn_extension_free(extensions); 211 } 212 213 struct testcase_t hs_cell_tests[] = { 214 { "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK, 215 NULL, NULL }, 216 { "gen_establish_intro_cell_bad", test_gen_establish_intro_cell_bad, TT_FORK, 217 NULL, NULL }, 218 { "gen_establish_intro_dos_ext", test_gen_establish_intro_dos_ext, TT_FORK, 219 NULL, NULL }, 220 221 END_OF_TESTCASES 222 };