Coverage Report

Created: 2025-08-28 07:03

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