curve_mechanism_base.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MPL-2.0 */
2 
3 
4 #include "precompiled.hpp"
6 #include "msg.hpp"
7 #include "wire.hpp"
8 #include "session_base.hpp"
9 
10 #ifdef ZMQ_HAVE_CURVE
11 
12 #ifdef ZMQ_USE_LIBSODIUM
13 // libsodium added crypto_box_easy_afternm and crypto_box_open_easy_afternm with
14 // https: //github.com/jedisct1/libsodium/commit/aaf5fbf2e53a33b18d8ea9bdf2c6f73d7acc8c3e
15 #if SODIUM_LIBRARY_VERSION_MAJOR > 7 \
16  || (SODIUM_LIBRARY_VERSION_MAJOR == 7 && SODIUM_LIBRARY_VERSION_MINOR >= 4)
17 #define ZMQ_HAVE_CRYPTO_BOX_EASY_FNS 1
18 #endif
19 #endif
20 
21 zmq::curve_mechanism_base_t::curve_mechanism_base_t (
22  session_base_t *session_,
23  const options_t &options_,
24  const char *encode_nonce_prefix_,
25  const char *decode_nonce_prefix_,
26  const bool downgrade_sub_) :
27  mechanism_base_t (session_, options_),
28  curve_encoding_t (
29  encode_nonce_prefix_, decode_nonce_prefix_, downgrade_sub_)
30 {
31 }
32 
33 int zmq::curve_mechanism_base_t::encode (msg_t *msg_)
34 {
35  return curve_encoding_t::encode (msg_);
36 }
37 
38 int zmq::curve_mechanism_base_t::decode (msg_t *msg_)
39 {
40  int rc = check_basic_command_structure (msg_);
41  if (rc == -1)
42  return -1;
43 
44  int error_event_code;
45  rc = curve_encoding_t::decode (msg_, &error_event_code);
46  if (-1 == rc) {
47  session->get_socket ()->event_handshake_failed_protocol (
48  session->get_endpoint (), error_event_code);
49  }
50 
51  return rc;
52 }
53 
54 zmq::curve_encoding_t::curve_encoding_t (const char *encode_nonce_prefix_,
55  const char *decode_nonce_prefix_,
56  const bool downgrade_sub_) :
57  _encode_nonce_prefix (encode_nonce_prefix_),
58  _decode_nonce_prefix (decode_nonce_prefix_),
59  _cn_nonce (1),
60  _cn_peer_nonce (1),
61  _downgrade_sub (downgrade_sub_)
62 {
63 }
64 
65 // Right now, we only transport the lower two bit flags of zmq::msg_t, so they
66 // are binary identical, and we can just use a bitmask to select them. If we
67 // happened to add more flags, this might change.
68 static const uint8_t flag_mask = zmq::msg_t::more | zmq::msg_t::command;
69 static const size_t flags_len = 1;
70 static const size_t nonce_prefix_len = 16;
71 static const char message_command[] = "\x07MESSAGE";
72 static const size_t message_command_len = sizeof (message_command) - 1;
73 static const size_t message_header_len =
74  message_command_len + sizeof (zmq::curve_encoding_t::nonce_t);
75 
76 #ifndef ZMQ_USE_LIBSODIUM
77 static const size_t crypto_box_MACBYTES = 16;
78 #endif
79 
80 int zmq::curve_encoding_t::check_validity (msg_t *msg_, int *error_event_code_)
81 {
82  const size_t size = msg_->size ();
83  const uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
84 
85  if (size < message_command_len
86  || 0 != memcmp (message, message_command, message_command_len)) {
87  *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND;
88  errno = EPROTO;
89  return -1;
90  }
91 
92  if (size < message_header_len + crypto_box_MACBYTES + flags_len) {
94  errno = EPROTO;
95  return -1;
96  }
97 
98  {
99  const uint64_t nonce = get_uint64 (message + message_command_len);
100  if (nonce <= _cn_peer_nonce) {
101  *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE;
102  errno = EPROTO;
103  return -1;
104  }
105  set_peer_nonce (nonce);
106  }
107 
108  return 0;
109 }
110 
111 int zmq::curve_encoding_t::encode (msg_t *msg_)
112 {
113  size_t sub_cancel_len = 0;
114  uint8_t message_nonce[crypto_box_NONCEBYTES];
115  memcpy (message_nonce, _encode_nonce_prefix, nonce_prefix_len);
116  put_uint64 (message_nonce + nonce_prefix_len, get_and_inc_nonce ());
117 
118  if (msg_->is_subscribe () || msg_->is_cancel ()) {
119  if (_downgrade_sub)
120  sub_cancel_len = 1;
121  else
122  sub_cancel_len = msg_->is_cancel ()
125  }
126 
127 #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
128  const size_t mlen = flags_len + sub_cancel_len + msg_->size ();
129  std::vector<uint8_t> message_plaintext (mlen);
130 #else
131  const size_t mlen =
132  crypto_box_ZEROBYTES + flags_len + sub_cancel_len + msg_->size ();
133  std::vector<uint8_t> message_plaintext_with_zerobytes (mlen);
134  uint8_t *const message_plaintext =
135  &message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];
136 
137  std::fill (message_plaintext_with_zerobytes.begin (),
138  message_plaintext_with_zerobytes.begin () + crypto_box_ZEROBYTES,
139  0);
140 #endif
141 
142  const uint8_t flags = msg_->flags () & flag_mask;
143  message_plaintext[0] = flags;
144 
145  // For backward compatibility subscribe/cancel command messages are not stored with
146  // the message flags, and are encoded in the encoder, so that messages for < 3.0 peers
147  // can be encoded in the "old" 0/1 way rather than as commands.
148  if (sub_cancel_len == 1)
149  message_plaintext[flags_len] = msg_->is_subscribe () ? 1 : 0;
150  else if (sub_cancel_len == zmq::msg_t::sub_cmd_name_size) {
151  message_plaintext[0] |= zmq::msg_t::command;
152  memcpy (&message_plaintext[flags_len], zmq::sub_cmd_name,
154  } else if (sub_cancel_len == zmq::msg_t::cancel_cmd_name_size) {
155  message_plaintext[0] |= zmq::msg_t::command;
156  memcpy (&message_plaintext[flags_len], zmq::cancel_cmd_name,
158  }
159 
160  // this is copying the data from insecure memory, so there is no point in
161  // using secure_allocator_t for message_plaintext
162  if (msg_->size () > 0)
163  memcpy (&message_plaintext[flags_len + sub_cancel_len], msg_->data (),
164  msg_->size ());
165 
166 #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
167  msg_t msg_box;
168  int rc =
169  msg_box.init_size (message_header_len + mlen + crypto_box_MACBYTES);
170  zmq_assert (rc == 0);
171 
172  rc = crypto_box_easy_afternm (
173  static_cast<uint8_t *> (msg_box.data ()) + message_header_len,
174  &message_plaintext[0], mlen, message_nonce, _cn_precom);
175  zmq_assert (rc == 0);
176 
177  msg_->move (msg_box);
178 
179  uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
180 #else
181  std::vector<uint8_t> message_box (mlen);
182 
183  int rc =
184  crypto_box_afternm (&message_box[0], &message_plaintext_with_zerobytes[0],
185  mlen, message_nonce, _cn_precom);
186  zmq_assert (rc == 0);
187 
188  rc = msg_->close ();
189  zmq_assert (rc == 0);
190 
191  rc = msg_->init_size (16 + mlen - crypto_box_BOXZEROBYTES);
192  zmq_assert (rc == 0);
193 
194  uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
195 
196  memcpy (message + message_header_len, &message_box[crypto_box_BOXZEROBYTES],
197  mlen - crypto_box_BOXZEROBYTES);
198 #endif
199 
200  memcpy (message, message_command, message_command_len);
201  memcpy (message + message_command_len, message_nonce + nonce_prefix_len,
202  sizeof (nonce_t));
203 
204  return 0;
205 }
206 
207 int zmq::curve_encoding_t::decode (msg_t *msg_, int *error_event_code_)
208 {
209  int rc = check_validity (msg_, error_event_code_);
210  if (0 != rc) {
211  return rc;
212  }
213 
214  uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
215 
216  uint8_t message_nonce[crypto_box_NONCEBYTES];
217  memcpy (message_nonce, _decode_nonce_prefix, nonce_prefix_len);
218  memcpy (message_nonce + nonce_prefix_len, message + message_command_len,
219  sizeof (nonce_t));
220 
221 #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
222  const size_t clen = msg_->size () - message_header_len;
223 
224  uint8_t *const message_plaintext = message + message_header_len;
225 
226  rc = crypto_box_open_easy_afternm (message_plaintext,
227  message + message_header_len, clen,
228  message_nonce, _cn_precom);
229 #else
230  const size_t clen =
231  crypto_box_BOXZEROBYTES + msg_->size () - message_header_len;
232 
233  std::vector<uint8_t> message_plaintext_with_zerobytes (clen);
234  std::vector<uint8_t> message_box (clen);
235 
236  std::fill (message_box.begin (),
237  message_box.begin () + crypto_box_BOXZEROBYTES, 0);
238  memcpy (&message_box[crypto_box_BOXZEROBYTES], message + message_header_len,
239  msg_->size () - message_header_len);
240 
241  rc = crypto_box_open_afternm (&message_plaintext_with_zerobytes[0],
242  &message_box[0], clen, message_nonce,
243  _cn_precom);
244 
245  const uint8_t *const message_plaintext =
246  &message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];
247 #endif
248 
249  if (rc == 0) {
250  const uint8_t flags = message_plaintext[0];
251 
252 #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
253  const size_t plaintext_size = clen - flags_len - crypto_box_MACBYTES;
254 
255  if (plaintext_size > 0) {
256  memmove (msg_->data (), &message_plaintext[flags_len],
257  plaintext_size);
258  }
259 
260  msg_->shrink (plaintext_size);
261 #else
262  rc = msg_->close ();
263  zmq_assert (rc == 0);
264 
265  rc = msg_->init_size (clen - flags_len - crypto_box_ZEROBYTES);
266  zmq_assert (rc == 0);
267 
268  // this is copying the data to insecure memory, so there is no point in
269  // using secure_allocator_t for message_plaintext
270  if (msg_->size () > 0) {
271  memcpy (msg_->data (), &message_plaintext[flags_len],
272  msg_->size ());
273  }
274 #endif
275 
276  msg_->set_flags (flags & flag_mask);
277  } else {
278  // CURVE I : connection key used for MESSAGE is wrong
279  *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC;
280  errno = EPROTO;
281  }
282 
283  return rc;
284 }
285 
286 #endif
zmq::msg_t::command
@ command
Definition: msg.hpp:56
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
#define ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
Definition: zmq.h:425
ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE
#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE
Definition: zmq.h:426
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
#define ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
Definition: zmq.h:437
zmq::msg_t::cancel_cmd_name_size
@ cancel_cmd_name_size
Definition: msg.hpp:160
precompiled.hpp
curve_mechanism_base.hpp
zmq_assert
#define zmq_assert(x)
Definition: err.hpp:102
zmq::msg_t::sub_cmd_name_size
@ sub_cmd_name_size
Definition: msg.hpp:161
zmq::cancel_cmd_name
static const char cancel_cmd_name[]
Definition: msg.hpp:30
errno
int errno
flags
GLbitfield flags
Definition: glcorearb.h:3585
wire.hpp
EPROTO
#define EPROTO
Definition: err.hpp:26
msg.hpp
zmq::put_uint64
void put_uint64(unsigned char *buffer_, uint64_t value_)
Definition: wire.hpp:51
zmq::msg_t::more
@ more
Definition: msg.hpp:55
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
Definition: zmq.h:429
size
GLsizeiptr size
Definition: glcorearb.h:2943
zmq::get_uint64
uint64_t get_uint64(const unsigned char *buffer_)
Definition: wire.hpp:63
zmq::sub_cmd_name
static const char sub_cmd_name[]
Definition: msg.hpp:31
session_base.hpp
message
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: glcorearb.h:2695
options_
DebugStringOptions options_
Definition: src/google/protobuf/descriptor.cc:2410


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:49