curve_mechanism_base.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
  3. This file is part of libzmq, the ZeroMQ core engine in C++.
  4. libzmq is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU Lesser General Public License (LGPL) as published
  6. by the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. As a special exception, the Contributors give you permission to link
  9. this library with independent modules to produce an executable,
  10. regardless of the license terms of these independent modules, and to
  11. copy and distribute the resulting executable under terms of your choice,
  12. provided that you also meet, for each linked independent module, the
  13. terms and conditions of the license of that module. An independent
  14. module is a module which is not derived from or based on this library.
  15. If you modify this library, you must extend this exception to your
  16. version of the library.
  17. libzmq is distributed in the hope that it will be useful, but WITHOUT
  18. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  20. License for more details.
  21. You should have received a copy of the GNU Lesser General Public License
  22. along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. #include "precompiled.hpp"
  25. #include "curve_mechanism_base.hpp"
  26. #include "msg.hpp"
  27. #include "wire.hpp"
  28. #include "session_base.hpp"
  29. #ifdef ZMQ_HAVE_CURVE
  30. #ifdef ZMQ_USE_LIBSODIUM
  31. // libsodium added crypto_box_easy_afternm and crypto_box_open_easy_afternm with
  32. // https: //github.com/jedisct1/libsodium/commit/aaf5fbf2e53a33b18d8ea9bdf2c6f73d7acc8c3e
  33. #if SODIUM_LIBRARY_VERSION_MAJOR > 7 \
  34. || (SODIUM_LIBRARY_VERSION_MAJOR == 7 && SODIUM_LIBRARY_VERSION_MINOR >= 4)
  35. #define ZMQ_HAVE_CRYPTO_BOX_EASY_FNS 1
  36. #endif
  37. #endif
  38. zmq::curve_mechanism_base_t::curve_mechanism_base_t (
  39. session_base_t *session_,
  40. const options_t &options_,
  41. const char *encode_nonce_prefix_,
  42. const char *decode_nonce_prefix_,
  43. const bool downgrade_sub_) :
  44. mechanism_base_t (session_, options_),
  45. curve_encoding_t (
  46. encode_nonce_prefix_, decode_nonce_prefix_, downgrade_sub_)
  47. {
  48. }
  49. int zmq::curve_mechanism_base_t::encode (msg_t *msg_)
  50. {
  51. return curve_encoding_t::encode (msg_);
  52. }
  53. int zmq::curve_mechanism_base_t::decode (msg_t *msg_)
  54. {
  55. int rc = check_basic_command_structure (msg_);
  56. if (rc == -1)
  57. return -1;
  58. int error_event_code;
  59. rc = curve_encoding_t::decode (msg_, &error_event_code);
  60. if (-1 == rc) {
  61. session->get_socket ()->event_handshake_failed_protocol (
  62. session->get_endpoint (), error_event_code);
  63. }
  64. return rc;
  65. }
  66. zmq::curve_encoding_t::curve_encoding_t (const char *encode_nonce_prefix_,
  67. const char *decode_nonce_prefix_,
  68. const bool downgrade_sub_) :
  69. _encode_nonce_prefix (encode_nonce_prefix_),
  70. _decode_nonce_prefix (decode_nonce_prefix_),
  71. _cn_nonce (1),
  72. _cn_peer_nonce (1),
  73. _downgrade_sub (downgrade_sub_)
  74. {
  75. }
  76. // Right now, we only transport the lower two bit flags of zmq::msg_t, so they
  77. // are binary identical, and we can just use a bitmask to select them. If we
  78. // happened to add more flags, this might change.
  79. static const uint8_t flag_mask = zmq::msg_t::more | zmq::msg_t::command;
  80. static const size_t flags_len = 1;
  81. static const size_t nonce_prefix_len = 16;
  82. static const char message_command[] = "\x07MESSAGE";
  83. static const size_t message_command_len = sizeof (message_command) - 1;
  84. static const size_t message_header_len =
  85. message_command_len + sizeof (zmq::curve_encoding_t::nonce_t);
  86. #ifndef ZMQ_USE_LIBSODIUM
  87. static const size_t crypto_box_MACBYTES = 16;
  88. #endif
  89. int zmq::curve_encoding_t::check_validity (msg_t *msg_, int *error_event_code_)
  90. {
  91. const size_t size = msg_->size ();
  92. const uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
  93. if (size < message_command_len
  94. || 0 != memcmp (message, message_command, message_command_len)) {
  95. *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND;
  96. errno = EPROTO;
  97. return -1;
  98. }
  99. if (size < message_header_len + crypto_box_MACBYTES + flags_len) {
  100. *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE;
  101. errno = EPROTO;
  102. return -1;
  103. }
  104. {
  105. const uint64_t nonce = get_uint64 (message + message_command_len);
  106. if (nonce <= _cn_peer_nonce) {
  107. *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE;
  108. errno = EPROTO;
  109. return -1;
  110. }
  111. set_peer_nonce (nonce);
  112. }
  113. return 0;
  114. }
  115. int zmq::curve_encoding_t::encode (msg_t *msg_)
  116. {
  117. size_t sub_cancel_len = 0;
  118. uint8_t message_nonce[crypto_box_NONCEBYTES];
  119. memcpy (message_nonce, _encode_nonce_prefix, nonce_prefix_len);
  120. put_uint64 (message_nonce + nonce_prefix_len, get_and_inc_nonce ());
  121. if (msg_->is_subscribe () || msg_->is_cancel ()) {
  122. if (_downgrade_sub)
  123. sub_cancel_len = 1;
  124. else
  125. sub_cancel_len = msg_->is_cancel ()
  126. ? zmq::msg_t::cancel_cmd_name_size
  127. : zmq::msg_t::sub_cmd_name_size;
  128. }
  129. #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
  130. const size_t mlen = flags_len + sub_cancel_len + msg_->size ();
  131. std::vector<uint8_t> message_plaintext (mlen);
  132. #else
  133. const size_t mlen =
  134. crypto_box_ZEROBYTES + flags_len + sub_cancel_len + msg_->size ();
  135. std::vector<uint8_t> message_plaintext_with_zerobytes (mlen);
  136. uint8_t *const message_plaintext =
  137. &message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];
  138. std::fill (message_plaintext_with_zerobytes.begin (),
  139. message_plaintext_with_zerobytes.begin () + crypto_box_ZEROBYTES,
  140. 0);
  141. #endif
  142. const uint8_t flags = msg_->flags () & flag_mask;
  143. message_plaintext[0] = flags;
  144. // For backward compatibility subscribe/cancel command messages are not stored with
  145. // the message flags, and are encoded in the encoder, so that messages for < 3.0 peers
  146. // can be encoded in the "old" 0/1 way rather than as commands.
  147. if (sub_cancel_len == 1)
  148. message_plaintext[flags_len] = msg_->is_subscribe () ? 1 : 0;
  149. else if (sub_cancel_len == zmq::msg_t::sub_cmd_name_size) {
  150. message_plaintext[0] |= zmq::msg_t::command;
  151. memcpy (&message_plaintext[flags_len], zmq::sub_cmd_name,
  152. zmq::msg_t::sub_cmd_name_size);
  153. } else if (sub_cancel_len == zmq::msg_t::cancel_cmd_name_size) {
  154. message_plaintext[0] |= zmq::msg_t::command;
  155. memcpy (&message_plaintext[flags_len], zmq::cancel_cmd_name,
  156. zmq::msg_t::cancel_cmd_name_size);
  157. }
  158. // this is copying the data from insecure memory, so there is no point in
  159. // using secure_allocator_t for message_plaintext
  160. if (msg_->size () > 0)
  161. memcpy (&message_plaintext[flags_len + sub_cancel_len], msg_->data (),
  162. msg_->size ());
  163. #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
  164. msg_t msg_box;
  165. int rc =
  166. msg_box.init_size (message_header_len + mlen + crypto_box_MACBYTES);
  167. zmq_assert (rc == 0);
  168. rc = crypto_box_easy_afternm (
  169. static_cast<uint8_t *> (msg_box.data ()) + message_header_len,
  170. &message_plaintext[0], mlen, message_nonce, _cn_precom);
  171. zmq_assert (rc == 0);
  172. msg_->move (msg_box);
  173. uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
  174. #else
  175. std::vector<uint8_t> message_box (mlen);
  176. int rc =
  177. crypto_box_afternm (&message_box[0], &message_plaintext_with_zerobytes[0],
  178. mlen, message_nonce, _cn_precom);
  179. zmq_assert (rc == 0);
  180. rc = msg_->close ();
  181. zmq_assert (rc == 0);
  182. rc = msg_->init_size (16 + mlen - crypto_box_BOXZEROBYTES);
  183. zmq_assert (rc == 0);
  184. uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
  185. memcpy (message + message_header_len, &message_box[crypto_box_BOXZEROBYTES],
  186. mlen - crypto_box_BOXZEROBYTES);
  187. #endif
  188. memcpy (message, message_command, message_command_len);
  189. memcpy (message + message_command_len, message_nonce + nonce_prefix_len,
  190. sizeof (nonce_t));
  191. return 0;
  192. }
  193. int zmq::curve_encoding_t::decode (msg_t *msg_, int *error_event_code_)
  194. {
  195. int rc = check_validity (msg_, error_event_code_);
  196. if (0 != rc) {
  197. return rc;
  198. }
  199. uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
  200. uint8_t message_nonce[crypto_box_NONCEBYTES];
  201. memcpy (message_nonce, _decode_nonce_prefix, nonce_prefix_len);
  202. memcpy (message_nonce + nonce_prefix_len, message + message_command_len,
  203. sizeof (nonce_t));
  204. #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
  205. const size_t clen = msg_->size () - message_header_len;
  206. uint8_t *const message_plaintext = message + message_header_len;
  207. rc = crypto_box_open_easy_afternm (message_plaintext,
  208. message + message_header_len, clen,
  209. message_nonce, _cn_precom);
  210. #else
  211. const size_t clen =
  212. crypto_box_BOXZEROBYTES + msg_->size () - message_header_len;
  213. std::vector<uint8_t> message_plaintext_with_zerobytes (clen);
  214. std::vector<uint8_t> message_box (clen);
  215. std::fill (message_box.begin (),
  216. message_box.begin () + crypto_box_BOXZEROBYTES, 0);
  217. memcpy (&message_box[crypto_box_BOXZEROBYTES], message + message_header_len,
  218. msg_->size () - message_header_len);
  219. rc = crypto_box_open_afternm (&message_plaintext_with_zerobytes[0],
  220. &message_box[0], clen, message_nonce,
  221. _cn_precom);
  222. const uint8_t *const message_plaintext =
  223. &message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];
  224. #endif
  225. if (rc == 0) {
  226. const uint8_t flags = message_plaintext[0];
  227. #ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
  228. const size_t plaintext_size = clen - flags_len - crypto_box_MACBYTES;
  229. if (plaintext_size > 0) {
  230. memmove (msg_->data (), &message_plaintext[flags_len],
  231. plaintext_size);
  232. }
  233. msg_->shrink (plaintext_size);
  234. #else
  235. rc = msg_->close ();
  236. zmq_assert (rc == 0);
  237. rc = msg_->init_size (clen - flags_len - crypto_box_ZEROBYTES);
  238. zmq_assert (rc == 0);
  239. // this is copying the data to insecure memory, so there is no point in
  240. // using secure_allocator_t for message_plaintext
  241. if (msg_->size () > 0) {
  242. memcpy (msg_->data (), &message_plaintext[flags_len],
  243. msg_->size ());
  244. }
  245. #endif
  246. msg_->set_flags (flags & flag_mask);
  247. } else {
  248. // CURVE I : connection key used for MESSAGE is wrong
  249. *error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC;
  250. errno = EPROTO;
  251. }
  252. return rc;
  253. }
  254. #endif