test_security_curve.cpp 9.56 KB
Newer Older
Ian Barber's avatar
Ian Barber committed
1
/*
2
    Copyright (c) 2007-2015 Contributors as noted in the AUTHORS file
Ian Barber's avatar
Ian Barber committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ 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.

    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"
21 22
#if defined (ZMQ_HAVE_WINDOWS)
#   include <winsock2.h>
23
#   include <ws2tcpip.h>
24
#   include <stdexcept>
25
#   define close closesocket
26 27 28 29 30 31
#else
#   include <sys/socket.h>
#   include <netinet/in.h>
#   include <arpa/inet.h>
#   include <unistd.h>
#endif
32

33 34 35 36 37
//  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
38

39
//  --------------------------------------------------------------------------
Pieter Hintjens's avatar
Pieter Hintjens committed
40 41
//  This methods receives and validates ZAP requestes (allowing or denying
//  each client connection).
42

43
static void zap_handler (void *handler)
Ian Barber's avatar
Ian Barber committed
44
{
45 46
    //  Process ZAP requests forever
    while (true) {
47
        char *version = s_recv (handler);
48 49 50
        if (!version)
            break;          //  Terminating

51 52 53 54 55
        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);
56
        uint8_t client_key [32];
57
        int size = zmq_recv (handler, client_key, 32, 0);
58 59
        assert (size == 32);

60
        char client_key_text [41];
61
        zmq_z85_encode (client_key_text, client_key, 32);
62

63 64 65 66
        assert (streq (version, "1.0"));
        assert (streq (mechanism, "CURVE"));
        assert (streq (identity, "IDENT"));

67 68
        s_sendmore (handler, version);
        s_sendmore (handler, sequence);
69

70
        if (streq (client_key_text, client_public)) {
71 72 73 74
            s_sendmore (handler, "200");
            s_sendmore (handler, "OK");
            s_sendmore (handler, "anonymous");
            s_send     (handler, "");
75 76
        }
        else {
77 78 79 80
            s_sendmore (handler, "400");
            s_sendmore (handler, "Invalid client public key");
            s_sendmore (handler, "");
            s_send     (handler, "");
81
        }
82 83 84 85 86 87
        free (version);
        free (sequence);
        free (domain);
        free (address);
        free (identity);
        free (mechanism);
MinRK's avatar
MinRK committed
88
    }
89
    zmq_close (handler);
Ian Barber's avatar
Ian Barber committed
90 91
}

MinRK's avatar
MinRK committed
92

Ian Barber's avatar
Ian Barber committed
93 94 95
int main (void)
{
#ifndef HAVE_LIBSODIUM
Pieter Hintjens's avatar
Pieter Hintjens committed
96
    printf ("libsodium not installed, skipping CURVE test\n");
Ian Barber's avatar
Ian Barber committed
97 98
    return 0;
#endif
99 100 101 102 103 104 105

    //  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);

106
    setup_test_environment ();
Ian Barber's avatar
Ian Barber committed
107 108 109
    void *ctx = zmq_ctx_new ();
    assert (ctx);

110
    //  Spawn ZAP handler
111 112 113 114
    //  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);
115
    rc = zmq_bind (handler, "inproc://zeromq.zap.01");
116 117
    assert (rc == 0);
    void *zap_thread = zmq_threadstart (&zap_handler, handler);
Ian Barber's avatar
Ian Barber committed
118

119 120 121
    //  Server socket will accept connections
    void *server = zmq_socket (ctx, ZMQ_DEALER);
    assert (server);
122
    int as_server = 1;
123
    rc = zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int));
Pieter Hintjens's avatar
Pieter Hintjens committed
124
    assert (rc == 0);
125
    rc = zmq_setsockopt (server, ZMQ_CURVE_SECRETKEY, server_secret, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
126
    assert (rc == 0);
127 128
    rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6);
    assert (rc == 0);
129
    rc = zmq_bind (server, "tcp://127.0.0.1:9998");
130
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
131

132 133 134
    //  Check CURVE security with valid credentials
    void *client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
135
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
136
    assert (rc == 0);
137
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
138
    assert (rc == 0);
139
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
Pieter Hintjens's avatar
Pieter Hintjens committed
140
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
141 142 143 144 145
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
    bounce (server, client);
    rc = zmq_close (client);
    assert (rc == 0);
146

147 148 149
    //  Check CURVE security with a garbage server key
    //  This will be caught by the curve_server class, not passed to ZAP
    char garbage_key [] = "0000111122223333444455556666777788889999";
MinRK's avatar
MinRK committed
150 151
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
152
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
153
    assert (rc == 0);
154
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
MinRK's avatar
MinRK committed
155
    assert (rc == 0);
156
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
MinRK's avatar
MinRK committed
157
    assert (rc == 0);
158 159 160 161
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
    expect_bounce_fail (server, client);
    close_zero_linger (client);
162

163 164 165 166
    //  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);
167
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
168
    assert (rc == 0);
169
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
170
    assert (rc == 0);
171
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
MinRK's avatar
MinRK committed
172
    assert (rc == 0);
173
    rc = zmq_connect (client, "tcp://localhost:9998");
MinRK's avatar
MinRK committed
174
    assert (rc == 0);
175 176
    expect_bounce_fail (server, client);
    close_zero_linger (client);
177

178 179 180 181
    //  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);
182
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
183
    assert (rc == 0);
184
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
MinRK's avatar
MinRK committed
185
    assert (rc == 0);
186
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, garbage_key, 41);
MinRK's avatar
MinRK committed
187
    assert (rc == 0);
188
    rc = zmq_connect (client, "tcp://localhost:9998");
MinRK's avatar
MinRK committed
189
    assert (rc == 0);
190 191
    expect_bounce_fail (server, client);
    close_zero_linger (client);
192

193 194
    //  Check CURVE security with bogus client credentials
    //  This must be caught by the ZAP handler
195 196 197
    char bogus_public [41];
    char bogus_secret [41];
    zmq_curve_keypair (bogus_public, bogus_secret);
198

199 200
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
201
    rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
MinRK's avatar
MinRK committed
202
    assert (rc == 0);
203
    rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, bogus_public, 41);
MinRK's avatar
MinRK committed
204
    assert (rc == 0);
205
    rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, bogus_secret, 41);
MinRK's avatar
MinRK committed
206
    assert (rc == 0);
207 208
    rc = zmq_connect (client, "tcp://localhost:9998");
    assert (rc == 0);
209
    expect_bounce_fail (server, client);
210
    close_zero_linger (client);
211

212
    //  Check CURVE security with NULL client credentials
213
    //  This must be caught by the curve_server class, not passed to ZAP
214 215 216 217 218 219 220 221
    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
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_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);
231

232 233 234 235 236 237 238 239 240 241 242
    // 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);
    inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr);

    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    rc = connect (s, (struct sockaddr*) &ip4addr, sizeof (ip4addr));
    assert (rc > -1);
243 244 245 246
    // 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);
247 248 249
    int timeout = 150;
    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
    char *buf = s_recv (server);
250 251 252 253
    if (buf != NULL) {
        printf ("Received unauthenticated message: %s\n", buf);
        assert (buf == NULL);
    }
254 255
    close (s);

256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    //  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
271
    //  Shutdown
272 273
    rc = zmq_close (server);
    assert (rc == 0);
Ian Barber's avatar
Ian Barber committed
274 275
    rc = zmq_ctx_term (ctx);
    assert (rc == 0);
276

277 278
    //  Wait until ZAP handler terminates
    zmq_threadclose (zap_thread);
Ian Barber's avatar
Ian Barber committed
279 280 281

    return 0;
}