Added more scaffolding for security

- additional messages to help people debugging security errors
This commit is contained in:
Pieter Hintjens 2014-04-29 22:21:58 +02:00
parent d1232d144a
commit 39ccfea036
6 changed files with 131 additions and 63 deletions

View File

@ -97,6 +97,8 @@ int zmq::curve_server_t::process_handshake_command (msg_t *msg_)
state = errored;
break;
default:
// Temporary support for security debugging
puts ("CURVE I: invalid handshake command");
state = errored;
errno = EPROTO;
rc = -1;
@ -166,12 +168,16 @@ int zmq::curve_server_t::decode (msg_t *msg_)
zmq_assert (state == connected);
if (msg_->size () < 33) {
// Temporary support for security debugging
puts ("CURVE I: invalid CURVE client, sent malformed command");
errno = EPROTO;
return -1;
}
const uint8_t *message = static_cast <uint8_t *> (msg_->data ());
if (memcmp (message, "\x07MESSAGE", 8)) {
// Temporary support for security debugging
puts ("CURVE I: invalid CURVE client, did not send MESSAGE");
errno = EPROTO;
return -1;
}
@ -209,9 +215,11 @@ int zmq::curve_server_t::decode (msg_t *msg_)
message_plaintext + crypto_box_ZEROBYTES + 1,
msg_->size ());
}
else
else {
// Temporary support for security debugging
puts ("CURVE I: connection key used for MESSAGE is wrong");
errno = EPROTO;
}
free (message_plaintext);
free (message_box);
@ -238,7 +246,7 @@ bool zmq::curve_server_t::is_handshake_complete () const
int zmq::curve_server_t::process_hello (msg_t *msg_)
{
if (msg_->size () != 200) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: client HELLO is not correct size");
errno = EPROTO;
return -1;
@ -246,7 +254,7 @@ int zmq::curve_server_t::process_hello (msg_t *msg_)
const uint8_t * const hello = static_cast <uint8_t *> (msg_->data ());
if (memcmp (hello, "\x05HELLO", 6)) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: client HELLO has invalid command name");
errno = EPROTO;
return -1;
@ -256,7 +264,7 @@ int zmq::curve_server_t::process_hello (msg_t *msg_)
const uint8_t minor = hello [7];
if (major != 1 || minor != 0) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: client HELLO has unknown version number");
errno = EPROTO;
return -1;
@ -280,7 +288,7 @@ int zmq::curve_server_t::process_hello (msg_t *msg_)
sizeof hello_box,
hello_nonce, cn_client, secret_key);
if (rc != 0) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: cannot open client HELLO -- wrong server key?");
errno = EPROTO;
return -1;
@ -352,7 +360,7 @@ int zmq::curve_server_t::produce_welcome (msg_t *msg_)
int zmq::curve_server_t::process_initiate (msg_t *msg_)
{
if (msg_->size () < 257) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: client INITIATE is not correct size");
errno = EPROTO;
return -1;
@ -360,7 +368,7 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
const uint8_t *initiate = static_cast <uint8_t *> (msg_->data ());
if (memcmp (initiate, "\x08INITIATE", 9)) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: client INITIATE has invalid command name");
errno = EPROTO;
return -1;
@ -381,7 +389,7 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
sizeof cookie_box,
cookie_nonce, cookie_key);
if (rc != 0) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: cannot open client INITIATE cookie");
errno = EPROTO;
return -1;
@ -390,7 +398,7 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
// Check cookie plain text is as expected [C' + s']
if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, cn_client, 32)
|| memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, cn_secret, 32)) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: client INITIATE cookie is not valid");
errno = EPROTO;
return -1;
@ -413,7 +421,7 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
rc = crypto_box_open (initiate_plaintext, initiate_box,
clen, initiate_nonce, cn_client, cn_secret);
if (rc != 0) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: cannot open client INITIATE");
errno = EPROTO;
return -1;
@ -438,7 +446,7 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
sizeof vouch_box,
vouch_nonce, client_key, cn_secret);
if (rc != 0) {
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: cannot open client INITIATE vouch");
errno = EPROTO;
return -1;
@ -446,6 +454,8 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
// What we decrypted must be the client's short-term public key
if (memcmp (vouch_plaintext + crypto_box_ZEROBYTES, cn_client, 32)) {
// Temporary support for security debugging
puts ("CURVE I: invalid handshake from client (public key)");
errno = EPROTO;
return -1;
}
@ -601,6 +611,8 @@ int zmq::curve_server_t::receive_and_process_zap_reply ()
if (rc == -1)
break;
if ((msg [i].flags () & msg_t::more) == (i < 6? 0: msg_t::more)) {
// Temporary support for security debugging
puts ("CURVE I: ZAP handler sent incomplete reply message");
errno = EPROTO;
rc = -1;
break;
@ -612,31 +624,37 @@ int zmq::curve_server_t::receive_and_process_zap_reply ()
// Address delimiter frame
if (msg [0].size () > 0) {
rc = -1;
// Temporary support for security debugging
puts ("CURVE I: ZAP handler sent malformed reply message");
errno = EPROTO;
rc = -1;
goto error;
}
// Version frame
if (msg [1].size () != 3 || memcmp (msg [1].data (), "1.0", 3)) {
rc = -1;
// Temporary support for security debugging
puts ("CURVE I: ZAP handler sent bad version number");
errno = EPROTO;
rc = -1;
goto error;
}
// Request id frame
if (msg [2].size () != 1 || memcmp (msg [2].data (), "1", 1)) {
rc = -1;
// Temporary support for security debugging
puts ("CURVE I: ZAP handler sent bad request ID");
errno = EPROTO;
rc = -1;
goto error;
}
// Status code frame
if (msg [3].size () != 3 || memcmp (msg [3].data (), "200", 3)) {
rc = -1;
// Temporary support for CURVE debugging
// Temporary support for security debugging
puts ("CURVE I: ZAP handler rejected client authentication");
errno = EACCES;
rc = -1;
goto error;
}

View File

@ -74,7 +74,7 @@ int zmq::null_mechanism_t::next_handshake_command (msg_t *msg_)
zap_reply_received = true;
}
unsigned char * const command_buffer = (unsigned char *) malloc (512);
unsigned char *const command_buffer = (unsigned char *) malloc (512);
alloc_assert (command_buffer);
unsigned char *ptr = command_buffer;
@ -90,10 +90,8 @@ int zmq::null_mechanism_t::next_handshake_command (msg_t *msg_)
// Add identity property
if (options.type == ZMQ_REQ
|| options.type == ZMQ_DEALER
|| options.type == ZMQ_ROUTER) {
ptr += add_property (ptr, "Identity",
options.identity, options.identity_size);
}
|| options.type == ZMQ_ROUTER)
ptr += add_property (ptr, "Identity", options.identity, options.identity_size);
const size_t command_size = ptr - command_buffer;
const int rc = msg_->init_size (command_size);
@ -109,6 +107,8 @@ int zmq::null_mechanism_t::next_handshake_command (msg_t *msg_)
int zmq::null_mechanism_t::process_handshake_command (msg_t *msg_)
{
if (ready_command_received) {
// Temporary support for security debugging
puts ("NULL I: client sent invalid NULL handshake (duplicate READY)");
errno = EPROTO;
return -1;
}
@ -118,6 +118,8 @@ int zmq::null_mechanism_t::process_handshake_command (msg_t *msg_)
size_t bytes_left = msg_->size ();
if (bytes_left < 6 || memcmp (ptr, "\5READY", 6)) {
// Temporary support for security debugging
puts ("NULL I: client sent invalid NULL handshake (not READY)");
errno = EPROTO;
return -1;
}
@ -231,6 +233,8 @@ int zmq::null_mechanism_t::receive_and_process_zap_reply ()
if (rc == -1)
break;
if ((msg [i].flags () & msg_t::more) == (i < 6? 0: msg_t::more)) {
// Temporary support for security debugging
puts ("NULL I: ZAP handler sent incomplete reply message");
errno = EPROTO;
rc = -1;
break;
@ -242,29 +246,37 @@ int zmq::null_mechanism_t::receive_and_process_zap_reply ()
// Address delimiter frame
if (msg [0].size () > 0) {
rc = -1;
// Temporary support for security debugging
puts ("NULL I: ZAP handler sent malformed reply message");
errno = EPROTO;
rc = -1;
goto error;
}
// Version frame
if (msg [1].size () != 3 || memcmp (msg [1].data (), "1.0", 3)) {
rc = -1;
// Temporary support for security debugging
puts ("NULL I: ZAP handler sent bad version number");
errno = EPROTO;
rc = -1;
goto error;
}
// Request id frame
if (msg [2].size () != 1 || memcmp (msg [2].data (), "1", 1)) {
rc = -1;
// Temporary support for security debugging
puts ("NULL I: ZAP handler sent bad request ID");
errno = EPROTO;
rc = -1;
goto error;
}
// Status code frame
if (msg [3].size () != 3 || memcmp (msg [3].data (), "200", 3)) {
rc = -1;
// Temporary support for security debugging
puts ("NULL I: ZAP handler rejected client authentication");
errno = EACCES;
rc = -1;
goto error;
}

View File

@ -104,6 +104,8 @@ int zmq::plain_mechanism_t::process_handshake_command (msg_t *msg_)
state = ready;
break;
default:
// Temporary support for security debugging
puts ("PLAIN I: invalid handshake command");
errno = EPROTO;
rc = -1;
break;
@ -170,6 +172,8 @@ int zmq::plain_mechanism_t::process_hello (msg_t *msg_)
size_t bytes_left = msg_->size ();
if (bytes_left < 6 || memcmp (ptr, "\x05HELLO", 6)) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send HELLO");
errno = EPROTO;
return -1;
}
@ -177,6 +181,8 @@ int zmq::plain_mechanism_t::process_hello (msg_t *msg_)
bytes_left -= 6;
if (bytes_left < 1) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send username");
errno = EPROTO;
return -1;
}
@ -184,29 +190,36 @@ int zmq::plain_mechanism_t::process_hello (msg_t *msg_)
bytes_left -= 1;
if (bytes_left < username_length) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, sent malformed username");
errno = EPROTO;
return -1;
}
const std::string username = std::string ((char *) ptr, username_length);
ptr += username_length;
bytes_left -= username_length;
if (bytes_left < 1) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send password");
errno = EPROTO;
return -1;
}
const size_t password_length = static_cast <size_t> (*ptr++);
bytes_left -= 1;
if (bytes_left < password_length) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, sent malformed password");
errno = EPROTO;
return -1;
}
const std::string password = std::string ((char *) ptr, password_length);
ptr += password_length;
bytes_left -= password_length;
if (bytes_left > 0) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, sent extraneous data");
errno = EPROTO;
return -1;
}
@ -240,6 +253,8 @@ int zmq::plain_mechanism_t::process_welcome (msg_t *msg_)
size_t bytes_left = msg_->size ();
if (bytes_left != 8 || memcmp (ptr, "\x07WELCOME", 8)) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send WELCOME");
errno = EPROTO;
return -1;
}
@ -284,6 +299,8 @@ int zmq::plain_mechanism_t::process_initiate (msg_t *msg_)
size_t bytes_left = msg_->size ();
if (bytes_left < 9 || memcmp (ptr, "\x08INITIATE", 9)) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send INITIATE");
errno = EPROTO;
return -1;
}
@ -330,6 +347,8 @@ int zmq::plain_mechanism_t::process_ready (msg_t *msg_)
size_t bytes_left = msg_->size ();
if (bytes_left < 6 || memcmp (ptr, "\x05READY", 6)) {
// Temporary support for security debugging
puts ("PLAIN I: invalid PLAIN client, did not send READY");
errno = EPROTO;
return -1;
}
@ -431,6 +450,8 @@ int zmq::plain_mechanism_t::receive_and_process_zap_reply ()
if (rc == -1)
break;
if ((msg [i].flags () & msg_t::more) == (i < 6? 0: msg_t::more)) {
// Temporary support for security debugging
puts ("PLAIN I: ZAP handler sent incomplete reply message");
errno = EPROTO;
rc = -1;
break;
@ -442,20 +463,26 @@ int zmq::plain_mechanism_t::receive_and_process_zap_reply ()
// Address delimiter frame
if (msg [0].size () > 0) {
rc = -1;
// Temporary support for security debugging
puts ("PLAIN I: ZAP handler sent malformed reply message");
errno = EPROTO;
rc = -1;
goto error;
}
// Version frame
if (msg [1].size () != 3 || memcmp (msg [1].data (), "1.0", 3)) {
rc = -1;
// Temporary support for security debugging
puts ("PLAIN I: ZAP handler sent bad version number");
errno = EPROTO;
rc = -1;
goto error;
}
// Request id frame
if (msg [2].size () != 1 || memcmp (msg [2].data (), "1", 1)) {
// Temporary support for security debugging
puts ("PLAIN I: ZAP handler sent bad request ID");
rc = -1;
errno = EPROTO;
goto error;
@ -463,8 +490,10 @@ int zmq::plain_mechanism_t::receive_and_process_zap_reply ()
// Status code frame
if (msg [3].size () != 3 || memcmp (msg [3].data (), "200", 3)) {
rc = -1;
// Temporary support for security debugging
puts ("PLAIN I: ZAP handler rejected client authentication");
errno = EACCES;
rc = -1;
goto error;
}

View File

@ -491,6 +491,7 @@ bool zmq::stream_engine_t::handshake ()
if (options.mechanism == ZMQ_GSSAPI)
memcpy (outpos + outsize, "GSSAPI", 6);
else
if (options.mechanism == ZMQ_CURVE)
memcpy (outpos + outsize, "CURVE", 5);
outsize += 20;
memset (outpos + outsize, 0, 32);
@ -667,6 +668,9 @@ int zmq::stream_engine_t::next_handshake_command (msg_t *msg_)
if (mechanism->is_handshake_complete ())
mechanism_ready ();
}
// TODO:
// if (errno == EPROTO || errno == EACCES)
// return ERROR command to client
return rc;
}
@ -681,6 +685,9 @@ int zmq::stream_engine_t::process_handshake_command (msg_t *msg_)
if (output_stopped)
restart_output ();
}
// TODO:
// if (errno == EPROTO || errno == EACCES)
// return ERROR command to client
return rc;
}
@ -691,6 +698,9 @@ void zmq::stream_engine_t::zap_msg_available ()
const int rc = mechanism->zap_msg_available ();
if (rc == -1) {
// TODO:
// if (errno == EACCES)
// return ERROR command to client
error ();
return;
}
@ -846,7 +856,6 @@ int zmq::stream_engine_t::write (const void *data_, size_t size_)
return nbytes;
#else
ssize_t nbytes = send (s, data_, size_, 0);
// Several errors are OK. When speculative write is being done we may not

View File

@ -227,7 +227,7 @@ int zmq::tcp_listener_t::set_address (const char *addr_)
goto error;
#endif
// Listen for incomming connections.
// Listen for incoming connections.
rc = listen (s, options.backlog);
#ifdef ZMQ_HAVE_WINDOWS
if (rc == SOCKET_ERROR) {

View File

@ -78,26 +78,26 @@ int main (void)
// We bounce between a binding server and a connecting client
// We first test client/server with no ZAP domain
// Libzmq does not call our ZAP handler, the connect must succeed
void *server = zmq_socket (ctx, ZMQ_DEALER);
assert (server);
void *client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
rc = zmq_bind (server, "tcp://127.0.0.1:9000");
assert (rc == 0);
rc = zmq_connect (client, "tcp://127.0.0.1:9000");
assert (rc == 0);
bounce (server, client);
close_zero_linger (client);
close_zero_linger (server);
// // We first test client/server with no ZAP domain
// // Libzmq does not call our ZAP handler, the connect must succeed
// void *server = zmq_socket (ctx, ZMQ_DEALER);
// assert (server);
// void *client = zmq_socket (ctx, ZMQ_DEALER);
// assert (client);
// rc = zmq_bind (server, "tcp://127.0.0.1:9000");
// assert (rc == 0);
// rc = zmq_connect (client, "tcp://127.0.0.1:9000");
// assert (rc == 0);
// bounce (server, client);
// close_zero_linger (client);
// close_zero_linger (server);
// Now define a ZAP domain for the server; this enables
// authentication. We're using the wrong domain so this test
// must fail.
server = zmq_socket (ctx, ZMQ_DEALER);
void *server = zmq_socket (ctx, ZMQ_DEALER);
assert (server);
client = zmq_socket (ctx, ZMQ_DEALER);
void *client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "WRONG", 5);
assert (rc == 0);
@ -109,20 +109,20 @@ int main (void)
close_zero_linger (client);
close_zero_linger (server);
// Now use the right domain, the test must pass
server = zmq_socket (ctx, ZMQ_DEALER);
assert (server);
client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 4);
assert (rc == 0);
rc = zmq_bind (server, "tcp://127.0.0.1:9002");
assert (rc == 0);
rc = zmq_connect (client, "tcp://127.0.0.1:9002");
assert (rc == 0);
bounce (server, client);
close_zero_linger (client);
close_zero_linger (server);
// // Now use the right domain, the test must pass
// server = zmq_socket (ctx, ZMQ_DEALER);
// assert (server);
// client = zmq_socket (ctx, ZMQ_DEALER);
// assert (client);
// rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 4);
// assert (rc == 0);
// rc = zmq_bind (server, "tcp://127.0.0.1:9002");
// assert (rc == 0);
// rc = zmq_connect (client, "tcp://127.0.0.1:9002");
// assert (rc == 0);
// bounce (server, client);
// close_zero_linger (client);
// close_zero_linger (server);
// Shutdown
rc = zmq_ctx_term (ctx);