Commit 75d4f50b authored by Pieter Hintjens's avatar Pieter Hintjens

Problem: ZMQ_CURVE_SECRETKEY reads beyond end of Z85 data

Solution: change setsockopts on printable keys to expect 41, nor 40
bytes. Code still accepts 40 bytes for compatibility, and copies the
key to a well-terminated string before using it.

Fixes #1148
parent 0dcf6b5e
...@@ -85,6 +85,8 @@ ZMQ_CURVE_SECRETKEY: Retrieve current CURVE secret key ...@@ -85,6 +85,8 @@ ZMQ_CURVE_SECRETKEY: Retrieve current CURVE secret key
Retrieves the current long term secret key for the socket. You can Retrieves the current long term secret key for the socket. You can
provide either a 32 byte buffer, to retrieve the binary key value, or provide either a 32 byte buffer, to retrieve the binary key value, or
a 41 byte buffer, to retrieve the key in a printable Z85 format. a 41 byte buffer, to retrieve the key in a printable Z85 format.
NOTE: to fetch a printable key, the buffer must be 41 bytes large
to hold the 40-char key value and one null byte.
[horizontal] [horizontal]
Option value type:: binary data or Z85 text string Option value type:: binary data or Z85 text string
...@@ -98,7 +100,9 @@ ZMQ_CURVE_SERVERKEY: Retrieve current CURVE server key ...@@ -98,7 +100,9 @@ ZMQ_CURVE_SERVERKEY: Retrieve current CURVE server key
Retrieves the current server key for the client socket. You can Retrieves the current server key for the client socket. You can
provide either a 32 byte buffer, to retrieve the binary key value, or provide either a 32 byte buffer, to retrieve the binary key value, or
a 40 byte buffer, to retrieve the key in a printable Z85 format. a 41-byte buffer, to retrieve the key in a printable Z85 format.
NOTE: to fetch a printable key, the buffer must be 41 bytes large
to hold the 40-char key value and one null byte.
[horizontal] [horizontal]
Option value type:: binary data or Z85 text string Option value type:: binary data or Z85 text string
......
...@@ -112,13 +112,17 @@ ZMQ_CURVE_PUBLICKEY: Set CURVE public key ...@@ -112,13 +112,17 @@ ZMQ_CURVE_PUBLICKEY: Set CURVE public key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the socket's long term public key. You must set this on CURVE client Sets the socket's long term public key. You must set this on CURVE client
sockets, see linkzmq:zmq_curve[7]. You can provide the key as 32 binary sockets, see linkzmq:zmq_curve[7]. You can provide the key as 32 binary
bytes, or as a 40-character string encoded in the Z85 encoding format. bytes, or as a 40-character string encoded in the Z85 encoding format and
The public key must always be used with the matching secret key. To terminated in a null byte. The public key must always be used with the
generate a public/secret key pair, use linkzmq:zmq_curve_keypair[3]. matching secret key. To generate a public/secret key pair, use
linkzmq:zmq_curve_keypair[3].
NOTE: an option value size of 40 is supported for backwards compatibility,
though is deprecated.
[horizontal] [horizontal]
Option value type:: binary data or Z85 text string Option value type:: binary data or Z85 text string
Option value size:: 32 or 40 Option value size:: 32 or 41
Default value:: NULL Default value:: NULL
Applicable socket types:: all, when using TCP transport Applicable socket types:: all, when using TCP transport
...@@ -128,12 +132,15 @@ ZMQ_CURVE_SECRETKEY: Set CURVE secret key ...@@ -128,12 +132,15 @@ ZMQ_CURVE_SECRETKEY: Set CURVE secret key
Sets the socket's long term secret key. You must set this on both CURVE Sets the socket's long term secret key. You must set this on both CURVE
client and server sockets, see linkzmq:zmq_curve[7]. You can provide the client and server sockets, see linkzmq:zmq_curve[7]. You can provide the
key as 32 binary bytes, or as a 40-character string encoded in the Z85 key as 32 binary bytes, or as a 40-character string encoded in the Z85
encoding format. To generate a public/secret key pair, use encoding format and terminated in a null byte. To generate a public/secret
linkzmq:zmq_curve_keypair[3]. key pair, use linkzmq:zmq_curve_keypair[3].
NOTE: an option value size of 40 is supported for backwards compatibility,
though is deprecated.
[horizontal] [horizontal]
Option value type:: binary data or Z85 text string Option value type:: binary data or Z85 text string
Option value size:: 32 or 40 Option value size:: 32 or 41
Default value:: NULL Default value:: NULL
Applicable socket types:: all, when using TCP transport Applicable socket types:: all, when using TCP transport
...@@ -160,12 +167,17 @@ ZMQ_CURVE_SERVERKEY: Set CURVE server key ...@@ -160,12 +167,17 @@ ZMQ_CURVE_SERVERKEY: Set CURVE server key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the socket's long term server key. You must set this on CURVE client Sets the socket's long term server key. You must set this on CURVE client
sockets, see linkzmq:zmq_curve[7]. You can provide the key as 32 binary sockets, see linkzmq:zmq_curve[7]. You can provide the key as 32 binary
bytes, or as a 40-character string encoded in the Z85 encoding format. bytes, or as a 40-character string encoded in the Z85 encoding format and
This key must have been generated together with the server's secret key. terminated in a null byte. This key must have been generated together with
the server's secret key. To generate a public/secret key pair, use
linkzmq:zmq_curve_keypair[3].
NOTE: an option value size of 40 is supported for backwards compatibility,
though is deprecated.
[horizontal] [horizontal]
Option value type:: binary data or Z85 text string Option value type:: binary data or Z85 text string
Option value size:: 32 or 40 Option value size:: 32 or 41
Default value:: NULL Default value:: NULL
Applicable socket types:: all, when using TCP transport Applicable socket types:: all, when using TCP transport
......
...@@ -366,17 +366,30 @@ int zmq::options_t::setsockopt (int option_, const void *optval_, ...@@ -366,17 +366,30 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
break; break;
case ZMQ_CURVE_PUBLICKEY: case ZMQ_CURVE_PUBLICKEY:
// TODO: refactor repeated code for these three options
// into set_curve_key (destination, optval, optlen) method
// ==> set_curve_key (curve_public_key, optval_, optvallen_);
if (optvallen_ == CURVE_KEYSIZE) { if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_public_key, optval_, CURVE_KEYSIZE); memcpy (curve_public_key, optval_, CURVE_KEYSIZE);
mechanism = ZMQ_CURVE; mechanism = ZMQ_CURVE;
return 0; return 0;
} }
else else
if (optvallen_ == CURVE_KEYSIZE_Z85) { if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
zmq_z85_decode (curve_public_key, (char *) optval_); zmq_z85_decode (curve_public_key, (char *) optval_);
mechanism = ZMQ_CURVE; mechanism = ZMQ_CURVE;
return 0; return 0;
} }
else
// Deprecated, not symmetrical with zmq_getsockopt
if (optvallen_ == CURVE_KEYSIZE_Z85) {
char z85_key [41];
memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
z85_key [CURVE_KEYSIZE_Z85] = 0;
zmq_z85_decode (curve_public_key, z85_key);
mechanism = ZMQ_CURVE;
return 0;
}
break; break;
case ZMQ_CURVE_SECRETKEY: case ZMQ_CURVE_SECRETKEY:
...@@ -386,25 +399,46 @@ int zmq::options_t::setsockopt (int option_, const void *optval_, ...@@ -386,25 +399,46 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
return 0; return 0;
} }
else else
if (optvallen_ == CURVE_KEYSIZE_Z85) { if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
zmq_z85_decode (curve_secret_key, (char *) optval_); zmq_z85_decode (curve_secret_key, (char *) optval_);
mechanism = ZMQ_CURVE; mechanism = ZMQ_CURVE;
return 0; return 0;
} }
else
// Deprecated, not symmetrical with zmq_getsockopt
if (optvallen_ == CURVE_KEYSIZE_Z85) {
char z85_key [41];
memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
z85_key [CURVE_KEYSIZE_Z85] = 0;
zmq_z85_decode (curve_secret_key, z85_key);
mechanism = ZMQ_CURVE;
return 0;
}
break; break;
case ZMQ_CURVE_SERVERKEY: case ZMQ_CURVE_SERVERKEY:
if (optvallen_ == CURVE_KEYSIZE) { if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_server_key, optval_, CURVE_KEYSIZE); memcpy (curve_server_key, optval_, CURVE_KEYSIZE);
as_server = 0;
mechanism = ZMQ_CURVE; mechanism = ZMQ_CURVE;
as_server = 0;
return 0; return 0;
} }
else else
if (optvallen_ == CURVE_KEYSIZE_Z85) { if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
zmq_z85_decode (curve_server_key, (char *) optval_); zmq_z85_decode (curve_server_key, (char *) optval_);
mechanism = ZMQ_CURVE;
as_server = 0; as_server = 0;
return 0;
}
else
// Deprecated, not symmetrical with zmq_getsockopt
if (optvallen_ == CURVE_KEYSIZE_Z85) {
char z85_key [41];
memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
z85_key [CURVE_KEYSIZE_Z85] = 0;
zmq_z85_decode (curve_server_key, z85_key);
mechanism = ZMQ_CURVE; mechanism = ZMQ_CURVE;
as_server = 0;
return 0; return 0;
} }
break; break;
......
...@@ -111,7 +111,7 @@ int main (void) ...@@ -111,7 +111,7 @@ int main (void)
int as_server = 1; int as_server = 1;
rc = zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int)); rc = zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int));
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (server, ZMQ_CURVE_SECRETKEY, server_secret, 40); rc = zmq_setsockopt (server, ZMQ_CURVE_SECRETKEY, server_secret, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6); rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6);
assert (rc == 0); assert (rc == 0);
...@@ -121,11 +121,11 @@ int main (void) ...@@ -121,11 +121,11 @@ int main (void)
// Check CURVE security with valid credentials // Check CURVE security with valid credentials
void *client = zmq_socket (ctx, ZMQ_DEALER); void *client = zmq_socket (ctx, ZMQ_DEALER);
assert (client); assert (client);
rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_connect (client, "tcp://localhost:9998"); rc = zmq_connect (client, "tcp://localhost:9998");
assert (rc == 0); assert (rc == 0);
...@@ -138,11 +138,11 @@ int main (void) ...@@ -138,11 +138,11 @@ int main (void)
char garbage_key [] = "0000111122223333444455556666777788889999"; char garbage_key [] = "0000111122223333444455556666777788889999";
client = zmq_socket (ctx, ZMQ_DEALER); client = zmq_socket (ctx, ZMQ_DEALER);
assert (client); assert (client);
rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, garbage_key, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, garbage_key, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_connect (client, "tcp://localhost:9998"); rc = zmq_connect (client, "tcp://localhost:9998");
assert (rc == 0); assert (rc == 0);
...@@ -153,11 +153,11 @@ int main (void) ...@@ -153,11 +153,11 @@ int main (void)
// This will be caught by the curve_server class, not passed to ZAP // This will be caught by the curve_server class, not passed to ZAP
client = zmq_socket (ctx, ZMQ_DEALER); client = zmq_socket (ctx, ZMQ_DEALER);
assert (client); assert (client);
rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, garbage_key, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, garbage_key, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_connect (client, "tcp://localhost:9998"); rc = zmq_connect (client, "tcp://localhost:9998");
assert (rc == 0); assert (rc == 0);
...@@ -168,11 +168,11 @@ int main (void) ...@@ -168,11 +168,11 @@ int main (void)
// This will be caught by the curve_server class, not passed to ZAP // This will be caught by the curve_server class, not passed to ZAP
client = zmq_socket (ctx, ZMQ_DEALER); client = zmq_socket (ctx, ZMQ_DEALER);
assert (client); assert (client);
rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, garbage_key, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, garbage_key, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_connect (client, "tcp://localhost:9998"); rc = zmq_connect (client, "tcp://localhost:9998");
assert (rc == 0); assert (rc == 0);
...@@ -187,11 +187,11 @@ int main (void) ...@@ -187,11 +187,11 @@ int main (void)
client = zmq_socket (ctx, ZMQ_DEALER); client = zmq_socket (ctx, ZMQ_DEALER);
assert (client); assert (client);
rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, bogus_public, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, bogus_public, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, bogus_secret, 40); rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, bogus_secret, 41);
assert (rc == 0); assert (rc == 0);
rc = zmq_connect (client, "tcp://localhost:9998"); rc = zmq_connect (client, "tcp://localhost:9998");
assert (rc == 0); assert (rc == 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment