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
33#ifdef ZMQ_HAVE_CURVE
34
35#include "msg.hpp"
36#include "session_base.hpp"
37#include "err.hpp"
38#include "curve_server.hpp"
39#include "wire.hpp"
40#include "secure_allocator.hpp"
41
42zmq::curve_server_t::curve_server_t (session_base_t *session_,
43 const std::string &peer_address_,
44 const options_t &options_) :
45 mechanism_base_t (session_, options_),
46 zap_client_common_handshake_t (
47 session_, peer_address_, options_, sending_ready),
48 curve_mechanism_base_t (
49 session_, options_, "CurveZMQMESSAGES", "CurveZMQMESSAGEC")
50{
51 int rc;
52 // Fetch our secret key from socket options
53 memcpy (_secret_key, options_.curve_secret_key, crypto_box_SECRETKEYBYTES);
54
55 // Generate short-term key pair
56 rc = crypto_box_keypair (_cn_public, _cn_secret);
57 zmq_assert (rc == 0);
58}
59
60zmq::curve_server_t::~curve_server_t ()
61{
62}
63
64int zmq::curve_server_t::next_handshake_command (msg_t *msg_)
65{
66 int rc = 0;
67
68 switch (state) {
69 case sending_welcome:
70 rc = produce_welcome (msg_);
71 if (rc == 0)
72 state = waiting_for_initiate;
73 break;
74 case sending_ready:
75 rc = produce_ready (msg_);
76 if (rc == 0)
77 state = ready;
78 break;
79 case sending_error:
80 rc = produce_error (msg_);
81 if (rc == 0)
82 state = error_sent;
83 break;
84 default:
85 errno = EAGAIN;
86 rc = -1;
87 break;
88 }
89 return rc;
90}
91
92int zmq::curve_server_t::process_handshake_command (msg_t *msg_)
93{
94 int rc = 0;
95
96 switch (state) {
97 case waiting_for_hello:
98 rc = process_hello (msg_);
99 break;
100 case waiting_for_initiate:
101 rc = process_initiate (msg_);
102 break;
103 default:
104 // TODO I think this is not a case reachable with a misbehaving
105 // client. It is not an "invalid handshake command", but would be
106 // trying to process a handshake command in an invalid state,
107 // which is purely under control of this peer.
108 // Therefore, it should be changed to zmq_assert (false);
109
110 // CURVE I: invalid handshake command
111 session->get_socket ()->event_handshake_failed_protocol (
112 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED);
113 errno = EPROTO;
114 rc = -1;
115 break;
116 }
117 if (rc == 0) {
118 rc = msg_->close ();
119 errno_assert (rc == 0);
120 rc = msg_->init ();
121 errno_assert (rc == 0);
122 }
123 return rc;
124}
125
126int zmq::curve_server_t::encode (msg_t *msg_)
127{
128 zmq_assert (state == ready);
129 return curve_mechanism_base_t::encode (msg_);
130}
131
132int zmq::curve_server_t::decode (msg_t *msg_)
133{
134 zmq_assert (state == ready);
135 return curve_mechanism_base_t::decode (msg_);
136}
137
138int zmq::curve_server_t::process_hello (msg_t *msg_)
139{
140 int rc = check_basic_command_structure (msg_);
141 if (rc == -1)
142 return -1;
143
144 const size_t size = msg_->size ();
145 const uint8_t *const hello = static_cast<uint8_t *> (msg_->data ());
146
147 if (size < 6 || memcmp (hello, "\x05HELLO", 6)) {
148 session->get_socket ()->event_handshake_failed_protocol (
149 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
150 errno = EPROTO;
151 return -1;
152 }
153
154 if (size != 200) {
155 session->get_socket ()->event_handshake_failed_protocol (
156 session->get_endpoint (),
157 ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
158 errno = EPROTO;
159 return -1;
160 }
161
162 const uint8_t major = hello[6];
163 const uint8_t minor = hello[7];
164
165 if (major != 1 || minor != 0) {
166 // CURVE I: client HELLO has unknown version number
167 session->get_socket ()->event_handshake_failed_protocol (
168 session->get_endpoint (),
169 ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
170 errno = EPROTO;
171 return -1;
172 }
173
174 // Save client's short-term public key (C')
175 memcpy (_cn_client, hello + 80, 32);
176
177 uint8_t hello_nonce[crypto_box_NONCEBYTES];
178 std::vector<uint8_t, secure_allocator_t<uint8_t> > hello_plaintext (
179 crypto_box_ZEROBYTES + 64);
180 uint8_t hello_box[crypto_box_BOXZEROBYTES + 80];
181
182 memcpy (hello_nonce, "CurveZMQHELLO---", 16);
183 memcpy (hello_nonce + 16, hello + 112, 8);
184 cn_peer_nonce = get_uint64 (hello + 112);
185
186 memset (hello_box, 0, crypto_box_BOXZEROBYTES);
187 memcpy (hello_box + crypto_box_BOXZEROBYTES, hello + 120, 80);
188
189 // Open Box [64 * %x0](C'->S)
190 rc = crypto_box_open (&hello_plaintext[0], hello_box, sizeof hello_box,
191 hello_nonce, _cn_client, _secret_key);
192 if (rc != 0) {
193 // CURVE I: cannot open client HELLO -- wrong server key?
194 session->get_socket ()->event_handshake_failed_protocol (
195 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
196 errno = EPROTO;
197 return -1;
198 }
199
200 state = sending_welcome;
201 return rc;
202}
203
204int zmq::curve_server_t::produce_welcome (msg_t *msg_)
205{
206 uint8_t cookie_nonce[crypto_secretbox_NONCEBYTES];
207 std::vector<uint8_t, secure_allocator_t<uint8_t> > cookie_plaintext (
208 crypto_secretbox_ZEROBYTES + 64);
209 uint8_t cookie_ciphertext[crypto_secretbox_BOXZEROBYTES + 80];
210
211 // Create full nonce for encryption
212 // 8-byte prefix plus 16-byte random nonce
213 memcpy (cookie_nonce, "COOKIE--", 8);
214 randombytes (cookie_nonce + 8, 16);
215
216 // Generate cookie = Box [C' + s'](t)
217 std::fill (cookie_plaintext.begin (),
218 cookie_plaintext.begin () + crypto_secretbox_ZEROBYTES, 0);
219 memcpy (&cookie_plaintext[crypto_secretbox_ZEROBYTES], _cn_client, 32);
220 memcpy (&cookie_plaintext[crypto_secretbox_ZEROBYTES + 32], _cn_secret, 32);
221
222 // Generate fresh cookie key
223 randombytes (_cookie_key, crypto_secretbox_KEYBYTES);
224
225 // Encrypt using symmetric cookie key
226 int rc =
227 crypto_secretbox (cookie_ciphertext, &cookie_plaintext[0],
228 cookie_plaintext.size (), cookie_nonce, _cookie_key);
229 zmq_assert (rc == 0);
230
231 uint8_t welcome_nonce[crypto_box_NONCEBYTES];
232 std::vector<uint8_t, secure_allocator_t<uint8_t> > welcome_plaintext (
233 crypto_box_ZEROBYTES + 128);
234 uint8_t welcome_ciphertext[crypto_box_BOXZEROBYTES + 144];
235
236 // Create full nonce for encryption
237 // 8-byte prefix plus 16-byte random nonce
238 memcpy (welcome_nonce, "WELCOME-", 8);
239 randombytes (welcome_nonce + 8, crypto_box_NONCEBYTES - 8);
240
241 // Create 144-byte Box [S' + cookie](S->C')
242 std::fill (welcome_plaintext.begin (),
243 welcome_plaintext.begin () + crypto_box_ZEROBYTES, 0);
244 memcpy (&welcome_plaintext[crypto_box_ZEROBYTES], _cn_public, 32);
245 memcpy (&welcome_plaintext[crypto_box_ZEROBYTES + 32], cookie_nonce + 8,
246 16);
247 memcpy (&welcome_plaintext[crypto_box_ZEROBYTES + 48],
248 cookie_ciphertext + crypto_secretbox_BOXZEROBYTES, 80);
249
250 rc = crypto_box (welcome_ciphertext, &welcome_plaintext[0],
251 welcome_plaintext.size (), welcome_nonce, _cn_client,
252 _secret_key);
253
254 // TODO I think we should change this back to zmq_assert (rc == 0);
255 // as it was before https://github.com/zeromq/libzmq/pull/1832
256 // The reason given there was that secret_key might be 0ed.
257 // But if it were, we would never get this far, since we could
258 // not have opened the client's hello box with a 0ed key.
259
260 if (rc == -1)
261 return -1;
262
263 rc = msg_->init_size (168);
264 errno_assert (rc == 0);
265
266 uint8_t *const welcome = static_cast<uint8_t *> (msg_->data ());
267 memcpy (welcome, "\x07WELCOME", 8);
268 memcpy (welcome + 8, welcome_nonce + 8, 16);
269 memcpy (welcome + 24, welcome_ciphertext + crypto_box_BOXZEROBYTES, 144);
270
271 return 0;
272}
273
274int zmq::curve_server_t::process_initiate (msg_t *msg_)
275{
276 int rc = check_basic_command_structure (msg_);
277 if (rc == -1)
278 return -1;
279
280 const size_t size = msg_->size ();
281 const uint8_t *initiate = static_cast<uint8_t *> (msg_->data ());
282
283 if (size < 9 || memcmp (initiate, "\x08INITIATE", 9)) {
284 session->get_socket ()->event_handshake_failed_protocol (
285 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
286 errno = EPROTO;
287 return -1;
288 }
289
290 if (size < 257) {
291 session->get_socket ()->event_handshake_failed_protocol (
292 session->get_endpoint (),
293 ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);
294 errno = EPROTO;
295 return -1;
296 }
297
298 uint8_t cookie_nonce[crypto_secretbox_NONCEBYTES];
299 uint8_t cookie_plaintext[crypto_secretbox_ZEROBYTES + 64];
300 uint8_t cookie_box[crypto_secretbox_BOXZEROBYTES + 80];
301
302 // Open Box [C' + s'](t)
303 memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES);
304 memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80);
305
306 memcpy (cookie_nonce, "COOKIE--", 8);
307 memcpy (cookie_nonce + 8, initiate + 9, 16);
308
309 rc = crypto_secretbox_open (cookie_plaintext, cookie_box, sizeof cookie_box,
310 cookie_nonce, _cookie_key);
311 if (rc != 0) {
312 // CURVE I: cannot open client INITIATE cookie
313 session->get_socket ()->event_handshake_failed_protocol (
314 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
315 errno = EPROTO;
316 return -1;
317 }
318
319 // Check cookie plain text is as expected [C' + s']
320 if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, _cn_client, 32)
321 || memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32,
322 _cn_secret, 32)) {
323 // TODO this case is very hard to test, as it would require a modified
324 // client that knows the server's secret temporary cookie key
325
326 // CURVE I: client INITIATE cookie is not valid
327 session->get_socket ()->event_handshake_failed_protocol (
328 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
329 errno = EPROTO;
330 return -1;
331 }
332
333 const size_t clen = (size - 113) + crypto_box_BOXZEROBYTES;
334
335 uint8_t initiate_nonce[crypto_box_NONCEBYTES];
336 std::vector<uint8_t, secure_allocator_t<uint8_t> > initiate_plaintext (
337 crypto_box_ZEROBYTES + clen);
338 std::vector<uint8_t> initiate_box (crypto_box_BOXZEROBYTES + clen);
339
340 // Open Box [C + vouch + metadata](C'->S')
341 std::fill (initiate_box.begin (),
342 initiate_box.begin () + crypto_box_BOXZEROBYTES, 0);
343 memcpy (&initiate_box[crypto_box_BOXZEROBYTES], initiate + 113,
344 clen - crypto_box_BOXZEROBYTES);
345
346 memcpy (initiate_nonce, "CurveZMQINITIATE", 16);
347 memcpy (initiate_nonce + 16, initiate + 105, 8);
348 cn_peer_nonce = get_uint64 (initiate + 105);
349
350 const uint8_t *client_key = &initiate_plaintext[crypto_box_ZEROBYTES];
351
352 rc = crypto_box_open (&initiate_plaintext[0], &initiate_box[0], clen,
353 initiate_nonce, _cn_client, _cn_secret);
354 if (rc != 0) {
355 // CURVE I: cannot open client INITIATE
356 session->get_socket ()->event_handshake_failed_protocol (
357 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
358 errno = EPROTO;
359 return -1;
360 }
361
362 uint8_t vouch_nonce[crypto_box_NONCEBYTES];
363 std::vector<uint8_t, secure_allocator_t<uint8_t> > vouch_plaintext (
364 crypto_box_ZEROBYTES + 64);
365 uint8_t vouch_box[crypto_box_BOXZEROBYTES + 80];
366
367 // Open Box Box [C',S](C->S') and check contents
368 memset (vouch_box, 0, crypto_box_BOXZEROBYTES);
369 memcpy (vouch_box + crypto_box_BOXZEROBYTES,
370 &initiate_plaintext[crypto_box_ZEROBYTES + 48], 80);
371
372 memcpy (vouch_nonce, "VOUCH---", 8);
373 memcpy (vouch_nonce + 8, &initiate_plaintext[crypto_box_ZEROBYTES + 32],
374 16);
375
376 rc = crypto_box_open (&vouch_plaintext[0], vouch_box, sizeof vouch_box,
377 vouch_nonce, client_key, _cn_secret);
378 if (rc != 0) {
379 // CURVE I: cannot open client INITIATE vouch
380 session->get_socket ()->event_handshake_failed_protocol (
381 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
382 errno = EPROTO;
383 return -1;
384 }
385
386 // What we decrypted must be the client's short-term public key
387 if (memcmp (&vouch_plaintext[crypto_box_ZEROBYTES], _cn_client, 32)) {
388 // TODO this case is very hard to test, as it would require a modified
389 // client that knows the server's secret short-term key
390
391 // CURVE I: invalid handshake from client (public key)
392 session->get_socket ()->event_handshake_failed_protocol (
393 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE);
394 errno = EPROTO;
395 return -1;
396 }
397
398 // Precompute connection secret from client key
399 rc = crypto_box_beforenm (cn_precom, _cn_client, _cn_secret);
400 zmq_assert (rc == 0);
401
402 // Given this is a backward-incompatible change, it's behind a socket
403 // option disabled by default.
404 if (zap_required () || !options.zap_enforce_domain) {
405 // Use ZAP protocol (RFC 27) to authenticate the user.
406 rc = session->zap_connect ();
407 if (rc == 0) {
408 send_zap_request (client_key);
409 state = waiting_for_zap_reply;
410
411 // TODO actually, it is quite unlikely that we can read the ZAP
412 // reply already, but removing this has some strange side-effect
413 // (probably because the pipe's in_active flag is true until a read
414 // is attempted)
415 if (-1 == receive_and_process_zap_reply ())
416 return -1;
417 } else if (!options.zap_enforce_domain) {
418 // This supports the Stonehouse pattern (encryption without
419 // authentication) in legacy mode (domain set but no handler).
420 state = sending_ready;
421 } else {
422 session->get_socket ()->event_handshake_failed_no_detail (
423 session->get_endpoint (), EFAULT);
424 return -1;
425 }
426 } else {
427 // This supports the Stonehouse pattern (encryption without authentication).
428 state = sending_ready;
429 }
430
431 return parse_metadata (&initiate_plaintext[crypto_box_ZEROBYTES + 128],
432 clen - crypto_box_ZEROBYTES - 128);
433}
434
435int zmq::curve_server_t::produce_ready (msg_t *msg_)
436{
437 const size_t metadata_length = basic_properties_len ();
438 uint8_t ready_nonce[crypto_box_NONCEBYTES];
439
440 std::vector<uint8_t, secure_allocator_t<uint8_t> > ready_plaintext (
441 crypto_box_ZEROBYTES + metadata_length);
442
443 // Create Box [metadata](S'->C')
444 std::fill (ready_plaintext.begin (),
445 ready_plaintext.begin () + crypto_box_ZEROBYTES, 0);
446 uint8_t *ptr = &ready_plaintext[crypto_box_ZEROBYTES];
447
448 ptr += add_basic_properties (ptr, metadata_length);
449 const size_t mlen = ptr - &ready_plaintext[0];
450
451 memcpy (ready_nonce, "CurveZMQREADY---", 16);
452 put_uint64 (ready_nonce + 16, cn_nonce);
453
454 std::vector<uint8_t> ready_box (crypto_box_BOXZEROBYTES + 16
455 + metadata_length);
456
457 int rc = crypto_box_afternm (&ready_box[0], &ready_plaintext[0], mlen,
458 ready_nonce, cn_precom);
459 zmq_assert (rc == 0);
460
461 rc = msg_->init_size (14 + mlen - crypto_box_BOXZEROBYTES);
462 errno_assert (rc == 0);
463
464 uint8_t *ready = static_cast<uint8_t *> (msg_->data ());
465
466 memcpy (ready, "\x05READY", 6);
467 // Short nonce, prefixed by "CurveZMQREADY---"
468 memcpy (ready + 6, ready_nonce + 16, 8);
469 // Box [metadata](S'->C')
470 memcpy (ready + 14, &ready_box[crypto_box_BOXZEROBYTES],
471 mlen - crypto_box_BOXZEROBYTES);
472
473 cn_nonce++;
474
475 return 0;
476}
477
478int zmq::curve_server_t::produce_error (msg_t *msg_) const
479{
480 const size_t expected_status_code_length = 3;
481 zmq_assert (status_code.length () == 3);
482 const int rc = msg_->init_size (6 + 1 + expected_status_code_length);
483 zmq_assert (rc == 0);
484 char *msg_data = static_cast<char *> (msg_->data ());
485 memcpy (msg_data, "\5ERROR", 6);
486 msg_data[6] = expected_status_code_length;
487 memcpy (msg_data + 7, status_code.c_str (), expected_status_code_length);
488 return 0;
489}
490
491void zmq::curve_server_t::send_zap_request (const uint8_t *key_)
492{
493 zap_client_t::send_zap_request ("CURVE", 5, key_,
494 crypto_box_PUBLICKEYBYTES);
495}
496
497#endif
498