Skip to content

Commit

Permalink
Merge pull request zeromq#16 from hintjens/master
Browse files Browse the repository at this point in the history
Cherry picking changes from libzmq master
  • Loading branch information
hintjens committed Oct 4, 2013
2 parents 34471cd + 814b93e commit b20573c
Show file tree
Hide file tree
Showing 15 changed files with 199 additions and 69 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ tests/test_inproc_connect
tests/test_linger
tests/test_security_null
tests/test_security_plain
tests/test*.log
tests/test*.trs
src/platform.hpp*
src/stamp-h1
perf/local_lat
Expand Down
2 changes: 1 addition & 1 deletion doc/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ MAN3 = zmq_bind.3 zmq_unbind.3 zmq_connect.3 zmq_disconnect.3 zmq_close.3 \
zmq_socket.3 zmq_socket_monitor.3 zmq_poll.3 \
zmq_errno.3 zmq_strerror.3 zmq_version.3 zmq_proxy.3 \
zmq_sendmsg.3 zmq_recvmsg.3 zmq_init.3 zmq_term.3 \
zmq_z85_encode.3 zmq_z85_decode.3
zmq_z85_encode.3 zmq_z85_decode.3 zmq_curve_keypair.3

MAN7 = zmq.7 zmq_tcp.7 zmq_pgm.7 zmq_epgm.7 zmq_inproc.7 zmq_ipc.7 \
zmq_null.7 zmq_plain.7 zmq_curve.7
Expand Down
9 changes: 9 additions & 0 deletions doc/zmq.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ Plain-text authentication using username and password::
Elliptic curve authentication and encryption::
linkzmq:zmq_curve[7]

Generate a CURVE keypair in armored text format:
linkzmq:zmq_curve_keypair[3]

Convert an armored key into a 32-byte binary key:
linkzmq:zmq_z85_decode[3]

Convert a 32-byte binary CURVE key to an armored text string:
linkzmq:zmq_z85_encode[3]


ERROR HANDLING
--------------
Expand Down
2 changes: 1 addition & 1 deletion doc/zmq_ctx_get.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ EXAMPLE
.Setting a limit on the number of sockets
----
void *context = zmq_ctx_new ();
zmq_ctx_get (context, ZMQ_MAX_SOCKETS, 256);
zmq_ctx_set (context, ZMQ_MAX_SOCKETS, 256);
int max_sockets = zmq_ctx_get (context, ZMQ_MAX_SOCKETS);
assert (max_sockets == 256);
----
Expand Down
56 changes: 56 additions & 0 deletions doc/zmq_curve_keypair.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
zmq_curve_keypair(3)
====================


NAME
----
zmq_curve_keypair - generate a new CURVE keypair


SYNOPSIS
--------
*int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);*


DESCRIPTION
-----------
The _zmq_curve_keypair()_ function shall return a newly generated random
keypair consisting of a public key and a secret key. The caller provides
two buffers, each at least 41 octets large, in which this method will
store the keys. The keys are encoded using linkzmq:zmq_z85_encode[3].


RETURN VALUE
------------
The _zmq_curve_keypair()_ function shall return 0 if successful, else it
shall return `-1` and set 'errno' to one of the values defined below.


ERRORS
------
*ENOTSUP*::
The libzmq library was not built with cryptographic support (libsodium).


EXAMPLE
-------
.Generating a new CURVE keypair
----
char public_key [41];
char secret_key [41];
int rc = crypto_box_keypair (public_key, secret_key);
assert (rc == 0);
----


SEE ALSO
--------
linkzmq:zmq_z85_decode[3]
linkzmq:zmq_z85_encode[3]
linkzmq:zmq_curve[7]


AUTHORS
-------
This page was written by the 0MQ community. To make a change please
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.
2 changes: 1 addition & 1 deletion doc/zmq_z85_decode.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ EXAMPLE
-------
.Decoding a CURVE key
----
#include <sodium.h>
char decoded [] = "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7";
uint8_t public_key [32];
zmq_z85_decode (public_key, decoded);
Expand All @@ -41,6 +40,7 @@ zmq_z85_decode (public_key, decoded);
SEE ALSO
--------
linkzmq:zmq_z85_decode[3]
linkzmq:zmq_curve_keypair[3]
linkzmq:zmq_curve[7]


Expand Down
1 change: 1 addition & 0 deletions doc/zmq_z85_encode.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ puts (encoded);
SEE ALSO
--------
linkzmq:zmq_z85_decode[3]
linkzmq:zmq_curve_keypair[3]
linkzmq:zmq_curve[7]


Expand Down
8 changes: 8 additions & 0 deletions include/zmq.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*************************************************************************
NOTE to contributors. This file comprises the principal public contract
for ZeroMQ API users (along with zmq_utils.h). Any change to this file
supplied in a stable release SHOULD not break existing applications.
In practice this means that the value of constants must not change, and
that old values may not be reused for new constants.
*************************************************************************
*/

#ifndef __ZMQ_H_INCLUDED__
Expand Down
20 changes: 14 additions & 6 deletions include/zmq_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,22 @@ extern "C" {
# endif
#endif

/* These functions are documented by man pages */

/* Encode data with Z85 encoding. Returns encoded data */
ZMQ_EXPORT char *zmq_z85_encode (char *dest, uint8_t *data, size_t size);

/* Decode data with Z85 encoding. Returns decoded data */
ZMQ_EXPORT uint8_t *zmq_z85_decode (uint8_t *dest, char *string);

/* Generate z85-encoded public and private keypair with libsodium. */
/* Returns 0 on success. */
ZMQ_EXPORT int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);

typedef void (zmq_thread_fn) (void*);

/* These functions are not documented by man pages */

/* Helper functions are used by perf tests so that they don't have to care */
/* about minutiae of time-related functions on different OS platforms. */

Expand All @@ -82,12 +96,6 @@ ZMQ_EXPORT void *zmq_threadstart (zmq_thread_fn* func, void* arg);
/* Wait for thread to complete then free up resources. */
ZMQ_EXPORT void zmq_threadclose (void* thread);

/* Encode data with Z85 encoding. Returns encoded data */
ZMQ_EXPORT char *zmq_z85_encode (char *dest, uint8_t *data, size_t size);

/* Decode data with Z85 encoding. Returns decoded data */
ZMQ_EXPORT uint8_t *zmq_z85_decode (uint8_t *dest, char *string);

#undef ZMQ_EXPORT

#ifdef __cplusplus
Expand Down
25 changes: 14 additions & 11 deletions src/curve_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,34 +297,38 @@ int zmq::curve_client_t::process_welcome (msg_t *msg_)
int zmq::curve_client_t::produce_initiate (msg_t *msg_)
{
uint8_t vouch_nonce [crypto_box_NONCEBYTES];
uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 32];
uint8_t vouch_box [crypto_box_BOXZEROBYTES + 48];
uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 64];
uint8_t vouch_box [crypto_box_BOXZEROBYTES + 80];

// Create vouch = Box [C'](C->S)
// Create vouch = Box [C',S](C->S')
memset (vouch_plaintext, 0, crypto_box_ZEROBYTES);
memcpy (vouch_plaintext + crypto_box_ZEROBYTES, cn_public, 32);
memcpy (vouch_plaintext + crypto_box_ZEROBYTES + 32, server_key, 32);

memcpy (vouch_nonce, "VOUCH---", 8);
randombytes (vouch_nonce + 8, 16);

int rc = crypto_box (vouch_box, vouch_plaintext,
sizeof vouch_plaintext,
vouch_nonce, server_key, secret_key);
vouch_nonce, cn_server, secret_key);
zmq_assert (rc == 0);

// Assume here that metadata is limited to 256 bytes
uint8_t initiate_nonce [crypto_box_NONCEBYTES];
uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 96 + 256];
uint8_t initiate_box [crypto_box_BOXZEROBYTES + 112 + 256];
uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 128 + 256];
uint8_t initiate_box [crypto_box_BOXZEROBYTES + 144 + 256];

// Create Box [C + vouch + metadata](C'->S')
memset (initiate_plaintext, 0, crypto_box_ZEROBYTES);
memcpy (initiate_plaintext + crypto_box_ZEROBYTES, public_key, 32);
memcpy (initiate_plaintext + crypto_box_ZEROBYTES,
public_key, 32);
memcpy (initiate_plaintext + crypto_box_ZEROBYTES + 32,
vouch_nonce + 8, 16);
memcpy (initiate_plaintext + crypto_box_ZEROBYTES + 48,
vouch_box + crypto_box_BOXZEROBYTES, 48);
vouch_box + crypto_box_BOXZEROBYTES, 80);

uint8_t *ptr = initiate_plaintext + crypto_box_ZEROBYTES + 96;
// Metadata starts after vouch
uint8_t *ptr = initiate_plaintext + crypto_box_ZEROBYTES + 128;

// Add socket type property
const char *socket_type = socket_type_string (options.type);
Expand All @@ -335,7 +339,7 @@ int zmq::curve_client_t::produce_initiate (msg_t *msg_)
|| options.type == ZMQ_DEALER
|| options.type == ZMQ_ROUTER)
ptr += add_property (ptr, "Identity",
options.identity, options.identity_size);
options.identity, options.identity_size);

const size_t mlen = ptr - initiate_plaintext;

Expand All @@ -359,7 +363,6 @@ int zmq::curve_client_t::produce_initiate (msg_t *msg_)
// Box [C + vouch + metadata](C'->S')
memcpy (initiate + 113, initiate_box + crypto_box_BOXZEROBYTES,
mlen - crypto_box_BOXZEROBYTES);

cn_nonce++;

return 0;
Expand Down
28 changes: 13 additions & 15 deletions src/curve_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ int zmq::curve_server_t::produce_welcome (msg_t *msg_)

int zmq::curve_server_t::process_initiate (msg_t *msg_)
{
if (msg_->size () < 225) {
if (msg_->size () < 257) {
errno = EPROTO;
return -1;
}
Expand Down Expand Up @@ -369,19 +369,17 @@ 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)) {
errno = EAGAIN;
if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, cn_client, 32)
|| memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, cn_secret, 32)) {
errno = EPROTO;
return -1;
}

const size_t clen = (msg_->size () - 113) + crypto_box_BOXZEROBYTES;

uint8_t initiate_nonce [crypto_box_NONCEBYTES];
uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 96 + 256];
uint8_t initiate_box [crypto_box_BOXZEROBYTES + 112 + 256];
uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 128 + 256];
uint8_t initiate_box [crypto_box_BOXZEROBYTES + 144 + 256];

// Open Box [C + vouch + metadata](C'->S')
memset (initiate_box, 0, crypto_box_BOXZEROBYTES);
Expand All @@ -401,21 +399,21 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
const uint8_t *client_key = initiate_plaintext + crypto_box_ZEROBYTES;

uint8_t vouch_nonce [crypto_box_NONCEBYTES];
uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 32];
uint8_t vouch_box [crypto_box_BOXZEROBYTES + 48];
uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 64];
uint8_t vouch_box [crypto_box_BOXZEROBYTES + 80];

// Open Box [C'](C->S) and check contents
// Open Box Box [C',S](C->S') and check contents
memset (vouch_box, 0, crypto_box_BOXZEROBYTES);
memcpy (vouch_box + crypto_box_BOXZEROBYTES,
initiate_plaintext + crypto_box_ZEROBYTES + 48, 48);
initiate_plaintext + crypto_box_ZEROBYTES + 48, 80);

memcpy (vouch_nonce, "VOUCH---", 8);
memcpy (vouch_nonce + 8,
initiate_plaintext + crypto_box_ZEROBYTES + 32, 16);

rc = crypto_box_open (vouch_plaintext, vouch_box,
sizeof vouch_box,
vouch_nonce, client_key, secret_key);
vouch_nonce, client_key, cn_secret);
if (rc != 0) {
errno = EPROTO;
return -1;
Expand Down Expand Up @@ -443,8 +441,8 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
}
}

return parse_metadata (initiate_plaintext + crypto_box_ZEROBYTES + 96,
clen - crypto_box_ZEROBYTES - 96);
return parse_metadata (initiate_plaintext + crypto_box_ZEROBYTES + 128,
clen - crypto_box_ZEROBYTES - 128);
}

int zmq::curve_server_t::produce_ready (msg_t *msg_)
Expand Down
50 changes: 47 additions & 3 deletions src/zmq_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#else
#include "windows.hpp"
#endif
#ifdef HAVE_LIBSODIUM
# include <sodium.h>
#endif


void zmq_sleep (int seconds_)
{
Expand Down Expand Up @@ -100,10 +104,14 @@ static uint8_t decoder [96] = {
// Encode a binary frame as a string; destination string MUST be at least
// size * 5 / 4 bytes long plus 1 byte for the null terminator. Returns
// dest. Size must be a multiple of 4.
// Returns NULL and sets errno = EINVAL for invalid input.

char *zmq_z85_encode (char *dest, uint8_t *data, size_t size)
{
assert (size % 4 == 0);
if (size % 4 != 0) {
errno = EINVAL;
return NULL;
}
unsigned int char_nbr = 0;
unsigned int byte_nbr = 0;
uint32_t value = 0;
Expand All @@ -125,15 +133,20 @@ char *zmq_z85_encode (char *dest, uint8_t *data, size_t size)
return dest;
}


// --------------------------------------------------------------------------
// Decode an encoded string into a binary frame; dest must be at least
// strlen (string) * 4 / 5 bytes long. Returns dest. strlen (string)
// must be a multiple of 5.
// Returns NULL and sets errno = EINVAL for invalid input.

uint8_t *zmq_z85_decode (uint8_t *dest, char *string)
{
assert (strlen (string) % 5 == 0);

if (strlen (string) % 5 != 0) {
errno = EINVAL;
return NULL;
}
unsigned int byte_nbr = 0;
unsigned int char_nbr = 0;
uint32_t value = 0;
Expand All @@ -153,3 +166,34 @@ uint8_t *zmq_z85_decode (uint8_t *dest, char *string)
assert (byte_nbr == strlen (string) * 4 / 5);
return dest;
}

// --------------------------------------------------------------------------
// Generate a public/private keypair with libsodium.
// Generated keys will be 40 byte z85-encoded strings.
// Returns 0 on success, -1 on failure, setting errno.
// Sets errno = ENOTSUP in the absence of libsodium.

int zmq_curve_keypair (char* z85_public_key, char *z85_secret_key)
{
#ifdef HAVE_LIBSODIUM
# if crypto_box_PUBLICKEYBYTES != 32 \
|| crypto_box_SECRETKEYBYTES != 32
# error "libsodium not built correctly"
# endif

uint8_t public_key [32];
uint8_t secret_key [32];

int rc = crypto_box_keypair (public_key, secret_key);
// is there a sensible errno to set here?
if (rc) return rc;

zmq_z85_encode (z85_public_key, public_key, 32);
zmq_z85_encode (z85_secret_key, secret_key, 32);

return 0;
#else // requires libsodium
errno = ENOTSUP;
return -1;
#endif
}
Loading

0 comments on commit b20573c

Please sign in to comment.