test_security_curve.cpp 10.3 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
//  --------------------------------------------------------------------------
Pieter Hintjens's avatar
Pieter Hintjens committed
50 51
//  This methods receives and validates ZAP requestes (allowing or denying
//  each client connection).
52

53
static void zap_handler (void *handler)
Ian Barber's avatar
Ian Barber committed
54
{
55 56
    //  Process ZAP requests forever
    while (true) {
57
        char *version = s_recv (handler);
58 59 60
        if (!version)
            break;          //  Terminating

61 62 63 64 65
        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);
66
        uint8_t client_key [32];
67
        int size = zmq_recv (handler, client_key, 32, 0);
68 69
        assert (size == 32);

70
        char client_key_text [41];
71
        zmq_z85_encode (client_key_text, client_key, 32);
72

73 74 75 76
        assert (streq (version, "1.0"));
        assert (streq (mechanism, "CURVE"));
        assert (streq (identity, "IDENT"));

77 78
        s_sendmore (handler, version);
        s_sendmore (handler, sequence);
79

80
        if (streq (client_key_text, client_public)) {
81 82 83 84
            s_sendmore (handler, "200");
            s_sendmore (handler, "OK");
            s_sendmore (handler, "anonymous");
            s_send     (handler, "");
85 86
        }
        else {
87 88 89 90
            s_sendmore (handler, "400");
            s_sendmore (handler, "Invalid client public key");
            s_sendmore (handler, "");
            s_send     (handler, "");
91
        }
92 93 94 95 96 97
        free (version);
        free (sequence);
        free (domain);
        free (address);
        free (identity);
        free (mechanism);
MinRK's avatar
MinRK committed
98
    }
99
    zmq_close (handler);
Ian Barber's avatar
Ian Barber committed
100 101
}

MinRK's avatar
MinRK committed
102

Ian Barber's avatar
Ian Barber committed
103 104
int main (void)
{
105 106
#ifndef ZMQ_HAVE_CURVE
    printf ("CURVE encryption not installed, skipping test\n");
Ian Barber's avatar
Ian Barber committed
107 108
    return 0;
#endif
109 110 111 112 113 114
    //  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);

115
    setup_test_environment ();
Ian Barber's avatar
Ian Barber committed
116 117 118
    void *ctx = zmq_ctx_new ();
    assert (ctx);

119
    //  Spawn ZAP handler
120 121 122 123
    //  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);
124
    rc = zmq_bind (handler, "inproc://zeromq.zap.01");
125 126
    assert (rc == 0);
    void *zap_thread = zmq_threadstart (&zap_handler, handler);
Ian Barber's avatar
Ian Barber committed
127

128 129 130
    //  Server socket will accept connections
    void *server = zmq_socket (ctx, ZMQ_DEALER);
    assert (server);
131
    int as_server = 1;
132
    rc = zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int));
Pieter Hintjens's avatar
Pieter Hintjens committed
133
    assert (rc == 0);
134
    rc = zmq_setsockopt (server, ZMQ_CURVE_SECRETKEY, server_secret, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
135
    assert (rc == 0);
136 137
    rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6);
    assert (rc == 0);
138
    rc = zmq_bind (server, "tcp://127.0.0.1:9998");
139
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
140

141 142 143
    //  Check CURVE security with valid credentials
    void *client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
144
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
145
    assert (rc == 0);
146
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
147
    assert (rc == 0);
148
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
149
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
150 151 152 153 154
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
    bounce (server, client);
    rc = zmq_close (client);
    assert (rc == 0);
155

156 157
    //  Check CURVE security with a garbage server key
    //  This will be caught by the curve_server class, not passed to ZAP
158
    char garbage_key [] = "0000000000000000000000000000000000000000";
MinRK's avatar
MinRK committed
159 160
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
161
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
162
    assert (rc == 0);
163
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
MinRK's avatar
MinRK committed
164
    assert (rc == 0);
165
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
MinRK's avatar
MinRK committed
166
    assert (rc == 0);
167 168 169 170
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
    expect_bounce_fail (server, client);
    close_zero_linger (client);
171

172 173 174 175
    //  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);
176
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
177
    assert (rc == 0);
178
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
179
    assert (rc == 0);
180
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
MinRK's avatar
MinRK committed
181
    assert (rc == 0);
182
    rc = zmq_connect (client, "tcp://localhost:9998");
MinRK's avatar
MinRK committed
183
    assert (rc == 0);
184 185
    expect_bounce_fail (server, client);
    close_zero_linger (client);
186

187 188 189 190
    //  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);
191
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
192
    assert (rc == 0);
193
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
MinRK's avatar
MinRK committed
194
    assert (rc == 0);
195
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
196
    assert (rc == 0);
197
    rc = zmq_connect (client, "tcp://localhost:9998");
MinRK's avatar
MinRK committed
198
    assert (rc == 0);
199 200
    expect_bounce_fail (server, client);
    close_zero_linger (client);
201

202 203
    //  Check CURVE security with bogus client credentials
    //  This must be caught by the ZAP handler
204 205 206
    char bogus_public [41];
    char bogus_secret [41];
    zmq_curve_keypair (bogus_public, bogus_secret);
207

208 209
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
210
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
211
    assert (rc == 0);
212
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, bogus_public, 41);
MinRK's avatar
MinRK committed
213
    assert (rc == 0);
214
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, bogus_secret, 41);
MinRK's avatar
MinRK committed
215
    assert (rc == 0);
216 217
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
218
    expect_bounce_fail (server, client);
219
    close_zero_linger (client);
220

221
    //  Check CURVE security with NULL client credentials
222
    //  This must be caught by the curve_server class, not passed to ZAP
223 224 225 226 227 228 229 230
    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);

    //  Check CURVE security with PLAIN client credentials
231
    //  This must be caught by the curve_server class, not passed to ZAP
232 233 234 235 236 237 238 239
    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);
240

241 242 243 244 245 246
    // 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);
247
#if defined (ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
248 249 250 251
    ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
#else
    inet_pton(AF_INET, "127.0.0.1", &ip4addr.sin_addr);
#endif
252 253 254 255

    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    rc = connect (s, (struct sockaddr*) &ip4addr, sizeof (ip4addr));
    assert (rc > -1);
256 257 258 259
    // 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);
260
    int timeout = 250;
261 262
    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
    char *buf = s_recv (server);
263 264 265 266
    if (buf != NULL) {
        printf ("Received unauthenticated message: %s\n", buf);
        assert (buf == NULL);
    }
267 268
    close (s);

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
    //  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
284
    //  Shutdown
285 286
    rc = zmq_close (server);
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
287 288
    rc = zmq_ctx_term (ctx);
    assert (rc == 0);
289

290 291
    //  Wait until ZAP handler terminates
    zmq_threadclose (zap_thread);
Ian Barber's avatar
Ian Barber committed
292 293 294

    return 0;
}