1 /* Copyright (c) 2017-2020, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief Test hidden service cell functionality.
9 #define HS_INTROPOINT_PRIVATE
10 #define HS_SERVICE_PRIVATE
12 #include "test/test.h"
13 #include "test/test_helpers.h"
14 #include "test/log_test_helpers.h"
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"
23 #include "trunnel/hs/cell_common.h"
24 #include "trunnel/hs/cell_establish_intro.h"
26 /** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we
27 * parse it from the receiver side. */
29 test_gen_establish_intro_cell(void *arg
)
33 char circ_nonce
[DIGEST_LEN
] = {0};
34 uint8_t buf
[RELAY_PAYLOAD_SIZE
];
35 trn_cell_establish_intro_t
*cell_in
= NULL
;
37 crypto_rand(circ_nonce
, sizeof(circ_nonce
));
39 /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we
40 attempt to parse it. */
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);
53 /* Check the contents of the cell */
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
);
65 /* Parse it as the receiver */
67 ret
= trn_cell_establish_intro_parse(&cell_in
, buf
, sizeof(buf
));
68 tt_u64_op(ret
, OP_GT
, 0);
70 ret
= verify_establish_intro_cell(cell_in
,
71 (const uint8_t *) circ_nonce
,
73 tt_u64_op(ret
, OP_EQ
, 0);
77 trn_cell_establish_intro_free(cell_in
);
80 /* Mocked ed25519_sign_prefixed() function that always fails :) */
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
) {
94 /** We simulate a failure to create an ESTABLISH_INTRO cell */
96 test_gen_establish_intro_cell_bad(void *arg
)
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
;
105 memset(&config
, 0, sizeof(config
));
107 MOCK(ed25519_sign_prefixed
, mock_ed25519_sign_prefixed
);
109 crypto_rand(circ_nonce
, sizeof(circ_nonce
));
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();
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);
125 trn_cell_establish_intro_free(cell
);
126 UNMOCK(ed25519_sign_prefixed
);
130 test_gen_establish_intro_dos_ext(void *arg
)
133 hs_service_config_t config
;
134 hs_service_intro_point_t
*ip
= NULL
;
135 trn_cell_extension_t
*extensions
= NULL
;
136 trn_cell_extension_dos_t
*dos
= NULL
;
140 memset(&config
, 0, sizeof(config
));
141 ip
= service_intro_point_new(NULL
);
143 ip
->support_intro2_dos_defense
= 1;
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_cell_extension_get_num(extensions
), OP_EQ
, 0);
148 trn_cell_extension_free(extensions
);
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_cell_extension_get_num(extensions
), OP_EQ
, 1);
157 /* Validate the extension. */
158 const trn_cell_extension_field_t
*field
=
159 trn_cell_extension_getconst_fields(extensions
, 0);
160 tt_int_op(trn_cell_extension_field_get_field_type(field
), OP_EQ
,
161 TRUNNEL_CELL_EXTENSION_TYPE_DOS
);
162 ret
= trn_cell_extension_dos_parse(&dos
,
163 trn_cell_extension_field_getconstarray_field(field
),
164 trn_cell_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_cell_extension_free(extensions
); extensions
= NULL
;
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_cell_extension_get_num(extensions
), OP_EQ
, 1);
186 /* Validate the extension. */
187 field
= trn_cell_extension_getconst_fields(extensions
, 0);
188 tt_int_op(trn_cell_extension_field_get_field_type(field
), OP_EQ
,
189 TRUNNEL_CELL_EXTENSION_TYPE_DOS
);
190 ret
= trn_cell_extension_dos_parse(&dos
,
191 trn_cell_extension_field_getconstarray_field(field
),
192 trn_cell_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_cell_extension_free(extensions
); extensions
= NULL
;
208 service_intro_point_free(ip
);
209 trn_cell_extension_dos_free(dos
);
210 trn_cell_extension_free(extensions
);
213 struct testcase_t hs_cell_tests
[] = {
214 { "gen_establish_intro_cell", test_gen_establish_intro_cell
, TT_FORK
,
216 { "gen_establish_intro_cell_bad", test_gen_establish_intro_cell_bad
, TT_FORK
,
218 { "gen_establish_intro_dos_ext", test_gen_establish_intro_dos_ext
, TT_FORK
,