Add libnss security support to corosync.

git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@2145 fd59a12c-fef9-0310-b244-a6a79926bd2f
This commit is contained in:
Christine Caulfield 2009-04-25 14:05:27 +00:00
parent bc7939d8de
commit e9660ee62f
22 changed files with 860 additions and 32 deletions

View File

@ -61,24 +61,30 @@ encrypt_and_sign to prepare the message to be sent. When the executive
wants to receive a message from the network, it uses
authenticate_and_decrypt to verify the message is valid and decrypt it.
These two functions utilize the following algorithms:
There are currently two encryption methods available in corosync.
sha1/hmac/sober which are coded internally, and AES/SHA256 which
are in the Mozilla Network Security Services (libnss) library.
The internal functions utilize the following algorithms:
sha1 - hash algorithm secure for using with hmac
hmac - produces a 16 byte digest from any length input
sober - pseudo random number generator and stream cipher
The hmac algorithm requires a 16 byte key.
The sober algorithm requires a 16 byte private key.
The sober algorithm requires a 16 byte public initial vector.
The private key is read from disk and stored in memory for use with the
sober algorithm to generate the three required keys.
Every message starts with a
struct security {
unsigned char digest[20]; A one way hash digest
unsigned char salt[16]; A securely generated random number
}
INTERNAL SECURITY CODE:
-----------------------
The hmac algorithm requires a 16 byte key.
The sober algorithm requires a 16 byte private key.
The sober algorithm requires a 16 byte public initial vector.
The private key is read from disk and stored in memory for use with the
sober algorithm to generate the three required keys.
When a message is sent (encrypt_and_sign):
------------------------------------------
1. sober is used to create a 16 byte random number (salt) using the md4
@ -123,4 +129,59 @@ is randomly unique (within the 2^128 search space of the input to sober) to
ensure that keys are never reused, nonce's are never reused, and hmac's are
never reused.
USING LIBNSS
------------
The process is similar in concept to the above, but most of the details are
hidden inside the NSS library. When corosync is started up libnss is initialised,
the private key is read into memory and stored for later use by the code.
When a message is sent (encrypt_and_sign):
------------------------------------------
- The message is encrypted using AES.
- A digest of that message is then created using SHA256 and based on the
private key.
- the message is then transmitted.
When a message is received (decrypt_and_authenticate):
- A Digest of the encrypted message is created using the private key
- That digest is compared to the one in the message security_header
- If they do not match the packet is rejected
- If they do match then the message is decrypted using the private key.
- The message is processed.
Compatibility
-------------
The default mode of operation is to allow for wire-compatibility with existing
openais systems. That means that the internal encryption system is used
and all received packets are expected to use that system. This allows a rolling
upgrade from openais to corosync.
Once all nodes in the cluster are running corosync they can be changed to allow
the newer libnss-based encryption by setting the
totem {
crypto_accept: new
}
option in corosync.conf.
This enables the new encryption system but does not switch it on. It simply
adds a byte to the end of the packets to indicate the encryption type.
Once all nodes have been upgraded and 'crypto_accept: new' has been set,
the encryption type can be set using a single command:
# corosync-cfgtool -c1
This will tell all cluster nodes to start using libnss encryption. Note that
it is possible to upgrade node individially by seetting the encryption type in
corosync.conf. The last byte of the packet indicates the decryption algorithm
that the receiver should use.
Once all nodes are using libnss encryption, the option should be set in
in corosync.conf so that it takes effect at the next system reboot.
Comments welcome mailto:corosync@lists.osdl.org

View File

@ -51,6 +51,7 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_RANLIB
AC_CHECK_PROGS([GROFF], [groff])
AC_CHECK_PROGS([PKGCONFIG], [pkg-config])
# Checks for libraries.
AC_CHECK_LIB([dl], [dlopen])
@ -176,6 +177,10 @@ AC_ARG_ENABLE([coverage],
[ --enable-coverage : coverage analysis of the codebase. ],
[ default="no" ])
AC_ARG_ENABLE([nss],
[ --enable-nss : Network Security Services encryption. ],
[ default="yes" ])
AC_ARG_WITH([lcrso-dir],
[ --with-lcrso-dir=DIR : corosync lcrso files. ],
[ LCRSODIR="$withval" ],
@ -257,6 +262,16 @@ else
GDB_FLAGS="-g"
fi
# Look for libnss
if test "x${enable_nss}" = xyes; then
if $PKGCONFIG --exists nss; then
NSS_CFLAGS="`$PKGCONFIG --cflags nss`"
NSS_LDFLAGS="`$PKGCONFIG --libs nss`"
AC_DEFINE_UNQUOTED([HAVE_LIBNSS], 1, [have libnss])
PKG_FEATURES="$PKG_FEATURES nss"
fi
fi
# extra warnings
EXTRA_WARNINGS=""
@ -320,7 +335,7 @@ fi
# final build of *FLAGS
CFLAGS="$ENV_CFLAGS $OPT_CFLAGS $GDB_FLAGS $OS_CFLAGS \
$COVERAGE_CFLAGS $EXTRA_WARNINGS $WERROR_CFLAGS"
$COVERAGE_CFLAGS $EXTRA_WARNINGS $WERROR_CFLAGS $NSS_CFLAGS"
CPPFLAGS="$ENV_CPPFLAGS $ANSI_CPPFLAGS $OS_CPPFLAGS"
LDFLAGS="$ENV_LDFLAGS $COVERAGE_LDFLAGS $OS_LDFLAGS"
@ -335,6 +350,8 @@ AC_SUBST([SONAME])
AC_SUBST([OS_DYFLAGS])
AC_SUBST([NSS_LDFLAGS])
AM_CONDITIONAL(BUILD_DARWIN, test -n "${DARWIN_OPTS}")
AC_SUBST([DARWIN_OPTS])

View File

@ -94,7 +94,7 @@ else
libtotem_pg.so.$(SONAME): $(TOTEM_OBJS)
$(CC) -shared -o $@ \
-Wl,-soname=libtotem_pg.so.$(SOMAJOR) \
$^ $(LDFLAGS) -lpthread
$^ $(LDFLAGS) $(NSS_LDFLAGS) -lpthread
ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so
ln -sf libtotem_pg.so.$(SONAME) libtotem_pg.so.$(SOMAJOR)

View File

@ -116,6 +116,7 @@ static struct corosync_api_v1 apidef_corosync_api_v1 = {
.totem_ifaces_get = totempg_ifaces_get,
.totem_ifaces_print = totempg_ifaces_print,
.totem_ip_print = totemip_print,
.totem_crypto_set = totempg_crypto_set,
.totem_callback_token_create = totempg_callback_token_create,
.tpg_init = totempg_groups_initialize,
.tpg_exit = NULL, /* missing from totempg api */

View File

@ -56,6 +56,13 @@
#include <corosync/engine/config.h>
#include <corosync/engine/logsys.h>
#ifdef HAVE_LIBNSS
#include <nss.h>
#include <pk11pub.h>
#include <pkcs11.h>
#include <prerror.h>
#endif
#include "util.h"
#include "totemconfig.h"
#include "tlist.h" /* for HZ */
@ -218,6 +225,46 @@ static void totem_volatile_config_read (
}
static void totem_get_crypto_type(
const struct objdb_iface_ver0 *objdb,
hdb_handle_t object_totem_handle,
struct totem_config *totem_config)
{
const char *str;
totem_config->crypto_accept = TOTEM_CRYPTO_ACCEPT_OLD;
if (!objdb_get_string (objdb, object_totem_handle, "crypto_accept", &str)) {
if (strcmp(str, "new") == 0) {
totem_config->crypto_accept = TOTEM_CRYPTO_ACCEPT_NEW;
}
}
totem_config->crypto_type = TOTEM_CRYPTO_SOBER;
#ifdef HAVE_LIBNSS
/*
* We must set these even if the key does not exist.
* Encryption type can be set on-the-fly using CFG
*/
totem_config->crypto_crypt_type = CKM_AES_CBC_PAD;
totem_config->crypto_sign_type = CKM_SHA256_RSA_PKCS;
#endif
if (!objdb_get_string (objdb, object_totem_handle, "crypto_type", &str)) {
if (strcmp(str, "sober") == 0) {
return;
}
#ifdef HAVE_LIBNSS
if (strcmp(str, "nss") == 0) {
totem_config->crypto_type = TOTEM_CRYPTO_NSS;
}
#endif
}
}
extern int totem_config_read (
struct objdb_iface_ver0 *objdb,
struct totem_config *totem_config,
@ -263,6 +310,11 @@ printf ("couldn't find totem handle\n");
totem_config->secauth = 0;
}
}
if (totem_config->secauth == 1) {
totem_get_crypto_type(objdb, object_totem_handle, totem_config);
}
if (!objdb_get_string (objdb, object_totem_handle, "rrp_mode", &str)) {
strcpy (totem_config->rrp_mode, str);
}

View File

@ -210,6 +210,13 @@ int totemmrp_ifaces_get (
return (res);
}
int totemmrp_crypto_set (
unsigned int type)
{
return totemsrp_crypto_set (totemsrp_handle_in,
type);
}
unsigned int totemmrp_my_nodeid_get (void)
{
return (totemsrp_my_nodeid_get (totemsrp_handle_in));

View File

@ -108,6 +108,8 @@ extern unsigned int totemmrp_my_nodeid_get (void);
extern int totemmrp_my_family_get (void);
extern int totemmrp_crypto_set (unsigned int);
extern int totemmrp_ring_reenable (void);
#endif /* TOTEMMRP_H_DEFINED */

View File

@ -69,8 +69,14 @@
#include "crypto.h"
#define MCAST_SOCKET_BUFFER_SIZE (TRANSMITS_ALLOWED * FRAME_SIZE_MAX)
#ifdef HAVE_LIBNSS
#include <nss.h>
#include <pk11pub.h>
#include <pkcs11.h>
#include <prerror.h>
#endif
#define MCAST_SOCKET_BUFFER_SIZE (TRANSMITS_ALLOWED * FRAME_SIZE_MAX)
#define NETIF_STATE_REPORT_UP 1
#define NETIF_STATE_REPORT_DOWN 2
@ -101,6 +107,12 @@ struct totemnet_instance {
prng_state totemnet_prng_state;
#ifdef HAVE_LIBNSS
SECItem *nss_sec_param;
PK11SymKey *nss_sym_key;
unsigned char nss_iv_data[16];
#endif
unsigned char totemnet_private_key[1024];
unsigned int totemnet_private_key_len;
@ -234,9 +246,11 @@ do { \
level, (const char *)format, ##args); \
} while (0);
static int authenticate_and_decrypt (
static int authenticate_and_decrypt_sober (
struct totemnet_instance *instance,
struct iovec *iov)
struct iovec *iov,
unsigned int iov_len)
{
unsigned char keys[48];
struct security_header *header = iov[0].iov_base;
@ -280,7 +294,6 @@ static int authenticate_and_decrypt (
hmac_done (&instance->totemnet_hmac_state, digest_comparison, &len);
if (memcmp (digest_comparison, header->hash_digest, len) != 0) {
log_printf (instance->totemnet_log_level_security, "Received message has invalid digest... ignoring.\n");
return (-1);
}
@ -294,13 +307,333 @@ static int authenticate_and_decrypt (
return (0);
}
static void encrypt_and_sign_worker (
static void init_sober_crypto(
struct totemnet_instance *instance)
{
log_printf(instance->totemnet_log_level_notice, "Initialising SOBER128 crypto\n");
rng_make_prng (128, PRNG_SOBER, &instance->totemnet_prng_state, NULL);
}
#ifdef HAVE_LIBNSS
static unsigned char *copy_from_iovec(
const struct iovec *iov,
unsigned int iov_len,
size_t *buf_size)
{
int i;
size_t bufptr;
size_t buflen = 0;
unsigned char *newbuf;
for (i=0; i<iov_len; i++)
buflen += iov[i].iov_len;
newbuf = malloc(buflen);
if (!newbuf)
return NULL;
bufptr=0;
for (i=0; i<iov_len; i++) {
memcpy(newbuf+bufptr, iov[i].iov_base, iov[i].iov_len);
bufptr += iov[i].iov_len;
}
*buf_size = buflen;
return newbuf;
}
static void copy_to_iovec(
struct iovec *iov,
unsigned int iov_len,
const unsigned char *buf,
size_t buf_size)
{
int i;
size_t copylen;
size_t bufptr = 0;
bufptr=0;
for (i=0; i<iov_len; i++) {
copylen = iov[i].iov_len;
if (bufptr + copylen > buf_size) {
copylen = buf_size - bufptr;
}
memcpy(iov[i].iov_base, buf+bufptr, copylen);
bufptr += copylen;
if (iov[i].iov_len != copylen) {
iov[i].iov_len = copylen;
return;
}
}
}
static void init_nss_crypto(
struct totemnet_instance *instance)
{
PK11SlotInfo* slot = NULL;
SECItem key_item, iv_item;
SECStatus rv;
log_printf(instance->totemnet_log_level_notice, "Initialising NSS crypto\n");
rv = NSS_NoDB_Init(".");
if (rv != SECSuccess)
{
log_printf(instance->totemnet_log_level_security, "NSS initialization failed (err %d)\n",
PR_GetError());
goto out;
}
slot = PK11_GetBestSlot(instance->totem_config->crypto_crypt_type, NULL);
if (slot == NULL)
{
log_printf(instance->totemnet_log_level_security, "Unable to find security slot (err %d)\n",
PR_GetError());
goto out;
}
/*
* Make the private key into a SymKey that we can use
*/
key_item.type = siBuffer;
key_item.data = instance->totem_config->private_key;
key_item.len = 32; /* Use 128 bits */
instance->nss_sym_key = PK11_ImportSymKey(slot, instance->totem_config->crypto_crypt_type,
PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT|CKA_SIGN,
&key_item, NULL);
if (instance->nss_sym_key == NULL)
{
log_printf(instance->totemnet_log_level_security, "Failure to import key into NSS (err %d)\n",
PR_GetError());
goto out;
}
/* set up the PKCS11 encryption paramters.
* when not using CBC mode, iv_item.data and iv_item.len can be 0, or you
* can simply pass NULL for the iv parameter in PK11_ParamFromIV func
*/
rng_get_bytes(instance->nss_iv_data, sizeof(instance->nss_iv_data), NULL);
iv_item.type = siBuffer;
iv_item.data = instance->nss_iv_data;
iv_item.len = sizeof(instance->nss_iv_data);
instance->nss_sec_param = PK11_ParamFromIV(instance->totem_config->crypto_crypt_type, &iv_item);
if (instance->nss_sec_param == NULL)
{
log_printf(instance->totemnet_log_level_security, "Failure to set up PKCS11 param (err %d)\n",
PR_GetError());
goto out;
}
out:
return;
}
static int encrypt_and_sign_nss (
struct totemnet_instance *instance,
unsigned char *buf,
size_t *buf_len,
const struct iovec *iovec,
size_t iov_len,
prng_state *prng_state_in)
unsigned int iov_len)
{
PK11Context* enc_context = NULL;
SECStatus rv1, rv2;
int tmp1_outlen;
unsigned int tmp2_outlen;
unsigned char *inbuf;
unsigned char *data;
unsigned char *outdata;
size_t datalen;
SECItem no_params;
struct security_header *header;
no_params.type = siBuffer;
no_params.data = 0;
no_params.len = 0;
tmp1_outlen = tmp2_outlen = 0;
inbuf = copy_from_iovec(iovec, iov_len, &datalen);
if (!inbuf) {
log_printf(instance->totemnet_log_level_security, "malloc error copying buffer from iovec\n");
return -1;
}
data = inbuf + sizeof (struct security_header);
datalen -= sizeof (struct security_header);
outdata = buf + sizeof (struct security_header);
header = (struct security_header *)buf;
/*
* Create cipher context for encryption
*/
enc_context = PK11_CreateContextBySymKey(instance->totem_config->crypto_crypt_type, CKA_ENCRYPT,
instance->nss_sym_key, instance->nss_sec_param);
if (!enc_context) {
char err[1024];
PR_GetErrorText(err);
err[PR_GetErrorTextLength()] = 0;
log_printf(instance->totemnet_log_level_security, "PK11_CreateContext failed (encrypt) crypt_type=%d (err %d): %s\n",
instance->totem_config->crypto_crypt_type,
PR_GetError(), err);
return -1;
}
rv1 = PK11_CipherOp(enc_context, outdata,
&tmp1_outlen, FRAME_SIZE_MAX - sizeof(struct security_header),
data, datalen);
rv2 = PK11_DigestFinal(enc_context, outdata + tmp1_outlen, &tmp2_outlen,
FRAME_SIZE_MAX - tmp1_outlen);
PK11_DestroyContext(enc_context, PR_TRUE);
*buf_len = tmp1_outlen + tmp2_outlen;
free(inbuf);
if (rv1 != SECSuccess || rv2 != SECSuccess)
goto out;
/* Now do the digest */
enc_context = PK11_CreateContextBySymKey(CKM_MD5, CKA_DIGEST, instance->nss_sym_key, &no_params);
if (!enc_context) {
char err[1024];
PR_GetErrorText(err);
err[PR_GetErrorTextLength()] = 0;
log_printf(instance->totemnet_log_level_security, "encrypt: PK11_CreateContext failed (digest) err %d: %s\n",
PR_GetError(), err);
return -1;
}
PK11_DigestBegin(enc_context);
rv1 = PK11_DigestOp(enc_context, outdata, *buf_len);
rv2 = PK11_DigestFinal(enc_context, header->hash_digest, &tmp2_outlen, sizeof(header->hash_digest));
PK11_DestroyContext(enc_context, PR_TRUE);
if (rv1 != SECSuccess || rv2 != SECSuccess)
goto out;
memcpy(header->salt, instance->nss_iv_data, sizeof(instance->nss_iv_data));
*buf_len += sizeof(struct security_header);
return 0;
out:
return -1;
}
static int authenticate_and_decrypt_nss (
struct totemnet_instance *instance,
struct iovec *iov,
unsigned int iov_len)
{
PK11Context* enc_context = NULL;
SECStatus rv1, rv2;
int tmp1_outlen;
unsigned int tmp2_outlen;
unsigned char outbuf[FRAME_SIZE_MAX];
unsigned char digest[HMAC_HASH_SIZE];
unsigned char *outdata;
int result_len;
unsigned char *data;
unsigned char *inbuf;
size_t datalen;
struct security_header *header = iov[0].iov_base;
SECItem no_params;
SECItem ivdata;
no_params.type = siBuffer;
no_params.data = 0;
no_params.len = 0;
tmp1_outlen = tmp2_outlen = 0;
if (iov_len > 1) {
inbuf = copy_from_iovec(iov, iov_len, &datalen);
if (!inbuf) {
log_printf(instance->totemnet_log_level_security, "malloc error copying buffer from iovec\n");
return -1;
}
}
else {
inbuf = iov[0].iov_base;
datalen = iov[0].iov_len;
}
data = inbuf + sizeof (struct security_header);
datalen -= sizeof (struct security_header);
outdata = outbuf + sizeof (struct security_header);
/* Check the digest */
enc_context = PK11_CreateContextBySymKey(CKM_MD5, CKA_DIGEST, instance->nss_sym_key, &no_params);
if (!enc_context) {
char err[1024];
PR_GetErrorText(err);
err[PR_GetErrorTextLength()] = 0;
log_printf(instance->totemnet_log_level_security, "PK11_CreateContext failed (check digest) err %d: %s\n",
PR_GetError(), err);
return -1;
}
PK11_DigestBegin(enc_context);
rv1 = PK11_DigestOp(enc_context, data, datalen);
rv2 = PK11_DigestFinal(enc_context, digest, &tmp2_outlen, sizeof(digest));
PK11_DestroyContext(enc_context, PR_TRUE);
if (rv1 != SECSuccess || rv2 != SECSuccess) {
log_printf(instance->totemnet_log_level_security, "Digest check failed\n");
return -1;
}
if (memcmp(digest, header->hash_digest, tmp2_outlen) != 0) {
log_printf(instance->totemnet_log_level_error, "Digest does not match\n");
return -1;
}
/* Create cipher context for decryption */
ivdata.type = siBuffer;
ivdata.data = header->salt;
ivdata.len = sizeof(header->salt);
enc_context = PK11_CreateContextBySymKey(instance->totem_config->crypto_crypt_type, CKA_DECRYPT,
instance->nss_sym_key, &ivdata);
if (!enc_context) {
log_printf(instance->totemnet_log_level_security, "PK11_CreateContext (decrypt) failed (err %d)\n",
PR_GetError());
return -1;
}
rv1 = PK11_CipherOp(enc_context, outdata, &tmp1_outlen,
sizeof(outbuf) - sizeof (struct security_header),
data, datalen);
if (rv1 != SECSuccess) {
log_printf(instance->totemnet_log_level_security, "PK11_CipherOp (decrypt) failed (err %d)\n",
PR_GetError());
}
rv2 = PK11_DigestFinal(enc_context, outdata + tmp1_outlen, &tmp2_outlen,
sizeof(outbuf) - tmp1_outlen);
PK11_DestroyContext(enc_context, PR_TRUE);
result_len = tmp1_outlen + tmp2_outlen + sizeof (struct security_header);
/* Copy it back to the buffer */
copy_to_iovec(iov, iov_len, outbuf, result_len);
if (iov_len > 1)
free(inbuf);
if (rv1 != SECSuccess || rv2 != SECSuccess)
return -1;
return 0;
}
#endif
static int encrypt_and_sign_sober (
struct totemnet_instance *instance,
unsigned char *buf,
size_t *buf_len,
const struct iovec *iovec,
unsigned int iov_len)
{
int i;
unsigned char *addr;
@ -314,6 +647,7 @@ static void encrypt_and_sign_worker (
hmac_state hmac_st;
prng_state keygen_prng_state;
prng_state stream_prng_state;
prng_state *prng_state_in = &instance->totemnet_prng_state;
header = (struct security_header *)buf;
addr = buf + sizeof (struct security_header);
@ -374,8 +708,124 @@ static void encrypt_and_sign_worker (
hmac_done (&hmac_st, header->hash_digest, &len);
*buf_len = outlen;
return 0;
}
static int encrypt_and_sign_worker (
struct totemnet_instance *instance,
unsigned char *buf,
size_t *buf_len,
const struct iovec *iovec,
unsigned int iov_len)
{
if (instance->totem_config->crypto_type == TOTEM_CRYPTO_SOBER ||
instance->totem_config->crypto_accept == TOTEM_CRYPTO_ACCEPT_OLD)
return encrypt_and_sign_sober(instance, buf, buf_len, iovec, iov_len);
#ifdef HAVE_LIBNSS
if (instance->totem_config->crypto_type == TOTEM_CRYPTO_NSS)
return encrypt_and_sign_nss(instance, buf, buf_len, iovec, iov_len);
#endif
return -1;
}
static int authenticate_and_decrypt (
struct totemnet_instance *instance,
struct iovec *iov,
unsigned int iov_len)
{
unsigned char type;
unsigned char *endbuf = iov[iov_len-1].iov_base;
int res = -1;
/*
* Get the encryption type and remove it from the buffer
*/
type = endbuf[iov[iov_len-1].iov_len-1];
iov[iov_len-1].iov_len -= 1;
if (type == TOTEM_CRYPTO_SOBER)
res = authenticate_and_decrypt_sober(instance, iov, iov_len);
/*
* Only try higher crypto options if NEW has been requested
*/
if (instance->totem_config->crypto_accept == TOTEM_CRYPTO_ACCEPT_NEW) {
#ifdef HAVE_LIBNSS
if (type == TOTEM_CRYPTO_NSS)
res = authenticate_and_decrypt_nss(instance, iov, iov_len);
#endif
}
/*
* If it failed, then try decrypting the whole packet as it might be
* from aisexec
*/
if (res == -1) {
iov[iov_len-1].iov_len += 1;
res = authenticate_and_decrypt_sober(instance, iov, iov_len);
}
return res;
}
static void init_crypto(
struct totemnet_instance *instance)
{
/*
* If we are expecting NEW crypto type then initialise all available
* crypto options. For OLD then we only need SOBER128.
*/
init_sober_crypto(instance);
if (instance->totem_config->crypto_accept == TOTEM_CRYPTO_ACCEPT_OLD)
return;
#ifdef HAVE_LIBNSS
init_nss_crypto(instance);
#endif
}
int totemnet_crypto_set (hdb_handle_t handle,
unsigned int type)
{
struct totemnet_instance *instance;
int res = 0;
res = hdb_handle_get (&totemnet_instance_database, handle,
(void *)&instance);
if (res != 0) {
res = ENOENT;
goto error_exit;
}
/*
* Can't set crypto type if OLD is selected
*/
if (instance->totem_config->crypto_accept == TOTEM_CRYPTO_ACCEPT_OLD) {
res = -1;
}
else {
/*
* Validate number
*/
if (type == TOTEM_CRYPTO_SOBER ||
type == TOTEM_CRYPTO_NSS) {
instance->totem_config->crypto_type = type;
log_printf(instance->totemnet_log_level_security, "Encryption type set to %d\n", type);
}
else {
res = -1;
}
}
hdb_handle_put (&totemnet_instance_database, handle);
error_exit:
return res;
}
static inline void ucast_sendmsg (
struct totemnet_instance *instance,
struct totem_ip_address *system_to,
@ -408,8 +858,14 @@ static inline void ucast_sendmsg (
encrypt_data,
&buf_len,
iovec_encrypt,
iov_len_in + 1,
&instance->totemnet_prng_state);
iov_len_in + 1);
if (instance->totem_config->crypto_accept == TOTEM_CRYPTO_ACCEPT_NEW) {
encrypt_data[buf_len++] = instance->totem_config->crypto_type;
}
else {
encrypt_data[buf_len++] = 0;
}
iovec_encrypt[0].iov_base = encrypt_data;
iovec_encrypt[0].iov_len = buf_len;
@ -472,8 +928,14 @@ static inline void mcast_sendmsg (
encrypt_data,
&buf_len,
iovec_encrypt,
iov_len_in + 1,
&instance->totemnet_prng_state);
iov_len_in + 1);
if (instance->totem_config->crypto_accept == TOTEM_CRYPTO_ACCEPT_NEW) {
encrypt_data[buf_len++] = instance->totem_config->crypto_type;
}
else {
encrypt_data[buf_len++] = 0;
}
iovec_encrypt[0].iov_base = encrypt_data;
iovec_encrypt[0].iov_len = buf_len;
@ -546,8 +1008,7 @@ static void totemnet_mcast_worker_fn (void *thread_state, void *work_item_in)
encrypt_and_sign_worker (
instance,
totemnet_mcast_thread_state->iobuf, &buf_len,
work_item->iovec, work_item->iov_len + 1,
&totemnet_mcast_thread_state->prng_state);
work_item->iovec, work_item->iov_len + 1);
iovec_sendmsg = &iovec_encrypted;
iovec_sendmsg->iov_base = totemnet_mcast_thread_state->iobuf;
@ -660,8 +1121,9 @@ static int net_deliver_fn (
* Authenticate and if authenticated, decrypt datagram
*/
res = authenticate_and_decrypt (instance, iovec);
res = authenticate_and_decrypt (instance, iovec, 1);
if (res == -1) {
log_printf (instance->totemnet_log_level_security, "Received message has invalid digest... ignoring.\n");
log_printf (instance->totemnet_log_level_security,
"Invalid packet data\n");
iovec->iov_len = FRAME_SIZE_MAX;
@ -698,7 +1160,7 @@ static int netif_determine (
res = totemip_iface_check (bindnet, bound_to,
interface_up, interface_num,
+ 0); // TODO andrew can address this instance->totem_config->clear_node_high_bit);
0); // TODO andrew can address this instance->totem_config->clear_node_high_bit);
return (res);
@ -1200,7 +1662,7 @@ int totemnet_initialize (
instance->totemnet_private_key_len = totem_config->private_key_len;
rng_make_prng (128, PRNG_SOBER, &instance->totemnet_prng_state, NULL);
init_crypto(instance);
/*
* Initialize local variables for totemnet
@ -1233,8 +1695,6 @@ int totemnet_initialize (
instance->handle = *handle;
rng_make_prng (128, PRNG_SOBER, &instance->totemnet_prng_state, NULL);
totemip_localhost (instance->mcast_address.family, &localhost);
netif_down_check (instance);

View File

@ -105,4 +105,8 @@ extern int totemnet_token_target_set (
hdb_handle_t handle,
const struct totem_ip_address *token_target);
extern int totemnet_crypto_set (
hdb_handle_t handle,
unsigned int type);
#endif /* TOTEMNET_H_DEFINED */

View File

@ -1293,6 +1293,17 @@ int totempg_ifaces_get (
return (res);
}
int totempg_crypto_set (
unsigned int type)
{
int res;
res = totemmrp_crypto_set (
type);
return (res);
}
int totempg_ring_reenable (void)
{
int res;

View File

@ -1710,6 +1710,26 @@ error_exit:
return (res);
}
int totemrrp_crypto_set (
hdb_handle_t handle,
unsigned int type)
{
int res;
struct totemrrp_instance *instance;
res = hdb_handle_get (&totemrrp_instance_database, handle,
(void *)&instance);
if (res != 0) {
return (0);
}
res = totemnet_crypto_set(instance->net_handles[0], type);
hdb_handle_put (&totemrrp_instance_database, handle);
return (res);
}
int totemrrp_ring_reenable (
hdb_handle_t handle)
{

View File

@ -112,6 +112,10 @@ extern int totemrrp_ifaces_get (
char ***status,
unsigned int *iface_count);
extern int totemrrp_crypto_set (
hdb_handle_t handle,
unsigned int type);
extern int totemrrp_ring_reenable (
hdb_handle_t handle);

View File

@ -79,6 +79,7 @@
#include <corosync/totem/coropoll.h>
#include "totemsrp.h"
#include "totemrrp.h"
#include "totemnet.h"
#include "wthread.h"
#include "crypto.h"
@ -942,6 +943,26 @@ error_exit:
return (res);
}
int totemsrp_crypto_set (
hdb_handle_t handle,
unsigned int type)
{
int res;
struct totemsrp_instance *instance;
res = hdb_handle_get (&totemsrp_instance_database, handle,
(void *)&instance);
if (res != 0) {
return (0);
}
res = totemrrp_crypto_set(instance->totemrrp_handle, type);
hdb_handle_put (&totemsrp_instance_database, handle);
return (res);
}
unsigned int totemsrp_my_nodeid_get (
hdb_handle_t handle)
{

View File

@ -108,6 +108,10 @@ extern unsigned int totemsrp_my_nodeid_get (
extern int totemsrp_my_family_get (
hdb_handle_t handle);
extern int totemsrp_crypto_set (
hdb_handle_t handle,
unsigned int type);
extern int totemsrp_ring_reenable (
hdb_handle_t handle);

View File

@ -228,6 +228,11 @@ corosync_cfg_local_get (
corosync_cfg_handle_t handle,
unsigned int *local_nodeid);
cs_error_t
corosync_cfg_crypto_set (
corosync_cfg_handle_t handle,
unsigned int type);
#ifdef __cplusplus
}
#endif

View File

@ -443,6 +443,7 @@ struct corosync_api_v1 {
const char *(*totem_ip_print) (const struct totem_ip_address *addr);
int (*totem_crypto_set) (unsigned int type);
int (*totem_callback_token_create) (
void **handle_out,

View File

@ -52,7 +52,8 @@ enum req_lib_cfg_types {
MESSAGE_REQ_CFG_TRYSHUTDOWN = 9,
MESSAGE_REQ_CFG_REPLYTOSHUTDOWN = 10,
MESSAGE_REQ_CFG_GET_NODE_ADDRS = 11,
MESSAGE_REQ_CFG_LOCAL_GET = 12
MESSAGE_REQ_CFG_LOCAL_GET = 12,
MESSAGE_REQ_CFG_CRYPTO_SET = 13
};
enum res_lib_cfg_types {
@ -69,7 +70,8 @@ enum res_lib_cfg_types {
MESSAGE_RES_CFG_TESTSHUTDOWN = 10,
MESSAGE_RES_CFG_GET_NODE_ADDRS = 11,
MESSAGE_RES_CFG_LOCAL_GET = 12,
MESSAGE_RES_CFG_REPLYTOSHUTDOWN = 13
MESSAGE_RES_CFG_REPLYTOSHUTDOWN = 13,
MESSAGE_RES_CFG_CRYPTO_SET = 14,
};
struct req_lib_cfg_statetrack {
@ -205,6 +207,15 @@ struct res_lib_cfg_local_get {
mar_uint32_t local_nodeid __attribute__((aligned(8)));
};
struct req_lib_cfg_crypto_set {
coroipc_response_header_t header __attribute__((aligned(8)));
mar_uint32_t type __attribute__((aligned(8)));
};
struct res_lib_cfg_crypto_set {
coroipc_response_header_t header __attribute__((aligned(8)));
};
typedef enum {
AIS_AMF_ADMINISTRATIVETARGET_SERVICEUNIT = 0,
AIS_AMF_ADMINISTRATIVETARGET_SERVICEGROUP = 1,

View File

@ -145,6 +145,12 @@ struct totem_config {
unsigned int max_messages;
const char *vsf_type;
enum { TOTEM_CRYPTO_SOBER=0, TOTEM_CRYPTO_NSS } crypto_type;
enum { TOTEM_CRYPTO_ACCEPT_OLD=0, TOTEM_CRYPTO_ACCEPT_NEW } crypto_accept;
int crypto_crypt_type;
int crypto_sign_type;
};
#define TOTEM_CONFIGURATION_TYPE

View File

@ -145,6 +145,8 @@ extern unsigned int totempg_my_nodeid_get (void);
extern int totempg_my_family_get (void);
extern int totempg_crypto_set (unsigned int type);
extern int totempg_ring_reenable (void);
#endif /* TOTEMPG_H_DEFINED */

View File

@ -822,3 +822,44 @@ error_exit:
return (error);
}
cs_error_t
corosync_cfg_crypto_set (
corosync_cfg_handle_t handle,
unsigned int type)
{
struct cfg_instance *cfg_instance;
struct req_lib_cfg_crypto_set req_lib_cfg_crypto_set;
struct res_lib_cfg_crypto_set res_lib_cfg_crypto_set;
struct iovec iov;
cs_error_t error;
error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_instance));
if (error != CS_OK) {
return (error);
}
req_lib_cfg_crypto_set.header.id = MESSAGE_REQ_CFG_CRYPTO_SET;
req_lib_cfg_crypto_set.header.size = sizeof (struct req_lib_cfg_crypto_set);
req_lib_cfg_crypto_set.type = type;
iov.iov_base = &req_lib_cfg_crypto_set;
iov.iov_len = sizeof (struct req_lib_cfg_crypto_set);
pthread_mutex_lock (&cfg_instance->response_mutex);
error = coroipcc_msg_send_reply_receive (cfg_instance->ipc_ctx,
&iov,
1,
&res_lib_cfg_crypto_set,
sizeof (struct res_lib_cfg_crypto_set));
pthread_mutex_unlock (&cfg_instance->response_mutex);
if (error == CS_OK)
error = res_lib_cfg_crypto_set.header.error;
(void)hdb_handle_put (&cfg_hdb, handle);
return (error);
}

View File

@ -57,6 +57,7 @@
#include <corosync/queue.h>
#include <corosync/mar_gen.h>
#include <corosync/totem/totemip.h>
#include <corosync/totem/totem.h>
#include <corosync/ipc_cfg.h>
#include <corosync/lcr/lcr_comp.h>
#include <corosync/engine/logsys.h>
@ -68,7 +69,8 @@ LOGSYS_DECLARE_SUBSYS ("CFG");
enum cfg_message_req_types {
MESSAGE_REQ_EXEC_CFG_RINGREENABLE = 0,
MESSAGE_REQ_EXEC_CFG_KILLNODE = 1,
MESSAGE_REQ_EXEC_CFG_SHUTDOWN = 2
MESSAGE_REQ_EXEC_CFG_SHUTDOWN = 2,
MESSAGE_REQ_EXEC_CFG_CRYPTO_SET = 3
};
#define DEFAULT_SHUTDOWN_TIMEOUT 5
@ -120,6 +122,10 @@ static void message_handler_req_exec_cfg_shutdown (
const void *message,
unsigned int nodeid);
static void message_handler_req_exec_cfg_crypto_set (
const void *message,
unsigned int nodeid);
static void exec_cfg_killnode_endian_convert (void *msg);
static void message_handler_req_lib_cfg_ringstatusget (
@ -174,6 +180,10 @@ static void message_handler_req_lib_cfg_local_get (
void *conn,
const void *msg);
static void message_handler_req_lib_cfg_crypto_set (
void *conn,
const void *msg);
/*
* Service Handler Definition
*/
@ -256,6 +266,12 @@ static struct corosync_lib_handler cfg_lib_engine[] =
.response_size = sizeof (struct res_lib_cfg_local_get),
.response_id = MESSAGE_RES_CFG_LOCAL_GET,
.flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
},
{ /* 13 */
.lib_handler_fn = message_handler_req_lib_cfg_crypto_set,
.response_size = sizeof (struct res_lib_cfg_crypto_set),
.response_id = MESSAGE_RES_CFG_CRYPTO_SET,
.flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED
}
};
@ -270,6 +286,9 @@ static struct corosync_exec_handler cfg_exec_engine[] =
},
{ /* 2 */
.exec_handler_fn = message_handler_req_exec_cfg_shutdown,
},
{ /* 3 */
.exec_handler_fn = message_handler_req_exec_cfg_crypto_set,
}
};
@ -342,6 +361,11 @@ struct req_exec_cfg_killnode {
mar_name_t reason __attribute__((aligned(8)));
};
struct req_exec_cfg_crypto_set {
coroipc_request_header_t header __attribute__((aligned(8)));
mar_uint32_t type __attribute__((aligned(8)));
};
struct req_exec_cfg_shutdown {
coroipc_request_header_t header __attribute__((aligned(8)));
};
@ -630,6 +654,19 @@ static void message_handler_req_exec_cfg_shutdown (
LEAVE();
}
static void message_handler_req_exec_cfg_crypto_set (
const void *message,
unsigned int nodeid)
{
const struct req_exec_cfg_crypto_set *req_exec_cfg_crypto_set = message;
ENTER();
log_printf(LOGSYS_LEVEL_NOTICE, "Node %d requested set crypto to %d\n", nodeid, req_exec_cfg_crypto_set->type);
api->totem_crypto_set(req_exec_cfg_crypto_set->type);
LEAVE();
}
/*
* Library Interface Implementation
@ -1058,3 +1095,40 @@ static void message_handler_req_lib_cfg_local_get (void *conn, const void *msg)
api->ipc_response_send(conn, &res_lib_cfg_local_get,
sizeof(res_lib_cfg_local_get));
}
static void message_handler_req_lib_cfg_crypto_set (
void *conn,
const void *msg)
{
const struct req_lib_cfg_crypto_set *req_lib_cfg_crypto_set = msg;
struct res_lib_cfg_crypto_set res_lib_cfg_crypto_set;
struct req_exec_cfg_crypto_set req_exec_cfg_crypto_set;
struct iovec iovec;
int ret = CS_ERR_INVALID_PARAM;
req_exec_cfg_crypto_set.header.size =
sizeof (struct req_exec_cfg_crypto_set);
req_exec_cfg_crypto_set.header.id = SERVICE_ID_MAKE (CFG_SERVICE,
MESSAGE_REQ_EXEC_CFG_CRYPTO_SET);
/*
* Set it locally first so we can tell if it is allowed
*/
if (api->totem_crypto_set(req_lib_cfg_crypto_set->type) == 0) {
req_exec_cfg_crypto_set.type = req_lib_cfg_crypto_set->type;
iovec.iov_base = (char *)&req_exec_cfg_crypto_set;
iovec.iov_len = sizeof (struct req_exec_cfg_crypto_set);
assert (api->totem_mcast (&iovec, 1, TOTEM_SAFE) == 0);
ret = CS_OK;
}
res_lib_cfg_crypto_set.header.size = sizeof(res_lib_cfg_crypto_set);
res_lib_cfg_crypto_set.header.id = MESSAGE_RES_CFG_CRYPTO_SET;
res_lib_cfg_crypto_set.header.error = ret;
api->ipc_response_send(conn, &res_lib_cfg_crypto_set,
sizeof(res_lib_cfg_crypto_set));
}

View File

@ -211,6 +211,26 @@ static void showaddrs_do(int nodeid)
(void)corosync_cfg_finalize (handle);
}
static void crypto_do(unsigned int type)
{
cs_error_t result;
corosync_cfg_handle_t handle;
printf ("Setting crypto to mode %d\n", type);
result = corosync_cfg_initialize (&handle, NULL);
if (result != CS_OK) {
printf ("Could not initialize corosync configuration API error %d\n", result);
exit (1);
}
result = corosync_cfg_crypto_set (handle, type);
if (result != CS_OK) {
printf ("Could not set crypto mode (error = %d)\n", result);
}
(void)corosync_cfg_finalize (handle);
}
static void killnode_do(unsigned int nodeid)
{
cs_error_t result;
@ -241,6 +261,7 @@ static void usage_do (void)
printf ("\t-l\tLoad a service identified by name.\n");
printf ("\t-u\tUnload a service identified by name.\n");
printf ("\t-a\tDisplay the IP address(es) of a node\n");
printf ("\t-c\tSet the cryptography mode of cluster communications\n");
printf ("\t-k\tKill a node identified by node id.\n");
printf ("\t-H\tShutdown corosync cleanly on this node.\n");
}
@ -257,7 +278,7 @@ xstrdup (char const *s)
}
int main (int argc, char *argv[]) {
const char *options = "srl:u:v:k:a:hH";
const char *options = "srl:u:v:k:a:c:hH";
int opt;
int service_load = 0;
unsigned int nodeid;
@ -294,6 +315,9 @@ int main (int argc, char *argv[]) {
case 'a':
showaddrs_do( atoi(optarg) );
break;
case 'c':
crypto_do( atoi(optarg) );
break;
case 'v':
version = atoi (optarg);
break;