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