curve_client.cpp
Go to the documentation of this file.
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_client.hpp"
12 #include "wire.hpp"
13 #include "curve_client_tools.hpp"
14 #include "secure_allocator.hpp"
15 
16 zmq::curve_client_t::curve_client_t (session_base_t *session_,
17  const options_t &options_,
18  const bool downgrade_sub_) :
19  mechanism_base_t (session_, options_),
20  curve_mechanism_base_t (session_,
21  options_,
22  "CurveZMQMESSAGEC",
23  "CurveZMQMESSAGES",
24  downgrade_sub_),
25  _state (send_hello),
26  _tools (options_.curve_public_key,
27  options_.curve_secret_key,
28  options_.curve_server_key)
29 {
30 }
31 
32 zmq::curve_client_t::~curve_client_t ()
33 {
34 }
35 
36 int zmq::curve_client_t::next_handshake_command (msg_t *msg_)
37 {
38  int rc = 0;
39 
40  switch (_state) {
41  case send_hello:
42  rc = produce_hello (msg_);
43  if (rc == 0)
44  _state = expect_welcome;
45  break;
46  case send_initiate:
47  rc = produce_initiate (msg_);
48  if (rc == 0)
49  _state = expect_ready;
50  break;
51  default:
52  errno = EAGAIN;
53  rc = -1;
54  }
55  return rc;
56 }
57 
58 int zmq::curve_client_t::process_handshake_command (msg_t *msg_)
59 {
60  const unsigned char *msg_data =
61  static_cast<unsigned char *> (msg_->data ());
62  const size_t msg_size = msg_->size ();
63 
64  int rc = 0;
65  if (curve_client_tools_t::is_handshake_command_welcome (msg_data, msg_size))
66  rc = process_welcome (msg_data, msg_size);
67  else if (curve_client_tools_t::is_handshake_command_ready (msg_data,
68  msg_size))
69  rc = process_ready (msg_data, msg_size);
70  else if (curve_client_tools_t::is_handshake_command_error (msg_data,
71  msg_size))
72  rc = process_error (msg_data, msg_size);
73  else {
74  session->get_socket ()->event_handshake_failed_protocol (
75  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
76  errno = EPROTO;
77  rc = -1;
78  }
79 
80  if (rc == 0) {
81  rc = msg_->close ();
82  errno_assert (rc == 0);
83  rc = msg_->init ();
84  errno_assert (rc == 0);
85  }
86 
87  return rc;
88 }
89 
90 int zmq::curve_client_t::encode (msg_t *msg_)
91 {
92  zmq_assert (_state == connected);
93  return curve_mechanism_base_t::encode (msg_);
94 }
95 
96 int zmq::curve_client_t::decode (msg_t *msg_)
97 {
98  zmq_assert (_state == connected);
99  return curve_mechanism_base_t::decode (msg_);
100 }
101 
102 zmq::mechanism_t::status_t zmq::curve_client_t::status () const
103 {
104  if (_state == connected)
105  return mechanism_t::ready;
106  if (_state == error_received)
107  return mechanism_t::error;
108 
110 }
111 
112 int zmq::curve_client_t::produce_hello (msg_t *msg_)
113 {
114  int rc = msg_->init_size (200);
115  errno_assert (rc == 0);
116 
117  rc = _tools.produce_hello (msg_->data (), get_and_inc_nonce ());
118  if (rc == -1) {
119  session->get_socket ()->event_handshake_failed_protocol (
120  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
121 
122  // TODO this is somewhat inconsistent: we call init_size, but we may
123  // not close msg_; i.e. we assume that msg_ is initialized but empty
124  // (if it were non-empty, calling init_size might cause a leak!)
125 
126  // msg_->close ();
127  return -1;
128  }
129 
130  return 0;
131 }
132 
133 int zmq::curve_client_t::process_welcome (const uint8_t *msg_data_,
134  size_t msg_size_)
135 {
136  const int rc = _tools.process_welcome (msg_data_, msg_size_,
137  get_writable_precom_buffer ());
138 
139  if (rc == -1) {
140  session->get_socket ()->event_handshake_failed_protocol (
141  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
142 
143  errno = EPROTO;
144  return -1;
145  }
146 
147  _state = send_initiate;
148 
149  return 0;
150 }
151 
152 int zmq::curve_client_t::produce_initiate (msg_t *msg_)
153 {
154  const size_t metadata_length = basic_properties_len ();
155  std::vector<unsigned char, secure_allocator_t<unsigned char> >
156  metadata_plaintext (metadata_length);
157 
158  add_basic_properties (&metadata_plaintext[0], metadata_length);
159 
160  const size_t msg_size =
161  113 + 128 + crypto_box_BOXZEROBYTES + metadata_length;
162  int rc = msg_->init_size (msg_size);
163  errno_assert (rc == 0);
164 
165  rc = _tools.produce_initiate (msg_->data (), msg_size, get_and_inc_nonce (),
166  &metadata_plaintext[0], metadata_length);
167 
168  if (-1 == rc) {
169  session->get_socket ()->event_handshake_failed_protocol (
170  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
171 
172  // TODO see comment in produce_hello
173  return -1;
174  }
175 
176  return 0;
177 }
178 
179 int zmq::curve_client_t::process_ready (const uint8_t *msg_data_,
180  size_t msg_size_)
181 {
182  if (msg_size_ < 30) {
183  session->get_socket ()->event_handshake_failed_protocol (
184  session->get_endpoint (),
186  errno = EPROTO;
187  return -1;
188  }
189 
190  const size_t clen = (msg_size_ - 14) + crypto_box_BOXZEROBYTES;
191 
192  uint8_t ready_nonce[crypto_box_NONCEBYTES];
193  std::vector<uint8_t, secure_allocator_t<uint8_t> > ready_plaintext (
194  crypto_box_ZEROBYTES + clen);
195  std::vector<uint8_t> ready_box (crypto_box_BOXZEROBYTES + 16 + clen);
196 
197  std::fill (ready_box.begin (), ready_box.begin () + crypto_box_BOXZEROBYTES,
198  0);
199  memcpy (&ready_box[crypto_box_BOXZEROBYTES], msg_data_ + 14,
200  clen - crypto_box_BOXZEROBYTES);
201 
202  memcpy (ready_nonce, "CurveZMQREADY---", 16);
203  memcpy (ready_nonce + 16, msg_data_ + 6, 8);
204  set_peer_nonce (get_uint64 (msg_data_ + 6));
205 
206  int rc = crypto_box_open_afternm (&ready_plaintext[0], &ready_box[0], clen,
207  ready_nonce, get_precom_buffer ());
208 
209  if (rc != 0) {
210  session->get_socket ()->event_handshake_failed_protocol (
211  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
212  errno = EPROTO;
213  return -1;
214  }
215 
216  rc = parse_metadata (&ready_plaintext[crypto_box_ZEROBYTES],
217  clen - crypto_box_ZEROBYTES);
218 
219  if (rc == 0)
220  _state = connected;
221  else {
222  session->get_socket ()->event_handshake_failed_protocol (
223  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);
224  errno = EPROTO;
225  }
226 
227  return rc;
228 }
229 
230 int zmq::curve_client_t::process_error (const uint8_t *msg_data_,
231  size_t msg_size_)
232 {
233  if (_state != expect_welcome && _state != expect_ready) {
234  session->get_socket ()->event_handshake_failed_protocol (
235  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
236  errno = EPROTO;
237  return -1;
238  }
239  if (msg_size_ < 7) {
240  session->get_socket ()->event_handshake_failed_protocol (
241  session->get_endpoint (),
243  errno = EPROTO;
244  return -1;
245  }
246  const size_t error_reason_len = static_cast<size_t> (msg_data_[6]);
247  if (error_reason_len > msg_size_ - 7) {
248  session->get_socket ()->event_handshake_failed_protocol (
249  session->get_endpoint (),
251  errno = EPROTO;
252  return -1;
253  }
254  const char *error_reason = reinterpret_cast<const char *> (msg_data_) + 7;
255  handle_error_reason (error_reason, error_reason_len);
256  _state = error_received;
257  return 0;
258 }
259 
260 #endif
curve_client_tools.hpp
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
#define ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
Definition: zmq.h:425
zmq::mechanism_t::ready
@ ready
Definition: mechanism.hpp:25
zmq::mechanism_t::error
@ error
Definition: mechanism.hpp:26
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
#define ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
Definition: zmq.h:437
EAGAIN
#define EAGAIN
Definition: errno.hpp:14
precompiled.hpp
zmq_assert
#define zmq_assert(x)
Definition: err.hpp:102
errno
int errno
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR
Definition: zmq.h:432
wire.hpp
EPROTO
#define EPROTO
Definition: err.hpp:26
ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
Definition: zmq.h:435
errno_assert
#define errno_assert(x)
Definition: err.hpp:113
macros.hpp
zmq::mechanism_t::handshaking
@ handshaking
Definition: mechanism.hpp:24
zmq::mechanism_t::status_t
status_t
Definition: mechanism.hpp:22
secure_allocator.hpp
msg.hpp
zmq::get_uint64
uint64_t get_uint64(const unsigned char *buffer_)
Definition: wire.hpp:63
err.hpp
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY
Definition: zmq.h:433
session_base.hpp
curve_client.hpp
options_
DebugStringOptions options_
Definition: src/google/protobuf/descriptor.cc:2410


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