diff --git a/configure.ac b/configure.ac index 300c1ed0..2ef0907a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,465 +1,479 @@ # # Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. # # Authors: Fabio M. Di Nitto # Federico Simoncelli # # This software licensed under GPL-2.0+, LGPL-2.0+ # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # AC_PREREQ([2.63]) AC_INIT([kronosnet], m4_esyscmd([build-aux/git-version-gen .tarball-version]), [devel@lists.kronosnet.org]) AC_USE_SYSTEM_EXTENSIONS AM_INIT_AUTOMAKE([1.11.1 dist-bzip2 dist-xz color-tests -Wno-portability subdir-objects]) LT_PREREQ([2.2.6]) LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([kronosnetd/main.c]) AC_CONFIG_HEADERS([config.h]) AC_CANONICAL_HOST AC_PROG_LIBTOOL AC_LANG([C]) systemddir=${prefix}/lib/systemd/system if test "$prefix" = "NONE"; then prefix="/usr" if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi if test "$sysconfdir" = "\${prefix}/etc"; then sysconfdir="/etc" fi if test "$systemddir" = "NONE/lib/systemd/system"; then systemddir=/lib/systemd/system fi if test "$libdir" = "\${exec_prefix}/lib"; then if test -e /usr/lib64; then libdir="/usr/lib64" else libdir="/usr/lib" fi fi fi # Checks for programs. if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then AC_MSG_ERROR(["you don't seem to have GNU make; it is required"]) fi AC_PROG_AWK AC_PROG_GREP AC_PROG_SED AC_PROG_CPP AC_PROG_CC AC_PROG_CC_C99 if test "x$ac_cv_prog_cc_c99" = "xno"; then AC_MSG_ERROR(["C99 support is required"]) fi AC_PROG_LN_S AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_CXX AC_PROG_RANLIB AC_CHECK_PROGS([PUBLICAN], [publican], [:]) AC_CHECK_PROGS([PKGCONFIG], [pkg-config]) AC_ARG_ENABLE([libknet-sctp], [ --disable-libknet-sctp : disable libknet SCTP support ],, [ enable_libknet_sctp="yes" ]) +AC_ARG_ENABLE([crypto-all], + [ --disable-crypto-all : disable libknet all crypto modules support ],, + [ enable_crypto_all="yes" ]) + +AC_ARG_ENABLE([crypto-nss], + [ --disable-crypto-nss : disable libknet nss support ],, + [ enable_crypto_nss="$enable_crypto_all" ]) + AC_ARG_ENABLE([compress-all], - [ --disable-compress-all : disable libknet all compress support ],, + [ --disable-compress-all : disable libknet all compress modules support ],, [ enable_compress_all="yes" ]) AC_ARG_ENABLE([compress-zlib], [ --disable-compress-zlib : disable libknet zlib support ],, [ enable_compress_zlib="$enable_compress_all" ]) AC_ARG_ENABLE([compress-lz4], [ --disable-compress-lz4 : disable libknet lz4 support ],, [ enable_compress_lz4="$enable_compress_all" ]) AC_ARG_ENABLE([compress-lzo2], [ --disable-compress-lzo2 : disable libknet lzo2 support ],, [ enable_compress_lzo2="$enable_compress_all" ]) AC_ARG_ENABLE([compress-lzma], [ --disable-compress-lzma : disable libknet lzma support ],, [ enable_compress_lzma="$enable_compress_all" ]) AC_ARG_ENABLE([compress-bzip2], [ --disable-compress-bzip2 : disable libknet bzip2 support ],, [ enable_compress_bzip2="$enable_compress_all" ]) AC_ARG_ENABLE([poc], [ --disable-poc : disable building poc code ],, [ enable_poc="yes" ]) AM_CONDITIONAL([BUILD_POC], [test x$enable_poc = xyes]) AC_ARG_ENABLE([kronosnetd], [ --enable-kronosnetd : Kronosnetd support ],, [ enable_kronosnetd="no" ]) AM_CONDITIONAL([BUILD_KRONOSNETD], [test x$enable_kronosnetd = xyes]) AC_ARG_ENABLE([libtap], [ --enable-libtap : libtap support ],, [ enable_libtap="no" ]) if test "x$enable_kronosnetd" = xyes; then enable_libtap=yes fi AM_CONDITIONAL([BUILD_LIBTAP], [test x$enable_libtap = xyes]) ## local helper functions # this function checks if CC support options passed as # args. Global CFLAGS are ignored during this test. cc_supports_flag() { saveCPPFLAGS="$CPPFLAGS" CPPFLAGS="$@" if echo $CC | grep -q clang; then CPPFLAGS="-Werror $CPPFLAGS" fi AC_MSG_CHECKING([whether $CC supports "$@"]) AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])], [RC=0; AC_MSG_RESULT([yes])], [RC=1; AC_MSG_RESULT([no])]) CPPFLAGS="$saveCPPFLAGS" return $RC } # helper macro to check libs without adding them to LIBS check_lib_no_libs() { lib_no_libs_arg1=$1 shift lib_no_libs_arg2=$1 shift lib_no_libs_args=$@ AC_CHECK_LIB([$lib_no_libs_arg1], [$lib_no_libs_arg2],,, [$lib_no_libs_args]) LIBS=$ac_check_lib_save_LIBS } # Checks for C features AC_C_INLINE # Checks for libraries. AC_CHECK_LIB([pthread], [pthread_create]) AC_CHECK_LIB([m], [ceil]) AC_CHECK_LIB([rt], [clock_gettime]) +# workaround pkg-config bootstrapping +PKG_CHECK_MODULES([foobarbaz],[foobarbaz], [AC_MSG_NOTICE([bootstrapping pkg-config])], [AC_MSG_NOTICE([bootstrapping pkg-config])]) + # crypto libraries checks -PKG_CHECK_MODULES([nss],[nss]) +if test "x$enable_crypto_nss" = xyes; then + PKG_CHECK_MODULES([nss],[nss]) + AC_DEFINE_UNQUOTED([BUILDCRYPTONSS], [1], [Enable nss crypto]) +fi # compress libraries checks if test "x$enable_compress_zlib" = xyes; then PKG_CHECK_MODULES([zlib], [zlib]) AC_DEFINE_UNQUOTED([BUILDCOMPZLIB], [1], [Enable zlib compression]) fi if test "x$enable_compress_lz4" = xyes; then PKG_CHECK_MODULES([liblz4], [liblz4]) AC_DEFINE_UNQUOTED([BUILDCOMPLZ4], [1], [Enable lz4 compress]) fi if test "x$enable_compress_lzo2" = xyes; then PKG_CHECK_MODULES([lzo2], [lzo2],, [AC_CHECK_HEADERS([lzo/lzo1x.h], [AC_CHECK_LIB([lzo2], [lzo1x_decompress_safe], [AC_SUBST([lzo2_LIBS], [-llzo2])])], [AC_MSG_ERROR(["missing required lzo/lzo1x.h header"])])]) AC_DEFINE_UNQUOTED([BUILDCOMPLZO2], [1], [Enable lzo2 compress]) fi if test "x$enable_compress_lzma" = xyes; then PKG_CHECK_MODULES([liblzma], [liblzma]) AC_DEFINE_UNQUOTED([BUILDCOMPLZMA], [1], [Enable lzma compress]) fi if test "x$enable_compress_bzip2" = xyes; then PKG_CHECK_MODULES([bzip2], [bzip2],, [AC_CHECK_HEADERS([bzlib.h], [AC_CHECK_LIB([bz2], [BZ2_bzBuffToBuffCompress], [AC_SUBST([bzip2_LIBS], [-lbz2])])], [AC_MSG_ERROR(["missing required bzlib.h"])])]) AC_DEFINE_UNQUOTED([BUILDCOMPBZIP2], [1], [Enable bzip2 compress]) fi # Checks for header files. AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([stdlib.h]) AC_CHECK_HEADERS([string.h]) AC_CHECK_HEADERS([strings.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([syslog.h]) AC_CHECK_HEADERS([unistd.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([arpa/inet.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([limits.h]) AC_CHECK_HEADERS([stdint.h]) AC_CHECK_HEADERS([sys/epoll.h]) if test "x$enable_libknet_sctp" = xyes; then AC_CHECK_HEADERS([netinet/sctp.h],, [AC_MSG_ERROR(["missing required SCTP headers"])]) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_PID_T AC_TYPE_SSIZE_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_INT32_T # Checks for library functions. AC_FUNC_ALLOCA AC_FUNC_FORK AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([memset]) AC_CHECK_FUNCS([strdup]) AC_CHECK_FUNCS([strerror]) AC_CHECK_FUNCS([dup2]) AC_CHECK_FUNCS([select]) AC_CHECK_FUNCS([socket]) AC_CHECK_FUNCS([inet_ntoa]) AC_CHECK_FUNCS([memmove]) AC_CHECK_FUNCS([strchr]) AC_CHECK_FUNCS([atexit]) AC_CHECK_FUNCS([ftruncate]) AC_CHECK_FUNCS([strrchr]) AC_CHECK_FUNCS([strstr]) AC_CHECK_FUNCS([clock_gettime]) AC_CHECK_FUNCS([strcasecmp]) AC_CHECK_FUNCS([kevent]) # if neither sys/epoll.h nor kevent are present, we should fail. if test "x$ac_cv_header_sys_epoll_h" = xno && test "x$ac_cv_func_kevent" = xno; then AC_MSG_ERROR([Both epoll and kevent unavailable on this OS]) fi if test "x$ac_cv_header_sys_epoll_h" = xyes && test "x$ac_cv_func_kevent" = xyes; then AC_MSG_ERROR([Both epoll and kevent available on this OS, please contact the maintainers to fix the code]) fi # checks (for kronosnetd) if test "x$enable_kronosnetd" = xyes; then AC_CHECK_HEADERS([security/pam_appl.h], [AC_CHECK_LIB([pam], [pam_start])], [AC_MSG_ERROR([Unable to find LinuxPAM devel files])]) AC_CHECK_HEADERS([security/pam_misc.h], [AC_CHECK_LIB([pam_misc], [misc_conv])], [AC_MSG_ERROR([Unable to find LinuxPAM MISC devel files])]) PKG_CHECK_MODULES([libqb], [libqb]) AC_CHECK_LIB([qb], [qb_log_thread_priority_set], [have_qb_log_thread_priority_set="yes"], [have_qb_log_thread_priority_set="no"]) if test "x${have_qb_log_thread_priority_set}" = xyes; then AC_DEFINE_UNQUOTED([HAVE_QB_LOG_THREAD_PRIORITY_SET], [1], [have qb_log_thread_priority_set]) fi fi # local options AC_ARG_ENABLE([debug], [ --enable-debug enable debug build. ], [ default="no" ]) AC_ARG_ENABLE([publicandocs], [ --enable-publicandocs enable docs build. ], [ default="no" ]) AC_ARG_WITH([initdefaultdir], [ --with-initdefaultdir : path to /etc/sysconfig/.. or /etc/default dir. ], [ INITDEFAULTDIR="$withval" ], [ INITDEFAULTDIR="$sysconfdir/default" ]) AC_ARG_WITH([initddir], [ --with-initddir=DIR : path to init script directory. ], [ INITDDIR="$withval" ], [ INITDDIR="$sysconfdir/init.d" ]) AC_ARG_WITH([systemddir], [ --with-systemddir=DIR : path to systemd unit files directory. ], [ SYSTEMDDIR="$withval" ], [ SYSTEMDDIR="$systemddir" ]) AC_ARG_WITH([syslogfacility], [ --with-syslogfacility=FACILITY default syslog facility. ], [ SYSLOGFACILITY="$withval" ], [ SYSLOGFACILITY="LOG_DAEMON" ]) AC_ARG_WITH([sysloglevel], [ --with-sysloglevel=LEVEL default syslog level. ], [ SYSLOGLEVEL="$withval" ], [ SYSLOGLEVEL="LOG_INFO" ]) AC_ARG_WITH([defaultadmgroup], [ --with-defaultadmgroup=GROUP define PAM group. Users part of this group will be allowed to configure kronosnet. Others will only receive read-only rights. ], [ DEFAULTADMGROUP="$withval" ], [ DEFAULTADMGROUP="kronosnetadm" ]) ## random vars LOGDIR=${localstatedir}/log/ RUNDIR=${localstatedir}/run/ DEFAULT_CONFIG_DIR=${sysconfdir}/kronosnet ## do subst AM_CONDITIONAL([BUILD_DOCS], [test "x${enable_publicandocs}" = xyes]) AM_CONDITIONAL([DEBUG], [test "x${enable_debug}" = xyes]) AC_SUBST([DEFAULT_CONFIG_DIR]) AC_SUBST([INITDEFAULTDIR]) AC_SUBST([INITDDIR]) AC_SUBST([SYSTEMDDIR]) AC_SUBST([LOGDIR]) AC_SUBST([DEFAULTADMGROUP]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_DIR], ["$(eval echo ${DEFAULT_CONFIG_DIR})"], [Default config directory]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_FILE], ["$(eval echo ${DEFAULT_CONFIG_DIR}/kronosnetd.conf)"], [Default config file]) AC_DEFINE_UNQUOTED([LOGDIR], ["$(eval echo ${LOGDIR})"], [Default logging directory]) AC_DEFINE_UNQUOTED([DEFAULT_LOG_FILE], ["$(eval echo ${LOGDIR}/kronosnetd.log)"], [Default log file]) AC_DEFINE_UNQUOTED([RUNDIR], ["$(eval echo ${RUNDIR})"], [Default run directory]) AC_DEFINE_UNQUOTED([SYSLOGFACILITY], [$(eval echo ${SYSLOGFACILITY})], [Default syslog facility]) AC_DEFINE_UNQUOTED([SYSLOGLEVEL], [$(eval echo ${SYSLOGLEVEL})], [Default syslog level]) AC_DEFINE_UNQUOTED([DEFAULTADMGROUP], ["$(eval echo ${DEFAULTADMGROUP})"], [Default admin group]) ## *FLAGS handling ENV_CFLAGS="$CFLAGS" ENV_CPPFLAGS="$CPPFLAGS" ENV_LDFLAGS="$LDFLAGS" # debug build stuff if test "x${enable_debug}" = xyes; then AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code]) OPT_CFLAGS="-O0" else OPT_CFLAGS="-O3" fi # gdb flags if test "x${GCC}" = xyes; then GDB_FLAGS="-ggdb3" else GDB_FLAGS="-g" fi # extra warnings EXTRA_WARNINGS="" WARNLIST=" all extra unused shadow missing-prototypes missing-declarations suggest-attribute=noreturn suggest-attribute=format strict-prototypes declaration-after-statement pointer-arith write-strings cast-align bad-function-cast missing-format-attribute float-equal format=2 format-signedness format-security format-nonliteral no-long-long unsigned-char gnu89-inline no-strict-aliasing error address cpp overflow parentheses sequence-point switch shift-overflow=2 overlength-strings retundent-decls init-self uninitialized unused-but-set-variable unused-function unused-result unused-value unused-variable unknown-pragmas no-unused-parameter " for j in $WARNLIST; do if cc_supports_flag -W$j; then EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j"; fi done CFLAGS="$ENV_CFLAGS $lt_prog_compiler_pic $OPT_CFLAGS $GDB_FLAGS \ $EXTRA_WARNINGS $WERROR_CFLAGS" CPPFLAGS="$ENV_CPPFLAGS" LDFLAGS="$ENV_LDFLAGS $lt_prog_compiler_pic -Wl,--as-needed" AC_CONFIG_FILES([ Makefile init/Makefile libtap/Makefile libtap/libtap.pc kronosnetd/Makefile kronosnetd/kronosnetd.logrotate libknet/Makefile libknet/libknet.pc libknet/tests/Makefile docs/Makefile poc-code/Makefile poc-code/iov-hash/Makefile poc-code/access-list/Makefile ]) AC_OUTPUT diff --git a/libknet/crypto.c b/libknet/crypto.c index 7ae3129e..565b14ea 100644 --- a/libknet/crypto.c +++ b/libknet/crypto.c @@ -1,122 +1,136 @@ /* * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include "crypto.h" #include "crypto_nss.h" #include "internals.h" #include "logging.h" /* * internal module switch data */ crypto_model_t crypto_modules_cmds[] = { - { "nss", nsscrypto_init, nsscrypto_fini, nsscrypto_encrypt_and_sign, nsscrypto_encrypt_and_signv, nsscrypto_authenticate_and_decrypt }, - { NULL, NULL, NULL, NULL, NULL, NULL }, +#ifdef BUILDCRYPTONSS + { "nss", 1, nsscrypto_init, nsscrypto_fini, nsscrypto_encrypt_and_sign, nsscrypto_encrypt_and_signv, nsscrypto_authenticate_and_decrypt }, +#else + { "nss", 0, NULL, NULL, NULL, NULL, NULL }, +#endif + { NULL, 0, NULL, NULL, NULL, NULL, NULL }, }; static int get_model(const char *model) { int idx = 0; while (crypto_modules_cmds[idx].model_name != NULL) { if (!strcmp(crypto_modules_cmds[idx].model_name, model)) return idx; idx++; } return -1; } /* * exported API */ int crypto_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) { return crypto_modules_cmds[knet_h->crypto_instance->model].crypt(knet_h, buf_in, buf_in_len, buf_out, buf_out_len); } int crypto_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) { return crypto_modules_cmds[knet_h->crypto_instance->model].cryptv(knet_h, iov_in, iovcnt_in, buf_out, buf_out_len); } int crypto_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) { return crypto_modules_cmds[knet_h->crypto_instance->model].decrypt(knet_h, buf_in, buf_in_len, buf_out, buf_out_len); } int crypto_init( knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg) { + int model = 0; + + model = get_model(knet_handle_crypto_cfg->crypto_model); + if (model < 0) { + log_err(knet_h, KNET_SUB_CRYPTO, "model %s not supported", knet_handle_crypto_cfg->crypto_model); + goto out_err; + } + + if (crypto_modules_cmds[model].built_in == 0) { + log_err(knet_h, KNET_SUB_CRYPTO, "this version of libknet was built without %s support. Please contact your vendor or fix the build.", knet_handle_crypto_cfg->crypto_model); + goto out_err; + } + log_debug(knet_h, KNET_SUB_CRYPTO, "Initizializing crypto module [%s/%s/%s]", knet_handle_crypto_cfg->crypto_model, knet_handle_crypto_cfg->crypto_cipher_type, knet_handle_crypto_cfg->crypto_hash_type); knet_h->crypto_instance = malloc(sizeof(struct crypto_instance)); if (!knet_h->crypto_instance) { log_err(knet_h, KNET_SUB_CRYPTO, "Unable to allocate memory for crypto instance"); return -1; } - knet_h->crypto_instance->model = get_model(knet_handle_crypto_cfg->crypto_model); - if (knet_h->crypto_instance->model < 0) { - log_err(knet_h, KNET_SUB_CRYPTO, "model %s not supported", knet_handle_crypto_cfg->crypto_model); - goto out_err; - } - + knet_h->crypto_instance->model = model; if (crypto_modules_cmds[knet_h->crypto_instance->model].init(knet_h, knet_handle_crypto_cfg)) goto out_err; log_debug(knet_h, KNET_SUB_CRYPTO, "security network overhead: %u", knet_h->sec_header_size); return 0; out_err: - free(knet_h->crypto_instance); - knet_h->crypto_instance = NULL; + if (knet_h->crypto_instance) { + free(knet_h->crypto_instance); + knet_h->crypto_instance = NULL; + } return -1; } void crypto_fini( knet_handle_t knet_h) { if (knet_h->crypto_instance) { crypto_modules_cmds[knet_h->crypto_instance->model].fini(knet_h); free(knet_h->crypto_instance); knet_h->crypto_instance = NULL; } return; } diff --git a/libknet/crypto.h b/libknet/crypto.h index bac3359c..053ea094 100644 --- a/libknet/crypto.h +++ b/libknet/crypto.h @@ -1,69 +1,70 @@ /* * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_CRYPTO_H__ #define __KNET_CRYPTO_H__ #include "internals.h" struct crypto_instance { int model; void *model_instance; }; typedef struct { const char *model_name; + uint8_t built_in; int (*init) (knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg); void (*fini) (knet_handle_t knet_h); int (*crypt) (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); int (*cryptv) (knet_handle_t knet_h, const struct iovec *iov_in, int iovcnt_in, unsigned char *buf_out, ssize_t *buf_out_len); int (*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); } crypto_model_t; int crypto_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); int crypto_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); int crypto_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); int crypto_init( knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg); void crypto_fini( knet_handle_t knet_h); #endif diff --git a/libknet/crypto_nss.c b/libknet/crypto_nss.c index db1f1b44..0386b22b 100644 --- a/libknet/crypto_nss.c +++ b/libknet/crypto_nss.c @@ -1,820 +1,822 @@ /* * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" +#ifdef BUILDCRYPTONSS #include #include #include #include #include #include #include #include #include #include #include "crypto.h" #include "crypto_nss.h" #include "logging.h" static pthread_mutex_t nssdbinit_mutex = PTHREAD_MUTEX_INITIALIZER; static int nssdbinit_done = 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 crypto_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 cipher_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 cypher_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 crypto_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 hash_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 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; } 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 *import_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 = cipher_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 = import_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; icrypto_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 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; } 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 = import_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, hash_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 void nss_atexit_handler(void) { NSS_Shutdown(); PL_ArenaFinish(); PR_Cleanup(); } static int init_nss_db(knet_handle_t knet_h) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; int err = 0; if ((!cipher_to_nss[instance->crypto_cipher_type]) && (!hash_to_nss[instance->crypto_hash_type])) { return 0; } err = pthread_mutex_lock(&nssdbinit_mutex); if (err) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "NSS DB unable to get mutex lock (%d)", err); return -1; } if (nssdbinit_done) { err = 0; goto out_unlock; } PR_Init(PR_USER_THREAD, PR_PRIORITY_URGENT, 0); 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)); err = -1; goto out_unlock; } if (atexit(&nss_atexit_handler) != 0) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "NSS DB unable to register atexit handler"); err = -1; goto out_unlock; } nssdbinit_done = 1; out_unlock: pthread_mutex_unlock(&nssdbinit_mutex); return err; } static int init_nss(knet_handle_t knet_h) { if (init_nss_db(knet_h) < 0) { return -1; } if (init_nss_crypto(knet_h) < 0) { return -1; } if (init_nss_hash(knet_h) < 0) { return -1; } return 0; } /* * exported API */ 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); } 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; icrypto_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 + hash_len[instance->crypto_hash_type]; } return 0; } 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[hash_len[instance->crypto_hash_type]]; ssize_t temp_buf_len = buf_in_len - hash_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, hash_len[instance->crypto_hash_type]) != 0) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Digest does not match"); return -1; } temp_len = temp_len - hash_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; } 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 = string_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 = string_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 += hash_len[nsscrypto_instance->crypto_hash_type]; knet_h->sec_hash_size = hash_len[nsscrypto_instance->crypto_hash_type]; } if (nsscrypto_instance->crypto_cipher_type > 0) { int block_size; if (cypher_block_len[nsscrypto_instance->crypto_cipher_type]) { block_size = cypher_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; } 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; } +#endif diff --git a/libknet/tests/api_knet_handle_crypto.c b/libknet/tests/api_knet_handle_crypto.c index d725368b..13703abd 100644 --- a/libknet/tests/api_knet_handle_crypto.c +++ b/libknet/tests/api_knet_handle_crypto.c @@ -1,210 +1,216 @@ /* * Copyright (C) 2016 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; struct knet_handle_crypto_cfg knet_handle_crypto_cfg; memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); printf("Test knet_handle_crypto incorrect knet_h\n"); if ((!knet_handle_crypto(NULL, &knet_handle_crypto_cfg)) || (errno != EINVAL)) { printf("knet_handle_crypto accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_crypto with invalid cfg\n"); if ((!knet_handle_crypto(knet_h, NULL)) || (errno != EINVAL)) { printf("knet_handle_crypto accepted invalid cfg or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_crypto with un-initialized cfg\n"); if ((!knet_handle_crypto(knet_h, &knet_handle_crypto_cfg)) || (errno != EINVAL)) { printf("knet_handle_crypto accepted invalid un-initialized cfg\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_crypto with none crypto model (disable crypto)\n"); memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); strncpy(knet_handle_crypto_cfg.crypto_model, "none", sizeof(knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_handle_crypto_cfg.crypto_cipher_type, "aes128", sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_handle_crypto_cfg.crypto_hash_type, "sha1", sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); if (knet_handle_crypto(knet_h, &knet_handle_crypto_cfg) != 0) { printf("knet_handle_crypto did not accept none crypto mode cfg\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_crypto with none crypto cipher and hash (disable crypto)\n"); memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); strncpy(knet_handle_crypto_cfg.crypto_model, "nss", sizeof(knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_handle_crypto_cfg.crypto_cipher_type, "none", sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_handle_crypto_cfg.crypto_hash_type, "none", sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); if (knet_handle_crypto(knet_h, &knet_handle_crypto_cfg) != 0) { printf("knet_handle_crypto did not accept none crypto cipher and hash cfg\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_crypto with nss/aes128/sha1 and too short key\n"); memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); strncpy(knet_handle_crypto_cfg.crypto_model, "nss", sizeof(knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_handle_crypto_cfg.crypto_cipher_type, "aes128", sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_handle_crypto_cfg.crypto_hash_type, "sha1", sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); knet_handle_crypto_cfg.private_key_len = 10; if ((!knet_handle_crypto(knet_h, &knet_handle_crypto_cfg)) || (errno != EINVAL)) { printf("knet_handle_crypto accepted too short private key\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_crypto with nss/aes128/sha1 and too long key\n"); memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); strncpy(knet_handle_crypto_cfg.crypto_model, "nss", sizeof(knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_handle_crypto_cfg.crypto_cipher_type, "aes128", sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_handle_crypto_cfg.crypto_hash_type, "sha1", sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); knet_handle_crypto_cfg.private_key_len = 10000; if ((!knet_handle_crypto(knet_h, &knet_handle_crypto_cfg)) || (errno != EINVAL)) { printf("knet_handle_crypto accepted too long private key\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); +#ifdef BUILDCRYPTONSS printf("Test knet_handle_crypto with nss/aes128/sha1 and normal key\n"); memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); strncpy(knet_handle_crypto_cfg.crypto_model, "nss", sizeof(knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_handle_crypto_cfg.crypto_cipher_type, "aes128", sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_handle_crypto_cfg.crypto_hash_type, "sha1", sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); knet_handle_crypto_cfg.private_key_len = 2000; if (knet_handle_crypto(knet_h, &knet_handle_crypto_cfg)) { printf("knet_handle_crypto failed with correct config: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_crypto (nss specific test) with nss/aes128/none and normal key\n"); memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); strncpy(knet_handle_crypto_cfg.crypto_model, "nss", sizeof(knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_handle_crypto_cfg.crypto_cipher_type, "aes128", sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_handle_crypto_cfg.crypto_hash_type, "none", sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); knet_handle_crypto_cfg.private_key_len = 2000; if (!knet_handle_crypto(knet_h, &knet_handle_crypto_cfg)) { printf("knet_handle_crypto (nss) accepted crypto without hashing\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Shutdown crypto\n"); memset(&knet_handle_crypto_cfg, 0, sizeof(struct knet_handle_crypto_cfg)); strncpy(knet_handle_crypto_cfg.crypto_model, "none", sizeof(knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_handle_crypto_cfg.crypto_cipher_type, "none", sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_handle_crypto_cfg.crypto_hash_type, "none", sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); knet_handle_crypto_cfg.private_key_len = 2000; if (knet_handle_crypto(knet_h, &knet_handle_crypto_cfg) < 0) { printf("Unable to shutdown crypto: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); - +#endif knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); +#ifdef BUILDCRYPTONSS return PASS; +#else + printf("WARNING: nss support not builtin the library. Unable to test/verify internal crypto API calls\n"); + return SKIP; +#endif }