|
@@ -77,9 +77,11 @@
|
|
|
#include <prerror.h>
|
|
#include <prerror.h>
|
|
|
|
|
|
|
|
#define CRYPTO_HMAC_HASH_SIZE 20
|
|
#define CRYPTO_HMAC_HASH_SIZE 20
|
|
|
|
|
+#define SALT_SIZE 16
|
|
|
|
|
+
|
|
|
struct crypto_security_header {
|
|
struct crypto_security_header {
|
|
|
unsigned char hash_digest[CRYPTO_HMAC_HASH_SIZE]; /* The hash *MUST* be first in the data structure */
|
|
unsigned char hash_digest[CRYPTO_HMAC_HASH_SIZE]; /* The hash *MUST* be first in the data structure */
|
|
|
- unsigned char salt[16]; /* random number */
|
|
|
|
|
|
|
+ unsigned char salt[SALT_SIZE]; /* random number */
|
|
|
char msg[0];
|
|
char msg[0];
|
|
|
} __attribute__((packed));
|
|
} __attribute__((packed));
|
|
|
|
|
|
|
@@ -111,8 +113,8 @@ struct crypto_instance {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
CK_MECHANISM_TYPE cipher_to_nss[] = {
|
|
CK_MECHANISM_TYPE cipher_to_nss[] = {
|
|
|
- 0, /* CRYPTO_CIPHER_TYPE_NONE */
|
|
|
|
|
- CKM_AES_CBC_PAD /* CRYPTO_CIPHER_TYPE_AES256 */
|
|
|
|
|
|
|
+ 0, /* CRYPTO_CIPHER_TYPE_NONE */
|
|
|
|
|
+ CKM_AES_CBC_PAD /* CRYPTO_CIPHER_TYPE_AES256 */
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
size_t cipher_key_len[] = {
|
|
size_t cipher_key_len[] = {
|
|
@@ -121,15 +123,15 @@ size_t cipher_key_len[] = {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
CK_MECHANISM_TYPE hash_to_nss[] = {
|
|
CK_MECHANISM_TYPE hash_to_nss[] = {
|
|
|
- 0, /* CRYPTO_HASH_TYPE_NONE */
|
|
|
|
|
- CKM_SHA_1_HMAC /* CRYPTO_HASH_TYPE_SHA1 */
|
|
|
|
|
|
|
+ 0, /* CRYPTO_HASH_TYPE_NONE */
|
|
|
|
|
+ CKM_SHA_1_HMAC /* CRYPTO_HASH_TYPE_SHA1 */
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
#define log_printf(level, format, args...) \
|
|
#define log_printf(level, format, args...) \
|
|
|
do { \
|
|
do { \
|
|
|
- instance->log_printf_func ( \
|
|
|
|
|
- level, instance->log_subsys_id, \
|
|
|
|
|
- __FUNCTION__, __FILE__, __LINE__, \
|
|
|
|
|
|
|
+ instance->log_printf_func ( \
|
|
|
|
|
+ level, instance->log_subsys_id, \
|
|
|
|
|
+ __FUNCTION__, __FILE__, __LINE__, \
|
|
|
(const char *)format, ##args); \
|
|
(const char *)format, ##args); \
|
|
|
} while (0);
|
|
} while (0);
|
|
|
|
|
|
|
@@ -137,76 +139,86 @@ do { \
|
|
|
do { \
|
|
do { \
|
|
|
char _error_str[LOGSYS_MAX_PERROR_MSG_LEN]; \
|
|
char _error_str[LOGSYS_MAX_PERROR_MSG_LEN]; \
|
|
|
const char *_error_ptr = qb_strerror_r(err_num, _error_str, sizeof(_error_str)); \
|
|
const char *_error_ptr = qb_strerror_r(err_num, _error_str, sizeof(_error_str)); \
|
|
|
- instance->totemudp_log_printf ( \
|
|
|
|
|
- level, instance->log_subsys_id, \
|
|
|
|
|
|
|
+ instance->totemudp_log_printf ( \
|
|
|
|
|
+ level, instance->log_subsys_id, \
|
|
|
__FUNCTION__, __FILE__, __LINE__, \
|
|
__FUNCTION__, __FILE__, __LINE__, \
|
|
|
- fmt ": %s (%d)", ##args, _error_ptr, err_num); \
|
|
|
|
|
- } while(0)
|
|
|
|
|
|
|
+ fmt ": %s (%d)", ##args, _error_ptr, err_num); \
|
|
|
|
|
+} while(0)
|
|
|
|
|
|
|
|
-static void init_nss_crypto(struct crypto_instance *instance)
|
|
|
|
|
|
|
+static int init_nss_crypto(struct crypto_instance *instance,
|
|
|
|
|
+ const char *crypto_cipher_type,
|
|
|
|
|
+ const char *crypto_hash_type)
|
|
|
{
|
|
{
|
|
|
- PK11SlotInfo* aes_slot = NULL;
|
|
|
|
|
- PK11SlotInfo* sha1_slot = NULL;
|
|
|
|
|
- SECItem key_item;
|
|
|
|
|
- SECStatus rv;
|
|
|
|
|
|
|
+ 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");
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
log_printf(instance->log_level_notice,
|
|
log_printf(instance->log_level_notice,
|
|
|
- "Initializing transmit/receive security: NSS AES256CBC/SHA1HMAC (mode %u).", 0);
|
|
|
|
|
- rv = NSS_NoDB_Init(".");
|
|
|
|
|
- if (rv != SECSuccess)
|
|
|
|
|
- {
|
|
|
|
|
|
|
+ "Initializing transmit/receive security: NSS crypto: %s hash: %s",
|
|
|
|
|
+ crypto_cipher_type, crypto_hash_type);
|
|
|
|
|
+
|
|
|
|
|
+ if (NSS_NoDB_Init(".") != SECSuccess) {
|
|
|
log_printf(instance->log_level_security, "NSS initialization failed (err %d)",
|
|
log_printf(instance->log_level_security, "NSS initialization failed (err %d)",
|
|
|
- PR_GetError());
|
|
|
|
|
|
|
+ PR_GetError());
|
|
|
goto out;
|
|
goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /*
|
|
|
|
|
- * TODO: use instance info!
|
|
|
|
|
- */
|
|
|
|
|
- aes_slot = PK11_GetBestSlot(cipher_to_nss[instance->crypto_cipher_type], NULL);
|
|
|
|
|
- if (aes_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;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- sha1_slot = PK11_GetBestSlot(hash_to_nss[instance->crypto_hash_type], NULL);
|
|
|
|
|
- if (sha1_slot == NULL)
|
|
|
|
|
- {
|
|
|
|
|
- log_printf(instance->log_level_security, "Unable to find security slot (err %d)",
|
|
|
|
|
- PR_GetError());
|
|
|
|
|
- goto out;
|
|
|
|
|
- }
|
|
|
|
|
- /*
|
|
|
|
|
- * Make the private key into a SymKey that we can use
|
|
|
|
|
- */
|
|
|
|
|
- key_item.type = siBuffer;
|
|
|
|
|
- key_item.data = instance->private_key;
|
|
|
|
|
- key_item.len = cipher_key_len[instance->crypto_cipher_type];
|
|
|
|
|
-
|
|
|
|
|
- instance->nss_sym_key = PK11_ImportSymKey(aes_slot,
|
|
|
|
|
- cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
- PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT,
|
|
|
|
|
- &key_item, 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;
|
|
|
|
|
|
|
+ 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_sign = PK11_ImportSymKey(sha1_slot,
|
|
|
|
|
- hash_to_nss[instance->crypto_hash_type],
|
|
|
|
|
- PK11_OriginUnwrap, CKA_SIGN,
|
|
|
|
|
- &key_item, 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;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return 0;
|
|
|
out:
|
|
out:
|
|
|
- return;
|
|
|
|
|
|
|
+ return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int encrypt_and_sign_nss (
|
|
static int encrypt_and_sign_nss (
|
|
@@ -216,226 +228,301 @@ static int encrypt_and_sign_nss (
|
|
|
unsigned char *buf_out,
|
|
unsigned char *buf_out,
|
|
|
size_t *buf_out_len)
|
|
size_t *buf_out_len)
|
|
|
{
|
|
{
|
|
|
- PK11Context* enc_context = NULL;
|
|
|
|
|
- SECStatus rv1, rv2;
|
|
|
|
|
- int tmp1_outlen;
|
|
|
|
|
- unsigned int tmp2_outlen;
|
|
|
|
|
- unsigned char *outdata;
|
|
|
|
|
- SECItem no_params;
|
|
|
|
|
- SECItem iv_item;
|
|
|
|
|
- struct crypto_security_header *header;
|
|
|
|
|
- SECItem *nss_sec_param;
|
|
|
|
|
- unsigned char nss_iv_data[16];
|
|
|
|
|
- SECStatus rv;
|
|
|
|
|
-
|
|
|
|
|
- no_params.type = siBuffer;
|
|
|
|
|
- no_params.data = 0;
|
|
|
|
|
- no_params.len = 0;
|
|
|
|
|
-
|
|
|
|
|
- tmp1_outlen = tmp2_outlen = 0;
|
|
|
|
|
|
|
+ PK11Context* enc_context = NULL;
|
|
|
|
|
+ SECItem crypt_param;
|
|
|
|
|
+ SECItem hash_param;
|
|
|
|
|
+ SECItem *nss_sec_param = NULL;
|
|
|
|
|
+ struct crypto_security_header *header;
|
|
|
|
|
+ unsigned char *outdata;
|
|
|
|
|
+ int tmp1_outlen = 0;
|
|
|
|
|
+ unsigned int tmp2_outlen = 0;
|
|
|
|
|
|
|
|
outdata = buf_out + sizeof (struct crypto_security_header);
|
|
outdata = buf_out + sizeof (struct crypto_security_header);
|
|
|
header = (struct crypto_security_header *)buf_out;
|
|
header = (struct crypto_security_header *)buf_out;
|
|
|
|
|
|
|
|
- rv = PK11_GenerateRandom (
|
|
|
|
|
- nss_iv_data,
|
|
|
|
|
- sizeof (nss_iv_data));
|
|
|
|
|
- if (rv != SECSuccess) {
|
|
|
|
|
|
|
+ memset(header->salt, 0, SALT_SIZE);
|
|
|
|
|
+
|
|
|
|
|
+ if (!cipher_to_nss[instance->crypto_cipher_type]) {
|
|
|
|
|
+ memcpy(outdata, buf_in, buf_in_len);
|
|
|
|
|
+ *buf_out_len = buf_in_len;
|
|
|
|
|
+ goto only_hash;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (PK11_GenerateRandom (header->salt, SALT_SIZE) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
log_printf(instance->log_level_security,
|
|
|
"Failure to generate a random number %d",
|
|
"Failure to generate a random number %d",
|
|
|
PR_GetError());
|
|
PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- memcpy(header->salt, nss_iv_data, sizeof(nss_iv_data));
|
|
|
|
|
- iv_item.type = siBuffer;
|
|
|
|
|
- iv_item.data = nss_iv_data;
|
|
|
|
|
- iv_item.len = sizeof (nss_iv_data);
|
|
|
|
|
|
|
+ crypt_param.type = siBuffer;
|
|
|
|
|
+ crypt_param.data = header->salt;
|
|
|
|
|
+ crypt_param.len = SALT_SIZE;
|
|
|
|
|
|
|
|
- nss_sec_param = PK11_ParamFromIV (
|
|
|
|
|
- cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
- &iv_item);
|
|
|
|
|
|
|
+ nss_sec_param = PK11_ParamFromIV (cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
+ &crypt_param);
|
|
|
if (nss_sec_param == NULL) {
|
|
if (nss_sec_param == NULL) {
|
|
|
log_printf(instance->log_level_security,
|
|
log_printf(instance->log_level_security,
|
|
|
- "Failure to set up PKCS11 param (err %d)",
|
|
|
|
|
- PR_GetError());
|
|
|
|
|
- return (-1);
|
|
|
|
|
|
|
+ "Failure to set up PKCS11 param (err %d)",
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
* Create cipher context for encryption
|
|
* 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);
|
|
|
|
|
|
|
+ enc_context = PK11_CreateContextBySymKey (cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
+ CKA_ENCRYPT,
|
|
|
|
|
+ instance->nss_sym_key,
|
|
|
|
|
+ nss_sec_param);
|
|
|
if (!enc_context) {
|
|
if (!enc_context) {
|
|
|
- char err[1024];
|
|
|
|
|
- PR_GetErrorText(err);
|
|
|
|
|
- err[PR_GetErrorTextLength()] = 0;
|
|
|
|
|
log_printf(instance->log_level_security,
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_CreateContext failed (encrypt) crypt_type=%d (err %d): %s",
|
|
|
|
|
- (int)cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
- PR_GetError(), err);
|
|
|
|
|
- return -1;
|
|
|
|
|
- }
|
|
|
|
|
- rv1 = PK11_CipherOp(enc_context, outdata,
|
|
|
|
|
- &tmp1_outlen, FRAME_SIZE_MAX - sizeof(struct crypto_security_header),
|
|
|
|
|
- (unsigned char *)buf_in, buf_in_len);
|
|
|
|
|
- rv2 = PK11_DigestFinal(enc_context, outdata + tmp1_outlen, &tmp2_outlen,
|
|
|
|
|
- FRAME_SIZE_MAX - tmp1_outlen);
|
|
|
|
|
|
|
+ "PK11_CreateContext failed (encrypt) crypt_type=%d (err %d)",
|
|
|
|
|
+ (int)cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (PK11_CipherOp(enc_context, outdata,
|
|
|
|
|
+ &tmp1_outlen, FRAME_SIZE_MAX - sizeof(struct crypto_security_header),
|
|
|
|
|
+ (unsigned char *)buf_in, buf_in_len) != SECSuccess) {
|
|
|
|
|
+ log_printf(instance->log_level_security,
|
|
|
|
|
+ "PK11_CipherOp failed (encrypt) crypt_type=%d (err %d)",
|
|
|
|
|
+ (int)cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (PK11_DigestFinal(enc_context, outdata + 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)",
|
|
|
|
|
+ (int)cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
PK11_DestroyContext(enc_context, PR_TRUE);
|
|
PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
|
|
|
|
|
*buf_out_len = tmp1_outlen + tmp2_outlen;
|
|
*buf_out_len = tmp1_outlen + tmp2_outlen;
|
|
|
|
|
|
|
|
- if (rv1 != SECSuccess || rv2 != SECSuccess)
|
|
|
|
|
- goto out;
|
|
|
|
|
|
|
+only_hash:
|
|
|
|
|
+
|
|
|
|
|
+ if (!hash_to_nss[instance->crypto_hash_type]) {
|
|
|
|
|
+ goto no_hash;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/* Now do the digest */
|
|
/* Now do the digest */
|
|
|
|
|
+ hash_param.type = siBuffer;
|
|
|
|
|
+ hash_param.data = 0;
|
|
|
|
|
+ hash_param.len = 0;
|
|
|
|
|
+
|
|
|
enc_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type],
|
|
enc_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type],
|
|
|
- CKA_SIGN, instance->nss_sym_key_sign, &no_params);
|
|
|
|
|
|
|
+ CKA_SIGN,
|
|
|
|
|
+ instance->nss_sym_key_sign,
|
|
|
|
|
+ &hash_param);
|
|
|
if (!enc_context) {
|
|
if (!enc_context) {
|
|
|
- char err[1024];
|
|
|
|
|
- PR_GetErrorText(err);
|
|
|
|
|
- err[PR_GetErrorTextLength()] = 0;
|
|
|
|
|
- log_printf(instance->log_level_security, "encrypt: PK11_CreateContext failed (digest) err %d: %s",
|
|
|
|
|
- PR_GetError(), err);
|
|
|
|
|
- return -1;
|
|
|
|
|
|
|
+ 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 (PK11_DigestBegin(enc_context) != SECSuccess) {
|
|
|
|
|
+ log_printf(instance->log_level_security,
|
|
|
|
|
+ "PK11_DigestBegin failed (hash) hash_type=%d (err %d)",
|
|
|
|
|
+ (int)hash_to_nss[instance->crypto_hash_type],
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- PK11_DigestBegin(enc_context);
|
|
|
|
|
-
|
|
|
|
|
- rv1 = PK11_DigestOp(enc_context, outdata - 16, *buf_out_len + 16);
|
|
|
|
|
- rv2 = PK11_DigestFinal(enc_context, header->hash_digest, &tmp2_outlen, sizeof(header->hash_digest));
|
|
|
|
|
|
|
+ if (PK11_DigestOp(enc_context,
|
|
|
|
|
+ outdata - SALT_SIZE,
|
|
|
|
|
+ *buf_out_len + SALT_SIZE) != SECSuccess) {
|
|
|
|
|
+ log_printf(instance->log_level_security,
|
|
|
|
|
+ "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,
|
|
|
|
|
+ header->hash_digest,
|
|
|
|
|
+ &tmp2_outlen,
|
|
|
|
|
+ sizeof(header->hash_digest)) != 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());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
PK11_DestroyContext(enc_context, PR_TRUE);
|
|
PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
|
|
|
|
|
- if (rv1 != SECSuccess || rv2 != SECSuccess)
|
|
|
|
|
- goto out;
|
|
|
|
|
|
|
+no_hash:
|
|
|
|
|
|
|
|
- *buf_out_len = *buf_out_len + sizeof(struct crypto_security_header);
|
|
|
|
|
SECITEM_FreeItem(nss_sec_param, PR_TRUE);
|
|
SECITEM_FreeItem(nss_sec_param, PR_TRUE);
|
|
|
|
|
+
|
|
|
|
|
+ *buf_out_len = *buf_out_len + sizeof(struct crypto_security_header);
|
|
|
|
|
+
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
out:
|
|
out:
|
|
|
|
|
+ if (enc_context) {
|
|
|
|
|
+ PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (nss_sec_param) {
|
|
|
|
|
+ SECITEM_FreeItem(nss_sec_param, PR_TRUE);
|
|
|
|
|
+ }
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
static int authenticate_and_decrypt_nss (
|
|
static int authenticate_and_decrypt_nss (
|
|
|
struct crypto_instance *instance,
|
|
struct crypto_instance *instance,
|
|
|
unsigned char *buf,
|
|
unsigned char *buf,
|
|
|
int *buf_len)
|
|
int *buf_len)
|
|
|
{
|
|
{
|
|
|
- PK11Context* enc_context = NULL;
|
|
|
|
|
- SECStatus rv1, rv2;
|
|
|
|
|
- int tmp1_outlen;
|
|
|
|
|
- unsigned int tmp2_outlen;
|
|
|
|
|
- unsigned char outbuf[FRAME_SIZE_MAX];
|
|
|
|
|
- unsigned char digest[CRYPTO_HMAC_HASH_SIZE];
|
|
|
|
|
- unsigned char *outdata;
|
|
|
|
|
- int result_len;
|
|
|
|
|
- unsigned char *data;
|
|
|
|
|
- unsigned char *inbuf;
|
|
|
|
|
- size_t datalen;
|
|
|
|
|
- struct crypto_security_header *header = (struct crypto_security_header *)buf;
|
|
|
|
|
- SECItem no_params;
|
|
|
|
|
- SECItem ivdata;
|
|
|
|
|
-
|
|
|
|
|
- no_params.type = siBuffer;
|
|
|
|
|
- no_params.data = 0;
|
|
|
|
|
- no_params.len = 0;
|
|
|
|
|
-
|
|
|
|
|
- tmp1_outlen = tmp2_outlen = 0;
|
|
|
|
|
- inbuf = (unsigned char *)buf;
|
|
|
|
|
|
|
+ PK11Context* enc_context = NULL;
|
|
|
|
|
+ int tmp1_outlen = 0;
|
|
|
|
|
+ unsigned int tmp2_outlen = 0;
|
|
|
|
|
+ unsigned char outbuf[FRAME_SIZE_MAX];
|
|
|
|
|
+ unsigned char digest[CRYPTO_HMAC_HASH_SIZE];
|
|
|
|
|
+ unsigned char *outdata;
|
|
|
|
|
+ int result_len;
|
|
|
|
|
+ unsigned char *data;
|
|
|
|
|
+ size_t datalen;
|
|
|
|
|
+ struct crypto_security_header *header = (struct crypto_security_header *)buf;
|
|
|
|
|
+ SECItem crypt_param;
|
|
|
|
|
+ SECItem hash_param;
|
|
|
|
|
+
|
|
|
datalen = *buf_len;
|
|
datalen = *buf_len;
|
|
|
- data = inbuf + sizeof (struct crypto_security_header) - 16;
|
|
|
|
|
- datalen = datalen - sizeof (struct crypto_security_header) + 16;
|
|
|
|
|
|
|
+ data = buf + sizeof (struct crypto_security_header) - SALT_SIZE;
|
|
|
|
|
+ datalen = datalen - sizeof (struct crypto_security_header) + SALT_SIZE;
|
|
|
|
|
|
|
|
outdata = outbuf + sizeof (struct crypto_security_header);
|
|
outdata = outbuf + sizeof (struct crypto_security_header);
|
|
|
|
|
|
|
|
|
|
+ if (!hash_to_nss[instance->crypto_hash_type]) {
|
|
|
|
|
+ goto only_decrypt;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ hash_param.type = siBuffer;
|
|
|
|
|
+ hash_param.data = 0;
|
|
|
|
|
+ hash_param.len = 0;
|
|
|
|
|
+
|
|
|
/* Check the digest */
|
|
/* Check the digest */
|
|
|
- enc_context = PK11_CreateContextBySymKey (
|
|
|
|
|
- hash_to_nss[instance->crypto_hash_type], CKA_SIGN,
|
|
|
|
|
- instance->nss_sym_key_sign,
|
|
|
|
|
- &no_params);
|
|
|
|
|
|
|
+ enc_context = PK11_CreateContextBySymKey (hash_to_nss[instance->crypto_hash_type],
|
|
|
|
|
+ CKA_SIGN,
|
|
|
|
|
+ instance->nss_sym_key_sign,
|
|
|
|
|
+ &hash_param);
|
|
|
if (!enc_context) {
|
|
if (!enc_context) {
|
|
|
- char err[1024];
|
|
|
|
|
- PR_GetErrorText(err);
|
|
|
|
|
- err[PR_GetErrorTextLength()] = 0;
|
|
|
|
|
- log_printf(instance->log_level_security, "PK11_CreateContext failed (check digest) err %d: %s",
|
|
|
|
|
- PR_GetError(), err);
|
|
|
|
|
- return -1;
|
|
|
|
|
|
|
+ log_printf(instance->log_level_security,
|
|
|
|
|
+ "PK11_CreateContext failed (check digest) err %d",
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- PK11_DigestBegin(enc_context);
|
|
|
|
|
-
|
|
|
|
|
- rv1 = PK11_DigestOp(enc_context, data, datalen);
|
|
|
|
|
- rv2 = PK11_DigestFinal(enc_context, digest, &tmp2_outlen, sizeof(digest));
|
|
|
|
|
|
|
+ if (PK11_DigestBegin(enc_context) != SECSuccess) {
|
|
|
|
|
+ log_printf(instance->log_level_security,
|
|
|
|
|
+ "PK11_DigestBegin failed (check digest) err %d",
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
|
|
|
|
+ if (PK11_DigestOp(enc_context, data, datalen) != SECSuccess) {
|
|
|
|
|
+ log_printf(instance->log_level_security,
|
|
|
|
|
+ "PK11_DigestOp failed (check digest) err %d",
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (rv1 != SECSuccess || rv2 != SECSuccess) {
|
|
|
|
|
- log_printf(instance->log_level_security, "Digest check failed");
|
|
|
|
|
- return -1;
|
|
|
|
|
|
|
+ if (PK11_DigestFinal(enc_context, digest,
|
|
|
|
|
+ &tmp2_outlen, sizeof(digest)) != SECSuccess) {
|
|
|
|
|
+ log_printf(instance->log_level_security,
|
|
|
|
|
+ "PK11_DigestFinal failed (check digest) err %d",
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
|
|
+
|
|
|
if (memcmp(digest, header->hash_digest, tmp2_outlen) != 0) {
|
|
if (memcmp(digest, header->hash_digest, tmp2_outlen) != 0) {
|
|
|
log_printf(instance->log_level_error, "Digest does not match");
|
|
log_printf(instance->log_level_error, "Digest does not match");
|
|
|
- return -1;
|
|
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+only_decrypt:
|
|
|
|
|
+
|
|
|
|
|
+ if (!cipher_to_nss[instance->crypto_cipher_type]) {
|
|
|
|
|
+ memcpy(outbuf, buf + sizeof (struct crypto_security_header), *buf_len - sizeof (struct crypto_security_header));
|
|
|
|
|
+ outdata = outbuf;
|
|
|
|
|
+ result_len = *buf_len - sizeof (struct crypto_security_header);
|
|
|
|
|
+ goto no_decrypt;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
|
* Get rid of salt
|
|
* Get rid of salt
|
|
|
*/
|
|
*/
|
|
|
- data += 16;
|
|
|
|
|
- datalen -= 16;
|
|
|
|
|
|
|
+ data += SALT_SIZE;
|
|
|
|
|
+ datalen -= SALT_SIZE;
|
|
|
|
|
|
|
|
/* Create cipher context for decryption */
|
|
/* Create cipher context for decryption */
|
|
|
- ivdata.type = siBuffer;
|
|
|
|
|
- ivdata.data = header->salt;
|
|
|
|
|
- ivdata.len = sizeof(header->salt);
|
|
|
|
|
-
|
|
|
|
|
- enc_context = PK11_CreateContextBySymKey(
|
|
|
|
|
- cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
- CKA_DECRYPT,
|
|
|
|
|
- instance->nss_sym_key, &ivdata);
|
|
|
|
|
|
|
+ crypt_param.type = siBuffer;
|
|
|
|
|
+ crypt_param.data = header->salt;
|
|
|
|
|
+ crypt_param.len = SALT_SIZE;
|
|
|
|
|
+
|
|
|
|
|
+ enc_context = PK11_CreateContextBySymKey(cipher_to_nss[instance->crypto_cipher_type],
|
|
|
|
|
+ CKA_DECRYPT,
|
|
|
|
|
+ instance->nss_sym_key, &crypt_param);
|
|
|
if (!enc_context) {
|
|
if (!enc_context) {
|
|
|
log_printf(instance->log_level_security,
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_CreateContext (decrypt) failed (err %d)",
|
|
|
|
|
- PR_GetError());
|
|
|
|
|
- return -1;
|
|
|
|
|
|
|
+ "PK11_CreateContext (decrypt) failed (err %d)",
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- rv1 = PK11_CipherOp(enc_context, outdata, &tmp1_outlen,
|
|
|
|
|
- sizeof(outbuf) - sizeof (struct crypto_security_header),
|
|
|
|
|
- data, datalen);
|
|
|
|
|
- if (rv1 != SECSuccess) {
|
|
|
|
|
|
|
+ if (PK11_CipherOp(enc_context, outdata, &tmp1_outlen,
|
|
|
|
|
+ sizeof(outbuf) - sizeof (struct crypto_security_header),
|
|
|
|
|
+ data, datalen) != SECSuccess) {
|
|
|
log_printf(instance->log_level_security,
|
|
log_printf(instance->log_level_security,
|
|
|
- "PK11_CipherOp (decrypt) failed (err %d)",
|
|
|
|
|
- PR_GetError());
|
|
|
|
|
|
|
+ "PK11_CipherOp (decrypt) failed (err %d)",
|
|
|
|
|
+ PR_GetError());
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (PK11_DigestFinal(enc_context, outdata + 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;
|
|
|
}
|
|
}
|
|
|
- rv2 = PK11_DigestFinal(enc_context, outdata + tmp1_outlen, &tmp2_outlen,
|
|
|
|
|
- sizeof(outbuf) - tmp1_outlen);
|
|
|
|
|
|
|
+
|
|
|
PK11_DestroyContext(enc_context, PR_TRUE);
|
|
PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
|
|
+
|
|
|
result_len = tmp1_outlen + tmp2_outlen + sizeof (struct crypto_security_header);
|
|
result_len = tmp1_outlen + tmp2_outlen + sizeof (struct crypto_security_header);
|
|
|
|
|
|
|
|
|
|
+no_decrypt:
|
|
|
|
|
+
|
|
|
memset(buf, 0, *buf_len);
|
|
memset(buf, 0, *buf_len);
|
|
|
memcpy(buf, outdata, result_len);
|
|
memcpy(buf, outdata, result_len);
|
|
|
|
|
|
|
|
*buf_len = result_len;
|
|
*buf_len = result_len;
|
|
|
|
|
|
|
|
- if (rv1 != SECSuccess || rv2 != SECSuccess)
|
|
|
|
|
- return -1;
|
|
|
|
|
-
|
|
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
+
|
|
|
|
|
+out:
|
|
|
|
|
+ if (enc_context) {
|
|
|
|
|
+ PK11_DestroyContext(enc_context, PR_TRUE);
|
|
|
|
|
+ }
|
|
|
|
|
+ return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-size_t crypto_sec_header_size(const char *crypto_hash_type)
|
|
|
|
|
|
|
+size_t crypto_sec_header_size(
|
|
|
|
|
+ const char *crypto_cipher_type,
|
|
|
|
|
+ const char *crypto_hash_type)
|
|
|
{
|
|
{
|
|
|
/*
|
|
/*
|
|
|
- * TODO: add switch / size mapping
|
|
|
|
|
|
|
+ * TODO: crypto_cipher_type determines the crypto BLOCK size
|
|
|
|
|
+ * crypto_hash_type determines the HASH_SIZE
|
|
|
*/
|
|
*/
|
|
|
return sizeof(struct crypto_security_header);
|
|
return sizeof(struct crypto_security_header);
|
|
|
}
|
|
}
|
|
@@ -447,6 +534,16 @@ int crypto_encrypt_and_sign (
|
|
|
unsigned char *buf_out,
|
|
unsigned char *buf_out,
|
|
|
size_t *buf_out_len)
|
|
size_t *buf_out_len)
|
|
|
{
|
|
{
|
|
|
|
|
+ /*
|
|
|
|
|
+ * if crypto is totally disabled, let's skip complex parsing
|
|
|
|
|
+ */
|
|
|
|
|
+ if ((!cipher_to_nss[instance->crypto_cipher_type]) &&
|
|
|
|
|
+ (!hash_to_nss[instance->crypto_hash_type])) {
|
|
|
|
|
+ memcpy(buf_out, buf_in, buf_in_len);
|
|
|
|
|
+ *buf_out_len = buf_in_len;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return (encrypt_and_sign_nss(instance, buf_in, buf_in_len, buf_out, buf_out_len));
|
|
return (encrypt_and_sign_nss(instance, buf_in, buf_in_len, buf_out, buf_out_len));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -454,6 +551,14 @@ int crypto_authenticate_and_decrypt (struct crypto_instance *instance,
|
|
|
unsigned char *buf,
|
|
unsigned char *buf,
|
|
|
int *buf_len)
|
|
int *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])) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return (authenticate_and_decrypt_nss(instance, buf, buf_len));
|
|
return (authenticate_and_decrypt_nss(instance, buf, buf_len));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -503,7 +608,10 @@ struct crypto_instance *crypto_init(
|
|
|
instance->log_level_error = log_level_error;
|
|
instance->log_level_error = log_level_error;
|
|
|
instance->log_subsys_id = log_subsys_id;
|
|
instance->log_subsys_id = log_subsys_id;
|
|
|
|
|
|
|
|
- init_nss_crypto(instance);
|
|
|
|
|
|
|
+ if (init_nss_crypto(instance, crypto_cipher_type, crypto_hash_type) < 0) {
|
|
|
|
|
+ free(instance);
|
|
|
|
|
+ return(NULL);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
return (instance);
|
|
return (instance);
|
|
|
}
|
|
}
|