From 490337f4f9a81afdf180d1a56ba83b8513335dbd Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Wed, 13 Apr 2016 12:44:58 -0500 Subject: [PATCH] Make OpenSSL an hcrypto backend proper This adds a new backend for libhcrypto: the OpenSSL backend. Now libhcrypto has these backends: - hcrypto itself (i.e., the algorithms coded in lib/hcrypto) - Common Crypto (OS X) - PKCS#11 (specifically for Solaris, but not Solaris-specific) - Windows CNG (Windows) - OpenSSL (generic) The ./configure --with-openssl=... option no longer disables the use of hcrypto. Instead it enables the use of OpenSSL as a (and the default) backend in libhcrypto. The libhcrypto framework is now always used. OpenSSL should no longer be used directly within Heimdal, except in the OpenSSL hcrypto backend itself, and files where elliptic curve (EC) crypto is needed. Because libhcrypto's EC support is incomplete, we can only use OpenSSL for EC. Currently that means separating all EC-using code so that it does not use hcrypto, thus the libhx509/hxtool and PKINIT EC code has been moved out of the files it used to be in. --- admin/Makefile.am | 2 +- appl/ftp/ftp/Makefile.am | 2 +- appl/otp/Makefile.am | 2 - appl/su/Makefile.am | 2 - cf/crypto.m4 | 102 ++--- include/config.h.w32 | 6 +- include/crypto-headers.h | 36 -- include/hcrypto/Makefile.am | 3 +- include/heim_threads.h | 2 +- kadmin/Makefile.am | 2 +- kcm/Makefile.am | 2 +- kdc/Makefile.am | 4 +- kdc/NTMakefile | 15 +- kdc/pkinit-ec.c | 323 +++++++++++++++ kdc/pkinit.c | 158 ++------ kpasswd/Makefile.am | 2 - kuser/Makefile.am | 2 +- lib/NTMakefile | 2 +- lib/base/test_base.c | 2 +- lib/gssapi/Makefile.am | 3 +- lib/gssapi/ntlm/crypto.c | 2 +- lib/hcrypto/Makefile.am | 18 +- lib/hcrypto/NTMakefile | 13 +- lib/hcrypto/bn.h | 4 +- lib/hcrypto/dh.h | 2 + lib/hcrypto/dsa.h | 2 + lib/hcrypto/ec.h | 2 +- lib/hcrypto/engine.h | 2 +- lib/hcrypto/evp-openssl.c | 627 +++++++++++++++++++++++++++++ lib/hcrypto/evp-openssl.h | 102 +++++ lib/hcrypto/evp-pkcs11.c | 2 +- lib/hcrypto/evp.c | 5 +- lib/hcrypto/evp.h | 12 +- lib/hcrypto/libhcrypto-exports.def | 19 + lib/hcrypto/mdtest.c | 6 +- lib/hcrypto/rand.h | 2 + lib/hcrypto/rsa.h | 2 +- lib/hcrypto/test_cipher.c | 19 +- lib/hcrypto/version-script.map | 19 + lib/hdb/Makefile.am | 2 +- lib/hx509/Makefile.am | 7 +- lib/hx509/NTMakefile | 6 +- lib/hx509/crypto-ec.c | 482 ++++++++++++++++++++++ lib/hx509/crypto.c | 585 +++------------------------ lib/hx509/hx_locl.h | 99 ++++- lib/hx509/hxtool.c | 4 +- lib/hx509/ks_file.c | 2 + lib/kafs/Makefile.am | 2 +- lib/krb5/Makefile.am | 4 +- lib/krb5/NTMakefile | 6 +- lib/krb5/aes-test.c | 6 +- lib/krb5/crypto.h | 9 +- lib/krb5/krb5_locl.h | 32 +- lib/krb5/pkinit-ec.c | 246 +++++++++++ lib/krb5/pkinit.c | 147 +------ lib/ntlm/Makefile.am | 2 - lib/otp/Makefile.am | 2 +- tools/Makefile.am | 1 - tools/krb5-config.in | 2 +- windows/NTMakefile.config | 4 + 60 files changed, 2206 insertions(+), 976 deletions(-) create mode 100644 kdc/pkinit-ec.c create mode 100644 lib/hcrypto/evp-openssl.c create mode 100644 lib/hcrypto/evp-openssl.h create mode 100644 lib/hx509/crypto-ec.c create mode 100644 lib/krb5/pkinit-ec.c diff --git a/admin/Makefile.am b/admin/Makefile.am index 21d015780..a4a7bb4c0 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_readline) $(INCLUDE_hcrypto) +AM_CPPFLAGS += $(INCLUDE_readline) man_MANS = ktutil.1 diff --git a/appl/ftp/ftp/Makefile.am b/appl/ftp/ftp/Makefile.am index 8bda036e5..e68c7d291 100644 --- a/appl/ftp/ftp/Makefile.am +++ b/appl/ftp/ftp/Makefile.am @@ -4,7 +4,7 @@ include $(top_srcdir)/Makefile.am.common WFLAGS += $(WFLAGS_LITE) -AM_CPPFLAGS += -I$(srcdir)/../common $(INCLUDE_readline) $(INCLUDE_hcrypto) +AM_CPPFLAGS += -I$(srcdir)/../common $(INCLUDE_readline) bin_PROGRAMS = ftp diff --git a/appl/otp/Makefile.am b/appl/otp/Makefile.am index 07ab13882..d8e5d51dd 100644 --- a/appl/otp/Makefile.am +++ b/appl/otp/Makefile.am @@ -2,8 +2,6 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) - bin_PROGRAMS = otp otpprint bin_SUIDS = otp otp_SOURCES = otp.c otp_locl.h diff --git a/appl/su/Makefile.am b/appl/su/Makefile.am index 0a942ee7d..605aae349 100644 --- a/appl/su/Makefile.am +++ b/appl/su/Makefile.am @@ -2,8 +2,6 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) - bin_PROGRAMS = su bin_SUIDS = su su_SOURCES = su.c supaths.h diff --git a/cf/crypto.m4 b/cf/crypto.m4 index a0b033ff0..b3a1bd0c3 100644 --- a/cf/crypto.m4 +++ b/cf/crypto.m4 @@ -6,7 +6,7 @@ dnl - own-built libhcrypto m4_define([test_headers], [ #undef KRB5 /* makes md4.h et al unhappy */ - #ifdef HAVE_OPENSSL + #ifdef HAVE_HCRYPTO_W_OPENSSL #ifdef HAVE_SYS_TYPES_H #include #endif @@ -54,7 +54,7 @@ m4_define([test_body], [ EVP_CIPHER_iv_length(((EVP_CIPHER*)0)); UI_UTIL_read_pw_string(0,0,0,0); RAND_status(); - #ifdef HAVE_OPENSSL + #ifdef HAVE_HCRYPTO_W_OPENSSL EC_KEY_new(); #endif @@ -63,77 +63,53 @@ m4_define([test_body], [ DES_cbc_encrypt(0, 0, 0, schedule, 0, 0); RC4(0, 0, 0, 0);]) -m4_define([bn_headers], [ - #include - #include - ]) -m4_define([bn_body], [ - BIGNUM *bn = BN_new(); - BN_set_word(bn, 1); - if (BN_is_negative(bn)) - exit(EXIT_FAILURE); - BN_set_negative(bn, 1); - if (!BN_is_negative(bn)) - exit(EXIT_FAILURE); - exit(EXIT_SUCCESS); - ]) - AC_DEFUN([KRB_CRYPTO],[ -crypto_lib=unknown AC_WITH_ALL([openssl]) -DIR_hcrypto= - AC_MSG_CHECKING([for crypto library]) openssl=no -if test "$crypto_lib" = "unknown" -a "$with_openssl" != "no"; then - save_CFLAGS="$CFLAGS" - save_LIBS="$LIBS" - INCLUDE_hcrypto= - LIB_hcrypto= +if test "$with_openssl" = "yes"; then + with_openssl=/usr +fi +if test "$with_openssl" != "no"; then + INCLUDE_openssl_crypto= + LIB_openssl_crypto= if test "$with_openssl_include" != ""; then - INCLUDE_hcrypto="-I${with_openssl_include}" + INCLUDE_openssl_crypto="${with_openssl_include}" + else + INCLUDE_openssl_crypto="${with_openssl}/include" fi if test "$with_openssl_lib" != ""; then - LIB_hcrypto="-L${with_openssl_lib}" + LIB_openssl_crypto="-L${with_openssl_lib}" fi - CFLAGS="-DHAVE_OPENSSL ${INCLUDE_hcrypto} ${CFLAGS}" - saved_LIB_hcrypto="$LIB_hcrypto" - for lres in "" "-ldl" "-lnsl -lsocket" "-lnsl -lsocket -ldl"; do - LIB_hcrypto="${saved_LIB_hcrypto} -lcrypto $lres" - LIB_hcrypto_a="$LIB_hcrypto" - LIB_hcrypto_so="$LIB_hcrypto" - LIB_hcrypto_appl="$LIB_hcrypto" - LIBS="${LIBS} ${LIB_hcrypto}" - AC_LINK_IFELSE([AC_LANG_PROGRAM([test_headers],[test_body])], [ - crypto_lib=libcrypto openssl=yes - AC_MSG_RESULT([libcrypto]) - AC_RUN_IFELSE([AC_LANG_PROGRAM([bn_headers],[bn_body])], [ - AC_DEFINE([HAVE_BN_IS_NEGATIVE], 1, [define if OpenSSL provides BN_is_negative]) - ]) - ]) - if test "$crypto_lib" = libcrypto ; then - break; - fi - done - AC_CHECK_LIB(crypto, OPENSSL_init, []) - CFLAGS="$save_CFLAGS" - LIBS="$save_LIBS" + CFLAGS="-DHAVE_HCRYPTO_W_OPENSSL -I${INCLUDE_openssl_crypto} ${CFLAGS}" + # XXX What about rpath? Yeah... + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto"; openssl=yes], [openssl=no], []) + # These cases are just for static linking on older OSes, + # presumably. + if test "$openssl" = "no"; then + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto -ldl"; openssl=yes], [openssl=no], [-ldl]) + fi + if test "$openssl" = "no"; then + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto -ldl -lnsl"; openssl=yes], [openssl=no], [-ldl -lnsl]) + fi + if test "$openssl" = "no"; then + AC_CHECK_LIB([crypto], [OPENSSL_init], + [LIB_openssl_crypto="${LIB_openssl_crypto} -lcrypto -ldl -lnsl -lsocket"; openssl=yes], [openssl=no], [-ldl -lnsl -lsocket]) + fi fi -if test "$crypto_lib" = "unknown"; then +LIB_hcrypto='$(top_builddir)/lib/hcrypto/libhcrypto.la' +LIB_hcrypto_a='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.a' +LIB_hcrypto_so='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.so' +LIB_hcrypto_appl="-lhcrypto" - DIR_hcrypto='hcrypto' - LIB_hcrypto='$(top_builddir)/lib/hcrypto/libhcrypto.la' - LIB_hcrypto_a='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.a' - LIB_hcrypto_so='$(top_builddir)/lib/hcrypto/.libs/libhcrypto.so' - LIB_hcrypto_appl="-lhcrypto" - - AC_MSG_RESULT([included libhcrypto]) - -fi +AC_MSG_RESULT([included libhcrypto]) AC_ARG_WITH(pkcs11-module, AS_HELP_STRING([--with-pkcs11-module=path], @@ -147,12 +123,12 @@ if test "$pkcs11_module" != ""; then fi if test "$openssl" = "yes"; then - AC_DEFINE([HAVE_OPENSSL], 1, [define to use openssl's libcrypto]) + AC_DEFINE([HAVE_HCRYPTO_W_OPENSSL], 1, [define to use openssl's libcrypto as the default backend for libhcrypto]) fi -AM_CONDITIONAL(HAVE_OPENSSL, test "$openssl" = yes)dnl +AM_CONDITIONAL(HAVE_HCRYPTO_W_OPENSSL, test "$openssl" = yes)dnl -AC_SUBST(DIR_hcrypto) -AC_SUBST(INCLUDE_hcrypto) +AC_SUBST(INCLUDE_openssl_crypto) +AC_SUBST(LIB_openssl_crypto) AC_SUBST(LIB_hcrypto) AC_SUBST(LIB_hcrypto_a) AC_SUBST(LIB_hcrypto_so) diff --git a/include/config.h.w32 b/include/config.h.w32 index 3b23b26dc..b12dee959 100644 --- a/include/config.h.w32 +++ b/include/config.h.w32 @@ -1,5 +1,5 @@ /*********************************************************************** - * Copyright (c) 2009, Secure Endpoints Inc. + * Copyright (c) 2009-2016, Secure Endpoints Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -652,8 +652,8 @@ static const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } /* Define to 1 if you have the `openpty' function. */ /* #define HAVE_OPENPTY 1 */ -/* define to use openssl's libcrypto */ -/* #undef HAVE_OPENSSL */ +/* define to 1 to use openssl's libcrypto as a (default) backend for libhcrypto */ +/* #undef HAVE_HCRYPTO_W_OPENSSL */ /* Define to enable basic OSF C2 support. */ /* #undef HAVE_OSFC2 */ diff --git a/include/crypto-headers.h b/include/crypto-headers.h index d69505455..5c0b24223 100644 --- a/include/crypto-headers.h +++ b/include/crypto-headers.h @@ -5,37 +5,6 @@ #error "need config.h" #endif -#ifdef HAVE_OPENSSL - -#define OPENSSL_DES_LIBDES_COMPATIBILITY - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef HAVE_BN_IS_NEGATIVE -#define BN_set_negative(bn, flag) ((bn)->neg=(flag)?1:0) -#define BN_is_negative(bn) ((bn)->neg != 0) -#endif - -#else /* !HAVE_OPENSSL */ - #ifdef KRB5 #include #endif @@ -52,10 +21,5 @@ #include #include #include -#include -#include -#include - -#endif /* HAVE_OPENSSL */ #endif /* __crypto_header__ */ diff --git a/include/hcrypto/Makefile.am b/include/hcrypto/Makefile.am index 4b76909d6..f15c779a8 100644 --- a/include/hcrypto/Makefile.am +++ b/include/hcrypto/Makefile.am @@ -25,6 +25,7 @@ CLEANFILES = \ rc4.h \ rsa.h \ sha.h \ - ui.h + ui.h \ + undef.h EXTRA_DIST = NTMakefile diff --git a/include/heim_threads.h b/include/heim_threads.h index 8770e174d..7ba845af7 100644 --- a/include/heim_threads.h +++ b/include/heim_threads.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Kungliga Tekniska Högskolan + * Copyright (c) 2003-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * diff --git a/kadmin/Makefile.am b/kadmin/Makefile.am index 085a4dd62..74a2d5492 100644 --- a/kadmin/Makefile.am +++ b/kadmin/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_readline) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5 -I$(top_builddir)/include/gssapi +AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_readline) -I$(srcdir)/../lib/krb5 -I$(top_builddir)/include/gssapi bin_PROGRAMS = kadmin diff --git a/kcm/Makefile.am b/kcm/Makefile.am index 71f63c404..b9649d387 100644 --- a/kcm/Makefile.am +++ b/kcm/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5 +AM_CPPFLAGS += $(INCLUDE_libintl) -I$(srcdir)/../lib/krb5 libexec_PROGRAMS = kcm diff --git a/kdc/Makefile.am b/kdc/Makefile.am index 64bcd2017..ade443ffb 100644 --- a/kdc/Makefile.am +++ b/kdc/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_libintl) $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5 +AM_CPPFLAGS += $(INCLUDE_libintl) -I$(srcdir)/../lib/krb5 lib_LTLIBRARIES = libkdc.la @@ -44,6 +44,7 @@ libkdc_la_SOURCES = \ kerberos5.c \ krb5tgs.c \ pkinit.c \ + pkinit-ec.c \ log.c \ misc.c \ kx509.c \ @@ -108,6 +109,7 @@ libkdc_la_LIBADD = \ $(LIB_kdb) \ $(top_builddir)/lib/ntlm/libheimntlm.la \ $(LIB_hcrypto) \ + $(LIB_openssl_crypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(LIB_roken) \ $(DB3LIB) $(DB1LIB) $(LMDBLIB) $(NDBMLIB) diff --git a/kdc/NTMakefile b/kdc/NTMakefile index b0b6584c6..c4bc69ab1 100644 --- a/kdc/NTMakefile +++ b/kdc/NTMakefile @@ -1,6 +1,6 @@ ######################################################################## # -# Copyright (c) 2009, Secure Endpoints Inc. +# Copyright (c) 2009-2016, Secure Endpoints Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -86,7 +86,7 @@ $(BINDIR)\digest-service.exe: $(OBJ)\digest-service.obj $(BIN_LIBS) $(LIBEXECDIR)\kdc.exe: \ $(OBJ)\connect.obj $(OBJ)\config.obj $(OBJ)\announce.obj \ $(OBJ)\main.obj $(OBJ)\kdc-version.res \ - $(LIBKDC) $(BIN_LIBS) + $(LIBKDC) $(BIN_LIBS) $(LIB_openssl_crypto) $(EXECONLINK) $(EXEPREP) @@ -98,6 +98,7 @@ LIBKDC_OBJS=\ $(OBJ)\kerberos5.obj \ $(OBJ)\krb5tgs.obj \ $(OBJ)\pkinit.obj \ + $(OBJ)\pkinit-ec.obj \ $(OBJ)\log.obj \ $(OBJ)\misc.obj \ $(OBJ)\kx509.obj \ @@ -105,10 +106,11 @@ LIBKDC_OBJS=\ $(OBJ)\windc.obj LIBKDC_LIBS=\ - $(LIBHDB) \ - $(LIBHEIMBASE) \ - $(LIBHEIMDAL) \ - $(LIBHEIMNTLM) \ + $(LIBHDB) \ + $(LIBHEIMBASE) \ + $(LIBHEIMDAL) \ + $(LIBHEIMNTLM) \ + $(LIB_openssl_crypto) \ $(LIBROKEN) LIBKDCRES=$(OBJ)\libkdc-version.res @@ -131,6 +133,7 @@ libkdc_la_SOURCES = \ kerberos5.c \ krb5tgs.c \ pkinit.c \ + pkinit-ec.c \ log.c \ misc.c \ kx509.c \ diff --git a/kdc/pkinit-ec.c b/kdc/pkinit-ec.c new file mode 100644 index 000000000..cbc85bd88 --- /dev/null +++ b/kdc/pkinit-ec.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#ifdef PKINIT + +/* + * As with the other *-ec.c files in Heimdal, this is a bit of a hack. + * + * The idea is to use OpenSSL for EC because hcrypto doesn't have the + * required functionality at this time. To do this we segregate + * EC-using code into separate source files and then we arrange for them + * to get the OpenSSL headers and not the conflicting hcrypto ones. + * + * Because of auto-generated *-private.h headers, we end up needing to + * make sure various types are defined before we include them, thus the + * strange header include order here. + */ + +#ifdef HAVE_HCRYPTO_W_OPENSSL +#include +#include +#include +#include +#define HEIM_NO_CRYPTO_HDRS +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +#ifdef HAVE_STDINT_H +#include +#endif + +#define NO_HCRYPTO_POLLUTION + +#include + +#include "kdc_locl.h" + +#include +#include +#include +#include + +#include + +#ifdef HAVE_HCRYPTO_W_OPENSSL +static void +free_client_ec_param(krb5_context context, + EC_KEY *ec_key_pk, + EC_KEY *ec_key_key) +{ + if (ec_key_pk != NULL) + EC_KEY_free(ec_key_pk); + if (ec_key_key != NULL) + EC_KEY_free(ec_key_key); +} +#endif + +void +_kdc_pk_free_client_ec_param(krb5_context context, + void *ec_key_pk, + void *ec_key_key) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + free_client_ec_param(context, ec_key_pk, ec_key_key); +#endif +} + +#ifdef HAVE_HCRYPTO_W_OPENSSL +static krb5_error_code +generate_ecdh_keyblock(krb5_context context, + EC_KEY *ec_key_pk, /* the client's public key */ + EC_KEY **ec_key_key, /* the KDC's ephemeral private */ + unsigned char **dh_gen_key, /* shared secret */ + size_t *dh_gen_keylen) +{ + const EC_GROUP *group; + EC_KEY *ephemeral; + krb5_keyblock key; + krb5_error_code ret; + unsigned char *p; + size_t size; + int len; + + *dh_gen_key = NULL; + *dh_gen_keylen = 0; + *ec_key_key = NULL; + + memset(&key, 0, sizeof(key)); + + if (ec_key_pk == NULL) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, "public_key"); + return ret; + } + + group = EC_KEY_get0_group(ec_key_pk); + if (group == NULL) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, "failed to get the group of " + "the client's public key"); + return ret; + } + + ephemeral = EC_KEY_new(); + if (ephemeral == NULL) + return krb5_enomem(context); + + EC_KEY_set_group(ephemeral, group); + + if (EC_KEY_generate_key(ephemeral) != 1) { + EC_KEY_free(ephemeral); + return krb5_enomem(context); + } + + size = (EC_GROUP_get_degree(group) + 7) / 8; + p = malloc(size); + if (p == NULL) { + EC_KEY_free(ephemeral); + return krb5_enomem(context); + } + + len = ECDH_compute_key(p, size, + EC_KEY_get0_public_key(ec_key_pk), + ephemeral, NULL); + if (len <= 0) { + free(p); + EC_KEY_free(ephemeral); + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, "Failed to compute ECDH " + "public shared secret"); + return ret; + } + + *ec_key_key = ephemeral; + *dh_gen_key = p; + *dh_gen_keylen = len; + + return 0; +} +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +krb5_error_code +_kdc_generate_ecdh_keyblock(krb5_context context, + void *ec_key_pk, /* the client's public key */ + void **ec_key_key, /* the KDC's ephemeral private */ + unsigned char **dh_gen_key, /* shared secret */ + size_t *dh_gen_keylen) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + return generate_ecdh_keyblock(context, ec_key_pk, + (EC_KEY **)ec_key_key, + dh_gen_key, dh_gen_keylen); +#else + return ENOTSUP; +#endif /* HAVE_HCRYPTO_W_OPENSSL */ +} + +#ifdef HAVE_HCRYPTO_W_OPENSSL +static krb5_error_code +get_ecdh_param(krb5_context context, + krb5_kdc_configuration *config, + SubjectPublicKeyInfo *dh_key_info, + EC_KEY **out) +{ + ECParameters ecp; + EC_KEY *public = NULL; + krb5_error_code ret; + const unsigned char *p; + size_t len; + int nid; + + if (dh_key_info->algorithm.parameters == NULL) { + krb5_set_error_message(context, KRB5_BADMSGTYPE, + "PKINIT missing algorithm parameter " + "in clientPublicValue"); + return KRB5_BADMSGTYPE; + } + + memset(&ecp, 0, sizeof(ecp)); + + ret = decode_ECParameters(dh_key_info->algorithm.parameters->data, + dh_key_info->algorithm.parameters->length, &ecp, &len); + if (ret) + goto out; + + if (ecp.element != choice_ECParameters_namedCurve) { + ret = KRB5_BADMSGTYPE; + goto out; + } + + if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0) + nid = NID_X9_62_prime256v1; + else { + ret = KRB5_BADMSGTYPE; + goto out; + } + + /* XXX verify group is ok */ + + public = EC_KEY_new_by_curve_name(nid); + + p = dh_key_info->subjectPublicKey.data; + len = dh_key_info->subjectPublicKey.length / 8; + if (o2i_ECPublicKey(&public, &p, len) == NULL) { + ret = KRB5_BADMSGTYPE; + krb5_set_error_message(context, ret, + "PKINIT failed to decode ECDH key"); + goto out; + } + *out = public; + public = NULL; + + out: + if (public) + EC_KEY_free(public); + free_ECParameters(&ecp); + return ret; +} +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +krb5_error_code +_kdc_get_ecdh_param(krb5_context context, + krb5_kdc_configuration *config, + SubjectPublicKeyInfo *dh_key_info, + void **out) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + return get_ecdh_param(context, config, dh_key_info, (EC_KEY **)out); +#else + return ENOTSUP; +#endif /* HAVE_HCRYPTO_W_OPENSSL */ +} + + +/* + * + */ + +#ifdef HAVE_HCRYPTO_W_OPENSSL +static krb5_error_code +serialize_ecdh_key(krb5_context context, + EC_KEY *key, + unsigned char **out, + size_t *out_len) +{ + krb5_error_code ret = 0; + unsigned char *p; + int len; + + *out = NULL; + *out_len = 0; + + len = i2o_ECPublicKey(key, NULL); + if (len <= 0) + return EOVERFLOW; + + *out = malloc(len); + if (*out == NULL) + return krb5_enomem(context); + + p = *out; + len = i2o_ECPublicKey(key, &p); + if (len <= 0) { + free(*out); + *out = NULL; + ret = EINVAL; /* XXX Better error please */ + krb5_set_error_message(context, ret, + "PKINIT failed to encode ECDH key"); + return ret; + } + + *out_len = len * 8; + return ret; +} +#endif + +krb5_error_code +_kdc_serialize_ecdh_key(krb5_context context, + void *key, + unsigned char **out, + size_t *out_len) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + return serialize_ecdh_key(context, key, out, out_len); +#else + return ENOTSUP; +#endif +} + +#endif diff --git a/kdc/pkinit.c b/kdc/pkinit.c index 4e35fa681..d92304ae9 100644 --- a/kdc/pkinit.c +++ b/kdc/pkinit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 - 2008 Kungliga Tekniska Högskolan + * Copyright (c) 2003 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -53,12 +53,10 @@ struct pk_client_params { BIGNUM *public_key; DH *key; } dh; -#ifdef HAVE_OPENSSL struct { - EC_KEY *public_key; - EC_KEY *key; + void *public_key; + void *key; } ecdh; -#endif } u; hx509_cert cert; unsigned nonce; @@ -181,14 +179,9 @@ _kdc_pk_free_client_param(krb5_context context, pk_client_params *cp) if (cp->u.dh.public_key) BN_free(cp->u.dh.public_key); } -#ifdef HAVE_OPENSSL - if (cp->keyex == USE_ECDH) { - if (cp->u.ecdh.key) - EC_KEY_free(cp->u.ecdh.key); - if (cp->u.ecdh.public_key) - EC_KEY_free(cp->u.ecdh.public_key); - } -#endif + if (cp->keyex == USE_ECDH) + _kdc_pk_free_client_ec_param(context, cp->u.ecdh.key, + cp->u.ecdh.public_key); krb5_free_keyblock_contents(context, &cp->reply_key); if (cp->dh_group_name) free(cp->dh_group_name); @@ -216,7 +209,7 @@ generate_dh_keyblock(krb5_context context, if (client_params->u.dh.public_key == NULL) { ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, "public_key"); + krb5_set_error_message(context, ret, "missing DH public_key"); goto out; } @@ -250,42 +243,18 @@ generate_dh_keyblock(krb5_context context, } ret = 0; -#ifdef HAVE_OPENSSL } else if (client_params->keyex == USE_ECDH) { - if (client_params->u.ecdh.public_key == NULL) { ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, "public_key"); + krb5_set_error_message(context, ret, "missing ECDH public_key"); goto out; } - - client_params->u.ecdh.key = EC_KEY_new(); - if (client_params->u.ecdh.key == NULL) { - ret = ENOMEM; - goto out; - } - EC_KEY_set_group(client_params->u.ecdh.key, - EC_KEY_get0_group(client_params->u.ecdh.public_key)); - - if (EC_KEY_generate_key(client_params->u.ecdh.key) != 1) { - ret = ENOMEM; - goto out; - } - - size = (EC_GROUP_get_degree(EC_KEY_get0_group(client_params->u.ecdh.key)) + 7) / 8; - dh_gen_key = malloc(size); - if (dh_gen_key == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, - N_("malloc: out of memory", "")); - goto out; - } - - dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, - EC_KEY_get0_public_key(client_params->u.ecdh.public_key), - client_params->u.ecdh.key, NULL); - -#endif /* HAVE_OPENSSL */ + ret = _kdc_generate_ecdh_keyblock(context, + client_params->u.ecdh.public_key, + &client_params->u.ecdh.key, + &dh_gen_key, &dh_gen_keylen); + if (ret) + goto out; } else { ret = KRB5KRB_ERR_GENERIC; krb5_set_error_message(context, ret, @@ -422,71 +391,6 @@ get_dh_param(krb5_context context, return ret; } -#ifdef HAVE_OPENSSL - -static krb5_error_code -get_ecdh_param(krb5_context context, - krb5_kdc_configuration *config, - SubjectPublicKeyInfo *dh_key_info, - pk_client_params *client_params) -{ - ECParameters ecp; - EC_KEY *public = NULL; - krb5_error_code ret; - const unsigned char *p; - size_t len; - int nid; - - if (dh_key_info->algorithm.parameters == NULL) { - krb5_set_error_message(context, KRB5_BADMSGTYPE, - "PKINIT missing algorithm parameter " - "in clientPublicValue"); - return KRB5_BADMSGTYPE; - } - - memset(&ecp, 0, sizeof(ecp)); - - ret = decode_ECParameters(dh_key_info->algorithm.parameters->data, - dh_key_info->algorithm.parameters->length, &ecp, &len); - if (ret) - goto out; - - if (ecp.element != choice_ECParameters_namedCurve) { - ret = KRB5_BADMSGTYPE; - goto out; - } - - if (der_heim_oid_cmp(&ecp.u.namedCurve, &asn1_oid_id_ec_group_secp256r1) == 0) - nid = NID_X9_62_prime256v1; - else { - ret = KRB5_BADMSGTYPE; - goto out; - } - - /* XXX verify group is ok */ - - public = EC_KEY_new_by_curve_name(nid); - - p = dh_key_info->subjectPublicKey.data; - len = dh_key_info->subjectPublicKey.length / 8; - if (o2i_ECPublicKey(&public, &p, len) == NULL) { - ret = KRB5_BADMSGTYPE; - krb5_set_error_message(context, ret, - "PKINIT failed to decode ECDH key"); - goto out; - } - client_params->u.ecdh.public_key = public; - public = NULL; - - out: - if (public) - EC_KEY_free(public); - free_ECParameters(&ecp); - return ret; -} - -#endif /* HAVE_OPENSSL */ - krb5_error_code _kdc_pk_rd_padata(krb5_context context, krb5_kdc_configuration *config, @@ -829,12 +733,11 @@ _kdc_pk_rd_padata(krb5_context context, cp->keyex = USE_DH; ret = get_dh_param(context, config, ap.clientPublicValue, cp); -#ifdef HAVE_OPENSSL } else if (der_heim_oid_cmp(&ap.clientPublicValue->algorithm.algorithm, &asn1_oid_id_ecPublicKey) == 0) { cp->keyex = USE_ECDH; - ret = get_ecdh_param(context, config, - ap.clientPublicValue, cp); -#endif /* HAVE_OPENSSL */ + ret = _kdc_get_ecdh_param(context, config, + ap.clientPublicValue, + &cp->u.ecdh.public_key); } else { ret = KRB5_BADMSGTYPE; krb5_set_error_message(context, ret, "PKINIT unknown DH mechanism"); @@ -1134,26 +1037,13 @@ pk_mk_pa_reply_dh(krb5_context context, dh_info.subjectPublicKey.length = buf.length * 8; dh_info.subjectPublicKey.data = buf.data; krb5_data_zero(&buf); -#ifdef HAVE_OPENSSL } else if (cp->keyex == USE_ECDH) { - unsigned char *p; - int len; - - len = i2o_ECPublicKey(cp->u.ecdh.key, NULL); - if (len <= 0) - abort(); - - p = malloc(len); - if (p == NULL) - abort(); - - dh_info.subjectPublicKey.length = len * 8; - dh_info.subjectPublicKey.data = p; - - len = i2o_ECPublicKey(cp->u.ecdh.key, &p); - if (len <= 0) - abort(); -#endif + unsigned char *p; + ret = _kdc_serialize_ecdh_key(context, cp->u.ecdh.key, &p, + &dh_info.subjectPublicKey.length); + dh_info.subjectPublicKey.data = p; + if (ret) + goto out; } else krb5_abortx(context, "no keyex selected ?"); @@ -1329,9 +1219,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, switch (cp->keyex) { case USE_DH: type = "dh"; break; -#ifdef HAVE_OPENSSL case USE_ECDH: type = "ecdh"; break; -#endif default: krb5_abortx(context, "unknown keyex"); break; } diff --git a/kpasswd/Makefile.am b/kpasswd/Makefile.am index c2bfb6588..88132df6a 100644 --- a/kpasswd/Makefile.am +++ b/kpasswd/Makefile.am @@ -2,8 +2,6 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) - man_MANS = kpasswd.1 kpasswdd.8 bin_PROGRAMS = kpasswd diff --git a/kuser/Makefile.am b/kuser/Makefile.am index 64b23be53..c62b203fc 100644 --- a/kuser/Makefile.am +++ b/kuser/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) -I$(srcdir)/../lib/krb5 \ +AM_CPPFLAGS += -I$(srcdir)/../lib/krb5 \ $(INCLUDE_libintl) \ -DHEIMDAL_LOCALEDIR='"$(localedir)"' diff --git a/lib/NTMakefile b/lib/NTMakefile index f97c4c0d7..4a6d2543d 100644 --- a/lib/NTMakefile +++ b/lib/NTMakefile @@ -1,6 +1,6 @@ ######################################################################## # -# Copyright (c) 2009,2011, Secure Endpoints Inc. +# Copyright (c) 2009-2016, Secure Endpoints Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/lib/base/test_base.c b/lib/base/test_base.c index b12e778a0..250708df2 100644 --- a/lib/base/test_base.c +++ b/lib/base/test_base.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kungliga Tekniska Högskolan + * Copyright (c) 2010-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * diff --git a/lib/gssapi/Makefile.am b/lib/gssapi/Makefile.am index 3158bb022..c2be0b3dc 100644 --- a/lib/gssapi/Makefile.am +++ b/lib/gssapi/Makefile.am @@ -12,8 +12,7 @@ AM_CPPFLAGS += \ -I$(srcdir)/ntlm \ -I$(srcdir)/krb5 \ -I$(srcdir)/spnego \ - $(INCLUDE_libintl) \ - $(INCLUDE_hcrypto) + $(INCLUDE_libintl) lib_LTLIBRARIES = libgssapi.la diff --git a/lib/gssapi/ntlm/crypto.c b/lib/gssapi/ntlm/crypto.c index 80373a007..40469a7a7 100644 --- a/lib/gssapi/ntlm/crypto.c +++ b/lib/gssapi/ntlm/crypto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * diff --git a/lib/hcrypto/Makefile.am b/lib/hcrypto/Makefile.am index c24f72bfa..d2bb42494 100644 --- a/lib/hcrypto/Makefile.am +++ b/lib/hcrypto/Makefile.am @@ -2,8 +2,12 @@ include $(top_srcdir)/Makefile.am.common +if HAVE_HCRYPTO_W_OPENSSL +AM_CPPFLAGS += -I$(INCLUDE_openssl_crypto) +endif + AM_CPPFLAGS += -I$(top_srcdir)/lib/hx509 \ - -I$(srcdir)/libtommath -DUSE_HCRYPTO_LTM=1 + -I$(srcdir)/libtommath -DUSE_HCRYPTO_LTM=1 lib_LTLIBRARIES = libhcrypto.la check_LTLIBRARIES = libhctest.la @@ -15,6 +19,10 @@ libhcrypto_la_LIBADD = \ $(LIB_heimbase) \ $(LIBADD_roken) +if HAVE_HCRYPTO_W_OPENSSL +libhcrypto_la_LIBADD += $(LIB_openssl_crypto) +endif + hcryptoincludedir = $(includedir)/hcrypto buildhcryptoinclude = $(buildinclude)/hcrypto @@ -31,6 +39,7 @@ hcryptoinclude_HEADERS = \ evp.h \ evp-hcrypto.h \ evp-cc.h \ + evp-openssl.h \ evp-pkcs11.h \ hmac.h \ md2.h \ @@ -42,7 +51,8 @@ hcryptoinclude_HEADERS = \ rc4.h \ rsa.h \ sha.h \ - ui.h + ui.h \ + undef.h install-build-headers:: $(hcryptoinclude_HEADERS) @foo='$(hcryptoinclude_HEADERS)'; \ @@ -117,6 +127,7 @@ libhcrypto_la_SOURCES = \ evp.h \ evp-hcrypto.c \ evp-cc.c \ + evp-openssl.c \ evp-pkcs11.c \ engine.c \ engine.h \ @@ -154,7 +165,8 @@ libhcrypto_la_SOURCES = \ sha512.c \ validate.c \ ui.c \ - ui.h + ui.h \ + undef.h ltmsources = \ libtommath/tommath.h \ diff --git a/lib/hcrypto/NTMakefile b/lib/hcrypto/NTMakefile index 9d0fe74b1..c35059517 100644 --- a/lib/hcrypto/NTMakefile +++ b/lib/hcrypto/NTMakefile @@ -1,6 +1,6 @@ ######################################################################## # -# Copyright (c) 2009, Secure Endpoints Inc. +# Copyright (c) 2009-2016, Secure Endpoints Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -41,8 +41,12 @@ HEIMBASEDIR = $(SRC)\lib\base HX509DIR = $(SRC)\lib\hx509 +!if INCLUDE_openssl_crypto +openssl_inc=-I$(INCLUDE_openssl_crypto) +!endif + intcflags=-DKRB5 -DASN1_LIB -I$(HCRYPTOINCLUDEDIR) -DUSE_HCRYPTO_LTM=1 \ - -I$(HX509DIR) + -I$(HX509DIR) $(openssl_inc) # Do dependencies first @@ -67,6 +71,7 @@ INCFILES= \ $(HCRYPTOINCLUDEDIR)\evp.h \ $(HCRYPTOINCLUDEDIR)\evp-hcrypto.h \ $(HCRYPTOINCLUDEDIR)\evp-cc.h \ + $(HCRYPTOINCLUDEDIR)\evp-openssl.h \ $(HCRYPTOINCLUDEDIR)\evp-pkcs11.h \ $(HCRYPTOINCLUDEDIR)\evp-wincng.h \ $(HCRYPTOINCLUDEDIR)\evp-w32.h \ @@ -81,7 +86,8 @@ INCFILES= \ $(HCRYPTOINCLUDEDIR)\rc4.h \ $(HCRYPTOINCLUDEDIR)\rsa.h \ $(HCRYPTOINCLUDEDIR)\sha.h \ - $(HCRYPTOINCLUDEDIR)\ui.h + $(HCRYPTOINCLUDEDIR)\ui.h \ + $(HCRYPTOINCLUDEDIR)\undef.h mkincdir: !if !exist($(HCRYPTOINCLUDEDIR)) @@ -111,6 +117,7 @@ libhcrypto_OBJs = \ $(OBJ)\evp.obj \ $(OBJ)\evp-hcrypto.obj \ $(OBJ)\evp-cc.obj \ + $(OBJ)\evp-openssl.obj \ $(OBJ)\evp-pkcs11.obj \ $(OBJ)\evp-wincng.obj \ $(OBJ)\evp-w32.obj \ diff --git a/lib/hcrypto/bn.h b/lib/hcrypto/bn.h index 3b78c220d..727b919a3 100644 --- a/lib/hcrypto/bn.h +++ b/lib/hcrypto/bn.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -72,6 +72,8 @@ #define BN_GENCB hc_BN_GENCB #define BN_CTX hc_BN_CTX #define BN_BLINDING hc_BN_BLINDING +#define BN_MONT_CTX hc_BN_MONT_CTX + /* * diff --git a/lib/hcrypto/dh.h b/lib/hcrypto/dh.h index 637f218bc..61868054b 100644 --- a/lib/hcrypto/dh.h +++ b/lib/hcrypto/dh.h @@ -39,6 +39,8 @@ #define _HEIM_DH_H 1 /* symbol renaming */ +#define DH hc_DH +#define DH_METHOD hc_DH_METHOD #define DH_null_method hc_DH_null_method #define DH_tfm_method hc_DH_tfm_method #define DH_ltm_method hc_DH_ltm_method diff --git a/lib/hcrypto/dsa.h b/lib/hcrypto/dsa.h index 686d05087..a8f087f79 100644 --- a/lib/hcrypto/dsa.h +++ b/lib/hcrypto/dsa.h @@ -41,6 +41,8 @@ #include /* symbol renaming */ +#define DSA hc_DSA +#define DSA_METHOD hc_DSA_METHOD #define DSA_null_method hc_DSA_null_method #define DSA_new hc_DSA_new #define DSA_free hc_DSA_free diff --git a/lib/hcrypto/ec.h b/lib/hcrypto/ec.h index ac6e87788..726deec61 100644 --- a/lib/hcrypto/ec.h +++ b/lib/hcrypto/ec.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Kungliga Tekniska Högskolan + * Copyright (c) 2009-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * diff --git a/lib/hcrypto/engine.h b/lib/hcrypto/engine.h index 2ee745e4e..e6fc5b92e 100644 --- a/lib/hcrypto/engine.h +++ b/lib/hcrypto/engine.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * diff --git a/lib/hcrypto/evp-openssl.c b/lib/hcrypto/evp-openssl.c new file mode 100644 index 000000000..188c09797 --- /dev/null +++ b/lib/hcrypto/evp-openssl.c @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2016, Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* OpenSSL provider */ + +#include "config.h" +#include +#include + +#include + +#ifdef HAVE_HCRYPTO_W_OPENSSL + +/* + * This is the OpenSSL 1.x backend for hcrypto. It has been tested with + * OpenSSL 1.0.1f and OpenSSL 1.1.0-pre3-dev. + * + * NOTE: In order for this to work with OpenSSL 1.1.x and up, it is + * critical to use opaque OpenSSL type accessors everywhere / + * never use knowledge of opaque OpenSSL type internals. + */ + +#include +#include + +/* + * This being an OpenSSL backend for hcrypto... we need to be able to + * refer to types and objects (functions) from both, OpenSSL and + * hcrypto. + * + * The hcrypto API is *very* similar to the OpenSSL 1.0.x API, with the + * same type and symbol names in many cases, except that the hcrypto + * names are prefixed with hc_*. hcrypto has convenience macros that + * provide OpenSSL aliases for the hcrypto interfaces, and hcrypto + * applications are expected to use the OpenSSL names. + * + * Since here we must be able to refer to types and objects from both + * OpenSSL and from hcrypto, we disable the hcrypto renaming for the + * rest of this file. These #undefs could be collected into an + * for the purpose of permitting other applications to + * use both, hcrypto and OpenSSL in the same source files (provided that + * such applications refer to hcrypto types and objects by their proper + * hc_-prefixed names). + */ +#include + +/* Now it's safe to include OpenSSL headers */ +#include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define EVP_MD_CTX_new EVP_MD_CTX_create +#define EVP_MD_CTX_free EVP_MD_CTX_destroy +#endif + +/* A HEIM_BASE_ONCE argument struct for per-EVP one-time initialization */ +struct once_init_cipher_ctx { + hc_EVP_CIPHER **hc_memoizep; /* ptr to static ptr to hc_EVP_CIPHER */ + hc_EVP_CIPHER *hc_memoize; /* ptr to static hc_EVP_CIPHER */ + unsigned long flags; + unsigned char *initialized; + int nid; +}; + +/* Our wrapper for OpenSSL EVP_CIPHER_CTXs */ +struct ossl_cipher_ctx { + EVP_CIPHER_CTX *ossl_cipher_ctx; /* OpenSSL cipher ctx */ + const EVP_CIPHER *ossl_cipher; /* OpenSSL cipher */ + int initialized; +}; + +/* + * Our hc_EVP_CIPHER init() method; wraps around OpenSSL + * EVP_CipherInit_ex(). + * + * This is very similar to the init() function pointer in an OpenSSL + * EVP_CIPHER, but a) we can't access them in 1.1, and b) the method + * invocation protocols in hcrypto and OpenSSL are similar but not the + * same, thus we must have this wrapper. + */ +static int +cipher_ctx_init(hc_EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; /* EVP_CIPHER_CTX wrapper */ + const EVP_CIPHER *c; + + assert(ossl_ctx != NULL); + assert(ctx->cipher != NULL); + assert(ctx->cipher->app_data != NULL); + + /* + * Here be dragons. + * + * We need to make sure that the OpenSSL EVP_CipherInit_ex() is + * called with cipher!=NULL just once per EVP_CIPHER_CTX, otherwise + * state in the OpenSSL EVP_CIPHER_CTX will get cleaned up and then + * we'll segfault. + * + * hcrypto applications can re-initialize an (hc_)EVP_CIPHER_CTX as + * usual by calling (hc)EVP_CipherInit_ex() with a non-NULL cipher + * argument, and that will cause cipher_cleanup() (below) to be + * called. + */ + c = ossl_ctx->ossl_cipher = ctx->cipher->app_data; /* OpenSSL's EVP_CIPHER * */ + if (!ossl_ctx->initialized) { + ossl_ctx->ossl_cipher_ctx = EVP_CIPHER_CTX_new(); + if (ossl_ctx->ossl_cipher_ctx == NULL) + return 0; + /* + * So we always call EVP_CipherInit_ex() with c!=NULL, but other + * things NULL... + */ + if (!EVP_CipherInit_ex(ossl_ctx->ossl_cipher_ctx, c, NULL, NULL, NULL, enc)) + return 0; + ossl_ctx->initialized = 1; + } + + /* ...and from here on always call EVP_CipherInit_ex() with c=NULL */ + if ((ctx->cipher->flags & hc_EVP_CIPH_VARIABLE_LENGTH) && + ctx->key_len > 0) + EVP_CIPHER_CTX_set_key_length(ossl_ctx->ossl_cipher_ctx, ctx->key_len); + + return EVP_CipherInit_ex(ossl_ctx->ossl_cipher_ctx, NULL, NULL, key, iv, enc); +} + +static int +cipher_do_cipher(hc_EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, unsigned int len) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; + + assert(ossl_ctx != NULL); + return EVP_Cipher(ossl_ctx->ossl_cipher_ctx, out, in, len); +} + +static int +cipher_cleanup(hc_EVP_CIPHER_CTX *ctx) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; + + if (ossl_ctx == NULL || !ossl_ctx->initialized) + return 1; + + if (ossl_ctx->ossl_cipher_ctx != NULL) + EVP_CIPHER_CTX_free(ossl_ctx->ossl_cipher_ctx); + + ossl_ctx->ossl_cipher_ctx = NULL; + ossl_ctx->ossl_cipher = NULL; + ossl_ctx->initialized = 0; + return 1; +} + +static int +cipher_ctrl(hc_EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +{ + struct ossl_cipher_ctx *ossl_ctx = ctx->cipher_data; + + assert(ossl_ctx != NULL); + return EVP_CIPHER_CTX_ctrl(ossl_ctx->ossl_cipher_ctx, type, arg, ptr); +} + + +static void +get_EVP_CIPHER_once_cb(void *d) +{ + struct once_init_cipher_ctx *arg = d; + const EVP_CIPHER *ossl_evp; + hc_EVP_CIPHER *hc_evp; + + hc_evp = arg->hc_memoize; + + /* + * We lookup EVP_CIPHER *s by NID so that we don't fail to find a + * symbol such as EVP_aes...() when libcrypto changes after build + * time (e.g., updates, LD_LIBRARY_PATH/LD_PRELOAD). + */ + ossl_evp = EVP_get_cipherbynid(arg->nid); + if (ossl_evp == NULL) { + (void) memset(hc_evp, 0, sizeof(*hc_evp)); + *arg->hc_memoizep = NULL; + *arg->initialized = 1; + return; + } + + /* Build the hc_EVP_CIPHER */ + hc_evp->nid = EVP_CIPHER_nid(ossl_evp); /* We would an hcrypto NIDs if we had them */ + hc_evp->block_size = EVP_CIPHER_block_size(ossl_evp); + hc_evp->key_len = EVP_CIPHER_key_length(ossl_evp); + hc_evp->iv_len = EVP_CIPHER_iv_length(ossl_evp); + + /* + * We force hc_EVP_CipherInit_ex to always call our init() function, + * otherwise we don't get a chance to call EVP_CipherInit_ex() + * correctly. + */ + hc_evp->flags = hc_EVP_CIPH_ALWAYS_CALL_INIT | arg->flags; + + /* Our cipher context */ + hc_evp->ctx_size = sizeof(struct ossl_cipher_ctx); + + /* Our wrappers */ + hc_evp->init = cipher_ctx_init; + hc_evp->do_cipher = cipher_do_cipher; + hc_evp->cleanup = cipher_cleanup; + hc_evp->set_asn1_parameters = NULL; + hc_evp->get_asn1_parameters = NULL; + hc_evp->ctrl = cipher_ctrl; + + /* Our link to the OpenSSL EVP_CIPHER */ + hc_evp->app_data = (void *)ossl_evp; + + /* Finally, set the static hc_EVP_CIPHER * to the one we just built */ + *arg->hc_memoizep = hc_evp; + *arg->initialized = 1; +} + +static hc_EVP_CIPHER * +get_EVP_CIPHER(heim_base_once_t *once, hc_EVP_CIPHER *hc_memoize, + hc_EVP_CIPHER **hc_memoizep, unsigned long flags, + unsigned char *initialized, int nid) +{ + struct once_init_cipher_ctx arg; + + arg.flags = flags; + arg.hc_memoizep = hc_memoizep; + arg.hc_memoize = hc_memoize; + arg.initialized = initialized; + arg.nid = nid; + heim_base_once_f(once, &arg, get_EVP_CIPHER_once_cb); + return *hc_memoizep; /* May be NULL */ +} + +#define OSSL_CIPHER_ALGORITHM(name, flags) \ + const hc_EVP_CIPHER *hc_EVP_ossl_##name(void) \ + { \ + static hc_EVP_CIPHER ossl_##name##_st; \ + static hc_EVP_CIPHER *ossl_##name; \ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; \ + static unsigned char initialized; \ + if (initialized) \ + return ossl_##name; \ + return get_EVP_CIPHER(&once, &ossl_##name##_st, &ossl_##name, \ + flags, &initialized, NID_##name); \ + } + +/* As above, but for EVP_MDs */ + +struct ossl_md_ctx { + EVP_MD_CTX *ossl_md_ctx; /* OpenSSL md ctx */ + const EVP_MD *ossl_md; /* OpenSSL md */ + int initialized; +}; + +static int +ossl_md_init(struct ossl_md_ctx *ctx, const EVP_MD *md) +{ + if (ctx->initialized) + EVP_MD_CTX_free(ctx->ossl_md_ctx); + ctx->initialized = 0; + + ctx->ossl_md = md; + ctx->ossl_md_ctx = EVP_MD_CTX_new(); + if (!EVP_DigestInit(ctx->ossl_md_ctx, md)) { + EVP_MD_CTX_free(ctx->ossl_md_ctx); + ctx->ossl_md_ctx = NULL; + ctx->ossl_md = NULL; + return 0; + } + ctx->initialized = 1; + return 1; +} + +static int +ossl_md_update(hc_EVP_MD_CTX *d, const void *data, size_t count) +{ + struct ossl_md_ctx *ctx = (void *)d; + + return EVP_DigestUpdate(ctx->ossl_md_ctx, data, count); +} + +static int +ossl_md_final(void *md_data, hc_EVP_MD_CTX *d) +{ + struct ossl_md_ctx *ctx = (void *)d; + + return EVP_DigestFinal(ctx->ossl_md_ctx, md_data, NULL); +} + +static int +ossl_md_cleanup(hc_EVP_MD_CTX *d) +{ + struct ossl_md_ctx *ctx = (void *)d; + + if (!ctx->initialized) + return 1; + EVP_MD_CTX_free(ctx->ossl_md_ctx); + ctx->ossl_md = NULL; + ctx->initialized = 0; + + return 1; +} + +struct once_init_md_ctx { + const EVP_MD **ossl_memoizep; + hc_EVP_MD **hc_memoizep; + hc_EVP_MD *hc_memoize; + hc_evp_md_init md_init; + int nid; + unsigned char *initialized; +}; + +static void +get_EVP_MD_once_cb(void *d) +{ + struct once_init_md_ctx *arg = d; + const EVP_MD *ossl_evp; + hc_EVP_MD *hc_evp; + + hc_evp = arg->hc_memoize; + *arg->ossl_memoizep = ossl_evp = EVP_get_digestbynid(arg->nid); + + if (ossl_evp == NULL) { + (void) memset(hc_evp, 0, sizeof(*hc_evp)); + *arg->hc_memoizep = NULL; + *arg->initialized = 1; + return; + } + + /* Build the hc_EVP_MD */ + hc_evp->ctx_size = sizeof(struct ossl_md_ctx); + hc_evp->init = arg->md_init; + hc_evp->update = ossl_md_update; + hc_evp->final = ossl_md_final; + hc_evp->cleanup = ossl_md_cleanup; + + *arg->hc_memoizep = hc_evp; + *arg->initialized = 1; +} + +static hc_EVP_MD * +get_EVP_MD(heim_base_once_t *once, hc_EVP_MD *hc_memoize, + hc_EVP_MD **hc_memoizep, const EVP_MD **ossl_memoizep, + hc_evp_md_init md_init, unsigned char *initialized, int nid) +{ + struct once_init_md_ctx ctx; + + ctx.ossl_memoizep = ossl_memoizep; + ctx.hc_memoizep = hc_memoizep; + ctx.hc_memoize = hc_memoize; + ctx.md_init = md_init; + ctx.initialized = initialized; + ctx.nid = nid; + heim_base_once_f(once, &ctx, get_EVP_MD_once_cb); + return *hc_memoizep; /* May be NULL */ +} + +#define OSSL_MD_ALGORITHM(name) \ + static const EVP_MD *ossl_EVP_##name; \ + static hc_EVP_MD *ossl_##name; \ + static int ossl_init_##name(hc_EVP_MD_CTX *d) \ + { \ + return ossl_md_init((void *)d, ossl_EVP_##name); \ + } \ + const hc_EVP_MD *hc_EVP_ossl_##name(void) \ + { \ + static hc_EVP_MD ossl_##name##_st; \ + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; \ + static unsigned char initialized; \ + if (initialized) \ + return ossl_##name; \ + return get_EVP_MD(&once, &ossl_##name##_st, &ossl_##name, \ + &ossl_EVP_##name, ossl_init_##name, \ + &initialized, NID_##name); \ + } + +/** + * The triple DES cipher type (OpenSSL provider) + * + * @return the DES-EDE3-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(des_ede3_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The DES cipher type (OpenSSL provider) + * + * @return the DES-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(des_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The AES-128 cipher type (OpenSSL provider) + * + * @return the AES-128-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_128_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The AES-192 cipher type (OpenSSL provider) + * + * @return the AES-192-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_192_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The AES-256 cipher type (OpenSSL provider) + * + * @return the AES-256-CBC EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_256_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The AES-128 CFB8 cipher type (OpenSSL provider) + * + * @return the AES-128-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_128_cfb8, hc_EVP_CIPH_CFB8_MODE) + +/** + * The AES-192 CFB8 cipher type (OpenSSL provider) + * + * @return the AES-192-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_192_cfb8, hc_EVP_CIPH_CFB8_MODE) + +/** + * The AES-256 CFB8 cipher type (OpenSSL provider) + * + * @return the AES-256-CFB8 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(aes_256_cfb8, hc_EVP_CIPH_CFB8_MODE) + +/* + * RC2 is only needed for tests of PKCS#12 support, which currently uses + * the RC2 PBE. So no RC2 -> tests fail. + */ + +/** + * The RC2 cipher type - OpenSSL + * + * @return the RC2 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc2_cbc, + hc_EVP_CIPH_CBC_MODE | + hc_EVP_CIPH_VARIABLE_LENGTH) + +/** + * The RC2-40 cipher type - OpenSSL + * + * @return the RC2-40 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc2_40_cbc, + hc_EVP_CIPH_CBC_MODE) + +/** + * The RC2-64 cipher type - OpenSSL + * + * @return the RC2-64 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc2_64_cbc, + hc_EVP_CIPH_CBC_MODE | + hc_EVP_CIPH_VARIABLE_LENGTH) + +/** + * The Camellia-128 cipher type - OpenSSL + * + * @return the Camellia-128 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(camellia_128_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The Camellia-198 cipher type - OpenSSL + * + * @return the Camellia-198 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(camellia_192_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The Camellia-256 cipher type - OpenSSL + * + * @return the Camellia-256 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(camellia_256_cbc, hc_EVP_CIPH_CBC_MODE) + +/** + * The RC4 cipher type (OpenSSL provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc4, + hc_EVP_CIPH_STREAM_CIPHER | + hc_EVP_CIPH_VARIABLE_LENGTH) + +/** + * The RC4-40 cipher type (OpenSSL provider) + * + * @return the RC4 EVP_CIPHER pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_CIPHER_ALGORITHM(rc4_40, + hc_EVP_CIPH_STREAM_CIPHER | + hc_EVP_CIPH_VARIABLE_LENGTH) + +/** + * The MD2 hash algorithm (OpenSSL provider) + * + * @return the MD2 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(md2) + +/** + * The MD4 hash algorithm (OpenSSL provider) + * + * @return the MD4 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(md4) + +/** + * The MD5 hash algorithm (OpenSSL provider) + * + * @return the MD5 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(md5) + +/** + * The SHA-1 hash algorithm (OpenSSL provider) + * + * @return the SHA-1 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha1) + +/** + * The SHA-256 hash algorithm (OpenSSL provider) + * + * @return the SHA-256 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha256) + +/** + * The SHA-384 hash algorithm (OpenSSL provider) + * + * @return the SHA-384 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha384) + +/** + * The SHA-512 hash algorithm (OpenSSL provider) + * + * @return the SHA-512 EVP_MD pointer. + * + * @ingroup hcrypto_evp + */ +OSSL_MD_ALGORITHM(sha512) + +#else /* HAVE_HCRYPTO_W_OPENSSL */ +static char dummy; +#endif /* HAVE_HCRYPTO_W_OPENSSL */ diff --git a/lib/hcrypto/evp-openssl.h b/lib/hcrypto/evp-openssl.h new file mode 100644 index 000000000..225ff454a --- /dev/null +++ b/lib/hcrypto/evp-openssl.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009-2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +#ifndef HEIM_EVP_OSSL_H +#define HEIM_EVP_OSSL_H 1 + +/* symbol renaming */ +#define EVP_ossl_md2 hc_EVP_ossl_md2 +#define EVP_ossl_md4 hc_EVP_ossl_md4 +#define EVP_ossl_md5 hc_EVP_ossl_md5 +#define EVP_ossl_sha1 hc_EVP_ossl_sha1 +#define EVP_ossl_sha256 hc_EVP_ossl_sha256 +#define EVP_ossl_sha384 hc_EVP_ossl_sha384 +#define EVP_ossl_sha512 hc_EVP_ossl_sha512 +#define EVP_ossl_des_cbc hc_EVP_ossl_des_cbc +#define EVP_ossl_des_ede3_cbc hc_EVP_ossl_des_ede3_cbc +#define EVP_ossl_aes_128_cbc hc_EVP_ossl_aes_128_cbc +#define EVP_ossl_aes_192_cbc hc_EVP_ossl_aes_192_cbc +#define EVP_ossl_aes_256_cbc hc_EVP_ossl_aes_256_cbc +#define EVP_ossl_aes_128_cfb8 hc_EVP_ossl_aes_128_cfb8 +#define EVP_ossl_aes_192_cfb8 hc_EVP_ossl_aes_192_cfb8 +#define EVP_ossl_aes_256_cfb8 hc_EVP_ossl_aes_256_cfb8 +#define EVP_ossl_rc4 hc_EVP_ossl_rc4 +#define EVP_ossl_rc4_40 hc_EVP_ossl_rc4_40 +#define EVP_ossl_rc2_40_cbc hc_EVP_ossl_rc2_40_cbc +#define EVP_ossl_rc2_64_cbc hc_EVP_ossl_rc2_64_cbc +#define EVP_ossl_rc2_cbc hc_EVP_ossl_rc2_cbc +#define EVP_ossl_camellia_128_cbc hc_EVP_ossl_camellia_128_cbc +#define EVP_ossl_camellia_192_cbc hc_EVP_ossl_camellia_192_cbc +#define EVP_ossl_camellia_256_cbc hc_EVP_ossl_camellia_256_cbc + +/* + * + */ + +HC_CPP_BEGIN + +const hc_EVP_MD * hc_EVP_ossl_md2(void); +const hc_EVP_MD * hc_EVP_ossl_md4(void); +const hc_EVP_MD * hc_EVP_ossl_md5(void); +const hc_EVP_MD * hc_EVP_ossl_sha1(void); +const hc_EVP_MD * hc_EVP_ossl_sha256(void); +const hc_EVP_MD * hc_EVP_ossl_sha384(void); +const hc_EVP_MD * hc_EVP_ossl_sha512(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_rc2_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_rc2_40_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_rc2_64_cbc(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_rc4(void); +const hc_EVP_CIPHER * hc_EVP_ossl_rc4_40(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_des_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_des_ede3_cbc(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_aes_128_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_192_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_256_cbc(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_aes_128_cfb8(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_192_cfb8(void); +const hc_EVP_CIPHER * hc_EVP_ossl_aes_256_cfb8(void); + +const hc_EVP_CIPHER * hc_EVP_ossl_camellia_128_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_camellia_192_cbc(void); +const hc_EVP_CIPHER * hc_EVP_ossl_camellia_256_cbc(void); + +HC_CPP_END + +#endif /* HEIM_EVP_OSSL_H */ diff --git a/lib/hcrypto/evp-pkcs11.c b/lib/hcrypto/evp-pkcs11.c index 5c1bc6c18..ed0d2fc49 100644 --- a/lib/hcrypto/evp-pkcs11.c +++ b/lib/hcrypto/evp-pkcs11.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Secure Endpoints Inc. + * Copyright (c) 2015-2016, Secure Endpoints Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/lib/hcrypto/evp.c b/lib/hcrypto/evp.c index a8aeb53bf..5e7c2e83f 100644 --- a/lib/hcrypto/evp.c +++ b/lib/hcrypto/evp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -54,6 +55,8 @@ # define HCRYPTO_DEF_PROVIDER cc # elif __sun # define HCRYPTO_DEF_PROVIDER pkcs11_hcrypto +# elif HAVE_HCRYPTO_W_OPENSSL +# define HCRYPTO_DEF_PROVIDER ossl # else # define HCRYPTO_DEF_PROVIDER hcrypto # endif diff --git a/lib/hcrypto/evp.h b/lib/hcrypto/evp.h index 8c5be7916..22e8f4d04 100644 --- a/lib/hcrypto/evp.h +++ b/lib/hcrypto/evp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 - 2008 Kungliga Tekniska Högskolan + * Copyright (c) 2005 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -154,7 +154,7 @@ struct hc_CIPHER { * cipher is used in (use EVP_CIPHER.._mode() to extract the * mode). The rest of the flag field is a bitfield. */ -#define hc_EVP_CIPH_STREAM_CIPHER 1 +#define hc_EVP_CIPH_STREAM_CIPHER 0 #define hc_EVP_CIPH_CBC_MODE 2 #define hc_EVP_CIPH_CFB8_MODE 4 #define hc_EVP_CIPH_MODE 0x7 @@ -171,8 +171,8 @@ struct hc_CIPHER { const unsigned char *, unsigned int); int (*cleanup)(EVP_CIPHER_CTX *); int ctx_size; - void *set_asn1_parameters; - void *get_asn1_parameters; + int (*set_asn1_parameters)(void); + int (*get_asn1_parameters)(void); int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); #define EVP_CTRL_RAND_KEY 0x6 @@ -197,6 +197,10 @@ struct hc_CIPHER_CTX { unsigned char final[EVP_MAX_BLOCK_LENGTH]; }; +/* + * LIES. It's not an EVP_MD_CTX that gets passed to these functions + * here in hcrypto, but an object of ctx_size. + */ typedef int (*hc_evp_md_init)(EVP_MD_CTX *); typedef int (*hc_evp_md_update)(EVP_MD_CTX *,const void *, size_t); typedef int (*hc_evp_md_final)(void *, EVP_MD_CTX *); diff --git a/lib/hcrypto/libhcrypto-exports.def b/lib/hcrypto/libhcrypto-exports.def index ef58e4638..366270f6c 100644 --- a/lib/hcrypto/libhcrypto-exports.def +++ b/lib/hcrypto/libhcrypto-exports.def @@ -177,6 +177,25 @@ EXPORTS ;! hc_EVP_cc_aes_192_cfb8 ;! hc_EVP_cc_aes_256_cfb8 + hc_EVP_ossl_md2 + hc_EVP_ossl_md4 + hc_EVP_ossl_md5 + hc_EVP_ossl_sha1 + hc_EVP_ossl_sha256 + hc_EVP_ossl_sha384 + hc_EVP_ossl_sha512 + hc_EVP_ossl_des_ede3_cbc + hc_EVP_ossl_aes_128_cbc + hc_EVP_ossl_aes_192_cbc + hc_EVP_ossl_aes_256_cbc + hc_EVP_ossl_aes_128_cfb8 + hc_EVP_ossl_aes_192_cfb8 + hc_EVP_ossl_aes_256_cfb8 + hc_EVP_ossl_rc2_cbc + hc_EVP_ossl_rc2_40_cbc + hc_EVP_ossl_rc4 + hc_EVP_ossl_rc4_40 + hc_EVP_pkcs11_md2 hc_EVP_pkcs11_md4 hc_EVP_pkcs11_md5 diff --git a/lib/hcrypto/mdtest.c b/lib/hcrypto/mdtest.c index afde93820..d301c5c4a 100644 --- a/lib/hcrypto/mdtest.c +++ b/lib/hcrypto/mdtest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995 - 2002 Kungliga Tekniska Högskolan + * Copyright (c) 1995 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -274,6 +274,10 @@ hash_test (struct hash_foo *hash, struct test *tests) char buf[1000]; ectx = EVP_MD_CTX_create(); + if (hash->evp() == NULL) { + printf("unavailable\n"); + continue; + } EVP_DigestInit_ex(ectx, hash->evp(), NULL); (*hash->init)(ctx); diff --git a/lib/hcrypto/rand.h b/lib/hcrypto/rand.h index 1c9df8a18..7b5553803 100644 --- a/lib/hcrypto/rand.h +++ b/lib/hcrypto/rand.h @@ -39,6 +39,8 @@ #ifndef _HEIM_RAND_H #define _HEIM_RAND_H 1 +#define RAND_METHOD hc_RAND_METHOD + typedef struct RAND_METHOD RAND_METHOD; #include diff --git a/lib/hcrypto/rsa.h b/lib/hcrypto/rsa.h index a5bf51395..d59213b39 100644 --- a/lib/hcrypto/rsa.h +++ b/lib/hcrypto/rsa.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * diff --git a/lib/hcrypto/test_cipher.c b/lib/hcrypto/test_cipher.c index 717e50b17..357e90e5b 100644 --- a/lib/hcrypto/test_cipher.c +++ b/lib/hcrypto/test_cipher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -410,5 +411,21 @@ main(int argc, char **argv) ret += test_cipher(i, EVP_pkcs11_rc4(), &rc4_tests[i]); #endif /* PKCS11_MODULE_PATH */ + /* OpenSSL */ +#ifdef HAVE_HCRYPTO_W_OPENSSL + for (i = 0; i < sizeof(aes_tests)/sizeof(aes_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_aes_256_cbc(), &aes_tests[i]); + for (i = 0; i < sizeof(aes_cfb_tests)/sizeof(aes_cfb_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_aes_128_cfb8(), &aes_cfb_tests[i]); + for (i = 0; i < sizeof(rc2_tests)/sizeof(rc2_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_rc2_cbc(), &rc2_tests[i]); + for (i = 0; i < sizeof(rc2_40_tests)/sizeof(rc2_40_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_rc2_40_cbc(), &rc2_40_tests[i]); + for (i = 0; i < sizeof(des_ede3_tests)/sizeof(des_ede3_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_des_ede3_cbc(), &des_ede3_tests[i]); + for (i = 0; i < sizeof(rc4_tests)/sizeof(rc4_tests[0]); i++) + ret += test_cipher(i, EVP_ossl_rc4(), &rc4_tests[i]); +#endif /* PKCS11_MODULE_PATH */ + return ret; } diff --git a/lib/hcrypto/version-script.map b/lib/hcrypto/version-script.map index 177e27981..e94048baf 100644 --- a/lib/hcrypto/version-script.map +++ b/lib/hcrypto/version-script.map @@ -201,6 +201,25 @@ HEIMDAL_CRYPTO_1.0 { hc_EVP_hcrypto_rc4; hc_EVP_hcrypto_rc4_40; + hc_EVP_ossl_md2; + hc_EVP_ossl_md4; + hc_EVP_ossl_md5; + hc_EVP_ossl_sha1; + hc_EVP_ossl_sha256; + hc_EVP_ossl_sha384; + hc_EVP_ossl_sha512; + hc_EVP_ossl_des_ede3_cbc; + hc_EVP_ossl_aes_128_cbc; + hc_EVP_ossl_aes_192_cbc; + hc_EVP_ossl_aes_256_cbc; + hc_EVP_ossl_aes_128_cfb8; + hc_EVP_ossl_aes_192_cfb8; + hc_EVP_ossl_aes_256_cfb8; + hc_EVP_ossl_rc2_cbc; + hc_EVP_ossl_rc2_40_cbc; + hc_EVP_ossl_rc4; + hc_EVP_ossl_rc4_40; + hc_EVP_pkcs11_md2; hc_EVP_pkcs11_md4; hc_EVP_pkcs11_md5; diff --git a/lib/hdb/Makefile.am b/lib/hdb/Makefile.am index b8c50cce4..140d5d7ca 100644 --- a/lib/hdb/Makefile.am +++ b/lib/hdb/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += -I../asn1 -I$(srcdir)/../asn1 $(INCLUDE_hcrypto) +AM_CPPFLAGS += -I../asn1 -I$(srcdir)/../asn1 AM_CPPFLAGS += $(INCLUDE_openldap) -DHDB_DB_DIR=\"$(DIR_hdbdir)\" AM_CPPFLAGS += -I$(srcdir)/../krb5 AM_CPPFLAGS += $(INCLUDE_sqlite3) diff --git a/lib/hx509/Makefile.am b/lib/hx509/Makefile.am index f093cbb10..cd8ccc553 100644 --- a/lib/hx509/Makefile.am +++ b/lib/hx509/Makefile.am @@ -58,6 +58,7 @@ dist_libhx509_la_SOURCES = \ cms.c \ collector.c \ crypto.c \ + crypto-ec.c \ doxygen.c \ error.c \ env.c \ @@ -92,6 +93,7 @@ libhx509_la_DEPENDENCIES = version-script.map libhx509_la_LIBADD = \ $(LIB_com_err) \ $(LIB_hcrypto) \ + $(LIB_openssl_crypto) \ $(top_builddir)/lib/asn1/libasn1.la \ $(top_builddir)/lib/wind/libwind.la \ $(top_builddir)/lib/base/libheimbase.la \ @@ -107,7 +109,6 @@ libhx509_la_LDFLAGS += $(LDFLAGS_VERSION_SCRIPT)$(srcdir)/version-script.map endif $(libhx509_la_OBJECTS): $(srcdir)/version-script.map $(nodist_include_HEADERS) $(priv_headers) -libhx509_la_CPPFLAGS = $(INCLUDE_hcrypto) nodist_libhx509_la_SOURCES = $(BUILT_SOURCES) $(gen_files_ocsp) ocsp_asn1.hx ocsp_asn1-priv.hx: ocsp_asn1_files @@ -163,7 +164,6 @@ nodist_hxtool_SOURCES = hxtool-commands.c hxtool-commands.h $(hxtool_OBJECTS): hxtool-commands.h hx509_err.h -hxtool_CPPFLAGS = $(INCLUDE_hcrypto) hxtool_LDADD = \ libhx509.la \ $(top_builddir)/lib/asn1/libasn1.la \ @@ -207,11 +207,8 @@ check_PROGRAMS = $(PROGRAM_TESTS) test_soft_pkcs11 LDADD = libhx509.la test_soft_pkcs11_LDADD = libhx509.la -test_soft_pkcs11_CPPFLAGS = $(INCLUDE_hcrypto) -test_name_CPPFLAGS = $(INCLUDE_hcrypto) test_name_LDADD = libhx509.la $(LIB_roken) -test_expr_CPPFLAGS = $(INCLUDE_hcrypto) test_expr_LDADD = libhx509.la $(LIB_roken) TESTS = $(SCRIPT_TESTS) $(PROGRAM_TESTS) diff --git a/lib/hx509/NTMakefile b/lib/hx509/NTMakefile index 91f5f4c73..871c4ee5a 100644 --- a/lib/hx509/NTMakefile +++ b/lib/hx509/NTMakefile @@ -1,6 +1,6 @@ ######################################################################## # -# Copyright (c) 2009, Secure Endpoints Inc. +# Copyright (c) 2009-2016, Secure Endpoints Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -47,6 +47,7 @@ libhx509_la_OBJS = \ $(OBJ)\cms.obj \ $(OBJ)\collector.obj \ $(OBJ)\crypto.obj \ + $(OBJ)\crypto-ec.obj \ $(OBJ)\error.obj \ $(OBJ)\env.obj \ $(OBJ)\file.obj \ @@ -81,6 +82,7 @@ dist_libhx509_la_SOURCES = \ $(SRCDIR)\cms.c \ $(SRCDIR)\collector.c \ $(SRCDIR)\crypto.c \ + $(SRCDIR)\crypto-ec.c \ $(SRCDIR)\doxygen.c \ $(SRCDIR)\error.c \ $(SRCDIR)\env.c \ @@ -162,7 +164,7 @@ $(OBJ)\hxtool-commands.c $(OBJ)\hxtool-commands.h: hxtool-commands.in $(SLC) cd $(SRCDIR) $(BINDIR)\hxtool.exe: $(OBJ)\tool\hxtool.obj $(OBJ)\tool\hxtool-commands.obj $(LIBHEIMDAL) $(OBJ)\hxtool-version.res - $(EXECONLINK) $(LIBHEIMDAL) $(LIBROKEN) $(LIBSL) $(LIBVERS) $(LIBCOMERR) + $(EXECONLINK) $(LIBHEIMDAL) $(LIBROKEN) $(LIBSL) $(LIBVERS) $(LIBCOMERR) $(LIB_openssl_crypto) $(EXEPREP) $(OBJ)\hx509-protos.h: diff --git a/lib/hx509/crypto-ec.c b/lib/hx509/crypto-ec.c new file mode 100644 index 000000000..698e52c4b --- /dev/null +++ b/lib/hx509/crypto-ec.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#ifdef HAVE_HCRYPTO_W_OPENSSL +#include +#include +#include +#include +#include +#define HEIM_NO_CRYPTO_HDRS +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +#include "hx_locl.h" + +extern const AlgorithmIdentifier _hx509_signature_sha256_data; +extern const AlgorithmIdentifier _hx509_signature_sha1_data; + +void +_hx509_private_eckey_free(void *eckey) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + EC_KEY_free(eckey); +#endif +} + +#ifdef HAVE_HCRYPTO_W_OPENSSL +static int +heim_oid2ecnid(heim_oid *oid) +{ + /* + * Now map to openssl OID fun + */ + + if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP256R1) == 0) + return NID_X9_62_prime256v1; + else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP160R1) == 0) + return NID_secp160r1; + else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP160R2) == 0) + return NID_secp160r2; + + return NID_undef; +} + +static int +parse_ECParameters(hx509_context context, + heim_octet_string *parameters, int *nid) +{ + ECParameters ecparam; + size_t size; + int ret; + + if (parameters == NULL) { + ret = HX509_PARSING_KEY_FAILED; + hx509_set_error_string(context, 0, ret, + "EC parameters missing"); + return ret; + } + + ret = decode_ECParameters(parameters->data, parameters->length, + &ecparam, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to decode EC parameters"); + return ret; + } + + if (ecparam.element != choice_ECParameters_namedCurve) { + free_ECParameters(&ecparam); + hx509_set_error_string(context, 0, ret, + "EC parameters is not a named curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + *nid = heim_oid2ecnid(&ecparam.u.namedCurve); + free_ECParameters(&ecparam); + if (*nid == NID_undef) { + hx509_set_error_string(context, 0, ret, + "Failed to find matcing NID for EC curve"); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + return 0; +} + + +/* + * + */ + +static int +ecdsa_verify_signature(hx509_context context, + const struct signature_alg *sig_alg, + const Certificate *signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + const heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + const SubjectPublicKeyInfo *spi; + heim_octet_string digest; + int ret; + EC_KEY *key = NULL; + int groupnid; + EC_GROUP *group; + const unsigned char *p; + long len; + + digest_alg = sig_alg->digest_alg; + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &digest); + if (ret) + return ret; + + /* set up EC KEY */ + spi = &signer->tbsCertificate.subjectPublicKeyInfo; + + if (der_heim_oid_cmp(&spi->algorithm.algorithm, ASN1_OID_ID_ECPUBLICKEY) != 0) + return HX509_CRYPTO_SIG_INVALID_FORMAT; + + /* + * Find the group id + */ + + ret = parse_ECParameters(context, spi->algorithm.parameters, &groupnid); + if (ret) { + der_free_octet_string(&digest); + return ret; + } + + /* + * Create group, key, parse key + */ + + key = EC_KEY_new(); + group = EC_GROUP_new_by_curve_name(groupnid); + EC_KEY_set_group(key, group); + EC_GROUP_free(group); + + p = spi->subjectPublicKey.data; + len = spi->subjectPublicKey.length / 8; + + if (o2i_ECPublicKey(&key, &p, len) == NULL) { + EC_KEY_free(key); + return HX509_CRYPTO_SIG_INVALID_FORMAT; + } + + ret = ECDSA_verify(-1, digest.data, digest.length, + sig->data, sig->length, key); + der_free_octet_string(&digest); + EC_KEY_free(key); + if (ret != 1) { + ret = HX509_CRYPTO_SIG_INVALID_FORMAT; + return ret; + } + + return 0; +} + +static int +ecdsa_create_signature(hx509_context context, + const struct signature_alg *sig_alg, + const hx509_private_key signer, + const AlgorithmIdentifier *alg, + const heim_octet_string *data, + AlgorithmIdentifier *signatureAlgorithm, + heim_octet_string *sig) +{ + const AlgorithmIdentifier *digest_alg; + heim_octet_string indata; + const heim_oid *sig_oid; + unsigned int siglen; + int ret; + + if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig_oid = sig_alg->sig_oid; + digest_alg = sig_alg->digest_alg; + + if (signatureAlgorithm) { + ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid, + "\x05\x00", 2); + if (ret) { + hx509_clear_error_string(context); + return ret; + } + } + + ret = _hx509_create_signature(context, + NULL, + digest_alg, + data, + NULL, + &indata); + if (ret) + goto error; + + sig->length = ECDSA_size(signer->private_key.ecdsa); + sig->data = malloc(sig->length); + if (sig->data == NULL) { + der_free_octet_string(&indata); + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "out of memory"); + goto error; + } + + siglen = sig->length; + + ret = ECDSA_sign(-1, indata.data, indata.length, + sig->data, &siglen, signer->private_key.ecdsa); + der_free_octet_string(&indata); + if (ret != 1) { + ret = HX509_CMS_FAILED_CREATE_SIGATURE; + hx509_set_error_string(context, 0, ret, + "ECDSA sign failed: %d", ret); + goto error; + } + if (siglen > sig->length) + _hx509_abort("ECDSA signature prelen longer the output len"); + + sig->length = siglen; + + return 0; + error: + if (signatureAlgorithm) + free_AlgorithmIdentifier(signatureAlgorithm); + return ret; +} + +static int +ecdsa_available(const hx509_private_key signer, + const AlgorithmIdentifier *sig_alg) +{ + const struct signature_alg *sig; + const EC_GROUP *group; + BN_CTX *bnctx = NULL; + BIGNUM *order = NULL; + int ret = 0; + + if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) + _hx509_abort("internal error passing private key to wrong ops"); + + sig = _hx509_find_sig_alg(&sig_alg->algorithm); + + if (sig == NULL || sig->digest_size == 0) + return 0; + + group = EC_KEY_get0_group(signer->private_key.ecdsa); + if (group == NULL) + return 0; + + bnctx = BN_CTX_new(); + order = BN_new(); + if (order == NULL) + goto err; + + if (EC_GROUP_get_order(group, order, bnctx) != 1) + goto err; + + if (BN_num_bytes(order) > sig->digest_size) + ret = 1; + err: + if (bnctx) + BN_CTX_free(bnctx); + if (order) + BN_clear_free(order); + + return ret; +} + +static int +ecdsa_private_key2SPKI(hx509_context context, + hx509_private_key private_key, + SubjectPublicKeyInfo *spki) +{ + memset(spki, 0, sizeof(*spki)); + return ENOMEM; +} + +static int +ecdsa_private_key_export(hx509_context context, + const hx509_private_key key, + hx509_key_format_t format, + heim_octet_string *data) +{ + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; +} + +static int +ecdsa_private_key_import(hx509_context context, + const AlgorithmIdentifier *keyai, + const void *data, + size_t len, + hx509_key_format_t format, + hx509_private_key private_key) +{ + const unsigned char *p = data; + EC_KEY **pkey = NULL; + EC_KEY *key; + + if (keyai->parameters) { + EC_GROUP *group; + int groupnid; + int ret; + + ret = parse_ECParameters(context, keyai->parameters, &groupnid); + if (ret) + return ret; + + key = EC_KEY_new(); + if (key == NULL) + return ENOMEM; + + group = EC_GROUP_new_by_curve_name(groupnid); + if (group == NULL) { + EC_KEY_free(key); + return ENOMEM; + } + EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); + if (EC_KEY_set_group(key, group) == 0) { + EC_KEY_free(key); + EC_GROUP_free(group); + return ENOMEM; + } + EC_GROUP_free(group); + pkey = &key; + } + + switch (format) { + case HX509_KEY_FORMAT_DER: + + private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); + if (private_key->private_key.ecdsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse EC private key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; + break; + + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; + } + + return 0; +} + +static int +ecdsa_generate_private_key(hx509_context context, + struct hx509_generate_private_context *ctx, + hx509_private_key private_key) +{ + return ENOMEM; +} + +static BIGNUM * +ecdsa_get_internal(hx509_context context, + hx509_private_key key, + const char *type) +{ + return NULL; +} + +static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 }; +const AlgorithmIdentifier _hx509_signature_ecPublicKey = { + { 6, rk_UNCONST(ecPublicKey) }, NULL +}; + +static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = { + { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL +}; + +static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 }; +const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = { + { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL +}; + + +const AlgorithmIdentifier * +hx509_signature_ecdsa_with_sha1(void) +{ return &_hx509_signature_ecdsa_with_sha1_data; } + + +hx509_private_key_ops ecdsa_private_key_ops = { + "EC PRIVATE KEY", + ASN1_OID_ID_ECPUBLICKEY, + ecdsa_available, + ecdsa_private_key2SPKI, + ecdsa_private_key_export, + ecdsa_private_key_import, + ecdsa_generate_private_key, + ecdsa_get_internal +}; + +const struct signature_alg ecdsa_with_sha256_alg = { + "ecdsa-with-sha256", + ASN1_OID_ID_ECDSA_WITH_SHA256, + &_hx509_signature_ecdsa_with_sha256_data, + ASN1_OID_ID_ECPUBLICKEY, + &_hx509_signature_sha256_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| + SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + ecdsa_verify_signature, + ecdsa_create_signature, + 32 +}; + +const struct signature_alg ecdsa_with_sha1_alg = { + "ecdsa-with-sha1", + ASN1_OID_ID_ECDSA_WITH_SHA1, + &_hx509_signature_ecdsa_with_sha1_data, + ASN1_OID_ID_ECPUBLICKEY, + &_hx509_signature_sha1_data, + PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO| + SIG_PUBLIC_SIG|SELF_SIGNED_OK, + 0, + NULL, + ecdsa_verify_signature, + ecdsa_create_signature, + 20 +}; + +#endif /* HAVE_HCRYPTO_W_OPENSSL */ + +const AlgorithmIdentifier * +hx509_signature_ecPublicKey(void) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + return &_hx509_signature_ecPublicKey; +#else + return NULL; +#endif /* HAVE_HCRYPTO_W_OPENSSL */ +} + +const AlgorithmIdentifier * +hx509_signature_ecdsa_with_sha256(void) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + return &_hx509_signature_ecdsa_with_sha256_data; +#else + return NULL; +#endif /* HAVE_HCRYPTO_W_OPENSSL */ +} diff --git a/lib/hx509/crypto.c b/lib/hx509/crypto.c index 1949588a3..5296686ac 100644 --- a/lib/hx509/crypto.c +++ b/lib/hx509/crypto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,94 +33,6 @@ #include "hx_locl.h" -struct hx509_crypto; - -struct signature_alg; - -struct hx509_generate_private_context { - const heim_oid *key_oid; - int isCA; - unsigned long num_bits; -}; - -struct hx509_private_key_ops { - const char *pemtype; - const heim_oid *key_oid; - int (*available)(const hx509_private_key, - const AlgorithmIdentifier *); - int (*get_spki)(hx509_context, - const hx509_private_key, - SubjectPublicKeyInfo *); - int (*export)(hx509_context context, - const hx509_private_key, - hx509_key_format_t, - heim_octet_string *); - int (*import)(hx509_context, const AlgorithmIdentifier *, - const void *, size_t, hx509_key_format_t, - hx509_private_key); - int (*generate_private_key)(hx509_context, - struct hx509_generate_private_context *, - hx509_private_key); - BIGNUM *(*get_internal)(hx509_context, hx509_private_key, const char *); -}; - -struct hx509_private_key { - unsigned int ref; - const struct signature_alg *md; - const heim_oid *signature_alg; - union { - RSA *rsa; - void *keydata; -#ifdef HAVE_OPENSSL - EC_KEY *ecdsa; -#endif - } private_key; - hx509_private_key_ops *ops; -}; - -/* - * - */ - -struct signature_alg { - const char *name; - const heim_oid *sig_oid; - const AlgorithmIdentifier *sig_alg; - const heim_oid *key_oid; - const AlgorithmIdentifier *digest_alg; - int flags; -#define PROVIDE_CONF 0x1 -#define REQUIRE_SIGNER 0x2 -#define SELF_SIGNED_OK 0x4 -#define WEAK_SIG_ALG 0x8 - -#define SIG_DIGEST 0x100 -#define SIG_PUBLIC_SIG 0x200 -#define SIG_SECRET 0x400 - -#define RA_RSA_USES_DIGEST_INFO 0x1000000 - - time_t best_before; /* refuse signature made after best before date */ - const EVP_MD *(*evp_md)(void); - int (*verify_signature)(hx509_context context, - const struct signature_alg *, - const Certificate *, - const AlgorithmIdentifier *, - const heim_octet_string *, - const heim_octet_string *); - int (*create_signature)(hx509_context, - const struct signature_alg *, - const hx509_private_key, - const AlgorithmIdentifier *, - const heim_octet_string *, - AlgorithmIdentifier *, - heim_octet_string *); - int digest_size; -}; - -static const struct signature_alg * -find_sig_alg(const heim_oid *oid); - /*- * RFC5758 specifies no parameters for ecdsa-with-SHA signatures * RFC5754 specifies NULL parameters for shaWithRSAEncryption signatures @@ -156,21 +68,6 @@ const AlgorithmIdentifier _hx509_signature_md5_data = { { 6, rk_UNCONST(md5_oid_tree) }, rk_UNCONST(&null_entry_oid) }; -static const unsigned ecPublicKey[] ={ 1, 2, 840, 10045, 2, 1 }; -const AlgorithmIdentifier _hx509_signature_ecPublicKey = { - { 6, rk_UNCONST(ecPublicKey) }, NULL -}; - -static const unsigned ecdsa_with_sha256_oid[] ={ 1, 2, 840, 10045, 4, 3, 2 }; -const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha256_data = { - { 7, rk_UNCONST(ecdsa_with_sha256_oid) }, NULL -}; - -static const unsigned ecdsa_with_sha1_oid[] ={ 1, 2, 840, 10045, 4, 1 }; -const AlgorithmIdentifier _hx509_signature_ecdsa_with_sha1_data = { - { 6, rk_UNCONST(ecdsa_with_sha1_oid) }, NULL -}; - static const unsigned rsa_with_sha512_oid[] ={ 1, 2, 840, 113549, 1, 1, 13 }; const AlgorithmIdentifier _hx509_signature_rsa_with_sha512_data = { { 7, rk_UNCONST(rsa_with_sha512_oid) }, rk_UNCONST(&null_entry_oid) @@ -239,10 +136,10 @@ heim_int2BN(const heim_integer *i) * */ -static int -set_digest_alg(DigestAlgorithmIdentifier *id, - const heim_oid *oid, - const void *param, size_t length) +int +_hx509_set_digest_alg(DigestAlgorithmIdentifier *id, + const heim_oid *oid, + const void *param, size_t length) { int ret; if (param) { @@ -271,262 +168,6 @@ set_digest_alg(DigestAlgorithmIdentifier *id, return 0; } -#ifdef HAVE_OPENSSL - -static int -heim_oid2ecnid(heim_oid *oid) -{ - /* - * Now map to openssl OID fun - */ - - if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP256R1) == 0) - return NID_X9_62_prime256v1; - else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP160R1) == 0) - return NID_secp160r1; - else if (der_heim_oid_cmp(oid, ASN1_OID_ID_EC_GROUP_SECP160R2) == 0) - return NID_secp160r2; - - return -1; -} - -static int -parse_ECParameters(hx509_context context, - heim_octet_string *parameters, int *nid) -{ - ECParameters ecparam; - size_t size; - int ret; - - if (parameters == NULL) { - ret = HX509_PARSING_KEY_FAILED; - hx509_set_error_string(context, 0, ret, - "EC parameters missing"); - return ret; - } - - ret = decode_ECParameters(parameters->data, parameters->length, - &ecparam, &size); - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to decode EC parameters"); - return ret; - } - - if (ecparam.element != choice_ECParameters_namedCurve) { - free_ECParameters(&ecparam); - hx509_set_error_string(context, 0, ret, - "EC parameters is not a named curve"); - return HX509_CRYPTO_SIG_INVALID_FORMAT; - } - - *nid = heim_oid2ecnid(&ecparam.u.namedCurve); - free_ECParameters(&ecparam); - if (*nid == -1) { - hx509_set_error_string(context, 0, ret, - "Failed to find matcing NID for EC curve"); - return HX509_CRYPTO_SIG_INVALID_FORMAT; - } - return 0; -} - - -/* - * - */ - -static int -ecdsa_verify_signature(hx509_context context, - const struct signature_alg *sig_alg, - const Certificate *signer, - const AlgorithmIdentifier *alg, - const heim_octet_string *data, - const heim_octet_string *sig) -{ - const AlgorithmIdentifier *digest_alg; - const SubjectPublicKeyInfo *spi; - heim_octet_string digest; - int ret; - EC_KEY *key = NULL; - int groupnid; - EC_GROUP *group; - const unsigned char *p; - long len; - - digest_alg = sig_alg->digest_alg; - - ret = _hx509_create_signature(context, - NULL, - digest_alg, - data, - NULL, - &digest); - if (ret) - return ret; - - /* set up EC KEY */ - spi = &signer->tbsCertificate.subjectPublicKeyInfo; - - if (der_heim_oid_cmp(&spi->algorithm.algorithm, ASN1_OID_ID_ECPUBLICKEY) != 0) - return HX509_CRYPTO_SIG_INVALID_FORMAT; - -#ifdef HAVE_OPENSSL - /* - * Find the group id - */ - - ret = parse_ECParameters(context, spi->algorithm.parameters, &groupnid); - if (ret) { - der_free_octet_string(&digest); - return ret; - } - - /* - * Create group, key, parse key - */ - - key = EC_KEY_new(); - group = EC_GROUP_new_by_curve_name(groupnid); - EC_KEY_set_group(key, group); - EC_GROUP_free(group); - - p = spi->subjectPublicKey.data; - len = spi->subjectPublicKey.length / 8; - - if (o2i_ECPublicKey(&key, &p, len) == NULL) { - EC_KEY_free(key); - return HX509_CRYPTO_SIG_INVALID_FORMAT; - } -#else - key = SubjectPublicKeyInfo2EC_KEY(spi); -#endif - - ret = ECDSA_verify(-1, digest.data, digest.length, - sig->data, sig->length, key); - der_free_octet_string(&digest); - EC_KEY_free(key); - if (ret != 1) { - ret = HX509_CRYPTO_SIG_INVALID_FORMAT; - return ret; - } - - return 0; -} - -static int -ecdsa_create_signature(hx509_context context, - const struct signature_alg *sig_alg, - const hx509_private_key signer, - const AlgorithmIdentifier *alg, - const heim_octet_string *data, - AlgorithmIdentifier *signatureAlgorithm, - heim_octet_string *sig) -{ - const AlgorithmIdentifier *digest_alg; - heim_octet_string indata; - const heim_oid *sig_oid; - unsigned int siglen; - int ret; - - if (signer->ops && der_heim_oid_cmp(signer->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) != 0) - _hx509_abort("internal error passing private key to wrong ops"); - - sig_oid = sig_alg->sig_oid; - digest_alg = sig_alg->digest_alg; - - if (signatureAlgorithm) { - ret = set_digest_alg(signatureAlgorithm, sig_oid, "\x05\x00", 2); - if (ret) { - hx509_clear_error_string(context); - return ret; - } - } - - ret = _hx509_create_signature(context, - NULL, - digest_alg, - data, - NULL, - &indata); - if (ret) - goto error; - - sig->length = ECDSA_size(signer->private_key.ecdsa); - sig->data = malloc(sig->length); - if (sig->data == NULL) { - der_free_octet_string(&indata); - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "out of memory"); - goto error; - } - - siglen = sig->length; - - ret = ECDSA_sign(-1, indata.data, indata.length, - sig->data, &siglen, signer->private_key.ecdsa); - der_free_octet_string(&indata); - if (ret != 1) { - ret = HX509_CMS_FAILED_CREATE_SIGATURE; - hx509_set_error_string(context, 0, ret, - "ECDSA sign failed: %d", ret); - goto error; - } - if (siglen > sig->length) - _hx509_abort("ECDSA signature prelen longer the output len"); - - sig->length = siglen; - - return 0; - error: - if (signatureAlgorithm) - free_AlgorithmIdentifier(signatureAlgorithm); - return ret; -} - -static int -ecdsa_available(const hx509_private_key signer, - const AlgorithmIdentifier *sig_alg) -{ - const struct signature_alg *sig; - const EC_GROUP *group; - BN_CTX *bnctx = NULL; - BIGNUM *order = NULL; - int ret = 0; - - if (der_heim_oid_cmp(signer->ops->key_oid, &asn1_oid_id_ecPublicKey) != 0) - _hx509_abort("internal error passing private key to wrong ops"); - - sig = find_sig_alg(&sig_alg->algorithm); - - if (sig == NULL || sig->digest_size == 0) - return 0; - - group = EC_KEY_get0_group(signer->private_key.ecdsa); - if (group == NULL) - return 0; - - bnctx = BN_CTX_new(); - order = BN_new(); - if (order == NULL) - goto err; - - if (EC_GROUP_get_order(group, order, bnctx) != 1) - goto err; - - if (BN_num_bytes(order) > sig->digest_size) - ret = 1; - err: - if (bnctx) - BN_CTX_free(bnctx); - if (order) - BN_clear_free(order); - - return ret; -} - - -#endif /* HAVE_OPENSSL */ - /* * */ @@ -688,7 +329,8 @@ rsa_create_signature(hx509_context context, return HX509_ALG_NOT_SUPP; if (signatureAlgorithm) { - ret = set_digest_alg(signatureAlgorithm, sig_oid, "\x05\x00", 2); + ret = _hx509_set_digest_alg(signatureAlgorithm, sig_oid, + "\x05\x00", 2); if (ret) { hx509_clear_error_string(context); return ret; @@ -802,8 +444,9 @@ rsa_private_key2SPKI(hx509_context context, } spki->subjectPublicKey.length = len * 8; - ret = set_digest_alg(&spki->algorithm, ASN1_OID_ID_PKCS1_RSAENCRYPTION, - "\x05\x00", 2); + ret = _hx509_set_digest_alg(&spki->algorithm, + ASN1_OID_ID_PKCS1_RSAENCRYPTION, + "\x05\x00", 2); if (ret) { hx509_set_error_string(context, 0, ret, "malloc - out of memory"); free(spki->subjectPublicKey.data); @@ -927,115 +570,6 @@ static hx509_private_key_ops rsa_private_key_ops = { rsa_get_internal }; -#ifdef HAVE_OPENSSL - -static int -ecdsa_private_key2SPKI(hx509_context context, - hx509_private_key private_key, - SubjectPublicKeyInfo *spki) -{ - memset(spki, 0, sizeof(*spki)); - return ENOMEM; -} - -static int -ecdsa_private_key_export(hx509_context context, - const hx509_private_key key, - hx509_key_format_t format, - heim_octet_string *data) -{ - return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; -} - -static int -ecdsa_private_key_import(hx509_context context, - const AlgorithmIdentifier *keyai, - const void *data, - size_t len, - hx509_key_format_t format, - hx509_private_key private_key) -{ - const unsigned char *p = data; - EC_KEY **pkey = NULL; - EC_KEY *key; - - if (keyai->parameters) { - EC_GROUP *group; - int groupnid; - int ret; - - ret = parse_ECParameters(context, keyai->parameters, &groupnid); - if (ret) - return ret; - - key = EC_KEY_new(); - if (key == NULL) - return ENOMEM; - - group = EC_GROUP_new_by_curve_name(groupnid); - if (group == NULL) { - EC_KEY_free(key); - return ENOMEM; - } - EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); - if (EC_KEY_set_group(key, group) == 0) { - EC_KEY_free(key); - EC_GROUP_free(group); - return ENOMEM; - } - EC_GROUP_free(group); - pkey = &key; - } - - switch (format) { - case HX509_KEY_FORMAT_DER: - - private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); - if (private_key->private_key.ecdsa == NULL) { - hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "Failed to parse EC private key"); - return HX509_PARSING_KEY_FAILED; - } - private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; - break; - - default: - return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; - } - - return 0; -} - -static int -ecdsa_generate_private_key(hx509_context context, - struct hx509_generate_private_context *ctx, - hx509_private_key private_key) -{ - return ENOMEM; -} - -static BIGNUM * -ecdsa_get_internal(hx509_context context, - hx509_private_key key, - const char *type) -{ - return NULL; -} - - -static hx509_private_key_ops ecdsa_private_key_ops = { - "EC PRIVATE KEY", - ASN1_OID_ID_ECPUBLICKEY, - ecdsa_available, - ecdsa_private_key2SPKI, - ecdsa_private_key_export, - ecdsa_private_key_import, - ecdsa_generate_private_key, - ecdsa_get_internal -}; - -#endif /* HAVE_OPENSSL */ - /* * */ @@ -1164,8 +698,8 @@ evp_md_create_signature(hx509_context context, if (signatureAlgorithm) { int ret; - ret = set_digest_alg(signatureAlgorithm, sig_alg->sig_oid, - "\x05\x00", 2); + ret = _hx509_set_digest_alg(signatureAlgorithm, + sig_alg->sig_oid, "\x05\x00", 2); if (ret) return ret; } @@ -1221,36 +755,9 @@ evp_md_verify_signature(hx509_context context, return 0; } -#ifdef HAVE_OPENSSL - -static const struct signature_alg ecdsa_with_sha256_alg = { - "ecdsa-with-sha256", - ASN1_OID_ID_ECDSA_WITH_SHA256, - &_hx509_signature_ecdsa_with_sha256_data, - ASN1_OID_ID_ECPUBLICKEY, - &_hx509_signature_sha256_data, - PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, - 0, - NULL, - ecdsa_verify_signature, - ecdsa_create_signature, - 32 -}; - -static const struct signature_alg ecdsa_with_sha1_alg = { - "ecdsa-with-sha1", - ASN1_OID_ID_ECDSA_WITH_SHA1, - &_hx509_signature_ecdsa_with_sha1_data, - ASN1_OID_ID_ECPUBLICKEY, - &_hx509_signature_sha1_data, - PROVIDE_CONF|REQUIRE_SIGNER|RA_RSA_USES_DIGEST_INFO|SIG_PUBLIC_SIG|SELF_SIGNED_OK, - 0, - NULL, - ecdsa_verify_signature, - ecdsa_create_signature, - 20 -}; - +#ifdef HAVE_HCRYPTO_W_OPENSSL +extern const struct signature_alg ecdsa_with_sha256_alg; +extern const struct signature_alg ecdsa_with_sha1_alg; #endif static const struct signature_alg heim_rsa_pkcs1_x509 = { @@ -1455,7 +962,7 @@ static const struct signature_alg md5_alg = { */ static const struct signature_alg *sig_algs[] = { -#ifdef HAVE_OPENSSL +#ifdef HAVE_HCRYPTO_W_OPENSSL &ecdsa_with_sha256_alg, &ecdsa_with_sha1_alg, #endif @@ -1476,8 +983,8 @@ static const struct signature_alg *sig_algs[] = { NULL }; -static const struct signature_alg * -find_sig_alg(const heim_oid *oid) +const struct signature_alg * +_hx509_find_sig_alg(const heim_oid *oid) { unsigned int i; for (i = 0; sig_algs[i]; i++) @@ -1518,10 +1025,13 @@ alg_for_privatekey(const hx509_private_key pk, int type) /* * */ +#ifdef HAVE_HCRYPTO_W_OPENSSL +extern hx509_private_key_ops ecdsa_private_key_ops; +#endif static struct hx509_private_key_ops *private_algs[] = { &rsa_private_key_ops, -#ifdef HAVE_OPENSSL +#ifdef HAVE_HCRYPTO_W_OPENSSL &ecdsa_private_key_ops, #endif NULL @@ -1550,7 +1060,7 @@ _hx509_signature_is_weak(hx509_context context, const AlgorithmIdentifier *alg) { const struct signature_alg *md; - md = find_sig_alg(&alg->algorithm); + md = _hx509_find_sig_alg(&alg->algorithm); if (md == NULL) { hx509_clear_error_string(context); return HX509_SIG_ALG_NO_SUPPORTED; @@ -1569,7 +1079,7 @@ _hx509_self_signed_valid(hx509_context context, { const struct signature_alg *md; - md = find_sig_alg(&alg->algorithm); + md = _hx509_find_sig_alg(&alg->algorithm); if (md == NULL) { hx509_clear_error_string(context); return HX509_SIG_ALG_NO_SUPPORTED; @@ -1597,7 +1107,7 @@ _hx509_verify_signature(hx509_context context, if (cert) signer = _hx509_get_cert(cert); - md = find_sig_alg(&alg->algorithm); + md = _hx509_find_sig_alg(&alg->algorithm); if (md == NULL) { hx509_clear_error_string(context); return HX509_SIG_ALG_NO_SUPPORTED; @@ -1632,7 +1142,7 @@ _hx509_create_signature(hx509_context context, { const struct signature_alg *md; - md = find_sig_alg(&alg->algorithm); + md = _hx509_find_sig_alg(&alg->algorithm); if (md == NULL) { hx509_set_error_string(context, 0, HX509_SIG_ALG_NO_SUPPORTED, "algorithm no supported"); @@ -1926,18 +1436,6 @@ const AlgorithmIdentifier * hx509_signature_md5(void) { return &_hx509_signature_md5_data; } -const AlgorithmIdentifier * -hx509_signature_ecPublicKey(void) -{ return &_hx509_signature_ecPublicKey; } - -const AlgorithmIdentifier * -hx509_signature_ecdsa_with_sha256(void) -{ return &_hx509_signature_ecdsa_with_sha256_data; } - -const AlgorithmIdentifier * -hx509_signature_ecdsa_with_sha1(void) -{ return &_hx509_signature_ecdsa_with_sha1_data; } - const AlgorithmIdentifier * hx509_signature_rsa_with_sha512(void) { return &_hx509_signature_rsa_with_sha512_data; } @@ -2038,11 +1536,10 @@ hx509_private_key_free(hx509_private_key *key) if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, ASN1_OID_ID_PKCS1_RSAENCRYPTION) == 0) { if ((*key)->private_key.rsa) RSA_free((*key)->private_key.rsa); -#ifdef HAVE_OPENSSL - } else if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, ASN1_OID_ID_ECPUBLICKEY) == 0) { - if ((*key)->private_key.ecdsa) - EC_KEY_free((*key)->private_key.ecdsa); -#endif + } else if ((*key)->ops && der_heim_oid_cmp((*key)->ops->key_oid, + ASN1_OID_ID_ECPUBLICKEY) == 0 && + (*key)->private_key.ecdsa != NULL) { + _hx509_private_eckey_free((*key)->private_key.ecdsa); } (*key)->private_key.rsa = NULL; free(*key); @@ -2810,29 +2307,49 @@ find_string2key(const heim_oid *oid, { if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND40BITRC2_CBC) == 0) { *c = EVP_rc2_40_cbc(); + if (*c == NULL) + return NULL; *md = EVP_sha1(); + if (*md == NULL) + return NULL; *s2k = PBE_string2key; return &asn1_oid_private_rc2_40; } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND128BITRC2_CBC) == 0) { *c = EVP_rc2_cbc(); + if (*c == NULL) + return NULL; *md = EVP_sha1(); + if (*md == NULL) + return NULL; *s2k = PBE_string2key; return ASN1_OID_ID_PKCS3_RC2_CBC; #if 0 } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND40BITRC4) == 0) { *c = EVP_rc4_40(); + if (*c == NULL) + return NULL; *md = EVP_sha1(); + if (*md == NULL) + return NULL; *s2k = PBE_string2key; return NULL; } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND128BITRC4) == 0) { *c = EVP_rc4(); + if (*c == NULL) + return NULL; *md = EVP_sha1(); + if (*md == NULL) + return NULL; *s2k = PBE_string2key; return ASN1_OID_ID_PKCS3_RC4; #endif } else if (der_heim_oid_cmp(oid, ASN1_OID_ID_PBEWITHSHAAND3_KEYTRIPLEDES_CBC) == 0) { *c = EVP_des_ede3_cbc(); + if (*c == NULL) + return NULL; *md = EVP_sha1(); + if (*md == NULL) + return NULL; *s2k = PBE_string2key; return ASN1_OID_ID_PKCS3_DES_EDE3_CBC; } @@ -3031,7 +2548,7 @@ find_keytype(const hx509_private_key key) if (key == NULL) return NULL; - md = find_sig_alg(key->signature_alg); + md = _hx509_find_sig_alg(key->signature_alg); if (md == NULL) return NULL; return md->key_oid; diff --git a/lib/hx509/hx_locl.h b/lib/hx509/hx_locl.h index 101e968aa..44d241f35 100644 --- a/lib/hx509/hx_locl.h +++ b/lib/hx509/hx_locl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -70,8 +70,16 @@ #include +/* + * We use OpenSSL for EC, but to do this we need to disable cross-references + * between OpenSSL and hcrypto bn.h and such. Source files that use OpenSSL EC + * must define HEIM_NO_CRYPTO_HDRS before including this file. + */ + #define HC_DEPRECATED_CRYPTO +#ifndef HEIM_NO_CRYPTO_HDRS #include "crypto-headers.h" +#endif struct hx509_keyset_ops; struct hx509_collector; @@ -213,6 +221,95 @@ extern const AlgorithmIdentifier * _hx509_crypto_default_sig_alg; extern const AlgorithmIdentifier * _hx509_crypto_default_digest_alg; extern const AlgorithmIdentifier * _hx509_crypto_default_secret_alg; +/* + * Private bits from crypto.c, so crypto-ec.c can also see them. + * + * This is part of the use-OpenSSL-for-EC hack. + */ + +struct hx509_crypto; + +struct signature_alg; + +struct hx509_generate_private_context { + const heim_oid *key_oid; + int isCA; + unsigned long num_bits; +}; + +struct hx509_private_key_ops { + const char *pemtype; + const heim_oid *key_oid; + int (*available)(const hx509_private_key, + const AlgorithmIdentifier *); + int (*get_spki)(hx509_context, + const hx509_private_key, + SubjectPublicKeyInfo *); + int (*export)(hx509_context context, + const hx509_private_key, + hx509_key_format_t, + heim_octet_string *); + int (*import)(hx509_context, const AlgorithmIdentifier *, + const void *, size_t, hx509_key_format_t, + hx509_private_key); + int (*generate_private_key)(hx509_context, + struct hx509_generate_private_context *, + hx509_private_key); + BIGNUM *(*get_internal)(hx509_context, hx509_private_key, const char *); +}; + +struct hx509_private_key { + unsigned int ref; + const struct signature_alg *md; + const heim_oid *signature_alg; + union { + RSA *rsa; + void *keydata; + void *ecdsa; /* EC_KEY */ + } private_key; + hx509_private_key_ops *ops; +}; + +/* + * + */ + +struct signature_alg { + const char *name; + const heim_oid *sig_oid; + const AlgorithmIdentifier *sig_alg; + const heim_oid *key_oid; + const AlgorithmIdentifier *digest_alg; + int flags; +#define PROVIDE_CONF 0x1 +#define REQUIRE_SIGNER 0x2 +#define SELF_SIGNED_OK 0x4 +#define WEAK_SIG_ALG 0x8 + +#define SIG_DIGEST 0x100 +#define SIG_PUBLIC_SIG 0x200 +#define SIG_SECRET 0x400 + +#define RA_RSA_USES_DIGEST_INFO 0x1000000 + + time_t best_before; /* refuse signature made after best before date */ + const EVP_MD *(*evp_md)(void); + int (*verify_signature)(hx509_context context, + const struct signature_alg *, + const Certificate *, + const AlgorithmIdentifier *, + const heim_octet_string *, + const heim_octet_string *); + int (*create_signature)(hx509_context, + const struct signature_alg *, + const hx509_private_key, + const AlgorithmIdentifier *, + const heim_octet_string *, + AlgorithmIdentifier *, + heim_octet_string *); + int digest_size; +}; + /* * Configurable options */ diff --git a/lib/hx509/hxtool.c b/lib/hx509/hxtool.c index 54cc06300..0a7048bdf 100644 --- a/lib/hx509/hxtool.c +++ b/lib/hx509/hxtool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 2004 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -1433,7 +1433,7 @@ info(void *opt, int argc, char **argv) if (m != NULL) printf("dh: %s\n", m->name); } -#ifdef HAVE_OPENSSL +#ifdef HAVE_HCRYPTO_W_OPENSSL { printf("ecdsa: ECDSA_METHOD-not-export\n"); } diff --git a/lib/hx509/ks_file.c b/lib/hx509/ks_file.c index 3eaf69515..a487da393 100644 --- a/lib/hx509/ks_file.c +++ b/lib/hx509/ks_file.c @@ -319,7 +319,9 @@ struct pem_formats { { "CERTIFICATE", parse_certificate, NULL }, { "PRIVATE KEY", parse_pkcs8_private_key, NULL }, { "RSA PRIVATE KEY", parse_pem_private_key, hx509_signature_rsa }, +#ifdef HAVE_HCRYPTO_W_OPENSSL { "EC PRIVATE KEY", parse_pem_private_key, hx509_signature_ecPublicKey } +#endif }; diff --git a/lib/kafs/Makefile.am b/lib/kafs/Makefile.am index 8c1983ef7..dd23aef76 100644 --- a/lib/kafs/Makefile.am +++ b/lib/kafs/Makefile.am @@ -6,7 +6,7 @@ AM_CPPFLAGS += $(AFS_EXTRA_DEFS) $(ROKEN_RENAME) if KRB5 DEPLIB_krb5 = ../krb5/libkrb5.la $(LIB_hcrypto) -krb5_am_workaround = $(INCLUDE_hcrypto) -I$(top_srcdir)/lib/krb5 +krb5_am_workaround = -I$(top_srcdir)/lib/krb5 else DEPLIB_krb5 = krb5_am_workaround = diff --git a/lib/krb5/Makefile.am b/lib/krb5/Makefile.am index a2058e44f..57ee89a74 100644 --- a/lib/krb5/Makefile.am +++ b/lib/krb5/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) -I../com_err -I$(srcdir)/../com_err $(INCLUDE_sqlite3) $(INCLUDE_libintl) +AM_CPPFLAGS += -I../com_err -I$(srcdir)/../com_err $(INCLUDE_sqlite3) $(INCLUDE_libintl) bin_PROGRAMS = verify_krb5_conf @@ -71,6 +71,7 @@ libkrb5_la_LIBADD = \ $(top_builddir)/lib/wind/libwind.la \ $(top_builddir)/lib/base/libheimbase.la \ $(LIB_pkinit) \ + $(LIB_openssl_crypto) \ $(use_sqlite) \ $(LIB_com_err) \ $(LIB_hcrypto) \ @@ -200,6 +201,7 @@ dist_libkrb5_la_SOURCES = \ padata.c \ pcache.c \ pkinit.c \ + pkinit-ec.c \ principal.c \ prog_setup.c \ prompter_posix.c \ diff --git a/lib/krb5/NTMakefile b/lib/krb5/NTMakefile index 89a0aef93..8c5064b11 100644 --- a/lib/krb5/NTMakefile +++ b/lib/krb5/NTMakefile @@ -1,6 +1,6 @@ ######################################################################## # -# Copyright (c) 2009 - 2013, Secure Endpoints Inc. +# Copyright (c) 2009 - 2016, Secure Endpoints Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -119,6 +119,7 @@ libkrb5_OBJS = \ $(OBJ)\padata.obj \ $(OBJ)\pcache.obj \ $(OBJ)\pkinit.obj \ + $(OBJ)\pkinit-ec.obj \ $(OBJ)\plugin.obj \ $(OBJ)\principal.obj \ $(OBJ)\prog_setup.obj \ @@ -269,6 +270,7 @@ dist_libkrb5_la_SOURCES = \ pac.c \ padata.c \ pkinit.c \ + pkinit-ec.c \ plugin.c \ principal.c \ prog_setup.c \ @@ -340,7 +342,7 @@ $(OBJ)\k524_err.c $(OBJ)\k524_err.h: k524_err.et # libkrb5 $(LIBKRB5): $(libkrb5_OBJS) $(libkrb5_gen_OBJS) - $(LIBCON_C) -OUT:$@ $(LIBHEIMBASE) @<< + $(LIBCON_C) -OUT:$@ $(LIBHEIMBASE) $(LIB_openssl_crypto) @<< $(libkrb5_OBJS: = ) $(libkrb5_gen_OBJS: = diff --git a/lib/krb5/aes-test.c b/lib/krb5/aes-test.c index 1ff197dcf..da66af04d 100644 --- a/lib/krb5/aes-test.c +++ b/lib/krb5/aes-test.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 Kungliga Tekniska Högskolan + * Copyright (c) 2003-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -35,10 +35,6 @@ #include #include -#ifdef HAVE_OPENSSL -#include -#endif - static int verbose = 0; static void diff --git a/lib/krb5/crypto.h b/lib/krb5/crypto.h index 201a1d3ee..368d4f5db 100644 --- a/lib/krb5/crypto.h +++ b/lib/krb5/crypto.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -173,8 +173,15 @@ extern struct _krb5_encryption_type _krb5_enctype_null; extern struct _krb5_encryption_type *_krb5_etypes[]; extern int _krb5_num_etypes; +/* NO_HCRYPTO_POLLUTION is defined in pkinit-ec.c. See commentary there. */ +#ifndef NO_HCRYPTO_POLLUTION /* Interface to the EVP crypto layer provided by hcrypto */ struct _krb5_evp_schedule { + /* + * Normally we'd say EVP_CIPHER_CTX here, but! this header gets + * included in lib/krb5/pkinit-ec.ck + */ EVP_CIPHER_CTX ectx; EVP_CIPHER_CTX dctx; }; +#endif diff --git a/lib/krb5/krb5_locl.h b/lib/krb5/krb5_locl.h index 5e0987fef..cc39b8612 100644 --- a/lib/krb5/krb5_locl.h +++ b/lib/krb5/krb5_locl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -59,6 +59,9 @@ #ifdef HAVE_SYS_MMAN_H #include #endif +#ifdef HAVE_STDINT_H +#include +#endif #ifdef HAVE_UNISTD_H #include #endif @@ -154,11 +157,19 @@ struct sockaddr_dl; #include +/* + * We use OpenSSL for EC, but to do this we need to disable cross-references + * between OpenSSL and hcrypto bn.h and such. Source files that use OpenSSL EC + * must define HEIM_NO_CRYPTO_HDRS before including this file. + */ #define HC_DEPRECATED_CRYPTO +#ifndef HEIM_NO_CRYPTO_HDRS #include "crypto-headers.h" +#endif #include +#include struct send_to_kdc; @@ -378,6 +389,25 @@ enum krb5_pk_type { PKINIT_27 = 2 }; +struct krb5_pk_init_ctx_data { + struct krb5_pk_identity *id; + enum { USE_RSA, USE_DH, USE_ECDH } keyex; + union { + DH *dh; + void *eckey; + } u; + krb5_data *clientDHNonce; + struct krb5_dh_moduli **m; + hx509_peer_info peer; + enum krb5_pk_type type; + unsigned int require_binding:1; + unsigned int require_eku:1; + unsigned int require_krbtgt_otherName:1; + unsigned int require_hostname_match:1; + unsigned int trustedCertifiers:1; + unsigned int anonymous:1; +}; + #endif /* PKINIT */ #define ISTILDE(x) (x == '~') diff --git a/lib/krb5/pkinit-ec.c b/lib/krb5/pkinit-ec.c new file mode 100644 index 000000000..33d7deaa0 --- /dev/null +++ b/lib/krb5/pkinit-ec.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2016 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#ifdef PKINIT + +/* + * As with the other *-ec.c files in Heimdal, this is a bit of a hack. + * + * The idea is to use OpenSSL for EC because hcrypto doesn't have the + * required functionality at this time. To do this we segregate + * EC-using code into separate source files and then we arrange for them + * to get the OpenSSL headers and not the conflicting hcrypto ones. + * + * Because of auto-generated *-private.h headers, we end up needing to + * make sure various types are defined before we include them, thus the + * strange header include order here. + */ + +#ifdef HAVE_HCRYPTO_W_OPENSSL +#include +#include +#include +#include +#define HEIM_NO_CRYPTO_HDRS +#endif + +#include + +/* + * NO_HCRYPTO_POLLUTION -> don't refer to hcrypto type/function names + * that we don't need in this file and which would clash with OpenSSL's + * in ways that are difficult to address in cleaner ways. + * + * In the medium- to long-term what we should do is move all PK in + * Heimdal to the newer EVP interfaces for PK and then nothing outside + * lib/hcrypto should ever have to include OpenSSL headers, and -more + * specifically- the only thing that should ever have to include OpenSSL + * headers is the OpenSSL backend to hcrypto. + */ +#define NO_HCRYPTO_POLLUTION + +#ifdef HAVE_STDINT_H +#include +#endif +#include +#include "krb5_locl.h" + +#include +#include +#include +#include +#include +#include + +#include + +krb5_error_code +_krb5_build_authpack_subjectPK_EC(krb5_context context, + krb5_pk_init_ctx ctx, + AuthPack *a) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + krb5_error_code ret; + ECParameters ecp; + unsigned char *p; + size_t size; + int xlen; + + /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */ + + ecp.element = choice_ECParameters_namedCurve; + ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1, + &ecp.u.namedCurve); + if (ret) + return ret; + + ALLOC(a->clientPublicValue->algorithm.parameters, 1); + if (a->clientPublicValue->algorithm.parameters == NULL) { + free_ECParameters(&ecp); + return krb5_enomem(context); + } + ASN1_MALLOC_ENCODE(ECParameters, p, xlen, &ecp, &size, ret); + free_ECParameters(&ecp); + if (ret) + return ret; + if ((int)size != xlen) + krb5_abortx(context, "asn1 internal error"); + + a->clientPublicValue->algorithm.parameters->data = p; + a->clientPublicValue->algorithm.parameters->length = size; + + /* copy in public key */ + + ret = der_copy_oid(&asn1_oid_id_ecPublicKey, + &a->clientPublicValue->algorithm.algorithm); + if (ret) + return ret; + + ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (ctx->u.eckey == NULL) + return krb5_enomem(context); + + ret = EC_KEY_generate_key(ctx->u.eckey); + if (ret != 1) + return EINVAL; + + xlen = i2o_ECPublicKey(ctx->u.eckey, NULL); + if (xlen <= 0) + return EINVAL; + + p = malloc(xlen); + if (p == NULL) + return krb5_enomem(context); + + a->clientPublicValue->subjectPublicKey.data = p; + + xlen = i2o_ECPublicKey(ctx->u.eckey, &p); + if (xlen <= 0) { + a->clientPublicValue->subjectPublicKey.data = NULL; + free(p); + return EINVAL; + } + + a->clientPublicValue->subjectPublicKey.length = xlen * 8; + + return 0; + + /* XXX verify that this is right with RFC3279 */ +#else + krb5_set_error_message(context, ENOTSUP, + N_("PKINIT: ECDH not supported", "")); + return ENOTSUP; +#endif +} + +krb5_error_code +_krb5_pk_rd_pa_reply_ecdh_compute_key(krb5_context context, + krb5_pk_init_ctx ctx, + const unsigned char *in, + size_t in_sz, + unsigned char **out, + int *out_sz) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + krb5_error_code ret = 0; + int dh_gen_keylen; + + const EC_GROUP *group; + EC_KEY *public = NULL; + + group = EC_KEY_get0_group(ctx->u.eckey); + + public = EC_KEY_new(); + if (public == NULL) + return krb5_enomem(context); + if (EC_KEY_set_group(public, group) != 1) { + EC_KEY_free(public); + return krb5_enomem(context); + } + + if (o2i_ECPublicKey(&public, &in, in_sz) == NULL) { + EC_KEY_free(public); + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't parse ECDH public key", "")); + return ret; + } + + *out_sz = (EC_GROUP_get_degree(group) + 7) / 8; + if (*out_sz < 0) + return EOVERFLOW; + *out = malloc(*out_sz); + if (*out == NULL) { + EC_KEY_free(public); + return krb5_enomem(context); + } + dh_gen_keylen = ECDH_compute_key(*out, *out_sz, + EC_KEY_get0_public_key(public), + ctx->u.eckey, NULL); + EC_KEY_free(public); + if (dh_gen_keylen <= 0) { + ret = KRB5KRB_ERR_GENERIC; + dh_gen_keylen = 0; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't compute ECDH public key", "")); + free(*out); + *out = NULL; + *out_sz = 0; + } + *out_sz = dh_gen_keylen; + + return ret; +#else + krb5_set_error_message(context, ENOTSUP, + N_("PKINIT: ECDH not supported", "")); + return ENOTSUP; +#endif +} + +void +_krb5_pk_eckey_free(void *eckey) +{ +#ifdef HAVE_HCRYPTO_W_OPENSSL + EC_KEY_free(eckey); +#endif +} + +#else + +static char lib_krb5_pkinit_ec_c = '\0'; + +#endif diff --git a/lib/krb5/pkinit.c b/lib/krb5/pkinit.c index c0bd40bfd..7cc630d8d 100644 --- a/lib/krb5/pkinit.c +++ b/lib/krb5/pkinit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 2003 - 2016 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -58,27 +58,6 @@ struct krb5_pk_cert { hx509_cert cert; }; -struct krb5_pk_init_ctx_data { - struct krb5_pk_identity *id; - enum { USE_RSA, USE_DH, USE_ECDH } keyex; - union { - DH *dh; -#ifdef HAVE_OPENSSL - EC_KEY *eckey; -#endif - } u; - krb5_data *clientDHNonce; - struct krb5_dh_moduli **m; - hx509_peer_info peer; - enum krb5_pk_type type; - unsigned int require_binding:1; - unsigned int require_eku:1; - unsigned int require_krbtgt_otherName:1; - unsigned int require_hostname_match:1; - unsigned int trustedCertifiers:1; - unsigned int anonymous:1; -}; - static void pk_copy_error(krb5_context context, hx509_context hx509ctx, @@ -533,74 +512,14 @@ build_auth_pack(krb5_context context, return ret; if (size != dhbuf.length) krb5_abortx(context, "asn1 internal error"); + a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8; + a->clientPublicValue->subjectPublicKey.data = dhbuf.data; } else if (ctx->keyex == USE_ECDH) { -#ifdef HAVE_OPENSSL - ECParameters ecp; - unsigned char *p; - int xlen; - - /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */ - - ecp.element = choice_ECParameters_namedCurve; - ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1, - &ecp.u.namedCurve); - if (ret) - return ret; - - ALLOC(a->clientPublicValue->algorithm.parameters, 1); - if (a->clientPublicValue->algorithm.parameters == NULL) { - free_ECParameters(&ecp); - return ENOMEM; - } - ASN1_MALLOC_ENCODE(ECParameters, p, xlen, &ecp, &size, ret); - free_ECParameters(&ecp); - if (ret) - return ret; - if ((int)size != xlen) - krb5_abortx(context, "asn1 internal error"); - - a->clientPublicValue->algorithm.parameters->data = p; - a->clientPublicValue->algorithm.parameters->length = size; - - /* copy in public key */ - - ret = der_copy_oid(&asn1_oid_id_ecPublicKey, - &a->clientPublicValue->algorithm.algorithm); - if (ret) - return ret; - - ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - if (ctx->u.eckey == NULL) - return ENOMEM; - - ret = EC_KEY_generate_key(ctx->u.eckey); - if (ret != 1) - return EINVAL; - - /* encode onto dhkey */ - - xlen = i2o_ECPublicKey(ctx->u.eckey, NULL); - if (xlen <= 0) - abort(); - - dhbuf.data = malloc(xlen); - if (dhbuf.data == NULL) - abort(); - dhbuf.length = xlen; - p = dhbuf.data; - - xlen = i2o_ECPublicKey(ctx->u.eckey, &p); - if (xlen <= 0) - abort(); - - /* XXX verify that this is right with RFC3279 */ -#else - return EINVAL; -#endif + ret = _krb5_build_authpack_subjectPK_EC(context, ctx, a); + if (ret) + return ret; } else krb5_abortx(context, "internal error"); - a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8; - a->clientPublicValue->subjectPublicKey.data = dhbuf.data; } { @@ -1443,51 +1362,11 @@ pk_rd_pa_reply_dh(krb5_context context, } } else { -#ifdef HAVE_OPENSSL - const EC_GROUP *group; - EC_KEY *public = NULL; - - group = EC_KEY_get0_group(ctx->u.eckey); - - public = EC_KEY_new(); - if (public == NULL) { - ret = ENOMEM; - goto out; - } - if (EC_KEY_set_group(public, group) != 1) { - EC_KEY_free(public); - ret = ENOMEM; - goto out; - } - - if (o2i_ECPublicKey(&public, &p, size) == NULL) { - EC_KEY_free(public); - ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, - N_("PKINIT: Can't parse ECDH public key", "")); - goto out; - } - - size = (EC_GROUP_get_degree(group) + 7) / 8; - dh_gen_key = malloc(size); - if (dh_gen_key == NULL) { - EC_KEY_free(public); - ret = krb5_enomem(context); - goto out; - } - dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, - EC_KEY_get0_public_key(public), ctx->u.eckey, NULL); - EC_KEY_free(public); - if (dh_gen_keylen == -1) { - ret = KRB5KRB_ERR_GENERIC; - dh_gen_keylen = 0; - krb5_set_error_message(context, ret, - N_("PKINIT: Can't compute ECDH public key", "")); - goto out; - } -#else - ret = EINVAL; -#endif + ret = _krb5_pk_rd_pa_reply_ecdh_compute_key(context, ctx, p, + size, &dh_gen_key, + &dh_gen_keylen); + if (ret) + goto out; } if (dh_gen_keylen <= 0) { @@ -2309,10 +2188,8 @@ _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) case USE_RSA: break; case USE_ECDH: -#ifdef HAVE_OPENSSL if (ctx->u.eckey) - EC_KEY_free(ctx->u.eckey); -#endif + _krb5_pk_eckey_free(ctx->u.eckey); break; } if (ctx->id) { diff --git a/lib/ntlm/Makefile.am b/lib/ntlm/Makefile.am index e37f53cea..d33efd2b6 100644 --- a/lib/ntlm/Makefile.am +++ b/lib/ntlm/Makefile.am @@ -2,8 +2,6 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) - lib_LTLIBRARIES = libheimntlm.la dist_include_HEADERS = heimntlm.h $(srcdir)/heimntlm-protos.h diff --git a/lib/otp/Makefile.am b/lib/otp/Makefile.am index 38681ef0c..371a61ae3 100644 --- a/lib/otp/Makefile.am +++ b/lib/otp/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += $(INCLUDE_hcrypto) $(ROKEN_RENAME) +AM_CPPFLAGS += $(ROKEN_RENAME) if HAVE_DBHEADER AM_CPPFLAGS += -I$(DBHEADER) endif diff --git a/tools/Makefile.am b/tools/Makefile.am index aa3e27686..f2efe9b62 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -33,7 +33,6 @@ subst = sed -e "s!@PACKAGE\@!$(PACKAGE)!g" \ -e "s!@PTHREAD_LIBADD\@!$(PTHREAD_LIBADD)!g" \ -e "s!@LIB_crypt\@!$(LIB_crypt)!g" \ -e "s!@LIB_dbopen\@!$(LIB_dbopen)!g" \ - -e "s!@INCLUDE_hcrypto\@!$(INCLUDE_hcrypto)!g" \ -e "s!@LIB_hcrypto_appl\@!$(LIB_hcrypto_appl)!g" \ -e "s!@LIB_dlopen\@!$(LIB_dlopen)!g" \ -e "s!@LIB_door_create\@!$(LIB_door_create)!g" \ diff --git a/tools/krb5-config.in b/tools/krb5-config.in index 9e72161e6..77652d3bc 100644 --- a/tools/krb5-config.in +++ b/tools/krb5-config.in @@ -246,7 +246,7 @@ if test "$do_libs" = "yes"; then echo ${lib_flags} fi if test "$do_cflags" = "yes"; then - cflags="@INCLUDE_hcrypto@" + cflags="" if test X"${includedir}" != X/usr/include; then cflags="-I${includedir} $cflags" fi diff --git a/windows/NTMakefile.config b/windows/NTMakefile.config index 4da9cb53a..adde4b649 100644 --- a/windows/NTMakefile.config +++ b/windows/NTMakefile.config @@ -39,6 +39,10 @@ PKINIT=1 # Disable AFS support NO_AFS=1 +# OpenSSL (mostly not needed on Windows, but should work) +# INCLUDE_openssl_crypto= +# LIB_openssl_crypto= + # OpenLDAP package is available # OPENLDAP=1