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