| 1 | /* |
| 2 | Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file |
| 3 | |
| 4 | This file is part of libzmq, the ZeroMQ core engine in C++. |
| 5 | |
| 6 | libzmq is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU Lesser General Public License (LGPL) as published |
| 8 | by the Free Software Foundation; either version 3 of the License, or |
| 9 | (at your option) any later version. |
| 10 | |
| 11 | As a special exception, the Contributors give you permission to link |
| 12 | this library with independent modules to produce an executable, |
| 13 | regardless of the license terms of these independent modules, and to |
| 14 | copy and distribute the resulting executable under terms of your choice, |
| 15 | provided that you also meet, for each linked independent module, the |
| 16 | terms and conditions of the license of that module. An independent |
| 17 | module is a module which is not derived from or based on this library. |
| 18 | If you modify this library, you must extend this exception to your |
| 19 | version of the library. |
| 20 | |
| 21 | libzmq is distributed in the hope that it will be useful, but WITHOUT |
| 22 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 23 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| 24 | License for more details. |
| 25 | |
| 26 | You should have received a copy of the GNU Lesser General Public License |
| 27 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 28 | */ |
| 29 | |
| 30 | // TODO remove this workaround for handling libsodium/tweetnacl |
| 31 | |
| 32 | // To define SIZE_MAX with older compilers |
| 33 | #define __STDC_LIMIT_MACROS |
| 34 | |
| 35 | #if defined ZMQ_CUSTOM_PLATFORM_HPP |
| 36 | #include "platform.hpp" |
| 37 | #else |
| 38 | #include "../src/platform.hpp" |
| 39 | #endif |
| 40 | |
| 41 | #ifndef ZMQ_USE_TWEETNACL |
| 42 | #define ZMQ_USE_TWEETNACL |
| 43 | #endif |
| 44 | #ifdef ZMQ_USE_LIBSODIUM |
| 45 | #undef ZMQ_USE_LIBSODIUM |
| 46 | #endif |
| 47 | |
| 48 | #include "testutil.hpp" |
| 49 | #include "testutil_security.hpp" |
| 50 | #if defined(ZMQ_HAVE_WINDOWS) |
| 51 | #include <winsock2.h> |
| 52 | #include <ws2tcpip.h> |
| 53 | #include <stdexcept> |
| 54 | #define close closesocket |
| 55 | #else |
| 56 | #include <sys/socket.h> |
| 57 | #include <netinet/in.h> |
| 58 | #include <arpa/inet.h> |
| 59 | #include <unistd.h> |
| 60 | #endif |
| 61 | #include <unity.h> |
| 62 | |
| 63 | #include "../src/tweetnacl.h" |
| 64 | #include "../src/curve_client_tools.hpp" |
| 65 | #include "../src/random.hpp" |
| 66 | |
| 67 | char error_message_buffer[256]; |
| 68 | |
| 69 | void *handler; |
| 70 | void *zap_thread; |
| 71 | void *server; |
| 72 | void *server_mon; |
| 73 | char my_endpoint[MAX_SOCKET_STRING]; |
| 74 | |
| 75 | void setUp () |
| 76 | { |
| 77 | setup_test_context (); |
| 78 | setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon, |
| 79 | my_endpoint); |
| 80 | } |
| 81 | |
| 82 | void tearDown () |
| 83 | { |
| 84 | shutdown_context_and_server_side (zap_thread, server, server_mon, handler); |
| 85 | teardown_test_context (); |
| 86 | } |
| 87 | |
| 88 | const int timeout = 250; |
| 89 | |
| 90 | const char large_routing_id[] = "0123456789012345678901234567890123456789" |
| 91 | "0123456789012345678901234567890123456789" |
| 92 | "0123456789012345678901234567890123456789" |
| 93 | "0123456789012345678901234567890123456789" |
| 94 | "0123456789012345678901234567890123456789" |
| 95 | "0123456789012345678901234567890123456789" |
| 96 | "012345678901234" ; |
| 97 | |
| 98 | static void zap_handler_large_routing_id (void * /*unused_*/) |
| 99 | { |
| 100 | zap_handler_generic (zap_ok, large_routing_id); |
| 101 | } |
| 102 | |
| 103 | void expect_new_client_curve_bounce_fail (const char *server_public_, |
| 104 | const char *client_public_, |
| 105 | const char *client_secret_, |
| 106 | char *my_endpoint_, |
| 107 | void *server_, |
| 108 | void **client_mon_ = NULL, |
| 109 | int expected_client_event_ = 0, |
| 110 | int expected_client_value_ = 0) |
| 111 | { |
| 112 | curve_client_data_t curve_client_data = {server_public_, client_public_, |
| 113 | client_secret_}; |
| 114 | expect_new_client_bounce_fail ( |
| 115 | my_endpoint_, server_, socket_config_curve_client, &curve_client_data, |
| 116 | client_mon_, expected_client_event_, expected_client_value_); |
| 117 | } |
| 118 | |
| 119 | void test_null_key (void *server_, |
| 120 | void *server_mon_, |
| 121 | char *my_endpoint_, |
| 122 | char *server_public_, |
| 123 | char *client_public_, |
| 124 | char *client_secret_) |
| 125 | { |
| 126 | expect_new_client_curve_bounce_fail (server_public_, client_public_, |
| 127 | client_secret_, my_endpoint_, server_); |
| 128 | |
| 129 | int handshake_failed_encryption_event_count = |
| 130 | expect_monitor_event_multiple (server_mon_, |
| 131 | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 132 | ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC); |
| 133 | |
| 134 | // handshake_failed_encryption_event_count should be at least two because |
| 135 | // expect_bounce_fail involves two exchanges |
| 136 | // however, with valgrind we see only one event (maybe the next one takes |
| 137 | // very long, or does not happen at all because something else takes very |
| 138 | // long) |
| 139 | |
| 140 | fprintf (stderr, |
| 141 | "count of " |
| 142 | "ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL/" |
| 143 | "ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC events: %i\n" , |
| 144 | handshake_failed_encryption_event_count); |
| 145 | } |
| 146 | |
| 147 | void test_curve_security_with_valid_credentials () |
| 148 | { |
| 149 | curve_client_data_t curve_client_data = { |
| 150 | valid_server_public, valid_client_public, valid_client_secret}; |
| 151 | void *client_mon; |
| 152 | void *client = create_and_connect_client ( |
| 153 | my_endpoint, socket_config_curve_client, &curve_client_data, &client_mon); |
| 154 | bounce (server, client); |
| 155 | test_context_socket_close (client); |
| 156 | |
| 157 | int event = get_monitor_event_with_timeout (server_mon, NULL, NULL, -1); |
| 158 | assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED); |
| 159 | |
| 160 | assert_no_more_monitor_events_with_timeout (server_mon, timeout); |
| 161 | |
| 162 | event = get_monitor_event_with_timeout (client_mon, NULL, NULL, -1); |
| 163 | assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED); |
| 164 | |
| 165 | assert_no_more_monitor_events_with_timeout (client_mon, timeout); |
| 166 | |
| 167 | test_context_socket_close (client_mon); |
| 168 | } |
| 169 | |
| 170 | void test_curve_security_with_bogus_client_credentials () |
| 171 | { |
| 172 | // This must be caught by the ZAP handler |
| 173 | char bogus_public[41]; |
| 174 | char bogus_secret[41]; |
| 175 | zmq_curve_keypair (bogus_public, bogus_secret); |
| 176 | |
| 177 | expect_new_client_curve_bounce_fail ( |
| 178 | valid_server_public, bogus_public, bogus_secret, my_endpoint, server, |
| 179 | NULL, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 400); |
| 180 | |
| 181 | int server_event_count = 0; |
| 182 | server_event_count = expect_monitor_event_multiple ( |
| 183 | server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 400); |
| 184 | TEST_ASSERT_LESS_OR_EQUAL_INT (1, server_event_count); |
| 185 | |
| 186 | // there may be more than one ZAP request due to repeated attempts by the client |
| 187 | TEST_ASSERT (0 == server_event_count |
| 188 | || 1 <= zmq_atomic_counter_value (zap_requests_handled)); |
| 189 | } |
| 190 | |
| 191 | void expect_zmtp_mechanism_mismatch (void *client_, |
| 192 | char *my_endpoint_, |
| 193 | void *server_, |
| 194 | void *server_mon_) |
| 195 | { |
| 196 | // This must be caught by the curve_server class, not passed to ZAP |
| 197 | TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_, my_endpoint_)); |
| 198 | expect_bounce_fail (server_, client_); |
| 199 | test_context_socket_close_zero_linger (client_); |
| 200 | |
| 201 | expect_monitor_event_multiple (server_mon_, |
| 202 | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 203 | ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH); |
| 204 | |
| 205 | TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_value (zap_requests_handled)); |
| 206 | } |
| 207 | |
| 208 | void test_curve_security_with_null_client_credentials () |
| 209 | { |
| 210 | void *client = test_context_socket (ZMQ_DEALER); |
| 211 | |
| 212 | expect_zmtp_mechanism_mismatch (client, my_endpoint, server, server_mon); |
| 213 | } |
| 214 | |
| 215 | void test_curve_security_with_plain_client_credentials () |
| 216 | { |
| 217 | void *client = test_context_socket (ZMQ_DEALER); |
| 218 | TEST_ASSERT_SUCCESS_ERRNO ( |
| 219 | zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, "admin" , 5)); |
| 220 | TEST_ASSERT_SUCCESS_ERRNO ( |
| 221 | zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, "password" , 8)); |
| 222 | |
| 223 | expect_zmtp_mechanism_mismatch (client, my_endpoint, server, server_mon); |
| 224 | } |
| 225 | |
| 226 | fd_t connect_vanilla_socket (char *my_endpoint_) |
| 227 | { |
| 228 | fd_t s; |
| 229 | struct sockaddr_in ip4addr; |
| 230 | |
| 231 | unsigned short int port; |
| 232 | int rc = sscanf (my_endpoint_, "tcp://127.0.0.1:%hu" , &port); |
| 233 | TEST_ASSERT_EQUAL_INT (1, rc); |
| 234 | |
| 235 | ip4addr.sin_family = AF_INET; |
| 236 | ip4addr.sin_port = htons (port); |
| 237 | #if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600) |
| 238 | ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1" ); |
| 239 | #else |
| 240 | inet_pton (AF_INET, "127.0.0.1" , &ip4addr.sin_addr); |
| 241 | #endif |
| 242 | |
| 243 | s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); |
| 244 | rc = connect (s, reinterpret_cast<struct sockaddr *> (&ip4addr), |
| 245 | sizeof (ip4addr)); |
| 246 | TEST_ASSERT_GREATER_THAN_INT (-1, rc); |
| 247 | return s; |
| 248 | } |
| 249 | |
| 250 | void test_curve_security_unauthenticated_message () |
| 251 | { |
| 252 | // Unauthenticated messages from a vanilla socket shouldn't be received |
| 253 | fd_t s = connect_vanilla_socket (my_endpoint); |
| 254 | // send anonymous ZMTP/1.0 greeting |
| 255 | send (s, "\x01\x00" , 2, 0); |
| 256 | // send sneaky message that shouldn't be received |
| 257 | send (s, "\x08\x00sneaky\0" , 9, 0); |
| 258 | |
| 259 | zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout)); |
| 260 | char *buf = s_recv (server); |
| 261 | TEST_ASSERT_NULL_MESSAGE (buf, "Received unauthenticated message" ); |
| 262 | close (s); |
| 263 | } |
| 264 | |
| 265 | void send_all (fd_t fd_, const char *data_, socket_size_t size_) |
| 266 | { |
| 267 | while (size_ > 0) { |
| 268 | int res = send (fd_, data_, size_, 0); |
| 269 | TEST_ASSERT_GREATER_THAN_INT (0, res); |
| 270 | size_ -= res; |
| 271 | data_ += res; |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | template <size_t N> void send (fd_t fd_, const char (&data_)[N]) |
| 276 | { |
| 277 | send_all (fd_, data_, N - 1); |
| 278 | } |
| 279 | |
| 280 | void send_greeting (fd_t s_) |
| 281 | { |
| 282 | send (s_, "\xff\0\0\0\0\0\0\0\0\x7f" ); // signature |
| 283 | send (s_, "\x03\x00" ); // version 3.0 |
| 284 | send (s_, "CURVE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ); // mechanism CURVE |
| 285 | send (s_, "\0" ); // as-server == false |
| 286 | send (s_, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ); |
| 287 | } |
| 288 | |
| 289 | void test_curve_security_invalid_hello_wrong_length () |
| 290 | { |
| 291 | fd_t s = connect_vanilla_socket (my_endpoint); |
| 292 | |
| 293 | // send GREETING |
| 294 | send_greeting (s); |
| 295 | |
| 296 | // send CURVE HELLO of wrong size |
| 297 | send (s, "\x04\x06\x05HELLO" ); |
| 298 | |
| 299 | expect_monitor_event_multiple ( |
| 300 | server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 301 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO); |
| 302 | |
| 303 | close (s); |
| 304 | } |
| 305 | |
| 306 | const size_t hello_length = 200; |
| 307 | const size_t welcome_length = 168; |
| 308 | |
| 309 | zmq::curve_client_tools_t make_curve_client_tools () |
| 310 | { |
| 311 | uint8_t valid_client_secret_decoded[32]; |
| 312 | uint8_t valid_client_public_decoded[32]; |
| 313 | |
| 314 | zmq_z85_decode (valid_client_public_decoded, valid_client_public); |
| 315 | zmq_z85_decode (valid_client_secret_decoded, valid_client_secret); |
| 316 | |
| 317 | uint8_t valid_server_public_decoded[32]; |
| 318 | zmq_z85_decode (valid_server_public_decoded, valid_server_public); |
| 319 | |
| 320 | return zmq::curve_client_tools_t (valid_client_public_decoded, |
| 321 | valid_client_secret_decoded, |
| 322 | valid_server_public_decoded); |
| 323 | } |
| 324 | |
| 325 | // same as htonll, which is only available on few platforms (recent Windows, but not on Linux, e.g.( |
| 326 | static uint64_t host_to_network (uint64_t value_) |
| 327 | { |
| 328 | // The answer is 42 |
| 329 | static const int num = 42; |
| 330 | |
| 331 | // Check the endianness |
| 332 | if (*reinterpret_cast<const char *> (&num) == num) { |
| 333 | const uint32_t high_part = htonl (static_cast<uint32_t> (value_ >> 32)); |
| 334 | const uint32_t low_part = |
| 335 | htonl (static_cast<uint32_t> (value_ & 0xFFFFFFFFLL)); |
| 336 | |
| 337 | return (static_cast<uint64_t> (low_part) << 32) | high_part; |
| 338 | } |
| 339 | return value_; |
| 340 | } |
| 341 | |
| 342 | template <size_t N> void send_command (fd_t s_, char (&command_)[N]) |
| 343 | { |
| 344 | if (N < 256) { |
| 345 | send (s_, "\x04" ); |
| 346 | char len = (char) N; |
| 347 | send_all (s_, &len, 1); |
| 348 | } else { |
| 349 | send (s_, "\x06" ); |
| 350 | uint64_t len = host_to_network (N); |
| 351 | send_all (s_, reinterpret_cast<char *> (&len), 8); |
| 352 | } |
| 353 | send_all (s_, command_, N); |
| 354 | } |
| 355 | |
| 356 | void test_curve_security_invalid_hello_command_name () |
| 357 | { |
| 358 | fd_t s = connect_vanilla_socket (my_endpoint); |
| 359 | |
| 360 | send_greeting (s); |
| 361 | |
| 362 | zmq::curve_client_tools_t tools = make_curve_client_tools (); |
| 363 | |
| 364 | // send CURVE HELLO with a misspelled command name (but otherwise correct) |
| 365 | char hello[hello_length]; |
| 366 | TEST_ASSERT_SUCCESS_ERRNO (tools.produce_hello (hello, 0)); |
| 367 | hello[5] = 'X'; |
| 368 | |
| 369 | send_command (s, hello); |
| 370 | |
| 371 | expect_monitor_event_multiple (server_mon, |
| 372 | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 373 | ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
| 374 | |
| 375 | close (s); |
| 376 | } |
| 377 | |
| 378 | void test_curve_security_invalid_hello_version () |
| 379 | { |
| 380 | fd_t s = connect_vanilla_socket (my_endpoint); |
| 381 | |
| 382 | send_greeting (s); |
| 383 | |
| 384 | zmq::curve_client_tools_t tools = make_curve_client_tools (); |
| 385 | |
| 386 | // send CURVE HELLO with a wrong version number (but otherwise correct) |
| 387 | char hello[hello_length]; |
| 388 | TEST_ASSERT_SUCCESS_ERRNO (tools.produce_hello (hello, 0)); |
| 389 | hello[6] = 2; |
| 390 | |
| 391 | send_command (s, hello); |
| 392 | |
| 393 | expect_monitor_event_multiple ( |
| 394 | server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 395 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO); |
| 396 | |
| 397 | close (s); |
| 398 | } |
| 399 | |
| 400 | void flush_read (fd_t fd_) |
| 401 | { |
| 402 | int res; |
| 403 | char buf[256]; |
| 404 | |
| 405 | while ((res = recv (fd_, buf, 256, 0)) == 256) { |
| 406 | } |
| 407 | TEST_ASSERT_NOT_EQUAL (-1, res); |
| 408 | } |
| 409 | |
| 410 | void recv_all (fd_t fd_, uint8_t *data_, socket_size_t len_) |
| 411 | { |
| 412 | socket_size_t received = 0; |
| 413 | while (received < len_) { |
| 414 | int res = recv (fd_, reinterpret_cast<char *> (data_), len_, 0); |
| 415 | TEST_ASSERT_GREATER_THAN_INT (0, res); |
| 416 | |
| 417 | data_ += res; |
| 418 | received += res; |
| 419 | } |
| 420 | } |
| 421 | |
| 422 | void recv_greeting (fd_t fd_) |
| 423 | { |
| 424 | uint8_t greeting[64]; |
| 425 | recv_all (fd_, greeting, 64); |
| 426 | // TODO assert anything about the greeting received from the server? |
| 427 | } |
| 428 | |
| 429 | fd_t connect_exchange_greeting_and_send_hello ( |
| 430 | char *my_endpoint_, zmq::curve_client_tools_t &tools_) |
| 431 | { |
| 432 | fd_t s = connect_vanilla_socket (my_endpoint_); |
| 433 | |
| 434 | send_greeting (s); |
| 435 | recv_greeting (s); |
| 436 | |
| 437 | // send valid CURVE HELLO |
| 438 | char hello[hello_length]; |
| 439 | TEST_ASSERT_SUCCESS_ERRNO (tools_.produce_hello (hello, 0)); |
| 440 | |
| 441 | send_command (s, hello); |
| 442 | return s; |
| 443 | } |
| 444 | |
| 445 | void test_curve_security_invalid_initiate_wrong_length () |
| 446 | { |
| 447 | zmq::curve_client_tools_t tools = make_curve_client_tools (); |
| 448 | |
| 449 | fd_t s = connect_exchange_greeting_and_send_hello (my_endpoint, tools); |
| 450 | |
| 451 | // receive but ignore WELCOME |
| 452 | flush_read (s); |
| 453 | |
| 454 | int res = get_monitor_event_with_timeout (server_mon, NULL, NULL, timeout); |
| 455 | TEST_ASSERT_EQUAL_INT (-1, res); |
| 456 | |
| 457 | send (s, "\x04\x09\x08INITIATE" ); |
| 458 | |
| 459 | expect_monitor_event_multiple ( |
| 460 | server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 461 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE); |
| 462 | |
| 463 | close (s); |
| 464 | } |
| 465 | |
| 466 | fd_t connect_exchange_greeting_and_hello_welcome ( |
| 467 | char *my_endpoint_, |
| 468 | void *server_mon_, |
| 469 | int timeout_, |
| 470 | zmq::curve_client_tools_t &tools_) |
| 471 | { |
| 472 | fd_t s = connect_exchange_greeting_and_send_hello (my_endpoint_, tools_); |
| 473 | |
| 474 | // receive but ignore WELCOME |
| 475 | uint8_t welcome[welcome_length + 2]; |
| 476 | recv_all (s, welcome, welcome_length + 2); |
| 477 | |
| 478 | uint8_t cn_precom[crypto_box_BEFORENMBYTES]; |
| 479 | TEST_ASSERT_SUCCESS_ERRNO ( |
| 480 | tools_.process_welcome (welcome + 2, welcome_length, cn_precom)); |
| 481 | |
| 482 | const int res = |
| 483 | get_monitor_event_with_timeout (server_mon_, NULL, NULL, timeout_); |
| 484 | TEST_ASSERT_EQUAL_INT (-1, res); |
| 485 | |
| 486 | return s; |
| 487 | } |
| 488 | |
| 489 | void test_curve_security_invalid_initiate_command_name () |
| 490 | { |
| 491 | zmq::curve_client_tools_t tools = make_curve_client_tools (); |
| 492 | fd_t s = connect_exchange_greeting_and_hello_welcome ( |
| 493 | my_endpoint, server_mon, timeout, tools); |
| 494 | |
| 495 | char initiate[257]; |
| 496 | tools.produce_initiate (initiate, 257, 1, NULL, 0); |
| 497 | // modify command name |
| 498 | initiate[5] = 'X'; |
| 499 | |
| 500 | send_command (s, initiate); |
| 501 | |
| 502 | expect_monitor_event_multiple (server_mon, |
| 503 | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 504 | ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
| 505 | |
| 506 | close (s); |
| 507 | } |
| 508 | |
| 509 | void test_curve_security_invalid_initiate_command_encrypted_cookie () |
| 510 | { |
| 511 | zmq::curve_client_tools_t tools = make_curve_client_tools (); |
| 512 | fd_t s = connect_exchange_greeting_and_hello_welcome ( |
| 513 | my_endpoint, server_mon, timeout, tools); |
| 514 | |
| 515 | char initiate[257]; |
| 516 | tools.produce_initiate (initiate, 257, 1, NULL, 0); |
| 517 | // make garbage from encrypted cookie |
| 518 | initiate[30] = !initiate[30]; |
| 519 | |
| 520 | send_command (s, initiate); |
| 521 | |
| 522 | expect_monitor_event_multiple (server_mon, |
| 523 | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 524 | ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC); |
| 525 | |
| 526 | close (s); |
| 527 | } |
| 528 | |
| 529 | void test_curve_security_invalid_initiate_command_encrypted_content () |
| 530 | { |
| 531 | zmq::curve_client_tools_t tools = make_curve_client_tools (); |
| 532 | fd_t s = connect_exchange_greeting_and_hello_welcome ( |
| 533 | my_endpoint, server_mon, timeout, tools); |
| 534 | |
| 535 | char initiate[257]; |
| 536 | tools.produce_initiate (initiate, 257, 1, NULL, 0); |
| 537 | // make garbage from encrypted content |
| 538 | initiate[150] = !initiate[150]; |
| 539 | |
| 540 | send_command (s, initiate); |
| 541 | |
| 542 | expect_monitor_event_multiple (server_mon, |
| 543 | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, |
| 544 | ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC); |
| 545 | |
| 546 | close (s); |
| 547 | } |
| 548 | |
| 549 | void test_curve_security_invalid_keysize (void *ctx_) |
| 550 | { |
| 551 | // Check return codes for invalid buffer sizes |
| 552 | void *client = zmq_socket (ctx_, ZMQ_DEALER); |
| 553 | TEST_ASSERT_NOT_NULL (client); |
| 554 | errno = 0; |
| 555 | int rc = |
| 556 | zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, valid_server_public, 123); |
| 557 | assert (rc == -1 && errno == EINVAL); |
| 558 | errno = 0; |
| 559 | rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, valid_client_public, 123); |
| 560 | assert (rc == -1 && errno == EINVAL); |
| 561 | errno = 0; |
| 562 | rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, valid_client_secret, 123); |
| 563 | assert (rc == -1 && errno == EINVAL); |
| 564 | TEST_ASSERT_SUCCESS_ERRNO (zmq_close (client)); |
| 565 | } |
| 566 | |
| 567 | // TODO why isn't this const? |
| 568 | char null_key[] = "0000000000000000000000000000000000000000" ; |
| 569 | |
| 570 | void test_null_server_key () |
| 571 | { |
| 572 | // Check CURVE security with a null server key |
| 573 | // This will be caught by the curve_server class, not passed to ZAP |
| 574 | test_null_key (server, server_mon, my_endpoint, null_key, |
| 575 | valid_client_public, valid_client_secret); |
| 576 | } |
| 577 | |
| 578 | void test_null_client_public_key () |
| 579 | { |
| 580 | // Check CURVE security with a null client public key |
| 581 | // This will be caught by the curve_server class, not passed to ZAP |
| 582 | test_null_key (server, server_mon, my_endpoint, valid_server_public, |
| 583 | null_key, valid_client_secret); |
| 584 | } |
| 585 | |
| 586 | void test_null_client_secret_key () |
| 587 | { |
| 588 | // Check CURVE security with a null client public key |
| 589 | // This will be caught by the curve_server class, not passed to ZAP |
| 590 | test_null_key (server, server_mon, my_endpoint, valid_server_public, |
| 591 | valid_client_public, null_key); |
| 592 | } |
| 593 | |
| 594 | |
| 595 | int main (void) |
| 596 | { |
| 597 | if (!zmq_has ("curve" )) { |
| 598 | printf ("CURVE encryption not installed, skipping test\n" ); |
| 599 | return 0; |
| 600 | } |
| 601 | |
| 602 | zmq::random_open (); |
| 603 | |
| 604 | setup_testutil_security_curve (); |
| 605 | |
| 606 | |
| 607 | setup_test_environment (); |
| 608 | |
| 609 | UNITY_BEGIN (); |
| 610 | RUN_TEST (test_curve_security_with_valid_credentials); |
| 611 | RUN_TEST (test_null_server_key); |
| 612 | RUN_TEST (test_null_client_public_key); |
| 613 | RUN_TEST (test_null_client_secret_key); |
| 614 | RUN_TEST (test_curve_security_with_bogus_client_credentials); |
| 615 | RUN_TEST (test_curve_security_with_null_client_credentials); |
| 616 | RUN_TEST (test_curve_security_with_plain_client_credentials); |
| 617 | RUN_TEST (test_curve_security_unauthenticated_message); |
| 618 | |
| 619 | // tests with misbehaving CURVE client |
| 620 | RUN_TEST (test_curve_security_invalid_hello_wrong_length); |
| 621 | RUN_TEST (test_curve_security_invalid_hello_command_name); |
| 622 | RUN_TEST (test_curve_security_invalid_hello_version); |
| 623 | RUN_TEST (test_curve_security_invalid_initiate_wrong_length); |
| 624 | RUN_TEST (test_curve_security_invalid_initiate_command_name); |
| 625 | RUN_TEST (test_curve_security_invalid_initiate_command_encrypted_cookie); |
| 626 | RUN_TEST (test_curve_security_invalid_initiate_command_encrypted_content); |
| 627 | |
| 628 | // TODO this requires a deviating test setup, must be moved to a separate executable/fixture |
| 629 | // test with a large routing id (resulting in large metadata) |
| 630 | fprintf (stderr, |
| 631 | "test_curve_security_with_valid_credentials (large routing id)\n" ); |
| 632 | setup_test_context (); |
| 633 | setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon, |
| 634 | my_endpoint, &zap_handler_large_routing_id, |
| 635 | &socket_config_curve_server, |
| 636 | &valid_server_secret, large_routing_id); |
| 637 | test_curve_security_with_valid_credentials (); |
| 638 | shutdown_context_and_server_side (zap_thread, server, server_mon, handler); |
| 639 | teardown_test_context (); |
| 640 | |
| 641 | void *ctx = zmq_ctx_new (); |
| 642 | test_curve_security_invalid_keysize (ctx); |
| 643 | TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_term (ctx)); |
| 644 | |
| 645 | zmq::random_close (); |
| 646 | |
| 647 | return UNITY_END (); |
| 648 | } |
| 649 | |