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#ifndef __ZMQ_CURVE_CLIENT_TOOLS_HPP_INCLUDED__
31#define __ZMQ_CURVE_CLIENT_TOOLS_HPP_INCLUDED__
32
33#ifdef ZMQ_HAVE_CURVE
34
35#if defined(ZMQ_USE_TWEETNACL)
36#include "tweetnacl.h"
37#elif defined(ZMQ_USE_LIBSODIUM)
38#include "sodium.h"
39#endif
40
41#if crypto_box_NONCEBYTES != 24 || crypto_box_PUBLICKEYBYTES != 32 \
42 || crypto_box_SECRETKEYBYTES != 32 || crypto_box_ZEROBYTES != 32 \
43 || crypto_box_BOXZEROBYTES != 16
44#error "CURVE library not built properly"
45#endif
46
47#include "wire.hpp"
48#include "err.hpp"
49#include "secure_allocator.hpp"
50
51#include <vector>
52
53namespace zmq
54{
55struct curve_client_tools_t
56{
57 static int produce_hello (void *data_,
58 const uint8_t *server_key_,
59 const uint64_t cn_nonce_,
60 const uint8_t *cn_public_,
61 const uint8_t *cn_secret_)
62 {
63 uint8_t hello_nonce[crypto_box_NONCEBYTES];
64 std::vector<uint8_t, secure_allocator_t<uint8_t> > hello_plaintext (
65 crypto_box_ZEROBYTES + 64, 0);
66 uint8_t hello_box[crypto_box_BOXZEROBYTES + 80];
67
68 // Prepare the full nonce
69 memcpy (hello_nonce, "CurveZMQHELLO---", 16);
70 put_uint64 (hello_nonce + 16, cn_nonce_);
71
72 // Create Box [64 * %x0](C'->S)
73 int rc =
74 crypto_box (hello_box, &hello_plaintext[0], hello_plaintext.size (),
75 hello_nonce, server_key_, cn_secret_);
76 if (rc == -1)
77 return -1;
78
79 uint8_t *hello = static_cast<uint8_t *> (data_);
80
81 memcpy (hello, "\x05HELLO", 6);
82 // CurveZMQ major and minor version numbers
83 memcpy (hello + 6, "\1\0", 2);
84 // Anti-amplification padding
85 memset (hello + 8, 0, 72);
86 // Client public connection key
87 memcpy (hello + 80, cn_public_, crypto_box_PUBLICKEYBYTES);
88 // Short nonce, prefixed by "CurveZMQHELLO---"
89 memcpy (hello + 112, hello_nonce + 16, 8);
90 // Signature, Box [64 * %x0](C'->S)
91 memcpy (hello + 120, hello_box + crypto_box_BOXZEROBYTES, 80);
92
93 return 0;
94 }
95
96 static int process_welcome (const uint8_t *msg_data_,
97 size_t msg_size_,
98 const uint8_t *server_key_,
99 const uint8_t *cn_secret_,
100 uint8_t *cn_server_,
101 uint8_t *cn_cookie_,
102 uint8_t *cn_precom_)
103 {
104 if (msg_size_ != 168) {
105 errno = EPROTO;
106 return -1;
107 }
108
109 uint8_t welcome_nonce[crypto_box_NONCEBYTES];
110 std::vector<uint8_t, secure_allocator_t<uint8_t> > welcome_plaintext (
111 crypto_box_ZEROBYTES + 128);
112 uint8_t welcome_box[crypto_box_BOXZEROBYTES + 144];
113
114 // Open Box [S' + cookie](C'->S)
115 memset (welcome_box, 0, crypto_box_BOXZEROBYTES);
116 memcpy (welcome_box + crypto_box_BOXZEROBYTES, msg_data_ + 24, 144);
117
118 memcpy (welcome_nonce, "WELCOME-", 8);
119 memcpy (welcome_nonce + 8, msg_data_ + 8, 16);
120
121 int rc = crypto_box_open (&welcome_plaintext[0], welcome_box,
122 sizeof welcome_box, welcome_nonce,
123 server_key_, cn_secret_);
124 if (rc != 0) {
125 errno = EPROTO;
126 return -1;
127 }
128
129 memcpy (cn_server_, &welcome_plaintext[crypto_box_ZEROBYTES], 32);
130 memcpy (cn_cookie_, &welcome_plaintext[crypto_box_ZEROBYTES + 32],
131 16 + 80);
132
133 // Message independent precomputation
134 rc = crypto_box_beforenm (cn_precom_, cn_server_, cn_secret_);
135 zmq_assert (rc == 0);
136
137 return 0;
138 }
139
140 static int produce_initiate (void *data_,
141 size_t size_,
142 const uint64_t cn_nonce_,
143 const uint8_t *server_key_,
144 const uint8_t *public_key_,
145 const uint8_t *secret_key_,
146 const uint8_t *cn_public_,
147 const uint8_t *cn_secret_,
148 const uint8_t *cn_server_,
149 const uint8_t *cn_cookie_,
150 const uint8_t *metadata_plaintext_,
151 const size_t metadata_length_)
152 {
153 uint8_t vouch_nonce[crypto_box_NONCEBYTES];
154 std::vector<uint8_t, secure_allocator_t<uint8_t> > vouch_plaintext (
155 crypto_box_ZEROBYTES + 64);
156 uint8_t vouch_box[crypto_box_BOXZEROBYTES + 80];
157
158 // Create vouch = Box [C',S](C->S')
159 std::fill (vouch_plaintext.begin (),
160 vouch_plaintext.begin () + crypto_box_ZEROBYTES, 0);
161 memcpy (&vouch_plaintext[crypto_box_ZEROBYTES], cn_public_, 32);
162 memcpy (&vouch_plaintext[crypto_box_ZEROBYTES + 32], server_key_, 32);
163
164 memcpy (vouch_nonce, "VOUCH---", 8);
165 randombytes (vouch_nonce + 8, 16);
166
167 int rc =
168 crypto_box (vouch_box, &vouch_plaintext[0], vouch_plaintext.size (),
169 vouch_nonce, cn_server_, secret_key_);
170 if (rc == -1)
171 return -1;
172
173 uint8_t initiate_nonce[crypto_box_NONCEBYTES];
174 std::vector<uint8_t> initiate_box (crypto_box_BOXZEROBYTES + 144
175 + metadata_length_);
176 std::vector<uint8_t, secure_allocator_t<uint8_t> > initiate_plaintext (
177 crypto_box_ZEROBYTES + 128 + metadata_length_);
178
179 // Create Box [C + vouch + metadata](C'->S')
180 std::fill (initiate_plaintext.begin (),
181 initiate_plaintext.begin () + crypto_box_ZEROBYTES, 0);
182 memcpy (&initiate_plaintext[crypto_box_ZEROBYTES], public_key_, 32);
183 memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 32], vouch_nonce + 8,
184 16);
185 memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 48],
186 vouch_box + crypto_box_BOXZEROBYTES, 80);
187 if (metadata_length_) {
188 memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 48 + 80],
189 metadata_plaintext_, metadata_length_);
190 }
191
192 memcpy (initiate_nonce, "CurveZMQINITIATE", 16);
193 put_uint64 (initiate_nonce + 16, cn_nonce_);
194
195 rc = crypto_box (&initiate_box[0], &initiate_plaintext[0],
196 crypto_box_ZEROBYTES + 128 + metadata_length_,
197 initiate_nonce, cn_server_, cn_secret_);
198
199 if (rc == -1)
200 return -1;
201
202 uint8_t *initiate = static_cast<uint8_t *> (data_);
203
204 zmq_assert (size_
205 == 113 + 128 + crypto_box_BOXZEROBYTES + metadata_length_);
206
207 memcpy (initiate, "\x08INITIATE", 9);
208 // Cookie provided by the server in the WELCOME command
209 memcpy (initiate + 9, cn_cookie_, 96);
210 // Short nonce, prefixed by "CurveZMQINITIATE"
211 memcpy (initiate + 105, initiate_nonce + 16, 8);
212 // Box [C + vouch + metadata](C'->S')
213 memcpy (initiate + 113, &initiate_box[crypto_box_BOXZEROBYTES],
214 128 + metadata_length_ + crypto_box_BOXZEROBYTES);
215
216 return 0;
217 }
218
219 static bool is_handshake_command_welcome (const uint8_t *msg_data_,
220 const size_t msg_size_)
221 {
222 return is_handshake_command (msg_data_, msg_size_, "\7WELCOME");
223 }
224
225 static bool is_handshake_command_ready (const uint8_t *msg_data_,
226 const size_t msg_size_)
227 {
228 return is_handshake_command (msg_data_, msg_size_, "\5READY");
229 }
230
231 static bool is_handshake_command_error (const uint8_t *msg_data_,
232 const size_t msg_size_)
233 {
234 return is_handshake_command (msg_data_, msg_size_, "\5ERROR");
235 }
236
237 // non-static functions
238 curve_client_tools_t (
239 const uint8_t (&curve_public_key_)[crypto_box_PUBLICKEYBYTES],
240 const uint8_t (&curve_secret_key_)[crypto_box_SECRETKEYBYTES],
241 const uint8_t (&curve_server_key_)[crypto_box_PUBLICKEYBYTES])
242 {
243 int rc;
244 memcpy (public_key, curve_public_key_, crypto_box_PUBLICKEYBYTES);
245 memcpy (secret_key, curve_secret_key_, crypto_box_SECRETKEYBYTES);
246 memcpy (server_key, curve_server_key_, crypto_box_PUBLICKEYBYTES);
247
248 // Generate short-term key pair
249 rc = crypto_box_keypair (cn_public, cn_secret);
250 zmq_assert (rc == 0);
251 }
252
253 int produce_hello (void *data_, const uint64_t cn_nonce_) const
254 {
255 return produce_hello (data_, server_key, cn_nonce_, cn_public,
256 cn_secret);
257 }
258
259 int process_welcome (const uint8_t *msg_data_,
260 size_t msg_size_,
261 uint8_t *cn_precom_)
262 {
263 return process_welcome (msg_data_, msg_size_, server_key, cn_secret,
264 cn_server, cn_cookie, cn_precom_);
265 }
266
267 int produce_initiate (void *data_,
268 size_t size_,
269 const uint64_t cn_nonce_,
270 const uint8_t *metadata_plaintext_,
271 const size_t metadata_length_)
272 {
273 return produce_initiate (data_, size_, cn_nonce_, server_key,
274 public_key, secret_key, cn_public, cn_secret,
275 cn_server, cn_cookie, metadata_plaintext_,
276 metadata_length_);
277 }
278
279 // Our public key (C)
280 uint8_t public_key[crypto_box_PUBLICKEYBYTES];
281
282 // Our secret key (c)
283 uint8_t secret_key[crypto_box_SECRETKEYBYTES];
284
285 // Our short-term public key (C')
286 uint8_t cn_public[crypto_box_PUBLICKEYBYTES];
287
288 // Our short-term secret key (c')
289 uint8_t cn_secret[crypto_box_SECRETKEYBYTES];
290
291 // Server's public key (S)
292 uint8_t server_key[crypto_box_PUBLICKEYBYTES];
293
294 // Server's short-term public key (S')
295 uint8_t cn_server[crypto_box_PUBLICKEYBYTES];
296
297 // Cookie received from server
298 uint8_t cn_cookie[16 + 80];
299
300 private:
301 template <size_t N>
302 static bool is_handshake_command (const uint8_t *msg_data_,
303 const size_t msg_size_,
304 const char (&prefix_)[N])
305 {
306 return msg_size_ >= (N - 1) && !memcmp (msg_data_, prefix_, N - 1);
307 }
308};
309}
310
311#endif
312
313#endif
314