libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
curve_server.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 "precompiled.hpp"
31 #include "macros.hpp"
32 #include "platform.hpp"
33 
34 #ifdef ZMQ_HAVE_CURVE
35 
36 #ifdef ZMQ_HAVE_WINDOWS
37 #include "windows.hpp"
38 #endif
39 
40 #include "msg.hpp"
41 #include "session_base.hpp"
42 #include "err.hpp"
43 #include "curve_server.hpp"
44 #include "wire.hpp"
45 
46 zmq::curve_server_t::curve_server_t (session_base_t *session_,
47  const std::string &peer_address_,
48  const options_t &options_) :
49  mechanism_t (options_),
50  session (session_),
51  peer_address (peer_address_),
52  state (expect_hello),
53  cn_nonce (1),
54  cn_peer_nonce(1)
55 {
56  int rc;
57  // Fetch our secret key from socket options
58  memcpy (secret_key, options_.curve_secret_key, crypto_box_SECRETKEYBYTES);
59 
60  // Generate short-term key pair
61  rc = crypto_box_keypair (cn_public, cn_secret);
62  zmq_assert (rc == 0);
63 }
64 
65 zmq::curve_server_t::~curve_server_t ()
66 {
67 }
68 
69 int zmq::curve_server_t::next_handshake_command (msg_t *msg_)
70 {
71  int rc = 0;
72 
73  switch (state) {
74  case send_welcome:
75  rc = produce_welcome (msg_);
76  if (rc == 0)
77  state = expect_initiate;
78  break;
79  case send_ready:
80  rc = produce_ready (msg_);
81  if (rc == 0)
82  state = connected;
83  break;
84  case send_error:
85  rc = produce_error (msg_);
86  if (rc == 0)
87  state = error_sent;
88  break;
89  default:
90  errno = EAGAIN;
91  rc = -1;
92  break;
93  }
94  return rc;
95 }
96 
97 int zmq::curve_server_t::process_handshake_command (msg_t *msg_)
98 {
99  int rc = 0;
100 
101  switch (state) {
102  case expect_hello:
103  rc = process_hello (msg_);
104  break;
105  case expect_initiate:
106  rc = process_initiate (msg_);
107  break;
108  default:
109  // Temporary support for security debugging
110  puts ("CURVE I: invalid handshake command");
111  errno = EPROTO;
112  rc = -1;
113  break;
114  }
115  if (rc == 0) {
116  rc = msg_->close ();
117  errno_assert (rc == 0);
118  rc = msg_->init ();
119  errno_assert (rc == 0);
120  }
121  return rc;
122 }
123 
124 int zmq::curve_server_t::encode (msg_t *msg_)
125 {
126  zmq_assert (state == connected);
127 
128  const size_t mlen = crypto_box_ZEROBYTES + 1 + msg_->size ();
129 
130  uint8_t message_nonce [crypto_box_NONCEBYTES];
131  memcpy (message_nonce, "CurveZMQMESSAGES", 16);
132  put_uint64 (message_nonce + 16, cn_nonce);
133 
134  uint8_t flags = 0;
135  if (msg_->flags () & msg_t::more)
136  flags |= 0x01;
137  if (msg_->flags () & msg_t::command)
138  flags |= 0x02;
139 
140  uint8_t *message_plaintext = static_cast <uint8_t *> (malloc (mlen));
141  alloc_assert (message_plaintext);
142 
143  memset (message_plaintext, 0, crypto_box_ZEROBYTES);
144  message_plaintext [crypto_box_ZEROBYTES] = flags;
145  memcpy (message_plaintext + crypto_box_ZEROBYTES + 1,
146  msg_->data (), msg_->size ());
147 
148  uint8_t *message_box = static_cast <uint8_t *> (malloc (mlen));
149  alloc_assert (message_box);
150 
151  int rc = crypto_box_afternm (message_box, message_plaintext,
152  mlen, message_nonce, cn_precom);
153  zmq_assert (rc == 0);
154 
155  rc = msg_->close ();
156  zmq_assert (rc == 0);
157 
158  rc = msg_->init_size (16 + mlen - crypto_box_BOXZEROBYTES);
159  zmq_assert (rc == 0);
160 
161  uint8_t *message = static_cast <uint8_t *> (msg_->data ());
162 
163  memcpy (message, "\x07MESSAGE", 8);
164  memcpy (message + 8, message_nonce + 16, 8);
165  memcpy (message + 16, message_box + crypto_box_BOXZEROBYTES,
166  mlen - crypto_box_BOXZEROBYTES);
167 
168  free (message_plaintext);
169  free (message_box);
170 
171  cn_nonce++;
172 
173  return 0;
174 }
175 
176 int zmq::curve_server_t::decode (msg_t *msg_)
177 {
178  zmq_assert (state == connected);
179 
180  if (msg_->size () < 33) {
181  // Temporary support for security debugging
182  puts ("CURVE I: invalid CURVE client, sent malformed command");
183  errno = EPROTO;
184  return -1;
185  }
186 
187  const uint8_t *message = static_cast <uint8_t *> (msg_->data ());
188  if (memcmp (message, "\x07MESSAGE", 8)) {
189  // Temporary support for security debugging
190  puts ("CURVE I: invalid CURVE client, did not send MESSAGE");
191  errno = EPROTO;
192  return -1;
193  }
194 
195  uint8_t message_nonce [crypto_box_NONCEBYTES];
196  memcpy (message_nonce, "CurveZMQMESSAGEC", 16);
197  memcpy (message_nonce + 16, message + 8, 8);
198  uint64_t nonce = get_uint64(message + 8);
199  if (nonce <= cn_peer_nonce) {
200  errno = EPROTO;
201  return -1;
202  }
203  cn_peer_nonce = nonce;
204 
205  const size_t clen = crypto_box_BOXZEROBYTES + msg_->size () - 16;
206 
207  uint8_t *message_plaintext = static_cast <uint8_t *> (malloc (clen));
208  alloc_assert (message_plaintext);
209 
210  uint8_t *message_box = static_cast <uint8_t *> (malloc (clen));
211  alloc_assert (message_box);
212 
213  memset (message_box, 0, crypto_box_BOXZEROBYTES);
214  memcpy (message_box + crypto_box_BOXZEROBYTES,
215  message + 16, msg_->size () - 16);
216 
217  int rc = crypto_box_open_afternm (message_plaintext, message_box,
218  clen, message_nonce, cn_precom);
219  if (rc == 0) {
220  rc = msg_->close ();
221  zmq_assert (rc == 0);
222 
223  rc = msg_->init_size (clen - 1 - crypto_box_ZEROBYTES);
224  zmq_assert (rc == 0);
225 
226  const uint8_t flags = message_plaintext [crypto_box_ZEROBYTES];
227  if (flags & 0x01)
228  msg_->set_flags (msg_t::more);
229  if (flags & 0x02)
230  msg_->set_flags (msg_t::command);
231 
232  memcpy (msg_->data (),
233  message_plaintext + crypto_box_ZEROBYTES + 1,
234  msg_->size ());
235  }
236  else {
237  // Temporary support for security debugging
238  puts ("CURVE I: connection key used for MESSAGE is wrong");
239  errno = EPROTO;
240  }
241  free (message_plaintext);
242  free (message_box);
243 
244  return rc;
245 }
246 
247 int zmq::curve_server_t::zap_msg_available ()
248 {
249  if (state != expect_zap_reply) {
250  errno = EFSM;
251  return -1;
252  }
253  const int rc = receive_and_process_zap_reply ();
254  if (rc == 0)
255  state = status_code == "200"
256  ? send_ready
257  : send_error;
258  return rc;
259 }
260 
261 zmq::mechanism_t::status_t zmq::curve_server_t::status () const
262 {
263  if (state == connected)
264  return mechanism_t::ready;
265  else
266  if (state == error_sent)
267  return mechanism_t::error;
268  else
270 }
271 
272 int zmq::curve_server_t::process_hello (msg_t *msg_)
273 {
274  if (msg_->size () != 200) {
275  // Temporary support for security debugging
276  puts ("CURVE I: client HELLO is not correct size");
277  errno = EPROTO;
278  return -1;
279  }
280 
281  const uint8_t * const hello = static_cast <uint8_t *> (msg_->data ());
282  if (memcmp (hello, "\x05HELLO", 6)) {
283  // Temporary support for security debugging
284  puts ("CURVE I: client HELLO has invalid command name");
285  errno = EPROTO;
286  return -1;
287  }
288 
289  const uint8_t major = hello [6];
290  const uint8_t minor = hello [7];
291 
292  if (major != 1 || minor != 0) {
293  // Temporary support for security debugging
294  puts ("CURVE I: client HELLO has unknown version number");
295  errno = EPROTO;
296  return -1;
297  }
298 
299  // Save client's short-term public key (C')
300  memcpy (cn_client, hello + 80, 32);
301 
302  uint8_t hello_nonce [crypto_box_NONCEBYTES];
303  uint8_t hello_plaintext [crypto_box_ZEROBYTES + 64];
304  uint8_t hello_box [crypto_box_BOXZEROBYTES + 80];
305 
306  memcpy (hello_nonce, "CurveZMQHELLO---", 16);
307  memcpy (hello_nonce + 16, hello + 112, 8);
308  cn_peer_nonce = get_uint64(hello + 112);
309 
310  memset (hello_box, 0, crypto_box_BOXZEROBYTES);
311  memcpy (hello_box + crypto_box_BOXZEROBYTES, hello + 120, 80);
312 
313  // Open Box [64 * %x0](C'->S)
314  int rc = crypto_box_open (hello_plaintext, hello_box,
315  sizeof hello_box,
316  hello_nonce, cn_client, secret_key);
317  if (rc != 0) {
318  // Temporary support for security debugging
319  puts ("CURVE I: cannot open client HELLO -- wrong server key?");
320  errno = EPROTO;
321  return -1;
322  }
323 
324  state = send_welcome;
325  return rc;
326 }
327 
328 int zmq::curve_server_t::produce_welcome (msg_t *msg_)
329 {
330  uint8_t cookie_nonce [crypto_secretbox_NONCEBYTES];
331  uint8_t cookie_plaintext [crypto_secretbox_ZEROBYTES + 64];
332  uint8_t cookie_ciphertext [crypto_secretbox_BOXZEROBYTES + 80];
333 
334  // Create full nonce for encryption
335  // 8-byte prefix plus 16-byte random nonce
336  memcpy (cookie_nonce, "COOKIE--", 8);
337  randombytes (cookie_nonce + 8, 16);
338 
339  // Generate cookie = Box [C' + s'](t)
340  memset (cookie_plaintext, 0, crypto_secretbox_ZEROBYTES);
341  memcpy (cookie_plaintext + crypto_secretbox_ZEROBYTES,
342  cn_client, 32);
343  memcpy (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32,
344  cn_secret, 32);
345 
346  // Generate fresh cookie key
347  randombytes (cookie_key, crypto_secretbox_KEYBYTES);
348 
349  // Encrypt using symmetric cookie key
350  int rc = crypto_secretbox (cookie_ciphertext, cookie_plaintext,
351  sizeof cookie_plaintext,
352  cookie_nonce, cookie_key);
353  zmq_assert (rc == 0);
354 
355  uint8_t welcome_nonce [crypto_box_NONCEBYTES];
356  uint8_t welcome_plaintext [crypto_box_ZEROBYTES + 128];
357  uint8_t welcome_ciphertext [crypto_box_BOXZEROBYTES + 144];
358 
359  // Create full nonce for encryption
360  // 8-byte prefix plus 16-byte random nonce
361  memcpy (welcome_nonce, "WELCOME-", 8);
362  randombytes (welcome_nonce + 8, crypto_box_NONCEBYTES - 8);
363 
364  // Create 144-byte Box [S' + cookie](S->C')
365  memset (welcome_plaintext, 0, crypto_box_ZEROBYTES);
366  memcpy (welcome_plaintext + crypto_box_ZEROBYTES, cn_public, 32);
367  memcpy (welcome_plaintext + crypto_box_ZEROBYTES + 32,
368  cookie_nonce + 8, 16);
369  memcpy (welcome_plaintext + crypto_box_ZEROBYTES + 48,
370  cookie_ciphertext + crypto_secretbox_BOXZEROBYTES, 80);
371 
372  rc = crypto_box (welcome_ciphertext, welcome_plaintext,
373  sizeof welcome_plaintext,
374  welcome_nonce, cn_client, secret_key);
375  if (rc == -1)
376  return -1;
377 
378  rc = msg_->init_size (168);
379  errno_assert (rc == 0);
380 
381  uint8_t * const welcome = static_cast <uint8_t *> (msg_->data ());
382  memcpy (welcome, "\x07WELCOME", 8);
383  memcpy (welcome + 8, welcome_nonce + 8, 16);
384  memcpy (welcome + 24, welcome_ciphertext + crypto_box_BOXZEROBYTES, 144);
385 
386  return 0;
387 }
388 
389 int zmq::curve_server_t::process_initiate (msg_t *msg_)
390 {
391  if (msg_->size () < 257) {
392  // Temporary support for security debugging
393  puts ("CURVE I: client INITIATE is not correct size");
394  errno = EPROTO;
395  return -1;
396  }
397 
398  const uint8_t *initiate = static_cast <uint8_t *> (msg_->data ());
399  if (memcmp (initiate, "\x08INITIATE", 9)) {
400  // Temporary support for security debugging
401  puts ("CURVE I: client INITIATE has invalid command name");
402  errno = EPROTO;
403  return -1;
404  }
405 
406  uint8_t cookie_nonce [crypto_secretbox_NONCEBYTES];
407  uint8_t cookie_plaintext [crypto_secretbox_ZEROBYTES + 64];
408  uint8_t cookie_box [crypto_secretbox_BOXZEROBYTES + 80];
409 
410  // Open Box [C' + s'](t)
411  memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES);
412  memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80);
413 
414  memcpy (cookie_nonce, "COOKIE--", 8);
415  memcpy (cookie_nonce + 8, initiate + 9, 16);
416 
417  int rc = crypto_secretbox_open (cookie_plaintext, cookie_box,
418  sizeof cookie_box,
419  cookie_nonce, cookie_key);
420  if (rc != 0) {
421  // Temporary support for security debugging
422  puts ("CURVE I: cannot open client INITIATE cookie");
423  errno = EPROTO;
424  return -1;
425  }
426 
427  // Check cookie plain text is as expected [C' + s']
428  if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, cn_client, 32)
429  || memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, cn_secret, 32)) {
430  // Temporary support for security debugging
431  puts ("CURVE I: client INITIATE cookie is not valid");
432  errno = EPROTO;
433  return -1;
434  }
435 
436  const size_t clen = (msg_->size () - 113) + crypto_box_BOXZEROBYTES;
437 
438  uint8_t initiate_nonce [crypto_box_NONCEBYTES];
439  uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 128 + 256];
440  uint8_t initiate_box [crypto_box_BOXZEROBYTES + 144 + 256];
441 
442  // Open Box [C + vouch + metadata](C'->S')
443  memset (initiate_box, 0, crypto_box_BOXZEROBYTES);
444  memcpy (initiate_box + crypto_box_BOXZEROBYTES,
445  initiate + 113, clen - crypto_box_BOXZEROBYTES);
446 
447  memcpy (initiate_nonce, "CurveZMQINITIATE", 16);
448  memcpy (initiate_nonce + 16, initiate + 105, 8);
449  cn_peer_nonce = get_uint64(initiate + 105);
450 
451  rc = crypto_box_open (initiate_plaintext, initiate_box,
452  clen, initiate_nonce, cn_client, cn_secret);
453  if (rc != 0) {
454  // Temporary support for security debugging
455  puts ("CURVE I: cannot open client INITIATE");
456  errno = EPROTO;
457  return -1;
458  }
459 
460  const uint8_t *client_key = initiate_plaintext + crypto_box_ZEROBYTES;
461 
462  uint8_t vouch_nonce [crypto_box_NONCEBYTES];
463  uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 64];
464  uint8_t vouch_box [crypto_box_BOXZEROBYTES + 80];
465 
466  // Open Box Box [C',S](C->S') and check contents
467  memset (vouch_box, 0, crypto_box_BOXZEROBYTES);
468  memcpy (vouch_box + crypto_box_BOXZEROBYTES,
469  initiate_plaintext + crypto_box_ZEROBYTES + 48, 80);
470 
471  memcpy (vouch_nonce, "VOUCH---", 8);
472  memcpy (vouch_nonce + 8,
473  initiate_plaintext + crypto_box_ZEROBYTES + 32, 16);
474 
475  rc = crypto_box_open (vouch_plaintext, vouch_box,
476  sizeof vouch_box,
477  vouch_nonce, client_key, cn_secret);
478  if (rc != 0) {
479  // Temporary support for security debugging
480  puts ("CURVE I: cannot open client INITIATE vouch");
481  errno = EPROTO;
482  return -1;
483  }
484 
485  // What we decrypted must be the client's short-term public key
486  if (memcmp (vouch_plaintext + crypto_box_ZEROBYTES, cn_client, 32)) {
487  // Temporary support for security debugging
488  puts ("CURVE I: invalid handshake from client (public key)");
489  errno = EPROTO;
490  return -1;
491  }
492 
493  // Precompute connection secret from client key
494  rc = crypto_box_beforenm (cn_precom, cn_client, cn_secret);
495  zmq_assert (rc == 0);
496 
497  // Use ZAP protocol (RFC 27) to authenticate the user.
498  rc = session->zap_connect ();
499  if (rc == 0) {
500  send_zap_request (client_key);
501  rc = receive_and_process_zap_reply ();
502  if (rc == 0)
503  state = status_code == "200"
504  ? send_ready
505  : send_error;
506  else
507  if (errno == EAGAIN)
508  state = expect_zap_reply;
509  else
510  return -1;
511  }
512  else
513  state = send_ready;
514 
515  return parse_metadata (initiate_plaintext + crypto_box_ZEROBYTES + 128,
516  clen - crypto_box_ZEROBYTES - 128);
517 }
518 
519 int zmq::curve_server_t::produce_ready (msg_t *msg_)
520 {
521  uint8_t ready_nonce [crypto_box_NONCEBYTES];
522  uint8_t ready_plaintext [crypto_box_ZEROBYTES + 256];
523  uint8_t ready_box [crypto_box_BOXZEROBYTES + 16 + 256];
524 
525  // Create Box [metadata](S'->C')
526  memset (ready_plaintext, 0, crypto_box_ZEROBYTES);
527  uint8_t *ptr = ready_plaintext + crypto_box_ZEROBYTES;
528 
529  // Add socket type property
530  const char *socket_type = socket_type_string (options.type);
531  ptr += add_property (ptr, "Socket-Type", socket_type, strlen (socket_type));
532 
533  // Add identity property
534  if (options.type == ZMQ_REQ
535  || options.type == ZMQ_DEALER
536  || options.type == ZMQ_ROUTER)
537  ptr += add_property (ptr, "Identity", options.identity, options.identity_size);
538 
539  const size_t mlen = ptr - ready_plaintext;
540 
541  memcpy (ready_nonce, "CurveZMQREADY---", 16);
542  put_uint64 (ready_nonce + 16, cn_nonce);
543 
544  int rc = crypto_box_afternm (ready_box, ready_plaintext,
545  mlen, ready_nonce, cn_precom);
546  zmq_assert (rc == 0);
547 
548  rc = msg_->init_size (14 + mlen - crypto_box_BOXZEROBYTES);
549  errno_assert (rc == 0);
550 
551  uint8_t *ready = static_cast <uint8_t *> (msg_->data ());
552 
553  memcpy (ready, "\x05READY", 6);
554  // Short nonce, prefixed by "CurveZMQREADY---"
555  memcpy (ready + 6, ready_nonce + 16, 8);
556  // Box [metadata](S'->C')
557  memcpy (ready + 14, ready_box + crypto_box_BOXZEROBYTES,
558  mlen - crypto_box_BOXZEROBYTES);
559 
560  cn_nonce++;
561 
562  return 0;
563 }
564 
565 int zmq::curve_server_t::produce_error (msg_t *msg_) const
566 {
567  zmq_assert (status_code.length () == 3);
568  const int rc = msg_->init_size (6 + 1 + status_code.length ());
569  zmq_assert (rc == 0);
570  char *msg_data = static_cast <char *> (msg_->data ());
571  memcpy (msg_data, "\5ERROR", 6);
572  msg_data [6] = sizeof status_code;
573  memcpy (msg_data + 7, status_code.c_str (), status_code.length ());
574  return 0;
575 }
576 
577 void zmq::curve_server_t::send_zap_request (const uint8_t *key)
578 {
579  int rc;
580  msg_t msg;
581 
582  // Address delimiter frame
583  rc = msg.init ();
584  errno_assert (rc == 0);
585  msg.set_flags (msg_t::more);
586  rc = session->write_zap_msg (&msg);
587  errno_assert (rc == 0);
588 
589  // Version frame
590  rc = msg.init_size (3);
591  errno_assert (rc == 0);
592  memcpy (msg.data (), "1.0", 3);
593  msg.set_flags (msg_t::more);
594  rc = session->write_zap_msg (&msg);
595  errno_assert (rc == 0);
596 
597  // Request ID frame
598  rc = msg.init_size (1);
599  errno_assert (rc == 0);
600  memcpy (msg.data (), "1", 1);
601  msg.set_flags (msg_t::more);
602  rc = session->write_zap_msg (&msg);
603  errno_assert (rc == 0);
604 
605  // Domain frame
606  rc = msg.init_size (options.zap_domain.length ());
607  errno_assert (rc == 0);
608  memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
609  msg.set_flags (msg_t::more);
610  rc = session->write_zap_msg (&msg);
611  errno_assert (rc == 0);
612 
613  // Address frame
614  rc = msg.init_size (peer_address.length ());
615  errno_assert (rc == 0);
616  memcpy (msg.data (), peer_address.c_str (), peer_address.length ());
617  msg.set_flags (msg_t::more);
618  rc = session->write_zap_msg (&msg);
619  errno_assert (rc == 0);
620 
621  // Identity frame
622  rc = msg.init_size (options.identity_size);
623  errno_assert (rc == 0);
624  memcpy (msg.data (), options.identity, options.identity_size);
625  msg.set_flags (msg_t::more);
626  rc = session->write_zap_msg (&msg);
627  errno_assert (rc == 0);
628 
629  // Mechanism frame
630  rc = msg.init_size (5);
631  errno_assert (rc == 0);
632  memcpy (msg.data (), "CURVE", 5);
633  msg.set_flags (msg_t::more);
634  rc = session->write_zap_msg (&msg);
635  errno_assert (rc == 0);
636 
637  // Credentials frame
638  rc = msg.init_size (crypto_box_PUBLICKEYBYTES);
639  errno_assert (rc == 0);
640  memcpy (msg.data (), key, crypto_box_PUBLICKEYBYTES);
641  rc = session->write_zap_msg (&msg);
642  errno_assert (rc == 0);
643 }
644 
645 int zmq::curve_server_t::receive_and_process_zap_reply ()
646 {
647  int rc = 0;
648  msg_t msg [7]; // ZAP reply consists of 7 frames
649 
650  // Initialize all reply frames
651  for (int i = 0; i < 7; i++) {
652  rc = msg [i].init ();
653  errno_assert (rc == 0);
654  }
655 
656  for (int i = 0; i < 7; i++) {
657  rc = session->read_zap_msg (&msg [i]);
658  if (rc == -1)
659  break;
660  if ((msg [i].flags () & msg_t::more) == (i < 6? 0: msg_t::more)) {
661  // Temporary support for security debugging
662  puts ("CURVE I: ZAP handler sent incomplete reply message");
663  errno = EPROTO;
664  rc = -1;
665  break;
666  }
667  }
668 
669  if (rc != 0)
670  goto error;
671 
672  // Address delimiter frame
673  if (msg [0].size () > 0) {
674  // Temporary support for security debugging
675  puts ("CURVE I: ZAP handler sent malformed reply message");
676  errno = EPROTO;
677  rc = -1;
678  goto error;
679  }
680 
681  // Version frame
682  if (msg [1].size () != 3 || memcmp (msg [1].data (), "1.0", 3)) {
683  // Temporary support for security debugging
684  puts ("CURVE I: ZAP handler sent bad version number");
685  errno = EPROTO;
686  rc = -1;
687  goto error;
688  }
689 
690  // Request id frame
691  if (msg [2].size () != 1 || memcmp (msg [2].data (), "1", 1)) {
692  // Temporary support for security debugging
693  puts ("CURVE I: ZAP handler sent bad request ID");
694  errno = EPROTO;
695  rc = -1;
696  goto error;
697  }
698 
699  // Status code frame
700  if (msg [3].size () != 3) {
701  // Temporary support for security debugging
702  puts ("CURVE I: ZAP handler rejected client authentication");
703  errno = EACCES;
704  rc = -1;
705  goto error;
706  }
707 
708  // Save status code
709  status_code.assign (static_cast <char *> (msg [3].data ()), 3);
710 
711  // Save user id
712  set_user_id (msg [5].data (), msg [5].size ());
713 
714  // Process metadata frame
715  rc = parse_metadata (static_cast <const unsigned char*> (msg [6].data ()),
716  msg [6].size (), true);
717 
718 error:
719  for (int i = 0; i < 7; i++) {
720  const int rc2 = msg [i].close ();
721  errno_assert (rc2 == 0);
722  }
723 
724  return rc;
725 }
726 
727 #endif
#define size
#define EFSM
Definition: zmq.h:167
#define ZMQ_DEALER
Definition: zmq.h:251
#define zmq_assert(x)
Definition: err.hpp:119
#define ZMQ_ROUTER
Definition: zmq.h:252
#define ZMQ_REQ
Definition: zmq.h:249
uint64_t get_uint64(const unsigned char *buffer_)
Definition: wire.hpp:93
#define EPROTO
Definition: err.hpp:58
void put_uint64(unsigned char *buffer_, uint64_t value)
Definition: wire.hpp:81
#define alloc_assert(x)
Definition: err.hpp:159
#define errno_assert(x)
Definition: err.hpp:129