|
@@ -69,8 +69,14 @@
|
|
|
|
|
|
|
|
#include "crypto.h"
|
|
#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_UP 1
|
|
|
#define NETIF_STATE_REPORT_DOWN 2
|
|
#define NETIF_STATE_REPORT_DOWN 2
|
|
|
|
|
|
|
@@ -101,6 +107,12 @@ struct totemnet_instance {
|
|
|
|
|
|
|
|
prng_state totemnet_prng_state;
|
|
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 char totemnet_private_key[1024];
|
|
|
|
|
|
|
|
unsigned int totemnet_private_key_len;
|
|
unsigned int totemnet_private_key_len;
|
|
@@ -234,9 +246,11 @@ do { \
|
|
|
level, (const char *)format, ##args); \
|
|
level, (const char *)format, ##args); \
|
|
|
} while (0);
|
|
} while (0);
|
|
|
|
|
|
|
|
-static int authenticate_and_decrypt (
|
|
|
|
|
|
|
+
|
|
|
|
|
+static int authenticate_and_decrypt_sober (
|
|
|
struct totemnet_instance *instance,
|
|
struct totemnet_instance *instance,
|
|
|
- struct iovec *iov)
|
|
|
|
|
|
|
+ struct iovec *iov,
|
|
|
|
|
+ unsigned int iov_len)
|
|
|
{
|
|
{
|
|
|
unsigned char keys[48];
|
|
unsigned char keys[48];
|
|
|
struct security_header *header = iov[0].iov_base;
|
|
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);
|
|
hmac_done (&instance->totemnet_hmac_state, digest_comparison, &len);
|
|
|
|
|
|
|
|
if (memcmp (digest_comparison, header->hash_digest, len) != 0) {
|
|
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);
|
|
return (-1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -294,13 +307,333 @@ static int authenticate_and_decrypt (
|
|
|
|
|
|
|
|
return (0);
|
|
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,
|
|
|
|
|
+ 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,
|
|
struct totemnet_instance *instance,
|
|
|
unsigned char *buf,
|
|
unsigned char *buf,
|
|
|
size_t *buf_len,
|
|
size_t *buf_len,
|
|
|
const struct iovec *iovec,
|
|
const struct iovec *iovec,
|
|
|
- size_t iov_len,
|
|
|
|
|
- prng_state *prng_state_in)
|
|
|
|
|
|
|
+ unsigned int iov_len)
|
|
|
{
|
|
{
|
|
|
int i;
|
|
int i;
|
|
|
unsigned char *addr;
|
|
unsigned char *addr;
|
|
@@ -314,6 +647,7 @@ static void encrypt_and_sign_worker (
|
|
|
hmac_state hmac_st;
|
|
hmac_state hmac_st;
|
|
|
prng_state keygen_prng_state;
|
|
prng_state keygen_prng_state;
|
|
|
prng_state stream_prng_state;
|
|
prng_state stream_prng_state;
|
|
|
|
|
+ prng_state *prng_state_in = &instance->totemnet_prng_state;
|
|
|
|
|
|
|
|
header = (struct security_header *)buf;
|
|
header = (struct security_header *)buf;
|
|
|
addr = buf + sizeof (struct security_header);
|
|
addr = buf + sizeof (struct security_header);
|
|
@@ -374,8 +708,124 @@ static void encrypt_and_sign_worker (
|
|
|
hmac_done (&hmac_st, header->hash_digest, &len);
|
|
hmac_done (&hmac_st, header->hash_digest, &len);
|
|
|
|
|
|
|
|
*buf_len = outlen;
|
|
*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 (
|
|
static inline void ucast_sendmsg (
|
|
|
struct totemnet_instance *instance,
|
|
struct totemnet_instance *instance,
|
|
|
struct totem_ip_address *system_to,
|
|
struct totem_ip_address *system_to,
|
|
@@ -408,8 +858,14 @@ static inline void ucast_sendmsg (
|
|
|
encrypt_data,
|
|
encrypt_data,
|
|
|
&buf_len,
|
|
&buf_len,
|
|
|
iovec_encrypt,
|
|
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_base = encrypt_data;
|
|
|
iovec_encrypt[0].iov_len = buf_len;
|
|
iovec_encrypt[0].iov_len = buf_len;
|
|
@@ -472,8 +928,14 @@ static inline void mcast_sendmsg (
|
|
|
encrypt_data,
|
|
encrypt_data,
|
|
|
&buf_len,
|
|
&buf_len,
|
|
|
iovec_encrypt,
|
|
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_base = encrypt_data;
|
|
|
iovec_encrypt[0].iov_len = buf_len;
|
|
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 (
|
|
encrypt_and_sign_worker (
|
|
|
instance,
|
|
instance,
|
|
|
totemnet_mcast_thread_state->iobuf, &buf_len,
|
|
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 = &iovec_encrypted;
|
|
|
iovec_sendmsg->iov_base = totemnet_mcast_thread_state->iobuf;
|
|
iovec_sendmsg->iov_base = totemnet_mcast_thread_state->iobuf;
|
|
@@ -660,8 +1121,9 @@ static int net_deliver_fn (
|
|
|
* Authenticate and if authenticated, decrypt datagram
|
|
* Authenticate and if authenticated, decrypt datagram
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
- res = authenticate_and_decrypt (instance, iovec);
|
|
|
|
|
|
|
+ res = authenticate_and_decrypt (instance, iovec, 1);
|
|
|
if (res == -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,
|
|
log_printf (instance->totemnet_log_level_security,
|
|
|
"Invalid packet data\n");
|
|
"Invalid packet data\n");
|
|
|
iovec->iov_len = FRAME_SIZE_MAX;
|
|
iovec->iov_len = FRAME_SIZE_MAX;
|
|
@@ -698,7 +1160,7 @@ static int netif_determine (
|
|
|
|
|
|
|
|
res = totemip_iface_check (bindnet, bound_to,
|
|
res = totemip_iface_check (bindnet, bound_to,
|
|
|
interface_up, interface_num,
|
|
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);
|
|
return (res);
|
|
@@ -1200,7 +1662,7 @@ int totemnet_initialize (
|
|
|
|
|
|
|
|
instance->totemnet_private_key_len = totem_config->private_key_len;
|
|
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
|
|
* Initialize local variables for totemnet
|
|
@@ -1233,8 +1695,6 @@ int totemnet_initialize (
|
|
|
|
|
|
|
|
instance->handle = *handle;
|
|
instance->handle = *handle;
|
|
|
|
|
|
|
|
- rng_make_prng (128, PRNG_SOBER, &instance->totemnet_prng_state, NULL);
|
|
|
|
|
-
|
|
|
|
|
totemip_localhost (instance->mcast_address.family, &localhost);
|
|
totemip_localhost (instance->mcast_address.family, &localhost);
|
|
|
|
|
|
|
|
netif_down_check (instance);
|
|
netif_down_check (instance);
|