libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
test_security_curve.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2007-2016 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 #include "testutil.hpp"
31 #if defined (ZMQ_HAVE_WINDOWS)
32 # include <winsock2.h>
33 # include <ws2tcpip.h>
34 # include <stdexcept>
35 # define close closesocket
36 #else
37 # include <sys/socket.h>
38 # include <netinet/in.h>
39 # include <arpa/inet.h>
40 # include <unistd.h>
41 #endif
42 
43 // We'll generate random test keys at startup
44 static char client_public [41];
45 static char client_secret [41];
46 static char server_public [41];
47 static char server_secret [41];
48 
49 // --------------------------------------------------------------------------
50 // This methods receives and validates ZAP requestes (allowing or denying
51 // each client connection).
52 
53 static void zap_handler (void *handler)
54 {
55  // Process ZAP requests forever
56  while (true) {
57  char *version = s_recv (handler);
58  if (!version)
59  break; // Terminating
60 
61  char *sequence = s_recv (handler);
62  char *domain = s_recv (handler);
63  char *address = s_recv (handler);
64  char *identity = s_recv (handler);
65  char *mechanism = s_recv (handler);
66  uint8_t client_key [32];
67  int size = zmq_recv (handler, client_key, 32, 0);
68  assert (size == 32);
69 
70  char client_key_text [41];
71  zmq_z85_encode (client_key_text, client_key, 32);
72 
73  assert (streq (version, "1.0"));
74  assert (streq (mechanism, "CURVE"));
75  assert (streq (identity, "IDENT"));
76 
77  s_sendmore (handler, version);
78  s_sendmore (handler, sequence);
79 
80  if (streq (client_key_text, client_public)) {
81  s_sendmore (handler, "200");
82  s_sendmore (handler, "OK");
83  s_sendmore (handler, "anonymous");
84  s_send (handler, "");
85  }
86  else {
87  s_sendmore (handler, "400");
88  s_sendmore (handler, "Invalid client public key");
89  s_sendmore (handler, "");
90  s_send (handler, "");
91  }
92  free (version);
93  free (sequence);
94  free (domain);
95  free (address);
96  free (identity);
97  free (mechanism);
98  }
99  zmq_close (handler);
100 }
101 
102 
103 int main (void)
104 {
105 #ifndef ZMQ_HAVE_CURVE
106  printf ("CURVE encryption not installed, skipping test\n");
107  return 0;
108 #endif
109  // Generate new keypairs for this test
111  assert (rc == 0);
113  assert (rc == 0);
114 
116  void *ctx = zmq_ctx_new ();
117  assert (ctx);
118 
119  // Spawn ZAP handler
120  // We create and bind ZAP socket in main thread to avoid case
121  // where child thread does not start up fast enough.
122  void *handler = zmq_socket (ctx, ZMQ_REP);
123  assert (handler);
124  rc = zmq_bind (handler, "inproc://zeromq.zap.01");
125  assert (rc == 0);
126  void *zap_thread = zmq_threadstart (&zap_handler, handler);
127 
128  // Server socket will accept connections
129  void *server = zmq_socket (ctx, ZMQ_DEALER);
130  assert (server);
131  int as_server = 1;
132  rc = zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int));
133  assert (rc == 0);
135  assert (rc == 0);
136  rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6);
137  assert (rc == 0);
138  rc = zmq_bind (server, "tcp://127.0.0.1:9998");
139  assert (rc == 0);
140 
141  // Check CURVE security with valid credentials
142  void *client = zmq_socket (ctx, ZMQ_DEALER);
143  assert (client);
145  assert (rc == 0);
147  assert (rc == 0);
149  assert (rc == 0);
150  rc = zmq_connect (client, "tcp://localhost:9998");
151  assert (rc == 0);
152  bounce (server, client);
153  rc = zmq_close (client);
154  assert (rc == 0);
155 
156  // Check CURVE security with a garbage server key
157  // This will be caught by the curve_server class, not passed to ZAP
158  char garbage_key [] = "0000000000000000000000000000000000000000";
159  client = zmq_socket (ctx, ZMQ_DEALER);
160  assert (client);
161  rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, garbage_key, 41);
162  assert (rc == 0);
164  assert (rc == 0);
166  assert (rc == 0);
167  rc = zmq_connect (client, "tcp://localhost:9998");
168  assert (rc == 0);
169  expect_bounce_fail (server, client);
170  close_zero_linger (client);
171 
172  // Check CURVE security with a garbage client public key
173  // This will be caught by the curve_server class, not passed to ZAP
174  client = zmq_socket (ctx, ZMQ_DEALER);
175  assert (client);
177  assert (rc == 0);
178  rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, garbage_key, 41);
179  assert (rc == 0);
181  assert (rc == 0);
182  rc = zmq_connect (client, "tcp://localhost:9998");
183  assert (rc == 0);
184  expect_bounce_fail (server, client);
185  close_zero_linger (client);
186 
187  // Check CURVE security with a garbage client secret key
188  // This will be caught by the curve_server class, not passed to ZAP
189  client = zmq_socket (ctx, ZMQ_DEALER);
190  assert (client);
192  assert (rc == 0);
194  assert (rc == 0);
195  rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, garbage_key, 41);
196  assert (rc == 0);
197  rc = zmq_connect (client, "tcp://localhost:9998");
198  assert (rc == 0);
199  expect_bounce_fail (server, client);
200  close_zero_linger (client);
201 
202  // Check CURVE security with bogus client credentials
203  // This must be caught by the ZAP handler
204  char bogus_public [41];
205  char bogus_secret [41];
206  zmq_curve_keypair (bogus_public, bogus_secret);
207 
208  client = zmq_socket (ctx, ZMQ_DEALER);
209  assert (client);
211  assert (rc == 0);
212  rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, bogus_public, 41);
213  assert (rc == 0);
214  rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, bogus_secret, 41);
215  assert (rc == 0);
216  rc = zmq_connect (client, "tcp://localhost:9998");
217  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  client = zmq_socket (ctx, ZMQ_DEALER);
224  assert (client);
225  rc = zmq_connect (client, "tcp://localhost:9998");
226  assert (rc == 0);
227  expect_bounce_fail (server, client);
228  close_zero_linger (client);
229 
230  // Check CURVE security with PLAIN client credentials
231  // This must be caught by the curve_server class, not passed to ZAP
232  client = zmq_socket (ctx, ZMQ_DEALER);
233  assert (client);
234  rc = zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, "admin", 5);
235  assert (rc == 0);
236  rc = zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, "password", 8);
237  assert (rc == 0);
238  expect_bounce_fail (server, client);
239  close_zero_linger (client);
240 
241  // Unauthenticated messages from a vanilla socket shouldn't be received
242  struct sockaddr_in ip4addr;
243  int s;
244 
245  ip4addr.sin_family = AF_INET;
246  ip4addr.sin_port = htons (9998);
247 #if defined (ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
248  ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
249 #else
250  inet_pton(AF_INET, "127.0.0.1", &ip4addr.sin_addr);
251 #endif
252 
253  s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
254  rc = connect (s, (struct sockaddr*) &ip4addr, sizeof (ip4addr));
255  assert (rc > -1);
256  // send anonymous ZMTP/1.0 greeting
257  send (s, "\x01\x00", 2, 0);
258  // send sneaky message that shouldn't be received
259  send (s, "\x08\x00sneaky\0", 9, 0);
260  int timeout = 250;
261  zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
262  char *buf = s_recv (server);
263  if (buf != NULL) {
264  printf ("Received unauthenticated message: %s\n", buf);
265  assert (buf == NULL);
266  }
267  close (s);
268 
269  // Check return codes for invalid buffer sizes
270  client = zmq_socket (ctx, ZMQ_DEALER);
271  assert (client);
272  errno = 0;
273  rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 123);
274  assert (rc == -1 && errno == EINVAL);
275  errno = 0;
276  rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 123);
277  assert (rc == -1 && errno == EINVAL);
278  errno = 0;
279  rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 123);
280  assert (rc == -1 && errno == EINVAL);
281  rc = zmq_close (client);
282  assert (rc == 0);
283 
284  // Shutdown
285  rc = zmq_close (server);
286  assert (rc == 0);
287  rc = zmq_ctx_term (ctx);
288  assert (rc == 0);
289 
290  // Wait until ZAP handler terminates
291  zmq_threadclose (zap_thread);
292 
293  return 0;
294 }
#define ZMQ_PLAIN_USERNAME
Definition: zmq.h:298
#define size
ZMQ_EXPORT int zmq_setsockopt(void *s, int option, const void *optval, size_t optvallen)
Definition: zmq.cpp:265
#define ZMQ_CURVE_SERVERKEY
Definition: zmq.h:303
int s_sendmore(void *socket, const char *string)
Definition: testutil.hpp:190
ZMQ_EXPORT void * zmq_ctx_new(void)
Definition: zmq.cpp:115
static void zap_handler(void *handler)
#define ZMQ_CURVE_SECRETKEY
Definition: zmq.h:302
#define ZMQ_DEALER
Definition: zmq.h:251
#define ZMQ_REP
Definition: zmq.h:250
static char client_secret[41]
void setup_test_environment(void)
Definition: testutil.hpp:285
ZMQ_EXPORT int zmq_recv(void *s, void *buf, size_t len, int flags)
Definition: zmq.cpp:507
void expect_bounce_fail(void *server, void *client)
Definition: testutil.hpp:128
#define ZMQ_PLAIN_PASSWORD
Definition: zmq.h:299
void handler(int timer_id, void *arg)
Definition: test_timers.cpp:43
#define ZMQ_CURVE_PUBLICKEY
Definition: zmq.h:301
ZMQ_EXPORT void * zmq_socket(void *, int type)
Definition: zmq.cpp:244
#define ZMQ_IDENTITY
Definition: zmq.h:265
ZMQ_EXPORT void zmq_threadclose(void *thread)
Definition: zmq_utils.cpp:85
#define streq(s1, s2)
Definition: testutil.hpp:195
static char server_secret[41]
ZMQ_EXPORT int zmq_connect(void *s, const char *addr)
Definition: zmq.cpp:332
ZMQ_EXPORT int zmq_close(void *s)
Definition: zmq.cpp:255
#define ZMQ_CURVE_SERVER
Definition: zmq.h:300
char * s_recv(void *socket)
Definition: testutil.hpp:170
ZMQ_EXPORT int zmq_curve_keypair(char *z85_public_key, char *z85_secret_key)
Definition: zmq_utils.cpp:191
void close_zero_linger(void *socket)
Definition: testutil.hpp:275
void bounce(void *server, void *client)
Definition: testutil.hpp:73
ZMQ_EXPORT int zmq_bind(void *s, const char *addr)
Definition: zmq.cpp:321
ZMQ_EXPORT int zmq_ctx_term(void *context)
Definition: zmq.cpp:162
int s_send(void *socket, const char *string)
Definition: testutil.hpp:183
int main(void)
static char server_public[41]
ZMQ_EXPORT void * zmq_threadstart(zmq_thread_fn *func, void *arg)
Definition: zmq_utils.cpp:78
#define ZMQ_RCVTIMEO
Definition: zmq.h:284
const char * address
Definition: test_fork.cpp:32
ZMQ_EXPORT char * zmq_z85_encode(char *dest, const uint8_t *data, size_t size)
Definition: zmq_utils.cpp:124
static char client_public[41]