From d8cc7b1ba3b70302d5495f2288c2358dbe6515dc Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Fri, 25 Sep 2015 11:48:58 +0200 Subject: [PATCH] Native signature verification --- configure.ac | 197 ++++++++++++++++++++++++++++++++++++++++++++ src/dnssec.c | 34 +++----- src/util-internal.h | 14 ++++ src/util/log.h | 11 ++- 4 files changed, 231 insertions(+), 25 deletions(-) diff --git a/configure.ac b/configure.ac index 4a6ff889..949d6a03 100644 --- a/configure.ac +++ b/configure.ac @@ -193,7 +193,204 @@ case "$enable_native_stub_dnssec" in ;; esac +USE_NSS="no" +# openssl +if test $USE_NSS = "no"; then ACX_WITH_SSL_OPTIONAL +ACX_LIB_SSL +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,strlcat,arc4random,arc4random_uniform,reallocarray]) +else + AC_MSG_RESULT([no]) +fi +AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) +AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) +AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode]) +AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ +AC_INCLUDES_DEFAULT +#ifdef HAVE_OPENSSL_ERR_H +#include +#endif + +#ifdef HAVE_OPENSSL_RAND_H +#include +#endif + +#ifdef HAVE_OPENSSL_CONF_H +#include +#endif + +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#endif +#include +#include +]) +fi + + +AC_ARG_ENABLE(sha2, AC_HELP_STRING([--disable-sha2], [Disable SHA256 and SHA512 RRSIG support])) +case "$enable_sha2" in + no) + ;; + yes|*) + AC_DEFINE([USE_SHA2], [1], [Define this to enable SHA256 and SHA512 support.]) + ;; +esac + +# check wether gost also works +AC_DEFUN([AC_CHECK_GOST_WORKS], +[AC_REQUIRE([AC_PROG_CC]) +AC_MSG_CHECKING([if GOST works]) +if test c${cross_compiling} = cno; then +BAKCFLAGS="$CFLAGS" +if test -n "$ssldir"; then + CFLAGS="$CFLAGS -Wl,-rpath,$ssldir/lib" +fi +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +#include +#include +/* routine to load gost (from sldns) */ +int 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; + } + EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth); + return gost_id; +} +int main(void) { + EVP_MD_CTX* ctx; + const EVP_MD* md; + unsigned char digest[64]; /* its a 256-bit digest, so uses 32 bytes */ + const char* str = "Hello world"; + const unsigned char check[] = { + 0x40 , 0xed , 0xf8 , 0x56 , 0x5a , 0xc5 , 0x36 , 0xe1 , + 0x33 , 0x7c , 0x7e , 0x87 , 0x62 , 0x1c , 0x42 , 0xe0 , + 0x17 , 0x1b , 0x5e , 0xce , 0xa8 , 0x46 , 0x65 , 0x4d , + 0x8d , 0x3e , 0x22 , 0x9b , 0xe1 , 0x30 , 0x19 , 0x9d + }; + OPENSSL_config(NULL); + (void)load_gost_id(); + md = EVP_get_digestbyname("md_gost94"); + if(!md) return 1; + memset(digest, 0, sizeof(digest)); + ctx = EVP_MD_CTX_create(); + if(!ctx) return 2; + if(!EVP_DigestInit_ex(ctx, md, NULL)) return 3; + if(!EVP_DigestUpdate(ctx, str, 10)) return 4; + if(!EVP_DigestFinal_ex(ctx, digest, NULL)) return 5; + /* uncomment to see the hash calculated. + {int i; + for(i=0; i<32; i++) + printf(" %2.2x", (int)digest[i]); + printf("\n");} + */ + if(memcmp(digest, check, sizeof(check)) != 0) + return 6; + return 0; +} +]])] , [eval "ac_cv_c_gost_works=yes"], [eval "ac_cv_c_gost_works=no"]) +CFLAGS="$BAKCFLAGS" +else +eval "ac_cv_c_gost_works=maybe" +fi +AC_MSG_RESULT($ac_cv_c_gost_works) +])dnl + +AC_ARG_ENABLE(gost, AC_HELP_STRING([--disable-gost], [Disable GOST support])) +use_gost="no" +if test $USE_NSS = "no"; then +case "$enable_gost" in + no) + ;; + *) + AC_CHECK_FUNC(EVP_PKEY_set_type_str, [:],[AC_MSG_ERROR([OpenSSL 1.0.0 is needed for GOST support])]) + AC_CHECK_FUNC(EC_KEY_new, [], [AC_MSG_ERROR([OpenSSL does not support ECC, needed for GOST support])]) + AC_CHECK_GOST_WORKS + if test "$ac_cv_c_gost_works" != no; then + use_gost="yes" + AC_DEFINE([USE_GOST], [1], [Define this to enable GOST support.]) + fi + ;; +esac +fi dnl !USE_NSS + +AC_ARG_ENABLE(ecdsa, AC_HELP_STRING([--disable-ecdsa], [Disable ECDSA support])) +use_ecdsa="no" +case "$enable_ecdsa" in + no) + ;; + *) + if test $USE_NSS = "no"; then + AC_CHECK_FUNC(ECDSA_sign, [], [AC_MSG_ERROR([OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa])]) + AC_CHECK_FUNC(SHA384_Init, [], [AC_MSG_ERROR([OpenSSL does not support SHA384: please upgrade or rerun with --disable-ecdsa])]) + AC_CHECK_DECLS([NID_X9_62_prime256v1, NID_secp384r1], [], [AC_MSG_ERROR([OpenSSL does not support the ECDSA curves: please upgrade or rerun with --disable-ecdsa])], [AC_INCLUDES_DEFAULT +#include + ]) + # see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency) + AC_MSG_CHECKING([if openssl supports SHA2 and ECDSA with EVP]) + if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then + if grep OPENSSL_VERSION_NUMBER $ssldir/include/openssl/opensslv.h | grep 0x0 >/dev/null; then + AC_MSG_RESULT([no]) + AC_DEFINE_UNQUOTED([USE_ECDSA_EVP_WORKAROUND], [1], [Define this to enable an EVP workaround for older openssl]) + else + AC_MSG_RESULT([yes]) + fi + else + # not OpenSSL, thus likely LibreSSL, which supports it + AC_MSG_RESULT([yes]) + fi + fi + # we now know we have ECDSA and the required curves. + AC_DEFINE_UNQUOTED([USE_ECDSA], [1], [Define this to enable ECDSA support.]) + use_ecdsa="yes" + ;; +esac + AC_ARG_ENABLE(draft-edns-cookies, AC_HELP_STRING([--enable-draft-edns-cookies], [Enable experimental edns cookies])) diff --git a/src/dnssec.c b/src/dnssec.c index e1e6a5c1..ec22495d 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -1553,6 +1553,7 @@ static int _getdns_verify_rrsig(struct mem_funcs *mf, size_t cdname_len, pos; uint32_t orig_ttl; gldns_buffer valbuf; + char *reason; /* nc_name should already have been initialized by the parent! */ assert(nc_name); @@ -1646,30 +1647,15 @@ static int _getdns_verify_rrsig(struct mem_funcs *mf, , gldns_buffer_position(&valbuf)); assert(gldns_buffer_position(&valbuf) == valbuf_sz); - /* Check with ldns to verify we're still on the right path. - */ - if (1) { - ldns_buffer lvalbuf; + r = _getdns_verify_canonrrset(&valbuf, key->rr_i.rr_type[13], + signer->nxt, rrsig->rr_i.nxt - signer->nxt, + key->rr_i.rr_type+14, key->rr_i.nxt - key->rr_i.rr_type-14, + &reason); - ldns_buffer_new_frm_data( &lvalbuf - , gldns_buffer_begin(&valbuf) - , gldns_buffer_position(&valbuf)); - ldns_buffer_set_position( &lvalbuf - , gldns_buffer_position(&valbuf)); - - r = ldns_verify_rrsig_buffers_raw( - /* sig, siglen */ - signer->nxt, rrsig->rr_i.nxt - signer->nxt, - - /* verify buf */ - &lvalbuf, - - /* key, keylen */ - key->rr_i.rr_type+14, key->rr_i.nxt - key->rr_i.rr_type-14, - - /* algo */ - key->rr_i.rr_type[13]) == LDNS_STATUS_OK; - } +#if defined(SEC_DEBUG) && SEC_DEBUG + if (r == 0) + DEBUG_SEC("verification failed: %s\n", reason); +#endif if (val_rrset != val_rrset_spc) GETDNS_FREE(*mf, val_rrset); if (valbuf_buf != valbuf_spc) @@ -1806,7 +1792,7 @@ static int nsec3_iteration_count_high(rrtype_iter *dnskey, getdns_rrset *nsec3) || rr->rr_i.rr_type + 14 > rr->rr_i.nxt) return 1; - bits = ldns_rr_dnskey_key_size_raw(dnskey->rr_i.rr_type + 10, + bits = gldns_rr_dnskey_key_size_raw(dnskey->rr_i.rr_type + 10, dnskey->rr_i.nxt - dnskey->rr_i.rr_type - 10, dnskey->rr_i.rr_type[13]); diff --git a/src/util-internal.h b/src/util-internal.h index d06d59d7..b6db818a 100644 --- a/src/util-internal.h +++ b/src/util-internal.h @@ -165,6 +165,20 @@ getdns_return_t _getdns_validate_extensions(struct getdns_dict * extensions); fprintf(stderr, __VA_ARGS__); \ } while (0) +#define DEBUG_NL(...) do { \ + struct timeval tv; \ + struct tm tm; \ + char buf[10]; \ + \ + gettimeofday(&tv, NULL); \ + gmtime_r(&tv.tv_sec, &tm); \ + strftime(buf, 10, "%T", &tm); \ + fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } while (0) + + #define DEBUG_OFF(...) do {} while (0) #if defined(SCHED_DEBUG) && SCHED_DEBUG diff --git a/src/util/log.h b/src/util/log.h index e05dff13..87f6cd31 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -34,9 +34,18 @@ #ifndef UTIL_LOG_H #define UTIL_LOG_H -#define log_assert(x) +#include "config.h" +#include "util-internal.h" + +#if defined(SEC_DEBUG) && SEC_DEBUG +#define verbose(x, ...) DEBUG_NL(__VA_ARGS__) +#define log_err(...) DEBUG_NL(__VA_ARGS__) +#else #define verbose(...) #define log_err(...) +#endif + +#define log_assert(x) #endif /* UTIL_LOG_H */