Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/libknet/common.c b/libknet/common.c
index 437e5392..2da535d3 100644
--- a/libknet/common.c
+++ b/libknet/common.c
@@ -1,203 +1,200 @@
/*
* Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved.
*
* Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <unistd.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <errno.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include "logging.h"
#include "common.h"
int _fdset_cloexec(int fd)
{
int fdflags;
fdflags = fcntl(fd, F_GETFD, 0);
if (fdflags < 0)
return -1;
fdflags |= FD_CLOEXEC;
if (fcntl(fd, F_SETFD, fdflags) < 0)
return -1;
return 0;
}
int _fdset_nonblock(int fd)
{
int fdflags;
fdflags = fcntl(fd, F_GETFL, 0);
if (fdflags < 0)
return -1;
fdflags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, fdflags) < 0)
return -1;
return 0;
}
void *open_lib(knet_handle_t knet_h, const char *libname, int extra_flags)
{
void *ret = NULL;
char *error = NULL;
char dir[MAXPATHLEN], path[MAXPATHLEN], link[MAXPATHLEN];
struct stat sb;
/*
* clear any pending error
*/
dlerror();
ret = dlopen(libname, RTLD_NOW | RTLD_GLOBAL | extra_flags);
error = dlerror();
if (error != NULL) {
log_err(knet_h, KNET_SUB_COMMON, "unable to dlopen %s: %s",
libname, error);
errno = EAGAIN;
return NULL;
}
memset(dir, 0, sizeof(dir));
memset(link, 0, sizeof(link));
memset(path, 0, sizeof(path));
if (dlinfo(ret, RTLD_DI_ORIGIN, &dir) < 0) {
/*
* should we dlclose and return error?
*/
log_warn(knet_h, KNET_SUB_COMMON, "unable to dlinfo %s: %s",
libname, error);
} else {
snprintf(path, sizeof(path), "%s/%s", dir, libname);
log_info(knet_h, KNET_SUB_COMMON, "%s has been loaded from %s", libname, path);
/*
* try to resolve the library and check if it is a symlink and to where.
* we can't prevent symlink attacks but at least we can log where the library
* has been loaded from
*/
if (lstat(path, &sb) < 0) {
log_debug(knet_h, KNET_SUB_COMMON, "Unable to stat %s: %s", path, strerror(errno));
goto out;
}
if (S_ISLNK(sb.st_mode)) {
if (readlink(path, link, sizeof(link)) < 0) {
log_debug(knet_h, KNET_SUB_COMMON, "Unable to readlink %s: %s", path, strerror(errno));
goto out;
}
/*
* symlink is relative to the directory
*/
if (link[0] != '/') {
snprintf(path, sizeof(path), "%s/%s", dir, link);
log_info(knet_h, KNET_SUB_COMMON, "%s/%s is a symlink to %s", dir, libname, path);
} else {
log_info(knet_h, KNET_SUB_COMMON, "%s/%s is a symlink to %s", dir, libname, link);
}
}
}
out:
return ret;
}
/* Separate these into compress.c and crypto.c or keep them together? */
int load_compress_lib(knet_handle_t knet_h, compress_model_t *model)
{
void *module;
log_msg_t **log_msg_sym;
compress_model_t *module_cmds;
char soname[MAXPATHLEN];
const char model_sym[] = "compress_model";
if (model->loaded) {
return 0;
}
snprintf (soname, sizeof soname, "compress_%s.so", model->model_name);
module = open_lib(knet_h, soname, 0);
if (!module) {
return -1;
}
log_msg_sym = dlsym (module, "log_msg");
if (!log_msg_sym) {
log_err (knet_h, KNET_SUB_COMPRESS, "unable to map symbol log_msg in module %s: %s",
soname, dlerror ());
errno = EINVAL;
return -1;
}
*log_msg_sym = log_msg;
module_cmds = dlsym (module, model_sym);
if (!module_cmds) {
log_err (knet_h, KNET_SUB_COMPRESS, "unable to map symbol %s in module %s: %s",
model_sym, soname, dlerror ());
errno = EINVAL;
return -1;
}
model->is_init = module_cmds->is_init;
model->init = module_cmds->init;
model->fini = module_cmds->fini;
model->val_level = module_cmds->val_level;
model->compress = module_cmds->compress;
model->decompress = module_cmds->decompress;
return 0;
}
int load_crypto_lib(knet_handle_t knet_h, crypto_model_t *model)
{
void *module;
log_msg_t **log_msg_sym;
crypto_model_t *module_cmds;
char soname[MAXPATHLEN];
const char model_sym[] = "crypto_model";
if (model->loaded) {
return 0;
}
snprintf (soname, sizeof soname, "crypto_%s.so", model->model_name);
module = open_lib(knet_h, soname, 0);
if (!module) {
return -1;
}
log_msg_sym = dlsym (module, "log_msg");
if (!log_msg_sym) {
log_err (knet_h, KNET_SUB_COMPRESS, "unable to map symbol log_msg in module %s: %s",
soname, dlerror ());
errno = EINVAL;
return -1;
}
*log_msg_sym = log_msg;
module_cmds = dlsym (module, model_sym);
if (!module_cmds) {
log_err (knet_h, KNET_SUB_CRYPTO, "unable to map symbol %s in module %s: %s",
model_sym, soname, dlerror ());
errno = EINVAL;
return -1;
}
- if (module_cmds->load_lib && (*module_cmds->load_lib)(knet_h)) {
- return -1;
- }
model->init = module_cmds->init;
model->fini = module_cmds->fini;
model->crypt = module_cmds->crypt;
model->cryptv = module_cmds->cryptv;
model->decrypt = module_cmds->decrypt;
return 0;
}
diff --git a/libknet/crypto_nss.c b/libknet/crypto_nss.c
index 70ca81fd..ec7a5094 100644
--- a/libknet/crypto_nss.c
+++ b/libknet/crypto_nss.c
@@ -1,807 +1,803 @@
/*
* Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved.
*
* Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#define KNET_MODULE
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <nss.h>
#include <nspr.h>
#include <pk11pub.h>
#include <pkcs11.h>
#include <prerror.h>
#include <blapit.h>
#include <hasht.h>
#include <pthread.h>
#include <secerr.h>
#include <prinit.h>
#include "crypto_model.h"
#include "logging.h"
static int nss_db_is_init = 0;
-static int at_exit_registered = 0;
static void nss_atexit_handler(void)
{
if (nss_db_is_init) {
NSS_Shutdown();
if (PR_Initialized()) {
PL_ArenaFinish();
PR_Cleanup();
}
}
return;
}
-static int nsscrypto_load_lib(
- knet_handle_t knet_h)
-{
- if (!at_exit_registered) {
- if (atexit(nss_atexit_handler)) {
- log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to register NSS atexit handler");
- errno = EAGAIN;
- return -1;
- }
- at_exit_registered = 1;
- }
-
- if (!nss_db_is_init) {
- if (NSS_NoDB_Init(".") != SECSuccess) {
- log_err(knet_h, KNET_SUB_NSSCRYPTO, "NSS DB initialization failed (err %d): %s",
- PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
- errno = EAGAIN;
- return -1;
- }
- nss_db_is_init = 1;
- }
- return 0;
-}
-
/*
* crypto definitions and conversion tables
*/
#define SALT_SIZE 16
/*
* This are defined in new NSS. For older one, we will define our own
*/
#ifndef AES_256_KEY_LENGTH
#define AES_256_KEY_LENGTH 32
#endif
#ifndef AES_192_KEY_LENGTH
#define AES_192_KEY_LENGTH 24
#endif
#ifndef AES_128_KEY_LENGTH
#define AES_128_KEY_LENGTH 16
#endif
enum nsscrypto_crypt_t {
CRYPTO_CIPHER_TYPE_NONE = 0,
CRYPTO_CIPHER_TYPE_AES256 = 1,
CRYPTO_CIPHER_TYPE_AES192 = 2,
CRYPTO_CIPHER_TYPE_AES128 = 3,
CRYPTO_CIPHER_TYPE_3DES = 4
};
CK_MECHANISM_TYPE cipher_to_nss[] = {
0, /* CRYPTO_CIPHER_TYPE_NONE */
CKM_AES_CBC_PAD, /* CRYPTO_CIPHER_TYPE_AES256 */
CKM_AES_CBC_PAD, /* CRYPTO_CIPHER_TYPE_AES192 */
CKM_AES_CBC_PAD, /* CRYPTO_CIPHER_TYPE_AES128 */
CKM_DES3_CBC_PAD /* CRYPTO_CIPHER_TYPE_3DES */
};
size_t nsscipher_key_len[] = {
0, /* CRYPTO_CIPHER_TYPE_NONE */
AES_256_KEY_LENGTH, /* CRYPTO_CIPHER_TYPE_AES256 */
AES_192_KEY_LENGTH, /* CRYPTO_CIPHER_TYPE_AES192 */
AES_128_KEY_LENGTH, /* CRYPTO_CIPHER_TYPE_AES128 */
24 /* CRYPTO_CIPHER_TYPE_3DES */
};
size_t nsscypher_block_len[] = {
0, /* CRYPTO_CIPHER_TYPE_NONE */
AES_BLOCK_SIZE, /* CRYPTO_CIPHER_TYPE_AES256 */
AES_BLOCK_SIZE, /* CRYPTO_CIPHER_TYPE_AES192 */
AES_BLOCK_SIZE, /* CRYPTO_CIPHER_TYPE_AES128 */
0 /* CRYPTO_CIPHER_TYPE_3DES */
};
/*
* hash definitions and conversion tables
*/
enum nsscrypto_hash_t {
CRYPTO_HASH_TYPE_NONE = 0,
CRYPTO_HASH_TYPE_MD5 = 1,
CRYPTO_HASH_TYPE_SHA1 = 2,
CRYPTO_HASH_TYPE_SHA256 = 3,
CRYPTO_HASH_TYPE_SHA384 = 4,
CRYPTO_HASH_TYPE_SHA512 = 5
};
CK_MECHANISM_TYPE hash_to_nss[] = {
0, /* CRYPTO_HASH_TYPE_NONE */
CKM_MD5_HMAC, /* CRYPTO_HASH_TYPE_MD5 */
CKM_SHA_1_HMAC, /* CRYPTO_HASH_TYPE_SHA1 */
CKM_SHA256_HMAC, /* CRYPTO_HASH_TYPE_SHA256 */
CKM_SHA384_HMAC, /* CRYPTO_HASH_TYPE_SHA384 */
CKM_SHA512_HMAC /* CRYPTO_HASH_TYPE_SHA512 */
};
size_t nsshash_len[] = {
0, /* CRYPTO_HASH_TYPE_NONE */
MD5_LENGTH, /* CRYPTO_HASH_TYPE_MD5 */
SHA1_LENGTH, /* CRYPTO_HASH_TYPE_SHA1 */
SHA256_LENGTH, /* CRYPTO_HASH_TYPE_SHA256 */
SHA384_LENGTH, /* CRYPTO_HASH_TYPE_SHA384 */
SHA512_LENGTH /* CRYPTO_HASH_TYPE_SHA512 */
};
enum sym_key_type {
SYM_KEY_TYPE_CRYPT,
SYM_KEY_TYPE_HASH
};
struct nsscrypto_instance {
PK11SymKey *nss_sym_key;
PK11SymKey *nss_sym_key_sign;
unsigned char *private_key;
unsigned int private_key_len;
int crypto_cipher_type;
int crypto_hash_type;
};
/*
* crypt/decrypt functions
*/
static int nssstring_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;
} else if (strcmp(crypto_cipher_type, "aes192") == 0) {
return CRYPTO_CIPHER_TYPE_AES192;
} else if (strcmp(crypto_cipher_type, "aes128") == 0) {
return CRYPTO_CIPHER_TYPE_AES128;
} else if (strcmp(crypto_cipher_type, "3des") == 0) {
return CRYPTO_CIPHER_TYPE_3DES;
}
return -1;
}
static PK11SymKey *nssimport_symmetric_key(knet_handle_t knet_h, enum sym_key_type key_type)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
SECItem key_item;
PK11SlotInfo *slot;
PK11SymKey *res_key;
CK_MECHANISM_TYPE cipher;
CK_ATTRIBUTE_TYPE operation;
CK_MECHANISM_TYPE wrap_mechanism;
int wrap_key_len;
PK11SymKey *wrap_key;
PK11Context *wrap_key_crypt_context;
SECItem tmp_sec_item;
SECItem wrapped_key;
int wrapped_key_len;
unsigned char wrapped_key_data[KNET_MAX_KEY_LEN];
memset(&key_item, 0, sizeof(key_item));
slot = NULL;
wrap_key = NULL;
res_key = NULL;
wrap_key_crypt_context = NULL;
key_item.type = siBuffer;
key_item.data = instance->private_key;
switch (key_type) {
case SYM_KEY_TYPE_CRYPT:
key_item.len = nsscipher_key_len[instance->crypto_cipher_type];
cipher = cipher_to_nss[instance->crypto_cipher_type];
operation = CKA_ENCRYPT|CKA_DECRYPT;
break;
case SYM_KEY_TYPE_HASH:
key_item.len = instance->private_key_len;
cipher = hash_to_nss[instance->crypto_hash_type];
operation = CKA_SIGN;
break;
default:
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Import symmetric key failed. Unknown keyimport request");
goto exit_res_key;
break;
}
slot = PK11_GetBestSlot(cipher, NULL);
if (slot == NULL) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to find security slot (%d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto exit_res_key;
}
/*
* Without FIPS it would be possible to just use
* res_key = PK11_ImportSymKey(slot, cipher, PK11_OriginUnwrap, operation, &key_item, NULL);
* with FIPS NSS Level 2 certification has to be "workarounded" (so it becomes Level 1) by using
* following method:
* 1. Generate wrap key
* 2. Encrypt authkey with wrap key
* 3. Unwrap encrypted authkey using wrap key
*/
/*
* Generate wrapping key
*/
wrap_mechanism = PK11_GetBestWrapMechanism(slot);
wrap_key_len = PK11_GetBestKeyLength(slot, wrap_mechanism);
wrap_key = PK11_KeyGen(slot, wrap_mechanism, NULL, wrap_key_len, NULL);
if (wrap_key == NULL) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to generate wrapping key (%d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto exit_res_key;
}
/*
* Encrypt authkey with wrapping key
*/
/*
* Initialization of IV is not needed because PK11_GetBestWrapMechanism should return ECB mode
*/
memset(&tmp_sec_item, 0, sizeof(tmp_sec_item));
wrap_key_crypt_context = PK11_CreateContextBySymKey(wrap_mechanism, CKA_ENCRYPT,
wrap_key, &tmp_sec_item);
if (wrap_key_crypt_context == NULL) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to create encrypt context (%d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto exit_res_key;
}
wrapped_key_len = (int)sizeof(wrapped_key_data);
if (PK11_CipherOp(wrap_key_crypt_context, wrapped_key_data, &wrapped_key_len,
sizeof(wrapped_key_data), key_item.data, key_item.len) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to encrypt authkey (%d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto exit_res_key;
}
if (PK11_Finalize(wrap_key_crypt_context) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to finalize encryption of authkey (%d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto exit_res_key;
}
/*
* Finally unwrap sym key
*/
memset(&tmp_sec_item, 0, sizeof(tmp_sec_item));
wrapped_key.data = wrapped_key_data;
wrapped_key.len = wrapped_key_len;
res_key = PK11_UnwrapSymKey(wrap_key, wrap_mechanism, &tmp_sec_item, &wrapped_key,
cipher, operation, key_item.len);
if (res_key == NULL) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to import key into NSS (%d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
if (PR_GetError() == SEC_ERROR_BAD_DATA) {
/*
* Maximum key length for FIPS enabled softtoken is limited to
* MAX_KEY_LEN (pkcs11i.h - 256) and checked in NSC_UnwrapKey. Returned
* error is CKR_TEMPLATE_INCONSISTENT which is mapped to SEC_ERROR_BAD_DATA.
*/
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Secret key is probably too long. "
"Try reduce it to 256 bytes");
}
goto exit_res_key;
}
exit_res_key:
if (wrap_key_crypt_context != NULL) {
PK11_DestroyContext(wrap_key_crypt_context, PR_TRUE);
}
if (wrap_key != NULL) {
PK11_FreeSymKey(wrap_key);
}
if (slot != NULL) {
PK11_FreeSlot(slot);
}
return (res_key);
}
static int init_nss_crypto(knet_handle_t knet_h)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
if (!cipher_to_nss[instance->crypto_cipher_type]) {
return 0;
}
instance->nss_sym_key = nssimport_symmetric_key(knet_h, SYM_KEY_TYPE_CRYPT);
if (instance->nss_sym_key == NULL) {
return -1;
}
return 0;
}
static int encrypt_nss(
knet_handle_t knet_h,
const struct iovec *iov,
int iovcnt,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
PK11Context* crypt_context = NULL;
SECItem crypt_param;
SECItem *nss_sec_param = NULL;
int tmp_outlen = 0, tmp1_outlen = 0;
unsigned int tmp2_outlen = 0;
unsigned char *salt = buf_out;
unsigned char *data = buf_out + SALT_SIZE;
int err = -1;
int i;
if (PK11_GenerateRandom(salt, SALT_SIZE) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to generate a random number (err %d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
crypt_param.type = siBuffer;
crypt_param.data = salt;
crypt_param.len = SALT_SIZE;
nss_sec_param = PK11_ParamFromIV(cipher_to_nss[instance->crypto_cipher_type],
&crypt_param);
if (nss_sec_param == NULL) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to set up PKCS11 param (err %d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
/*
* Create cipher context for encryption
*/
crypt_context = PK11_CreateContextBySymKey(cipher_to_nss[instance->crypto_cipher_type],
CKA_ENCRYPT,
instance->nss_sym_key,
nss_sec_param);
if (!crypt_context) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext failed (encrypt) crypt_type=%d (err %d): %s",
(int)cipher_to_nss[instance->crypto_cipher_type],
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
for (i=0; i<iovcnt; i++) {
if (PK11_CipherOp(crypt_context, data,
&tmp_outlen,
KNET_DATABUFSIZE_CRYPT,
(unsigned char *)iov[i].iov_base,
iov[i].iov_len) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CipherOp failed (encrypt) crypt_type=%d (err %d): %s",
(int)cipher_to_nss[instance->crypto_cipher_type],
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
tmp1_outlen = tmp1_outlen + tmp_outlen;
}
if (PK11_DigestFinal(crypt_context, data + tmp1_outlen,
&tmp2_outlen, KNET_DATABUFSIZE_CRYPT - tmp1_outlen) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinal failed (encrypt) crypt_type=%d (err %d): %s",
(int)cipher_to_nss[instance->crypto_cipher_type],
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
*buf_out_len = tmp1_outlen + tmp2_outlen + SALT_SIZE;
err = 0;
out:
if (crypt_context) {
PK11_DestroyContext(crypt_context, PR_TRUE);
}
if (nss_sec_param) {
SECITEM_FreeItem(nss_sec_param, PR_TRUE);
}
return err;
}
static int decrypt_nss (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
PK11Context* decrypt_context = NULL;
SECItem decrypt_param;
int tmp1_outlen = 0;
unsigned int tmp2_outlen = 0;
unsigned char *salt = (unsigned char *)buf_in;
unsigned char *data = salt + SALT_SIZE;
int datalen = buf_in_len - SALT_SIZE;
int err = -1;
/* 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_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext (decrypt) failed (err %d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
if (PK11_CipherOp(decrypt_context, buf_out, &tmp1_outlen,
KNET_DATABUFSIZE_CRYPT, data, datalen) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CipherOp (decrypt) failed (err %d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
if (PK11_DigestFinal(decrypt_context, buf_out + tmp1_outlen, &tmp2_outlen,
KNET_DATABUFSIZE_CRYPT - tmp1_outlen) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinal (decrypt) failed (err %d): %s",
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
*buf_out_len = tmp1_outlen + tmp2_outlen;
err = 0;
out:
if (decrypt_context) {
PK11_DestroyContext(decrypt_context, PR_TRUE);
}
return err;
}
/*
* hash/hmac/digest functions
*/
static int nssstring_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;
}
static int init_nss_hash(knet_handle_t knet_h)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
if (!hash_to_nss[instance->crypto_hash_type]) {
return 0;
}
instance->nss_sym_key_sign = nssimport_symmetric_key(knet_h, SYM_KEY_TYPE_HASH);
if (instance->nss_sym_key_sign == NULL) {
return -1;
}
return 0;
}
static int calculate_nss_hash(
knet_handle_t knet_h,
const unsigned char *buf,
const size_t buf_len,
unsigned char *hash)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
PK11Context* hash_context = NULL;
SECItem hash_param;
unsigned int hash_tmp_outlen = 0;
int err = -1;
/* Now do the digest */
hash_param.type = siBuffer;
hash_param.data = 0;
hash_param.len = 0;
hash_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type],
CKA_SIGN,
instance->nss_sym_key_sign,
&hash_param);
if (!hash_context) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext failed (hash) hash_type=%d (err %d): %s",
(int)hash_to_nss[instance->crypto_hash_type],
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
if (PK11_DigestBegin(hash_context) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestBegin failed (hash) hash_type=%d (err %d): %s",
(int)hash_to_nss[instance->crypto_hash_type],
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
if (PK11_DigestOp(hash_context, buf, buf_len) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestOp failed (hash) hash_type=%d (err %d): %s",
(int)hash_to_nss[instance->crypto_hash_type],
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
if (PK11_DigestFinal(hash_context, hash,
&hash_tmp_outlen, nsshash_len[instance->crypto_hash_type]) != SECSuccess) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinale failed (hash) hash_type=%d (err %d): %s",
(int)hash_to_nss[instance->crypto_hash_type],
PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
goto out;
}
err = 0;
out:
if (hash_context) {
PK11_DestroyContext(hash_context, PR_TRUE);
}
return err;
}
/*
* global/glue nss functions
*/
static int init_nss(knet_handle_t knet_h)
{
+ static int at_exit_registered = 0;
+
+ if (!at_exit_registered) {
+ if (atexit(nss_atexit_handler)) {
+ log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to register NSS atexit handler");
+ errno = EAGAIN;
+ return -1;
+ }
+ at_exit_registered = 1;
+ }
+
+ if (!nss_db_is_init) {
+ if (NSS_NoDB_Init(".") != SECSuccess) {
+ log_err(knet_h, KNET_SUB_NSSCRYPTO, "NSS DB initialization failed (err %d): %s",
+ PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
+ errno = EAGAIN;
+ return -1;
+ }
+ nss_db_is_init = 1;
+ }
+
if (init_nss_crypto(knet_h) < 0) {
return -1;
}
if (init_nss_hash(knet_h) < 0) {
return -1;
}
return 0;
}
/*
* exported API
*/
static int nsscrypto_encrypt_and_signv (
knet_handle_t knet_h,
const struct iovec *iov_in,
int iovcnt_in,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
int i;
if (cipher_to_nss[instance->crypto_cipher_type]) {
if (encrypt_nss(knet_h, iov_in, iovcnt_in, buf_out, buf_out_len) < 0) {
return -1;
}
} else {
*buf_out_len = 0;
for (i=0; i<iovcnt_in; i++) {
memmove(buf_out + *buf_out_len, iov_in[i].iov_base, iov_in[i].iov_len);
*buf_out_len = *buf_out_len + iov_in[i].iov_len;
}
}
if (hash_to_nss[instance->crypto_hash_type]) {
if (calculate_nss_hash(knet_h, buf_out, *buf_out_len, buf_out + *buf_out_len) < 0) {
return -1;
}
*buf_out_len = *buf_out_len + nsshash_len[instance->crypto_hash_type];
}
return 0;
}
static int nsscrypto_encrypt_and_sign (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct iovec iov_in;
memset(&iov_in, 0, sizeof(iov_in));
iov_in.iov_base = (unsigned char *)buf_in;
iov_in.iov_len = buf_in_len;
return nsscrypto_encrypt_and_signv(knet_h, &iov_in, 1, buf_out, buf_out_len);
}
static int nsscrypto_authenticate_and_decrypt (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance;
ssize_t temp_len = buf_in_len;
if (hash_to_nss[instance->crypto_hash_type]) {
unsigned char tmp_hash[nsshash_len[instance->crypto_hash_type]];
ssize_t temp_buf_len = buf_in_len - nsshash_len[instance->crypto_hash_type];
if ((temp_buf_len < 0) || (temp_buf_len > KNET_MAX_PACKET_SIZE)) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Incorrect packet size.");
return -1;
}
if (calculate_nss_hash(knet_h, buf_in, temp_buf_len, tmp_hash) < 0) {
return -1;
}
if (memcmp(tmp_hash, buf_in + temp_buf_len, nsshash_len[instance->crypto_hash_type]) != 0) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Digest does not match");
return -1;
}
temp_len = temp_len - nsshash_len[instance->crypto_hash_type];
*buf_out_len = temp_len;
}
if (cipher_to_nss[instance->crypto_cipher_type]) {
if (decrypt_nss(knet_h, buf_in, temp_len, buf_out, buf_out_len) < 0) {
return -1;
}
} else {
memmove(buf_out, buf_in, temp_len);
*buf_out_len = temp_len;
}
return 0;
}
static void nsscrypto_fini(
knet_handle_t knet_h)
{
struct nsscrypto_instance *nsscrypto_instance = knet_h->crypto_instance->model_instance;
if (nsscrypto_instance) {
if (nsscrypto_instance->nss_sym_key) {
PK11_FreeSymKey(nsscrypto_instance->nss_sym_key);
nsscrypto_instance->nss_sym_key = NULL;
}
if (nsscrypto_instance->nss_sym_key_sign) {
PK11_FreeSymKey(nsscrypto_instance->nss_sym_key_sign);
nsscrypto_instance->nss_sym_key_sign = NULL;
}
free(nsscrypto_instance);
knet_h->crypto_instance->model_instance = NULL;
knet_h->sec_header_size = 0;
}
return;
}
static int nsscrypto_init(
knet_handle_t knet_h,
struct knet_handle_crypto_cfg *knet_handle_crypto_cfg)
{
struct nsscrypto_instance *nsscrypto_instance = NULL;
log_debug(knet_h, KNET_SUB_NSSCRYPTO,
"Initizializing nss crypto module [%s/%s]",
knet_handle_crypto_cfg->crypto_cipher_type,
knet_handle_crypto_cfg->crypto_hash_type);
knet_h->crypto_instance->model_instance = malloc(sizeof(struct nsscrypto_instance));
if (!knet_h->crypto_instance->model_instance) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to allocate memory for nss model instance");
return -1;
}
nsscrypto_instance = knet_h->crypto_instance->model_instance;
memset(nsscrypto_instance, 0, sizeof(struct nsscrypto_instance));
nsscrypto_instance->crypto_cipher_type = nssstring_to_crypto_cipher_type(knet_handle_crypto_cfg->crypto_cipher_type);
if (nsscrypto_instance->crypto_cipher_type < 0) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "unknown crypto cipher type requested");
goto out_err;
}
nsscrypto_instance->crypto_hash_type = nssstring_to_crypto_hash_type(knet_handle_crypto_cfg->crypto_hash_type);
if (nsscrypto_instance->crypto_hash_type < 0) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "unknown crypto hash type requested");
goto out_err;
}
if ((nsscrypto_instance->crypto_cipher_type > 0) &&
(nsscrypto_instance->crypto_hash_type == 0)) {
log_err(knet_h, KNET_SUB_NSSCRYPTO, "crypto communication requires hash specified");
goto out_err;
}
nsscrypto_instance->private_key = knet_handle_crypto_cfg->private_key;
nsscrypto_instance->private_key_len = knet_handle_crypto_cfg->private_key_len;
if (init_nss(knet_h) < 0) {
goto out_err;
}
knet_h->sec_header_size = 0;
if (nsscrypto_instance->crypto_hash_type > 0) {
knet_h->sec_header_size += nsshash_len[nsscrypto_instance->crypto_hash_type];
knet_h->sec_hash_size = nsshash_len[nsscrypto_instance->crypto_hash_type];
}
if (nsscrypto_instance->crypto_cipher_type > 0) {
int block_size;
if (nsscypher_block_len[nsscrypto_instance->crypto_cipher_type]) {
block_size = nsscypher_block_len[nsscrypto_instance->crypto_cipher_type];
} else {
block_size = PK11_GetBlockSize(nsscrypto_instance->crypto_cipher_type, NULL);
if (block_size < 0) {
goto out_err;
}
}
knet_h->sec_header_size += (block_size * 2);
knet_h->sec_header_size += SALT_SIZE;
knet_h->sec_salt_size = SALT_SIZE;
knet_h->sec_block_size = block_size;
}
return 0;
out_err:
nsscrypto_fini(knet_h);
return -1;
}
-crypto_model_t crypto_model = { "", 0, nsscrypto_load_lib, 0, nsscrypto_init, nsscrypto_fini, nsscrypto_encrypt_and_sign, nsscrypto_encrypt_and_signv, nsscrypto_authenticate_and_decrypt };
+crypto_model_t crypto_model = { "", 0, NULL, 0, nsscrypto_init, nsscrypto_fini, nsscrypto_encrypt_and_sign, nsscrypto_encrypt_and_signv, nsscrypto_authenticate_and_decrypt };
diff --git a/libknet/crypto_openssl.c b/libknet/crypto_openssl.c
index 9d1ae8ba..647f5a57 100644
--- a/libknet/crypto_openssl.c
+++ b/libknet/crypto_openssl.c
@@ -1,523 +1,517 @@
/*
* Copyright (C) 2017 Red Hat, Inc. All rights reserved.
*
* Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#define KNET_MODULE
#include "config.h"
#include <string.h>
#include <errno.h>
#include <dlfcn.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#include "logging.h"
#include "crypto_model.h"
/*
* 1.0.2 requires at least 120 bytes
* 1.1.0 requires at least 256 bytes
*/
#define SSLERR_BUF_SIZE 512
-static int openssl_is_init = 0;
-
-static int opensslcrypto_load_lib(
- knet_handle_t knet_h)
-{
- if (!openssl_is_init) {
-#ifdef BUILDCRYPTOOPENSSL10
- ERR_load_crypto_strings();
- OPENSSL_add_all_algorithms_noconf();
-#endif
-#ifdef BUILDCRYPTOOPENSSL11
- if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
- | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)) {
- log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to init openssl");
- errno = EAGAIN;
- return -1;
- }
-#endif
- openssl_is_init = 1;
- }
- return 0;
-}
-
/*
* crypto definitions and conversion tables
*/
#define SALT_SIZE 16
struct opensslcrypto_instance {
void *private_key;
int private_key_len;
const EVP_CIPHER *crypto_cipher_type;
const EVP_MD *crypto_hash_type;
};
/*
* crypt/decrypt functions openssl1.0
*/
#ifdef BUILDCRYPTOOPENSSL10
static int encrypt_openssl(
knet_handle_t knet_h,
const struct iovec *iov,
int iovcnt,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct opensslcrypto_instance *instance = knet_h->crypto_instance->model_instance;
EVP_CIPHER_CTX ctx;
int tmplen = 0, offset = 0;
unsigned char *salt = buf_out;
unsigned char *data = buf_out + SALT_SIZE;
int err = 0;
int i;
char sslerr[SSLERR_BUF_SIZE];
EVP_CIPHER_CTX_init(&ctx);
/*
* contribute to PRNG for each packet we send/receive
*/
RAND_seed((unsigned char *)iov[iovcnt - 1].iov_base, iov[iovcnt - 1].iov_len);
if (!RAND_bytes(salt, SALT_SIZE)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to get random salt data: %s", sslerr);
err = -1;
goto out;
}
/*
* add warning re keylength
*/
EVP_EncryptInit_ex(&ctx, instance->crypto_cipher_type, NULL, instance->private_key, salt);
for (i=0; i<iovcnt; i++) {
if (!EVP_EncryptUpdate(&ctx,
data + offset, &tmplen,
(unsigned char *)iov[i].iov_base, iov[i].iov_len)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to encrypt: %s", sslerr);
err = -1;
goto out;
}
offset = offset + tmplen;
}
if (!EVP_EncryptFinal_ex(&ctx, data + offset, &tmplen)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to finalize encrypt: %s", sslerr);
err = -1;
goto out;
}
*buf_out_len = offset + tmplen + SALT_SIZE;
out:
EVP_CIPHER_CTX_cleanup(&ctx);
return err;
}
static int decrypt_openssl (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct opensslcrypto_instance *instance = knet_h->crypto_instance->model_instance;
EVP_CIPHER_CTX ctx;
int tmplen1 = 0, tmplen2 = 0;
unsigned char *salt = (unsigned char *)buf_in;
unsigned char *data = salt + SALT_SIZE;
int datalen = buf_in_len - SALT_SIZE;
int err = 0;
char sslerr[SSLERR_BUF_SIZE];
EVP_CIPHER_CTX_init(&ctx);
/*
* contribute to PRNG for each packet we send/receive
*/
RAND_seed(buf_in, buf_in_len);
/*
* add warning re keylength
*/
EVP_DecryptInit_ex(&ctx, instance->crypto_cipher_type, NULL, instance->private_key, salt);
if (!EVP_DecryptUpdate(&ctx, buf_out, &tmplen1, data, datalen)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to decrypt: %s", sslerr);
err = -1;
goto out;
}
if (!EVP_DecryptFinal_ex(&ctx, buf_out + tmplen1, &tmplen2)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to finalize decrypt: %s", sslerr);
err = -1;
goto out;
}
*buf_out_len = tmplen1 + tmplen2;
out:
EVP_CIPHER_CTX_cleanup(&ctx);
return err;
}
#endif
#ifdef BUILDCRYPTOOPENSSL11
static int encrypt_openssl(
knet_handle_t knet_h,
const struct iovec *iov,
int iovcnt,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct opensslcrypto_instance *instance = knet_h->crypto_instance->model_instance;
EVP_CIPHER_CTX *ctx;
int tmplen = 0, offset = 0;
unsigned char *salt = buf_out;
unsigned char *data = buf_out + SALT_SIZE;
int err = 0;
int i;
char sslerr[SSLERR_BUF_SIZE];
ctx = EVP_CIPHER_CTX_new();
/*
* contribute to PRNG for each packet we send/receive
*/
RAND_seed((unsigned char *)iov[iovcnt - 1].iov_base, iov[iovcnt - 1].iov_len);
if (!RAND_bytes(salt, SALT_SIZE)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to get random salt data: %s", sslerr);
err = -1;
goto out;
}
/*
* add warning re keylength
*/
EVP_EncryptInit_ex(ctx, instance->crypto_cipher_type, NULL, instance->private_key, salt);
for (i=0; i<iovcnt; i++) {
if (!EVP_EncryptUpdate(ctx,
data + offset, &tmplen,
(unsigned char *)iov[i].iov_base, iov[i].iov_len)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to encrypt: %s", sslerr);
err = -1;
goto out;
}
offset = offset + tmplen;
}
if (!EVP_EncryptFinal_ex(ctx, data + offset, &tmplen)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to finalize encrypt: %s", sslerr);
err = -1;
goto out;
}
*buf_out_len = offset + tmplen + SALT_SIZE;
out:
EVP_CIPHER_CTX_free(ctx);
return err;
}
static int decrypt_openssl (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct opensslcrypto_instance *instance = knet_h->crypto_instance->model_instance;
EVP_CIPHER_CTX *ctx;
int tmplen1 = 0, tmplen2 = 0;
unsigned char *salt = (unsigned char *)buf_in;
unsigned char *data = salt + SALT_SIZE;
int datalen = buf_in_len - SALT_SIZE;
int err = 0;
char sslerr[SSLERR_BUF_SIZE];
ctx = EVP_CIPHER_CTX_new();
/*
* contribute to PRNG for each packet we send/receive
*/
RAND_seed(buf_in, buf_in_len);
/*
* add warning re keylength
*/
EVP_DecryptInit_ex(ctx, instance->crypto_cipher_type, NULL, instance->private_key, salt);
if (!EVP_DecryptUpdate(ctx, buf_out, &tmplen1, data, datalen)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to decrypt: %s", sslerr);
err = -1;
goto out;
}
if (!EVP_DecryptFinal_ex(ctx, buf_out + tmplen1, &tmplen2)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to finalize decrypt: %s", sslerr);
err = -1;
goto out;
}
*buf_out_len = tmplen1 + tmplen2;
out:
EVP_CIPHER_CTX_free(ctx);
return err;
}
#endif
/*
* hash/hmac/digest functions
*/
static int calculate_openssl_hash(
knet_handle_t knet_h,
const unsigned char *buf,
const size_t buf_len,
unsigned char *hash)
{
struct opensslcrypto_instance *instance = knet_h->crypto_instance->model_instance;
unsigned int hash_len = 0;
unsigned char *hash_out = NULL;
char sslerr[SSLERR_BUF_SIZE];
hash_out = HMAC(instance->crypto_hash_type,
instance->private_key, instance->private_key_len,
buf, buf_len,
hash, &hash_len);
if ((!hash_out) || (hash_len != knet_h->sec_hash_size)) {
ERR_error_string_n(ERR_get_error(), sslerr, sizeof(sslerr));
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to calculate hash: %s", sslerr);
return -1;
}
return 0;
}
/*
* exported API
*/
static int opensslcrypto_encrypt_and_signv (
knet_handle_t knet_h,
const struct iovec *iov_in,
int iovcnt_in,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct opensslcrypto_instance *instance = knet_h->crypto_instance->model_instance;
int i;
if (instance->crypto_cipher_type) {
if (encrypt_openssl(knet_h, iov_in, iovcnt_in, buf_out, buf_out_len) < 0) {
return -1;
}
} else {
*buf_out_len = 0;
for (i=0; i<iovcnt_in; i++) {
memmove(buf_out + *buf_out_len, iov_in[i].iov_base, iov_in[i].iov_len);
*buf_out_len = *buf_out_len + iov_in[i].iov_len;
}
}
if (instance->crypto_hash_type) {
if (calculate_openssl_hash(knet_h, buf_out, *buf_out_len, buf_out + *buf_out_len) < 0) {
return -1;
}
*buf_out_len = *buf_out_len + knet_h->sec_hash_size;
}
return 0;
}
static int opensslcrypto_encrypt_and_sign (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct iovec iov_in;
memset(&iov_in, 0, sizeof(iov_in));
iov_in.iov_base = (unsigned char *)buf_in;
iov_in.iov_len = buf_in_len;
return opensslcrypto_encrypt_and_signv(knet_h, &iov_in, 1, buf_out, buf_out_len);
}
static int opensslcrypto_authenticate_and_decrypt (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
struct opensslcrypto_instance *instance = knet_h->crypto_instance->model_instance;
ssize_t temp_len = buf_in_len;
if (instance->crypto_hash_type) {
unsigned char tmp_hash[knet_h->sec_hash_size];
ssize_t temp_buf_len = buf_in_len - knet_h->sec_hash_size;
if ((temp_buf_len < 0) || (temp_buf_len > KNET_MAX_PACKET_SIZE)) {
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Incorrect packet size.");
return -1;
}
if (calculate_openssl_hash(knet_h, buf_in, temp_buf_len, tmp_hash) < 0) {
return -1;
}
if (memcmp(tmp_hash, buf_in + temp_buf_len, knet_h->sec_hash_size) != 0) {
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Digest does not match");
return -1;
}
temp_len = temp_len - knet_h->sec_hash_size;
*buf_out_len = temp_len;
}
if (instance->crypto_cipher_type) {
if (decrypt_openssl(knet_h, buf_in, temp_len, buf_out, buf_out_len) < 0) {
return -1;
}
} else {
memmove(buf_out, buf_in, temp_len);
*buf_out_len = temp_len;
}
return 0;
}
static void opensslcrypto_fini(
knet_handle_t knet_h)
{
struct opensslcrypto_instance *opensslcrypto_instance = knet_h->crypto_instance->model_instance;
if (opensslcrypto_instance) {
if (opensslcrypto_instance->private_key) {
free(opensslcrypto_instance->private_key);
opensslcrypto_instance->private_key = NULL;
}
free(opensslcrypto_instance);
knet_h->crypto_instance->model_instance = NULL;
knet_h->sec_header_size = 0;
}
return;
}
static int opensslcrypto_init(
knet_handle_t knet_h,
struct knet_handle_crypto_cfg *knet_handle_crypto_cfg)
{
+ static int openssl_is_init = 0;
struct opensslcrypto_instance *opensslcrypto_instance = NULL;
log_debug(knet_h, KNET_SUB_OPENSSLCRYPTO,
"Initizializing openssl crypto module [%s/%s]",
knet_handle_crypto_cfg->crypto_cipher_type,
knet_handle_crypto_cfg->crypto_hash_type);
+ if (!openssl_is_init) {
+#ifdef BUILDCRYPTOOPENSSL10
+ ERR_load_crypto_strings();
+ OPENSSL_add_all_algorithms_noconf();
+#endif
+#ifdef BUILDCRYPTOOPENSSL11
+ if (!OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
+ | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL)) {
+ log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to init openssl");
+ errno = EAGAIN;
+ return -1;
+ }
+#endif
+ openssl_is_init = 1;
+ }
+
knet_h->crypto_instance->model_instance = malloc(sizeof(struct opensslcrypto_instance));
if (!knet_h->crypto_instance->model_instance) {
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to allocate memory for openssl model instance");
return -1;
}
opensslcrypto_instance = knet_h->crypto_instance->model_instance;
memset(opensslcrypto_instance, 0, sizeof(struct opensslcrypto_instance));
if (strcmp(knet_handle_crypto_cfg->crypto_cipher_type, "none") == 0) {
opensslcrypto_instance->crypto_cipher_type = NULL;
} else {
opensslcrypto_instance->crypto_cipher_type = EVP_get_cipherbyname(knet_handle_crypto_cfg->crypto_cipher_type);
if (!opensslcrypto_instance->crypto_cipher_type) {
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "unknown crypto cipher type requested");
goto out_err;
}
}
if (strcmp(knet_handle_crypto_cfg->crypto_hash_type, "none") == 0) {
opensslcrypto_instance->crypto_hash_type = NULL;
} else {
opensslcrypto_instance->crypto_hash_type = EVP_get_digestbyname(knet_handle_crypto_cfg->crypto_hash_type);
if (!opensslcrypto_instance->crypto_hash_type) {
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "unknown crypto hash type requested");
goto out_err;
}
}
if ((opensslcrypto_instance->crypto_cipher_type) &&
(!opensslcrypto_instance->crypto_hash_type)) {
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "crypto communication requires hash specified");
goto out_err;
}
opensslcrypto_instance->private_key = malloc(knet_handle_crypto_cfg->private_key_len);
if (!opensslcrypto_instance->private_key) {
log_err(knet_h, KNET_SUB_OPENSSLCRYPTO, "Unable to allocate memory for openssl private key");
goto out_err;
}
memmove(opensslcrypto_instance->private_key, knet_handle_crypto_cfg->private_key, knet_handle_crypto_cfg->private_key_len);
opensslcrypto_instance->private_key_len = knet_handle_crypto_cfg->private_key_len;
knet_h->sec_header_size = 0;
if (opensslcrypto_instance->crypto_hash_type) {
knet_h->sec_hash_size = EVP_MD_size(opensslcrypto_instance->crypto_hash_type);
knet_h->sec_header_size += knet_h->sec_hash_size;
}
if (opensslcrypto_instance->crypto_cipher_type) {
int block_size;
block_size = EVP_CIPHER_block_size(opensslcrypto_instance->crypto_cipher_type);
if (block_size < 0) {
goto out_err;
}
knet_h->sec_header_size += (block_size * 2);
knet_h->sec_header_size += SALT_SIZE;
knet_h->sec_salt_size = SALT_SIZE;
knet_h->sec_block_size = block_size;
}
return 0;
out_err:
opensslcrypto_fini(knet_h);
return -1;
}
-crypto_model_t crypto_model = { "", 0, opensslcrypto_load_lib, 0, opensslcrypto_init, opensslcrypto_fini, opensslcrypto_encrypt_and_sign, opensslcrypto_encrypt_and_signv, opensslcrypto_authenticate_and_decrypt };
+crypto_model_t crypto_model = { "", 0, NULL, 0, opensslcrypto_init, opensslcrypto_fini, opensslcrypto_encrypt_and_sign, opensslcrypto_encrypt_and_signv, opensslcrypto_authenticate_and_decrypt };

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 10, 3:22 AM (17 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009917
Default Alt Text
(43 KB)

Event Timeline