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
31#include "precompiled.hpp"
32#include "curve_mechanism_base.hpp"
33#include "msg.hpp"
34#include "wire.hpp"
35#include "session_base.hpp"
36
37#ifdef ZMQ_HAVE_CURVE
38
39zmq::curve_mechanism_base_t::curve_mechanism_base_t (
40 session_base_t *session_,
41 const options_t &options_,
42 const char *encode_nonce_prefix_,
43 const char *decode_nonce_prefix_) :
44 mechanism_base_t (session_, options_),
45 encode_nonce_prefix (encode_nonce_prefix_),
46 decode_nonce_prefix (decode_nonce_prefix_),
47 cn_nonce (1),
48 cn_peer_nonce (1)
49{
50}
51
52int zmq::curve_mechanism_base_t::encode (msg_t *msg_)
53{
54 const size_t mlen = crypto_box_ZEROBYTES + 1 + msg_->size ();
55
56 uint8_t message_nonce[crypto_box_NONCEBYTES];
57 memcpy (message_nonce, encode_nonce_prefix, 16);
58 put_uint64 (message_nonce + 16, cn_nonce);
59
60 uint8_t flags = 0;
61 if (msg_->flags () & msg_t::more)
62 flags |= 0x01;
63 if (msg_->flags () & msg_t::command)
64 flags |= 0x02;
65
66 std::vector<uint8_t> message_plaintext (mlen);
67
68 std::fill (message_plaintext.begin (),
69 message_plaintext.begin () + crypto_box_ZEROBYTES, 0);
70 message_plaintext[crypto_box_ZEROBYTES] = flags;
71 // this is copying the data from insecure memory, so there is no point in
72 // using secure_allocator_t for message_plaintext
73 if (msg_->size () > 0)
74 memcpy (&message_plaintext[crypto_box_ZEROBYTES + 1], msg_->data (),
75 msg_->size ());
76
77 std::vector<uint8_t> message_box (mlen);
78
79 int rc = crypto_box_afternm (&message_box[0], &message_plaintext[0], mlen,
80 message_nonce, cn_precom);
81 zmq_assert (rc == 0);
82
83 rc = msg_->close ();
84 zmq_assert (rc == 0);
85
86 rc = msg_->init_size (16 + mlen - crypto_box_BOXZEROBYTES);
87 zmq_assert (rc == 0);
88
89 uint8_t *message = static_cast<uint8_t *> (msg_->data ());
90
91 memcpy (message, "\x07MESSAGE", 8);
92 memcpy (message + 8, message_nonce + 16, 8);
93 memcpy (message + 16, &message_box[crypto_box_BOXZEROBYTES],
94 mlen - crypto_box_BOXZEROBYTES);
95
96 cn_nonce++;
97
98 return 0;
99}
100
101int zmq::curve_mechanism_base_t::decode (msg_t *msg_)
102{
103 int rc = check_basic_command_structure (msg_);
104 if (rc == -1)
105 return -1;
106
107 const size_t size = msg_->size ();
108 const uint8_t *message = static_cast<uint8_t *> (msg_->data ());
109
110 if (size < 8 || memcmp (message, "\x07MESSAGE", 8)) {
111 session->get_socket ()->event_handshake_failed_protocol (
112 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
113 errno = EPROTO;
114 return -1;
115 }
116
117 if (size < 33) {
118 session->get_socket ()->event_handshake_failed_protocol (
119 session->get_endpoint (),
120 ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE);
121 errno = EPROTO;
122 return -1;
123 }
124
125 uint8_t message_nonce[crypto_box_NONCEBYTES];
126 memcpy (message_nonce, decode_nonce_prefix, 16);
127 memcpy (message_nonce + 16, message + 8, 8);
128 uint64_t nonce = get_uint64 (message + 8);
129 if (nonce <= cn_peer_nonce) {
130 session->get_socket ()->event_handshake_failed_protocol (
131 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE);
132 errno = EPROTO;
133 return -1;
134 }
135 cn_peer_nonce = nonce;
136
137 const size_t clen = crypto_box_BOXZEROBYTES + msg_->size () - 16;
138
139 std::vector<uint8_t> message_plaintext (clen);
140 std::vector<uint8_t> message_box (clen);
141
142 std::fill (message_box.begin (),
143 message_box.begin () + crypto_box_BOXZEROBYTES, 0);
144 memcpy (&message_box[crypto_box_BOXZEROBYTES], message + 16,
145 msg_->size () - 16);
146
147 rc = crypto_box_open_afternm (&message_plaintext[0], &message_box[0], clen,
148 message_nonce, cn_precom);
149 if (rc == 0) {
150 rc = msg_->close ();
151 zmq_assert (rc == 0);
152
153 rc = msg_->init_size (clen - 1 - crypto_box_ZEROBYTES);
154 zmq_assert (rc == 0);
155
156 const uint8_t flags = message_plaintext[crypto_box_ZEROBYTES];
157 if (flags & 0x01)
158 msg_->set_flags (msg_t::more);
159 if (flags & 0x02)
160 msg_->set_flags (msg_t::command);
161
162 // this is copying the data to insecure memory, so there is no point in
163 // using secure_allocator_t for message_plaintext
164 if (msg_->size () > 0)
165 memcpy (msg_->data (), &message_plaintext[crypto_box_ZEROBYTES + 1],
166 msg_->size ());
167 } else {
168 // CURVE I : connection key used for MESSAGE is wrong
169 session->get_socket ()->event_handshake_failed_protocol (
170 session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
171 errno = EPROTO;
172 }
173
174 return rc;
175}
176
177#endif
178