diff --git a/.travis.yml b/.travis.yml index 2cace3f4..e4a2b9e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ sudo: false +dist: xenial language: c compiler: - gcc @@ -6,6 +7,7 @@ compiler: addons: apt: packages: + - libssl-dev - libunbound-dev - libidn11-dev - libyaml-dev diff --git a/ChangeLog b/ChangeLog index 0eb7383c..234077f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,12 @@ * 2019-01-11: Version 1.5.1 + * Introduce proof of concept GnuTLS implementation. Incomplete support + for Trust Anchor validation. Requires GnuTLS DANE library. Currently + untested with GnuTLS prior to 3.5.19, so configure demands a minumum + version of 3.5.0. + * Be consistent and always fail connection setup if setting ciphers/curves/ + TLS version/cipher suites fails. + * Refactor OpenSSL usage into modules under src/openssl. + Drop support for LibreSSL and versions of OpenSSL prior to 1.0.2. * PR #414: remove TLS13 ciphers from cipher_list, but only when SSL_CTX_set_ciphersuites is available. Thanks Bruno Pagani diff --git a/Makefile.in b/Makefile.in index 180fc2c5..f92fccdf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -213,6 +213,7 @@ $(distdir): mkdir -p $(distdir)/src/compat mkdir -p $(distdir)/src/util mkdir -p $(distdir)/src/gldns + mkdir -p $(distdir)/src/openssl mkdir -p $(distdir)/src/tools mkdir -p $(distdir)/src/jsmn mkdir -p $(distdir)/src/yxml @@ -266,6 +267,7 @@ $(distdir): cp $(srcdir)/spec/*.html $(distdir)/spec cp $(srcdir)/spec/example/Makefile.in $(distdir)/spec/example cp $(srcdir)/spec/example/*.[ch] $(distdir)/spec/example + cp $(srcdir)/src/tools/*.[ch] $(distdir)/src/openssl cp $(srcdir)/src/tools/Makefile.in $(distdir)/src/tools cp $(srcdir)/src/tools/*.[ch] $(distdir)/src/tools cp $(srcdir)/stubby/stubby.yml.example $(distdir)/stubby diff --git a/configure.ac b/configure.ac index 4edd248f..f927ef6c 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,7 @@ AC_PREREQ([2.68]) AC_CONFIG_MACRO_DIRS([m4]) sinclude(./m4/acx_openssl.m4) sinclude(./m4/acx_getaddrinfo.m4) +sinclude(./m4/ac_lib_nettle.m4) sinclude(./m4/ax_check_compile_flag.m4) sinclude(./m4/pkg.m4) @@ -441,25 +442,65 @@ dnl SSLLIB="" dnl ] dnl ) +# Which TLS and crypto libs to use. +AC_ARG_WITH([gnutls], + [AS_HELP_STRING([--with-gnutls], + [use GnuTLS instead of OpenSSL])], + [ + PKG_CHECK_MODULES([libgnutls], [gnutls >= 3.5.0]) + PKG_CHECK_MODULES([libgnutlsdane], [gnutls-dane >= 3.5.0]) + LIBS="$libgnutls_LIBS $libgnutlsdane_LIBS $LIBS" + CFLAGS="$libgnutls_CFLAGS $libgnutlsdane_CFLAGS $CFLAGS" + AC_SUBST([TLSDIR], 'gnutls') + AC_DEFINE([USE_GNUTLS], [1], [Use the GnuTLS library]) + if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then + + AX_LIB_NETTLE(yes) + USE_NETTLE="yes" + AC_DEFINE(HAVE_NETTLE, 1, [Use libnettle for crypto]) + AC_CHECK_HEADERS([nettle/dsa-compat.h],,, [AC_INCLUDES_DEFAULT]) + fi + ], + [ + if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then + ACX_WITH_SSL + fi + ACX_LIB_SSL + AC_SUBST([TLSDIR], 'openssl') + + # Verify OpenSSL is at least version 1.0.2. + # We also check it's not LibreSSL, but that's a little later, not here. + AC_CHECK_FUNCS([X509_check_host SSL_dane_enable]) + if test "x$ac_cv_func_X509_check_host" != xyes; then + AC_MSG_ERROR([getdns requires OpenSSL version 1.0.2 or later]) + fi + + AC_MSG_CHECKING([whether we need to compile/link DANE support]) + DANESSL_XTRA_OBJS="" + if test "x$ac_cv_func_SSL_dane_enable" = xyes; then + AC_MSG_RESULT([no]) + else + AC_MSG_RESULT([yes]) + AC_DEFINE([USE_DANESSL], [1], [Define this to use DANE functions from the ssl_dane/danessl library.]) + DANESSL_XTRA_OBJS="danessl.lo" + fi + AC_SUBST(DANESSL_XTRA_OBJS) + ]) + + # openssl -if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then -ACX_WITH_SSL -fi -ACX_LIB_SSL +if test $USE_NSS = "no" -a $USE_NETTLE = "no" ; then AC_MSG_CHECKING([for LibreSSL]) if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_LIBRESSL], [1], [Define if we have LibreSSL]) - # libressl provides these compat functions, but they may also be - # declared by the OS in libc. See if they have been declared. - AC_CHECK_DECLS([strlcpy,arc4random,arc4random_uniform]) + AC_MSG_ERROR([getdns does not support LibreSSL]) else AC_MSG_RESULT([no]) fi AC_CHECK_HEADERS([openssl/conf.h openssl/ssl.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/bn.h openssl/rsa.h openssl/dsa.h],,, [AC_INCLUDES_DEFAULT]) -AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version SSL_CTX_dane_enable SSL_dane_enable SSL_dane_tlsa_add X509_check_host X509_get_notAfter X509_get0_notAfter SSL_CTX_set_ciphersuites SSL_set_ciphersuites]) +AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify OpenSSL_version_num OpenSSL_version SSL_CTX_dane_enable SSL_dane_enable SSL_dane_tlsa_add X509_check_host X509_get_notAfter X509_get0_notAfter SSL_CTX_set_ciphersuites SSL_set_ciphersuites OPENSSL_init_crypto DSA_set0_pqg DSA_set0_key RSA_set0_key]) AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set1_curves_list,SSL_set1_curves_list,SSL_set_min_proto_version,SSL_get_min_proto_version], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H @@ -480,29 +521,7 @@ AC_INCLUDES_DEFAULT #include #include ]) - -AC_MSG_CHECKING([whether we need to compile/link DANE support]) -DANESSL_XTRA_OBJS="" -AC_LANG_PUSH(C) -AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([ - [#include ] - [#if OPENSSL_VERSION_NUMBER < 0x1000000fL] - [#error "OpenSSL 1.0.0 or higher required for DANE library"] - [#elif defined(HAVE_SSL_DANE_ENABLE)] - [#error "OpenSSL has native DANE support"] - [#elif defined(LIBRESSL_VERSION_NUMBER)] - [#error "dane_ssl library does not work with LibreSSL"] - [#endif] - ],[[]])], - [ - AC_MSG_RESULT([yes]) - AC_DEFINE([USE_DANESSL], [1], [Define this to use DANE functions from the ssl_dane/danessl library.]) - DANESSL_XTRA_OBJS="danessl.lo" - ], - [AC_MSG_RESULT([no])]) -AC_LANG_POP(C) -AC_SUBST(DANESSL_XTRA_OBJS) +fi AC_ARG_ENABLE(sha1, AC_HELP_STRING([--disable-sha1], [Disable SHA1 RRSIG support, does not disable nsec3 support])) case "$enable_sha1" in @@ -772,8 +791,8 @@ case "$enable_edns_cookies" in no) ;; yes|*) - if test "x_$HAVE_SSL" != "x_yes"; then - AC_MSG_ERROR([edns cookies need openssl libcrypto which is not available, please rerun with --disable-edns-cookies]) + if test "x_$HAVE_SSL" != "x_yes" -a $USE_NETTLE = "no"; then + AC_MSG_ERROR([edns cookies needs crypto library which is not available, please rerun with --disable-edns-cookies]) fi AC_DEFINE_UNQUOTED([EDNS_COOKIES], [1], [Define this to enable the experimental edns cookies.]) ;; diff --git a/m4/ax_lib_nettle.m4 b/m4/ax_lib_nettle.m4 new file mode 100644 index 00000000..e0ba1eac --- /dev/null +++ b/m4/ax_lib_nettle.m4 @@ -0,0 +1,80 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_lib_nettle.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_LIB_NETTLE([yes|no|auto]) +# +# DESCRIPTION +# +# Searches for the 'nettle' library with the --with... option. +# +# If found, define HAVE_NETTLE and macro NETTLE_LIBS. Also defines +# NETTLE_WITH_ for the algorithms found available. Possible +# algorithms: AES ARCTWO BLOWFISH CAST128 DES DES3 SERPENT TWOFISH MD2 MD4 +# MD5 SHA1 SHA256. +# +# The argument is used if no --with...-nettle option is set. Value "yes" +# requires the configuration by default. Value "no" does not require it by +# default. Value "auto" configures the library only if available. +# +# See also AX_LIB_BEECRYPT, AX_LIB_CRYPTO, and AX_LIB_GCRYPT. +# +# LICENSE +# +# Copyright (c) 2009 Fabien Coelho +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +# AX_CHECK_NETTLE_ALGO([name],[function]) +AC_DEFUN([AX_CHECK_NETTLE_ALGO],[ + AC_CHECK_LIB([nettle], [nettle_$2], + AC_DEFINE([NETTLE_WITH_$1],[1],[Algorithm $1 in nettle library])) +]) + +# AX_LIB_NETTLE([yes|no|auto]) +AC_DEFUN([AX_LIB_NETTLE],[ + AC_MSG_CHECKING([whether nettle is enabled]) + AC_ARG_WITH([nettle], + AC_HELP_STRING([--with-nettle], [Require nettle library (required with GnuTLS)]),[ + AC_MSG_RESULT([$withval]) + ax_with_nettle=$withval + ],[ + AC_MSG_RESULT([$1]) + ax_with_nettle=$1 + ]) + if test "$ax_with_nettle" = "yes" -o "$ax_with_nettle" = "auto" ; then + AC_CHECK_HEADERS([nettle/nettle-meta.h],[ + AC_CHECK_LIB([nettle],[nettle_base64_encode_final],[ + AC_DEFINE([HAVE_NETTLE],[1],[Nettle library is available]) + HAVE_NETTLE=1 + AC_SUBST([NETTLE_LIBS],[-lnettle]) + # ciphers + AX_CHECK_NETTLE_ALGO([AES],[aes_encrypt]) + AX_CHECK_NETTLE_ALGO([ARCTWO],[arctwo_encrypt]) + AX_CHECK_NETTLE_ALGO([BLOWFISH],[blowfish_encrypt]) + AX_CHECK_NETTLE_ALGO([CAST128],[cast128_encrypt]) + AX_CHECK_NETTLE_ALGO([DES],[des_encrypt]) + AX_CHECK_NETTLE_ALGO([DES3],[des3_encrypt]) + AX_CHECK_NETTLE_ALGO([SERPENT],[serpent_encrypt]) + AX_CHECK_NETTLE_ALGO([TWOFISH],[twofish_encrypt]) + # digests + AX_CHECK_NETTLE_ALGO([MD2],[md2_digest]) + AX_CHECK_NETTLE_ALGO([MD4],[md4_digest]) + AX_CHECK_NETTLE_ALGO([MD5],[md5_digest]) + AX_CHECK_NETTLE_ALGO([SHA1],[sha1_digest]) + AX_CHECK_NETTLE_ALGO([SHA256],[sha256_digest]) + ]) + ]) + # complain only if explicitly required + if test "$ax_with_nettle" = "yes" -a "x$HAVE_NETTLE" = "x" ; then + AC_MSG_ERROR([cannot configure required nettle library]) + fi + fi +]) diff --git a/src/Makefile.in b/src/Makefile.in index 1059afca..411f5874 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -52,11 +52,12 @@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ srcdir = @srcdir@ +tlsdir = @TLSDIR@ stubbysrcdir = $(srcdir)/../stubby LIBTOOL = ../libtool CC=@CC@ -CFLAGS=-I$(srcdir) -I. -I$(srcdir)/util/auxiliary -I$(stubbysrcdir)/src @CFLAGS@ @CPPFLAGS@ $(XTRA_CFLAGS) +CFLAGS=-I$(srcdir) -I. -I$(srcdir)/util/auxiliary -I$(srcdir)/$(tlsdir) -I$(stubbysrcdir)/src @CFLAGS@ @CPPFLAGS@ $(XTRA_CFLAGS) WPEDANTICFLAG=@WPEDANTICFLAG@ WNOERRORFLAG=@WNOERRORFLAG@ LDFLAGS=@LDFLAGS@ @LIBS@ @@ -78,9 +79,9 @@ C99COMPATFLAGS=@C99COMPATFLAGS@ DEFAULT_EVENTLOOP_OBJ=@DEFAULT_EVENTLOOP@.lo GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \ - list.lo request-internal.lo platform.lo pubkey-pinning.lo rr-dict.lo \ + list.lo request-internal.lo platform.lo rr-dict.lo \ rr-iter.lo server.lo stub.lo sync.lo ub_loop.lo util-internal.lo \ - mdns.lo + mdns.lo pubkey-pinning.lo GLDNS_OBJ=keyraw.lo gbuffer.lo wire2str.lo parse.lo parseutil.lo rrdef.lo \ str2wire.lo @@ -91,9 +92,10 @@ LIBOBJDIR= LIBOBJS=@LIBOBJS@ COMPAT_OBJ=$(LIBOBJS:.o=.lo) -UTIL_OBJ=rbtree.lo val_secalgo.lo lruhash.lo lookup3.lo locks.lo +UTIL_OBJ=rbtree.lo lruhash.lo lookup3.lo locks.lo JSMN_OBJ=jsmn.lo +TLS_OBJ=tls.lo pubkey-pinning-internal.lo keyraw-internal.lo val_secalgo.lo anchor-internal.lo YXML_OBJ=yxml.lo YAML_OBJ=convert_yaml_to_json.lo @@ -133,6 +135,9 @@ $(UTIL_OBJ): $(JSMN_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -DJSMN_GETDNS -c $(srcdir)/jsmn/$(@:.lo=.c) -o $@ +$(TLS_OBJ): + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(srcdir)/$(tlsdir)/$(@:.lo=.c) -o $@ + $(YAML_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(stubbysrcdir)/src/yaml/$(@:.lo=.c) -o $@ @@ -194,8 +199,8 @@ libgetdns_ext_uv.la: libgetdns.la libuv.lo libgetdns_ext_ev.la: libgetdns.la libev.lo $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ libev.lo libgetdns.la $(LDFLAGS) $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols -libgetdns.la: $(GETDNS_OBJ) version.lo context.lo anchor.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(YXML_OBJ) $(GETDNS_XTRA_OBJS) - $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo anchor.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(YXML_OBJ) $(GETDNS_XTRA_OBJS) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols +libgetdns.la: $(GETDNS_OBJ) version.lo context.lo anchor.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(TLS_OBJ) $(YXML_OBJ) $(GETDNS_XTRA_OBJS) + $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo anchor.lo $(DEFAULT_EVENTLOOP_OBJ) $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(TLS_OBJ) $(YXML_OBJ) $(GETDNS_XTRA_OBJS) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols test: default cd test && $(MAKE) $@ @@ -271,15 +276,15 @@ Makefile: $(srcdir)/Makefile.in ../config.status depend: (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) - (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -Iyxml -Iutil/auxiliary -I../stubby/src *.c gldns/*.c compat/*.c util/*.c jsmn/*.c yxml/*.c ssl_dane/danessl.c extension/*.c ../stubby/src/*.c | \ + (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -I$(tlsdir) -Iyxml -Iutil/auxiliary -I../stubby/src *.c gldns/*.c compat/*.c util/*.c jsmn/*.c $(tlsdir)/*.c yxml/*.c extension/*.c ../stubby/src/*.c | \ sed -e "s? $$blddir/? ?g" \ -e 's? gldns/? $$(srcdir)/gldns/?g' \ -e 's? compat/? $$(srcdir)/compat/?g' \ -e 's? util/auxiliary/util/? $$(srcdir)/util/auxiliary/util/?g' \ -e 's? util/? $$(srcdir)/util/?g' \ -e 's? jsmn/? $$(srcdir)/jsmn/?g' \ + -e 's? $(tlsdir)/? $$(srcdir)/$$(tlsdir)/?g' \ -e 's? yxml/? $$(srcdir)/yxml/?g' \ - -e 's? ssl_dane/? $$(srcdir)/ssl_dane/?g' \ -e 's? extension/? $$(srcdir)/extension/?g' \ -e 's? \.\./stubby/? $$(stubbysrcdir)/?g' \ -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ @@ -300,124 +305,102 @@ FORCE: # Dependencies for gldns, utils, the extensions and compat functions anchor.lo anchor.o: $(srcdir)/anchor.c \ - config.h \ - $(srcdir)/debug.h $(srcdir)/anchor.h \ + config.h $(srcdir)/debug.h \ + $(srcdir)/anchor.h \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/types-internal.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/context.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/yxml/yxml.h \ - $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \ - $(srcdir)/gldns/keyraw.h $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/platform.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/dnssec.h \ + $(srcdir)/gldns/rrdef.h $(srcdir)/yxml/yxml.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/str2wire.h \ + $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/$(tlsdir)/keyraw-internal.h \ + $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/platform.h const-info.lo const-info.o: $(srcdir)/const-info.c \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/const-info.h context.lo context.o: $(srcdir)/context.c \ - config.h \ - $(srcdir)/anchor.h \ + config.h $(srcdir)/anchor.h \ getdns/getdns.h \ getdns/getdns_extra.h \ - $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/debug.h \ - $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h \ - $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ - $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/dnssec.h \ - $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h $(srcdir)/ssl_dane/danessl.h + $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/types-internal.h \ + $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/debug.h $(srcdir)/gldns/str2wire.h \ + $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h \ + $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/tls.h \ + $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h \ + $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h $(srcdir)/const-info.h convert.lo convert.o: $(srcdir)/convert.c \ config.h \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/extension/default_eventloop.h \ - $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h \ - $(srcdir)/util/lruhash.h $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h \ - $(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h \ - $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/gldns/wire2str.h \ - $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h $(srcdir)/const-info.h $(srcdir)/dict.h \ - $(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(srcdir)/convert.h -dict.lo dict.o: $(srcdir)/dict.c \ - config.h \ + $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h \ + $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ + $(srcdir)/gldns/parseutil.h $(srcdir)/const-info.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(srcdir)/convert.h \ + $(srcdir)/debug.h +dict.lo dict.o: $(srcdir)/dict.c config.h \ $(srcdir)/types-internal.h \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/util-internal.h $(srcdir)/context.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h \ - $(srcdir)/gldns/parseutil.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/dict.h $(srcdir)/list.h \ + $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/parseutil.h dnssec.lo dnssec.o: $(srcdir)/dnssec.c \ - config.h \ - $(srcdir)/debug.h \ + config.h $(srcdir)/debug.h \ getdns/getdns.h \ $(srcdir)/context.h \ getdns/getdns_extra.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/util-internal.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h \ - $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h \ - $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/util/val_secalgo.h \ - $(srcdir)/util/orig-headers/val_secalgo.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/util-internal.h \ + $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \ + $(srcdir)/gldns/keyraw.h $(srcdir)/$(tlsdir)/keyraw-internal.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h \ + $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/util/val_secalgo.h $(srcdir)/gldns/gbuffer.h general.lo general.o: $(srcdir)/general.c \ - config.h \ - $(srcdir)/general.h \ + config.h $(srcdir)/general.h \ getdns/getdns.h \ $(srcdir)/types-internal.h \ getdns/getdns_extra.h \ - $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/ub_loop.h $(srcdir)/debug.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h \ - $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/util-internal.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h \ - $(srcdir)/dict.h $(srcdir)/mdns.h $(srcdir)/platform.h + $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/gldns/wire2str.h $(srcdir)/context.h \ + $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/util-internal.h \ + $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/dict.h $(srcdir)/mdns.h $(srcdir)/debug.h list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/util-internal.h \ - config.h \ - $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/list.h $(srcdir)/dict.h -mdns.lo mdns.o: $(srcdir)/mdns.c \ - config.h \ + config.h $(srcdir)/context.h \ + $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/list.h $(srcdir)/dict.h +mdns.lo mdns.o: $(srcdir)/mdns.c config.h \ $(srcdir)/debug.h $(srcdir)/context.h \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/general.h $(srcdir)/gldns/rrdef.h $(srcdir)/util-internal.h \ - $(srcdir)/platform.h $(srcdir)/mdns.h $(srcdir)/util/auxiliary/util/fptr_wlist.h $(srcdir)/util/lookup3.h \ - $(srcdir)/util/orig-headers/lookup3.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/general.h \ + $(srcdir)/gldns/rrdef.h $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/mdns.h platform.lo platform.o: $(srcdir)/platform.c $(srcdir)/platform.h \ config.h pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c \ - config.h \ - $(srcdir)/debug.h \ + config.h $(srcdir)/debug.h \ getdns/getdns.h \ $(srcdir)/context.h \ getdns/getdns_extra.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/util-internal.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/util-internal.h \ + $(srcdir)/$(tlsdir)/pubkey-pinning-internal.h request-internal.lo request-internal.o: $(srcdir)/request-internal.c \ config.h \ $(srcdir)/types-internal.h \ @@ -425,11 +408,9 @@ request-internal.lo request-internal.o: $(srcdir)/request-internal.c \ getdns/getdns_extra.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/util-internal.h $(srcdir)/context.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ - $(srcdir)/dict.h $(srcdir)/convert.h $(srcdir)/general.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/gldns/rrdef.h \ + $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/debug.h $(srcdir)/convert.h $(srcdir)/general.h rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h \ config.h \ getdns/getdns.h \ @@ -437,10 +418,8 @@ rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h \ getdns/getdns_extra.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h \ - $(srcdir)/dict.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h \ + $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/dict.h rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ config.h \ getdns/getdns.h \ @@ -451,12 +430,10 @@ server.lo server.o: $(srcdir)/server.c \ getdns/getdns.h \ $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/util-internal.h $(srcdir)/platform.h -stub.lo stub.o: $(srcdir)/stub.c \ - config.h \ + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/debug.h \ + $(srcdir)/util-internal.h $(srcdir)/platform.h +stub.lo stub.o: $(srcdir)/stub.c config.h \ $(srcdir)/debug.h $(srcdir)/stub.h \ getdns/getdns.h \ $(srcdir)/types-internal.h \ @@ -464,53 +441,45 @@ stub.lo stub.o: $(srcdir)/stub.c \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h \ $(srcdir)/rr-dict.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h \ - $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h \ - $(srcdir)/util/lruhash.h $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h \ - $(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/anchor.h \ - $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h $(srcdir)/ssl_dane/danessl.h + $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/anchor.h \ + $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/general.h \ + $(srcdir)/pubkey-pinning.h sync.lo sync.o: $(srcdir)/sync.c \ getdns/getdns.h \ - config.h \ - $(srcdir)/context.h \ + config.h $(srcdir)/context.h \ getdns/getdns_extra.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h \ - $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/general.h \ + $(srcdir)/util-internal.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h ub_loop.lo ub_loop.o: $(srcdir)/ub_loop.c $(srcdir)/ub_loop.h \ - config.h \ - getdns/getdns.h \ - getdns/getdns_extra.h \ - $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/debug.h + config.h util-internal.lo util-internal.o: $(srcdir)/util-internal.c \ config.h \ - getdns/getdns.h \ - $(srcdir)/dict.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/types-internal.h \ + getdns/getdns.h $(srcdir)/dict.h \ + $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/types-internal.h \ getdns/getdns_extra.h \ $(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h \ - $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h \ - $(srcdir)/util/lruhash.h $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h \ - $(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h \ - $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/gldns/str2wire.h \ - $(srcdir)/gldns/rrdef.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h + $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h \ + $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dnssec.h \ + $(srcdir)/gldns/rrdef.h gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c \ config.h \ $(srcdir)/gldns/gbuffer.h keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c \ config.h \ - $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h + $(srcdir)/gldns/keyraw.h $(srcdir)/$(tlsdir)/keyraw-internal.h $(srcdir)/gldns/rrdef.h parse.lo parse.o: $(srcdir)/gldns/parse.c \ - config.h \ - $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h + config.h $(srcdir)/gldns/parse.h \ + $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h parseutil.lo parseutil.o: $(srcdir)/gldns/parseutil.c \ config.h \ $(srcdir)/gldns/parseutil.h rrdef.lo rrdef.o: $(srcdir)/gldns/rrdef.c \ - config.h \ - $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h + config.h $(srcdir)/gldns/rrdef.h \ + $(srcdir)/gldns/parseutil.h str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c \ config.h \ $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/gbuffer.h \ @@ -518,7 +487,8 @@ str2wire.lo str2wire.o: $(srcdir)/gldns/str2wire.c \ wire2str.lo wire2str.o: $(srcdir)/gldns/wire2str.c \ config.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/keyraw.h + $(srcdir)/gldns/parseutil.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/keyraw.h \ + $(srcdir)/$(tlsdir)/keyraw-internal.h arc4_lock.lo arc4_lock.o: $(srcdir)/compat/arc4_lock.c \ config.h arc4random.lo arc4random.o: $(srcdir)/compat/arc4random.c \ @@ -548,8 +518,8 @@ strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c \ strptime.lo strptime.o: $(srcdir)/compat/strptime.c \ config.h locks.lo locks.o: $(srcdir)/util/locks.c \ - config.h \ - $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h + config.h $(srcdir)/util/locks.h \ + $(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h lookup3.lo lookup3.o: $(srcdir)/util/lookup3.c \ config.h \ $(srcdir)/util/auxiliary/util/storage/lookup3.h $(srcdir)/util/lookup3.h \ @@ -564,17 +534,41 @@ rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c \ $(srcdir)/util/auxiliary/log.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h \ $(srcdir)/util/auxiliary/fptr_wlist.h $(srcdir)/util/auxiliary/util/fptr_wlist.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h -val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c \ +jsmn.lo jsmn.o: $(srcdir)/jsmn/jsmn.c $(srcdir)/jsmn/jsmn.h +anchor-internal.lo anchor-internal.o: $(srcdir)/$(tlsdir)/anchor-internal.c \ + config.h $(srcdir)/anchor.h \ + getdns/getdns.h \ + getdns/getdns_extra.h \ + $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/types-internal.h \ + $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h +keyraw-internal.lo keyraw-internal.o: $(srcdir)/$(tlsdir)/keyraw-internal.c \ config.h \ - $(srcdir)/util/auxiliary/util/data/packed_rrset.h \ - $(srcdir)/util/auxiliary/validator/val_secalgo.h $(srcdir)/util/val_secalgo.h \ - $(srcdir)/util/orig-headers/val_secalgo.h $(srcdir)/util/auxiliary/validator/val_nsec3.h \ + $(srcdir)/gldns/keyraw.h $(srcdir)/$(tlsdir)/keyraw-internal.h $(srcdir)/gldns/rrdef.h +pubkey-pinning-internal.lo pubkey-pinning-internal.o: $(srcdir)/$(tlsdir)/pubkey-pinning-internal.c $(srcdir)/context.h \ + getdns/getdns.h \ + getdns/getdns_extra.h \ + config.h \ + $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ + $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/pubkey-pinning.h +tls.lo tls.o: $(srcdir)/$(tlsdir)/tls.c \ + config.h $(srcdir)/debug.h \ + $(srcdir)/context.h \ + getdns/getdns.h \ + getdns/getdns_extra.h \ + $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ + $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/tls.h +val_secalgo.lo val_secalgo.o: $(srcdir)/$(tlsdir)/val_secalgo.c \ + config.h \ + $(srcdir)/util/auxiliary/util/data/packed_rrset.h $(srcdir)/$(tlsdir)/validator/val_secalgo.h \ + $(srcdir)/util/val_secalgo.h $(srcdir)/gldns/gbuffer.h $(srcdir)/$(tlsdir)/validator/val_nsec3.h \ $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/util/auxiliary/sldns/rrdef.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/util/auxiliary/sldns/keyraw.h $(srcdir)/gldns/keyraw.h \ - $(srcdir)/util/auxiliary/sldns/sbuffer.h $(srcdir)/gldns/gbuffer.h -jsmn.lo jsmn.o: $(srcdir)/jsmn/jsmn.c $(srcdir)/jsmn/jsmn.h + $(srcdir)/$(tlsdir)/keyraw-internal.h $(srcdir)/util/auxiliary/sldns/sbuffer.h yxml.lo yxml.o: $(srcdir)/yxml/yxml.c $(srcdir)/yxml/yxml.h -danessl.lo danessl.o: $(srcdir)/ssl_dane/danessl.c $(srcdir)/ssl_dane/danessl.h libev.lo libev.o: $(srcdir)/extension/libev.c \ config.h \ $(srcdir)/types-internal.h \ @@ -588,8 +582,8 @@ libevent.lo libevent.o: $(srcdir)/extension/libevent.c \ getdns/getdns_extra.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/getdns/getdns_ext_libevent.h libuv.lo libuv.o: $(srcdir)/extension/libuv.c \ - config.h \ - $(srcdir)/debug.h $(srcdir)/types-internal.h \ + config.h $(srcdir)/debug.h \ + $(srcdir)/types-internal.h \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/getdns/getdns_ext_libuv.h @@ -600,13 +594,11 @@ poll_eventloop.lo poll_eventloop.o: $(srcdir)/extension/poll_eventloop.c \ getdns/getdns_extra.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \ $(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \ - $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ - $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ - $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/platform.h + $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/tls.h $(srcdir)/$(tlsdir)/tls-internal.h $(srcdir)/platform.h $(srcdir)/debug.h select_eventloop.lo select_eventloop.o: $(srcdir)/extension/select_eventloop.c \ - config.h \ - $(srcdir)/debug.h $(srcdir)/types-internal.h \ + config.h $(srcdir)/debug.h \ + $(srcdir)/types-internal.h \ getdns/getdns.h \ getdns/getdns_extra.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/platform.h \ diff --git a/src/anchor.c b/src/anchor.c index cefa2477..1d685130 100644 --- a/src/anchor.c +++ b/src/anchor.c @@ -33,9 +33,6 @@ #include "debug.h" #include "anchor.h" #include -#include -#include -#include #include #include #include "types-internal.h" @@ -52,141 +49,6 @@ #include "util-internal.h" #include "platform.h" -/* get key usage out of its extension, returns 0 if no key_usage extension */ -static unsigned long -_getdns_get_usage_of_ex(X509* cert) -{ - unsigned long val = 0; - ASN1_BIT_STRING* s; - - if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) { - if(s->length > 0) { - val = s->data[0]; - if(s->length > 1) - val |= s->data[1] << 8; - } - ASN1_BIT_STRING_free(s); - } - return val; -} - -/** get valid signers from the list of signers in the signature */ -static STACK_OF(X509)* -_getdns_get_valid_signers(PKCS7* p7, const char* p7signer) -{ - int i; - STACK_OF(X509)* validsigners = sk_X509_new_null(); - STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0); - unsigned long usage = 0; - if(!validsigners) { - DEBUG_ANCHOR("ERROR %s(): Failed to allocated validsigners\n" - , __FUNC__); - sk_X509_free(signers); - return NULL; - } - if(!signers) { - DEBUG_ANCHOR("ERROR %s(): Failed to allocated signers\n" - , __FUNC__); - sk_X509_free(validsigners); - return NULL; - } - for(i=0; i= dstsize) + to_copy = dstsize -1; + memcpy(dst, src, to_copy); + dst[to_copy] = '\0'; +} + /** * XML convert DateTime element to time_t. * [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] @@ -213,7 +84,7 @@ typedef struct ta_iter { * @param str: the string * @return a time_t representation or 0 on failure. */ -static time_t +time_t _getdns_xml_convertdate(const char* str) { time_t t = 0; @@ -328,8 +199,8 @@ static ta_iter *ta_iter_next(ta_iter *ta) else if (level == 0 && cur) { /* content ready */ - (void) strncpy( ta->zone, value - , sizeof(ta->zone)); + strcpytrunc( ta->zone, value + , sizeof(ta->zone)); /* Reset to start of */ cur = NULL; @@ -504,20 +375,20 @@ static ta_iter *ta_iter_next(ta_iter *ta) DEBUG_ANCHOR("elem end: %s\n", value); switch (elem_type) { case KEYTAG: - (void) strncpy( ta->keytag, value - , sizeof(ta->keytag)); + strcpytrunc( ta->keytag, value + , sizeof(ta->keytag)); break; case ALGORITHM: - (void) strncpy( ta->algorithm, value - , sizeof(ta->algorithm)); + strcpytrunc( ta->algorithm, value + , sizeof(ta->algorithm)); break; case DIGESTTYPE: - (void) strncpy( ta->digesttype, value - , sizeof(ta->digesttype)); + strcpytrunc( ta->digesttype, value + , sizeof(ta->digesttype)); break; case DIGEST: - (void) strncpy( ta->digest, value - , sizeof(ta->digest)); + strcpytrunc( ta->digest, value + , sizeof(ta->digest)); break; } break; @@ -558,7 +429,7 @@ static ta_iter *ta_iter_init(ta_iter *ta, const char *doc, size_t doc_len) return ta_iter_next(ta); } -static uint16_t _getdns_parse_xml_trust_anchors_buf( +uint16_t _getdns_parse_xml_trust_anchors_buf( gldns_buffer *gbuf, uint64_t *now_ms, char *xml_data, size_t xml_len) { ta_iter ta_spc, *ta; @@ -647,226 +518,6 @@ static uint16_t _getdns_parse_xml_trust_anchors_buf( return ta_count; } -static uint8_t *tas_validate(struct mem_funcs *mf, - const getdns_bindata *xml_bd, const getdns_bindata *p7s_bd, - const getdns_bindata *crt_bd, const char *p7signer, - uint64_t *now_ms, uint8_t *tas, size_t *tas_len) -{ - BIO *xml = NULL, *p7s = NULL, *crt = NULL; - X509 *x = NULL; - X509_STORE *store = NULL; - uint8_t *success = NULL; - - if (!(xml = BIO_new_mem_buf(xml_bd->data, xml_bd->size))) - DEBUG_ANCHOR("ERROR %s(): Failed allocating xml BIO\n" - , __FUNC__); - - else if (!(p7s = BIO_new_mem_buf(p7s_bd->data, p7s_bd->size))) - DEBUG_ANCHOR("ERROR %s(): Failed allocating p7s BIO\n" - , __FUNC__); - - else if (!(crt = BIO_new_mem_buf(crt_bd->data, crt_bd->size))) - DEBUG_ANCHOR("ERROR %s(): Failed allocating crt BIO\n" - , __FUNC__); - - else if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL))) - DEBUG_ANCHOR("ERROR %s(): Parsing builtin certificate\n" - , __FUNC__); - - else if (!(store = X509_STORE_new())) - DEBUG_ANCHOR("ERROR %s(): Failed allocating store\n" - , __FUNC__); - - else if (!X509_STORE_add_cert(store, x)) - DEBUG_ANCHOR("ERROR %s(): Adding certificate to store\n" - , __FUNC__); - - else if (_getdns_verify_p7sig(xml, p7s, store, p7signer)) { - gldns_buffer gbuf; - - gldns_buffer_init_vfixed_frm_data(&gbuf, tas, *tas_len); - - if (!_getdns_parse_xml_trust_anchors_buf(&gbuf, now_ms, - (char *)xml_bd->data, xml_bd->size)) - DEBUG_ANCHOR("Failed to parse trust anchor XML data"); - - else if (gldns_buffer_position(&gbuf) > *tas_len) { - *tas_len = gldns_buffer_position(&gbuf); - if ((success = GETDNS_XMALLOC(*mf, uint8_t, *tas_len))) { - gldns_buffer_init_frm_data(&gbuf, success, *tas_len); - if (!_getdns_parse_xml_trust_anchors_buf(&gbuf, - now_ms, (char *)xml_bd->data, xml_bd->size)) { - - DEBUG_ANCHOR("Failed to re-parse trust" - " anchor XML data\n"); - GETDNS_FREE(*mf, success); - success = NULL; - } - } else - DEBUG_ANCHOR("Cannot allocate space for " - "trust anchors\n"); - } else { - success = tas; - *tas_len = gldns_buffer_position(&gbuf); - } - } else { - DEBUG_ANCHOR("Verifying trust-anchors failed!\n"); - } - if (store) X509_STORE_free(store); - if (x) X509_free(x); - if (crt) BIO_free(crt); - if (xml) BIO_free(xml); - if (p7s) BIO_free(p7s); - return success; -} - -void _getdns_context_equip_with_anchor( - getdns_context *context, uint64_t *now_ms) -{ - uint8_t xml_spc[4096], *xml_data = NULL; - uint8_t p7s_spc[4096], *p7s_data = NULL; - size_t xml_len, p7s_len; - const char *verify_email = NULL; - const char *verify_CA = NULL; - getdns_return_t r; - - BIO *xml = NULL, *p7s = NULL, *crt = NULL; - X509 *x = NULL; - X509_STORE *store = NULL; - - if ((r = getdns_context_get_trust_anchors_verify_CA( - context, &verify_CA))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Cannot get trust anchor verify CA: \"%s\"\n" - , getdns_get_errorstr_by_id(r)); - - else if (!verify_CA || !*verify_CA) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_INFO - , "Trust anchor verification explicitly " - "disabled by empty verify CA\n"); - - else if ((r = getdns_context_get_trust_anchors_verify_email( - context, &verify_email))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Cannot get trust anchor verify email address: " - "\"%s\"\n", getdns_get_errorstr_by_id(r)); - - else if (!verify_email || !*verify_email) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_INFO - , "Trust anchor verification explicitly " - "disabled by empty verify email\n"); - - else if (!(xml_data = _getdns_context_get_priv_file(context, - "root-anchors.xml", xml_spc, sizeof(xml_spc), &xml_len))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_DEBUG - , "root-anchors.xml not present\n"); - - else if (!(p7s_data = _getdns_context_get_priv_file(context, - "root-anchors.p7s", p7s_spc, sizeof(p7s_spc), &p7s_len))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_INFO - , "root-anchors.xml not present\n"); - - else if (!(xml = BIO_new_mem_buf(xml_data, xml_len))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Failed allocating xml BIO\n"); - - else if (!(p7s = BIO_new_mem_buf(p7s_data, p7s_len))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Failed allocating p7s BIO\n"); - - else if (!(crt = BIO_new_mem_buf((void *)verify_CA, -1))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Failed allocating crt BIO\n"); - - else if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL))) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Cannot parse builtin certificate\n"); - - else if (!(store = X509_STORE_new())) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Failed allocating X509 store\n"); - - else if (!X509_STORE_add_cert(store, x)) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Cannot add certificate to X509 store\n"); - - else if (_getdns_verify_p7sig(xml, p7s, store, verify_email)) { - uint8_t ta_spc[sizeof(context->trust_anchors_spc)]; - size_t ta_len; - uint8_t *ta = NULL; - gldns_buffer gbuf; - - gldns_buffer_init_vfixed_frm_data( - &gbuf, ta_spc, sizeof(ta_spc)); - - if (!_getdns_parse_xml_trust_anchors_buf(&gbuf, now_ms, - (char *)xml_data, xml_len)) - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Failed to parse trust anchor XML data\n"); - - else if ((ta_len = gldns_buffer_position(&gbuf)) > sizeof(ta_spc)) { - if ((ta = GETDNS_XMALLOC(context->mf, uint8_t, ta_len))) { - gldns_buffer_init_frm_data(&gbuf, ta, - gldns_buffer_position(&gbuf)); - if (!_getdns_parse_xml_trust_anchors_buf( - &gbuf, now_ms, (char *)xml_data, xml_len)) { - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR - , GETDNS_LOG_ERR - , "Error re-parsing trust " - "anchor XML data\n"); - GETDNS_FREE(context->mf, ta); - } else { - context->trust_anchors = ta; - context->trust_anchors_len = ta_len; - context->trust_anchors_source = GETDNS_TASRC_XML; - _getdns_ta_notify_dnsreqs(context); - } - } else - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR - , GETDNS_LOG_ERR - , "Cannot allocate space for " - "XML file"); - } else { - (void)memcpy(context->trust_anchors_spc, ta_spc, ta_len); - context->trust_anchors = context->trust_anchors_spc; - context->trust_anchors_len = ta_len; - context->trust_anchors_source = GETDNS_TASRC_XML; - _getdns_ta_notify_dnsreqs(context); - } - DEBUG_ANCHOR("ta: %p, ta_len: %d\n", - (void *)context->trust_anchors, (int)context->trust_anchors_len); - - } else { - _getdns_log( &context->log - , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR - , "Verifying trust-anchors XML failed!\n"); - } - if (store) X509_STORE_free(store); - if (x) X509_free(x); - if (crt) BIO_free(crt); - if (xml) BIO_free(xml); - if (p7s) BIO_free(p7s); - if (xml_data && xml_data != xml_spc) - GETDNS_FREE(context->mf, xml_data); - if (p7s_data && p7s_data != p7s_spc) - GETDNS_FREE(context->mf, p7s_data); -} - static const char tas_write_p7s_buf[] = "GET %s HTTP/1.1\r\n" "Host: %s\r\n" @@ -1067,7 +718,7 @@ static void tas_doc_read(getdns_context *context, tas_connection *a) , "Cannot get trust anchor verify email: " "\"%s\"\n", getdns_get_errorstr_by_id(r)); - else if (!(tas = tas_validate(&context->mf, &a->xml, &p7s_bd, + else if (!(tas = _getdns_tas_validate(&context->mf, &a->xml, &p7s_bd, &verify_CA, verify_email, &now_ms, tas, &tas_len))) ; /* pass */ diff --git a/src/anchor.h b/src/anchor.h index f8bff042..34a31cf8 100644 --- a/src/anchor.h +++ b/src/anchor.h @@ -39,6 +39,29 @@ #include #include "rr-iter.h" +#include "types-internal.h" + +/** + ** Internal functions, implemented in anchor-internal.c. + **/ +void _getdns_context_equip_with_anchor(getdns_context *context, uint64_t *now_ms); + +uint8_t *_getdns_tas_validate(struct mem_funcs *mf, + const getdns_bindata *xml_bd, const getdns_bindata *p7s_bd, + const getdns_bindata *crt_bd, const char *p7signer, + uint64_t *now_ms, uint8_t *tas, size_t *tas_len); + + +/** + ** anchor.c functions used by anchor-internal.c. + **/ +time_t _getdns_xml_convertdate(const char* str); + +uint16_t _getdns_parse_xml_trust_anchors_buf(gldns_buffer *gbuf, uint64_t *now_ms, char *xml_data, size_t xml_len); + +/** + ** Public interface. + **/ void _getdns_context_equip_with_anchor(getdns_context *context, uint64_t *now_ms); void _getdns_start_fetching_ta( diff --git a/src/context.c b/src/context.c index 825d6309..aa0478ff 100644 --- a/src/context.c +++ b/src/context.c @@ -47,20 +47,12 @@ #include typedef unsigned short in_port_t; -#include -#include -#include - #include #include #include #include #endif -#include -#include -#include - #include #include #include @@ -90,10 +82,8 @@ typedef unsigned short in_port_t; #include "list.h" #include "dict.h" #include "pubkey-pinning.h" -#ifdef USE_DANESSL -# include "ssl_dane/danessl.h" -#endif #include "const-info.h" +#include "tls.h" #define GETDNS_PORT_ZERO 0 #define GETDNS_PORT_DNS 53 @@ -182,124 +172,6 @@ _getdns_strdup2(const struct mem_funcs *mfs, const getdns_bindata *s) } } -#ifdef USE_WINSOCK -/* For windows, the CA trust store is not read by openssl. - Add code to open the trust store using wincrypt API and add - the root certs into openssl trust store */ -static int -add_WIN_cacerts_to_openssl_store(getdns_context *ctxt, SSL_CTX* tls_ctx) -{ - HCERTSTORE hSystemStore; - PCCERT_CONTEXT pTargetCert = NULL; - - _getdns_log(&ctxt->log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_DEBUG - , "%s: %s\n", STUB_DEBUG_SETUP_TLS, - , "Adding Windows certificates from system root store to CA store") - ; - - /* load just once per context lifetime for this version of getdns - TODO: dynamically update CA trust changes as they are available */ - assert(tls_ctx); - - /* Call wincrypt's CertOpenStore to open the CA root store. */ - - if ((hSystemStore = CertOpenStore( - CERT_STORE_PROV_SYSTEM, - 0, - 0, - /* NOTE: mingw does not have this const: replace with 1 << 16 from code - CERT_SYSTEM_STORE_CURRENT_USER, */ - 1 << 16, - L"root")) == 0) - { - _getdns_log(&ctxt->log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s\n", STUB_DEBUG_SETUP_TLS - , "Could not CertOpenStore()"); - return 0; - } - - X509_STORE* store = SSL_CTX_get_cert_store(tls_ctx); - if (!store) { - _getdns_log(&ctxt->log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s\n", STUB_DEBUG_SETUP_TLS - , "Could not SSL_CTX_get_cert_store()"); - return 0; - } - - /* failure if the CA store is empty or the call fails */ - if ((pTargetCert = CertEnumCertificatesInStore( - hSystemStore, pTargetCert)) == 0) { - _getdns_log(&ctxt->log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_NOTICE - , "%s: %s\n", STUB_DEBUG_SETUP_TLS - , "CA certificate store for Windows is empty."); - return 0; - } - /* iterate over the windows cert store and add to openssl store */ - do - { - X509 *cert1 = d2i_X509(NULL, - (const unsigned char **)&pTargetCert->pbCertEncoded, - pTargetCert->cbCertEncoded); - if (!cert1) { - /* return error if a cert fails */ - _getdns_log(&ctxt->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR, - , "%s: %s %d:%s\n" - , STUB_DEBUG_SETUP_TLS - , "Unable to parse certificate in memory" - , ERR_get_error() - , ERR_error_string(ERR_get_error(), NULL)); - return 0; - } - else { - /* return error if a cert add to store fails */ - if (X509_STORE_add_cert(store, cert1) == 0) { - unsigned long error = ERR_peek_last_error(); - - /* Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the - * certificate is already in the store. */ - if(ERR_GET_LIB(error) != ERR_LIB_X509 || - ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { - _getdns_log(&ctxt->log - , GETDNS_LOG_SYS_STUB - , GETDNS_LOG_ERR - , "%s: %s %d:%s\n" - , STUB_DEBUG_SETUP_TLS - , "Error adding certificate" - , ERR_get_error() - , ERR_error_string( ERR_get_error() - , NULL) - ); - X509_free(cert1); - return 0; - } - } - X509_free(cert1); - } - } while ((pTargetCert = CertEnumCertificatesInStore( - hSystemStore, pTargetCert)) != 0); - - /* Clean up memory and quit. */ - if (pTargetCert) - CertFreeCertificateContext(pTargetCert); - if (hSystemStore) - { - if (!CertCloseStore(hSystemStore, 0)) { - _getdns_log(&ctxt->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s\n", STUB_DEBUG_SETUP_TLS - , "Could not CertCloseStore()"); - return 0; - } - } - _getdns_log(&ctxt->log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_INFO - , "%s: %s\n", STUB_DEBUG_SETUP_TLS - , "Completed adding Windows certificates to CA store successfully") - ; - return 1; -} -#endif - static uint8_t* upstream_addr(getdns_upstream *upstream) { @@ -762,14 +634,11 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) } } if (upstream->tls_session != NULL) - SSL_SESSION_free(upstream->tls_session); + _getdns_tls_session_free(&upstreams->mf, upstream->tls_session); if (upstream->tls_obj != NULL) { - SSL_shutdown(upstream->tls_obj); -#ifdef USE_DANESSL - DANESSL_cleanup(upstream->tls_obj); -#endif - SSL_free(upstream->tls_obj); + _getdns_tls_connection_shutdown(upstream->tls_obj); + _getdns_tls_connection_free(&upstreams->mf, upstream->tls_obj); } if (upstream->fd != -1) { @@ -867,11 +736,8 @@ _getdns_upstream_reset(getdns_upstream *upstream) upstream->loop, &upstream->event); } if (upstream->tls_obj != NULL) { - SSL_shutdown(upstream->tls_obj); -#ifdef USE_DANESSL - DANESSL_cleanup(upstream->tls_obj); -#endif - SSL_free(upstream->tls_obj); + _getdns_tls_connection_shutdown(upstream->tls_obj); + _getdns_tls_connection_free(&upstream->upstreams->mf, upstream->tls_obj); upstream->tls_obj = NULL; } if (upstream->fd != -1) { @@ -1468,17 +1334,6 @@ static char const * const _getdns_default_trust_anchors_verify_CA = static char const * const _getdns_default_trust_anchors_verify_email = "dnssec@iana.org"; - -static char const * const _getdns_default_tls_cipher_list = -#ifndef HAVE_SSL_CTX_SET_CIPHERSUITES - "TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:" - "TLS13-CHACHA20-POLY1305-SHA256:" -#endif - "EECDH+AESGCM:EECDH+CHACHA20"; - -static char const * const _getdns_default_tls_ciphersuites = - "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"; - /* * getdns_context_create * @@ -1692,18 +1547,7 @@ getdns_context_create_with_extended_memory_functions( #endif /* Only initialise SSL once and ideally in a thread-safe manner */ if (ssl_init == false) { -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) - OpenSSL_add_all_algorithms(); - SSL_library_init(); -# ifdef USE_DANESSL - (void) DANESSL_library_init(); -# endif -#else - OPENSSL_init_crypto( OPENSSL_INIT_ADD_ALL_CIPHERS - | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); - (void)OPENSSL_init_ssl(0, NULL); -#endif + _getdns_tls_init(); ssl_init = true; } #ifdef HAVE_PTHREAD @@ -1829,7 +1673,7 @@ getdns_context_destroy(struct getdns_context *context) GETDNS_FREE(context->my_mf, context->dns_transports); if (context->tls_ctx) - SSL_CTX_free(context->tls_ctx); + _getdns_tls_context_free(&context->my_mf, context->tls_ctx); getdns_list_destroy(context->dns_root_servers); @@ -3718,8 +3562,6 @@ getdns_return_t _getdns_context_prepare_for_resolution(getdns_context *context) { getdns_return_t r; - char ssl_err[256]; - int osr; assert(context); if (context->destroying) @@ -3741,256 +3583,63 @@ _getdns_context_prepare_for_resolution(getdns_context *context) } if (context->tls_ctx == NULL) { -#ifdef HAVE_TLS_v1_2 - /* Create client context, use TLS v1.2 only for now */ -# ifdef HAVE_TLS_CLIENT_METHOD - context->tls_ctx = SSL_CTX_new(TLS_client_method()); -# else - context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); -# endif - if(context->tls_ctx == NULL) { - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Error creating TLS context" - , ssl_err); + context->tls_ctx = _getdns_tls_context_new(&context->my_mf, &context->log); + if (context->tls_ctx == NULL) return GETDNS_RETURN_BAD_CONTEXT; - } -# if defined(HAVE_DECL_SSL_SET_MIN_PROTO_VERSION) \ - && HAVE_DECL_SSL_SET_MIN_PROTO_VERSION - if (!SSL_CTX_set_min_proto_version(context->tls_ctx, - _getdns_tls_version2openssl_version( - context->tls_min_version))) { - SSL_CTX_free(context->tls_ctx); + r = _getdns_tls_context_set_min_max_tls_version(context->tls_ctx, context->tls_min_version, context->tls_max_version); + if (r) { + _getdns_tls_context_free(&context->my_mf, context->tls_ctx); context->tls_ctx = NULL; - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Error configuring TLS context with " - "minimum TLS version" - , ssl_err); - return GETDNS_RETURN_BAD_CONTEXT; + return r; } - if (context->tls_max_version - && !SSL_CTX_set_max_proto_version(context->tls_ctx, - _getdns_tls_version2openssl_version( - context->tls_max_version))) { - SSL_CTX_free(context->tls_ctx); + + /* Be strict and only use the cipher suites recommended in RFC7525 + Unless we later fallback to opportunistic. */ + r = _getdns_tls_context_set_cipher_list(context->tls_ctx, context->tls_cipher_list); + if (!r) + r = _getdns_tls_context_set_cipher_suites(context->tls_ctx, context->tls_ciphersuites); + if (!r && context->tls_curves_list) + r = _getdns_tls_context_set_curves_list(context->tls_ctx, context->tls_curves_list); + if (r) { + _getdns_tls_context_free(&context->my_mf, context->tls_ctx); context->tls_ctx = NULL; - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Error configuring TLS context with " - "maximum TLS version" - , ssl_err); - - return GETDNS_RETURN_BAD_CONTEXT; - } -# else -# ifndef HAVE_TLS_CLIENT_METHOD - if (( context->tls_min_version - && context->tls_min_version != GETDNS_TLS1_2) - || context->tls_max_version) { - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s\n" - , STUB_DEBUG_SETUP_TLS - , "This version of OpenSSL does not " - "support setting of mimum or maximum " - "TLS versions"); - return GETDNS_RETURN_NOT_IMPLEMENTED; - } -# endif -# endif - /* Be strict and only use the cipher suites recommended - * in RFC7525 Unless we later fallback to opportunistic. - */ - if (!SSL_CTX_set_cipher_list(context->tls_ctx, - context->tls_cipher_list - ? context->tls_cipher_list - : _getdns_default_tls_cipher_list)) { - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Error configuring TLS context with " - "cipher list" - , ssl_err); - - return GETDNS_RETURN_BAD_CONTEXT; - } -# ifdef HAVE_SSL_CTX_SET_CIPHERSUITES - if (!SSL_CTX_set_ciphersuites(context->tls_ctx, - context->tls_ciphersuites - ? context->tls_ciphersuites - : _getdns_default_tls_ciphersuites)) { - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Error configuring TLS context with " - "cipher suites" - , ssl_err); - - return GETDNS_RETURN_BAD_CONTEXT; - } -# else - if (context->tls_ciphersuites) { - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s\n" - , STUB_DEBUG_SETUP_TLS - , "This version of OpenSSL does not " - "support configuring cipher suites"); - return GETDNS_RETURN_NOT_IMPLEMENTED; - } -# endif -# if defined(HAVE_DECL_SSL_CTX_SET1_CURVES_LIST) \ - && HAVE_DECL_SSL_CTX_SET1_CURVES_LIST - if (context->tls_curves_list && - !SSL_CTX_set1_curves_list(context->tls_ctx, - context->tls_curves_list)) { - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Error configuring TLS context with " - "curves list" - , ssl_err); - return GETDNS_RETURN_BAD_CONTEXT; - } -# else - if (context->tls_curves_list) { - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s\n" - , STUB_DEBUG_SETUP_TLS - , "This version of OpenSSL does not " - "support configuring curves list"); - return GETDNS_RETURN_NOT_IMPLEMENTED; - } -# endif - /* For strict authentication, we must have local root - * certs available. Set up is done only when the tls_ctx - * is created (per getdns_context) - */ - osr = 0; - if (context->tls_ca_file || context->tls_ca_path) { - osr = SSL_CTX_load_verify_locations( - context->tls_ctx - , context->tls_ca_file - , context->tls_ca_path ); - if (!osr) { - ERR_error_string_n( ERR_get_error() - , ssl_err - , sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB - , GETDNS_LOG_WARNING - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Could not load verify locations" - , ssl_err); - } else { + return r; + } + + /* For strict authentication, we must have local root certs available + Set up is done only when the tls_ctx is created (per getdns_context)*/ + if (_getdns_tls_context_set_ca(context->tls_ctx, context->tls_ca_file, context->tls_ca_path)) { + if (context->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { _getdns_log(&context->log , GETDNS_LOG_SYS_STUB , GETDNS_LOG_DEBUG , "%s: %s\n" , STUB_DEBUG_SETUP_TLS - , "Verify locations loaded"); + , "Authentication is needed but no " + "verify location could be loaded"); + _getdns_tls_context_free(&context->my_mf, context->tls_ctx); + context->tls_ctx = NULL; + return GETDNS_RETURN_BAD_CONTEXT; } } - if (osr) - ; /* verify locations loaded: pass */ -# ifndef USE_WINSOCK - else if (!SSL_CTX_set_default_verify_paths( - context->tls_ctx) && -# else - else if (!add_WIN_cacerts_to_openssl_store( - context, context->tls_ctx) && -# endif /* USE_WINSOCK */ - context->tls_auth_min - == GETDNS_AUTHENTICATION_REQUIRED) { - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB - , GETDNS_LOG_ERR - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Authentication is needed but no default " - "verify location could be loaded" - , ssl_err); - return GETDNS_RETURN_BAD_CONTEXT; - } - -# if defined(HAVE_SSL_CTX_DANE_ENABLE) - if (!SSL_CTX_dane_enable(context->tls_ctx)) { - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_WARNING - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Could not enable DANE on TLX context" - , ssl_err); - } -# elif defined(USE_DANESSL) - if (!DANESSL_CTX_init(context->tls_ctx)) { - ERR_error_string_n( ERR_get_error() - , ssl_err, sizeof(ssl_err)); - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_WARNING - , "%s: %s (%s)\n" - , STUB_DEBUG_SETUP_TLS - , "Could not enable DANE on TLX context" - , ssl_err); - } -# endif -#else /* HAVE_TLS_v1_2 */ - if (tls_only_is_in_transports_list(context) == 1) { - _getdns_log(&context->log - , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR - , "%s: %s\n" - , STUB_DEBUG_SETUP_TLS - , "This version of OpenSSL does not " - "support authenticated TLS"); - return GETDNS_RETURN_NOT_IMPLEMENTED; - } - /* A null tls_ctx will make TLS fail and fallback to - * the other transports will kick-in. - */ -#endif /* HAVE_TLS_v1_2 */ + _getdns_tls_context_pinset_init(context->tls_ctx); } } /* Block use of TLS ONLY in recursive mode as it won't work */ /* Note: If TLS is used in recursive mode this will try TLS on port * 53 so it is blocked here. */ - if (context->resolution_type == GETDNS_RESOLUTION_RECURSING - && tls_only_is_in_transports_list(context) == 1) { + if (context->resolution_type == GETDNS_RESOLUTION_RECURSING && + tls_only_is_in_transports_list(context) == 1) { _getdns_log(&context->log , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR , "%s: %s\n" , STUB_DEBUG_SETUP_TLS , "TLS only transport is not supported for the recursing " "resolution type"); + _getdns_tls_context_free(&context->my_mf, context->tls_ctx); + context->tls_ctx = NULL; return GETDNS_RETURN_NOT_IMPLEMENTED; } if (context->resolution_type_set == context->resolution_type) @@ -4397,32 +4046,7 @@ getdns_context_get_api_information(const getdns_context* context) && ! getdns_dict_util_set_string( result, "default_hosts_location", GETDNS_FN_HOSTS) - && ! getdns_dict_set_int( - result, "openssl_build_version_number", OPENSSL_VERSION_NUMBER) - -#ifdef HAVE_OPENSSL_VERSION_NUM - && ! getdns_dict_set_int( - result, "openssl_version_number", OpenSSL_version_num()) -#endif -#ifdef HAVE_OPENSSL_VERSION - && ! getdns_dict_util_set_string( - result, "openssl_version_string", OpenSSL_version(OPENSSL_VERSION)) - - && ! getdns_dict_util_set_string( - result, "openssl_cflags", OpenSSL_version(OPENSSL_CFLAGS)) - - && ! getdns_dict_util_set_string( - result, "openssl_built_on", OpenSSL_version(OPENSSL_BUILT_ON)) - - && ! getdns_dict_util_set_string( - result, "openssl_platform", OpenSSL_version(OPENSSL_PLATFORM)) - - && ! getdns_dict_util_set_string( - result, "openssl_dir", OpenSSL_version(OPENSSL_DIR)) - - && ! getdns_dict_util_set_string( - result, "openssl_engines_dir", OpenSSL_version(OPENSSL_ENGINES_DIR)) -#endif + && ! _getdns_tls_get_api_information(result) && ! getdns_dict_set_int( result, "resolution_type", context->resolution_type) @@ -5658,7 +5282,7 @@ getdns_context_get_tls_cipher_list( *tls_cipher_list = context->tls_cipher_list ? context->tls_cipher_list - : _getdns_default_tls_cipher_list; + : _getdns_tls_context_get_default_cipher_list(); return GETDNS_RETURN_GOOD; } @@ -5687,7 +5311,7 @@ getdns_context_get_tls_ciphersuites( *tls_ciphersuites = context->tls_ciphersuites ? context->tls_ciphersuites - : _getdns_default_tls_ciphersuites; + : _getdns_tls_context_get_default_cipher_suites(); return GETDNS_RETURN_GOOD; } @@ -5697,7 +5321,7 @@ getdns_context_set_tls_curves_list( { if (!context) return GETDNS_RETURN_INVALID_PARAMETER; -#if defined(HAVE_DECL_SSL_CTX_SET1_CURVES_LIST) && HAVE_DECL_SSL_CTX_SET1_CURVES_LIST +#if HAVE_TLS_CTX_CURVES_LIST if (context->tls_curves_list) GETDNS_FREE(context->mf, context->tls_curves_list); context->tls_curves_list = tls_curves_list diff --git a/src/context.h b/src/context.h index 72b9d9d2..10031014 100644 --- a/src/context.h +++ b/src/context.h @@ -50,6 +50,7 @@ #endif #include "rr-iter.h" #include "anchor.h" +#include "tls.h" struct getdns_dns_req; struct ub_ctx; @@ -200,9 +201,9 @@ typedef struct getdns_upstream { getdns_network_req *write_queue_last; _getdns_rbtree_t netreq_by_query_id; - /* TLS specific connection handling */ - SSL* tls_obj; - SSL_SESSION* tls_session; + /* TLS specific connection handling*/ + _getdns_tls_connection* tls_obj; + _getdns_tls_session* tls_session; getdns_tls_hs_state_t tls_hs_state; getdns_auth_state_t tls_auth_state; unsigned tls_fallback_ok : 1; @@ -382,7 +383,7 @@ struct getdns_context { int edns_maximum_udp_payload_size; /* -1 is unset */ uint8_t edns_client_subnet_private; uint16_t tls_query_padding_blocksize; - SSL_CTX* tls_ctx; + _getdns_tls_context* tls_ctx; getdns_update_callback update_callback; getdns_update_callback2 update_callback2; diff --git a/src/dnssec.c b/src/dnssec.c index d4f6aff3..2be6096e 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -194,7 +194,6 @@ #include #include #include -#include #include "getdns/getdns.h" #include "context.h" #include "util-internal.h" @@ -210,6 +209,7 @@ #include "list.h" #include "util/val_secalgo.h" #include "anchor.h" +#include "tls.h" #define SIGNATURE_VERIFIED 0x10000 #define NSEC3_ITERATION_COUNT_HIGH 0x20000 @@ -1584,12 +1584,12 @@ static uint8_t *_getdns_nsec3_hash_label(uint8_t *label, size_t label_len, (void)memcpy(dst, salt + 1, *salt); dst += *salt; - (void)SHA1(buf, dst - buf, md); + _getdns_tls_sha1(buf, dst - buf, md); if (iterations) { (void)memcpy(buf + SHA_DIGEST_LENGTH, salt + 1, *salt); while (iterations--) { (void)memcpy(buf, md, SHA_DIGEST_LENGTH); - SHA1(buf, SHA_DIGEST_LENGTH + *salt, md); + _getdns_tls_sha1(buf, SHA_DIGEST_LENGTH + *salt, md); } } *label = gldns_b32_ntop_extended_hex( diff --git a/src/general.c b/src/general.c index cb923187..43cc7bd0 100644 --- a/src/general.c +++ b/src/general.c @@ -252,9 +252,17 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req) #ifdef HAVE_LIBUNBOUND #ifdef HAVE_UNBOUND_EVENT_API static void +#if UNBOUND_VERSION_MAJOR > 1 || (UNBOUND_VERSION_MAJOR == 1 && UNBOUND_VERSION_MINOR >= 8) +ub_resolve_event_callback(void* arg, int rcode, void *pkt, int pkt_len, + int sec, char* why_bogus, int was_ratelimited) +{ + (void) was_ratelimited; +#else +static void ub_resolve_event_callback(void* arg, int rcode, void *pkt, int pkt_len, int sec, char* why_bogus) { +#endif getdns_network_req *netreq = (getdns_network_req *) arg; getdns_dns_req *dns_req = netreq->owner; diff --git a/src/gldns/keyraw.c b/src/gldns/keyraw.c index 7fa5bc10..e59189e0 100644 --- a/src/gldns/keyraw.c +++ b/src/gldns/keyraw.c @@ -14,29 +14,6 @@ #include "gldns/keyraw.h" #include "gldns/rrdef.h" -#ifdef HAVE_SSL -#include -#include -#include -#include -#include -#ifdef HAVE_OPENSSL_CONF_H -# include -#endif -#ifdef HAVE_OPENSSL_ENGINE_H -# include -#endif -#ifdef HAVE_OPENSSL_BN_H -#include -#endif -#ifdef HAVE_OPENSSL_RSA_H -#include -#endif -#ifdef HAVE_OPENSSL_DSA_H -#include -#endif -#endif /* HAVE_SSL */ - size_t gldns_rr_dnskey_key_size_raw(const unsigned char* keydata, const size_t len, int alg) @@ -129,344 +106,3 @@ uint16_t gldns_calc_keytag_raw(const uint8_t* key, size_t keysize) return (uint16_t) (ac32 & 0xFFFF); } } - -#ifdef HAVE_SSL -#ifdef USE_GOST -/** store GOST engine reference loaded into OpenSSL library */ -#ifdef OPENSSL_NO_ENGINE -int -gldns_key_EVP_load_gost_id(void) -{ - return 0; -} -void gldns_key_EVP_unload_gost(void) -{ -} -#else -ENGINE* gldns_gost_engine = NULL; - -int -gldns_key_EVP_load_gost_id(void) -{ - static int gost_id = 0; - const EVP_PKEY_ASN1_METHOD* meth; - ENGINE* e; - - if(gost_id) return gost_id; - - /* see if configuration loaded gost implementation from other engine*/ - meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1); - if(meth) { - EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); - return gost_id; - } - - /* see if engine can be loaded already */ - e = ENGINE_by_id("gost"); - if(!e) { - /* load it ourself, in case statically linked */ - ENGINE_load_builtin_engines(); - ENGINE_load_dynamic(); - e = ENGINE_by_id("gost"); - } - if(!e) { - /* no gost engine in openssl */ - return 0; - } - if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { - ENGINE_finish(e); - ENGINE_free(e); - return 0; - } - - meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1); - if(!meth) { - /* algo not found */ - ENGINE_finish(e); - ENGINE_free(e); - return 0; - } - /* Note: do not ENGINE_finish and ENGINE_free the acquired engine - * on some platforms this frees up the meth and unloads gost stuff */ - gldns_gost_engine = e; - - EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); - return gost_id; -} - -void gldns_key_EVP_unload_gost(void) -{ - if(gldns_gost_engine) { - ENGINE_finish(gldns_gost_engine); - ENGINE_free(gldns_gost_engine); - gldns_gost_engine = NULL; - } -} -#endif /* ifndef OPENSSL_NO_ENGINE */ -#endif /* USE_GOST */ - -DSA * -gldns_key_buf2dsa_raw(unsigned char* key, size_t len) -{ - uint8_t T; - uint16_t length; - uint16_t offset; - DSA *dsa; - BIGNUM *Q; BIGNUM *P; - BIGNUM *G; BIGNUM *Y; - - if(len == 0) - return NULL; - T = (uint8_t)key[0]; - length = (64 + T * 8); - offset = 1; - - if (T > 8) { - return NULL; - } - if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length) - return NULL; - - Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL); - offset += SHA_DIGEST_LENGTH; - - P = BN_bin2bn(key+offset, (int)length, NULL); - offset += length; - - G = BN_bin2bn(key+offset, (int)length, NULL); - offset += length; - - Y = BN_bin2bn(key+offset, (int)length, NULL); - - /* create the key and set its properties */ - if(!Q || !P || !G || !Y || !(dsa = DSA_new())) { - BN_free(Q); - BN_free(P); - BN_free(G); - BN_free(Y); - return NULL; - } -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) -#ifndef S_SPLINT_S - dsa->p = P; - dsa->q = Q; - dsa->g = G; - dsa->pub_key = Y; -#endif /* splint */ - -#else /* OPENSSL_VERSION_NUMBER */ - if (!DSA_set0_pqg(dsa, P, Q, G)) { - /* QPG not yet attached, need to free */ - BN_free(Q); - BN_free(P); - BN_free(G); - - DSA_free(dsa); - BN_free(Y); - return NULL; - } - if (!DSA_set0_key(dsa, Y, NULL)) { - /* QPG attached, cleaned up by DSA_fre() */ - DSA_free(dsa); - BN_free(Y); - return NULL; - } -#endif - - return dsa; -} - -RSA * -gldns_key_buf2rsa_raw(unsigned char* key, size_t len) -{ - uint16_t offset; - uint16_t exp; - uint16_t int16; - RSA *rsa; - BIGNUM *modulus; - BIGNUM *exponent; - - if (len == 0) - return NULL; - if (key[0] == 0) { - if(len < 3) - return NULL; - memmove(&int16, key+1, 2); - exp = ntohs(int16); - offset = 3; - } else { - exp = key[0]; - offset = 1; - } - - /* key length at least one */ - if(len < (size_t)offset + exp + 1) - return NULL; - - /* Exponent */ - exponent = BN_new(); - if(!exponent) return NULL; - (void) BN_bin2bn(key+offset, (int)exp, exponent); - offset += exp; - - /* Modulus */ - modulus = BN_new(); - if(!modulus) { - BN_free(exponent); - return NULL; - } - /* length of the buffer must match the key length! */ - (void) BN_bin2bn(key+offset, (int)(len - offset), modulus); - - rsa = RSA_new(); - if(!rsa) { - BN_free(exponent); - BN_free(modulus); - return NULL; - } -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) -#ifndef S_SPLINT_S - rsa->n = modulus; - rsa->e = exponent; -#endif /* splint */ - -#else /* OPENSSL_VERSION_NUMBER */ - if (!RSA_set0_key(rsa, modulus, exponent, NULL)) { - BN_free(exponent); - BN_free(modulus); - RSA_free(rsa); - return NULL; - } -#endif - - return rsa; -} - -#ifdef USE_GOST -EVP_PKEY* -gldns_gost2pkey_raw(unsigned char* key, size_t keylen) -{ - /* prefix header for X509 encoding */ - uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, - 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, - 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, - 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40}; - unsigned char encoded[37+64]; - const unsigned char* pp; - if(keylen != 64) { - /* key wrong size */ - return NULL; - } - - /* create evp_key */ - memmove(encoded, asn, 37); - memmove(encoded+37, key, 64); - pp = (unsigned char*)&encoded[0]; - - return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded)); -} -#endif /* USE_GOST */ - -#ifdef USE_ECDSA -EVP_PKEY* -gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo) -{ - unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */ - const unsigned char* pp = buf; - EVP_PKEY *evp_key; - EC_KEY *ec; - /* check length, which uncompressed must be 2 bignums */ - if(algo == GLDNS_ECDSAP256SHA256) { - if(keylen != 2*256/8) return NULL; - ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - } else if(algo == GLDNS_ECDSAP384SHA384) { - if(keylen != 2*384/8) return NULL; - ec = EC_KEY_new_by_curve_name(NID_secp384r1); - } else ec = NULL; - if(!ec) return NULL; - if(keylen+1 > sizeof(buf)) { /* sanity check */ - EC_KEY_free(ec); - return NULL; - } - /* prepend the 0x02 (from docs) (or actually 0x04 from implementation - * of openssl) for uncompressed data */ - buf[0] = POINT_CONVERSION_UNCOMPRESSED; - memmove(buf+1, key, keylen); - if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) { - EC_KEY_free(ec); - return NULL; - } - evp_key = EVP_PKEY_new(); - if(!evp_key) { - EC_KEY_free(ec); - return NULL; - } - if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) { - EVP_PKEY_free(evp_key); - EC_KEY_free(ec); - return NULL; - } - return evp_key; -} -#endif /* USE_ECDSA */ - -#ifdef USE_ED25519 -EVP_PKEY* -gldns_ed255192pkey_raw(const unsigned char* key, size_t keylen) -{ - /* ASN1 for ED25519 is 302a300506032b6570032100 <32byteskey> */ - uint8_t pre[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, - 0x70, 0x03, 0x21, 0x00}; - int pre_len = 12; - uint8_t buf[256]; - EVP_PKEY *evp_key; - /* pp gets modified by d2i() */ - const unsigned char* pp = (unsigned char*)buf; - if(keylen != 32 || keylen + pre_len > sizeof(buf)) - return NULL; /* wrong length */ - memmove(buf, pre, pre_len); - memmove(buf+pre_len, key, keylen); - evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); - return evp_key; -} -#endif /* USE_ED25519 */ - -#ifdef USE_ED448 -EVP_PKEY* -gldns_ed4482pkey_raw(const unsigned char* key, size_t keylen) -{ - /* ASN1 for ED448 is 3043300506032b6571033a00 <57byteskey> */ - uint8_t pre[] = {0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, - 0x71, 0x03, 0x3a, 0x00}; - int pre_len = 12; - uint8_t buf[256]; - EVP_PKEY *evp_key; - /* pp gets modified by d2i() */ - const unsigned char* pp = (unsigned char*)buf; - if(keylen != 57 || keylen + pre_len > sizeof(buf)) - return NULL; /* wrong length */ - memmove(buf, pre, pre_len); - memmove(buf+pre_len, key, keylen); - evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); - return evp_key; -} -#endif /* USE_ED448 */ - -int -gldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest, - const EVP_MD* md) -{ - EVP_MD_CTX* ctx; - ctx = EVP_MD_CTX_create(); - if(!ctx) - return 0; - if(!EVP_DigestInit_ex(ctx, md, NULL) || - !EVP_DigestUpdate(ctx, data, len) || - !EVP_DigestFinal_ex(ctx, dest, NULL)) { - EVP_MD_CTX_destroy(ctx); - return 0; - } - EVP_MD_CTX_destroy(ctx); - return 1; -} -#endif /* HAVE_SSL */ diff --git a/src/gldns/keyraw.h b/src/gldns/keyraw.h index a847887c..caefad01 100644 --- a/src/gldns/keyraw.h +++ b/src/gldns/keyraw.h @@ -20,13 +20,11 @@ #ifndef GLDNS_KEYRAW_H #define GLDNS_KEYRAW_H +#include "keyraw-internal.h" + #ifdef __cplusplus extern "C" { #endif -#if GLDNS_BUILD_CONFIG_HAVE_SSL -# include -# include -#endif /* GLDNS_BUILD_CONFIG_HAVE_SSL */ /** * get the length of the keydata in bits @@ -46,83 +44,6 @@ size_t gldns_rr_dnskey_key_size_raw(const unsigned char *keydata, */ uint16_t gldns_calc_keytag_raw(const uint8_t* key, size_t keysize); -#if GLDNS_BUILD_CONFIG_HAVE_SSL -/** - * Get the PKEY id for GOST, loads GOST into openssl as a side effect. - * Only available if GOST is compiled into the library and openssl. - * \return the gost id for EVP_CTX creation. - */ -int gldns_key_EVP_load_gost_id(void); - -/** Release the engine reference held for the GOST engine. */ -void gldns_key_EVP_unload_gost(void); - -/** - * Like gldns_key_buf2dsa, but uses raw buffer. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return a DSA * structure with the key material - */ -DSA *gldns_key_buf2dsa_raw(unsigned char* key, size_t len); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with GOST. - * \param[in] key data to convert - * \param[in] keylen length of the key data - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_gost2pkey_raw(unsigned char* key, size_t keylen); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with ECDSA. - * \param[in] key data to convert - * \param[in] keylen length of the key data - * \param[in] algo precise algorithm to initialize ECC group values. - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo); - -/** - * Like gldns_key_buf2rsa, but uses raw buffer. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return a RSA * structure with the key material - */ -RSA *gldns_key_buf2rsa_raw(unsigned char* key, size_t len); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with ED25519. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_ed255192pkey_raw(const unsigned char* key, size_t len); - -/** - * Converts a holding buffer with key material to EVP PKEY in openssl. - * Only available if ldns was compiled with ED448. - * \param[in] key the uncompressed wireformat of the key. - * \param[in] len length of key data - * \return the key or NULL on error. - */ -EVP_PKEY* gldns_ed4482pkey_raw(const unsigned char* key, size_t len); - -/** - * Utility function to calculate hash using generic EVP_MD pointer. - * \param[in] data the data to hash. - * \param[in] len length of data. - * \param[out] dest the destination of the hash, must be large enough. - * \param[in] md the message digest to use. - * \return true if worked, false on failure. - */ -int gldns_digest_evp(unsigned char* data, unsigned int len, - unsigned char* dest, const EVP_MD* md); - -#endif /* GLDNS_BUILD_CONFIG_HAVE_SSL */ - #ifdef __cplusplus } #endif diff --git a/src/gnutls/anchor-internal.c b/src/gnutls/anchor-internal.c new file mode 100644 index 00000000..45b58d52 --- /dev/null +++ b/src/gnutls/anchor-internal.c @@ -0,0 +1,48 @@ +/** + * + * /brief functions for DNSSEC trust anchor management + * + */ + +/* + * Copyright (c) 2017, NLnet Labs + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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 "config.h" +#include "anchor.h" + +void _getdns_context_equip_with_anchor( + getdns_context *context, uint64_t *now_ms) +{ +} + +uint8_t *_getdns_tas_validate(struct mem_funcs *mf, + const getdns_bindata *xml_bd, const getdns_bindata *p7s_bd, + const getdns_bindata *crt_bd, const char *p7signer, + uint64_t *now_ms, uint8_t *tas, size_t *tas_len) +{ + return NULL; +} diff --git a/src/gnutls/keyraw-internal.c b/src/gnutls/keyraw-internal.c new file mode 100644 index 00000000..a674033f --- /dev/null +++ b/src/gnutls/keyraw-internal.c @@ -0,0 +1,15 @@ +/* + * keyraw.c - raw key operations and conversions - OpenSSL version + * + * (c) NLnet Labs, 2004-2008 + * + * See the file LICENSE for the license + */ +/** + * \file + * Implementation of raw DNSKEY functions (work on wire rdata). + */ + +#include "config.h" +#include "gldns/keyraw.h" +#include "gldns/rrdef.h" diff --git a/src/gnutls/keyraw-internal.h b/src/gnutls/keyraw-internal.h new file mode 100644 index 00000000..eaac30c3 --- /dev/null +++ b/src/gnutls/keyraw-internal.h @@ -0,0 +1,31 @@ +/* + * keyraw.h -- raw key and signature access and conversion - OpenSSL + * + * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + * + */ + +/** + * \file + * + * raw key and signature access and conversion + * + * Since those functions heavily rely op cryptographic operations, + * this module is dependent on openssl. + * + */ + +#ifndef GLDNS_KEYRAW_INTERNAL_H +#define GLDNS_KEYRAW_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* GLDNS_KEYRAW_INTERNAL_H */ diff --git a/src/gnutls/pubkey-pinning-internal.c b/src/gnutls/pubkey-pinning-internal.c new file mode 100644 index 00000000..41033bf3 --- /dev/null +++ b/src/gnutls/pubkey-pinning-internal.c @@ -0,0 +1,59 @@ +/** + * + * /brief functions for dealing with pubkey pinsets + * + */ + +/* + * Copyright (c) 2015 ACLU + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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 "context.h" +#include + +#include "types-internal.h" + +#include "pubkey-pinning.h" + +/** + ** Interfaces from pubkey-pinning.h + **/ + +getdns_return_t _getdns_decode_base64(const char* str, uint8_t* res, size_t res_size) +{ + struct base64_decode_ctx ctx; + uint8_t* lim = res + res_size; + + base64_decode_init(&ctx); + + for(; *str != '\0' && res < lim; ++str) { + int r = base64_decode_single(&ctx, res, *str); + if (r == -1 ) + return GETDNS_RETURN_GENERIC_ERROR; + res += r; + } + return (res == lim) ? GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR; +} diff --git a/src/gnutls/pubkey-pinning-internal.h b/src/gnutls/pubkey-pinning-internal.h new file mode 100644 index 00000000..e69de29b diff --git a/src/gnutls/tls-internal.h b/src/gnutls/tls-internal.h new file mode 100644 index 00000000..4f7f24f8 --- /dev/null +++ b/src/gnutls/tls-internal.h @@ -0,0 +1,102 @@ +/** + * + * \file tls-internal.h + * @brief getdns TLS implementation-specific items + */ + +/* + * Copyright (c) 2018-2019, NLnet Labs + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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. + */ + +#ifndef _GETDNS_TLS_INTERNAL_H +#define _GETDNS_TLS_INTERNAL_H + +#include + +#include +#include +#include + +#include "getdns/getdns.h" + +#define SHA_DIGEST_LENGTH 20 +#define SHA224_DIGEST_LENGTH 28 +#define SHA256_DIGEST_LENGTH 32 +#define SHA384_DIGEST_LENGTH 48 +#define SHA512_DIGEST_LENGTH 64 + +#define GETDNS_TLS_MAX_DIGEST_LENGTH (SHA512_DIGEST_LENGTH) + +#define HAVE_TLS_CTX_CURVES_LIST 0 +#define HAVE_TLS_CONN_CURVES_LIST 0 + +typedef struct getdns_log_config getdns_log_config; + +typedef struct _getdns_tls_context { + struct mem_funcs* mfs; + char* cipher_list; + char* cipher_suites; + char* curve_list; + gnutls_protocol_t min_tls; + gnutls_protocol_t max_tls; + char* ca_trust_file; + char* ca_trust_path; + const getdns_log_config* log; +} _getdns_tls_context; + +typedef struct _getdns_tls_connection { + gnutls_session_t tls; + gnutls_certificate_credentials_t cred; + int shutdown; + _getdns_tls_context* ctx; + struct mem_funcs* mfs; + char* cipher_list; + char* cipher_suites; + char* curve_list; + gnutls_protocol_t min_tls; + gnutls_protocol_t max_tls; + dane_query_t dane_query; + dane_state_t dane_state; + char* tlsa; + const getdns_log_config* log; +} _getdns_tls_connection; + +typedef struct _getdns_tls_session { + gnutls_datum_t tls; +} _getdns_tls_session; + +typedef struct _getdns_tls_x509 +{ + gnutls_datum_t tls; +} _getdns_tls_x509; + +typedef struct _getdns_tls_hmac +{ + gnutls_hmac_hd_t tls; + unsigned int md_len; +} _getdns_tls_hmac; + +#endif /* _GETDNS_TLS_INTERNAL_H */ diff --git a/src/gnutls/tls.c b/src/gnutls/tls.c new file mode 100644 index 00000000..5ef1849f --- /dev/null +++ b/src/gnutls/tls.c @@ -0,0 +1,903 @@ +/** + * + * \file tls.c + * @brief getdns TLS functions + */ + +/* + * Copyright (c) 2018-2019, NLnet Labs + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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 + +#include "config.h" + +#include "debug.h" +#include "context.h" + +#include "tls.h" + +/* + * Cipher suites recommended in RFC7525. + * + * The following strings generate a list with the same ciphers that are + * generated by the equivalent string in the OpenSSL version of this file. + */ +static char const * const _getdns_tls_context_default_cipher_list = + "+ECDHE-RSA:+ECDHE-ECDSA:+AEAD"; + +static char const * const _getdns_tls_context_default_cipher_suites = + "+AES-256-GCM:+AES-128-GCM:+CHACHA20-POLY1305"; + +static char const * const _getdns_tls_connection_opportunistic_cipher_list = + "NORMAL"; + +static char const * const _getdns_tls_priorities[] = { + NULL, /* No protocol */ + NULL, /* SSL3 - no available keyword. */ + "+VERS-TLS1.0", /* TLS1.0 */ + "+VERS-TLS1.1", /* TLS1.1 */ + "+VERS-TLS1.2", /* TLS1.2 */ + "+VERS-TLS1.3", /* TLS1.3 */ +}; + +static char* getdns_strdup(struct mem_funcs* mfs, const char* s) +{ + char* res; + + if (!s) + return NULL; + + res = GETDNS_XMALLOC(*mfs, char, strlen(s) + 1); + if (!res) + return NULL; + strcpy(res, s); + return res; +} + +static char* getdns_priappend(struct mem_funcs* mfs, char* s1, const char* s2) +{ + char* res; + + if (!s1) + return getdns_strdup(mfs, s2); + if (!s2) + return s1; + + res = GETDNS_XMALLOC(*mfs, char, strlen(s1) + strlen(s2) + 2); + if (!res) + return NULL; + strcpy(res, s1); + strcat(res, ":"); + strcat(res, s2); + GETDNS_FREE(*mfs, s1); + return res; +} + +static int set_connection_ciphers(_getdns_tls_connection* conn) +{ + char* pri = NULL; + int res; + + pri = getdns_priappend(conn->mfs, pri, "NONE:+COMP-ALL:+SIGN-RSA-SHA384"); + + if (conn->cipher_suites) + pri = getdns_priappend(conn->mfs, pri, conn->cipher_suites); + else if (conn->ctx->cipher_suites) + pri = getdns_priappend(conn->mfs, pri, conn->ctx->cipher_suites); + + if (conn->cipher_list) + pri = getdns_priappend(conn->mfs, pri, conn->cipher_list); + else if (conn->ctx->cipher_list) + pri = getdns_priappend(conn->mfs, pri, conn->ctx->cipher_list); + + if (conn->curve_list) + pri = getdns_priappend(conn->mfs, pri, conn->curve_list); + else if (conn->ctx->curve_list) + pri = getdns_priappend(conn->mfs, pri, conn->ctx->curve_list); + else + pri = getdns_priappend(conn->mfs, pri, "+CURVE-ALL"); + + gnutls_protocol_t min = conn->min_tls; + gnutls_protocol_t max = conn->max_tls; + if (!min) min = conn->ctx->min_tls; + if (!max) max = conn->ctx->max_tls; + + if (!min && !max) { + pri = getdns_priappend(conn->mfs, pri, "+VERS-TLS-ALL"); + } else { + if (!max) max = GNUTLS_TLS_VERSION_MAX; + + for (gnutls_protocol_t i = min; i <= max; ++i) + pri = getdns_priappend(conn->mfs, pri, _getdns_tls_priorities[i]); + } + + if (pri) { + res = gnutls_priority_set_direct(conn->tls, pri, NULL); + if (res != GNUTLS_E_SUCCESS) { + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS connection with " + , pri + , gnutls_strerror(res)); + } + } + else + res = gnutls_set_default_priority(conn->tls); + GETDNS_FREE(*conn->mfs, pri); + + return res; +} + +static getdns_return_t error_may_want_read_write(_getdns_tls_connection* conn, int err) +{ + switch (err) { + case GNUTLS_E_INTERRUPTED: + case GNUTLS_E_AGAIN: + case GNUTLS_E_WARNING_ALERT_RECEIVED: + case GNUTLS_E_GOT_APPLICATION_DATA: + if (gnutls_record_get_direction(conn->tls) == 0) + return GETDNS_RETURN_TLS_WANT_READ; + else + return GETDNS_RETURN_TLS_WANT_WRITE; + + default: + return GETDNS_RETURN_GENERIC_ERROR; + } +} + +static getdns_return_t get_gnu_mac_algorithm(int algorithm, gnutls_mac_algorithm_t* gnualg) +{ + switch (algorithm) { + case GETDNS_HMAC_MD5 : *gnualg = GNUTLS_MAC_MD5 ; break; + case GETDNS_HMAC_SHA1 : *gnualg = GNUTLS_MAC_SHA1 ; break; + case GETDNS_HMAC_SHA224: *gnualg = GNUTLS_MAC_SHA224; break; + case GETDNS_HMAC_SHA256: *gnualg = GNUTLS_MAC_SHA256; break; + case GETDNS_HMAC_SHA384: *gnualg = GNUTLS_MAC_SHA384; break; + case GETDNS_HMAC_SHA512: *gnualg = GNUTLS_MAC_SHA512; break; + default : return GETDNS_RETURN_GENERIC_ERROR; + } + + return GETDNS_RETURN_GOOD; +} + +static gnutls_protocol_t _getdns_tls_version2gnutls_version(getdns_tls_version_t v) +{ + switch (v) { + case GETDNS_SSL3 : return GNUTLS_SSL3; + case GETDNS_TLS1 : return GNUTLS_TLS1; + case GETDNS_TLS1_1: return GNUTLS_TLS1_1; + case GETDNS_TLS1_2: return GNUTLS_TLS1_2; +#if GNUTLS_VERSION_NUMBER >= 0x030605 + case GETDNS_TLS1_3: return GNUTLS_TLS1_3; +#endif + default : return GNUTLS_TLS_VERSION_MAX; + } +} + +static _getdns_tls_x509* _getdns_tls_x509_new(struct mem_funcs* mfs, gnutls_datum_t cert) +{ + _getdns_tls_x509* res; + + res = GETDNS_MALLOC(*mfs, _getdns_tls_x509); + if (res) + res->tls = cert; + + return res; +} + +void _getdns_tls_init() +{ + gnutls_global_init(); +} + +_getdns_tls_context* _getdns_tls_context_new(struct mem_funcs* mfs, const getdns_log_config* log) +{ + _getdns_tls_context* res; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_context))) + return NULL; + + res->mfs = mfs; + res->cipher_list = res->cipher_suites = res->curve_list = NULL; + res->min_tls = res->max_tls = 0; + res->ca_trust_file = NULL; + res->ca_trust_path = NULL; + res->log = log; + + return res; +} + +getdns_return_t _getdns_tls_context_free(struct mem_funcs* mfs, _getdns_tls_context* ctx) +{ + if (!ctx) + return GETDNS_RETURN_INVALID_PARAMETER; + + GETDNS_FREE(*mfs, ctx->ca_trust_path); + GETDNS_FREE(*mfs, ctx->ca_trust_file); + GETDNS_FREE(*mfs, ctx->curve_list); + GETDNS_FREE(*mfs, ctx->cipher_suites); + GETDNS_FREE(*mfs, ctx->cipher_list); + GETDNS_FREE(*mfs, ctx); + return GETDNS_RETURN_GOOD; +} + +void _getdns_tls_context_pinset_init(_getdns_tls_context* ctx) +{ + (void) ctx; +} + +getdns_return_t _getdns_tls_context_set_min_max_tls_version(_getdns_tls_context* ctx, getdns_tls_version_t min, getdns_tls_version_t max) +{ + if (!ctx) + return GETDNS_RETURN_INVALID_PARAMETER; + ctx->min_tls = _getdns_tls_version2gnutls_version(min); + ctx->max_tls = _getdns_tls_version2gnutls_version(max); + return GETDNS_RETURN_GOOD; +} + +const char* _getdns_tls_context_get_default_cipher_list() +{ + return _getdns_tls_context_default_cipher_list; +} + +getdns_return_t _getdns_tls_context_set_cipher_list(_getdns_tls_context* ctx, const char* list) +{ + if (!ctx) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (!list) + list = _getdns_tls_context_default_cipher_list; + + GETDNS_FREE(*ctx->mfs, ctx->cipher_list); + ctx->cipher_list = getdns_strdup(ctx->mfs, list); + return GETDNS_RETURN_GOOD; +} + +const char* _getdns_tls_context_get_default_cipher_suites() +{ + return _getdns_tls_context_default_cipher_suites; +} + +getdns_return_t _getdns_tls_context_set_cipher_suites(_getdns_tls_context* ctx, const char* list) +{ + if (!ctx) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (!list) + list = _getdns_tls_context_default_cipher_suites; + + GETDNS_FREE(*ctx->mfs, ctx->cipher_suites); + ctx->cipher_suites = getdns_strdup(ctx->mfs, list); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_context_set_curves_list(_getdns_tls_context* ctx, const char* list) +{ + if (!ctx) + return GETDNS_RETURN_INVALID_PARAMETER; + + GETDNS_FREE(*ctx->mfs, ctx->curve_list); + ctx->curve_list = getdns_strdup(ctx->mfs, list); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_context_set_ca(_getdns_tls_context* ctx, const char* file, const char* path) +{ + if (!ctx) + return GETDNS_RETURN_INVALID_PARAMETER; + + GETDNS_FREE(*ctx->mfs, ctx->ca_trust_file); + ctx->ca_trust_file = getdns_strdup(ctx->mfs, file); + GETDNS_FREE(*ctx->mfs, ctx->ca_trust_path); + ctx->ca_trust_path = getdns_strdup(ctx->mfs, path); + return GETDNS_RETURN_GOOD; +} + +_getdns_tls_connection* _getdns_tls_connection_new(struct mem_funcs* mfs, _getdns_tls_context* ctx, int fd, const getdns_log_config* log) +{ + _getdns_tls_connection* res; + + if (!ctx) + return NULL; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_connection))) + return NULL; + + res->shutdown = 0; + res->ctx = ctx; + res->mfs = mfs; + res->cred = NULL; + res->tls = NULL; + res->cipher_list = res->cipher_suites = res->curve_list = NULL; + res->min_tls = res->max_tls = 0; + res->dane_state = NULL; + res->dane_query = NULL; + res->tlsa = NULL; + res->log = log; + + if (gnutls_certificate_allocate_credentials(&res->cred) != GNUTLS_E_SUCCESS) + goto failed; + + if (!ctx->ca_trust_file && !ctx->ca_trust_path) + gnutls_certificate_set_x509_system_trust(res->cred); + else { + if (ctx->ca_trust_file) + gnutls_certificate_set_x509_trust_file(res->cred, ctx->ca_trust_file, GNUTLS_X509_FMT_PEM); + if (ctx->ca_trust_path) + gnutls_certificate_set_x509_trust_dir(res->cred, ctx->ca_trust_path, GNUTLS_X509_FMT_PEM); + } + + if (gnutls_init(&res->tls, GNUTLS_CLIENT | GNUTLS_NONBLOCK) != GNUTLS_E_SUCCESS) + goto failed; + if (set_connection_ciphers(res) != GNUTLS_E_SUCCESS) { + + goto failed; + } + if (gnutls_credentials_set(res->tls, GNUTLS_CRD_CERTIFICATE, res->cred) != GNUTLS_E_SUCCESS) + goto failed; + if (dane_state_init(&res->dane_state, DANE_F_IGNORE_DNSSEC) != DANE_E_SUCCESS) + goto failed; + + gnutls_transport_set_int(res->tls, fd); + return res; + +failed: + _getdns_tls_connection_free(mfs, res); + return NULL; +} + +getdns_return_t _getdns_tls_connection_free(struct mem_funcs* mfs, _getdns_tls_connection* conn) +{ + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (conn->dane_query) + dane_query_deinit(conn->dane_query); + if (conn->dane_state) + dane_state_deinit(conn->dane_state); + if (conn->tls) + gnutls_deinit(conn->tls); + if (conn->cred) + gnutls_certificate_free_credentials(conn->cred); + GETDNS_FREE(*mfs, conn->tlsa); + GETDNS_FREE(*mfs, conn->curve_list); + GETDNS_FREE(*mfs, conn->cipher_suites); + GETDNS_FREE(*mfs, conn->cipher_list); + GETDNS_FREE(*mfs, conn); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_shutdown(_getdns_tls_connection* conn) +{ + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (conn->shutdown == 0) { + gnutls_bye(conn->tls, GNUTLS_SHUT_WR); + conn->shutdown++; + } else { + gnutls_bye(conn->tls, GNUTLS_SHUT_RDWR); + conn->shutdown++; + } + + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_set_min_max_tls_version(_getdns_tls_connection* conn, getdns_tls_version_t min, getdns_tls_version_t max) +{ + if (!conn) + return GETDNS_RETURN_INVALID_PARAMETER; + conn->min_tls = _getdns_tls_version2gnutls_version(min); + conn->max_tls = _getdns_tls_version2gnutls_version(max); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_set_cipher_list(_getdns_tls_connection* conn, const char* list) +{ + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (!list) + list = _getdns_tls_connection_opportunistic_cipher_list; + + GETDNS_FREE(*conn->mfs, conn->cipher_list); + conn->cipher_list = getdns_strdup(conn->mfs, list); + if (set_connection_ciphers(conn) == GNUTLS_E_SUCCESS) + return GETDNS_RETURN_GOOD; + else + return GETDNS_RETURN_GENERIC_ERROR; +} + +getdns_return_t _getdns_tls_connection_set_cipher_suites(_getdns_tls_connection* conn, const char* list) +{ + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + GETDNS_FREE(*conn->mfs, conn->cipher_list); + conn->cipher_suites = getdns_strdup(conn->mfs, list); + if (set_connection_ciphers(conn) == GNUTLS_E_SUCCESS) + return GETDNS_RETURN_GOOD; + else + return GETDNS_RETURN_GENERIC_ERROR; +} + +getdns_return_t _getdns_tls_connection_set_curves_list(_getdns_tls_connection* conn, const char* list) +{ + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + GETDNS_FREE(*conn->mfs, conn->curve_list); + conn->curve_list = getdns_strdup(conn->mfs, list); + if (set_connection_ciphers(conn) == GNUTLS_E_SUCCESS) + return GETDNS_RETURN_GOOD; + else + return GETDNS_RETURN_GENERIC_ERROR; +} + +getdns_return_t _getdns_tls_connection_set_session(_getdns_tls_connection* conn, _getdns_tls_session* s) +{ + int r; + + if (!conn || !conn->tls || !s) + return GETDNS_RETURN_INVALID_PARAMETER; + + r = gnutls_session_set_data(conn->tls, s->tls.data, s->tls.size); + if (r != GNUTLS_E_SUCCESS) + return GETDNS_RETURN_GENERIC_ERROR; + return GETDNS_RETURN_GOOD; +} + +_getdns_tls_session* _getdns_tls_connection_get_session(struct mem_funcs* mfs, _getdns_tls_connection* conn) +{ + _getdns_tls_session* res; + int r; + + if (!conn || !conn->tls) + return NULL; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_session))) + return NULL; + + r = gnutls_session_get_data2(conn->tls, &res->tls); + if (r != GNUTLS_E_SUCCESS) { + GETDNS_FREE(*mfs, res); + return NULL; + } + + return res; +} + +const char* _getdns_tls_connection_get_version(_getdns_tls_connection* conn) +{ + if (!conn || !conn->tls) + return NULL; + + return gnutls_protocol_get_name(gnutls_protocol_get_version(conn->tls)); +} + +getdns_return_t _getdns_tls_connection_do_handshake(_getdns_tls_connection* conn) +{ + int r; + + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + r = gnutls_handshake(conn->tls); + if (r == GNUTLS_E_SUCCESS) { + return GETDNS_RETURN_GOOD; + } + else + return error_may_want_read_write(conn, r); +} + +_getdns_tls_x509* _getdns_tls_connection_get_peer_certificate(struct mem_funcs* mfs, _getdns_tls_connection* conn) +{ + const gnutls_datum_t *cert_list; + unsigned int cert_list_size; + + if (!conn || !conn->tls) + return NULL; + + cert_list = gnutls_certificate_get_peers(conn->tls, &cert_list_size); + if (cert_list == NULL) + return NULL; + + return _getdns_tls_x509_new(mfs, *cert_list); +} + +getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn) +{ + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (gnutls_session_is_resumed(conn->tls) != 0) + return GETDNS_RETURN_GOOD; + else + return GETDNS_RETURN_TLS_CONNECTION_FRESH; +} + +getdns_return_t _getdns_tls_connection_setup_hostname_auth(_getdns_tls_connection* conn, const char* auth_name) +{ + int r; + + if (!conn || !conn->tls || !auth_name) + return GETDNS_RETURN_INVALID_PARAMETER; + + r = gnutls_server_name_set(conn->tls, GNUTLS_NAME_DNS, auth_name, strlen(auth_name)); + if (r != GNUTLS_E_SUCCESS) + return GETDNS_RETURN_GENERIC_ERROR; + + gnutls_session_set_verify_cert(conn->tls, auth_name, 0); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* conn, const char* auth_name, const sha256_pin_t* pinset) +{ + int r; + + if (!conn || !conn->tls || !auth_name) + return GETDNS_RETURN_INVALID_PARAMETER; + + size_t npins = 0; + for (const sha256_pin_t* pin = pinset; pin; pin = pin->next) + npins++; + + GETDNS_FREE(*conn->mfs, conn->tlsa); + conn->tlsa = GETDNS_XMALLOC(*conn->mfs, char, npins * (SHA256_DIGEST_LENGTH + 3) * 2); + if (!conn->tlsa) + return GETDNS_RETURN_GENERIC_ERROR; + + char** dane_data = GETDNS_XMALLOC(*conn->mfs, char*, npins * 2 + 1); + if (!dane_data) + return GETDNS_RETURN_GENERIC_ERROR; + int* dane_data_len = GETDNS_XMALLOC(*conn->mfs, int, npins * 2 + 1); + if (!dane_data_len) { + GETDNS_FREE(*conn->mfs, dane_data); + return GETDNS_RETURN_GENERIC_ERROR; + } + + char** dane_p = dane_data; + int* dane_len_p = dane_data_len; + char* p = conn->tlsa; + for (const sha256_pin_t* pin = pinset; pin; pin = pin->next) { + *dane_p++ = p; + *dane_len_p++ = SHA256_DIGEST_LENGTH + 3; + p[0] = DANE_CERT_USAGE_LOCAL_CA; + p[1] = DANE_CERT_PK; + p[2] = DANE_MATCH_SHA2_256; + memcpy(&p[3], pin->pin, SHA256_DIGEST_LENGTH); + p += SHA256_DIGEST_LENGTH + 3; + + *dane_p++ = p; + *dane_len_p++ = SHA256_DIGEST_LENGTH + 3; + p[0] = DANE_CERT_USAGE_LOCAL_EE; + p[1] = DANE_CERT_PK; + p[2] = DANE_MATCH_SHA2_256; + memcpy(&p[3], pin->pin, SHA256_DIGEST_LENGTH); + p += SHA256_DIGEST_LENGTH + 3; + } + *dane_p = NULL; + + if (conn->dane_query) + dane_query_deinit(conn->dane_query); + r = dane_raw_tlsa(conn->dane_state, &conn->dane_query, dane_data, dane_data_len, 0, 0); + GETDNS_FREE(*conn->mfs, dane_data_len); + GETDNS_FREE(*conn->mfs, dane_data); + + return (r == DANE_E_SUCCESS) ? GETDNS_RETURN_GOOD : GETDNS_RETURN_GENERIC_ERROR; +} + +getdns_return_t _getdns_tls_connection_certificate_verify(_getdns_tls_connection* conn, long* errnum, const char** errmsg) +{ + if (!conn || !conn->tls) + return GETDNS_RETURN_INVALID_PARAMETER; + + /* If no pinset, no DANE info to check. */ + if (!conn->dane_query) + return GETDNS_RETURN_GOOD; + + /* Most of the internals of dane_verify_session_crt() */ + + const gnutls_datum_t* cert_list; + unsigned int cert_list_size = 0; + unsigned int type; + int ret; + const gnutls_datum_t* cl; + gnutls_datum_t* new_cert_list = NULL; + int clsize; + unsigned int verify; + + cert_list = gnutls_certificate_get_peers(conn->tls, &cert_list_size); + if (cert_list_size == 0) { + *errnum = 1; + *errmsg = "No peer certificate"; + return GETDNS_RETURN_GENERIC_ERROR; + } + cl = cert_list; + + type = gnutls_certificate_type_get(conn->tls); + + /* this list may be incomplete, try to get the self-signed CA if any */ + if (cert_list_size > 0) { + gnutls_x509_crt_t crt, ca; + gnutls_certificate_credentials_t sc; + + ret = gnutls_x509_crt_init(&crt); + if (ret < 0) + goto failsafe; + + ret = gnutls_x509_crt_import(crt, &cert_list[cert_list_size-1], GNUTLS_X509_FMT_DER); + if (ret < 0) { + gnutls_x509_crt_deinit(crt); + goto failsafe; + } + + /* if it is already self signed continue normally */ + ret = gnutls_x509_crt_check_issuer(crt, crt); + if (ret != 0) { + gnutls_x509_crt_deinit(crt); + goto failsafe; + } + + /* chain does not finish in a self signed cert, try to obtain the issuer */ + ret = gnutls_credentials_get(conn->tls, GNUTLS_CRD_CERTIFICATE, (void**)&sc); + if (ret < 0) { + gnutls_x509_crt_deinit(crt); + goto failsafe; + } + + ret = gnutls_certificate_get_issuer(sc, crt, &ca, 0); + if (ret < 0) { + gnutls_x509_crt_deinit(crt); + goto failsafe; + } + + /* make the new list */ + new_cert_list = GETDNS_XMALLOC(*conn->mfs, gnutls_datum_t, cert_list_size + 1); + if (new_cert_list == NULL) { + gnutls_x509_crt_deinit(crt); + goto failsafe; + } + + memcpy(new_cert_list, cert_list, cert_list_size*sizeof(gnutls_datum_t)); + cl = new_cert_list; + + ret = gnutls_x509_crt_export2(ca, GNUTLS_X509_FMT_DER, &new_cert_list[cert_list_size]); + if (ret < 0) { + GETDNS_FREE(*conn->mfs, new_cert_list); + gnutls_x509_crt_deinit(crt); + goto failsafe; + } + } + +failsafe: + + clsize = cert_list_size; + if (cl == new_cert_list) + clsize += 1; + + ret = dane_verify_crt_raw(conn->dane_state, cl, clsize, type, conn->dane_query, 0, 0, &verify); + + if (new_cert_list) { + gnutls_free(new_cert_list[cert_list_size].data); + GETDNS_FREE(*conn->mfs, new_cert_list); + } + + if (ret != DANE_E_SUCCESS) + return GETDNS_RETURN_GENERIC_ERROR; + + if (verify != 0) { + if (verify & DANE_VERIFY_CERT_DIFFERS) { + *errnum = 3; + *errmsg = "Pinset validation: Certificate differs"; + } else if (verify & DANE_VERIFY_CA_CONSTRAINTS_VIOLATED) { + *errnum = 2; + *errmsg = "Pinset validation: CA constraints violated"; + } else { + *errnum = 4; + *errmsg = "Pinset validation: Unknown DANE info"; + } + return GETDNS_RETURN_GENERIC_ERROR; + } + + return GETDNS_RETURN_GOOD; +} + + +getdns_return_t _getdns_tls_connection_read(_getdns_tls_connection* conn, uint8_t* buf, size_t to_read, size_t* read) +{ + ssize_t sread; + + if (!conn || !conn->tls || !read) + return GETDNS_RETURN_INVALID_PARAMETER; + + sread = gnutls_record_recv(conn->tls, buf, to_read); + if (sread < 0) + return error_may_want_read_write(conn, sread); + + *read = sread; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_write(_getdns_tls_connection* conn, uint8_t* buf, size_t to_write, size_t* written) +{ + int swritten; + + if (!conn || !conn->tls || !written) + return GETDNS_RETURN_INVALID_PARAMETER; + + swritten = gnutls_record_send(conn->tls, buf, to_write); + if (swritten < 0) + return error_may_want_read_write(conn, swritten); + + *written = swritten; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_session_free(struct mem_funcs* mfs, _getdns_tls_session* s) +{ + if (!s) + return GETDNS_RETURN_INVALID_PARAMETER; + GETDNS_FREE(*mfs, s); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict) +{ + if (! getdns_dict_set_int( + dict, "gnutls_version_number", GNUTLS_VERSION_NUMBER) + + && ! getdns_dict_util_set_string( + dict, "gnutls_version_string", GNUTLS_VERSION) + ) + return GETDNS_RETURN_GOOD; + return GETDNS_RETURN_GENERIC_ERROR; +} + +void _getdns_tls_x509_free(struct mem_funcs* mfs, _getdns_tls_x509* cert) +{ + if (cert) + GETDNS_FREE(*mfs, cert); +} + +int _getdns_tls_x509_to_der(struct mem_funcs* mfs, _getdns_tls_x509* cert, getdns_bindata* bindata) +{ + gnutls_x509_crt_t crt; + size_t s; + + if (!cert || gnutls_x509_crt_init(&crt) != GNUTLS_E_SUCCESS) + return 0; + + gnutls_x509_crt_import(crt, &cert->tls, GNUTLS_X509_FMT_DER); + gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, NULL, &s); + + if (!bindata) { + gnutls_x509_crt_deinit(crt); + return s; + } + + bindata->data = GETDNS_XMALLOC(*mfs, uint8_t, s); + if (!bindata->data) { + gnutls_x509_crt_deinit(crt); + return 0; + } + + gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_DER, bindata->data, &s); + bindata->size = s; + gnutls_x509_crt_deinit(crt); + return s; +} + +unsigned char* _getdns_tls_hmac_hash(struct mem_funcs* mfs, int algorithm, const void* key, size_t key_size, const void* data, size_t data_size, size_t* output_size) +{ + gnutls_mac_algorithm_t alg; + unsigned int md_len; + unsigned char* res; + + if (get_gnu_mac_algorithm(algorithm, &alg) != GETDNS_RETURN_GOOD) + return NULL; + + md_len = gnutls_hmac_get_len(alg); + res = (unsigned char*) GETDNS_XMALLOC(*mfs, unsigned char, md_len); + if (!res) + return NULL; + + (void) gnutls_hmac_fast(alg, key, key_size, data, data_size, res); + + if (output_size) + *output_size = md_len; + return res; +} + +_getdns_tls_hmac* _getdns_tls_hmac_new(struct mem_funcs* mfs, int algorithm, const void* key, size_t key_size) +{ + gnutls_mac_algorithm_t alg; + _getdns_tls_hmac* res; + + if (get_gnu_mac_algorithm(algorithm, &alg) != GETDNS_RETURN_GOOD) + return NULL; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_hmac))) + return NULL; + + if (gnutls_hmac_init(&res->tls, alg, key, key_size) < 0) { + GETDNS_FREE(*mfs, res); + return NULL; + } + res->md_len = gnutls_hmac_get_len(alg); + return res; +} + +getdns_return_t _getdns_tls_hmac_add(_getdns_tls_hmac* h, const void* data, size_t data_size) +{ + if (!h || !h->tls || !data) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (gnutls_hmac(h->tls, data, data_size) < 0) + return GETDNS_RETURN_GENERIC_ERROR; + else + return GETDNS_RETURN_GOOD; +} + +unsigned char* _getdns_tls_hmac_end(struct mem_funcs* mfs, _getdns_tls_hmac* h, size_t* output_size) +{ + unsigned char* res; + + if (!h || !h->tls) + return NULL; + + res = (unsigned char*) GETDNS_XMALLOC(*mfs, unsigned char, h->md_len); + if (!res) + return NULL; + + gnutls_hmac_deinit(h->tls, res); + if (output_size) + *output_size = h->md_len; + + GETDNS_FREE(*mfs, h); + return res; +} + +void _getdns_tls_sha1(const void* data, size_t data_size, unsigned char* buf) +{ + gnutls_hash_fast(GNUTLS_DIG_SHA1, data, data_size, buf); +} + +void _getdns_tls_cookie_sha256(uint32_t secret, void* addr, size_t addrlen, unsigned char* buf, size_t* buflen) +{ + gnutls_hash_hd_t digest; + + gnutls_hash_init(&digest, GNUTLS_DIG_SHA256); + gnutls_hash(digest, &secret, sizeof(secret)); + gnutls_hash(digest, addr, addrlen); + gnutls_hash_deinit(digest, buf); + *buflen = gnutls_hash_get_len(GNUTLS_DIG_SHA256); +} + +/* tls.c */ diff --git a/src/gnutls/val_secalgo.c b/src/gnutls/val_secalgo.c new file mode 120000 index 00000000..446f8e5f --- /dev/null +++ b/src/gnutls/val_secalgo.c @@ -0,0 +1 @@ +../openssl/val_secalgo.c \ No newline at end of file diff --git a/src/gnutls/validator b/src/gnutls/validator new file mode 120000 index 00000000..3e9ba44b --- /dev/null +++ b/src/gnutls/validator @@ -0,0 +1 @@ +../openssl/validator \ No newline at end of file diff --git a/src/openssl/anchor-internal.c b/src/openssl/anchor-internal.c new file mode 100644 index 00000000..db9e01f8 --- /dev/null +++ b/src/openssl/anchor-internal.c @@ -0,0 +1,382 @@ +/** + * + * /brief functions for DNSSEC trust anchor management + */ +/* + * Copyright (c) 2017, NLnet Labs, 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: + * * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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 "config.h" +#include "debug.h" +#include "anchor.h" +#include +#include +#include +#include +#include +#include +#include "types-internal.h" +#include "context.h" +#include "dnssec.h" +#include "yxml/yxml.h" +#include "gldns/parseutil.h" +#include "gldns/gbuffer.h" +#include "gldns/str2wire.h" +#include "gldns/wire2str.h" +#include "gldns/pkthdr.h" +#include "gldns/keyraw.h" +#include "general.h" +#include "util-internal.h" +#include "platform.h" + +/* get key usage out of its extension, returns 0 if no key_usage extension */ +static unsigned long +_getdns_get_usage_of_ex(X509* cert) +{ + unsigned long val = 0; + ASN1_BIT_STRING* s; + + if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) { + if(s->length > 0) { + val = s->data[0]; + if(s->length > 1) + val |= s->data[1] << 8; + } + ASN1_BIT_STRING_free(s); + } + return val; +} + +/** get valid signers from the list of signers in the signature */ +static STACK_OF(X509)* +_getdns_get_valid_signers(PKCS7* p7, const char* p7signer) +{ + int i; + STACK_OF(X509)* validsigners = sk_X509_new_null(); + STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0); + unsigned long usage = 0; + if(!validsigners) { + DEBUG_ANCHOR("ERROR %s(): Failed to allocated validsigners\n" + , __FUNC__); + sk_X509_free(signers); + return NULL; + } + if(!signers) { + DEBUG_ANCHOR("ERROR %s(): Failed to allocated signers\n" + , __FUNC__); + sk_X509_free(validsigners); + return NULL; + } + for(i=0; idata, xml_bd->size))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating xml BIO\n" + , __FUNC__); + + else if (!(p7s = BIO_new_mem_buf(p7s_bd->data, p7s_bd->size))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating p7s BIO\n" + , __FUNC__); + + else if (!(crt = BIO_new_mem_buf(crt_bd->data, crt_bd->size))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating crt BIO\n" + , __FUNC__); + + else if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL))) + DEBUG_ANCHOR("ERROR %s(): Parsing builtin certificate\n" + , __FUNC__); + + else if (!(store = X509_STORE_new())) + DEBUG_ANCHOR("ERROR %s(): Failed allocating store\n" + , __FUNC__); + + else if (!X509_STORE_add_cert(store, x)) + DEBUG_ANCHOR("ERROR %s(): Adding certificate to store\n" + , __FUNC__); + + else if (_getdns_verify_p7sig(xml, p7s, store, p7signer)) { + gldns_buffer gbuf; + + gldns_buffer_init_vfixed_frm_data(&gbuf, tas, *tas_len); + + if (!_getdns_parse_xml_trust_anchors_buf(&gbuf, now_ms, + (char *)xml_bd->data, xml_bd->size)) + DEBUG_ANCHOR("Failed to parse trust anchor XML data"); + + else if (gldns_buffer_position(&gbuf) > *tas_len) { + *tas_len = gldns_buffer_position(&gbuf); + if ((success = GETDNS_XMALLOC(*mf, uint8_t, *tas_len))) { + gldns_buffer_init_frm_data(&gbuf, success, *tas_len); + if (!_getdns_parse_xml_trust_anchors_buf(&gbuf, + now_ms, (char *)xml_bd->data, xml_bd->size)) { + + DEBUG_ANCHOR("Failed to re-parse trust" + " anchor XML data\n"); + GETDNS_FREE(*mf, success); + success = NULL; + } + } else + DEBUG_ANCHOR("Could not allocate space for " + "trust anchors\n"); + } else { + success = tas; + *tas_len = gldns_buffer_position(&gbuf); + } + } else { + DEBUG_ANCHOR("Verifying trust-anchors failed!\n"); + } + if (store) X509_STORE_free(store); + if (x) X509_free(x); + if (crt) BIO_free(crt); + if (xml) BIO_free(xml); + if (p7s) BIO_free(p7s); + return success; +} + +void _getdns_context_equip_with_anchor( + getdns_context *context, uint64_t *now_ms) +{ + uint8_t xml_spc[4096], *xml_data = NULL; + uint8_t p7s_spc[4096], *p7s_data = NULL; + size_t xml_len, p7s_len; + const char *verify_email = NULL; + const char *verify_CA = NULL; + getdns_return_t r; + + BIO *xml = NULL, *p7s = NULL, *crt = NULL; + X509 *x = NULL; + X509_STORE *store = NULL; + + if ((r = getdns_context_get_trust_anchors_verify_CA( + context, &verify_CA))) + DEBUG_ANCHOR("ERROR %s(): Getting trust anchor verify" + " CA: \"%s\"\n", __FUNC__ + , getdns_get_errorstr_by_id(r)); + + else if (!verify_CA || !*verify_CA) + DEBUG_ANCHOR("NOTICE: Trust anchor verification explicitely " + "disabled by empty verify CA\n"); + + else if ((r = getdns_context_get_trust_anchors_verify_email( + context, &verify_email))) + DEBUG_ANCHOR("ERROR %s(): Getting trust anchor verify email " + "address: \"%s\"\n", __FUNC__ + , getdns_get_errorstr_by_id(r)); + + else if (!verify_email || !*verify_email) + DEBUG_ANCHOR("NOTICE: Trust anchor verification explicitely " + "disabled by empty verify email\n"); + + else if (!(xml_data = _getdns_context_get_priv_file(context, + "root-anchors.xml", xml_spc, sizeof(xml_spc), &xml_len))) + DEBUG_ANCHOR("DEBUG %s(): root-anchors.xml not present\n" + , __FUNC__); + + else if (!(p7s_data = _getdns_context_get_priv_file(context, + "root-anchors.p7s", p7s_spc, sizeof(p7s_spc), &p7s_len))) + DEBUG_ANCHOR("DEBUG %s(): root-anchors.p7s not present\n" + , __FUNC__); + + else if (!(xml = BIO_new_mem_buf(xml_data, xml_len))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating xml BIO\n" + , __FUNC__); + + else if (!(p7s = BIO_new_mem_buf(p7s_data, p7s_len))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating p7s BIO\n" + , __FUNC__); + + else if (!(crt = BIO_new_mem_buf((void *)verify_CA, -1))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating crt BIO\n" + , __FUNC__); + + else if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL))) + DEBUG_ANCHOR("ERROR %s(): Parsing builtin certificate\n" + , __FUNC__); + + else if (!(store = X509_STORE_new())) + DEBUG_ANCHOR("ERROR %s(): Failed allocating store\n" + , __FUNC__); + + else if (!X509_STORE_add_cert(store, x)) + DEBUG_ANCHOR("ERROR %s(): Adding certificate to store\n" + , __FUNC__); + + else if (_getdns_verify_p7sig(xml, p7s, store, verify_email)) { + uint8_t ta_spc[sizeof(context->trust_anchors_spc)]; + size_t ta_len; + uint8_t *ta = NULL; + gldns_buffer gbuf; + + gldns_buffer_init_vfixed_frm_data( + &gbuf, ta_spc, sizeof(ta_spc)); + + if (!_getdns_parse_xml_trust_anchors_buf(&gbuf, now_ms, + (char *)xml_data, xml_len)) + DEBUG_ANCHOR("Failed to parse trust anchor XML data"); + else if ((ta_len = gldns_buffer_position(&gbuf)) > sizeof(ta_spc)) { + if ((ta = GETDNS_XMALLOC(context->mf, uint8_t, ta_len))) { + gldns_buffer_init_frm_data(&gbuf, ta, + gldns_buffer_position(&gbuf)); + if (!_getdns_parse_xml_trust_anchors_buf( + &gbuf, now_ms, (char *)xml_data, xml_len)) { + DEBUG_ANCHOR("Failed to re-parse trust" + " anchor XML data"); + GETDNS_FREE(context->mf, ta); + } else { + context->trust_anchors = ta; + context->trust_anchors_len = ta_len; + context->trust_anchors_source = GETDNS_TASRC_XML; + _getdns_ta_notify_dnsreqs(context); + } + } else + DEBUG_ANCHOR("Could not allocate space for XML file"); + } else { + (void)memcpy(context->trust_anchors_spc, ta_spc, ta_len); + context->trust_anchors = context->trust_anchors_spc; + context->trust_anchors_len = ta_len; + context->trust_anchors_source = GETDNS_TASRC_XML; + _getdns_ta_notify_dnsreqs(context); + } + DEBUG_ANCHOR("ta: %p, ta_len: %d\n", + (void *)context->trust_anchors, (int)context->trust_anchors_len); + + } else { + DEBUG_ANCHOR("Verifying trust-anchors failed!\n"); + } + if (store) X509_STORE_free(store); + if (x) X509_free(x); + if (crt) BIO_free(crt); + if (xml) BIO_free(xml); + if (p7s) BIO_free(p7s); + if (xml_data && xml_data != xml_spc) + GETDNS_FREE(context->mf, xml_data); + if (p7s_data && p7s_data != p7s_spc) + GETDNS_FREE(context->mf, p7s_data); +} diff --git a/src/openssl/keyraw-internal.c b/src/openssl/keyraw-internal.c new file mode 100644 index 00000000..6dab968a --- /dev/null +++ b/src/openssl/keyraw-internal.c @@ -0,0 +1,380 @@ +/* + * keyraw.c - raw key operations and conversions - OpenSSL version + * + * (c) NLnet Labs, 2004-2008 + * + * See the file LICENSE for the license + */ +/** + * \file + * Implementation of raw DNSKEY functions (work on wire rdata). + */ + +#include "config.h" +#include "gldns/keyraw.h" +#include "gldns/rrdef.h" + +#ifdef HAVE_SSL +#include +#include +#include +#include +#include +#ifdef HAVE_OPENSSL_CONF_H +# include +#endif +#ifdef HAVE_OPENSSL_ENGINE_H +# include +#endif +#ifdef HAVE_OPENSSL_BN_H +#include +#endif +#ifdef HAVE_OPENSSL_RSA_H +#include +#endif +#ifdef HAVE_OPENSSL_DSA_H +#include +#endif +#endif /* HAVE_SSL */ + +#ifdef HAVE_SSL +#ifdef USE_GOST + +/** store GOST engine reference loaded into OpenSSL library */ +#ifdef OPENSSL_NO_ENGINE +int +gldns_key_EVP_load_gost_id(void) +{ + return 0; +} +void gldns_key_EVP_unload_gost(void) +{ +} +#else +ENGINE* gldns_gost_engine = NULL; + +int +gldns_key_EVP_load_gost_id(void) +{ + static int gost_id = 0; + const EVP_PKEY_ASN1_METHOD* meth; + ENGINE* e; + + if(gost_id) return gost_id; + + /* see if configuration loaded gost implementation from other engine*/ + meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1); + if(meth) { + EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); + return gost_id; + } + + /* see if engine can be loaded already */ + e = ENGINE_by_id("gost"); + if(!e) { + /* load it ourself, in case statically linked */ + ENGINE_load_builtin_engines(); + ENGINE_load_dynamic(); + e = ENGINE_by_id("gost"); + } + if(!e) { + /* no gost engine in openssl */ + return 0; + } + if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + ENGINE_finish(e); + ENGINE_free(e); + return 0; + } + + meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1); + if(!meth) { + /* algo not found */ + ENGINE_finish(e); + ENGINE_free(e); + return 0; + } + /* Note: do not ENGINE_finish and ENGINE_free the acquired engine + * on some platforms this frees up the meth and unloads gost stuff */ + gldns_gost_engine = e; + + EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); + return gost_id; +} + +void gldns_key_EVP_unload_gost(void) +{ + if(gldns_gost_engine) { + ENGINE_finish(gldns_gost_engine); + ENGINE_free(gldns_gost_engine); + gldns_gost_engine = NULL; + } +} +#endif /* ifndef OPENSSL_NO_ENGINE */ +#endif /* USE_GOST */ + +DSA * +gldns_key_buf2dsa_raw(unsigned char* key, size_t len) +{ + uint8_t T; + uint16_t length; + uint16_t offset; + DSA *dsa; + BIGNUM *Q; BIGNUM *P; + BIGNUM *G; BIGNUM *Y; + + if(len == 0) + return NULL; + T = (uint8_t)key[0]; + length = (64 + T * 8); + offset = 1; + + if (T > 8) { + return NULL; + } + if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length) + return NULL; + + Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL); + offset += SHA_DIGEST_LENGTH; + + P = BN_bin2bn(key+offset, (int)length, NULL); + offset += length; + + G = BN_bin2bn(key+offset, (int)length, NULL); + offset += length; + + Y = BN_bin2bn(key+offset, (int)length, NULL); + + /* create the key and set its properties */ + if(!Q || !P || !G || !Y || !(dsa = DSA_new())) { + BN_free(Q); + BN_free(P); + BN_free(G); + BN_free(Y); + return NULL; + } + +#if defined(HAVE_DSA_SET0_PQG) && defined(HAVE_DSA_SET0_KEY) + if (!DSA_set0_pqg(dsa, P, Q, G)) { + /* QPG not yet attached, need to free */ + BN_free(Q); + BN_free(P); + BN_free(G); + + DSA_free(dsa); + BN_free(Y); + return NULL; + } + if (!DSA_set0_key(dsa, Y, NULL)) { + /* QPG attached, cleaned up by DSA_fre() */ + DSA_free(dsa); + BN_free(Y); + return NULL; + } +#else +# ifndef S_SPLINT_S + dsa->p = P; + dsa->q = Q; + dsa->g = G; + dsa->pub_key = Y; +# endif /* splint */ +#endif + + return dsa; +} + +RSA * +gldns_key_buf2rsa_raw(unsigned char* key, size_t len) +{ + uint16_t offset; + uint16_t exp; + uint16_t int16; + RSA *rsa; + BIGNUM *modulus; + BIGNUM *exponent; + + if (len == 0) + return NULL; + if (key[0] == 0) { + if(len < 3) + return NULL; + memmove(&int16, key+1, 2); + exp = ntohs(int16); + offset = 3; + } else { + exp = key[0]; + offset = 1; + } + + /* key length at least one */ + if(len < (size_t)offset + exp + 1) + return NULL; + + /* Exponent */ + exponent = BN_new(); + if(!exponent) return NULL; + (void) BN_bin2bn(key+offset, (int)exp, exponent); + offset += exp; + + /* Modulus */ + modulus = BN_new(); + if(!modulus) { + BN_free(exponent); + return NULL; + } + /* length of the buffer must match the key length! */ + (void) BN_bin2bn(key+offset, (int)(len - offset), modulus); + + rsa = RSA_new(); + if(!rsa) { + BN_free(exponent); + BN_free(modulus); + return NULL; + } + +#if defined(HAVE_RSA_SET0_KEY) + if (!RSA_set0_key(rsa, modulus, exponent, NULL)) { + BN_free(exponent); + BN_free(modulus); + RSA_free(rsa); + return NULL; + } +#else +# ifndef S_SPLINT_S + rsa->n = modulus; + rsa->e = exponent; +# endif /* splint */ +#endif + + return rsa; +} + +#ifdef USE_GOST +EVP_PKEY* +gldns_gost2pkey_raw(unsigned char* key, size_t keylen) +{ + /* prefix header for X509 encoding */ + uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, + 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, + 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, + 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40}; + unsigned char encoded[37+64]; + const unsigned char* pp; + if(keylen != 64) { + /* key wrong size */ + return NULL; + } + + /* create evp_key */ + memmove(encoded, asn, 37); + memmove(encoded+37, key, 64); + pp = (unsigned char*)&encoded[0]; + + return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded)); +} +#endif /* USE_GOST */ + +#ifdef USE_ECDSA +EVP_PKEY* +gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo) +{ + unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */ + const unsigned char* pp = buf; + EVP_PKEY *evp_key; + EC_KEY *ec; + /* check length, which uncompressed must be 2 bignums */ + if(algo == GLDNS_ECDSAP256SHA256) { + if(keylen != 2*256/8) return NULL; + ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + } else if(algo == GLDNS_ECDSAP384SHA384) { + if(keylen != 2*384/8) return NULL; + ec = EC_KEY_new_by_curve_name(NID_secp384r1); + } else ec = NULL; + if(!ec) return NULL; + if(keylen+1 > sizeof(buf)) { /* sanity check */ + EC_KEY_free(ec); + return NULL; + } + /* prepend the 0x02 (from docs) (or actually 0x04 from implementation + * of openssl) for uncompressed data */ + buf[0] = POINT_CONVERSION_UNCOMPRESSED; + memmove(buf+1, key, keylen); + if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) { + EC_KEY_free(ec); + return NULL; + } + evp_key = EVP_PKEY_new(); + if(!evp_key) { + EC_KEY_free(ec); + return NULL; + } + if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) { + EVP_PKEY_free(evp_key); + EC_KEY_free(ec); + return NULL; + } + return evp_key; +} +#endif /* USE_ECDSA */ + +#ifdef USE_ED25519 +EVP_PKEY* +gldns_ed255192pkey_raw(const unsigned char* key, size_t keylen) +{ + /* ASN1 for ED25519 is 302a300506032b6570032100 <32byteskey> */ + uint8_t pre[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, + 0x70, 0x03, 0x21, 0x00}; + int pre_len = 12; + uint8_t buf[256]; + EVP_PKEY *evp_key; + /* pp gets modified by d2i() */ + const unsigned char* pp = (unsigned char*)buf; + if(keylen != 32 || keylen + pre_len > sizeof(buf)) + return NULL; /* wrong length */ + memmove(buf, pre, pre_len); + memmove(buf+pre_len, key, keylen); + evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); + return evp_key; +} +#endif /* USE_ED25519 */ + +#ifdef USE_ED448 +EVP_PKEY* +gldns_ed4482pkey_raw(const unsigned char* key, size_t keylen) +{ + /* ASN1 for ED448 is 3043300506032b6571033a00 <57byteskey> */ + uint8_t pre[] = {0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, + 0x71, 0x03, 0x3a, 0x00}; + int pre_len = 12; + uint8_t buf[256]; + EVP_PKEY *evp_key; + /* pp gets modified by d2i() */ + const unsigned char* pp = (unsigned char*)buf; + if(keylen != 57 || keylen + pre_len > sizeof(buf)) + return NULL; /* wrong length */ + memmove(buf, pre, pre_len); + memmove(buf+pre_len, key, keylen); + evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen)); + return evp_key; +} +#endif /* USE_ED448 */ + +int +gldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest, + const EVP_MD* md) +{ + EVP_MD_CTX* ctx; + ctx = EVP_MD_CTX_create(); + if(!ctx) + return 0; + if(!EVP_DigestInit_ex(ctx, md, NULL) || + !EVP_DigestUpdate(ctx, data, len) || + !EVP_DigestFinal_ex(ctx, dest, NULL)) { + EVP_MD_CTX_destroy(ctx); + return 0; + } + EVP_MD_CTX_destroy(ctx); + return 1; +} +#endif /* HAVE_SSL */ diff --git a/src/openssl/keyraw-internal.h b/src/openssl/keyraw-internal.h new file mode 100644 index 00000000..92717c95 --- /dev/null +++ b/src/openssl/keyraw-internal.h @@ -0,0 +1,110 @@ +/* + * keyraw.h -- raw key and signature access and conversion - OpenSSL + * + * Copyright (c) 2005-2008, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + * + */ + +/** + * \file + * + * raw key and signature access and conversion + * + * Since those functions heavily rely op cryptographic operations, + * this module is dependent on openssl. + * + */ + +#ifndef GLDNS_KEYRAW_INTERNAL_H +#define GLDNS_KEYRAW_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif +#if GLDNS_BUILD_CONFIG_HAVE_SSL +# include +# include + +/** + * Get the PKEY id for GOST, loads GOST into openssl as a side effect. + * Only available if GOST is compiled into the library and openssl. + * \return the gost id for EVP_CTX creation. + */ +int gldns_key_EVP_load_gost_id(void); + +/** Release the engine reference held for the GOST engine. */ +void gldns_key_EVP_unload_gost(void); + +/** + * Like gldns_key_buf2dsa, but uses raw buffer. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return a DSA * structure with the key material + */ +DSA *gldns_key_buf2dsa_raw(unsigned char* key, size_t len); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with GOST. + * \param[in] key data to convert + * \param[in] keylen length of the key data + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_gost2pkey_raw(unsigned char* key, size_t keylen); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with ECDSA. + * \param[in] key data to convert + * \param[in] keylen length of the key data + * \param[in] algo precise algorithm to initialize ECC group values. + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo); + +/** + * Like gldns_key_buf2rsa, but uses raw buffer. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return a RSA * structure with the key material + */ +RSA *gldns_key_buf2rsa_raw(unsigned char* key, size_t len); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with ED25519. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_ed255192pkey_raw(const unsigned char* key, size_t len); + +/** + * Converts a holding buffer with key material to EVP PKEY in openssl. + * Only available if ldns was compiled with ED448. + * \param[in] key the uncompressed wireformat of the key. + * \param[in] len length of key data + * \return the key or NULL on error. + */ +EVP_PKEY* gldns_ed4482pkey_raw(const unsigned char* key, size_t len); + +/** + * Utility function to calculate hash using generic EVP_MD pointer. + * \param[in] data the data to hash. + * \param[in] len length of data. + * \param[out] dest the destination of the hash, must be large enough. + * \param[in] md the message digest to use. + * \return true if worked, false on failure. + */ +int gldns_digest_evp(unsigned char* data, unsigned int len, + unsigned char* dest, const EVP_MD* md); + +#endif /* GLDNS_BUILD_CONFIG_HAVE_SSL */ + +#ifdef __cplusplus +} +#endif + +#endif /* GLDNS_KEYRAW_INTERNAL_H */ diff --git a/src/openssl/pubkey-pinning-internal.c b/src/openssl/pubkey-pinning-internal.c new file mode 100644 index 00000000..d18103de --- /dev/null +++ b/src/openssl/pubkey-pinning-internal.c @@ -0,0 +1,90 @@ +/** + * + * /brief functions for Public Key Pinning + * + */ + +/* + * Copyright (c) 2015, Daniel Kahn Gillmor + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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. + */ + +/** + * getdns Public Key Pinning + * + * a public key pinset is a list of dicts. each dict should have a + * "digest" and a "value". + * + * "digest": a string indicating the type of digest. at the moment, we + * only support a "digest" of "sha256". + * + * "value": a binary representation of the digest provided. + * + * given a such a pinset, we should be able to validate a chain + * properly according to section 2.6 of RFC 7469. + */ +#include "config.h" +#include "debug.h" +#include +#include +#include +#include +#include +#include +#include "context.h" +#include "util-internal.h" + +#include "pubkey-pinning-internal.h" + +/* we only support sha256 at the moment. adding support for another + digest is more complex than just adding another entry here. in + particular, you'll probably need a match for a particular cert + against all supported algorithms. better to wait on doing that + until it is a better-understood problem (i.e. wait until hpkp is + updated and follow the guidance in rfc7469bis) +*/ + +/* b64 turns every 3 octets (or fraction thereof) into 4 octets */ +#define B64_ENCODED_SHA256_LENGTH (((SHA256_DIGEST_LENGTH + 2)/3) * 4) +getdns_return_t _getdns_decode_base64(const char* str, uint8_t* res, size_t res_size) +{ + BIO *bio = NULL; + char inbuf[B64_ENCODED_SHA256_LENGTH + 1]; + getdns_return_t ret = GETDNS_RETURN_GOOD; + + /* openssl needs a trailing newline to base64 decode */ + memcpy(inbuf, str, B64_ENCODED_SHA256_LENGTH); + inbuf[B64_ENCODED_SHA256_LENGTH] = '\n'; + + bio = BIO_push(BIO_new(BIO_f_base64()), + BIO_new_mem_buf(inbuf, sizeof(inbuf))); + if (BIO_read(bio, res, res_size) != (int) res_size) + ret = GETDNS_RETURN_GENERIC_ERROR; + + BIO_free_all(bio); + return ret; +} + +/* pubkey-pinning.c */ diff --git a/src/openssl/pubkey-pinning-internal.h b/src/openssl/pubkey-pinning-internal.h new file mode 100644 index 00000000..fc2511d0 --- /dev/null +++ b/src/openssl/pubkey-pinning-internal.h @@ -0,0 +1,42 @@ +/** + * + * /brief internal functions for dealing with pubkey pinsets + * + */ + +/* + * Copyright (c) 2015 ACLU + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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. + */ + +#ifndef PUBKEY_PINNING_INTERNAL_H_ +#define PUBKEY_PINNING_INTERNAL_H_ + +#include + +getdns_return_t _getdns_decode_base64(const char* str, uint8_t* res, size_t res_size); + +#endif +/* pubkey-pinning-internal.h */ diff --git a/src/openssl/tls-internal.h b/src/openssl/tls-internal.h new file mode 100644 index 00000000..e640150d --- /dev/null +++ b/src/openssl/tls-internal.h @@ -0,0 +1,91 @@ +/** + * + * \file tls-internal.h + * @brief getdns TLS implementation-specific items + */ + +/* + * Copyright (c) 2018-2019, NLnet Labs + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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. + */ + +#ifndef _GETDNS_TLS_INTERNAL_H +#define _GETDNS_TLS_INTERNAL_H + +#include +#include +#include +#include + +#include "getdns/getdns.h" + +#ifndef HAVE_DECL_SSL_CTX_SET1_CURVES_LIST +#define HAVE_TLS_CTX_CURVES_LIST 0 +#else +#define HAVE_TLS_CTX_CURVES_LIST (HAVE_DECL_SSL_CTX_SET1_CURVES_LIST) +#endif +#ifndef HAVE_DECL_SSL_SET1_CURVES_LIST +#define HAVE_TLS_CONN_CURVES_LIST 0 +#else +#define HAVE_TLS_CONN_CURVES_LIST (HAVE_DECL_SSL_SET1_CURVES_LIST) +#endif + +#define GETDNS_TLS_MAX_DIGEST_LENGTH (EVP_MAX_MD_SIZE) + +typedef struct sha256_pin sha256_pin_t; +typedef struct getdns_log_config getdns_log_config; + +typedef struct _getdns_tls_context { + SSL_CTX* ssl; + const getdns_log_config* log; +} _getdns_tls_context; + +typedef struct _getdns_tls_connection { + SSL* ssl; + const getdns_log_config* log; +#if defined(USE_DANESSL) + const char* auth_name; + sha256_pin_t* pinset; +#endif +} _getdns_tls_connection; + +typedef struct _getdns_tls_session { + SSL_SESSION* ssl; +} _getdns_tls_session; + +typedef struct _getdns_tls_x509 +{ + X509* ssl; +} _getdns_tls_x509; + +typedef struct _getdns_tls_hmac +{ + HMAC_CTX *ctx; +#ifndef HAVE_HMAC_CTX_NEW + HMAC_CTX ctx_space; +#endif +} _getdns_tls_hmac; + +#endif /* _GETDNS_TLS_INTERNAL_H */ diff --git a/src/openssl/tls.c b/src/openssl/tls.c new file mode 100644 index 00000000..33e37a4c --- /dev/null +++ b/src/openssl/tls.c @@ -0,0 +1,1278 @@ +/** + * + * \file tls.c + * @brief getdns TLS functions + */ + +/* + * Copyright (c) 2018-2019, NLnet Labs + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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 "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "debug.h" +#include "context.h" +#include "const-info.h" + +#ifdef USE_DANESSL +# include "ssl_dane/danessl.h" +#endif + +#include "tls.h" + +/* Double check configure has worked as expected. */ +#if defined(USE_DANESSL) && \ + (defined(HAVE_SSL_DANE_ENABLE) || \ + defined(HAVE_OPENSSL_INIT_CRYPTO) || \ + defined(HAVE_SSL_CTX_DANE_ENABLE)) +#error Configure error USE_DANESSL defined with OpenSSL 1.1 functions! +#endif + +/* Cipher suites recommended in RFC7525. */ +static char const * const _getdns_tls_context_default_cipher_list = +#ifndef HAVE_SSL_CTX_SET_CIPHERSUITES + "TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:" + "TLS13-CHACHA20-POLY1305-SHA256:" +#endif + "EECDH+AESGCM:EECDH+CHACHA20"; + +static char const * const _getdns_tls_context_default_cipher_suites = + "TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:" + "TLS_CHACHA20_POLY1305_SHA256"; + +static char const * const _getdns_tls_connection_opportunistic_cipher_list = + "DEFAULT"; + +static int _getdns_tls_verify_always_ok(int ok, X509_STORE_CTX *ctx) +{ +# if defined(STUB_DEBUG) && STUB_DEBUG + char buf[8192]; + X509 *cert; + int err; + int depth; + + cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + if (cert) + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + else + strcpy(buf, ""); + DEBUG_STUB("DEBUG Cert verify: depth=%d verify=%d err=%d subject=%s errorstr=%s\n", depth, ok, err, buf, X509_verify_cert_error_string(err)); +# else /* defined(STUB_DEBUG) && STUB_DEBUG */ + (void)ok; + (void)ctx; +# endif /* #else defined(STUB_DEBUG) && STUB_DEBUG */ + return 1; +} + +static _getdns_tls_x509* _getdns_tls_x509_new(struct mem_funcs* mfs, X509* cert) +{ + _getdns_tls_x509* res; + + if (!cert) + return NULL; + + res = GETDNS_MALLOC(*mfs, _getdns_tls_x509); + if (res) + res->ssl = cert; + + return res; +} + +static const EVP_MD* get_digester(int algorithm) +{ + const EVP_MD* digester; + + switch (algorithm) { +#ifdef HAVE_EVP_MD5 + case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break; +#endif +#ifdef HAVE_EVP_SHA1 + case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break; +#endif +#ifdef HAVE_EVP_SHA224 + case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break; +#endif +#ifdef HAVE_EVP_SHA256 + case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break; +#endif +#ifdef HAVE_EVP_SHA384 + case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break; +#endif +#ifdef HAVE_EVP_SHA512 + case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break; +#endif + default : digester = NULL; + } + + return digester; +} + +#if HAVE_DECL_SSL_SET_MIN_PROTO_VERSION +static int _getdns_tls_version2openssl_version(getdns_tls_version_t v) +{ + switch (v) { +# ifdef SSL3_VERSION + case GETDNS_SSL3 : return SSL3_VERSION; +# endif +# ifdef TLS1_VERSION + case GETDNS_TLS1 : return TLS1_VERSION; +# endif +# ifdef TLS1_1_VERSION + case GETDNS_TLS1_1: return TLS1_1_VERSION; +# endif +# ifdef TLS1_2_VERSION + case GETDNS_TLS1_2: return TLS1_2_VERSION; +# endif +# ifdef TLS1_3_VERSION + case GETDNS_TLS1_3: return TLS1_3_VERSION; +# endif + default : +# if defined(TLS_MAX_VERSION) + return TLS_MAX_VERSION; +# elif defined(TLS1_3_VERSION) + return TLS1_3_VERSION; +# elif defined(TLS1_2_VERSION) + return TLS1_2_VERSION; +# elif defined(TLS1_1_VERSION) + return TLS1_1_VERSION; +# elif defined(TLS1_VERSION) + return TLS1_VERSION; +# elif defined(SSL3_VERSION) + return SSL3_VERSION; +# else + return -1; +# endif + } +} +#endif + +#ifdef USE_WINSOCK +/* For windows, the CA trust store is not read by openssl. + Add code to open the trust store using wincrypt API and add + the root certs into openssl trust store */ +static int +add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx, const getdns_log_config* log) +{ + HCERTSTORE hSystemStore; + PCCERT_CONTEXT pTargetCert = NULL; + + _getdns_log(log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_DEBUG + , "%s: %s\n", STUB_DEBUG_SETUP_TLS, + , "Adding Windows certificates from system root store to CA store") + ; + + /* load just once per context lifetime for this version of getdns + TODO: dynamically update CA trust changes as they are available */ + assert(tls_ctx); + + /* Call wincrypt's CertOpenStore to open the CA root store. */ + + if ((hSystemStore = CertOpenStore( + CERT_STORE_PROV_SYSTEM, + 0, + 0, + /* NOTE: mingw does not have this const: replace with 1 << 16 from code + CERT_SYSTEM_STORE_CURRENT_USER, */ + 1 << 16, + L"root")) == 0) + { + _getdns_log(log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s\n", STUB_DEBUG_SETUP_TLS + , "Could not CertOpenStore()"); + return 0; + } + + X509_STORE* store = SSL_CTX_get_cert_store(tls_ctx); + if (!store) { + _getdns_log(log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s\n", STUB_DEBUG_SETUP_TLS + , "Could not SSL_CTX_get_cert_store()"); + return 0; + } + + /* failure if the CA store is empty or the call fails */ + if ((pTargetCert = CertEnumCertificatesInStore( + hSystemStore, pTargetCert)) == 0) { + _getdns_log(log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_NOTICE + , "%s: %s\n", STUB_DEBUG_SETUP_TLS + , "CA certificate store for Windows is empty."); + return 0; + } + /* iterate over the windows cert store and add to openssl store */ + do + { + X509 *cert1 = d2i_X509(NULL, + (const unsigned char **)&pTargetCert->pbCertEncoded, + pTargetCert->cbCertEncoded); + if (!cert1) { + /* return error if a cert fails */ + _getdns_log(log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR, + , "%s: %s %d:%s\n" + , STUB_DEBUG_SETUP_TLS + , "Unable to parse certificate in memory" + , ERR_get_error() + , ERR_error_string(ERR_get_error(), NULL)); + return 0; + } + else { + /* return error if a cert add to store fails */ + if (X509_STORE_add_cert(store, cert1) == 0) { + unsigned long error = ERR_peek_last_error(); + + /* Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the + * certificate is already in the store. */ + if(ERR_GET_LIB(error) != ERR_LIB_X509 || + ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { + _getdns_log(log + , GETDNS_LOG_SYS_STUB + , GETDNS_LOG_ERR + , "%s: %s %d:%s\n" + , STUB_DEBUG_SETUP_TLS + , "Error adding certificate" + , ERR_get_error() + , ERR_error_string( ERR_get_error() + , NULL) + ); + X509_free(cert1); + return 0; + } + } + X509_free(cert1); + } + } while ((pTargetCert = CertEnumCertificatesInStore( + hSystemStore, pTargetCert)) != 0); + + /* Clean up memory and quit. */ + if (pTargetCert) + CertFreeCertificateContext(pTargetCert); + if (hSystemStore) + { + if (!CertCloseStore(hSystemStore, 0)) { + _getdns_log(log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s\n", STUB_DEBUG_SETUP_TLS + , "Could not CertCloseStore()"); + return 0; + } + } + _getdns_log(log, GETDNS_LOG_SYS_STUB, GETDNS_LOG_INFO + , "%s: %s\n", STUB_DEBUG_SETUP_TLS + , "Completed adding Windows certificates to CA store successfully") + ; + return 1; +} +#endif + +void _getdns_tls_init() +{ +#ifdef HAVE_OPENSSL_INIT_CRYPTO + OPENSSL_init_crypto( OPENSSL_INIT_ADD_ALL_CIPHERS + | OPENSSL_INIT_ADD_ALL_DIGESTS + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); + (void)OPENSSL_init_ssl(0, NULL); +#else + OpenSSL_add_all_algorithms(); + SSL_library_init(); + +# ifdef USE_DANESSL + (void) DANESSL_library_init(); +# endif +#endif +} + +_getdns_tls_context* _getdns_tls_context_new(struct mem_funcs* mfs, const getdns_log_config* log) +{ + _getdns_tls_context* res; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_context))) + return NULL; + + res->log = log; + + /* Create client context, use TLS v1.2 only for now */ +# ifdef HAVE_TLS_CLIENT_METHOD + res->ssl = SSL_CTX_new(TLS_client_method()); +# else + res->ssl = SSL_CTX_new(TLSv1_2_client_method()); +# endif + if(res->ssl == NULL) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error creating TLS context" + , ssl_err); + GETDNS_FREE(*mfs, res); + return NULL; + } + return res; +} + +getdns_return_t _getdns_tls_context_free(struct mem_funcs* mfs, _getdns_tls_context* ctx) +{ + if (!ctx || !ctx->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + SSL_CTX_free(ctx->ssl); + GETDNS_FREE(*mfs, ctx); + return GETDNS_RETURN_GOOD; +} + +void _getdns_tls_context_pinset_init(_getdns_tls_context* ctx) +{ + int osr; + +#if defined(HAVE_SSL_CTX_DANE_ENABLE) + osr = SSL_CTX_dane_enable(ctx->ssl); +#elif defined(USE_DANESSL) + osr = DANESSL_CTX_init(ctx->ssl); +#else +#error Must have either DANE SSL or OpenSSL v1.1. +#endif + if (!osr) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_WARNING + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Could not enable DANE on TLX context" + , ssl_err); + } +} + +getdns_return_t _getdns_tls_context_set_min_max_tls_version(_getdns_tls_context* ctx, getdns_tls_version_t min, getdns_tls_version_t max) +{ +#if HAVE_DECL_SSL_SET_MIN_PROTO_VERSION + char ssl_err[256]; + int min_ssl = _getdns_tls_version2openssl_version(min); + int max_ssl = _getdns_tls_version2openssl_version(max); + + if (!ctx || !ctx->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + if (min && !SSL_CTX_set_min_proto_version(ctx->ssl, min_ssl)) { + struct const_info* ci = _getdns_get_const_info(min); + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS context with " + "minimum TLS version" + , ci->name + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } + if (max && !SSL_CTX_set_max_proto_version(ctx->ssl, max_ssl)) { + struct const_info* ci = _getdns_get_const_info(min); + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS context with " + "minimum TLS version" + , ci->name + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } + return GETDNS_RETURN_GOOD; +#else + /* + * We've used TLSv1_2_client_method() creating the context, so + * error if they asked for anything other than TLS 1.2 or better. + */ + (void) ctx; + if ((!min || min == GETDNS_TLS1_2) && !max) + return GETDNS_RETURN_GOOD; + + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s\n" + , STUB_DEBUG_SETUP_TLS + , "This version of OpenSSL does not " + "support setting of minimum or maximum " + "TLS versions"); + return GETDNS_RETURN_NOT_IMPLEMENTED; +#endif +} + +const char* _getdns_tls_context_get_default_cipher_list() +{ + return _getdns_tls_context_default_cipher_list; +} + +getdns_return_t _getdns_tls_context_set_cipher_list(_getdns_tls_context* ctx, const char* list) +{ + if (!ctx || !ctx->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (!list) + list = _getdns_tls_context_default_cipher_list; + + if (!SSL_CTX_set_cipher_list(ctx->ssl, list)) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS context with " + "cipher list" + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } + return GETDNS_RETURN_GOOD; +} + +const char* _getdns_tls_context_get_default_cipher_suites() +{ + return _getdns_tls_context_default_cipher_suites; +} + +getdns_return_t _getdns_tls_context_set_cipher_suites(_getdns_tls_context* ctx, const char* list) +{ + if (!ctx || !ctx->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES + if (!list) + list = _getdns_tls_context_default_cipher_suites; + + if (!SSL_CTX_set_ciphersuites(ctx->ssl, list)) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS context with " + "cipher suites" + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } +#else + if (list) { + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s\n" + , STUB_DEBUG_SETUP_TLS + , "This version of OpenSSL does not " + "support configuring cipher suites"); + return GETDNS_RETURN_NOT_IMPLEMENTED; + } +#endif + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_context_set_curves_list(_getdns_tls_context* ctx, const char* list) +{ + if (!ctx || !ctx->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; +#if HAVE_TLS_CTX_CURVES_LIST + if (list && + !SSL_CTX_set1_curves_list(ctx->ssl, list)) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS context with " + "curves list" + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } +#else + if (list) { + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR + , "%s: %s\n" + , STUB_DEBUG_SETUP_TLS + , "This version of OpenSSL does not " + "support configuring curves list"); + return GETDNS_RETURN_NOT_IMPLEMENTED; + } +#endif + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_context_set_ca(_getdns_tls_context* ctx, const char* file, const char* path) +{ + if (!ctx || !ctx->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + if (file || path) { + if (!SSL_CTX_load_verify_locations(ctx->ssl, file, path)) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err + , sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB + , GETDNS_LOG_WARNING + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Could not load verify locations" + , ssl_err); + } else { + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB + , GETDNS_LOG_DEBUG + , "%s: %s\n" + , STUB_DEBUG_SETUP_TLS + , "Verify locations loaded"); + } + return GETDNS_RETURN_GOOD; /* pass */ + } +#ifndef USE_WINSOCK + else if (SSL_CTX_set_default_verify_paths(ctx->ssl)) + return GETDNS_RETURN_GOOD; + else { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err + , sizeof(ssl_err)); + _getdns_log(ctx->log + , GETDNS_LOG_SYS_STUB + , GETDNS_LOG_WARNING + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Could not load default verify locations" + , ssl_err); + } +#else + else if (add_WIN_cacerts_to_openssl_store(ctx->ssl, ctx->log)) + return GETDNS_RETURN_GOOD; +#endif /* USE_WINSOCK */ + return GETDNS_RETURN_GENERIC_ERROR; +} + +_getdns_tls_connection* _getdns_tls_connection_new(struct mem_funcs* mfs, _getdns_tls_context* ctx, int fd, const getdns_log_config* log) +{ + _getdns_tls_connection* res; + + if (!ctx || !ctx->ssl) + return NULL; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_connection))) + return NULL; + + res->ssl = SSL_new(ctx->ssl); + if (!res->ssl) { + GETDNS_FREE(*mfs, res); + return NULL; + } + + if (!SSL_set_fd(res->ssl, fd)) { + SSL_free(res->ssl); + GETDNS_FREE(*mfs, res); + return NULL; + } + + res->log = log; + + /* Connection is a client. */ + SSL_set_connect_state(res->ssl); + + /* If non-application data received, retry read. */ + SSL_set_mode(res->ssl, SSL_MODE_AUTO_RETRY); + return res; +} + +getdns_return_t _getdns_tls_connection_free(struct mem_funcs* mfs, _getdns_tls_connection* conn) +{ + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + SSL_free(conn->ssl); + GETDNS_FREE(*mfs, conn); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_shutdown(_getdns_tls_connection* conn) +{ + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + +#ifdef USE_DANESSL + DANESSL_cleanup(conn->ssl); +#endif + + switch (SSL_shutdown(conn->ssl)) { + case 0: return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + case 1: return GETDNS_RETURN_GOOD; + default: return GETDNS_RETURN_GENERIC_ERROR; + } +} + +getdns_return_t _getdns_tls_connection_set_min_max_tls_version(_getdns_tls_connection* conn, getdns_tls_version_t min, getdns_tls_version_t max) +{ +#if HAVE_DECL_SSL_SET_MIN_PROTO_VERSION + char ssl_err[256]; + int min_ssl = _getdns_tls_version2openssl_version(min); + int max_ssl = _getdns_tls_version2openssl_version(max); + + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + if (min && !SSL_set_min_proto_version(conn->ssl, min_ssl)) { + struct const_info* ci = _getdns_get_const_info(min); + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS connection with " + "minimum TLS version" + , ci->name + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } + if (max && !SSL_set_max_proto_version(conn->ssl, max_ssl)) { + struct const_info* ci = _getdns_get_const_info(min); + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS connection with " + "minimum TLS version" + , ci->name + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } + return GETDNS_RETURN_GOOD; +#else + /* + * We've used TLSv1_2_client_method() creating the context, so + * error if they asked for anything other than TLS 1.2 or better. + */ + (void) conn; + if ((!min || min == GETDNS_TLS1_2) && !max) + return GETDNS_RETURN_GOOD; + + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s\n" + , STUB_DEBUG_SETUP_TLS + , "This version of OpenSSL does not " + "support setting of minimum or maximum " + "TLS versions"); + return GETDNS_RETURN_NOT_IMPLEMENTED; +#endif +} + +getdns_return_t _getdns_tls_connection_set_cipher_list(_getdns_tls_connection* conn, const char* list) +{ + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (!list) + list = _getdns_tls_connection_opportunistic_cipher_list; + + if (!SSL_set_cipher_list(conn->ssl, list)) { + + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS connection with " + "cipher list" + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_set_cipher_suites(_getdns_tls_connection* conn, const char* list) +{ + if (!conn || !conn->ssl || !list) + return GETDNS_RETURN_INVALID_PARAMETER; + +#ifdef HAVE_SSL_SET_CIPHERSUITES + if (!SSL_set_ciphersuites(conn->ssl, list)) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS connection with " + "cipher suites" + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } +#else + if (list) { + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s\n" + , STUB_DEBUG_SETUP_TLS + , "This version of OpenSSL does not " + "support configuring cipher suites"); + return GETDNS_RETURN_NOT_IMPLEMENTED; + } +#endif + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_set_curves_list(_getdns_tls_connection* conn, const char* list) +{ + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; +#if HAVE_TLS_CONN_CURVES_LIST + if (list && + !SSL_set1_curves_list(conn->ssl, list)) { + char ssl_err[256]; + ERR_error_string_n( ERR_get_error() + , ssl_err, sizeof(ssl_err)); + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s (%s)\n" + , STUB_DEBUG_SETUP_TLS + , "Error configuring TLS connection with " + "curves list" + , ssl_err); + return GETDNS_RETURN_BAD_CONTEXT; + } +#else + if (list) { + _getdns_log(conn->log + , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR + , "%s: %s\n" + , STUB_DEBUG_SETUP_TLS + , "This version of OpenSSL does not " + "support configuring curves list"); + return GETDNS_RETURN_NOT_IMPLEMENTED; + } +#endif + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_set_session(_getdns_tls_connection* conn, _getdns_tls_session* s) +{ + if (!conn || !conn->ssl || !s || !s->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + if (!SSL_set_session(conn->ssl, s->ssl)) + return GETDNS_RETURN_GENERIC_ERROR; + return GETDNS_RETURN_GOOD; +} + +_getdns_tls_session* _getdns_tls_connection_get_session(struct mem_funcs* mfs, _getdns_tls_connection* conn) +{ + _getdns_tls_session* res; + + if (!conn || !conn->ssl) + return NULL; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_session))) + return NULL; + + res->ssl = SSL_get1_session(conn->ssl); + if (!res->ssl) { + GETDNS_FREE(*mfs, res); + return NULL; + } + + return res; +} + +const char* _getdns_tls_connection_get_version(_getdns_tls_connection* conn) +{ + if (!conn || !conn->ssl) + return NULL; + return SSL_get_version(conn->ssl); +} + +getdns_return_t _getdns_tls_connection_do_handshake(_getdns_tls_connection* conn) +{ + int r; + int err; + + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + + ERR_clear_error(); + r = SSL_do_handshake(conn->ssl); + if (r == 1) + return GETDNS_RETURN_GOOD; + err = SSL_get_error(conn->ssl, r); + switch (err) { + case SSL_ERROR_WANT_READ: + return GETDNS_RETURN_TLS_WANT_READ; + + case SSL_ERROR_WANT_WRITE: + return GETDNS_RETURN_TLS_WANT_WRITE; + + default: + return GETDNS_RETURN_GENERIC_ERROR; + } +} + +_getdns_tls_x509* _getdns_tls_connection_get_peer_certificate(struct mem_funcs* mfs, _getdns_tls_connection* conn) +{ + if (!conn || !conn->ssl) + return NULL; + + return _getdns_tls_x509_new(mfs, SSL_get_peer_certificate(conn->ssl)); +} + +getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn) +{ + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (SSL_session_reused(conn->ssl)) + return GETDNS_RETURN_GOOD; + else + return GETDNS_RETURN_TLS_CONNECTION_FRESH; +} + +getdns_return_t _getdns_tls_connection_setup_hostname_auth(_getdns_tls_connection* conn, const char* auth_name) +{ + if (!conn || !conn->ssl || !auth_name) + return GETDNS_RETURN_INVALID_PARAMETER; + +#if defined(HAVE_SSL_DANE_ENABLE) + SSL_set_tlsext_host_name(conn->ssl, auth_name); + /* Set up native OpenSSL hostname verification */ + X509_VERIFY_PARAM *param; + param = SSL_get0_param(conn->ssl); + X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + X509_VERIFY_PARAM_set1_host(param, auth_name, 0); +#elif defined(USE_DANESSL) + /* Stash auth name away for use in cert verification. */ + conn->auth_name = auth_name; +#else +#error Must have either DANE SSL or OpenSSL v1.1. +#endif + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* conn, const char* auth_name, const sha256_pin_t* pinset) +{ + if (!conn || !conn->ssl || !auth_name) + return GETDNS_RETURN_INVALID_PARAMETER; + +#if defined(USE_DANE_SSL) + /* Stash auth name and pinset away for use in cert verification. */ + conn->auth_name = auth_name; + conn->pinset = pinset; +#endif + +#if defined(HAVE_SSL_DANE_ENABLE) + int osr = SSL_dane_enable(conn->ssl, *auth_name ? auth_name : NULL); + (void) osr; + DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr); + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); + const sha256_pin_t *pin_p; + size_t n_pins = 0; + for (pin_p = pinset; pin_p; pin_p = pin_p->next) { + osr = SSL_dane_tlsa_add(conn->ssl, 2, 1, 1, + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + osr = SSL_dane_tlsa_add(conn->ssl, 3, 1, 1, + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + } +#elif defined(USE_DANESSL) + if (pinset) { + const char *auth_names[2] = { auth_name, NULL }; + int osr = DANESSL_init(conn->ssl, + *auth_name ? auth_name : NULL, + *auth_name ? auth_names : NULL); + (void) osr; + DEBUG_STUB("%s %-35s: DEBUG: DANESSL_init(\"%s\") -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, auth_name, osr); + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); + const sha256_pin_t *pin_p; + size_t n_pins = 0; + for (pin_p = pinset; pin_p; pin_p = pin_p->next) { + osr = DANESSL_add_tlsa(conn->ssl, 3, 1, "sha256", + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + osr = DANESSL_add_tlsa(conn->ssl, 2, 1, "sha256", + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + } + } else { + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); + } +#else +#error Must have either DANE SSL or OpenSSL v1.1. +#endif + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_certificate_verify(_getdns_tls_connection* conn, long* errnum, const char** errmsg) +{ + if (!conn || !conn->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + + long verify_result = SSL_get_verify_result(conn->ssl); + + /* Since we don't have DANE validation yet, DANE validation + * failures are always pinset validation failures */ + + switch (verify_result) { + case X509_V_OK: +#if defined(USE_DANESSL) + { + getdns_return_t res = GETDNS_RETURN_GOOD; + X509* peer_cert = SSL_get_peer_certificate(conn->ssl); + if (peer_cert) { + if (conn->auth_name[0] && + X509_check_host(peer_cert, + conn->auth_name, + strlen(conn->auth_name), + X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, + NULL) <= 0) { + if (errnum) + *errnum = 1; + if (errmsg) + *errmsg = "Hostname mismatch"; + res = GETDNS_RETURN_GENERIC_ERROR; + } + X509_free(peer_cert); + } + return res; + } +#else + return GETDNS_RETURN_GOOD; +#endif + +#if defined(HAVE_SSL_DANE_ENABLE) + case X509_V_ERR_DANE_NO_MATCH: + if (errnum) + *errnum = 0; + if (errmsg) + *errmsg = "Pinset validation failure"; + return GETDNS_RETURN_GENERIC_ERROR; + +#elif defined(USE_DANESSL) + case X509_V_ERR_CERT_UNTRUSTED: + if (conn->pinset && + !DANESSL_get_match_cert(conn->ssl, NULL, NULL, NULL)) { + if (errnum) + *errnum = 0; + if (errmsg) + *errmsg = "Pinset validation failure"; + return GETDNS_RETURN_GENERIC_ERROR; + } + break; +#else +#error Must have either DANE SSL or OpenSSL v1.1. +#endif + } + + /* General error if we get here. */ + if (errnum) + *errnum = verify_result; + if (errmsg) + *errmsg = X509_verify_cert_error_string(verify_result); + return GETDNS_RETURN_GENERIC_ERROR; +} + + +getdns_return_t _getdns_tls_connection_read(_getdns_tls_connection* conn, uint8_t* buf, size_t to_read, size_t* read) +{ + int sread; + + if (!conn || !conn->ssl || !read) + return GETDNS_RETURN_INVALID_PARAMETER; + + ERR_clear_error(); + sread = SSL_read(conn->ssl, buf, to_read); + if (sread <= 0) { + switch (SSL_get_error(conn->ssl, sread)) { + case SSL_ERROR_WANT_READ: + return GETDNS_RETURN_TLS_WANT_READ; + + case SSL_ERROR_WANT_WRITE: + return GETDNS_RETURN_TLS_WANT_WRITE; + + default: + return GETDNS_RETURN_GENERIC_ERROR; + } + } + + *read = sread; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_connection_write(_getdns_tls_connection* conn, uint8_t* buf, size_t to_write, size_t* written) +{ + int swritten; + + if (!conn || !conn->ssl || !written) + return GETDNS_RETURN_INVALID_PARAMETER; + + ERR_clear_error(); + swritten = SSL_write(conn->ssl, buf, to_write); + if (swritten <= 0) { + switch(SSL_get_error(conn->ssl, swritten)) { + case SSL_ERROR_WANT_READ: + /* SSL_write will not do partial writes, because + * SSL_MODE_ENABLE_PARTIAL_WRITE is not default, + * but the write could fail because of renegotiation. + * In that case SSL_get_error() will return + * SSL_ERROR_WANT_READ or, SSL_ERROR_WANT_WRITE. + * Return for retry in such cases. + */ + return GETDNS_RETURN_TLS_WANT_READ; + + case SSL_ERROR_WANT_WRITE: + return GETDNS_RETURN_TLS_WANT_WRITE; + + default: + return GETDNS_RETURN_GENERIC_ERROR; + } + } + + *written = swritten; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_session_free(struct mem_funcs* mfs, _getdns_tls_session* s) +{ + if (!s || !s->ssl) + return GETDNS_RETURN_INVALID_PARAMETER; + SSL_SESSION_free(s->ssl); + GETDNS_FREE(*mfs, s); + return GETDNS_RETURN_GOOD; +} + +getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict) +{ + if (! getdns_dict_set_int( + dict, "openssl_build_version_number", OPENSSL_VERSION_NUMBER) + +#ifdef HAVE_OPENSSL_VERSION_NUM + && ! getdns_dict_set_int( + dict, "openssl_version_number", OpenSSL_version_num()) +#endif +#ifdef HAVE_OPENSSL_VERSION + && ! getdns_dict_util_set_string( + dict, "openssl_version_string", OpenSSL_version(OPENSSL_VERSION)) + + && ! getdns_dict_util_set_string( + dict, "openssl_cflags", OpenSSL_version(OPENSSL_CFLAGS)) + + && ! getdns_dict_util_set_string( + dict, "openssl_built_on", OpenSSL_version(OPENSSL_BUILT_ON)) + + && ! getdns_dict_util_set_string( + dict, "openssl_platform", OpenSSL_version(OPENSSL_PLATFORM)) + + && ! getdns_dict_util_set_string( + dict, "openssl_dir", OpenSSL_version(OPENSSL_DIR)) + + && ! getdns_dict_util_set_string( + dict, "openssl_engines_dir", OpenSSL_version(OPENSSL_ENGINES_DIR)) +#endif + ) + return GETDNS_RETURN_GOOD; + return GETDNS_RETURN_GENERIC_ERROR; +} + +void _getdns_tls_x509_free(struct mem_funcs* mfs, _getdns_tls_x509* cert) +{ + if (cert && cert->ssl) + X509_free(cert->ssl); + GETDNS_FREE(*mfs, cert); +} + +int _getdns_tls_x509_to_der(struct mem_funcs* mfs, _getdns_tls_x509* cert, getdns_bindata* bindata) +{ + unsigned char* buf = NULL; + int len; + + if (!cert || !cert->ssl ) + return 0; + + if (bindata == NULL) + return i2d_X509(cert->ssl, NULL); + + len = i2d_X509(cert->ssl, &buf); + if (len == 0 || (bindata->data = GETDNS_XMALLOC(*mfs, uint8_t, len)) == NULL) { + bindata->size = 0; + bindata->data = NULL; + } else { + bindata->size = len; + (void) memcpy(bindata->data, buf, len); + OPENSSL_free(buf); + } + + return len; +} + +unsigned char* _getdns_tls_hmac_hash(struct mem_funcs* mfs, int algorithm, const void* key, size_t key_size, const void* data, size_t data_size, size_t* output_size) +{ + const EVP_MD* digester = get_digester(algorithm); + unsigned char* res; + unsigned int md_len; + + if (!digester) + return NULL; + + res = (unsigned char*) GETDNS_XMALLOC(*mfs, unsigned char, GETDNS_TLS_MAX_DIGEST_LENGTH); + if (!res) + return NULL; + + (void) HMAC(digester, key, key_size, data, data_size, res, &md_len); + + if (output_size) + *output_size = md_len; + return res; +} + +_getdns_tls_hmac* _getdns_tls_hmac_new(struct mem_funcs* mfs, int algorithm, const void* key, size_t key_size) +{ + const EVP_MD *digester = get_digester(algorithm); + _getdns_tls_hmac* res; + + if (!digester) + return NULL; + + if (!(res = GETDNS_MALLOC(*mfs, struct _getdns_tls_hmac))) + return NULL; + +#ifdef HAVE_HMAC_CTX_NEW + res->ctx = HMAC_CTX_new(); + if (!res->ctx) { + GETDNS_FREE(*mfs, res); + return NULL; + } +#else + res->ctx = &res->ctx_space; + HMAC_CTX_init(res->ctx); +#endif + if (!HMAC_Init_ex(res->ctx, key, key_size, digester, NULL)) { +#ifdef HAVE_HMAC_CTX_NEW + HMAC_CTX_free(res->ctx); +#endif + GETDNS_FREE(*mfs, res); + return NULL; + } + + return res; +} + +getdns_return_t _getdns_tls_hmac_add(_getdns_tls_hmac* h, const void* data, size_t data_size) +{ + if (!h || !h->ctx || !data) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (!HMAC_Update(h->ctx, data, data_size)) + return GETDNS_RETURN_GENERIC_ERROR; + else + return GETDNS_RETURN_GOOD; +} + +unsigned char* _getdns_tls_hmac_end(struct mem_funcs* mfs, _getdns_tls_hmac* h, size_t* output_size) +{ + unsigned char* res; + unsigned int md_len; + + res = (unsigned char*) GETDNS_XMALLOC(*mfs, unsigned char, GETDNS_TLS_MAX_DIGEST_LENGTH); + if (!res) + return NULL; + + (void) HMAC_Final(h->ctx, res, &md_len); + +#ifdef HAVE_HMAC_CTX_NEW + HMAC_CTX_free(h->ctx); +#endif + GETDNS_FREE(*mfs, h); + + if (output_size) + *output_size = md_len; + return res; +} + +void _getdns_tls_sha1(const void* data, size_t data_size, unsigned char* buf) +{ + SHA1(data, data_size, buf); +} + +void _getdns_tls_cookie_sha256(uint32_t secret, void* addr, size_t addrlen, unsigned char* buf, size_t* buflen) +{ + const EVP_MD *md; + EVP_MD_CTX *mdctx; + unsigned int md_len; + + md = EVP_sha256(); + mdctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, &secret, sizeof(secret)); + EVP_DigestUpdate(mdctx, addr, addrlen); + EVP_DigestFinal_ex(mdctx, buf, &md_len); + EVP_MD_CTX_destroy(mdctx); + + *buflen = md_len; +} + +/* tls.c */ diff --git a/src/util/val_secalgo.c b/src/openssl/val_secalgo.c similarity index 99% rename from src/util/val_secalgo.c rename to src/openssl/val_secalgo.c index 0613316c..c7158d82 100644 --- a/src/util/val_secalgo.c +++ b/src/openssl/val_secalgo.c @@ -91,6 +91,7 @@ log_crypto_error(const char* str, unsigned long e) /* buf now contains */ /* error:[error code]:[library name]:[function name]:[reason string] */ log_err("%s crypto %s", str, buf); + (void) str; /* In case log_err() does nothing. */ } /* return size of digest if supported, or 0 otherwise */ @@ -1351,21 +1352,21 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, #elif defined(HAVE_NETTLE) -#include "sha.h" -#include "bignum.h" -#include "macros.h" -#include "rsa.h" -#include "dsa.h" +#include +#include +#include +#include +#include #ifdef HAVE_NETTLE_DSA_COMPAT_H -#include "dsa-compat.h" +#include #endif -#include "asn1.h" +#include #ifdef USE_ECDSA -#include "ecdsa.h" -#include "ecc-curve.h" +#include +#include #endif #ifdef HAVE_NETTLE_EDDSA_H -#include "eddsa.h" +#include #endif static int diff --git a/src/util/auxiliary/validator/val_nsec3.h b/src/openssl/validator/val_nsec3.h similarity index 100% rename from src/util/auxiliary/validator/val_nsec3.h rename to src/openssl/validator/val_nsec3.h diff --git a/src/openssl/validator/val_secalgo.h b/src/openssl/validator/val_secalgo.h new file mode 100644 index 00000000..ef26cf34 --- /dev/null +++ b/src/openssl/validator/val_secalgo.h @@ -0,0 +1,53 @@ +#ifndef VAL_SECALGO_H_VALIDATOR +#define VAL_SECALGO_H_VALIDATOR + +#define sldns_buffer gldns_buffer + +#define nsec3_hash_algo_size_supported _getdns_nsec3_hash_algo_size_supported +#define secalgo_nsec3_hash _getdns_secalgo_nsec3_hash +#define secalgo_hash_sha256 _getdns_secalgo_hash_sha256 +#define ds_digest_size_supported _getdns_ds_digest_size_supported +#define secalgo_ds_digest _getdns_secalgo_ds_digest +#define dnskey_algo_id_is_supported _getdns_dnskey_algo_id_is_supported +#define verify_canonrrset _getdns_verify_canonrrset +#define sec_status _getdns_sec_status +#define sec_status_secure _getdns_sec_status_secure +#define sec_status_insecure _getdns_sec_status_insecure +#define sec_status_unchecked _getdns_sec_status_unchecked +#define sec_status_bogus _getdns_sec_status_bogus +#define fake_sha1 _getdns_fake_sha1 +#define fake_dsa _getdns_fake_dsa + + +#define NSEC3_HASH_SHA1 0x01 + +#define LDNS_SHA1 GLDNS_SHA1 +#define LDNS_SHA256 GLDNS_SHA256 +#define LDNS_SHA384 GLDNS_SHA384 +#define LDNS_HASH_GOST GLDNS_HASH_GOST +#define LDNS_RSAMD5 GLDNS_RSAMD5 +#define LDNS_DSA GLDNS_DSA +#define LDNS_DSA_NSEC3 GLDNS_DSA_NSEC3 +#define LDNS_RSASHA1 GLDNS_RSASHA1 +#define LDNS_RSASHA1_NSEC3 GLDNS_RSASHA1_NSEC3 +#define LDNS_RSASHA256 GLDNS_RSASHA256 +#define LDNS_RSASHA512 GLDNS_RSASHA512 +#define LDNS_ECDSAP256SHA256 GLDNS_ECDSAP256SHA256 +#define LDNS_ECDSAP384SHA384 GLDNS_ECDSAP384SHA384 +#define LDNS_ECC_GOST GLDNS_ECC_GOST +#define LDNS_ED25519 GLDNS_ED25519 +#define LDNS_ED448 GLDNS_ED448 +#define sldns_ed255192pkey_raw gldns_ed255192pkey_raw +#define sldns_ed4482pkey_raw gldns_ed4482pkey_raw +#define sldns_key_EVP_load_gost_id gldns_key_EVP_load_gost_id +#define sldns_digest_evp gldns_digest_evp +#define sldns_key_buf2dsa_raw gldns_key_buf2dsa_raw +#define sldns_key_buf2rsa_raw gldns_key_buf2rsa_raw +#define sldns_gost2pkey_raw gldns_gost2pkey_raw +#define sldns_ecdsa2pkey_raw gldns_ecdsa2pkey_raw +#define sldns_buffer_begin gldns_buffer_begin +#define sldns_buffer_limit gldns_buffer_limit + +#include "util/val_secalgo.h" + +#endif diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c index e7aae2f7..543d892e 100644 --- a/src/pubkey-pinning.c +++ b/src/pubkey-pinning.c @@ -48,18 +48,13 @@ #include "config.h" #include "debug.h" #include -#include -#include -#include -#include #include #include "context.h" #include "util-internal.h" #include "gldns/parseutil.h" -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) -#define X509_STORE_CTX_get0_untrusted(store) store->untrusted -#endif +#include "pubkey-pinning.h" +#include "pubkey-pinning-internal.h" /* we only support sha256 at the moment. adding support for another digest is more complex than just adding another entry here. in @@ -74,12 +69,10 @@ static const getdns_bindata sha256 = { .data = (uint8_t*)"sha256" }; - #define PIN_PREFIX "pin-sha256=\"" #define PIN_PREFIX_LENGTH (sizeof(PIN_PREFIX) - 1) /* b64 turns every 3 octets (or fraction thereof) into 4 octets */ #define B64_ENCODED_SHA256_LENGTH (((SHA256_DIGEST_LENGTH + 2)/3) * 4) - /* convert an HPKP-style pin description to an appropriate getdns data structure. An example string is: (with the quotes, without any leading or trailing whitespace): @@ -96,10 +89,8 @@ static const getdns_bindata sha256 = { getdns_dict *getdns_pubkey_pin_create_from_string( const getdns_context *context, const char *str) { - BIO *bio = NULL; size_t i; uint8_t buf[SHA256_DIGEST_LENGTH]; - char inbuf[B64_ENCODED_SHA256_LENGTH + 1]; getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; getdns_dict *out = NULL; @@ -119,15 +110,9 @@ getdns_dict *getdns_pubkey_pin_create_from_string( if (str[i++] != '\0') return NULL; - /* openssl needs a trailing newline to base64 decode */ - memcpy(inbuf, str + PIN_PREFIX_LENGTH, B64_ENCODED_SHA256_LENGTH); - inbuf[B64_ENCODED_SHA256_LENGTH] = '\n'; - - bio = BIO_push(BIO_new(BIO_f_base64()), - BIO_new_mem_buf(inbuf, sizeof(inbuf))); - if (BIO_read(bio, buf, sizeof(buf)) != sizeof(buf)) - goto fail; - + if (_getdns_decode_base64(str + PIN_PREFIX_LENGTH, buf, sizeof(buf)) != GETDNS_RETURN_GOOD) + goto fail; + if (context) out = getdns_dict_create_with_context(context); else @@ -141,12 +126,10 @@ getdns_dict *getdns_pubkey_pin_create_from_string( return out; fail: - BIO_free_all(bio); getdns_dict_destroy(out); return NULL; } - /* Test whether a given pinset is reasonable, including: * is it well-formed? @@ -306,261 +289,3 @@ _getdns_get_pubkey_pinset_list(const getdns_context *ctx, getdns_list_destroy(out); return r; } - -/* this should only happen once ever in the life of the library. it's - used to associate a getdns_context_t with an SSL_CTX, to be able to - do custom verification. - - see doc/HOWTO/proxy_certificates.txt as an example -*/ -static int -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) -_get_ssl_getdns_upstream_idx(void) -#else -_get_ssl_getdns_upstream_idx(X509_STORE *store) -#endif -{ - static volatile int idx = -1; - if (idx < 0) { -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) - CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); -#else - X509_STORE_lock(store); -#endif - if (idx < 0) - idx = SSL_get_ex_new_index(0, "associated getdns upstream", - NULL,NULL,NULL); -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) - CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); -#else - X509_STORE_unlock(store); -#endif - } - return idx; -} - -getdns_upstream* -_getdns_upstream_from_x509_store(X509_STORE_CTX *store) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) - int uidx = _get_ssl_getdns_upstream_idx(); -#else - int uidx = _get_ssl_getdns_upstream_idx(X509_STORE_CTX_get0_store(store)); -#endif - int sslidx = SSL_get_ex_data_X509_STORE_CTX_idx(); - const SSL *ssl; - - /* all *_get_ex_data() should return NULL on failure anyway */ - ssl = X509_STORE_CTX_get_ex_data(store, sslidx); - if (ssl) - return (getdns_upstream*) SSL_get_ex_data(ssl, uidx); - else - return NULL; - /* TODO: if we want more details about errors somehow, we - * might call ERR_get_error (see CRYPTO_set_ex_data(3ssl))*/ -} - -getdns_return_t -_getdns_associate_upstream_with_SSL(SSL *ssl, - getdns_upstream *upstream) -{ -#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) - int uidx = _get_ssl_getdns_upstream_idx(); -#else - int uidx = _get_ssl_getdns_upstream_idx(SSL_CTX_get_cert_store(SSL_get_SSL_CTX(ssl))); -#endif - if (SSL_set_ex_data(ssl, uidx, upstream)) - return GETDNS_RETURN_GOOD; - else - return GETDNS_RETURN_GENERIC_ERROR; - /* TODO: if we want more details about errors somehow, we - * might call ERR_get_error (see CRYPTO_set_ex_data(3ssl))*/ -} - -getdns_return_t -_getdns_verify_pinset_match(const getdns_upstream *upstream, - const sha256_pin_t *pinset, X509_STORE_CTX *store) -{ - X509 *x, *prev = NULL; - char x_name_spc[1024], *x_name, prev_name_spc[1024]; - int i, len; - unsigned char raw[4096]; - unsigned char *next; - unsigned char buf[sizeof(pinset->pin)]; - const sha256_pin_t *p; - - assert(pinset); - assert(store); - - /* start at the base of the chain (the end-entity cert) and - * make sure that some valid element of the chain does match - * the pinset. */ - - /* Testing with OpenSSL 1.0.1e-1 on debian indicates that - * store->untrusted holds the chain offered by the server in - * the order that the server offers it. If the server offers - * bogus certificates (that is, matching and valid certs that - * belong to private keys that the server does not control), - * the the verification will succeed (including this pinset - * check), but the handshake will fail outside of this - * verification. */ - - /* TODO: how do we handle raw public keys? */ - - for ( i = 0 - ; i < sk_X509_num(X509_STORE_CTX_get0_untrusted(store)) - ; i++, prev = x) { - x = sk_X509_value(X509_STORE_CTX_get0_untrusted(store), i); - x_name = NULL; - - if (upstream->upstreams - && _getdns_check_log(&upstream->upstreams->log, - GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG)) { - - x_name = X509_NAME_oneline( X509_get_subject_name(x) - , x_name_spc - , sizeof(x_name_spc)); - _getdns_upstream_log( upstream - , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG - , "%-40s : Verifying pinsets with cert: %d %s\n" - , upstream->addr_str, i, x_name); - } - if (i > 0) { - /* we ensure that "prev" is signed by "x" */ - EVP_PKEY *pkey = X509_get_pubkey(x); - int verified; - - if (!pkey) { - if (!upstream->upstreams - || !_getdns_check_log( - &upstream->upstreams->log - , GETDNS_LOG_UPSTREAM_STATS - , GETDNS_LOG_ERR - )) - return GETDNS_RETURN_GENERIC_ERROR; - - if (!x_name) - x_name = X509_NAME_oneline( - X509_get_subject_name(x) - , x_name_spc, sizeof(x_name_spc)); - _getdns_upstream_log( upstream - , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR - , "%-40s : Could not get pubkey from cert " - "cert: %d %s\n" - , upstream->addr_str, i, x_name); - return GETDNS_RETURN_GENERIC_ERROR; - } - verified = X509_verify(prev, pkey); - EVP_PKEY_free(pkey); - if (!verified) { - if (!upstream->upstreams - || !_getdns_check_log( - &upstream->upstreams->log - , GETDNS_LOG_UPSTREAM_STATS - , GETDNS_LOG_ERR - )) - return GETDNS_RETURN_GENERIC_ERROR; - - if (!x_name) - x_name = X509_NAME_oneline( - X509_get_subject_name(x) - , x_name_spc, sizeof(x_name_spc)); - _getdns_upstream_log( upstream - , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR - , "%-40s : Cert: %d %swas not signed " - "by cert %d %s\n", upstream->addr_str - , i - 1 - , X509_NAME_oneline( - X509_get_subject_name(prev) - , prev_name_spc - , sizeof(prev_name_spc) ) - , i, x_name); - return GETDNS_RETURN_GENERIC_ERROR; - } - } - - /* digest the cert with sha256 */ - len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), NULL); - if (len > (int)sizeof(raw)) { - if (!upstream->upstreams - || !_getdns_check_log( &upstream->upstreams->log - , GETDNS_LOG_UPSTREAM_STATS - , GETDNS_LOG_WARNING )) - continue; - - if (!x_name) - x_name = X509_NAME_oneline( - X509_get_subject_name(x) - , x_name_spc, sizeof(x_name_spc)); - _getdns_upstream_log( upstream - , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_WARNING - , "%-40s : Skipping cert %d %s, because pubkey is " - "larger than buffer size (%"PRIsz" octets)\n" - , upstream->addr_str, i, x_name, sizeof(raw)); - continue; - } - next = raw; - i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &next); - if (next - raw != len) { - if (!upstream->upstreams - || !_getdns_check_log( &upstream->upstreams->log - , GETDNS_LOG_UPSTREAM_STATS - , GETDNS_LOG_WARNING )) - continue; - - if (!x_name) - x_name = X509_NAME_oneline( - X509_get_subject_name(x) - , x_name_spc, sizeof(x_name_spc)); - _getdns_upstream_log( upstream - , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_WARNING - , "%-40s : Skipping cert %d %s, because pubkey si" - "ze %"PRIsz" differs from earlier reported %d\n" - , upstream->addr_str, i, x_name, next - raw, len); - continue; - } - SHA256(raw, len, buf); - - /* compare it */ - for (p = pinset; p; p = p->next) { - char pin_str[1024]; - - if (x_name) /* only when debugging */ - gldns_b64_ntop( p->pin , sizeof(p->pin) - , pin_str, sizeof(pin_str) ); - - if (0 == memcmp(buf, p->pin, sizeof(p->pin))) { - if (!upstream->upstreams - || !_getdns_check_log( - &upstream->upstreams->log - , GETDNS_LOG_UPSTREAM_STATS - , GETDNS_LOG_INFO)) - return GETDNS_RETURN_GOOD; - - if (!x_name) { - x_name = X509_NAME_oneline( - X509_get_subject_name(x) - , x_name_spc, sizeof(x_name_spc)); - gldns_b64_ntop( p->pin , sizeof(p->pin) - , pin_str - , sizeof(pin_str) ); - } - _getdns_upstream_log( upstream - , GETDNS_LOG_UPSTREAM_STATS - , GETDNS_LOG_INFO - , "%-40s : Pubkey of cert %d %s matched " - "pin %s\n", upstream->addr_str - , i, x_name, pin_str); - return GETDNS_RETURN_GOOD; - } - _getdns_upstream_log( upstream - , GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG - , "%-40s : Pubkey of cert %d %s did not match" - " pin %s\n", upstream->addr_str - , i, x_name, pin_str); - } - } - return GETDNS_RETURN_GENERIC_ERROR; -} - -/* pubkey-pinning.c */ diff --git a/src/pubkey-pinning.h b/src/pubkey-pinning.h index a17ecb61..0e2347b2 100644 --- a/src/pubkey-pinning.h +++ b/src/pubkey-pinning.h @@ -1,6 +1,6 @@ /** * - * /brief internal functions for dealing with pubkey pinsets + * /brief functions for dealing with pubkey pinsets * */ @@ -34,6 +34,10 @@ #ifndef PUBKEY_PINNING_H_ #define PUBKEY_PINNING_H_ +/* getdns_pubkey_pin_create_from_string() is implemented in pubkey-pinning.c */ +#include "getdns/getdns_extra.h" + +#include "tls.h" /* create and populate a pinset linked list from a getdns_list pinset */ getdns_return_t @@ -48,21 +52,5 @@ _getdns_get_pubkey_pinset_list(const getdns_context *ctx, const sha256_pin_t *pinset_in, getdns_list **pinset_list); - -/* internal functions for associating X.509 verification processes in - * OpenSSL with getdns_upstream objects. */ - -getdns_upstream* -_getdns_upstream_from_x509_store(X509_STORE_CTX *store); - - -getdns_return_t -_getdns_associate_upstream_with_SSL(SSL *ssl, - getdns_upstream *upstream); - -getdns_return_t -_getdns_verify_pinset_match(const getdns_upstream *upstream, - const sha256_pin_t *pinset, X509_STORE_CTX *store); - #endif /* pubkey-pinning.h */ diff --git a/src/request-internal.c b/src/request-internal.c index d53f85e0..eedea35c 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -44,6 +44,7 @@ #include "debug.h" #include "convert.h" #include "general.h" +#include "tls.h" /* MAXIMUM_TSIG_SPACE = TSIG name (dname) : 256 * TSIG type (uint16_t) : 2 @@ -54,15 +55,15 @@ * Time Signed (uint48_t) : 6 * Fudge (uint16_t) : 2 * Mac Size (uint16_t) : 2 - * Mac (variable) : EVP_MAX_MD_SIZE + * Mac (variable) : GETDNS_TLS_MAX_DIGEST_LENGTH * Original Id (uint16_t) : 2 * Error (uint16_t) : 2 * Other Len (uint16_t) : 2 * Other Data (nothing) : 0 * ---- + - * 538 + EVP_MAX_MD_SIZE + * 538 + GETDNS_TLS_MAX_DIGEST_LENGTH */ -#define MAXIMUM_TSIG_SPACE (538 + EVP_MAX_MD_SIZE) +#define MAXIMUM_TSIG_SPACE (538 + GETDNS_TLS_MAX_DIGEST_LENGTH) getdns_dict dnssec_ok_checking_disabled_spc = { { RBTREE_NULL, 0, (int (*)(const void *, const void *)) strcmp }, @@ -125,7 +126,7 @@ network_req_cleanup(getdns_network_req *net_req) GETDNS_FREE(net_req->owner->my_mf, net_req->response); if (net_req->debug_tls_peer_cert.size && net_req->debug_tls_peer_cert.data) - OPENSSL_free(net_req->debug_tls_peer_cert.data); + GETDNS_FREE(net_req->owner->my_mf, net_req->debug_tls_peer_cert.data); } static uint8_t * @@ -401,9 +402,8 @@ _getdns_network_req_add_tsig(getdns_network_req *req) gldns_buffer gbuf; uint16_t arcount; const getdns_tsig_info *tsig_info; - uint8_t md_buf[EVP_MAX_MD_SIZE]; - unsigned int md_len = EVP_MAX_MD_SIZE; - const EVP_MD *digester; + unsigned char* md_buf; + size_t md_len; /* Should only be called when in stub mode */ assert(req->query); @@ -436,31 +436,9 @@ _getdns_network_req_add_tsig(getdns_network_req *req) gldns_buffer_write_u16(&gbuf, 0); /* Error */ gldns_buffer_write_u16(&gbuf, 0); /* Other len */ - switch (upstream->tsig_alg) { -#ifdef HAVE_EVP_MD5 - case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break; -#endif -#ifdef HAVE_EVP_SHA1 - case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break; -#endif -#ifdef HAVE_EVP_SHA224 - case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break; -#endif -#ifdef HAVE_EVP_SHA256 - case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break; -#endif -#ifdef HAVE_EVP_SHA384 - case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break; -#endif -#ifdef HAVE_EVP_SHA512 - case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break; -#endif - default : return req->response - req->query; - } - - (void) HMAC(digester, upstream->tsig_key, upstream->tsig_size, - (void *)req->query, gldns_buffer_current(&gbuf) - req->query, - md_buf, &md_len); + md_buf = _getdns_tls_hmac_hash(&req->owner->my_mf, upstream->tsig_alg, upstream->tsig_key, upstream->tsig_size, (void *)req->query, gldns_buffer_current(&gbuf) - req->query, &md_len); + if (!md_buf) + return req->response - req->query; gldns_buffer_rewind(&gbuf); gldns_buffer_write(&gbuf, @@ -480,6 +458,8 @@ _getdns_network_req_add_tsig(getdns_network_req *req) gldns_buffer_write_u16(&gbuf, 0); /* Error */ gldns_buffer_write_u16(&gbuf, 0); /* Other len */ + GETDNS_FREE(req->owner->my_mf, md_buf); + if (gldns_buffer_position(&gbuf) > gldns_buffer_limit(&gbuf)) return req->response - req->query; @@ -509,14 +489,10 @@ _getdns_network_validate_tsig(getdns_network_req *req) const uint8_t *response_mac; uint16_t response_mac_len; uint8_t other_len; - uint8_t result_mac[EVP_MAX_MD_SIZE]; - unsigned int result_mac_len = EVP_MAX_MD_SIZE; + unsigned char *result_mac; + size_t result_mac_len; uint16_t original_id; - const EVP_MD *digester; - HMAC_CTX *ctx; -#ifndef HAVE_HMAC_CTX_NEW - HMAC_CTX ctx_space; -#endif + _getdns_tls_hmac *hmac; DEBUG_STUB("%s %-35s: Validate TSIG\n", STUB_DEBUG_TSIG, __FUNC__); for ( rr = _getdns_rr_iter_init(&rr_spc, req->query, @@ -623,39 +599,16 @@ _getdns_network_validate_tsig(getdns_network_req *req) gldns_read_uint16(req->response + 10) - 1); gldns_write_uint16(req->response, original_id); - switch (req->upstream->tsig_alg) { -#ifdef HAVE_EVP_MD5 - case GETDNS_HMAC_MD5 : digester = EVP_md5() ; break; -#endif -#ifdef HAVE_EVP_SHA1 - case GETDNS_HMAC_SHA1 : digester = EVP_sha1() ; break; -#endif -#ifdef HAVE_EVP_SHA224 - case GETDNS_HMAC_SHA224: digester = EVP_sha224(); break; -#endif -#ifdef HAVE_EVP_SHA256 - case GETDNS_HMAC_SHA256: digester = EVP_sha256(); break; -#endif -#ifdef HAVE_EVP_SHA384 - case GETDNS_HMAC_SHA384: digester = EVP_sha384(); break; -#endif -#ifdef HAVE_EVP_SHA512 - case GETDNS_HMAC_SHA512: digester = EVP_sha512(); break; -#endif - default : return; - } -#ifdef HAVE_HMAC_CTX_NEW - ctx = HMAC_CTX_new(); -#else - ctx = &ctx_space; - HMAC_CTX_init(ctx); -#endif - (void) HMAC_Init_ex(ctx, req->upstream->tsig_key, - req->upstream->tsig_size, digester, NULL); - (void) HMAC_Update(ctx, request_mac - 2, request_mac_len + 2); - (void) HMAC_Update(ctx, req->response, rr->pos - req->response); - (void) HMAC_Update(ctx, tsig_vars, gldns_buffer_position(&gbuf)); - HMAC_Final(ctx, result_mac, &result_mac_len); + hmac = _getdns_tls_hmac_new(&req->owner->my_mf, req->upstream->tsig_alg, req->upstream->tsig_key, req->upstream->tsig_size); + if (!hmac) + return; + + _getdns_tls_hmac_add(hmac, request_mac - 2, request_mac_len + 2); + _getdns_tls_hmac_add(hmac, req->response, rr->pos - req->response); + _getdns_tls_hmac_add(hmac, tsig_vars, gldns_buffer_position(&gbuf)); + result_mac = _getdns_tls_hmac_end(&req->owner->my_mf, hmac, &result_mac_len); + if (!result_mac) + return; DEBUG_STUB("%s %-35s: Result MAC length: %d\n", STUB_DEBUG_TSIG, __FUNC__, (int)(result_mac_len)); @@ -663,11 +616,8 @@ _getdns_network_validate_tsig(getdns_network_req *req) memcmp(result_mac, response_mac, result_mac_len) == 0) req->tsig_status = GETDNS_DNSSEC_SECURE; -#ifdef HAVE_HMAC_CTX_FREE - HMAC_CTX_free(ctx); -#else - HMAC_CTX_cleanup(ctx); -#endif + GETDNS_FREE(req->owner->my_mf, result_mac); + gldns_write_uint16(req->response, gldns_read_uint16(req->query)); gldns_write_uint16(req->response + 10, gldns_read_uint16(req->response + 10) + 1); diff --git a/src/stub.c b/src/stub.c index 55bd0628..05e48f0a 100644 --- a/src/stub.c +++ b/src/stub.c @@ -39,9 +39,6 @@ #define INTERCEPT_COM_DS 0 #include "debug.h" -#include -#include -#include #include #include "stub.h" #include "gldns/gbuffer.h" @@ -55,10 +52,6 @@ #include "platform.h" #include "general.h" #include "pubkey-pinning.h" -#ifdef USE_DANESSL -# include "ssl_dane/danessl.h" -#endif -#include "const-info.h" /* WSA TODO: * STUB_TCP_RETRY added to deal with edge triggered event loops (versus @@ -128,10 +121,8 @@ rollover_secret() static void calc_new_cookie(getdns_upstream *upstream, uint8_t *cookie) { - const EVP_MD *md; - EVP_MD_CTX *mdctx; - unsigned char md_value[EVP_MAX_MD_SIZE]; - unsigned int md_len; + unsigned char md_value[GETDNS_TLS_MAX_DIGEST_LENGTH]; + size_t md_len; size_t i; sa_family_t af = upstream->addr.ss_family; void *sa_addr = ((struct sockaddr*)&upstream->addr)->sa_data; @@ -139,13 +130,7 @@ calc_new_cookie(getdns_upstream *upstream, uint8_t *cookie) : af == AF_INET ? sizeof(struct sockaddr_in) : 0 ) - sizeof(sa_family_t); - md = EVP_sha256(); - mdctx = EVP_MD_CTX_create(); - EVP_DigestInit_ex(mdctx, md, NULL); - EVP_DigestUpdate(mdctx, &secret, sizeof(secret)); - EVP_DigestUpdate(mdctx, sa_addr, addr_len); - EVP_DigestFinal_ex(mdctx, md_value, &md_len); - EVP_MD_CTX_destroy(mdctx); + _getdns_tls_cookie_sha256(secret, sa_addr, addr_len, md_value, &md_len); (void) memset(cookie, 0, 8); for (i = 0; i < md_len; i++) @@ -830,194 +815,46 @@ tls_requested(getdns_network_req *netreq) 1 : 0; } - -#if defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) - -static int -_getdns_tls_verify_always_ok(int ok, X509_STORE_CTX *ctx) -{ -# if defined(STUB_DEBUG) && STUB_DEBUG - char buf[8192]; - X509 *cert; - int err; - int depth; - - cert = X509_STORE_CTX_get_current_cert(ctx); - err = X509_STORE_CTX_get_error(ctx); - depth = X509_STORE_CTX_get_error_depth(ctx); - - if (cert) - X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); - else - strcpy(buf, ""); - DEBUG_STUB("DEBUG Cert verify: depth=%d verify=%d err=%d subject=%s errorstr=%s\n", depth, ok, err, buf, X509_verify_cert_error_string(err)); -# else /* defined(STUB_DEBUG) && STUB_DEBUG */ - (void)ok; - (void)ctx; -# endif /* #else defined(STUB_DEBUG) && STUB_DEBUG */ - return 1; -} - -#else /* defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */ - -static int -tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) -{ - getdns_upstream *upstream; - getdns_return_t pinset_ret = GETDNS_RETURN_GOOD; - upstream = _getdns_upstream_from_x509_store(ctx); - if (!upstream) - return 0; - - int err = X509_STORE_CTX_get_error(ctx); -# if defined(STUB_DEBUG) && STUB_DEBUG - DEBUG_STUB("%s %-35s: FD: %d Verify result: (%d) \"%s\"\n", - STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, err, - X509_verify_cert_error_string(err)); -# endif - if (!preverify_ok && !upstream->tls_fallback_ok) - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR, - "%-40s : Verify failed: TLS - *Failure* - (%d) \"%s\"\n", - upstream->addr_str, err, - X509_verify_cert_error_string(err)); - - /* No need to deal with hostname authentication, since this will be - * dealt with in the DANE preprocessor paths. - */ - - /* Deal with the pinset validation */ - if (upstream->tls_pubkey_pinset) - pinset_ret = _getdns_verify_pinset_match( - upstream, upstream->tls_pubkey_pinset, ctx); - - if (pinset_ret != GETDNS_RETURN_GOOD) { - DEBUG_STUB("%s %-35s: FD: %d, WARNING: Pinset validation failure!\n", - STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); - preverify_ok = 0; - upstream->tls_auth_state = GETDNS_AUTH_FAILED; - if (upstream->tls_fallback_ok) - DEBUG_STUB("%s %-35s: FD: %d, WARNING: Proceeding even though pinset validation failed!\n", - STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); - else - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR, - "%-40s : Conn failed: TLS - *Failure* - Pinset validation failure\n", - upstream->addr_str); - } - /* If nothing has failed yet and we had credentials, we have successfully authenticated*/ - if (preverify_ok == 0) - upstream->tls_auth_state = GETDNS_AUTH_FAILED; - else if (upstream->tls_auth_state == GETDNS_AUTH_NONE && - (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0])) - upstream->tls_auth_state = GETDNS_AUTH_OK; - - /* If fallback is allowed, proceed regardless of what the auth error is - (might not be hostname or pinset related) */ - return (upstream->tls_fallback_ok) ? 1 : preverify_ok; -} - -#endif /* #else defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */ - -static SSL* +static _getdns_tls_connection* tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) { - /* Create SSL instance */ + /* Create SSL instance and connect with a file descriptor */ getdns_context *context = dnsreq->context; if (context->tls_ctx == NULL) return NULL; - SSL* ssl = SSL_new(context->tls_ctx); - if(!ssl) + _getdns_tls_connection* tls = _getdns_tls_connection_new(&context->my_mf, context->tls_ctx, fd, &upstream->upstreams->log); + if(!tls) return NULL; - /* Connect the SSL object with a file descriptor */ - if(!SSL_set_fd(ssl,fd)) { - SSL_free(ssl); + + getdns_return_t r = GETDNS_RETURN_GOOD; + + if (upstream->tls_curves_list) + r = _getdns_tls_connection_set_curves_list(tls, upstream->tls_curves_list); + if (!r && upstream->tls_ciphersuites) + r = _getdns_tls_connection_set_cipher_suites(tls, upstream->tls_ciphersuites); + if (!r) + r = _getdns_tls_connection_set_min_max_tls_version(tls, upstream->tls_min_version, upstream->tls_max_version); + + if (!r) + { + if (upstream->tls_fallback_ok) + r = _getdns_tls_connection_set_cipher_list(tls, NULL); + else if (upstream->tls_cipher_list) + r = _getdns_tls_connection_set_cipher_list(tls, upstream->tls_cipher_list); + } + + if (r) { + _getdns_tls_connection_free(&upstream->upstreams->mf, tls); + upstream->tls_auth_state = r; return NULL; } -#if defined(HAVE_DECL_SSL_SET1_CURVES_LIST) && HAVE_DECL_SSL_SET1_CURVES_LIST - if (upstream->tls_curves_list - && !SSL_set1_curves_list(ssl, upstream->tls_curves_list)) { - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : Error configuring tls_curves_list " - "\"%s\"\n", upstream->addr_str, upstream->tls_curves_list); - SSL_free(ssl); - return NULL; - } -#else - if (upstream->tls_curves_list) { - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : tls_curves_list not supported " - "in tls library\n", upstream->addr_str); - SSL_free(ssl); - return NULL; - } -#endif -#ifdef HAVE_SSL_SET_CIPHERSUITES - if (upstream->tls_ciphersuites && - !SSL_set_ciphersuites(ssl, upstream->tls_ciphersuites)) { - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : Error configuring tls_ciphersuites " - "\"%s\"\n", upstream->addr_str, upstream->tls_ciphersuites); - } -#else - if (upstream->tls_ciphersuites) { - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : tls_ciphersuites not " - "supported in tls library\n", upstream->addr_str); - SSL_free(ssl); - return NULL; - } -#endif -#if defined(HAVE_DECL_SSL_SET_MIN_PROTO_VERSION) \ - && HAVE_DECL_SSL_SET_MIN_PROTO_VERSION - if (upstream->tls_min_version && !SSL_set_min_proto_version(ssl, - _getdns_tls_version2openssl_version(upstream->tls_min_version))) { - struct const_info *ci = - _getdns_get_const_info(upstream->tls_min_version); - if (ci && *ci->name) - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : Error configuring " - "tls_min_version \"%s\"\n", upstream->addr_str, - ci->name); - else - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : Error configuring " - "tls_min_version \"%d\"\n", upstream->addr_str, - upstream->tls_min_version); - } - if (upstream->tls_max_version && !SSL_set_max_proto_version(ssl, - _getdns_tls_version2openssl_version(upstream->tls_max_version))) { - struct const_info *ci = - _getdns_get_const_info(upstream->tls_max_version); - if (ci && *ci->name) - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : Error configuring " - "tls_max_version \"%s\"\n", upstream->addr_str, - ci->name); - else - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : Error configuring " - "tls_max_version \"%d\"\n", upstream->addr_str, - upstream->tls_max_version); - } -#else - if (upstream->tls_min_version) { - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : tls_min_version not " - "supported in tls library\n", upstream->addr_str); - SSL_free(ssl); - return NULL; - } - if (upstream->tls_max_version) { - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, - GETDNS_LOG_ERR, "%-40s : tls_max_version not " - "supported in tls library\n", upstream->addr_str); - SSL_free(ssl); - return NULL; - } -#endif - /* make sure we'll be able to find the context again when we need it */ - if (_getdns_associate_upstream_with_SSL(ssl, upstream) != GETDNS_RETURN_GOOD) { - SSL_free(ssl); - return NULL; + + if (upstream->tls_fallback_ok) { + DEBUG_STUB("%s %-35s: WARNING: Using Opportunistic TLS (fallback allowed)!\n", + STUB_DEBUG_SETUP_TLS, __FUNC__); + } else { + DEBUG_STUB("%s %-35s: Using Strict TLS \n", + STUB_DEBUG_SETUP_TLS, __FUNC__); } /* NOTE: this code will fallback on a given upstream, without trying @@ -1030,29 +867,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) /*Request certificate for the auth_name*/ DEBUG_STUB("%s %-35s: Hostname verification requested for: %s\n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name); - SSL_set_tlsext_host_name(ssl, upstream->tls_auth_name); -#if defined(HAVE_SSL_HN_AUTH) - /* Set up native OpenSSL hostname verification - * ( doesn't work with USE_DANESSL, but we verify the - * name afterwards in such cases ) - */ - X509_VERIFY_PARAM *param; - param = SSL_get0_param(ssl); - X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); - X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0); -#elif !defined(HAVE_X509_CHECK_HOST) - if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { - DEBUG_STUB("%s %-35s: ERROR: Hostname Authentication not available from TLS library (check library version)\n", - STUB_DEBUG_SETUP_TLS, __FUNC__); - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR, - "%-40s : ERROR: Hostname Authentication not available from TLS library (check library version)\n", - upstream->addr_str); - upstream->tls_hs_state = GETDNS_HS_FAILED; - SSL_free(ssl); - upstream->tls_auth_state = GETDNS_AUTH_FAILED; - return NULL; - } -#endif + _getdns_tls_connection_setup_hostname_auth(tls, upstream->tls_auth_name); /* Allow fallback to opportunistic if settings permit it*/ if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) upstream->tls_fallback_ok = 1; @@ -1070,7 +885,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) "%-40s : Verify fail: *CONFIG ERROR* - No auth name or pinset provided for this upstream for Strict TLS authentication\n", upstream->addr_str); upstream->tls_hs_state = GETDNS_HS_FAILED; - SSL_free(ssl); + _getdns_tls_connection_free(&upstream->upstreams->mf, tls); upstream->tls_auth_state = GETDNS_AUTH_FAILED; return NULL; } @@ -1081,89 +896,8 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) upstream->tls_fallback_ok = 1; } } - if (upstream->tls_fallback_ok) { - SSL_set_cipher_list(ssl, "DEFAULT"); - DEBUG_STUB("%s %-35s: WARNING: Using Oppotunistic TLS (fallback allowed)!\n", - STUB_DEBUG_SETUP_TLS, __FUNC__); - } else { - if (upstream->tls_cipher_list && - !SSL_set_cipher_list(ssl, upstream->tls_cipher_list)) - _getdns_upstream_log(upstream, - GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR, - "%-40s : Error configuring cipher_list\"%s\"\n", - upstream->addr_str, upstream->tls_cipher_list); - DEBUG_STUB("%s %-35s: Using Strict TLS \n", STUB_DEBUG_SETUP_TLS, - __FUNC__); - } -#if defined(HAVE_SSL_DANE_ENABLE) - int osr; -# if defined(STUB_DEBUG) && STUB_DEBUG - osr = -# else - (void) -# endif - SSL_dane_enable(ssl, *upstream->tls_auth_name ? upstream->tls_auth_name : NULL); - DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n" - , STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr); - SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); - sha256_pin_t *pin_p; - size_t n_pins = 0; - for (pin_p = upstream->tls_pubkey_pinset; pin_p; pin_p = pin_p->next) { - osr = SSL_dane_tlsa_add(ssl, 2, 1, 1, - (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); - DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n" - , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); - if (osr > 0) - ++n_pins; - osr = SSL_dane_tlsa_add(ssl, 3, 1, 1, - (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); - DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n" - , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); - if (osr > 0) - ++n_pins; - } -#elif defined(USE_DANESSL) - if (upstream->tls_pubkey_pinset) { - const char *auth_names[2] = { upstream->tls_auth_name, NULL }; - int osr; -# if defined(STUB_DEBUG) && STUB_DEBUG - osr = -# else - (void) -# endif - DANESSL_init(ssl, - *upstream->tls_auth_name ? upstream->tls_auth_name : NULL, - *upstream->tls_auth_name ? auth_names : NULL - ); - DEBUG_STUB("%s %-35s: DEBUG: DANESSL_init(\"%s\") -> %d\n" - , STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr); - SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); - sha256_pin_t *pin_p; - size_t n_pins = 0; - for (pin_p = upstream->tls_pubkey_pinset; pin_p; pin_p = pin_p->next) { - osr = DANESSL_add_tlsa(ssl, 3, 1, "sha256", - (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); - DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n" - , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); - if (osr > 0) - ++n_pins; - osr = DANESSL_add_tlsa(ssl, 2, 1, "sha256", - (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); - DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n" - , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); - if (osr > 0) - ++n_pins; - } - } else { - SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); - } -#else - SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); -#endif - - SSL_set_connect_state(ssl); - (void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + _getdns_tls_connection_set_host_pinset(tls, upstream->tls_auth_name, upstream->tls_pubkey_pinset); /* Session resumption. There are trade-offs here. Want to do it when possible only if we have the right type of connection. Note a change @@ -1172,12 +906,12 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) if ((upstream->tls_fallback_ok == 0 && upstream->last_tls_auth_state == GETDNS_AUTH_OK) || upstream->tls_fallback_ok == 1) { - SSL_set_session(ssl, upstream->tls_session); + _getdns_tls_connection_set_session(tls, upstream->tls_session); DEBUG_STUB("%s %-35s: Attempting session re-use\n", STUB_DEBUG_SETUP_TLS, __FUNC__); } } - return ssl; + return tls; } static int @@ -1186,13 +920,10 @@ tls_do_handshake(getdns_upstream *upstream) DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); int r; - int want; - ERR_clear_error(); - while ((r = SSL_do_handshake(upstream->tls_obj)) != 1) + while ((r = _getdns_tls_connection_do_handshake(upstream->tls_obj)) != GETDNS_RETURN_GOOD) { - want = SSL_get_error(upstream->tls_obj, r); - switch (want) { - case SSL_ERROR_WANT_READ: + switch (r) { + case GETDNS_RETURN_TLS_WANT_READ: GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = upstream_read_cb; upstream->event.write_cb = NULL; @@ -1200,7 +931,7 @@ tls_do_handshake(getdns_upstream *upstream) upstream->fd, TIMEOUT_TLS, &upstream->event); upstream->tls_hs_state = GETDNS_HS_READ; return STUB_TCP_RETRY; - case SSL_ERROR_WANT_WRITE: + case GETDNS_RETURN_TLS_WANT_WRITE: GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = NULL; upstream->event.write_cb = upstream_write_cb; @@ -1216,33 +947,13 @@ tls_do_handshake(getdns_upstream *upstream) } } /* A re-used session is not verified so need to fix up state in that case */ - if (SSL_session_reused(upstream->tls_obj)) + if (!_getdns_tls_connection_is_session_reused(upstream->tls_obj)) upstream->tls_auth_state = upstream->last_tls_auth_state; else if (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0]) { - X509 *peer_cert = SSL_get_peer_certificate(upstream->tls_obj); - long verify_result = SSL_get_verify_result(upstream->tls_obj); + _getdns_tls_x509* peer_cert = _getdns_tls_connection_get_peer_certificate(&upstream->upstreams->mf, upstream->tls_obj); -/* In case of DANESSL use, and a tls_auth_name was given alongside a pinset, - * we need to verify auth_name explicitly (otherwise it will not be checked, - * because this is not required with DANE with an EE match). - * This is not needed with native OpenSSL DANE, because EE name checks have - * to be disabled explicitly. - */ -#if defined(HAVE_X509_CHECK_HOST) && (defined(USE_DANESSL) || !defined(HAVE_SSL_HN_AUTH)) - int xch; - if (peer_cert && verify_result == X509_V_OK - && upstream->tls_auth_name[0] - && (xch = X509_check_host(peer_cert, - upstream->tls_auth_name, - strlen(upstream->tls_auth_name), - X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, - NULL)) <= 0) - verify_result = X509_V_ERR_HOSTNAME_MISMATCH; -#endif - upstream->tls_auth_state = peer_cert && verify_result == X509_V_OK - ? GETDNS_AUTH_OK : GETDNS_AUTH_FAILED; - if (!peer_cert) + if (!peer_cert) { _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, ( upstream->tls_fallback_ok @@ -1253,71 +964,44 @@ tls_do_handshake(getdns_upstream *upstream) ( upstream->tls_fallback_ok ? "Tolerated because of Opportunistic profile" : "*Failure*" )); - - /* Since we don't have DANE validation yet, DANE validation - * failures are always pinset validation failures - */ -#if defined(HAVE_SSL_DANE_ENABLE) - else if (verify_result == X509_V_ERR_DANE_NO_MATCH) - _getdns_upstream_log(upstream, - GETDNS_LOG_UPSTREAM_STATS, - ( upstream->tls_fallback_ok - ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), - "%-40s : Verify failed : TLS - %s - " - "Pinset validation failure\n", upstream->addr_str, - ( upstream->tls_fallback_ok - ? "Tolerated because of Opportunistic profile" - : "*Failure*" )); -#elif defined(USE_DANESSL) - else if (verify_result == X509_V_ERR_CERT_UNTRUSTED - && upstream->tls_pubkey_pinset - && !DANESSL_get_match_cert( - upstream->tls_obj, NULL, NULL, NULL)) - _getdns_upstream_log(upstream, - GETDNS_LOG_UPSTREAM_STATS, - ( upstream->tls_fallback_ok - ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), - "%-40s : Verify failed : TLS - %s - " - "Pinset validation failure\n", upstream->addr_str, - ( upstream->tls_fallback_ok - ? "Tolerated because of Opportunistic profile" - : "*Failure*" )); -#endif - else if (verify_result != X509_V_OK) - _getdns_upstream_log(upstream, - GETDNS_LOG_UPSTREAM_STATS, - ( upstream->tls_fallback_ok - ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), - "%-40s : Verify failed : TLS - %s - " - "(%d) \"%s\"\n", upstream->addr_str, - ( upstream->tls_fallback_ok - ? "Tolerated because of Opportunistic profile" - : "*Failure*" ), verify_result, - X509_verify_cert_error_string(verify_result)); -#if !defined(HAVE_SSL_HN_AUTH) && !defined(HAVE_X509_CHECK_HOST) - else if (*upstream->tls_auth_name) { - _getdns_upstream_log(upstream, - GETDNS_LOG_UPSTREAM_STATS, - ( upstream->tls_fallback_ok - ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), - "%-40s : Verify failed : TLS - %s - " - "Hostname Authentication not available from TLS " - "library (check library version)\n", - upstream->addr_str, - ( upstream->tls_fallback_ok - ? "Tolerated because of Opportunistic profile" - : "*Failure*" )); - upstream->tls_auth_state = GETDNS_AUTH_FAILED; - } -#endif - else - _getdns_upstream_log(upstream, - GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, - "%-40s : Verify passed : TLS\n", - upstream->addr_str); + } else { + long verify_errno; + const char* verify_errmsg; - X509_free(peer_cert); + if (_getdns_tls_connection_certificate_verify(upstream->tls_obj, &verify_errno, &verify_errmsg)) { + upstream->tls_auth_state = GETDNS_AUTH_FAILED; + if (verify_errno != 0) { + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, + ( upstream->tls_fallback_ok + ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), + "%-40s : Verify failed : TLS - %s - " + "(%ld) \"%s\"\n", upstream->addr_str, + ( upstream->tls_fallback_ok + ? "Tolerated because of Opportunistic profile" + : "*Failure*" ), + verify_errno, verify_errmsg); + } else { + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, + ( upstream->tls_fallback_ok + ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), "%-40s : Verify failed : TLS - %s - " + "%s\n", upstream->addr_str, + ( upstream->tls_fallback_ok + ? "Tolerated because of Opportunistic profile" + : "*Failure*" ), + verify_errmsg); + } + } else { + upstream->tls_auth_state = GETDNS_AUTH_OK; + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, + "%-40s : Verify passed : TLS\n", + upstream->addr_str); + } + _getdns_tls_x509_free(&upstream->upstreams->mf, peer_cert); + } if (upstream->tls_auth_state == GETDNS_AUTH_FAILED && !upstream->tls_fallback_ok) return STUB_SETUP_ERROR; @@ -1325,13 +1009,13 @@ tls_do_handshake(getdns_upstream *upstream) DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded with auth state %s. Session is %s.\n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, _getdns_auth_str(upstream->tls_auth_state), - SSL_session_reused(upstream->tls_obj) ?"re-used":"new"); + _getdns_tls_connection_is_session_reused(upstream->tls_obj) ? "new" : "re-used"); upstream->tls_hs_state = GETDNS_HS_DONE; upstream->conn_state = GETDNS_CONN_OPEN; upstream->conn_completed++; if (upstream->tls_session != NULL) - SSL_SESSION_free(upstream->tls_session); - upstream->tls_session = SSL_get1_session(upstream->tls_obj); + _getdns_tls_session_free(&upstream->upstreams->mf, upstream->tls_session); + upstream->tls_session = _getdns_tls_connection_get_session(&upstream->upstreams->mf, upstream->tls_obj); /* Reset timeout on success*/ GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = NULL; @@ -1369,10 +1053,10 @@ static int stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp, struct mem_funcs *mf) { - ssize_t read; + size_t read; uint8_t *buf; size_t buf_size; - SSL* tls_obj = upstream->tls_obj; + _getdns_tls_connection* tls_obj = upstream->tls_obj; int q = tls_connected(upstream); if (q != 0) @@ -1388,17 +1072,14 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp, tcp->to_read = 2; /* Packet size */ } - ERR_clear_error(); - read = SSL_read(tls_obj, tcp->read_pos, tcp->to_read); - if (read <= 0) { - /* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake - renegotiation. Need to keep handshake state to do that.*/ - int want = SSL_get_error(tls_obj, read); - if (want == SSL_ERROR_WANT_READ) { - return STUB_TCP_RETRY; /* Come back later */ - } else - return STUB_TCP_ERROR; - } + getdns_return_t r = _getdns_tls_connection_read(tls_obj, tcp->read_pos, tcp->to_read, &read); + /* TODO[TLS]: Handle GETDNS_RETURN_TLS_WANT_WRITE which means handshake + renegotiation. Need to keep handshake state to do that.*/ + if (r == GETDNS_RETURN_TLS_WANT_READ) + return STUB_TCP_RETRY; + else if (r != GETDNS_RETURN_GOOD) + return STUB_TCP_ERROR; + tcp->to_read -= read; tcp->read_pos += read; @@ -1429,15 +1110,17 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp, /* Ready to start reading the packet */ tcp->read_pos = tcp->read_buf; - read = SSL_read(tls_obj, tcp->read_pos, tcp->to_read); - if (read <= 0) { - /* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake + switch ((int)_getdns_tls_connection_read(tls_obj, tcp->read_pos, tcp->to_read, &read)) { + case GETDNS_RETURN_GOOD: + break; + + case GETDNS_RETURN_TLS_WANT_READ: + return STUB_TCP_RETRY; /* Come back later */ + + default: + /* TODO[TLS]: Handle GETDNS_RETURN_TLS_WANT_WRITE which means handshake renegotiation. Need to keep handshake state to do that.*/ - int want = SSL_get_error(tls_obj, read); - if (want == SSL_ERROR_WANT_READ) { - return STUB_TCP_RETRY; /* read more later */ - } else - return STUB_TCP_ERROR; + return STUB_TCP_ERROR; } tcp->to_read -= read; tcp->read_pos += read; @@ -1452,10 +1135,10 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, getdns_network_req *netreq) { size_t pkt_len; - ssize_t written; + size_t written; uint16_t query_id; intptr_t query_id_intptr; - SSL* tls_obj = upstream->tls_obj; + _getdns_tls_connection* tls_obj = upstream->tls_obj; uint16_t padding_sz; int q = tls_connected(upstream); @@ -1530,7 +1213,8 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, * Lets see how much of it we can write */ /* TODO[TLS]: Handle error cases, partial writes, renegotiation etc. */ - ERR_clear_error(); + getdns_return_t r; + #if INTERCEPT_COM_DS /* Intercept and do not sent out COM DS queries. For debugging * purposes only. Never commit with this turned on. @@ -1545,25 +1229,16 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, debug_req("Intercepting", netreq); written = pkt_len + 2; + r = GETDNS_RETURN_GOOD; } else #endif - written = SSL_write(tls_obj, netreq->query - 2, pkt_len + 2); - if (written <= 0) { - /* SSL_write will not do partial writes, because - * SSL_MODE_ENABLE_PARTIAL_WRITE is not default, - * but the write could fail because of renegotiation. - * In that case SSL_get_error() will return - * SSL_ERROR_WANT_READ or, SSL_ERROR_WANT_WRITE. - * Return for retry in such cases. - */ - switch (SSL_get_error(tls_obj, written)) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - return STUB_TCP_RETRY; - default: - return STUB_TCP_ERROR; - } - } + r = _getdns_tls_connection_write(tls_obj, netreq->query - 2, pkt_len + 2, &written); + if (r == GETDNS_RETURN_TLS_WANT_READ || + r == GETDNS_RETURN_TLS_WANT_WRITE) + return STUB_TCP_RETRY; + else if (r != GETDNS_RETURN_GOOD) + return STUB_TCP_ERROR; + /* We were able to write everything! Start reading. */ return (int) query_id; @@ -1897,7 +1572,7 @@ upstream_write_cb(void *userarg) getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_network_req *netreq = upstream->write_queue; int q; - X509 *cert; + _getdns_tls_x509 *cert; if (!netreq) { GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); @@ -1960,12 +1635,11 @@ upstream_write_cb(void *userarg) if (netreq->owner->return_call_reporting && netreq->upstream->tls_obj) { if (netreq->debug_tls_peer_cert.data == NULL && - (cert = SSL_get_peer_certificate(netreq->upstream->tls_obj))) { - netreq->debug_tls_peer_cert.size = i2d_X509( - cert, &netreq->debug_tls_peer_cert.data); - X509_free(cert); + (cert = _getdns_tls_connection_get_peer_certificate(&upstream->upstreams->mf, netreq->upstream->tls_obj))) { + _getdns_tls_x509_to_der(&upstream->upstreams->mf, cert, &netreq->debug_tls_peer_cert); + _getdns_tls_x509_free(&upstream->upstreams->mf, cert); } - netreq->debug_tls_version = SSL_get_version(netreq->upstream->tls_obj); + netreq->debug_tls_version = _getdns_tls_connection_get_version(netreq->upstream->tls_obj); } /* Need this because auth status is reset on connection close */ netreq->debug_tls_auth_status = netreq->upstream->tls_auth_state; diff --git a/src/tls.h b/src/tls.h new file mode 100644 index 00000000..aacf4257 --- /dev/null +++ b/src/tls.h @@ -0,0 +1,465 @@ +/** + * + * \file tls.h + * @brief getdns TLS functions + */ + +/* + * Copyright (c) 2018-2019, NLnet Labs + * 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. + * * Neither the names of the copyright holders 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 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 Verisign, Inc. 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. + */ + +#ifndef _GETDNS_TLS_H +#define _GETDNS_TLS_H + +#include "getdns/getdns.h" + +#include "types-internal.h" + +#include "tls-internal.h" + +/* Forward declare type. */ +struct sha256_pin; +typedef struct sha256_pin sha256_pin_t; + +/* Additional return codes required by TLS abstraction. Internal use only. */ +#define GETDNS_RETURN_TLS_WANT_READ ((getdns_return_t) 420) +#define GETDNS_RETURN_TLS_WANT_WRITE ((getdns_return_t) 421) +#define GETDNS_RETURN_TLS_CONNECTION_FRESH ((getdns_return_t) 422) + +/** + * Global initialisation of the TLS interface. + */ +void _getdns_tls_init(); + +/** + * Create a new TLS context. + * + * @param mfs pointer to getdns memory functions. + * @paam log pointer to context log config. + * @return pointer to new context or NULL on error. + */ +_getdns_tls_context* _getdns_tls_context_new(struct mem_funcs* mfs, const getdns_log_config* log); + +/** + * Free a TLS context. + * + * @param mfs point to getdns memory functions. + * @param ctx the context to free. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER if ctx is invalid. + */ +getdns_return_t _getdns_tls_context_free(struct mem_funcs* mfs, _getdns_tls_context* ctx); + +/** + * Initialise any shared state for pinset checking. + * + * @param ctx the context to initialise. + */ +void _getdns_tls_context_pinset_init(_getdns_tls_context* ctx); + +/** + * Set minimum and maximum TLS versions. + * If max or min are 0, that boundary is not set. + * + * @param ctx the context. + * @param min the minimum TLS version. + * @param max the maximum TLS version. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer. + * @return GETDNS_RETURN_NOT_IMPLEMENTED if not implemented. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_context_set_min_max_tls_version(_getdns_tls_context* ctx, getdns_tls_version_t min, getdns_tls_version_t max); + +/** + * Get the default context cipher list. + * + * @return the default context cipher list. + */ +const char* _getdns_tls_context_get_default_cipher_list(); + +/** + * Set list of allowed ciphers. + * + * @param ctx the context. + * @param list the list of cipher identifiers. NULL for default setting. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_context_set_cipher_list(_getdns_tls_context* ctx, const char* list); + +/** + * Get the default context cipher suites. + * + * @return the default context cipher suites. + */ +const char* _getdns_tls_context_get_default_cipher_suites(); + +/** + * Set list of allowed cipher suites. + * + * @param ctx the context. + * @param list the list of cipher suites. NULL for default setting. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_context_set_cipher_suites(_getdns_tls_context* ctx, const char* list); + +/** + * Set list of allowed curves. + * + * @param ctx the context. + * @param list the list of curve identifiers. NULL for default setting. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_context_set_curves_list(_getdns_tls_context* ctx, const char* list); + +/** + * Set certificate authority details. + * + * Load CA from either a file or a directory. If both file + * and path are NULL, use default locations. + * + * @param ctx the context. + * @param file a file of CA certificates in PEM format. + * @param path a directory containing CA certificates in PEM format. + * Files are looked up by CA subject name hash value. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer. + * @return GETDNS_RETURN_GENERIC_ERROR on failure. + */ +getdns_return_t _getdns_tls_context_set_ca(_getdns_tls_context* ctx, const char* file, const char* path); + +/** + * Create a new TLS connection and associate it with a file descriptior. + * + * @param mfs pointer to getdns memory functions. + * @param ctx the context. + * @param fd the file descriptor to associate with the connection. + * @paam log pointer to connection log config. + * @return pointer to new connection or NULL on error. + */ +_getdns_tls_connection* _getdns_tls_connection_new(struct mem_funcs* mfs, _getdns_tls_context* ctx, int fd, const getdns_log_config* log); + +/** + * Free a TLS connection. + * + * @param mfs pointer to getdns memory functions. + * @param conn the connection to free. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is invalid. + */ +getdns_return_t _getdns_tls_connection_free(struct mem_funcs* mfs, _getdns_tls_connection* conn); + +/** + * Shut down a TLS connection. + * + * @param conn the connection to shut down. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is invalid. + * @return GETDNS_RETURN_CONTEXT_UPDATE_FAIL if shutdown is not finished, + * and this routine should be called again. + * @return GETDNS_RETURN_GENERIC_ERROR on error. + */ +getdns_return_t _getdns_tls_connection_shutdown(_getdns_tls_connection* conn); + +/** + * Set minimum and maximum TLS versions for this connection. + * If max or min are 0, that boundary is not set. + * + * @param conn the connection. + * @param min the minimum TLS version. + * @param max the maximum TLS version. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer. + * @return GETDNS_RETURN_NOT_IMPLEMENTED if not implemented. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_connection_set_min_max_tls_version(_getdns_tls_connection* conn, getdns_tls_version_t min, getdns_tls_version_t max); + +/** + * Set list of allowed ciphers on this connection. + * + * @param conn the connection. + * @param list the list of cipher identifiers. NULL for opportunistic setting. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad connection pointer. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_connection_set_cipher_list(_getdns_tls_connection* conn, const char* list); + +/** + * Set list of allowed cipher suites on this connection. + * + * @param conn the connection. + * @param list the list of cipher suites. NULL for default setting. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad context pointer. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_connection_set_cipher_suites(_getdns_tls_connection* conn, const char* list); + +/** + * Set list of allowed curves on this connection. + * + * @param conn the connection. + * @param list the list of curve identifiers. NULL for default setting. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad connection pointer. + * @return GETDNS_RETURN_BAD_CONTEXT on failure. + */ +getdns_return_t _getdns_tls_connection_set_curves_list(_getdns_tls_connection* conn, const char* list); + +/** + * Set the session for this connection. + * + * @param conn the connection. + * @param s the session. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER on bad connection pointer. + * @return GETDNS_RETURN_GENERIC_ERROR on failure. + */ +getdns_return_t _getdns_tls_connection_set_session(_getdns_tls_connection* conn, _getdns_tls_session* s); + +/** + * Get the session for this connection. + * + * @param mfs pointer to getdns memory functions. + * @param conn the connection. + * @return pointer to the session or NULL on error. + */ +_getdns_tls_session* _getdns_tls_connection_get_session(struct mem_funcs* mfs, _getdns_tls_connection* conn); + +/** + * Report the TLS version of the connection. + * + * @param conn the connection. + * @return string with the connection description, NULL on error. + */ +const char* _getdns_tls_connection_get_version(_getdns_tls_connection* conn); + +/** + * Attempt TLS handshake. + * + * @param conn the connection. + * @return GETDNS_RETURN_GOOD if handshake is complete. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_TLS_WANT_READ if handshake needs to read to proceed. + * @return GETDNS_RETURN_TLS_WANT_WRITE if handshake needs to write to proceed. + * @return GETDNS_RETURN_GENERIC_ERROR if handshake failed. + */ +getdns_return_t _getdns_tls_connection_do_handshake(_getdns_tls_connection* conn); + +/** + * Get the connection peer certificate. + * + * @param mfs pointer to getdns memory functions. + * @param conn the connection. + * @return certificate or NULL on error. + */ +_getdns_tls_x509* _getdns_tls_connection_get_peer_certificate(struct mem_funcs* mfs, _getdns_tls_connection* conn); + +/** + * See whether the connection is reusing a session. + * + * @param conn the connection. + * @return GETDNS_RETURN_GOOD if connection is being reused. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_TLS_CONNECTION_FRESH if connection is not being reused. + */ +getdns_return_t _getdns_tls_connection_is_session_reused(_getdns_tls_connection* conn); + +/** + * Set up host name verification. + * + * @param conn the connection. + * @param auth_name the hostname. + * @return GETDNS_RETURN_GOOD if all OK. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + */ +getdns_return_t _getdns_tls_connection_setup_hostname_auth(_getdns_tls_connection* conn, const char* auth_name); + +/** + * Set host pinset. + * + * @param conn the connection. + * @param auth_name the hostname. + * @return GETDNS_RETURN_GOOD if all OK. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + */ +getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* conn, const char* auth_name, const sha256_pin_t* pinset); + +/** + * Get result of certificate verification. + * + * @param conn the connection. + * @param errno failure error number. + * @param errmsg failure error message. + * @return GETDNS_RETURN_GOOD if all OK. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_GENERIC_ERROR if verification failed. + */ +getdns_return_t _getdns_tls_connection_certificate_verify(_getdns_tls_connection* conn, long* errnum, const char** errmsg); + +/** + * Read from TLS. + * + * @param conn the connection. + * @param buf the buffer to read to. + * @param to_read the number of bytes to read. + * @param read pointer to holder for the number of bytes read. + * @return GETDNS_RETURN_GOOD if some bytes were read. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_TLS_WANT_READ if the read needs to be retried. + * @return GETDNS_RETURN_TLS_WANT_WRITE if handshake isn't finished. + * @return GETDNS_RETURN_GENERIC_ERROR if read failed. + */ +getdns_return_t _getdns_tls_connection_read(_getdns_tls_connection* conn, uint8_t* buf, size_t to_read, size_t* read); + +/** + * Write to TLS. + * + * @param conn the connection. + * @param buf the buffer to write from. + * @param to_write the number of bytes to write. + * @param written the number of bytes written. + * @return GETDNS_RETURN_GOOD if some bytes were read. + * @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL. + * @return GETDNS_RETURN_TLS_WANT_READ if handshake isn't finished. + * @return GETDNS_RETURN_TLS_WANT_WRITE if the write needs to be retried. + * @return GETDNS_RETURN_GENERIC_ERROR if write failed. + */ +getdns_return_t _getdns_tls_connection_write(_getdns_tls_connection* conn, uint8_t* buf, size_t to_write, size_t* written); + +/** + * Free a session. + * + * @param mfs pointer to getdns memory functions. + * @param s the session. + * @return GETDNS_RETURN_GOOD on success. + * @return GETDNS_RETURN_INVALID_PARAMETER if s is null or has no SSL. + */ +getdns_return_t _getdns_tls_session_free(struct mem_funcs* mfs, _getdns_tls_session* s); + +/** + * Free X509 certificate. + * + * @param mfs pointer to getdns memory functions. + * @param cert the certificate. + */ +void _getdns_tls_x509_free(struct mem_funcs* mfs, _getdns_tls_x509* cert); + +/** + * Convert X509 to DER. + * + * @param cert the certificate. + * @param buf buffer to receive conversion. + * @return length of conversion, 0 on error. + */ +int _getdns_tls_x509_to_der(struct mem_funcs* mfs, _getdns_tls_x509* cert, getdns_bindata* bindata); + +/** + * Fill in dictionary with TLS API information. + * + * @param dict the dictionary to add to. + * @return GETDNS_RETURN_GOOD if some bytes were read. + * @return GETDNS_RETURN_GENERIC_ERROR if items cannot be set. + */ +getdns_return_t _getdns_tls_get_api_information(getdns_dict* dict); + +/** + * Return buffer with HMAC hash. + * + * @param mfs pointer to getdns memory functions. + * @param algorithm hash algorithm to use (GETDNS_HMAC_?). + * @param key the key. + * @param key_size the key size. + * @param data the data to hash. + * @param data_size the data size. + * @param output_size the output size will be written here if not NULL. + * @return output malloc'd buffer with output, NULL on error. + */ +unsigned char* _getdns_tls_hmac_hash(struct mem_funcs* mfs, int algorithm, const void* key, size_t key_size, const void* data, size_t data_size, size_t* output_size); + +/** + * Return a new HMAC handle. + * + * @param mfs pointer to getdns memory functions. + * @param algorithm hash algorithm to use (GETDNS_HMAC_?). + * @param key the key. + * @param key_size the key size. + * @return HMAC handle or NULL on error. + */ +_getdns_tls_hmac* _getdns_tls_hmac_new(struct mem_funcs* mfs, int algorithm, const void* key, size_t key_size); + +/** + * Add data to a HMAC. + * + * @param h the HMAC. + * @param data the data to add. + * @param data_size the size of data to add. + * @return GETDNS_RETURN_GOOD if added. + * @return GETDNS_RETURN_INVALID_PARAMETER if h is null or has no HMAC. + * @return GETDNS_RETURN_GENERIC_ERROR on error. + */ +getdns_return_t _getdns_tls_hmac_add(_getdns_tls_hmac* h, const void* data, size_t data_size); + +/** + * Return the HMAC digest and free the handle. + * + * @param mfs pointer to getdns memory functions. + * @param h the HMAC. + * @param output_size the output size will be written here if not NULL. + * @return output malloc'd buffer with output, NULL on error. + */ +unsigned char* _getdns_tls_hmac_end(struct mem_funcs* mfs, _getdns_tls_hmac* h, size_t* output_size); + +/** + * Calculate a SHA1 hash. + * + * @param data the data to hash. + * @param data_size the size of the data to hash. + * @param buf the buffer to receive the hash. Must be at least + * SHA_DIGEST_LENGTH bytes. + */ +void _getdns_tls_sha1(const void* data, size_t data_size, unsigned char* buf); + +/** + * Calculate SHA256 for cookie. + * + * @param secret the secret. + * @param addr the address. + * @param addrlen the address length. + * @param buf buffer to receive hash. + * @param buflen receive the hash length. + */ +void _getdns_tls_cookie_sha256(uint32_t secret, void* addr, size_t addrlen, unsigned char* buf, size_t* buflen); + +#endif /* _GETDNS_TLS_H */ diff --git a/src/tools/Makefile.in b/src/tools/Makefile.in index 88d5f21d..6cefffcd 100644 --- a/src/tools/Makefile.in +++ b/src/tools/Makefile.in @@ -127,10 +127,7 @@ getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c \ $(srcdir)/../debug.h \ ../getdns/getdns.h \ ../getdns/getdns_extra.h - -# Dependencies for getdns_server_mon getdns_server_mon.lo getdns_server_mon.o: $(srcdir)/getdns_server_mon.c \ ../config.h \ - $(srcdir)/../debug.h \ ../getdns/getdns.h \ ../getdns/getdns_extra.h diff --git a/src/tools/getdns_server_mon.c b/src/tools/getdns_server_mon.c index 360bf520..3b2d1045 100644 --- a/src/tools/getdns_server_mon.c +++ b/src/tools/getdns_server_mon.c @@ -36,9 +36,13 @@ #include #include +#ifdef USE_GNUTLS +#include +#else #include #include #include +#endif #include #include @@ -181,7 +185,7 @@ static const char *rcode_text(int rcode) return getdns_intval_text(rcode, "rcode", "GETDNS_RCODE_"); } -#if OPENSSL_VERSION_NUMBER < 0x10002000 || defined(LIBRESSL_VERSION_NUMBER) +#if !defined(USE_GNUTLS) && (OPENSSL_VERSION_NUMBER < 0x10002000 || defined(LIBRESSL_VERSION_NUMBER)) /* * Convert date to Julian day. * See https://en.wikipedia.org/wiki/Julian_day @@ -212,6 +216,27 @@ static long secs_in_day(const struct tm *tm) */ static bool extract_cert_expiry(const unsigned char *data, size_t len, time_t *t) { +#ifdef USE_GNUTLS + gnutls_x509_crt_t cert; + gnutls_datum_t datum; + bool res = false; + + datum.data = (unsigned char*) data; + datum.size = len; + + if (gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS) + return false; + + if (gnutls_x509_crt_import(cert, &datum, GNUTLS_X509_FMT_DER) == GNUTLS_E_SUCCESS) { + time_t expiry = gnutls_x509_crt_get_expiration_time(cert); + if (expiry != GNUTLS_X509_NO_WELL_DEFINED_EXPIRATION) { + res = true; + *t = expiry; + } + } + gnutls_x509_crt_deinit(cert); + return res; +#else X509 *cert = d2i_X509(NULL, &data, len); if (!cert) return false; @@ -299,6 +324,7 @@ static bool extract_cert_expiry(const unsigned char *data, size_t len, time_t *t X509_free(cert); #endif *t += day_diff * SECS_IN_DAY + sec_diff; +#endif /* USE_GNUTLS */ return true; } diff --git a/src/util-internal.c b/src/util-internal.c index 5b007c0b..a592b90d 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -934,7 +934,7 @@ _getdns_create_call_reporting_dict( return NULL; } netreq->debug_tls_peer_cert.size = 0; - OPENSSL_free(netreq->debug_tls_peer_cert.data); + GETDNS_FREE(context->my_mf, netreq->debug_tls_peer_cert.data); netreq->debug_tls_peer_cert.data = NULL; return netreq_debug; } diff --git a/src/util-internal.h b/src/util-internal.h index d512a9d2..8a1a6d82 100644 --- a/src/util-internal.h +++ b/src/util-internal.h @@ -219,46 +219,5 @@ INLINE uint64_t _getdns_ms_until_expiry2(uint64_t expires, uint64_t *now_ms) return *now_ms >= expires ? 0 : expires - *now_ms; } -#if defined(HAVE_DECL_SSL_SET_MIN_PROTO_VERSION) \ - && HAVE_DECL_SSL_SET_MIN_PROTO_VERSION - -INLINE int _getdns_tls_version2openssl_version(getdns_tls_version_t v) -{ - switch (v) { -# ifdef SSL3_VERSION - case GETDNS_SSL3 : return SSL3_VERSION; -# endif -# ifdef TLS1_VERSION - case GETDNS_TLS1 : return TLS1_VERSION; -# endif -# ifdef TLS1_1_VERSION - case GETDNS_TLS1_1: return TLS1_1_VERSION; -# endif -# ifdef TLS1_2_VERSION - case GETDNS_TLS1_2: return TLS1_2_VERSION; -# endif -# ifdef TLS1_3_VERSION - case GETDNS_TLS1_3: return TLS1_3_VERSION; -# endif - default : -# if defined(TLS_MAX_VERSION) - return TLS_MAX_VERSION; -# elif defined(TLS1_3_VERSION) - return TLS1_3_VERSION; -# elif defined(TLS1_2_VERSION) - return TLS1_2_VERSION; -# elif defined(TLS1_1_VERSION) - return TLS1_1_VERSION; -# elif defined(TLS1_VERSION) - return TLS1_VERSION; -# elif defined(SSL3_VERSION) - return SSL3_VERSION; -# else - return -1; -# endif - } -} -#endif - #endif /* util-internal.h */ diff --git a/src/util/auxiliary/validator/val_secalgo.h b/src/util/auxiliary/validator/val_secalgo.h deleted file mode 100644 index 1e187cba..00000000 --- a/src/util/auxiliary/validator/val_secalgo.h +++ /dev/null @@ -1 +0,0 @@ -#include "util/val_secalgo.h" diff --git a/src/util/val_secalgo.h b/src/util/val_secalgo.h index 350007f7..3554c658 100644 --- a/src/util/val_secalgo.h +++ b/src/util/val_secalgo.h @@ -1,7 +1,7 @@ /** * - * \file rbtree.h - * /brief Alternative symbol names for unbound's rbtree.h + * \file val_secalgo.h + * /brief secalgo interface. * */ /* @@ -32,53 +32,23 @@ */ #ifndef VAL_SECALGO_H_SYMBOLS #define VAL_SECALGO_H_SYMBOLS -#define sldns_buffer gldns_buffer -#define nsec3_hash_algo_size_supported _getdns_nsec3_hash_algo_size_supported -#define secalgo_nsec3_hash _getdns_secalgo_nsec3_hash -#define secalgo_hash_sha256 _getdns_secalgo_hash_sha256 -#define ds_digest_size_supported _getdns_ds_digest_size_supported -#define secalgo_ds_digest _getdns_secalgo_ds_digest -#define dnskey_algo_id_is_supported _getdns_dnskey_algo_id_is_supported -#define verify_canonrrset _getdns_verify_canonrrset -#define sec_status _getdns_sec_status -#define sec_status_secure _getdns_sec_status_secure -#define sec_status_insecure _getdns_sec_status_insecure -#define sec_status_unchecked _getdns_sec_status_unchecked -#define sec_status_bogus _getdns_sec_status_bogus -#define fake_sha1 _getdns_fake_sha1 -#define fake_dsa _getdns_fake_dsa + +#include "gldns/gbuffer.h" enum sec_status { sec_status_bogus = 0 , sec_status_unchecked = 0 , sec_status_insecure = 0 , sec_status_secure = 1 }; -#define NSEC3_HASH_SHA1 0x01 -#define LDNS_SHA1 GLDNS_SHA1 -#define LDNS_SHA256 GLDNS_SHA256 -#define LDNS_SHA384 GLDNS_SHA384 -#define LDNS_HASH_GOST GLDNS_HASH_GOST -#define LDNS_RSAMD5 GLDNS_RSAMD5 -#define LDNS_DSA GLDNS_DSA -#define LDNS_DSA_NSEC3 GLDNS_DSA_NSEC3 -#define LDNS_RSASHA1 GLDNS_RSASHA1 -#define LDNS_RSASHA1_NSEC3 GLDNS_RSASHA1_NSEC3 -#define LDNS_RSASHA256 GLDNS_RSASHA256 -#define LDNS_RSASHA512 GLDNS_RSASHA512 -#define LDNS_ECDSAP256SHA256 GLDNS_ECDSAP256SHA256 -#define LDNS_ECDSAP384SHA384 GLDNS_ECDSAP384SHA384 -#define LDNS_ECC_GOST GLDNS_ECC_GOST -#define LDNS_ED25519 GLDNS_ED25519 -#define LDNS_ED448 GLDNS_ED448 -#define sldns_ed255192pkey_raw gldns_ed255192pkey_raw -#define sldns_ed4482pkey_raw gldns_ed4482pkey_raw -#define sldns_key_EVP_load_gost_id gldns_key_EVP_load_gost_id -#define sldns_digest_evp gldns_digest_evp -#define sldns_key_buf2dsa_raw gldns_key_buf2dsa_raw -#define sldns_key_buf2rsa_raw gldns_key_buf2rsa_raw -#define sldns_gost2pkey_raw gldns_gost2pkey_raw -#define sldns_ecdsa2pkey_raw gldns_ecdsa2pkey_raw -#define sldns_buffer_begin gldns_buffer_begin -#define sldns_buffer_limit gldns_buffer_limit -#include "util/orig-headers/val_secalgo.h" +size_t _getdns_ds_digest_size_supported(int algo); + +int _getdns_secalgo_ds_digest(int algo, unsigned char* buf, size_t len, + unsigned char* res); + +int _getdns_dnskey_algo_id_is_supported(int id); + +enum sec_status _getdns_verify_canonrrset(struct gldns_buffer* buf, int algo, + unsigned char* sigblock, unsigned int sigblock_len, + unsigned char* key, unsigned int keylen, char** reason); + #endif diff --git a/stubby b/stubby index 9c6e55a1..8fb853ac 160000 --- a/stubby +++ b/stubby @@ -1 +1 @@ -Subproject commit 9c6e55a16af8f3258736b804b17eac3d35daebf3 +Subproject commit 8fb853ac8d6148fd9b53fdcbc107ecd375071ec5