Line data Source code
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/hs/cell_common.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 1 : test_gen_establish_intro_cell(void *arg)
30 : {
31 1 : (void) arg;
32 1 : ssize_t ret;
33 1 : char circ_nonce[DIGEST_LEN] = {0};
34 1 : uint8_t buf[RELAY_PAYLOAD_SIZE];
35 1 : trn_cell_establish_intro_t *cell_in = NULL;
36 :
37 1 : 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 1 : hs_service_config_t config;
43 1 : memset(&config, 0, sizeof(config));
44 : /* We only need the auth key pair here. */
45 1 : 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 1 : ret = hs_cell_build_establish_intro(circ_nonce, &config, ip, buf);
49 1 : service_intro_point_free(ip);
50 1 : 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 1 : tt_int_op(buf[0], OP_EQ, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
57 : /* Next two bytes is auth key len */
58 1 : tt_int_op(ntohs(get_uint16(buf+1)), OP_EQ, ED25519_PUBKEY_LEN);
59 : /* Skip to the number of extensions: no extensions */
60 1 : 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 1 : 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 1 : ret = trn_cell_establish_intro_parse(&cell_in, buf, sizeof(buf));
68 1 : tt_u64_op(ret, OP_GT, 0);
69 :
70 1 : ret = verify_establish_intro_cell(cell_in,
71 : (const uint8_t *) circ_nonce,
72 : sizeof(circ_nonce));
73 1 : tt_u64_op(ret, OP_EQ, 0);
74 : }
75 :
76 1 : done:
77 1 : trn_cell_establish_intro_free(cell_in);
78 1 : }
79 :
80 : /* Mocked ed25519_sign_prefixed() function that always fails :) */
81 : static int
82 1 : 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 1 : (void) signature_out;
87 1 : (void) msg;
88 1 : (void) msg_len;
89 1 : (void) prefix_str;
90 1 : (void) keypair;
91 1 : return -1;
92 : }
93 :
94 : /** We simulate a failure to create an ESTABLISH_INTRO cell */
95 : static void
96 1 : test_gen_establish_intro_cell_bad(void *arg)
97 : {
98 1 : (void) arg;
99 1 : ssize_t cell_len = 0;
100 1 : trn_cell_establish_intro_t *cell = NULL;
101 1 : char circ_nonce[DIGEST_LEN] = {0};
102 1 : hs_service_intro_point_t *ip = NULL;
103 1 : hs_service_config_t config;
104 :
105 1 : memset(&config, 0, sizeof(config));
106 :
107 1 : MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed);
108 :
109 1 : crypto_rand(circ_nonce, sizeof(circ_nonce));
110 :
111 1 : 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 1 : cell = trn_cell_establish_intro_new();
115 1 : tt_assert(cell);
116 1 : ip = service_intro_point_new(NULL);
117 1 : cell_len = hs_cell_build_establish_intro(circ_nonce, &config, ip, NULL);
118 1 : service_intro_point_free(ip);
119 1 : expect_log_msg_containing("Unable to make signature for "
120 1 : "ESTABLISH_INTRO cell.");
121 1 : teardown_capture_of_logs();
122 1 : tt_i64_op(cell_len, OP_EQ, -1);
123 :
124 1 : done:
125 1 : trn_cell_establish_intro_free(cell);
126 1 : UNMOCK(ed25519_sign_prefixed);
127 1 : }
128 :
129 : static void
130 1 : test_gen_establish_intro_dos_ext(void *arg)
131 : {
132 1 : ssize_t ret;
133 1 : hs_service_config_t config;
134 1 : hs_service_intro_point_t *ip = NULL;
135 1 : trn_cell_extension_t *extensions = NULL;
136 1 : trn_cell_extension_dos_t *dos = NULL;
137 :
138 1 : (void) arg;
139 :
140 1 : memset(&config, 0, sizeof(config));
141 1 : ip = service_intro_point_new(NULL);
142 1 : tt_assert(ip);
143 1 : ip->support_intro2_dos_defense = 1;
144 :
145 : /* Case 1: No DoS parameters so no extension to be built. */
146 1 : extensions = build_establish_intro_extensions(&config, ip);
147 1 : tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 0);
148 1 : trn_cell_extension_free(extensions);
149 1 : 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 1 : config.has_dos_defense_enabled = 1;
155 1 : extensions = build_establish_intro_extensions(&config, ip);
156 1 : tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1);
157 : /* Validate the extension. */
158 1 : const trn_cell_extension_field_t *field =
159 1 : trn_cell_extension_getconst_fields(extensions, 0);
160 1 : tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ,
161 : TRUNNEL_CELL_EXTENSION_TYPE_DOS);
162 1 : ret = trn_cell_extension_dos_parse(&dos,
163 : trn_cell_extension_field_getconstarray_field(field),
164 : trn_cell_extension_field_getlen_field(field));
165 1 : tt_int_op(ret, OP_EQ, 19);
166 : /* Rate per sec param. */
167 1 : const trn_cell_extension_dos_param_t *param =
168 1 : trn_cell_extension_dos_getconst_params(dos, 0);
169 1 : tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
170 : TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC);
171 1 : tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0);
172 : /* Burst per sec param. */
173 1 : param = trn_cell_extension_dos_getconst_params(dos, 1);
174 1 : tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
175 : TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
176 1 : tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 0);
177 1 : trn_cell_extension_dos_free(dos); dos = NULL;
178 1 : trn_cell_extension_free(extensions); extensions = NULL;
179 :
180 : /* Case 3: Enable the DoS extension. Parameter set to some normal values. */
181 1 : config.has_dos_defense_enabled = 1;
182 1 : config.intro_dos_rate_per_sec = 42;
183 1 : config.intro_dos_burst_per_sec = 250;
184 1 : extensions = build_establish_intro_extensions(&config, ip);
185 1 : tt_int_op(trn_cell_extension_get_num(extensions), OP_EQ, 1);
186 : /* Validate the extension. */
187 1 : field = trn_cell_extension_getconst_fields(extensions, 0);
188 1 : tt_int_op(trn_cell_extension_field_get_field_type(field), OP_EQ,
189 : TRUNNEL_CELL_EXTENSION_TYPE_DOS);
190 1 : ret = trn_cell_extension_dos_parse(&dos,
191 : trn_cell_extension_field_getconstarray_field(field),
192 : trn_cell_extension_field_getlen_field(field));
193 1 : tt_int_op(ret, OP_EQ, 19);
194 : /* Rate per sec param. */
195 1 : param = trn_cell_extension_dos_getconst_params(dos, 0);
196 1 : tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
197 : TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC);
198 1 : tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 42);
199 : /* Burst per sec param. */
200 1 : param = trn_cell_extension_dos_getconst_params(dos, 1);
201 1 : tt_int_op(trn_cell_extension_dos_param_get_type(param), OP_EQ,
202 : TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
203 1 : tt_u64_op(trn_cell_extension_dos_param_get_value(param), OP_EQ, 250);
204 1 : trn_cell_extension_dos_free(dos); dos = NULL;
205 1 : trn_cell_extension_free(extensions); extensions = NULL;
206 :
207 1 : done:
208 1 : service_intro_point_free(ip);
209 1 : trn_cell_extension_dos_free(dos);
210 1 : trn_cell_extension_free(extensions);
211 1 : }
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 : };
223 :
|