test_security_curve.cpp 12.9 KB
Newer Older
Ian Barber's avatar
Ian Barber committed
1
/*
2
    Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
Ian Barber's avatar
Ian Barber committed
3

4
    This file is part of libzmq, the ZeroMQ core engine in C++.
Ian Barber's avatar
Ian Barber committed
5

6 7 8
    libzmq is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
Ian Barber's avatar
Ian Barber committed
9 10
    (at your option) any later version.

11 12 13 14 15 16 17 18 19 20 21 22 23 24
    As a special exception, the Contributors give you permission to link
    this library with independent modules to produce an executable,
    regardless of the license terms of these independent modules, and to
    copy and distribute the resulting executable under terms of your choice,
    provided that you also meet, for each linked independent module, the
    terms and conditions of the license of that module. An independent
    module is a module which is not derived from or based on this library.
    If you modify this library, you must extend this exception to your
    version of the library.

    libzmq is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    License for more details.
Ian Barber's avatar
Ian Barber committed
25 26 27 28 29 30

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "testutil.hpp"
31 32
#if defined (ZMQ_HAVE_WINDOWS)
#   include <winsock2.h>
33
#   include <ws2tcpip.h>
34
#   include <stdexcept>
35
#   define close closesocket
36 37 38 39 40 41
#else
#   include <sys/socket.h>
#   include <netinet/in.h>
#   include <arpa/inet.h>
#   include <unistd.h>
#endif
42

43 44 45 46 47
//  We'll generate random test keys at startup
static char client_public [41];
static char client_secret [41];
static char server_public [41];
static char server_secret [41];
Ian Barber's avatar
Ian Barber committed
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
#ifdef ZMQ_BUILD_DRAFT_API
//  Read one event off the monitor socket; return value and address
//  by reference, if not null, and event number by value. Returns -1
//  in case of error.

static int
get_monitor_event (void *monitor, int *value, char **address)
{
    //  First frame in message contains event number and value
    zmq_msg_t msg;
    zmq_msg_init (&msg);
    if (zmq_msg_recv (&msg, monitor, 0) == -1)
        return -1;              //  Interruped, presumably
    assert (zmq_msg_more (&msg));

    uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
    uint16_t event = *(uint16_t *) (data);
    if (value)
        *value = *(uint32_t *) (data + 2);

    //  Second frame in message contains event address
    zmq_msg_init (&msg);
    if (zmq_msg_recv (&msg, monitor, 0) == -1)
        return -1;              //  Interruped, presumably
    assert (!zmq_msg_more (&msg));

    if (address) {
        uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
        size_t size = zmq_msg_size (&msg);
        *address = (char *) malloc (size + 1);
        memcpy (*address, data, size);
        *address [size] = 0;
    }
    return event;
}
#endif


87
//  --------------------------------------------------------------------------
Pieter Hintjens's avatar
Pieter Hintjens committed
88 89
//  This methods receives and validates ZAP requestes (allowing or denying
//  each client connection).
90

91
static void zap_handler (void *handler)
Ian Barber's avatar
Ian Barber committed
92
{
93 94
    //  Process ZAP requests forever
    while (true) {
95
        char *version = s_recv (handler);
96 97 98
        if (!version)
            break;          //  Terminating

99 100 101 102 103
        char *sequence = s_recv (handler);
        char *domain = s_recv (handler);
        char *address = s_recv (handler);
        char *identity = s_recv (handler);
        char *mechanism = s_recv (handler);
104
        uint8_t client_key [32];
105
        int size = zmq_recv (handler, client_key, 32, 0);
106 107
        assert (size == 32);

108
        char client_key_text [41];
109
        zmq_z85_encode (client_key_text, client_key, 32);
110

111 112 113 114
        assert (streq (version, "1.0"));
        assert (streq (mechanism, "CURVE"));
        assert (streq (identity, "IDENT"));

115 116
        s_sendmore (handler, version);
        s_sendmore (handler, sequence);
117

118
        if (streq (client_key_text, client_public)) {
119 120 121 122
            s_sendmore (handler, "200");
            s_sendmore (handler, "OK");
            s_sendmore (handler, "anonymous");
            s_send     (handler, "");
123 124
        }
        else {
125 126 127 128
            s_sendmore (handler, "400");
            s_sendmore (handler, "Invalid client public key");
            s_sendmore (handler, "");
            s_send     (handler, "");
129
        }
130 131 132 133 134 135
        free (version);
        free (sequence);
        free (domain);
        free (address);
        free (identity);
        free (mechanism);
MinRK's avatar
MinRK committed
136
    }
137
    zmq_close (handler);
Ian Barber's avatar
Ian Barber committed
138 139
}

MinRK's avatar
MinRK committed
140

Ian Barber's avatar
Ian Barber committed
141 142
int main (void)
{
143 144
#ifndef ZMQ_HAVE_CURVE
    printf ("CURVE encryption not installed, skipping test\n");
Ian Barber's avatar
Ian Barber committed
145 146
    return 0;
#endif
147 148 149 150 151 152
    //  Generate new keypairs for this test
    int rc = zmq_curve_keypair (client_public, client_secret);
    assert (rc == 0);
    rc = zmq_curve_keypair (server_public, server_secret);
    assert (rc == 0);

153
    setup_test_environment ();
Ian Barber's avatar
Ian Barber committed
154 155 156
    void *ctx = zmq_ctx_new ();
    assert (ctx);

157
    //  Spawn ZAP handler
158 159 160 161
    //  We create and bind ZAP socket in main thread to avoid case
    //  where child thread does not start up fast enough.
    void *handler = zmq_socket (ctx, ZMQ_REP);
    assert (handler);
162
    rc = zmq_bind (handler, "inproc://zeromq.zap.01");
163 164
    assert (rc == 0);
    void *zap_thread = zmq_threadstart (&zap_handler, handler);
Ian Barber's avatar
Ian Barber committed
165

166 167 168
    //  Server socket will accept connections
    void *server = zmq_socket (ctx, ZMQ_DEALER);
    assert (server);
169
    int as_server = 1;
170
    rc = zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int));
Pieter Hintjens's avatar
Pieter Hintjens committed
171
    assert (rc == 0);
172
    rc = zmq_setsockopt (server, ZMQ_CURVE_SECRETKEY, server_secret, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
173
    assert (rc == 0);
174 175
    rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6);
    assert (rc == 0);
176
    rc = zmq_bind (server, "tcp://127.0.0.1:9998");
177
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
178

179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
#ifdef ZMQ_BUILD_DRAFT_API
    //  Monitor handshake events on the server
    rc = zmq_socket_monitor (server, "inproc://monitor-server",
            ZMQ_EVENT_HANDSHAKE_SUCCEED | ZMQ_EVENT_HANDSHAKE_FAILED);
    assert (rc == 0);

    //  Create socket for collecting monitor events
    void *server_mon = zmq_socket (ctx, ZMQ_PAIR);
    assert (server_mon);

    //  Connect it to the inproc endpoints so they'll get events
    rc = zmq_connect (server_mon, "inproc://monitor-server");
    assert (rc == 0);
#endif

194 195 196
    //  Check CURVE security with valid credentials
    void *client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
197
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
198
    assert (rc == 0);
199
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
200
    assert (rc == 0);
201
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
202
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
203 204 205 206 207
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
    bounce (server, client);
    rc = zmq_close (client);
    assert (rc == 0);
208

209 210 211 212 213
#ifdef ZMQ_BUILD_DRAFT_API
    int event = get_monitor_event (server_mon, NULL, NULL);
    assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEED);
#endif

214 215
    //  Check CURVE security with a garbage server key
    //  This will be caught by the curve_server class, not passed to ZAP
216
    char garbage_key [] = "0000000000000000000000000000000000000000";
MinRK's avatar
MinRK committed
217 218
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
219
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
220
    assert (rc == 0);
221
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
MinRK's avatar
MinRK committed
222
    assert (rc == 0);
223
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
MinRK's avatar
MinRK committed
224
    assert (rc == 0);
225 226 227 228
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
    expect_bounce_fail (server, client);
    close_zero_linger (client);
229

230 231 232 233 234
#ifdef ZMQ_BUILD_DRAFT_API
    event = get_monitor_event (server_mon, NULL, NULL);
    assert (event == ZMQ_EVENT_HANDSHAKE_FAILED);
#endif

235 236 237 238
    //  Check CURVE security with a garbage client public key
    //  This will be caught by the curve_server class, not passed to ZAP
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
239
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
240
    assert (rc == 0);
241
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
242
    assert (rc == 0);
243
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
MinRK's avatar
MinRK committed
244
    assert (rc == 0);
245
    rc = zmq_connect (client, "tcp://localhost:9998");
MinRK's avatar
MinRK committed
246
    assert (rc == 0);
247 248
    expect_bounce_fail (server, client);
    close_zero_linger (client);
249

250 251 252 253 254
#ifdef ZMQ_BUILD_DRAFT_API
    event = get_monitor_event (server_mon, NULL, NULL);
    assert (event == ZMQ_EVENT_HANDSHAKE_FAILED);
#endif

255 256 257 258
    //  Check CURVE security with a garbage client secret key
    //  This will be caught by the curve_server class, not passed to ZAP
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
259
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
260
    assert (rc == 0);
261
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
MinRK's avatar
MinRK committed
262
    assert (rc == 0);
263
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
264
    assert (rc == 0);
265
    rc = zmq_connect (client, "tcp://localhost:9998");
MinRK's avatar
MinRK committed
266
    assert (rc == 0);
267 268
    expect_bounce_fail (server, client);
    close_zero_linger (client);
269

270 271 272 273 274
#ifdef ZMQ_BUILD_DRAFT_API
    event = get_monitor_event (server_mon, NULL, NULL);
    assert (event == ZMQ_EVENT_HANDSHAKE_FAILED);
#endif

275 276
    //  Check CURVE security with bogus client credentials
    //  This must be caught by the ZAP handler
277 278 279
    char bogus_public [41];
    char bogus_secret [41];
    zmq_curve_keypair (bogus_public, bogus_secret);
280

281 282
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
283
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
284
    assert (rc == 0);
285
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, bogus_public, 41);
MinRK's avatar
MinRK committed
286
    assert (rc == 0);
287
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, bogus_secret, 41);
MinRK's avatar
MinRK committed
288
    assert (rc == 0);
289 290
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
291
    expect_bounce_fail (server, client);
292
    close_zero_linger (client);
293

294 295 296 297 298
#ifdef ZMQ_BUILD_DRAFT_API
    event = get_monitor_event (server_mon, NULL, NULL);
    assert (event == ZMQ_EVENT_HANDSHAKE_FAILED);
#endif

299
    //  Check CURVE security with NULL client credentials
300
    //  This must be caught by the curve_server class, not passed to ZAP
301 302 303 304 305 306 307
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
    expect_bounce_fail (server, client);
    close_zero_linger (client);

308 309 310 311 312
#ifdef ZMQ_BUILD_DRAFT_API
    event = get_monitor_event (server_mon, NULL, NULL);
    assert (event == ZMQ_EVENT_HANDSHAKE_FAILED);
#endif

313
    //  Check CURVE security with PLAIN client credentials
314
    //  This must be caught by the curve_server class, not passed to ZAP
315 316 317 318 319 320 321 322
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
    rc = zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, "admin", 5);
    assert (rc == 0);
    rc = zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, "password", 8);
    assert (rc == 0);
    expect_bounce_fail (server, client);
    close_zero_linger (client);
323

324 325 326 327 328 329
    // Unauthenticated messages from a vanilla socket shouldn't be received
    struct sockaddr_in ip4addr;
    int s;

    ip4addr.sin_family = AF_INET;
    ip4addr.sin_port = htons (9998);
330
#if defined (ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
331 332 333 334
    ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
#else
    inet_pton(AF_INET, "127.0.0.1", &ip4addr.sin_addr);
#endif
335 336 337 338

    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    rc = connect (s, (struct sockaddr*) &ip4addr, sizeof (ip4addr));
    assert (rc > -1);
339 340 341 342
    // send anonymous ZMTP/1.0 greeting
    send (s, "\x01\x00", 2, 0);
    // send sneaky message that shouldn't be received
    send (s, "\x08\x00sneaky\0", 9, 0);
343
    int timeout = 250;
344 345
    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
    char *buf = s_recv (server);
346 347 348 349
    if (buf != NULL) {
        printf ("Received unauthenticated message: %s\n", buf);
        assert (buf == NULL);
    }
350 351
    close (s);

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    //  Check return codes for invalid buffer sizes
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
    errno = 0;
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 123);
    assert (rc == -1 && errno == EINVAL);
    errno = 0;
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 123);
    assert (rc == -1 && errno == EINVAL);
    errno = 0;
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 123);
    assert (rc == -1 && errno == EINVAL);
    rc = zmq_close (client);
    assert (rc == 0);

Ian Barber's avatar
Ian Barber committed
367
    //  Shutdown
368 369 370
#ifdef ZMQ_BUILD_DRAFT_API
    close_zero_linger (server_mon);
#endif
371 372
    rc = zmq_close (server);
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
373 374
    rc = zmq_ctx_term (ctx);
    assert (rc == 0);
375

376 377
    //  Wait until ZAP handler terminates
    zmq_threadclose (zap_thread);
Ian Barber's avatar
Ian Barber committed
378 379 380

    return 0;
}