/src/libzmq/tests/testutil_security.cpp
Line | Count | Source |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | #include "testutil_security.hpp" |
3 | | |
4 | | #include <stdlib.h> |
5 | | #include <string.h> |
6 | | |
7 | | const char *test_zap_domain = "ZAPTEST"; |
8 | | |
9 | | void socket_config_null_client (void *server_, void *server_secret_) |
10 | 0 | { |
11 | 0 | LIBZMQ_UNUSED (server_); |
12 | 0 | LIBZMQ_UNUSED (server_secret_); |
13 | 0 | } |
14 | | |
15 | | void socket_config_null_server (void *server_, void *server_secret_) |
16 | 0 | { |
17 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
18 | 0 | server_, ZMQ_ZAP_DOMAIN, test_zap_domain, strlen (test_zap_domain))); |
19 | | #ifdef ZMQ_ZAP_ENFORCE_DOMAIN |
20 | | int required = server_secret_ ? *static_cast<int *> (server_secret_) : 0; |
21 | | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (server_, ZMQ_ZAP_ENFORCE_DOMAIN, |
22 | | &required, sizeof (int))); |
23 | | #else |
24 | 0 | LIBZMQ_UNUSED (server_secret_); |
25 | 0 | #endif |
26 | 0 | } |
27 | | |
28 | | static const char test_plain_username[] = "testuser"; |
29 | | static const char test_plain_password[] = "testpass"; |
30 | | |
31 | | void socket_config_plain_client (void *server_, void *server_secret_) |
32 | 0 | { |
33 | 0 | LIBZMQ_UNUSED (server_secret_); |
34 | |
|
35 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
36 | 0 | zmq_setsockopt (server_, ZMQ_PLAIN_PASSWORD, test_plain_password, 8)); |
37 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
38 | 0 | zmq_setsockopt (server_, ZMQ_PLAIN_USERNAME, test_plain_username, 8)); |
39 | 0 | } |
40 | | |
41 | | void socket_config_plain_server (void *server_, void *server_secret_) |
42 | 0 | { |
43 | 0 | LIBZMQ_UNUSED (server_secret_); |
44 | |
|
45 | 0 | int as_server = 1; |
46 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
47 | 0 | zmq_setsockopt (server_, ZMQ_PLAIN_SERVER, &as_server, sizeof (int))); |
48 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
49 | 0 | server_, ZMQ_ZAP_DOMAIN, test_zap_domain, strlen (test_zap_domain))); |
50 | 0 | } |
51 | | |
52 | | char valid_client_public[41]; |
53 | | char valid_client_secret[41]; |
54 | | char valid_server_public[41]; |
55 | | char valid_server_secret[41]; |
56 | | |
57 | | void setup_testutil_security_curve () |
58 | 0 | { |
59 | | // Generate new keypairs for these tests |
60 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
61 | 0 | zmq_curve_keypair (valid_client_public, valid_client_secret)); |
62 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
63 | 0 | zmq_curve_keypair (valid_server_public, valid_server_secret)); |
64 | 0 | } |
65 | | |
66 | | void socket_config_curve_server (void *server_, void *server_secret_) |
67 | 0 | { |
68 | 0 | int as_server = 1; |
69 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
70 | 0 | zmq_setsockopt (server_, ZMQ_CURVE_SERVER, &as_server, sizeof (int))); |
71 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
72 | 0 | zmq_setsockopt (server_, ZMQ_CURVE_SECRETKEY, server_secret_, 41)); |
73 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
74 | 0 | server_, ZMQ_ZAP_DOMAIN, test_zap_domain, strlen (test_zap_domain))); |
75 | |
|
76 | | #ifdef ZMQ_ZAP_ENFORCE_DOMAIN |
77 | | int required = 1; |
78 | | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (server_, ZMQ_ZAP_ENFORCE_DOMAIN, |
79 | | &required, sizeof (int))); |
80 | | #endif |
81 | 0 | } |
82 | | |
83 | | void socket_config_curve_client (void *client_, void *data_) |
84 | 0 | { |
85 | 0 | const curve_client_data_t *const curve_client_data = |
86 | 0 | static_cast<const curve_client_data_t *> (data_); |
87 | |
|
88 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
89 | 0 | client_, ZMQ_CURVE_SERVERKEY, curve_client_data->server_public, 41)); |
90 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
91 | 0 | client_, ZMQ_CURVE_PUBLICKEY, curve_client_data->client_public, 41)); |
92 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
93 | 0 | client_, ZMQ_CURVE_SECRETKEY, curve_client_data->client_secret, 41)); |
94 | 0 | } |
95 | | |
96 | | void *zap_requests_handled; |
97 | | |
98 | | void zap_handler_generic (zap_protocol_t zap_protocol_, |
99 | | const char *expected_routing_id_) |
100 | 0 | { |
101 | 0 | void *control = zmq_socket (get_test_context (), ZMQ_REQ); |
102 | 0 | TEST_ASSERT_NOT_NULL (control); |
103 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
104 | 0 | zmq_connect (control, "inproc://handler-control")); |
105 | |
|
106 | 0 | void *handler = zmq_socket (get_test_context (), ZMQ_REP); |
107 | 0 | TEST_ASSERT_NOT_NULL (handler); |
108 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01")); |
109 | | |
110 | | // Signal main thread that we are ready |
111 | 0 | send_string_expect_success (control, "GO", 0); |
112 | |
|
113 | 0 | zmq_pollitem_t items[] = { |
114 | 0 | {control, 0, ZMQ_POLLIN, 0}, |
115 | 0 | {handler, 0, ZMQ_POLLIN, 0}, |
116 | 0 | }; |
117 | | |
118 | | // if ordered not to receive the request, ignore the second poll item |
119 | 0 | const int numitems = (zap_protocol_ == zap_do_not_recv) ? 1 : 2; |
120 | | |
121 | | // Process ZAP requests forever |
122 | 0 | while (zmq_poll (items, numitems, -1) >= 0) { |
123 | 0 | if (items[0].revents & ZMQ_POLLIN) { |
124 | 0 | recv_string_expect_success (control, "STOP", 0); |
125 | 0 | break; // Terminating - main thread signal |
126 | 0 | } |
127 | 0 | if (!(items[1].revents & ZMQ_POLLIN)) |
128 | 0 | continue; |
129 | | |
130 | 0 | char *version = s_recv (handler); |
131 | 0 | if (!version) |
132 | 0 | break; // Terminating - peer's socket closed |
133 | 0 | if (zap_protocol_ == zap_disconnect) { |
134 | 0 | free (version); |
135 | 0 | break; |
136 | 0 | } |
137 | | |
138 | 0 | char *sequence = s_recv (handler); |
139 | 0 | char *domain = s_recv (handler); |
140 | 0 | char *address = s_recv (handler); |
141 | 0 | char *routing_id = s_recv (handler); |
142 | 0 | char *mechanism = s_recv (handler); |
143 | 0 | bool authentication_succeeded = false; |
144 | 0 | if (streq (mechanism, "CURVE")) { |
145 | 0 | uint8_t client_key[32]; |
146 | 0 | TEST_ASSERT_EQUAL_INT (32, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv ( |
147 | 0 | handler, client_key, 32, 0))); |
148 | |
|
149 | 0 | char client_key_text[41]; |
150 | 0 | zmq_z85_encode (client_key_text, client_key, 32); |
151 | |
|
152 | 0 | authentication_succeeded = |
153 | 0 | streq (client_key_text, valid_client_public); |
154 | 0 | } else if (streq (mechanism, "PLAIN")) { |
155 | 0 | char client_username[32]; |
156 | 0 | int size = TEST_ASSERT_SUCCESS_ERRNO ( |
157 | 0 | zmq_recv (handler, client_username, 32, 0)); |
158 | 0 | client_username[size] = 0; |
159 | |
|
160 | 0 | char client_password[32]; |
161 | 0 | size = TEST_ASSERT_SUCCESS_ERRNO ( |
162 | 0 | zmq_recv (handler, client_password, 32, 0)); |
163 | 0 | client_password[size] = 0; |
164 | |
|
165 | 0 | authentication_succeeded = |
166 | 0 | streq (test_plain_username, client_username) |
167 | 0 | && streq (test_plain_password, client_password); |
168 | 0 | } else if (streq (mechanism, "NULL")) { |
169 | 0 | authentication_succeeded = true; |
170 | 0 | } else { |
171 | 0 | char msg[128]; |
172 | 0 | printf ("Unsupported mechanism: %s\n", mechanism); |
173 | 0 | TEST_FAIL_MESSAGE (msg); |
174 | 0 | } |
175 | |
|
176 | 0 | TEST_ASSERT_EQUAL_STRING ("1.0", version); |
177 | 0 | TEST_ASSERT_EQUAL_STRING (expected_routing_id_, routing_id); |
178 | |
|
179 | 0 | send_string_expect_success ( |
180 | 0 | handler, |
181 | 0 | zap_protocol_ == zap_wrong_version ? "invalid_version" : version, |
182 | 0 | ZMQ_SNDMORE); |
183 | 0 | send_string_expect_success (handler, |
184 | 0 | zap_protocol_ == zap_wrong_request_id |
185 | 0 | ? "invalid_request_id" |
186 | 0 | : sequence, |
187 | 0 | ZMQ_SNDMORE); |
188 | |
|
189 | 0 | if (authentication_succeeded) { |
190 | 0 | const char *status_code; |
191 | 0 | switch (zap_protocol_) { |
192 | 0 | case zap_status_internal_error: |
193 | 0 | status_code = "500"; |
194 | 0 | break; |
195 | 0 | case zap_status_temporary_failure: |
196 | 0 | status_code = "300"; |
197 | 0 | break; |
198 | 0 | case zap_status_invalid: |
199 | 0 | status_code = "invalid_status"; |
200 | 0 | break; |
201 | 0 | default: |
202 | 0 | status_code = "200"; |
203 | 0 | } |
204 | 0 | send_string_expect_success (handler, status_code, ZMQ_SNDMORE); |
205 | 0 | send_string_expect_success (handler, "OK", ZMQ_SNDMORE); |
206 | 0 | send_string_expect_success (handler, "anonymous", ZMQ_SNDMORE); |
207 | 0 | if (zap_protocol_ == zap_too_many_parts) { |
208 | 0 | send_string_expect_success (handler, "", ZMQ_SNDMORE); |
209 | 0 | } |
210 | 0 | if (zap_protocol_ != zap_do_not_send) |
211 | 0 | send_string_expect_success (handler, "", 0); |
212 | 0 | } else { |
213 | 0 | send_string_expect_success (handler, "400", ZMQ_SNDMORE); |
214 | 0 | send_string_expect_success (handler, "Invalid client public key", |
215 | 0 | ZMQ_SNDMORE); |
216 | 0 | send_string_expect_success (handler, "", ZMQ_SNDMORE); |
217 | 0 | if (zap_protocol_ != zap_do_not_send) |
218 | 0 | send_string_expect_success (handler, "", 0); |
219 | 0 | } |
220 | 0 | free (version); |
221 | 0 | free (sequence); |
222 | 0 | free (domain); |
223 | 0 | free (address); |
224 | 0 | free (routing_id); |
225 | 0 | free (mechanism); |
226 | |
|
227 | 0 | zmq_atomic_counter_inc (zap_requests_handled); |
228 | 0 | } |
229 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (handler, "inproc://zeromq.zap.01")); |
230 | 0 | close_zero_linger (handler); |
231 | |
|
232 | 0 | if (zap_protocol_ != zap_disconnect) { |
233 | 0 | send_string_expect_success (control, "STOPPED", 0); |
234 | 0 | } |
235 | 0 | close_zero_linger (control); |
236 | 0 | } |
237 | | |
238 | | void zap_handler (void *) |
239 | 0 | { |
240 | 0 | zap_handler_generic (zap_ok); |
241 | 0 | } |
242 | | |
243 | | static void setup_handshake_socket_monitor (void *server_, |
244 | | void **server_mon_, |
245 | | const char *monitor_endpoint_) |
246 | 0 | { |
247 | | // Monitor handshake events on the server |
248 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor ( |
249 | 0 | server_, monitor_endpoint_, |
250 | 0 | ZMQ_EVENT_HANDSHAKE_SUCCEEDED | ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL |
251 | 0 | | ZMQ_EVENT_HANDSHAKE_FAILED_AUTH |
252 | 0 | | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL)); |
253 | | |
254 | | // Create socket for collecting monitor events |
255 | 0 | *server_mon_ = test_context_socket (ZMQ_PAIR); |
256 | 0 | int linger = 0; |
257 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
258 | 0 | zmq_setsockopt (*server_mon_, ZMQ_LINGER, &linger, sizeof (linger))); |
259 | | |
260 | | // Connect it to the inproc endpoints so they'll get events |
261 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (*server_mon_, monitor_endpoint_)); |
262 | 0 | } |
263 | | |
264 | | void setup_context_and_server_side (void **zap_control_, |
265 | | void **zap_thread_, |
266 | | void **server_, |
267 | | void **server_mon_, |
268 | | char *my_endpoint_, |
269 | | zmq_thread_fn zap_handler_, |
270 | | socket_config_fn socket_config_, |
271 | | void *socket_config_data_, |
272 | | const char *routing_id_) |
273 | 0 | { |
274 | | // Spawn ZAP handler |
275 | 0 | zap_requests_handled = zmq_atomic_counter_new (); |
276 | 0 | TEST_ASSERT_NOT_NULL (zap_requests_handled); |
277 | |
|
278 | 0 | *zap_control_ = test_context_socket (ZMQ_REP); |
279 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
280 | 0 | zmq_bind (*zap_control_, "inproc://handler-control")); |
281 | 0 | int linger = 0; |
282 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
283 | 0 | zmq_setsockopt (*zap_control_, ZMQ_LINGER, &linger, sizeof (linger))); |
284 | |
|
285 | 0 | if (zap_handler_ != NULL) { |
286 | 0 | *zap_thread_ = zmq_threadstart (zap_handler_, NULL); |
287 | |
|
288 | 0 | recv_string_expect_success (*zap_control_, "GO", 0); |
289 | 0 | } else |
290 | 0 | *zap_thread_ = NULL; |
291 | | |
292 | | // Server socket will accept connections |
293 | 0 | *server_ = test_context_socket (ZMQ_DEALER); |
294 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
295 | 0 | zmq_setsockopt (*server_, ZMQ_LINGER, &linger, sizeof (linger))); |
296 | | // As per API by default there's no limit to the size of a message, |
297 | | // but the sanitizer allocator will barf over a gig or so |
298 | 0 | int64_t max_msg_size = 64 * 1024 * 1024; |
299 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
300 | 0 | *server_, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t))); |
301 | |
|
302 | 0 | socket_config_ (*server_, socket_config_data_); |
303 | |
|
304 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt ( |
305 | 0 | *server_, ZMQ_ROUTING_ID, routing_id_, strlen (routing_id_))); |
306 | |
|
307 | 0 | bind_loopback_ipv4 (*server_, my_endpoint_, MAX_SOCKET_STRING); |
308 | |
|
309 | 0 | const char server_monitor_endpoint[] = "inproc://monitor-server"; |
310 | 0 | setup_handshake_socket_monitor (*server_, server_mon_, |
311 | 0 | server_monitor_endpoint); |
312 | 0 | } |
313 | | |
314 | | void shutdown_context_and_server_side (void *zap_thread_, |
315 | | void *server_, |
316 | | void *server_mon_, |
317 | | void *zap_control_, |
318 | | bool zap_handler_stopped_) |
319 | 0 | { |
320 | 0 | if (zap_thread_ && !zap_handler_stopped_) { |
321 | 0 | send_string_expect_success (zap_control_, "STOP", 0); |
322 | 0 | recv_string_expect_success (zap_control_, "STOPPED", 0); |
323 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
324 | 0 | zmq_unbind (zap_control_, "inproc://handler-control")); |
325 | 0 | } |
326 | 0 | test_context_socket_close (zap_control_); |
327 | 0 | zmq_socket_monitor (server_, NULL, 0); |
328 | 0 | test_context_socket_close (server_mon_); |
329 | 0 | test_context_socket_close (server_); |
330 | | |
331 | | // Wait until ZAP handler terminates |
332 | 0 | if (zap_thread_) |
333 | 0 | zmq_threadclose (zap_thread_); |
334 | |
|
335 | 0 | zmq_atomic_counter_destroy (&zap_requests_handled); |
336 | 0 | } |
337 | | |
338 | | void *create_and_connect_client (char *my_endpoint_, |
339 | | socket_config_fn socket_config_, |
340 | | void *socket_config_data_, |
341 | | void **client_mon_) |
342 | 0 | { |
343 | 0 | void *client = test_context_socket (ZMQ_DEALER); |
344 | | // As per API by default there's no limit to the size of a message, |
345 | | // but the sanitizer allocator will barf over a gig or so |
346 | 0 | int64_t max_msg_size = 64 * 1024 * 1024; |
347 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
348 | 0 | zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t))); |
349 | |
|
350 | 0 | socket_config_ (client, socket_config_data_); |
351 | |
|
352 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint_)); |
353 | |
|
354 | 0 | if (client_mon_) { |
355 | 0 | setup_handshake_socket_monitor (client, client_mon_, |
356 | 0 | "inproc://client-monitor"); |
357 | 0 | } |
358 | |
|
359 | 0 | return client; |
360 | 0 | } |
361 | | |
362 | | void expect_new_client_bounce_fail (char *my_endpoint_, |
363 | | void *server_, |
364 | | socket_config_fn socket_config_, |
365 | | void *socket_config_data_, |
366 | | void **client_mon_, |
367 | | int expected_client_event_, |
368 | | int expected_client_value_) |
369 | 0 | { |
370 | 0 | void *my_client_mon = NULL; |
371 | 0 | TEST_ASSERT_TRUE (client_mon_ == NULL || expected_client_event_ == 0); |
372 | 0 | if (expected_client_event_ != 0) |
373 | 0 | client_mon_ = &my_client_mon; |
374 | 0 | void *client = create_and_connect_client (my_endpoint_, socket_config_, |
375 | 0 | socket_config_data_, client_mon_); |
376 | 0 | expect_bounce_fail (server_, client); |
377 | |
|
378 | 0 | if (expected_client_event_ != 0) { |
379 | 0 | int events_received = 0; |
380 | 0 | events_received = expect_monitor_event_multiple ( |
381 | 0 | my_client_mon, expected_client_event_, expected_client_value_, false); |
382 | |
|
383 | 0 | TEST_ASSERT_EQUAL_INT (1, events_received); |
384 | |
|
385 | 0 | test_context_socket_close (my_client_mon); |
386 | 0 | } |
387 | |
|
388 | 0 | test_context_socket_close_zero_linger (client); |
389 | 0 | } |