|
|
@@ -6,6 +6,7 @@
|
|
|
* Author: Steven Dake (sdake@redhat.com)
|
|
|
* Christine Caulfield (ccaulfie@redhat.com)
|
|
|
* Jan Friesse (jfriesse@redhat.com)
|
|
|
+ * Fabio M. Di Nitto (fdinitto@redhat.com)
|
|
|
*
|
|
|
* This software licensed under BSD license, the text of which follows:
|
|
|
*
|
|
|
@@ -34,42 +35,7 @@
|
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
*/
|
|
|
|
|
|
-#include <config.h>
|
|
|
-
|
|
|
-#include <assert.h>
|
|
|
-#include <pthread.h>
|
|
|
-#include <sys/mman.h>
|
|
|
-#include <sys/types.h>
|
|
|
-#include <sys/stat.h>
|
|
|
-#include <sys/socket.h>
|
|
|
-#include <netdb.h>
|
|
|
-#include <sys/un.h>
|
|
|
-#include <sys/ioctl.h>
|
|
|
-#include <sys/param.h>
|
|
|
-#include <netinet/in.h>
|
|
|
-#include <arpa/inet.h>
|
|
|
-#include <unistd.h>
|
|
|
-#include <fcntl.h>
|
|
|
-#include <stdlib.h>
|
|
|
-#include <stdio.h>
|
|
|
-#include <errno.h>
|
|
|
-#include <sched.h>
|
|
|
-#include <time.h>
|
|
|
-#include <sys/time.h>
|
|
|
-#include <sys/poll.h>
|
|
|
-#include <limits.h>
|
|
|
-
|
|
|
-#include <corosync/sq.h>
|
|
|
-#include <corosync/swab.h>
|
|
|
-#include <corosync/list.h>
|
|
|
-#include <qb/qbdefs.h>
|
|
|
-#include <qb/qbloop.h>
|
|
|
-#define LOGSYS_UTILS_ONLY 1
|
|
|
-#include <corosync/logsys.h>
|
|
|
-#include <corosync/totem/totem.h>
|
|
|
-#include "totemcrypto.h"
|
|
|
-
|
|
|
-#include "util.h"
|
|
|
+#include "config.h"
|
|
|
|
|
|
#include <nss.h>
|
|
|
#include <pk11pub.h>
|
|
|
@@ -78,7 +44,14 @@
|
|
|
#include <blapit.h>
|
|
|
#include <hasht.h>
|
|
|
|
|
|
-#define SALT_SIZE 16
|
|
|
+#define LOGSYS_UTILS_ONLY 1
|
|
|
+#include <corosync/logsys.h>
|
|
|
+#include <corosync/totem/totem.h>
|
|
|
+#include "totemcrypto.h"
|
|
|
+
|
|
|
+/*
|
|
|
+ * define onwire crypto header
|
|
|
+ */
|
|
|
|
|
|
struct crypto_config_header {
|
|
|
uint8_t crypto_cipher_type;
|
|
|
@@ -87,6 +60,12 @@ struct crypto_config_header {
|
|
|
uint8_t __pad1;
|
|
|
} __attribute__((packed));
|
|
|
|
|
|
+/*
|
|
|
+ * crypto definitions and conversion tables
|
|
|
+ */
|
|
|
+
|
|
|
+#define SALT_SIZE 16
|
|
|
+
|
|
|
enum crypto_crypt_t {
|
|
|
CRYPTO_CIPHER_TYPE_NONE = 0,
|
|
|
CRYPTO_CIPHER_TYPE_AES256 = 1
|
|
|
@@ -107,6 +86,10 @@ size_t cypher_block_len[] = {
|
|
|
AES_BLOCK_SIZE /* CRYPTO_CIPHER_TYPE_AES256 */
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * hash definitions and conversion tables
|
|
|
+ */
|
|
|
+
|
|
|
enum crypto_hash_t {
|
|
|
CRYPTO_HASH_TYPE_NONE = 0,
|
|
|
CRYPTO_HASH_TYPE_MD5 = 1,
|
|
|
@@ -155,6 +138,8 @@ struct crypto_instance {
|
|
|
|
|
|
enum crypto_hash_t crypto_hash_type;
|
|
|
|
|
|
+ unsigned int crypto_header_size;
|
|
|
+
|
|
|
void (*log_printf_func) (
|
|
|
int level,
|
|
|
int subsys,
|
|
|
@@ -178,117 +163,73 @@ do { \
|
|
|
(const char *)format, ##args); \
|
|
|
} while (0);
|
|
|
|
|
|
-#define LOGSYS_PERROR(err_num, level, fmt, args...) \
|
|
|
-do { \
|
|
|
- char _error_str[LOGSYS_MAX_PERROR_MSG_LEN]; \
|
|
|
- const char *_error_ptr = qb_strerror_r(err_num, _error_str, sizeof(_error_str)); \
|
|
|
- instance->totemudp_log_printf ( \
|
|
|
- level, instance->log_subsys_id, \
|
|
|
- __FUNCTION__, __FILE__, __LINE__, \
|
|
|
- fmt ": %s (%d)", ##args, _error_ptr, err_num); \
|
|
|
-} while(0)
|
|
|
-
|
|
|
-static int init_nss_crypto(struct crypto_instance *instance,
|
|
|
- const char *crypto_cipher_type,
|
|
|
- const char *crypto_hash_type)
|
|
|
+/*
|
|
|
+ * crypt/decrypt functions
|
|
|
+ */
|
|
|
+
|
|
|
+static int string_to_crypto_cipher_type(const char* crypto_cipher_type)
|
|
|
+{
|
|
|
+ if (strcmp(crypto_cipher_type, "none") == 0) {
|
|
|
+ return CRYPTO_CIPHER_TYPE_NONE;
|
|
|
+ } else if (strcmp(crypto_cipher_type, "aes256") == 0) {
|
|
|
+ return CRYPTO_CIPHER_TYPE_AES256;
|
|
|
+ }
|
|
|
+ return CRYPTO_CIPHER_TYPE_AES256;
|
|
|
+}
|
|
|
+
|
|
|
+static int init_nss_crypto(struct crypto_instance *instance)
|
|
|
{
|
|
|
PK11SlotInfo* crypt_slot = NULL;
|
|
|
- PK11SlotInfo* hash_slot = NULL;
|
|
|
SECItem crypt_param;
|
|
|
- SECItem hash_param;
|
|
|
|
|
|
- if ((!cipher_to_nss[instance->crypto_cipher_type]) &&
|
|
|
- (!hash_to_nss[instance->crypto_hash_type])) {
|
|
|
- log_printf(instance->log_level_notice,
|
|
|
- "Initializing transmit/receive security: NONE");
|
|
|
+ if (!cipher_to_nss[instance->crypto_cipher_type]) {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- log_printf(instance->log_level_notice,
|
|
|
- "Initializing transmit/receive security: NSS crypto: %s hash: %s",
|
|
|
- crypto_cipher_type, crypto_hash_type);
|
|
|
+ crypt_param.type = siBuffer;
|
|
|
+ crypt_param.data = instance->private_key;
|
|
|
+ crypt_param.len = cipher_key_len[instance->crypto_cipher_type];
|
|
|
|
|
|
- if (NSS_NoDB_Init(".") != SECSuccess) {
|
|
|
- log_printf(instance->log_level_security, "NSS initialization failed (err %d)",
|
|
|
+ crypt_slot = PK11_GetBestSlot(cipher_to_nss[instance->crypto_cipher_type], NULL);
|
|
|
+ if (crypt_slot == NULL) {
|
|
|
+ log_printf(instance->log_level_security, "Unable to find security slot (err %d)",
|
|
|
PR_GetError());
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- if (cipher_to_nss[instance->crypto_cipher_type]) {
|
|
|
- crypt_param.type = siBuffer;
|
|
|
- crypt_param.data = instance->private_key;
|
|
|
- crypt_param.len = cipher_key_len[instance->crypto_cipher_type];
|
|
|
-
|
|
|
- crypt_slot = PK11_GetBestSlot(cipher_to_nss[instance->crypto_cipher_type], NULL);
|
|
|
- if (crypt_slot == NULL) {
|
|
|
- log_printf(instance->log_level_security, "Unable to find security slot (err %d)",
|
|
|
- PR_GetError());
|
|
|
- goto out;
|
|
|
- }
|
|
|
- instance->nss_sym_key = PK11_ImportSymKey(crypt_slot,
|
|
|
- cipher_to_nss[instance->crypto_cipher_type],
|
|
|
- PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT,
|
|
|
- &crypt_param, NULL);
|
|
|
- if (instance->nss_sym_key == NULL) {
|
|
|
- log_printf(instance->log_level_security, "Failure to import key into NSS (err %d)",
|
|
|
- PR_GetError());
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- if (hash_to_nss[instance->crypto_hash_type]) {
|
|
|
- hash_param.type = siBuffer;
|
|
|
- hash_param.data = 0;
|
|
|
- hash_param.len = 0;
|
|
|
-
|
|
|
- hash_slot = PK11_GetBestSlot(hash_to_nss[instance->crypto_hash_type], NULL);
|
|
|
- if (hash_slot == NULL) {
|
|
|
- log_printf(instance->log_level_security, "Unable to find security slot (err %d)",
|
|
|
- PR_GetError());
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- instance->nss_sym_key_sign = PK11_ImportSymKey(hash_slot,
|
|
|
- hash_to_nss[instance->crypto_hash_type],
|
|
|
- PK11_OriginUnwrap, CKA_SIGN,
|
|
|
- &hash_param, NULL);
|
|
|
- if (instance->nss_sym_key_sign == NULL) {
|
|
|
- log_printf(instance->log_level_security, "Failure to import key into NSS (err %d)",
|
|
|
- PR_GetError());
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ instance->nss_sym_key = PK11_ImportSymKey(crypt_slot,
|
|
|
+ cipher_to_nss[instance->crypto_cipher_type],
|
|
|
+ PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT,
|
|
|
+ &crypt_param, NULL);
|
|
|
+ if (instance->nss_sym_key == NULL) {
|
|
|
+ log_printf(instance->log_level_security, "Failure to import key into NSS (err %d)",
|
|
|
+ PR_GetError());
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
-out:
|
|
|
- return -1;
|
|
|
}
|
|
|
|
|
|
-static int encrypt_and_sign_nss (
|
|
|
+static int encrypt_nss(
|
|
|
struct crypto_instance *instance,
|
|
|
const unsigned char *buf_in,
|
|
|
const size_t buf_in_len,
|
|
|
unsigned char *buf_out,
|
|
|
size_t *buf_out_len)
|
|
|
{
|
|
|
- PK11Context* enc_context = NULL;
|
|
|
+ PK11Context* crypt_context = NULL;
|
|
|
SECItem crypt_param;
|
|
|
- SECItem hash_param;
|
|
|
SECItem *nss_sec_param = NULL;
|
|
|
-
|
|
|
- unsigned char *outdata;
|
|
|
int tmp1_outlen = 0;
|
|
|
unsigned int tmp2_outlen = 0;
|
|
|
-
|
|
|
- unsigned char salt[SALT_SIZE];
|
|
|
- unsigned char hash_block[hash_block_len[instance->crypto_hash_type]];
|
|
|
-
|
|
|
- outdata = buf_out + hash_len[instance->crypto_hash_type];
|
|
|
+ unsigned char *salt = buf_out;
|
|
|
+ unsigned char *data = buf_out + SALT_SIZE;
|
|
|
+ int err = -1;
|
|
|
|
|
|
if (!cipher_to_nss[instance->crypto_cipher_type]) {
|
|
|
- memcpy(outdata, buf_in, buf_in_len);
|
|
|
+ memcpy(buf_out, buf_in, buf_in_len);
|
|
|
*buf_out_len = buf_in_len;
|
|
|
- goto only_hash;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
if (PK11_GenerateRandom (salt, SALT_SIZE) != SECSuccess) {
|
|
|
@@ -297,7 +238,6 @@ static int encrypt_and_sign_nss (
|
|
|
PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
- memcpy(outdata, salt, SALT_SIZE);
|
|
|
|
|
|
crypt_param.type = siBuffer;
|
|
|
crypt_param.data = salt;
|
|
|
@@ -315,11 +255,11 @@ static int encrypt_and_sign_nss (
|
|
|
/*
|
|
|
* Create cipher context for encryption
|
|
|
*/
|
|
|
- enc_context = PK11_CreateContextBySymKey (cipher_to_nss[instance->crypto_cipher_type],
|
|
|
- CKA_ENCRYPT,
|
|
|
- instance->nss_sym_key,
|
|
|
- nss_sec_param);
|
|
|
- if (!enc_context) {
|
|
|
+ crypt_context = PK11_CreateContextBySymKey (cipher_to_nss[instance->crypto_cipher_type],
|
|
|
+ CKA_ENCRYPT,
|
|
|
+ instance->nss_sym_key,
|
|
|
+ nss_sec_param);
|
|
|
+ if (!crypt_context) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
"PK11_CreateContext failed (encrypt) crypt_type=%d (err %d)",
|
|
|
(int)cipher_to_nss[instance->crypto_cipher_type],
|
|
|
@@ -327,9 +267,9 @@ static int encrypt_and_sign_nss (
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (PK11_CipherOp(enc_context, outdata + SALT_SIZE,
|
|
|
+ if (PK11_CipherOp(crypt_context, data,
|
|
|
&tmp1_outlen,
|
|
|
- FRAME_SIZE_MAX - (sizeof(struct crypto_config_header) + hash_len[instance->crypto_hash_type] + SALT_SIZE),
|
|
|
+ FRAME_SIZE_MAX - instance->crypto_header_size,
|
|
|
(unsigned char *)buf_in, buf_in_len) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
"PK11_CipherOp failed (encrypt) crypt_type=%d (err %d)",
|
|
|
@@ -337,7 +277,8 @@ static int encrypt_and_sign_nss (
|
|
|
PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
- if (PK11_DigestFinal(enc_context, outdata + SALT_SIZE + tmp1_outlen,
|
|
|
+
|
|
|
+ if (PK11_DigestFinal(crypt_context, data + tmp1_outlen,
|
|
|
&tmp2_outlen, FRAME_SIZE_MAX - tmp1_outlen) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
"PK11_DigestFinal failed (encrypt) crypt_type=%d (err %d)",
|
|
|
@@ -347,260 +288,317 @@ static int encrypt_and_sign_nss (
|
|
|
|
|
|
}
|
|
|
|
|
|
- if (enc_context) {
|
|
|
- PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
- enc_context = 0;
|
|
|
- }
|
|
|
-
|
|
|
*buf_out_len = tmp1_outlen + tmp2_outlen + SALT_SIZE;
|
|
|
|
|
|
-only_hash:
|
|
|
+ err = 0;
|
|
|
|
|
|
- if (!hash_to_nss[instance->crypto_hash_type]) {
|
|
|
- goto no_hash;
|
|
|
+out:
|
|
|
+ if (crypt_context) {
|
|
|
+ PK11_DestroyContext(crypt_context, PR_TRUE);
|
|
|
}
|
|
|
+ if (nss_sec_param) {
|
|
|
+ SECITEM_FreeItem(nss_sec_param, PR_TRUE);
|
|
|
+ }
|
|
|
+ return err;
|
|
|
+}
|
|
|
|
|
|
- /* Now do the digest */
|
|
|
- hash_param.type = siBuffer;
|
|
|
- hash_param.data = 0;
|
|
|
- hash_param.len = 0;
|
|
|
+static int decrypt_nss (
|
|
|
+ struct crypto_instance *instance,
|
|
|
+ unsigned char *buf,
|
|
|
+ int *buf_len)
|
|
|
+{
|
|
|
+ PK11Context* decrypt_context = NULL;
|
|
|
+ SECItem decrypt_param;
|
|
|
+ int tmp1_outlen = 0;
|
|
|
+ unsigned int tmp2_outlen = 0;
|
|
|
+ unsigned char *salt = buf;
|
|
|
+ unsigned char *data = salt + SALT_SIZE;
|
|
|
+ int datalen = *buf_len - SALT_SIZE;
|
|
|
+ unsigned char outbuf[FRAME_SIZE_MAX];
|
|
|
+ int outbuf_len;
|
|
|
+ int err = -1;
|
|
|
|
|
|
- enc_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type],
|
|
|
- CKA_SIGN,
|
|
|
- instance->nss_sym_key_sign,
|
|
|
- &hash_param);
|
|
|
- if (!enc_context) {
|
|
|
- log_printf(instance->log_level_security,
|
|
|
- "PK11_CreateContext failed (hash) hash_type=%d (err %d)",
|
|
|
- (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
- PR_GetError());
|
|
|
- goto out;
|
|
|
+ if (!cipher_to_nss[instance->crypto_cipher_type]) {
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- if (PK11_DigestBegin(enc_context) != SECSuccess) {
|
|
|
+ /* Create cipher context for decryption */
|
|
|
+ decrypt_param.type = siBuffer;
|
|
|
+ decrypt_param.data = salt;
|
|
|
+ decrypt_param.len = SALT_SIZE;
|
|
|
+
|
|
|
+ decrypt_context = PK11_CreateContextBySymKey(cipher_to_nss[instance->crypto_cipher_type],
|
|
|
+ CKA_DECRYPT,
|
|
|
+ instance->nss_sym_key, &decrypt_param);
|
|
|
+ if (!decrypt_context) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_DigestBegin failed (hash) hash_type=%d (err %d)",
|
|
|
- (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
+ "PK11_CreateContext (decrypt) failed (err %d)",
|
|
|
PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (PK11_DigestOp(enc_context,
|
|
|
- outdata,
|
|
|
- *buf_out_len) != SECSuccess) {
|
|
|
+ if (PK11_CipherOp(decrypt_context, outbuf, &tmp1_outlen,
|
|
|
+ sizeof(outbuf), data, datalen) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_DigestOp failed (hash) hash_type=%d (err %d)",
|
|
|
- (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
+ "PK11_CipherOp (decrypt) failed (err %d)",
|
|
|
PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
- if (PK11_DigestFinal(enc_context,
|
|
|
- hash_block,
|
|
|
- &tmp2_outlen,
|
|
|
- hash_block_len[instance->crypto_hash_type]) != SECSuccess) {
|
|
|
+
|
|
|
+ if (PK11_DigestFinal(decrypt_context, outbuf + tmp1_outlen, &tmp2_outlen,
|
|
|
+ sizeof(outbuf) - tmp1_outlen) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_DigestFinale failed (hash) hash_type=%d (err %d)",
|
|
|
- (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
- PR_GetError());
|
|
|
+ "PK11_DigestFinal (decrypt) failed (err %d)",
|
|
|
+ PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (enc_context) {
|
|
|
- PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
- enc_context = 0;
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(buf_out, hash_block, hash_len[instance->crypto_hash_type]);
|
|
|
+ outbuf_len = tmp1_outlen + tmp2_outlen;
|
|
|
|
|
|
- *buf_out_len = *buf_out_len + hash_len[instance->crypto_hash_type];
|
|
|
+ memset(buf, 0, *buf_len);
|
|
|
+ memcpy(buf, outbuf, outbuf_len);
|
|
|
|
|
|
-no_hash:
|
|
|
+ *buf_len = outbuf_len;
|
|
|
|
|
|
- SECITEM_FreeItem(nss_sec_param, PR_TRUE);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ err = 0;
|
|
|
|
|
|
out:
|
|
|
- if (enc_context) {
|
|
|
- PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
+ if (decrypt_context) {
|
|
|
+ PK11_DestroyContext(decrypt_context, PR_TRUE);
|
|
|
}
|
|
|
- if (nss_sec_param) {
|
|
|
- SECITEM_FreeItem(nss_sec_param, PR_TRUE);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * hash/hmac/digest functions
|
|
|
+ */
|
|
|
+
|
|
|
+static int string_to_crypto_hash_type(const char* crypto_hash_type)
|
|
|
+{
|
|
|
+ if (strcmp(crypto_hash_type, "none") == 0) {
|
|
|
+ return CRYPTO_HASH_TYPE_NONE;
|
|
|
+ } else if (strcmp(crypto_hash_type, "md5") == 0) {
|
|
|
+ return CRYPTO_HASH_TYPE_MD5;
|
|
|
+ } else if (strcmp(crypto_hash_type, "sha1") == 0) {
|
|
|
+ return CRYPTO_HASH_TYPE_SHA1;
|
|
|
+ } else if (strcmp(crypto_hash_type, "sha256") == 0) {
|
|
|
+ return CRYPTO_HASH_TYPE_SHA256;
|
|
|
+ } else if (strcmp(crypto_hash_type, "sha384") == 0) {
|
|
|
+ return CRYPTO_HASH_TYPE_SHA384;
|
|
|
+ } else if (strcmp(crypto_hash_type, "sha512") == 0) {
|
|
|
+ return CRYPTO_HASH_TYPE_SHA512;
|
|
|
}
|
|
|
- return -1;
|
|
|
+
|
|
|
+ return CRYPTO_HASH_TYPE_SHA1;
|
|
|
}
|
|
|
|
|
|
-static int authenticate_and_decrypt_nss (
|
|
|
- struct crypto_instance *instance,
|
|
|
- unsigned char *buf,
|
|
|
- int *buf_len)
|
|
|
+static int init_nss_hash(struct crypto_instance *instance)
|
|
|
{
|
|
|
- PK11Context* enc_context = NULL;
|
|
|
- SECItem crypt_param;
|
|
|
+ PK11SlotInfo* hash_slot = NULL;
|
|
|
SECItem hash_param;
|
|
|
- unsigned char hash_block[hash_block_len[instance->crypto_hash_type]];
|
|
|
|
|
|
- int tmp1_outlen = 0;
|
|
|
- unsigned int tmp2_outlen = 0;
|
|
|
+ if (!hash_to_nss[instance->crypto_hash_type]) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- unsigned char *data;
|
|
|
- size_t datalen;
|
|
|
+ hash_param.type = siBuffer;
|
|
|
+ hash_param.data = 0;
|
|
|
+ hash_param.len = 0;
|
|
|
|
|
|
- unsigned char outbuf[FRAME_SIZE_MAX];
|
|
|
+ hash_slot = PK11_GetBestSlot(hash_to_nss[instance->crypto_hash_type], NULL);
|
|
|
+ if (hash_slot == NULL) {
|
|
|
+ log_printf(instance->log_level_security, "Unable to find security slot (err %d)",
|
|
|
+ PR_GetError());
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
- int result_len;
|
|
|
+ instance->nss_sym_key_sign = PK11_ImportSymKey(hash_slot,
|
|
|
+ hash_to_nss[instance->crypto_hash_type],
|
|
|
+ PK11_OriginUnwrap, CKA_SIGN,
|
|
|
+ &hash_param, NULL);
|
|
|
+ if (instance->nss_sym_key_sign == NULL) {
|
|
|
+ log_printf(instance->log_level_security, "Failure to import key into NSS (err %d)",
|
|
|
+ PR_GetError());
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
- data = buf + hash_len[instance->crypto_hash_type];
|
|
|
- datalen = *buf_len - hash_len[instance->crypto_hash_type];
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- if (!hash_to_nss[instance->crypto_hash_type]) {
|
|
|
- goto only_decrypt;
|
|
|
- }
|
|
|
+static int calculate_nss_hash(
|
|
|
+ struct crypto_instance *instance,
|
|
|
+ const unsigned char *buf,
|
|
|
+ const size_t buf_len,
|
|
|
+ unsigned char *hash)
|
|
|
+{
|
|
|
+ PK11Context* hash_context = NULL;
|
|
|
+ SECItem hash_param;
|
|
|
+ unsigned int hash_tmp_outlen = 0;
|
|
|
+ unsigned char hash_block[hash_block_len[instance->crypto_hash_type]];
|
|
|
+ int err = -1;
|
|
|
|
|
|
+ /* Now do the digest */
|
|
|
hash_param.type = siBuffer;
|
|
|
hash_param.data = 0;
|
|
|
hash_param.len = 0;
|
|
|
|
|
|
- /* Check the digest */
|
|
|
- enc_context = PK11_CreateContextBySymKey (hash_to_nss[instance->crypto_hash_type],
|
|
|
- CKA_SIGN,
|
|
|
- instance->nss_sym_key_sign,
|
|
|
- &hash_param);
|
|
|
- if (!enc_context) {
|
|
|
+ hash_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type],
|
|
|
+ CKA_SIGN,
|
|
|
+ instance->nss_sym_key_sign,
|
|
|
+ &hash_param);
|
|
|
+
|
|
|
+ if (!hash_context) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_CreateContext failed (check digest) err %d",
|
|
|
+ "PK11_CreateContext failed (hash) hash_type=%d (err %d)",
|
|
|
+ (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (PK11_DigestBegin(enc_context) != SECSuccess) {
|
|
|
+ if (PK11_DigestBegin(hash_context) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_DigestBegin failed (check digest) err %d",
|
|
|
- PR_GetError());
|
|
|
+ "PK11_DigestBegin failed (hash) hash_type=%d (err %d)",
|
|
|
+ (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
+ PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (PK11_DigestOp(enc_context, data, datalen) != SECSuccess) {
|
|
|
+ if (PK11_DigestOp(hash_context,
|
|
|
+ buf,
|
|
|
+ buf_len) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_DigestOp failed (check digest) err %d",
|
|
|
+ "PK11_DigestOp failed (hash) hash_type=%d (err %d)",
|
|
|
+ (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (PK11_DigestFinal(enc_context, hash_block,
|
|
|
- &tmp2_outlen, hash_block_len[instance->crypto_hash_type]) != SECSuccess) {
|
|
|
+ if (PK11_DigestFinal(hash_context,
|
|
|
+ hash_block,
|
|
|
+ &hash_tmp_outlen,
|
|
|
+ hash_block_len[instance->crypto_hash_type]) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_DigestFinal failed (check digest) err %d",
|
|
|
+ "PK11_DigestFinale failed (hash) hash_type=%d (err %d)",
|
|
|
+ (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
PR_GetError());
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (enc_context) {
|
|
|
- PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
- enc_context = 0;
|
|
|
- }
|
|
|
+ memcpy(hash, hash_block, hash_len[instance->crypto_hash_type]);
|
|
|
+ err = 0;
|
|
|
|
|
|
- if (memcmp(hash_block, buf, tmp2_outlen) != 0) {
|
|
|
- log_printf(instance->log_level_error, "Digest does not match");
|
|
|
- goto out;
|
|
|
+out:
|
|
|
+ if (hash_context) {
|
|
|
+ PK11_DestroyContext(hash_context, PR_TRUE);
|
|
|
}
|
|
|
|
|
|
-only_decrypt:
|
|
|
-
|
|
|
- if (!cipher_to_nss[instance->crypto_cipher_type]) {
|
|
|
- memcpy(outbuf, data, datalen);
|
|
|
- result_len = datalen;
|
|
|
- goto no_decrypt;
|
|
|
- }
|
|
|
+ return err;
|
|
|
+}
|
|
|
|
|
|
- /* Create cipher context for decryption */
|
|
|
- crypt_param.type = siBuffer;
|
|
|
- crypt_param.data = data;
|
|
|
- crypt_param.len = SALT_SIZE;
|
|
|
+/*
|
|
|
+ * global/glue nss functions
|
|
|
+ */
|
|
|
|
|
|
- /*
|
|
|
- * Get rid of salt
|
|
|
- */
|
|
|
- data += SALT_SIZE;
|
|
|
- datalen -= SALT_SIZE;
|
|
|
+static int init_nss_db(struct crypto_instance *instance)
|
|
|
+{
|
|
|
+ if ((!cipher_to_nss[instance->crypto_cipher_type]) &&
|
|
|
+ (!hash_to_nss[instance->crypto_hash_type])) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- enc_context = PK11_CreateContextBySymKey(cipher_to_nss[instance->crypto_cipher_type],
|
|
|
- CKA_DECRYPT,
|
|
|
- instance->nss_sym_key, &crypt_param);
|
|
|
- if (!enc_context) {
|
|
|
- log_printf(instance->log_level_security,
|
|
|
- "PK11_CreateContext (decrypt) failed (err %d)",
|
|
|
+ if (NSS_NoDB_Init(".") != SECSuccess) {
|
|
|
+ log_printf(instance->log_level_security, "NSS DB initialization failed (err %d)",
|
|
|
PR_GetError());
|
|
|
- goto out;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- if (PK11_CipherOp(enc_context, outbuf, &tmp1_outlen,
|
|
|
- sizeof(outbuf), data, datalen) != SECSuccess) {
|
|
|
- log_printf(instance->log_level_security,
|
|
|
- "PK11_CipherOp (decrypt) failed (err %d)",
|
|
|
- PR_GetError());
|
|
|
- goto out;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int init_nss(struct crypto_instance *instance,
|
|
|
+ const char *crypto_cipher_type,
|
|
|
+ const char *crypto_hash_type)
|
|
|
+{
|
|
|
+ log_printf(instance->log_level_notice,
|
|
|
+ "Initializing transmit/receive security (NSS) crypto: %s hash: %s",
|
|
|
+ crypto_cipher_type, crypto_hash_type);
|
|
|
+
|
|
|
+ if (init_nss_db(instance) < 0) {
|
|
|
+ return -1;
|
|
|
}
|
|
|
- if (PK11_DigestFinal(enc_context, outbuf + tmp1_outlen, &tmp2_outlen,
|
|
|
- sizeof(outbuf) - tmp1_outlen) != SECSuccess) {
|
|
|
- log_printf(instance->log_level_security,
|
|
|
- "PK11_DigestFinal (decrypt) failed (err %d)",
|
|
|
- PR_GetError());
|
|
|
- goto out;
|
|
|
+
|
|
|
+ if (init_nss_crypto(instance) < 0) {
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- if (enc_context) {
|
|
|
- PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
- enc_context = 0;
|
|
|
+ if (init_nss_hash(instance) < 0) {
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- result_len = tmp1_outlen + tmp2_outlen;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
-no_decrypt:
|
|
|
+static int encrypt_and_sign_nss (
|
|
|
+ struct crypto_instance *instance,
|
|
|
+ const unsigned char *buf_in,
|
|
|
+ const size_t buf_in_len,
|
|
|
+ unsigned char *buf_out,
|
|
|
+ size_t *buf_out_len)
|
|
|
+{
|
|
|
+ unsigned char *hash = buf_out;
|
|
|
+ unsigned char *data = hash + hash_len[instance->crypto_hash_type];
|
|
|
|
|
|
- memset(buf, 0, *buf_len);
|
|
|
- memcpy(buf, outbuf, result_len);
|
|
|
+ if (encrypt_nss(instance, buf_in, buf_in_len, data, buf_out_len) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
- *buf_len = result_len;
|
|
|
+ if (hash_to_nss[instance->crypto_hash_type]) {
|
|
|
+ if (calculate_nss_hash(instance, data, *buf_out_len, hash) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ *buf_out_len = *buf_out_len + hash_len[instance->crypto_hash_type];
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
-
|
|
|
-out:
|
|
|
- if (enc_context) {
|
|
|
- PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
- }
|
|
|
- return -1;
|
|
|
}
|
|
|
|
|
|
-static int string_to_crypto_cipher_type(const char* crypto_cipher_type)
|
|
|
+static int authenticate_and_decrypt_nss (
|
|
|
+ struct crypto_instance *instance,
|
|
|
+ unsigned char *buf,
|
|
|
+ int *buf_len)
|
|
|
{
|
|
|
- if (strcmp(crypto_cipher_type, "none") == 0) {
|
|
|
- return CRYPTO_CIPHER_TYPE_NONE;
|
|
|
- } else if (strcmp(crypto_cipher_type, "aes256") == 0) {
|
|
|
- return CRYPTO_CIPHER_TYPE_AES256;
|
|
|
+ if (hash_to_nss[instance->crypto_hash_type]) {
|
|
|
+ unsigned char tmp_hash[hash_len[instance->crypto_hash_type]];
|
|
|
+ unsigned char *hash = buf;
|
|
|
+ unsigned char *data = hash + hash_len[instance->crypto_hash_type];
|
|
|
+ int datalen = *buf_len - hash_len[instance->crypto_hash_type];
|
|
|
+
|
|
|
+ if (calculate_nss_hash(instance, data, datalen, tmp_hash) < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (memcmp(tmp_hash, hash, hash_len[instance->crypto_hash_type]) != 0) {
|
|
|
+ log_printf(instance->log_level_error, "Digest does not match");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ memmove(buf, data, datalen);
|
|
|
+ *buf_len = datalen;
|
|
|
}
|
|
|
- return CRYPTO_CIPHER_TYPE_AES256;
|
|
|
-}
|
|
|
|
|
|
-static int string_to_crypto_hash_type(const char* crypto_hash_type)
|
|
|
-{
|
|
|
- if (strcmp(crypto_hash_type, "none") == 0) {
|
|
|
- return CRYPTO_HASH_TYPE_NONE;
|
|
|
- } else if (strcmp(crypto_hash_type, "md5") == 0) {
|
|
|
- return CRYPTO_HASH_TYPE_MD5;
|
|
|
- } else if (strcmp(crypto_hash_type, "sha1") == 0) {
|
|
|
- return CRYPTO_HASH_TYPE_SHA1;
|
|
|
- } else if (strcmp(crypto_hash_type, "sha256") == 0) {
|
|
|
- return CRYPTO_HASH_TYPE_SHA256;
|
|
|
- } else if (strcmp(crypto_hash_type, "sha384") == 0) {
|
|
|
- return CRYPTO_HASH_TYPE_SHA384;
|
|
|
- } else if (strcmp(crypto_hash_type, "sha512") == 0) {
|
|
|
- return CRYPTO_HASH_TYPE_SHA512;
|
|
|
+ if (decrypt_nss(instance, buf, buf_len) < 0) {
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- return CRYPTO_HASH_TYPE_SHA1;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * exported API
|
|
|
+ */
|
|
|
+
|
|
|
size_t crypto_sec_header_size(
|
|
|
const char *crypto_cipher_type,
|
|
|
const char *crypto_hash_type)
|
|
|
@@ -630,26 +628,19 @@ int crypto_encrypt_and_sign (
|
|
|
unsigned char *buf_out,
|
|
|
size_t *buf_out_len)
|
|
|
{
|
|
|
- int err = 0;
|
|
|
- struct crypto_config_header *cch;
|
|
|
+ struct crypto_config_header *cch = (struct crypto_config_header *)buf_out;
|
|
|
+ int err;
|
|
|
|
|
|
- cch = (struct crypto_config_header *)buf_out;
|
|
|
cch->crypto_cipher_type = instance->crypto_cipher_type;
|
|
|
cch->crypto_hash_type = instance->crypto_hash_type;
|
|
|
cch->__pad0 = 0;
|
|
|
cch->__pad1 = 0;
|
|
|
|
|
|
- if ((!cipher_to_nss[instance->crypto_cipher_type]) &&
|
|
|
- (!hash_to_nss[instance->crypto_hash_type])) {
|
|
|
- memcpy(buf_out + sizeof(struct crypto_config_header), buf_in, buf_in_len);
|
|
|
- *buf_out_len = buf_in_len;
|
|
|
- err = 0;
|
|
|
- } else {
|
|
|
- err = encrypt_and_sign_nss(instance,
|
|
|
- buf_in, buf_in_len,
|
|
|
- buf_out + sizeof(struct crypto_config_header),
|
|
|
- buf_out_len);
|
|
|
- }
|
|
|
+ buf_out += sizeof(struct crypto_config_header);
|
|
|
+
|
|
|
+ err = encrypt_and_sign_nss(instance,
|
|
|
+ buf_in, buf_in_len,
|
|
|
+ buf_out, buf_out_len);
|
|
|
|
|
|
*buf_out_len = *buf_out_len + sizeof(struct crypto_config_header);
|
|
|
|
|
|
@@ -661,9 +652,7 @@ int crypto_authenticate_and_decrypt (struct crypto_instance *instance,
|
|
|
int *buf_len)
|
|
|
{
|
|
|
int err = 0;
|
|
|
- struct crypto_config_header *cch;
|
|
|
-
|
|
|
- cch = (struct crypto_config_header *)buf;
|
|
|
+ struct crypto_config_header *cch = (struct crypto_config_header *)buf;
|
|
|
|
|
|
/*
|
|
|
* decode crypto config of incoming packets
|
|
|
@@ -688,28 +677,13 @@ int crypto_authenticate_and_decrypt (struct crypto_instance *instance,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * invalidate config header
|
|
|
+ * invalidate config header and kill it
|
|
|
*/
|
|
|
cch = NULL;
|
|
|
-
|
|
|
- /*
|
|
|
- * and kill it
|
|
|
- */
|
|
|
- *buf_len = *buf_len - sizeof(struct crypto_config_header);
|
|
|
+ *buf_len -= sizeof(struct crypto_config_header);
|
|
|
memmove(buf, buf + sizeof(struct crypto_config_header), *buf_len);
|
|
|
|
|
|
-
|
|
|
- /*
|
|
|
- * if crypto is totally disabled, there is no work for us
|
|
|
- */
|
|
|
- if ((!cipher_to_nss[instance->crypto_cipher_type]) &&
|
|
|
- (!hash_to_nss[instance->crypto_hash_type])) {
|
|
|
- err = 0;
|
|
|
- } else {
|
|
|
- err = authenticate_and_decrypt_nss(instance, buf, buf_len);
|
|
|
- }
|
|
|
-
|
|
|
- return err;
|
|
|
+ return authenticate_and_decrypt_nss(instance, buf, buf_len);
|
|
|
}
|
|
|
|
|
|
struct crypto_instance *crypto_init(
|
|
|
@@ -743,13 +717,15 @@ struct crypto_instance *crypto_init(
|
|
|
instance->crypto_cipher_type = string_to_crypto_cipher_type(crypto_cipher_type);
|
|
|
instance->crypto_hash_type = string_to_crypto_hash_type(crypto_hash_type);
|
|
|
|
|
|
+ instance->crypto_header_size = crypto_sec_header_size(crypto_cipher_type, crypto_hash_type);
|
|
|
+
|
|
|
instance->log_printf_func = log_printf_func;
|
|
|
instance->log_level_security = log_level_security;
|
|
|
instance->log_level_notice = log_level_notice;
|
|
|
instance->log_level_error = log_level_error;
|
|
|
instance->log_subsys_id = log_subsys_id;
|
|
|
|
|
|
- if (init_nss_crypto(instance, crypto_cipher_type, crypto_hash_type) < 0) {
|
|
|
+ if (init_nss(instance, crypto_cipher_type, crypto_hash_type) < 0) {
|
|
|
free(instance);
|
|
|
return(NULL);
|
|
|
}
|