Added options for CURVE security

- ZMQ_CURVE_PUBLICKEY for clients and servers
- ZMQ_CURVE_SECRETKEY for clients
- ZMQ_CURVE_SERVERKEY for clients
- ZMQ_CURVE_SERVER for servers
- added tools/curve_keygen.c as example
- updated man pages
This commit is contained in:
Pieter Hintjens 2013-06-20 18:09:12 +02:00
parent 65c84abdb5
commit d9bb16725e
10 changed files with 222 additions and 40 deletions

2
.gitignore vendored
View File

@ -20,6 +20,8 @@ autom4te.cache
.*
*~
.*~
tools/curve_keygen.o
tools/curve_keygen
tests/test_term_endpoint
tests/test_monitor
tests/test_last_endpoint

View File

@ -187,10 +187,10 @@ The following security mechanisms are provided for IPC and TCP connections:
Null security::
linkzmq:zmq_null[7]
Clear-text authentication using username and password::
linkzmq:zmq_clear[7]
Plain-text authentication using username and password::
linkzmq:zmq_plain[7]
Secure authentication and encryption::
Elliptic curve authentication and encryption::
linkzmq:zmq_curve[7]

View File

@ -4,7 +4,7 @@ zmq_curve(7)
NAME
----
zmq_curve - clear-text authentication
zmq_curve - secure authentication and confidentiality
SYNOPSIS
@ -15,16 +15,41 @@ is intended for use on public networks. The CURVE mechanism is defined
by this document: <http://rfc.zeromq.org/spec:25>.
SERVER AND CLIENT ROLES
CLIENT AND SERVER ROLES
-----------------------
To use CURVE, the server shall set the ZMQ_CURVE_SERVER option, and the
client shall set the ZMQ_CURVE_PUBLICKEY and ZMQ_CURVE_SERVERKEY socket
options. Which peer binds, and which connects, is not relevant.
A socket using CURVE can be either client or server but not both. The role
is independent of bind/connect direction.
NOTE: this isn't implemented and not fully defined. The server keypair
needs to be persistent, and it would be sensible to define a format for
this as a CurveZMQ RFC.
To become a CURVE server, the application sets the ZMQ_CURVE_SERVER option
on the socket, and then sets the ZMQ_CURVE_SECRETKEY option to provide the
socket with its long-term secret key. The application does not provide the
socket with its long-term public key, which is used only by clients.
To become a CURVE client, the application sets the ZMQ_CURVE_SERVERKEY
option with the long-term public key of the server it intends to connect
to. A CURVE client can connect to (or accept connections from) at most
one CURVE server. The application then sets the ZMQ_CURVE_PUBLICKEY and
ZMQ_CURVE_SECRETKEY options with its client long-term key pair.
If the server does authentication it will be based on the client's long
term public key.
TEST KEY VALUES
---------------
For test cases, the client shall use this long-term key pair:
----
public: BB88471D65E2659B30C55A5321CEBB5AAB2B70A398645C26DCA2B2FCB43FC518
secret: 7BB864B489AFA3671FBE69101F94B38972F24816DFB01B51656B3FEC8DFD0888
----
And the server shall use this long-term key pair:
----
public: 54FCBA24E93249969316FB617C872BB0C1D1FF14800427C594CBFACF1BC2D652
secret: 8E0BDD697628B91D8F245587EE95C5B04D48963F79259877B49CD9063AEAD3B7
----
SEE ALSO
--------

View File

@ -528,7 +528,7 @@ ZMQ_PLAIN_SERVER: Set PLAIN server role
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Defines whether the socket will act as server for PLAIN security, see
linkzmq:zmq_plain[3]. A value of '1' means the socket will act as
linkzmq:zmq_plain[7]. A value of '1' means the socket will act as
PLAIN server. A value of '0' means the socket will not act as PLAIN
server, and its security role then depends on other option settings.
Setting this to '0' shall reset the socket security to NULL.
@ -537,7 +537,7 @@ Setting this to '0' shall reset the socket security to NULL.
Option value type:: int
Option value unit:: 0, 1
Default value:: 0
Applicable socket types:: all, when using TCP or IPC transports
Applicable socket types:: all, when using TCP transport
ZMQ_PLAIN_USERNAME: Set PLAIN security username
@ -545,14 +545,14 @@ ZMQ_PLAIN_USERNAME: Set PLAIN security username
Sets the username for outgoing connections over TCP or IPC. If you set this
to a non-null value, the security mechanism used for connections shall be
PLAIN, see linkzmq:zmq_plain[3]. If you set this to a null value, the security
PLAIN, see linkzmq:zmq_plain[7]. If you set this to a null value, the security
mechanism used for connections shall be NULL, see linkzmq:zmq_null[3].
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP or IPC transports
Applicable socket types:: all, when using TCP transport
ZMQ_PLAIN_PASSWORD: Set PLAIN security password
@ -567,7 +567,66 @@ mechanism used for connections shall be NULL, see linkzmq:zmq_null[3].
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP or IPC transports
Applicable socket types:: all, when using TCP transport
ZMQ_CURVE_SERVER: Set CURVE server role
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Defines whether the socket will act as server for CURVE security, see
linkzmq:zmq_curve[7]. A value of '1' means the socket will act as
CURVE server. A value of '0' means the socket will not act as CURVE
server, and its security role then depends on other option settings.
Setting this to '0' shall reset the socket security to NULL. When you
set this you must also set the ZMQ_CURVE_PUBLICKEY option.
[horizontal]
Option value type:: int
Option value unit:: 0, 1
Default value:: 0
Applicable socket types:: all, when using TCP transport
ZMQ_CURVE_PUBLICKEY: Set CURVE public key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the socket's long term public key. You must set this on a CURVE
client or server socket, see linkzmq:zmq_curve[7]. The key is 32 bytes.
For servers, it must be persisted and shared through some unspecified
secure mechanism to clients.
[horizontal]
Option value type:: binary data
Option value size:: 32
Default value:: NULL
Applicable socket types:: all, when using TCP transport
ZMQ_CURVE_SECRETKEY: Set CURVE secret key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the socket's long term secret key. You must set this on a CURVE
client socket, see linkzmq:zmq_curve[7]. The key is 32 bytes.
[horizontal]
Option value type:: binary data
Option value size:: 32
Default value:: NULL
Applicable socket types:: all, when using TCP transport
ZMQ_CURVE_SERVERKEY: Set CURVE server key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the socket's long term server key. You must set this on a CURVE
client socket, see linkzmq:zmq_curve[7]. The key is 32 bytes. This
key must be the same as the public key set on the server socket.
[horizontal]
Option value type:: binary data
Option value size:: 32
Default value:: NULL
Applicable socket types:: all, when using TCP transport
RETURN VALUE
@ -630,5 +689,3 @@ 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>.

View File

@ -255,7 +255,6 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
#define ZMQ_MULTICAST_HOPS 25
#define ZMQ_RCVTIMEO 27
#define ZMQ_SNDTIMEO 28
#define ZMQ_IPV4ONLY 31 /* Request replacement by IPV6 */
#define ZMQ_LAST_ENDPOINT 32
#define ZMQ_ROUTER_MANDATORY 33
#define ZMQ_TCP_KEEPALIVE 34
@ -273,8 +272,9 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
#define ZMQ_PLAIN_PASSWORD 46
#define ZMQ_CURVE_SERVER 47
#define ZMQ_CURVE_PUBLICKEY 48
#define ZMQ_CURVE_SERVERKEY 49
#define ZMQ_PROBE_ROUTER 50
#define ZMQ_CURVE_SECRETKEY 49
#define ZMQ_CURVE_SERVERKEY 50
#define ZMQ_PROBE_ROUTER 51
/* Message options */
#define ZMQ_MORE 1
@ -288,7 +288,8 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
#define ZMQ_PLAIN 1
#define ZMQ_CURVE 2
/* Deprecated aliases */
/* Deprecated options and aliases */
#define ZMQ_IPV4ONLY 31
#define ZMQ_DELAY_ATTACH_ON_CONNECT ZMQ_IMMEDIATE
#define ZMQ_NOBLOCK ZMQ_DONTWAIT
#define ZMQ_FAIL_UNROUTABLE ZMQ_ROUTER_MANDATORY

View File

@ -37,14 +37,9 @@ zmq::curve_client_t::curve_client_t (const options_t &options_) :
mechanism_t (options_),
state (send_hello)
{
zmq_assert (options_.public_key_size == crypto_box_PUBLICKEYBYTES);
memcpy (public_key, options_.public_key, crypto_box_PUBLICKEYBYTES);
zmq_assert (options_.secret_key_size == crypto_box_SECRETKEYBYTES);
memcpy (secret_key, options_.secret_key, crypto_box_SECRETKEYBYTES);
zmq_assert (options_.server_key_size == crypto_box_PUBLICKEYBYTES);
memcpy (server_key, options_.server_key, crypto_box_PUBLICKEYBYTES);
memcpy (public_key, options_.curve_public_key, crypto_box_PUBLICKEYBYTES);
memcpy (secret_key, options_.curve_secret_key, crypto_box_SECRETKEYBYTES);
memcpy (server_key, options_.curve_server_key, crypto_box_PUBLICKEYBYTES);
// Generate short-term key pair
const int rc = crypto_box_keypair (cn_public, cn_secret);

View File

@ -40,8 +40,7 @@ zmq::curve_server_t::curve_server_t (session_base_t *session_,
cn_nonce (1)
{
// Fetch our secret key from socket options
zmq_assert (options_.secret_key_size == crypto_box_SECRETKEYBYTES);
memcpy (secret_key, options_.secret_key, crypto_box_SECRETKEYBYTES);
memcpy (secret_key, options_.curve_secret_key, crypto_box_SECRETKEYBYTES);
// Generate short-term key pair
const int rc = crypto_box_keypair (cn_public, cn_secret);

View File

@ -285,6 +285,35 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
}
break;
case ZMQ_CURVE_SERVER:
if (is_int && (value == 0 || value == 1)) {
as_server = value;
mechanism = value? ZMQ_CURVE: ZMQ_NULL;
return 0;
}
break;
case ZMQ_CURVE_PUBLICKEY:
if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_public_key, optval_, CURVE_KEYSIZE);
return 0;
}
break;
case ZMQ_CURVE_SECRETKEY:
if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_secret_key, optval_, CURVE_KEYSIZE);
return 0;
}
break;
case ZMQ_CURVE_SERVERKEY:
if (optvallen_ == CURVE_KEYSIZE) {
memcpy (curve_server_key, optval_, CURVE_KEYSIZE);
return 0;
}
break;
default:
break;
}
@ -505,6 +534,34 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
return 0;
}
break;
case ZMQ_CURVE_SERVER:
if (is_int) {
*value = as_server && mechanism == ZMQ_CURVE;
return 0;
}
break;
case ZMQ_CURVE_PUBLICKEY:
if (*optvallen_ == CURVE_KEYSIZE) {
memcpy (optval_, curve_public_key, CURVE_KEYSIZE);
return 0;
}
break;
case ZMQ_CURVE_SECRETKEY:
if (*optvallen_ == CURVE_KEYSIZE) {
memcpy (optval_, curve_secret_key, CURVE_KEYSIZE);
return 0;
}
break;
case ZMQ_CURVE_SERVERKEY:
if (*optvallen_ == CURVE_KEYSIZE) {
memcpy (optval_, curve_server_key, CURVE_KEYSIZE);
return 0;
}
break;
}
errno = EINVAL;
return -1;

View File

@ -28,6 +28,8 @@
#include "tcp_address.hpp"
#include "../include/zmq.h"
#define CURVE_KEYSIZE 32
namespace zmq
{
struct options_t
@ -125,6 +127,7 @@ namespace zmq
// Security mechanism for all connections on this socket
int mechanism;
// If peer is acting as server for PLAIN or CURVE mechanisms
int as_server;
@ -132,14 +135,10 @@ namespace zmq
std::string plain_username;
std::string plain_password;
unsigned char public_key_size;
unsigned char public_key [32];
unsigned char secret_key_size;
unsigned char secret_key [32];
unsigned char server_key_size;
unsigned char server_key [32];
// Security credentials for CURVE mechanism
uint8_t curve_public_key [CURVE_KEYSIZE];
uint8_t curve_secret_key [CURVE_KEYSIZE];
uint8_t curve_server_key [CURVE_KEYSIZE];
// ID of the socket.
int socket_id;

47
tools/curve_keygen.c Normal file
View File

@ -0,0 +1,47 @@
/*
Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
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/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sodium.h>
int main (void)
{
# 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);
assert (rc == 0);
int byte_nbr;
printf ("public: ");
for (byte_nbr = 0; byte_nbr < 32; byte_nbr++)
printf ("%02X", public_key [byte_nbr]);
printf ("\n");
printf ("secret: ");
for (byte_nbr = 0; byte_nbr < 32; byte_nbr++)
printf ("%02X", secret_key [byte_nbr]);
printf ("\n");
exit (0);
}