From: Wouter Wijngaards Date: Tue, 17 Nov 2015 09:43:07 +0000 (+0000) Subject: - Fix #594. libunbound: optionally use libnettle for crypto. X-Git-Tag: release-1.5.7rc1~37 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2bdea62a9eb56e1ddfda2c643562f52682ea67a4;p=thirdparty%2Funbound.git - Fix #594. libunbound: optionally use libnettle for crypto. Contributed by Luca Bruno. Added --with-nettle for use with --with-libunbound-only. git-svn-id: file:///svn/unbound/trunk@3533 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/Makefile.in b/Makefile.in index b2e5ba334..4ffb5e45e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -38,6 +38,7 @@ UNBOUND_VERSION_MINOR=@UNBOUND_VERSION_MINOR@ UNBOUND_VERSION_MICRO=@UNBOUND_VERSION_MICRO@ ALLTARGET=@ALLTARGET@ INSTALLTARGET=@INSTALLTARGET@ +SSLLIB=@SSLLIB@ # _unbound.la if pyunbound enabled. PYUNBOUND_TARGET=@PYUNBOUND_TARGET@ @@ -295,22 +296,22 @@ longtest: tests lib: libunbound.la unbound.h libunbound.la: $(LIBUNBOUND_OBJ_LINK) - $(LINK_LIB) $(UBSYMS) -o $@ $(LIBUNBOUND_OBJ_LINK) -rpath $(libdir) -lssl $(LIBS) + $(LINK_LIB) $(UBSYMS) -o $@ $(LIBUNBOUND_OBJ_LINK) -rpath $(libdir) $(SSLLIB) $(LIBS) unbound$(EXEEXT): $(DAEMON_OBJ_LINK) libunbound.la - $(LINK) -o $@ $(DAEMON_OBJ_LINK) $(EXTRALINK) -lssl $(LIBS) + $(LINK) -o $@ $(DAEMON_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS) unbound-checkconf$(EXEEXT): $(CHECKCONF_OBJ_LINK) libunbound.la - $(LINK) -o $@ $(CHECKCONF_OBJ_LINK) $(EXTRALINK) -lssl $(LIBS) + $(LINK) -o $@ $(CHECKCONF_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS) unbound-control$(EXEEXT): $(CONTROL_OBJ_LINK) libunbound.la - $(LINK) -o $@ $(CONTROL_OBJ_LINK) $(EXTRALINK) -lssl $(LIBS) + $(LINK) -o $@ $(CONTROL_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS) unbound-host$(EXEEXT): $(HOST_OBJ_LINK) libunbound.la $(LINK) -o $@ $(HOST_OBJ_LINK) -L. -L.libs -lunbound $(LIBS) unbound-anchor$(EXEEXT): $(UBANCHOR_OBJ_LINK) libunbound.la - $(LINK) -o $@ $(UBANCHOR_OBJ_LINK) -L. -L.libs -lunbound -lexpat -lssl $(LIBS) + $(LINK) -o $@ $(UBANCHOR_OBJ_LINK) -L. -L.libs -lunbound -lexpat $(SSLLIB) $(LIBS) unbound-service-install$(EXEEXT): $(SVCINST_OBJ_LINK) $(LINK) -o $@ $(SVCINST_OBJ_LINK) $(LIBS) @@ -322,37 +323,37 @@ anchor-update$(EXEEXT): $(ANCHORUPD_OBJ_LINK) libunbound.la $(LINK) -o $@ $(ANCHORUPD_OBJ_LINK) -L. -L.libs -lunbound $(LIBS) unittest$(EXEEXT): $(UNITTEST_OBJ_LINK) - $(LINK) -o $@ $(UNITTEST_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(UNITTEST_OBJ_LINK) $(SSLLIB) $(LIBS) testbound$(EXEEXT): $(TESTBOUND_OBJ_LINK) - $(LINK) -o $@ $(TESTBOUND_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(TESTBOUND_OBJ_LINK) $(SSLLIB) $(LIBS) lock-verify$(EXEEXT): $(LOCKVERIFY_OBJ_LINK) - $(LINK) -o $@ $(LOCKVERIFY_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(LOCKVERIFY_OBJ_LINK) $(SSLLIB) $(LIBS) petal$(EXEEXT): $(PETAL_OBJ_LINK) - $(LINK) -o $@ $(PETAL_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(PETAL_OBJ_LINK) $(SSLLIB) $(LIBS) pktview$(EXEEXT): $(PKTVIEW_OBJ_LINK) - $(LINK) -o $@ $(PKTVIEW_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(PKTVIEW_OBJ_LINK) $(SSLLIB) $(LIBS) memstats$(EXEEXT): $(MEMSTATS_OBJ_LINK) - $(LINK) -o $@ $(MEMSTATS_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(MEMSTATS_OBJ_LINK) $(SSLLIB) $(LIBS) asynclook$(EXEEXT): $(ASYNCLOOK_OBJ_LINK) libunbound.la $(LINK) -o $@ $(ASYNCLOOK_OBJ_LINK) $(LIBS) -L. -L.libs -lunbound streamtcp$(EXEEXT): $(STREAMTCP_OBJ_LINK) - $(LINK) -o $@ $(STREAMTCP_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(STREAMTCP_OBJ_LINK) $(SSLLIB) $(LIBS) perf$(EXEEXT): $(PERF_OBJ_LINK) - $(LINK) -o $@ $(PERF_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(PERF_OBJ_LINK) $(SSLLIB) $(LIBS) delayer$(EXEEXT): $(DELAYER_OBJ_LINK) - $(LINK) -o $@ $(DELAYER_OBJ_LINK) -lssl $(LIBS) + $(LINK) -o $@ $(DELAYER_OBJ_LINK) $(SSLLIB) $(LIBS) signit$(EXEEXT): testcode/signit.c - $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ testcode/signit.c $(LDFLAGS) -lldns -lssl $(LIBS) + $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ testcode/signit.c $(LDFLAGS) -lldns $(SSLLIB) $(LIBS) unbound.h: $(srcdir)/libunbound/unbound.h sed -e 's/@''UNBOUND_VERSION_MAJOR@/$(UNBOUND_VERSION_MAJOR)/' -e 's/@''UNBOUND_VERSION_MINOR@/$(UNBOUND_VERSION_MINOR)/' -e 's/@''UNBOUND_VERSION_MICRO@/$(UNBOUND_VERSION_MICRO)/' < $(srcdir)/libunbound/unbound.h > $@ diff --git a/compat/getentropy_linux.c b/compat/getentropy_linux.c index 76f0f9df5..ad86f234b 100644 --- a/compat/getentropy_linux.c +++ b/compat/getentropy_linux.c @@ -46,7 +46,12 @@ #include #include #include + +#if defined(HAVE_SSL) #include +#elif defined(HAVE_NETTLE) +#include +#endif #include #include @@ -67,9 +72,21 @@ HD(b); \ } while (0) +#if defined(HAVE_SSL) +#define CRYPTO_SHA512_CTX SHA512_CTX +#define CRYPTO_SHA512_INIT(x) SHA512_Init(x) +#define CRYPTO_SHA512_FINAL(r, c) SHA512_Final(r, c) #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) #define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) #define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) +#elif defined(HAVE_NETTLE) +#define CRYPTO_SHA512_CTX struct sha512_ctx +#define CRYPTO_SHA512_INIT(x) sha512_init(x) +#define CRYPTO_SHA512_FINAL(r, c) sha512_digest(c, SHA512_DIGEST_SIZE, r) +#define HR(x, l) (sha512_update(&ctx, (l), (uint8_t *)(x))) +#define HD(x) (sha512_update(&ctx, sizeof (x), (uint8_t *)&(x))) +#define HF(x) (sha512_update(&ctx, sizeof (void*), (uint8_t *)&(x))) +#endif int getentropy(void *buf, size_t len); @@ -337,7 +354,7 @@ getentropy_fallback(void *buf, size_t len) struct rusage ru; sigset_t sigset; struct stat st; - SHA512_CTX ctx; + CRYPTO_SHA512_CTX ctx; static pid_t lastpid; pid_t pid; size_t i, ii, m; @@ -354,7 +371,7 @@ getentropy_fallback(void *buf, size_t len) } for (i = 0; i < len; ) { int j; - SHA512_Init(&ctx); + CRYPTO_SHA512_INIT(&ctx); for (j = 0; j < repeat; j++) { HX((e = gettimeofday(&tv, NULL)) == -1, tv); if (e != -1) { @@ -526,7 +543,7 @@ getentropy_fallback(void *buf, size_t len) # endif #endif /* HAVE_GETAUXVAL */ - SHA512_Final(results, &ctx); + CRYPTO_SHA512_FINAL(results, &ctx); memcpy((char*)buf + i, results, min(sizeof(results), len - i)); i += min(sizeof(results), len - i); } diff --git a/config.h.in b/config.h.in index 1e44741a3..e90f036cf 100644 --- a/config.h.in +++ b/config.h.in @@ -242,6 +242,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H +/* Use libnettle for crypto */ +#undef HAVE_NETTLE + /* Use libnss for crypto */ #undef HAVE_NSS diff --git a/configure b/configure index 7e2374414..acfb10739 100755 --- a/configure +++ b/configure @@ -661,6 +661,7 @@ CHECKLOCK_OBJ staticexe UNBOUND_EVENT_UNINSTALL UNBOUND_EVENT_INSTALL +SSLLIB HAVE_SSL CONFIG_DATE NETBSD_LINTFLAGS @@ -823,6 +824,7 @@ with_solaris_threads with_pyunbound with_pythonmodule with_nss +with_nettle with_ssl enable_sha2 enable_gost @@ -1534,6 +1536,7 @@ Optional Packages: --with-pythonmodule build Python module, or --without-pythonmodule to disable script engine. (default=no) --with-nss=path use libnss instead of openssl, installed at path. + --with-nettle=path use libnettle as crypto library, installed at path. --with-ssl=pathname enable SSL (will check /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr) @@ -16408,13 +16411,44 @@ $as_echo "#define HAVE_NSS 1" >>confdefs.h CPPFLAGS="-I/usr/include/nspr4 $CPPFLAGS" fi LIBS="$LIBS -lnss3 -lnspr4" + SSLLIB="" + + +fi + + +# libnettle +USE_NETTLE="no" + +# Check whether --with-nettle was given. +if test "${with_nettle+set}" = set; then : + withval=$with_nettle; + USE_NETTLE="yes" + +$as_echo "#define HAVE_NETTLE 1" >>confdefs.h + + if test "$withval" != "" -a "$withval" != "yes"; then + CPPFLAGS="$CPPFLAGS -I$withval/include/nettle" + LDFLAGS="$LDFLAGS -L$withval/lib" + + if test "x$enable_rpath" = xyes; then + if echo "$withval/lib" | grep "^/" >/dev/null; then + RUNTIME_PATH="$RUNTIME_PATH -R$withval/lib" + fi + fi + + else + CPPFLAGS="$CPPFLAGS -I/usr/include/nettle" + fi + LIBS="$LIBS -lhogweed -lnettle -lgmp" + SSLLIB="" fi # openssl -if test $USE_NSS = "no"; then +if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then # Check whether --with-ssl was given. @@ -16720,6 +16754,7 @@ fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +SSLLIB="-lssl" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LibreSSL" >&5 $as_echo_n "checking for LibreSSL... " >&6; } if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then @@ -16917,6 +16952,7 @@ _ACEOF fi + # Check whether --enable-sha2 was given. if test "${enable_sha2+set}" = set; then : enableval=$enable_sha2; @@ -16940,7 +16976,7 @@ if test "${enable_gost+set}" = set; then : fi use_gost="no" -if test $USE_NSS = "no"; then +if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then case "$enable_gost" in no) ;; @@ -17093,7 +17129,7 @@ case "$enable_ecdsa" in no) ;; *) - if test $USE_NSS = "no"; then + if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then ac_fn_c_check_func "$LINENO" "ECDSA_sign" "ac_cv_func_ECDSA_sign" if test "x$ac_cv_func_ECDSA_sign" = xyes; then : diff --git a/configure.ac b/configure.ac index dd7bd2a57..13d830456 100644 --- a/configure.ac +++ b/configure.ac @@ -563,13 +563,34 @@ AC_ARG_WITH([nss], AC_HELP_STRING([--with-nss=path], CPPFLAGS="-I/usr/include/nspr4 $CPPFLAGS" fi LIBS="$LIBS -lnss3 -lnspr4" + SSLLIB="" + ] +) + +# libnettle +USE_NETTLE="no" +AC_ARG_WITH([nettle], AC_HELP_STRING([--with-nettle=path], + [use libnettle as crypto library, installed at path.]), + [ + USE_NETTLE="yes" + AC_DEFINE(HAVE_NETTLE, 1, [Use libnettle for crypto]) + if test "$withval" != "" -a "$withval" != "yes"; then + CPPFLAGS="$CPPFLAGS -I$withval/include/nettle" + LDFLAGS="$LDFLAGS -L$withval/lib" + ACX_RUNTIME_PATH_ADD([$withval/lib]) + else + CPPFLAGS="$CPPFLAGS -I/usr/include/nettle" + fi + LIBS="$LIBS -lhogweed -lnettle -lgmp" + SSLLIB="" ] ) # openssl -if test $USE_NSS = "no"; then +if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then ACX_WITH_SSL ACX_LIB_SSL +SSLLIB="-lssl" AC_MSG_CHECKING([for LibreSSL]) if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then AC_MSG_RESULT([yes]) @@ -604,6 +625,7 @@ AC_INCLUDES_DEFAULT #include ]) fi +AC_SUBST(SSLLIB) AC_ARG_ENABLE(sha2, AC_HELP_STRING([--disable-sha2], [Disable SHA256 and SHA512 RRSIG support])) @@ -715,7 +737,7 @@ AC_MSG_RESULT($ac_cv_c_gost_works) AC_ARG_ENABLE(gost, AC_HELP_STRING([--disable-gost], [Disable GOST support])) use_gost="no" -if test $USE_NSS = "no"; then +if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then case "$enable_gost" in no) ;; @@ -729,7 +751,7 @@ case "$enable_gost" in fi ;; esac -fi dnl !USE_NSS +fi dnl !USE_NSS && !USE_NETTLE AC_ARG_ENABLE(ecdsa, AC_HELP_STRING([--disable-ecdsa], [Disable ECDSA support])) use_ecdsa="no" @@ -737,7 +759,7 @@ case "$enable_ecdsa" in no) ;; *) - if test $USE_NSS = "no"; then + if test $USE_NSS = "no" -a $USE_NETTLE = "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 diff --git a/doc/Changelog b/doc/Changelog index 1bbecfc33..a86cd6344 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,8 @@ +17 November 2015: Wouter + - Fix #594. libunbound: optionally use libnettle for crypto. + Contributed by Luca Bruno. Added --with-nettle for use with + --with-libunbound-only. + 16 November 2015: Wouter - Fix for lenient accept of reverse order DNAME and CNAME. diff --git a/testcode/testbound.c b/testcode/testbound.c index b297f4774..834dd0e4f 100644 --- a/testcode/testbound.c +++ b/testcode/testbound.c @@ -286,7 +286,7 @@ main(int argc, char* argv[]) testbound_selftest(); exit(0); case '2': -#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS)) && defined(USE_SHA2) +#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) printf("SHA256 supported\n"); exit(0); #else diff --git a/testcode/unitverify.c b/testcode/unitverify.c index 078af0a9c..9e75ce1c6 100644 --- a/testcode/unitverify.c +++ b/testcode/unitverify.c @@ -191,7 +191,8 @@ verifytest_rrset(struct module_env* env, struct val_env* ve, printf("verify outcome is: %s %s\n", sec_status_to_string(sec), reason?reason:""); } - if(should_be_bogus(rrset, qinfo)) { + if(should_be_bogus(rrset, qinfo) || + (reason && strncmp(reason, "(custom)", 8) == 0)) { unit_assert(sec == sec_status_bogus); } else { unit_assert(sec == sec_status_secure); @@ -504,12 +505,12 @@ verify_test(void) verifytest_file("testdata/test_signatures.6", "20080416005004"); verifytest_file("testdata/test_signatures.7", "20070829144150"); verifytest_file("testdata/test_signatures.8", "20070829144150"); -#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS)) && defined(USE_SHA2) +#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) verifytest_file("testdata/test_sigs.rsasha256", "20070829144150"); verifytest_file("testdata/test_sigs.sha1_and_256", "20070829144150"); verifytest_file("testdata/test_sigs.rsasha256_draft", "20090101000000"); #endif -#if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS)) && defined(USE_SHA2) +#if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) verifytest_file("testdata/test_sigs.rsasha512_draft", "20070829144150"); #endif verifytest_file("testdata/test_sigs.hinfo", "20090107100022"); diff --git a/util/random.c b/util/random.c index 71f0ba53e..684464e7d 100644 --- a/util/random.c +++ b/util/random.c @@ -68,6 +68,8 @@ /* nss3 */ #include "secport.h" #include "pk11pub.h" +#elif defined(HAVE_NETTLE) +#include "yarrow.h" #endif /** @@ -76,7 +78,7 @@ */ #define MAX_VALUE 0x7fffffff -#ifndef HAVE_NSS +#if defined(HAVE_SSL) void ub_systemseed(unsigned int ATTR_UNUSED(seed)) { @@ -110,7 +112,7 @@ ub_random_max(struct ub_randstate* state, long int x) return (long)arc4random_uniform((uint32_t)x); } -#else +#elif defined(HAVE_NSS) /* not much to remember for NSS since we use its pk11_random, placeholder */ struct ub_randstate { @@ -144,6 +146,72 @@ long int ub_random(struct ub_randstate* ATTR_UNUSED(state)) return x & MAX_VALUE; } +#elif defined(HAVE_NETTLE) + +/** + * libnettle implements a Yarrow-256 generator (SHA256 + AES), + * and we have to ensure it is seeded before use. + */ +struct ub_randstate { + struct yarrow256_ctx ctx; + int seeded; +}; + +void ub_systemseed(unsigned int ATTR_UNUSED(seed)) +{ +/** + * We seed on init and not here, as we need the ctx to re-seed. + * This also means that re-seeding is not supported. + */ + log_err("Re-seeding not supported, generator untouched"); +} + +struct ub_randstate* ub_initstate(unsigned int seed, + struct ub_randstate* ATTR_UNUSED(from)) +{ + struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s)); + uint8_t buf[YARROW256_SEED_FILE_SIZE]; + if(!s) { + log_err("malloc failure in random init"); + return NULL; + } + /* Setup Yarrow context */ + yarrow256_init(&s->ctx, 0, NULL); + + if(getentropy(buf, sizeof(buf)) != -1) { + /* got entropy */ + yarrow256_seed(&s->ctx, YARROW256_SEED_FILE_SIZE, buf); + s->seeded = yarrow256_is_seeded(&s->ctx); + } else { + /* Stretch the uint32 input seed and feed it to Yarrow */ + uint32_t v = seed; + size_t i; + for(i=0; i < (YARROW256_SEED_FILE_SIZE/sizeof(seed)); i++) { + memmove(buf+i*sizeof(seed), &v, sizeof(seed)); + v = v*seed + (uint32_t)i; + } + yarrow256_seed(&s->ctx, YARROW256_SEED_FILE_SIZE, buf); + s->seeded = yarrow256_is_seeded(&s->ctx); + } + + return s; +} + +long int ub_random(struct ub_randstate* s) +{ + /* random 31 bit value. */ + long int x = 0; + if (!s || !s->seeded) { + log_err("Couldn't generate randomness, Yarrow-256 generator not yet seeded"); + } else { + yarrow256_random(&s->ctx, sizeof(x), (uint8_t *)&x); + } + return x & MAX_VALUE; +} +#endif /* HAVE_SSL or HAVE_NSS or HAVE_NETTLE */ + + +#if defined(HAVE_NSS) || defined(HAVE_NETTLE) long int ub_random_max(struct ub_randstate* state, long int x) { @@ -155,7 +223,7 @@ ub_random_max(struct ub_randstate* state, long int x) v = ub_random(state); return (v % x); } -#endif /* HAVE_NSS */ +#endif /* HAVE_NSS or HAVE_NETTLE */ void ub_randfree(struct ub_randstate* s) diff --git a/validator/val_nsec3.c b/validator/val_nsec3.c index 80ca4d0ba..3ec157e74 100644 --- a/validator/val_nsec3.c +++ b/validator/val_nsec3.c @@ -48,6 +48,8 @@ #ifdef HAVE_NSS /* nss3 */ #include "sechash.h" +#elif defined(HAVE_NETTLE) +#include "sha1.h" #endif #include "validator/val_nsec3.h" #include "validator/validator.h" @@ -546,43 +548,70 @@ nsec3_get_hashed(sldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, sldns_buffer_write(buf, salt, saltlen); sldns_buffer_flip(buf); switch(algo) { -#if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS) +#if defined(HAVE_EVP_SHA1) case NSEC3_HASH_SHA1: -#ifdef HAVE_SSL hash_len = SHA_DIGEST_LENGTH; -#else - hash_len = SHA1_LENGTH; -#endif if(hash_len > max) return 0; -# ifdef HAVE_SSL (void)SHA1((unsigned char*)sldns_buffer_begin(buf), (unsigned long)sldns_buffer_limit(buf), (unsigned char*)res); -# else - (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)res, - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf)); -# endif for(i=0; i max) + return 0; + (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)res, + (unsigned char*)sldns_buffer_begin(buf), + (unsigned long)sldns_buffer_limit(buf)); + for(i=0; i max) + return 0; + sha1_init(&ctx); + sha1_update(&ctx, + (size_t)sldns_buffer_limit(buf), + (const uint8_t*)sldns_buffer_begin(buf)); + sha1_digest(&ctx, SHA1_DIGEST_SIZE, (uint8_t *)res); + for(i=0; ihash_len = SHA_DIGEST_LENGTH; -#else - c->hash_len = SHA1_LENGTH; -#endif - c->hash = (uint8_t*)regional_alloc(region, + c->hash = (uint8_t*)regional_alloc(region, c->hash_len); if(!c->hash) return 0; -# ifdef HAVE_SSL (void)SHA1((unsigned char*)sldns_buffer_begin(buf), (unsigned long)sldns_buffer_limit(buf), (unsigned char*)c->hash); -# else - (void)HASH_HashBuf(HASH_AlgSHA1, - (unsigned char*)c->hash, - (unsigned char*)sldns_buffer_begin(buf), - (unsigned long)sldns_buffer_limit(buf)); -# endif for(i=0; ihash, c->hash_len); sldns_buffer_write(buf, salt, saltlen); sldns_buffer_flip(buf); -# ifdef HAVE_SSL (void)SHA1( (unsigned char*)sldns_buffer_begin(buf), (unsigned long)sldns_buffer_limit(buf), (unsigned char*)c->hash); -# else + } + break; +#elif defined(HAVE_NSS) + case NSEC3_HASH_SHA1: + c->hash_len = SHA1_LENGTH; + c->hash = (uint8_t*)regional_alloc(region, + c->hash_len); + if(!c->hash) + return 0; + (void)HASH_HashBuf(HASH_AlgSHA1, + (unsigned char*)c->hash, + (unsigned char*)sldns_buffer_begin(buf), + (unsigned long)sldns_buffer_limit(buf)); + for(i=0; ihash, c->hash_len); + sldns_buffer_write(buf, salt, saltlen); + sldns_buffer_flip(buf); (void)HASH_HashBuf(HASH_AlgSHA1, (unsigned char*)c->hash, (unsigned char*)sldns_buffer_begin(buf), (unsigned long)sldns_buffer_limit(buf)); -# endif } break; -#endif /* HAVE_EVP_SHA1 or NSS */ +#elif defined(HAVE_NETTLE) + case NSEC3_HASH_SHA1: + { + struct sha1_ctx ctx; + c->hash_len = SHA1_DIGEST_SIZE; + c->hash = (uint8_t*)regional_alloc(region, + c->hash_len); + if(!c->hash) + return 0; + sha1_init(&ctx); + sha1_update(&ctx, + (size_t)sldns_buffer_limit(buf), + (const uint8_t*)sldns_buffer_begin(buf)); + sha1_digest(&ctx, SHA1_DIGEST_SIZE, (uint8_t *)c->hash); + for(i=0; ihash, c->hash_len); + sldns_buffer_write(buf, salt, saltlen); + sldns_buffer_flip(buf); + sha1_init(&ctx); + sha1_update(&ctx, + (size_t)sldns_buffer_limit(buf), + (const uint8_t*)sldns_buffer_begin(buf)); + sha1_digest(&ctx, SHA1_DIGEST_SIZE, (uint8_t *)c->hash); + } + break; + } +#endif /* HAVE_SSL or HAVE_NSS or HAVE_NETTLE */ default: log_err("nsec3 hash of unknown algo %d", algo); return -1; diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c index 8ed403dfc..dd56edf6f 100644 --- a/validator/val_secalgo.c +++ b/validator/val_secalgo.c @@ -49,7 +49,7 @@ #include "sldns/keyraw.h" #include "sldns/sbuffer.h" -#if !defined(HAVE_SSL) && !defined(HAVE_NSS) +#if !defined(HAVE_SSL) && !defined(HAVE_NSS) && !defined(HAVE_NETTLE) #error "Need crypto library to do digital signature cryptography" #endif @@ -74,7 +74,7 @@ /** * Return size of DS digest according to its hash algorithm. * @param algo: DS digest algo. - * @return size in bytes of digest, or 0 if not supported. + * @return size in bytes of digest, or 0 if not supported. */ size_t ds_digest_size_supported(int algo) @@ -1069,5 +1069,425 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, return sec_status_bogus; } +#elif defined(HAVE_NETTLE) -#endif /* HAVE_SSL or HAVE_NSS */ +#include "sha.h" +#include "bignum.h" +#include "macros.h" +#include "rsa.h" +#include "dsa.h" +#ifdef USE_ECDSA +#include "ecdsa.h" +#include "ecc-curve.h" +#endif + +/** + * Return size of DS digest according to its hash algorithm. + * @param algo: DS digest algo. + * @return size in bytes of digest, or 0 if not supported. + */ +size_t +ds_digest_size_supported(int algo) +{ + switch(algo) { + case LDNS_SHA1: + return SHA1_DIGEST_SIZE; +#ifdef USE_SHA2 + case LDNS_SHA256: + return SHA256_DIGEST_SIZE; +#endif +#ifdef USE_ECDSA + case LDNS_SHA384: + return SHA384_DIGEST_SIZE; +#endif + /* GOST not supported */ + case LDNS_HASH_GOST: + default: + break; + } + return 0; +} + + + +static int +_digest_nettle(int algo, uint8_t* buf, size_t len, + unsigned char* res) +{ + switch(algo) { + case SHA1_DIGEST_SIZE: + { + struct sha1_ctx ctx; + sha1_init(&ctx); + sha1_update(&ctx, len, buf); + sha1_digest(&ctx, SHA1_DIGEST_SIZE, res); + return 1; + } + case SHA256_DIGEST_SIZE: + { + struct sha256_ctx ctx; + sha256_init(&ctx); + sha256_update(&ctx, len, buf); + sha256_digest(&ctx, SHA256_DIGEST_SIZE, res); + return 1; + } + case SHA384_DIGEST_SIZE: + { + struct sha384_ctx ctx; + sha384_init(&ctx); + sha384_update(&ctx, len, buf); + sha384_digest(&ctx, SHA384_DIGEST_SIZE, res); + return 1; + } + case SHA512_DIGEST_SIZE: + { + struct sha512_ctx ctx; + sha512_init(&ctx); + sha512_update(&ctx, len, buf); + sha512_digest(&ctx, SHA512_DIGEST_SIZE, res); + return 1; + } + default: + break; + } + return 0; +} + +int +secalgo_ds_digest(int algo, unsigned char* buf, size_t len, + unsigned char* res) +{ + switch(algo) { + case LDNS_SHA1: + return _digest_nettle(SHA1_DIGEST_SIZE, buf, len, res); +#if defined(USE_SHA2) + case LDNS_SHA256: + return _digest_nettle(SHA256_DIGEST_SIZE, buf, len, res); +#endif +#ifdef USE_ECDSA + case LDNS_SHA384: + return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res); + +#endif + case LDNS_HASH_GOST: + default: + verbose(VERB_QUERY, "unknown DS digest algorithm %d", + algo); + break; + } + return 0; +} + +int +dnskey_algo_id_is_supported(int id) +{ + /* uses libnettle */ + switch(id) { + case LDNS_DSA: + case LDNS_DSA_NSEC3: + case LDNS_RSASHA1: + case LDNS_RSASHA1_NSEC3: +#ifdef USE_SHA2 + case LDNS_RSASHA256: + case LDNS_RSASHA512: +#endif +#ifdef USE_ECDSA + case LDNS_ECDSAP256SHA256: + case LDNS_ECDSAP384SHA384: +#endif + return 1; + case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */ + case LDNS_ECC_GOST: + default: + return 0; + } +} + +static char * +_verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, + unsigned int sigblock_len, unsigned char* key, unsigned int keylen) +{ + uint8_t digest[SHA1_DIGEST_SIZE]; + uint8_t key_t; + int res = 0; + size_t offset; + struct dsa_public_key pubkey; + struct dsa_signature signature; + unsigned int expected_len; + + // Validate T values constraints - RFC 2536 sec. 2 & sec. 3 + key_t = key[0]; + if (key_t != sigblock[0] || key_t > 8 ) { + return "invalid T value in DSA signature or pubkey"; + } + + // Signature length: 41 bytes - RFC 2536 sec. 3 + if (sigblock_len != 41) { + return "invalid DSA signature length"; + } + + // Pubkey minimum length: 21 bytes - RFC 2536 sec. 2 + if (keylen < 21) { + return "DSA pubkey too short"; + } + + expected_len = 1 + // T + 20 + // Q + (64 + key_t*8) + // P + (64 + key_t*8) + // G + (64 + key_t*8); // Y + if (keylen != expected_len ) { + return "invalid DSA pubkey length"; + } + + // Extract DSA pubkey from the record + nettle_dsa_public_key_init(&pubkey); + offset = 1; + nettle_mpz_set_str_256_u(pubkey.q, 20, key+offset); + offset += 20; + nettle_mpz_set_str_256_u(pubkey.p, (64 + key_t*8), key+offset); + offset += (64 + key_t*8); + nettle_mpz_set_str_256_u(pubkey.g, (64 + key_t*8), key+offset); + offset += (64 + key_t*8); + nettle_mpz_set_str_256_u(pubkey.y, (64 + key_t*8), key+offset); + + // Extract DSA signature from the record + nettle_dsa_signature_init(&signature); + nettle_mpz_set_str_256_u(signature.r, 20, sigblock+1); + nettle_mpz_set_str_256_u(signature.s, 20, sigblock+1+20); + + // Digest content of "buf" and verify its DSA signature in "sigblock" + res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), digest); + res &= dsa_sha1_verify_digest(&pubkey, digest, &signature); + + // Clear and return + nettle_dsa_signature_clear(&signature); + nettle_dsa_public_key_clear(&pubkey); + if (!res) + return "DSA signature verification failed"; + else + return NULL; +} + +static char * +_verify_nettle_rsa(sldns_buffer* buf, unsigned int digest_size, char* sigblock, + unsigned int sigblock_len, uint8_t* key, unsigned int keylen) +{ + uint16_t exp_len = 0; + size_t exp_offset = 0, mod_offset = 0; + struct rsa_public_key pubkey; + mpz_t signature; + int res = 0; + + // RSA pubkey parsing as per RFC 3110 sec. 2 + if( keylen <= 1) { + return "null RSA key"; + } + if (key[0] != 0) { + // 1-byte length + exp_len = key[0]; + exp_offset = 1; + } else { + // 1-byte NUL + 2-bytes exponent length + if (keylen < 3) { + return "incorrect RSA key length"; + } + exp_len = READ_UINT16(key+1); + if (exp_len == 0) + return "null RSA exponent length"; + exp_offset = 3; + } + // Check that we are not over-running input length + if (keylen < exp_offset + exp_len + 1) { + return "RSA key content shorter than expected"; + } + mod_offset = exp_offset + exp_len; + nettle_rsa_public_key_init(&pubkey); + pubkey.size = keylen - mod_offset; + nettle_mpz_set_str_256_u(pubkey.e, exp_len, &key[exp_offset]); + nettle_mpz_set_str_256_u(pubkey.n, pubkey.size, &key[mod_offset]); + + // Digest content of "buf" and verify its RSA signature in "sigblock" + nettle_mpz_init_set_str_256_u(signature, sigblock_len, (uint8_t*)sigblock); + switch (digest_size) { + case SHA1_DIGEST_SIZE: + { + uint8_t digest[SHA1_DIGEST_SIZE]; + res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), digest); + res &= rsa_sha1_verify_digest(&pubkey, digest, signature); + break; + } + case SHA256_DIGEST_SIZE: + { + uint8_t digest[SHA256_DIGEST_SIZE]; + res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), digest); + res &= rsa_sha256_verify_digest(&pubkey, digest, signature); + break; + } + case SHA512_DIGEST_SIZE: + { + uint8_t digest[SHA512_DIGEST_SIZE]; + res = _digest_nettle(SHA512_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), digest); + res &= rsa_sha512_verify_digest(&pubkey, digest, signature); + break; + } + default: + break; + } + + // Clear and return + nettle_rsa_public_key_clear(&pubkey); + mpz_clear(signature); + if (!res) { + return "RSA signature verification failed"; + } else { + return NULL; + } +} + +#ifdef USE_ECDSA +static char * +_verify_nettle_ecdsa(sldns_buffer* buf, unsigned int digest_size, unsigned char* sigblock, + unsigned int sigblock_len, unsigned char* key, unsigned int keylen) +{ + int res = 0; + struct ecc_point pubkey; + struct dsa_signature signature; + + // Always matched strength, as per RFC 6605 sec. 1 + if (sigblock_len != 2*digest_size || keylen != 2*digest_size) { + return "wrong ECDSA signature length"; + } + + // Parse ECDSA signature as per RFC 6605 sec. 4 + nettle_dsa_signature_init(&signature); + switch (digest_size) { + case SHA256_DIGEST_SIZE: + { + uint8_t digest[SHA256_DIGEST_SIZE]; + mpz_t x, y; + nettle_ecc_point_init(&pubkey, &nettle_secp_256r1); + nettle_mpz_init_set_str_256_u(x, SHA256_DIGEST_SIZE, key); + nettle_mpz_init_set_str_256_u(y, SHA256_DIGEST_SIZE, key+SHA256_DIGEST_SIZE); + nettle_mpz_set_str_256_u(signature.r, SHA256_DIGEST_SIZE, sigblock); + nettle_mpz_set_str_256_u(signature.s, SHA256_DIGEST_SIZE, sigblock+SHA256_DIGEST_SIZE); + res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), digest); + res &= nettle_ecc_point_set(&pubkey, x, y); + res &= nettle_ecdsa_verify (&pubkey, SHA256_DIGEST_SIZE, digest, &signature); + mpz_clear(x); + mpz_clear(y); + break; + } + case SHA384_DIGEST_SIZE: + { + uint8_t digest[SHA384_DIGEST_SIZE]; + mpz_t x, y; + nettle_ecc_point_init(&pubkey, &nettle_secp_384r1); + nettle_mpz_init_set_str_256_u(x, SHA384_DIGEST_SIZE, key); + nettle_mpz_init_set_str_256_u(y, SHA384_DIGEST_SIZE, key+SHA384_DIGEST_SIZE); + nettle_mpz_set_str_256_u(signature.r, SHA384_DIGEST_SIZE, sigblock); + nettle_mpz_set_str_256_u(signature.s, SHA384_DIGEST_SIZE, sigblock+SHA384_DIGEST_SIZE); + res = _digest_nettle(SHA384_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), + (unsigned int)sldns_buffer_limit(buf), digest); + res &= nettle_ecc_point_set(&pubkey, x, y); + res &= nettle_ecdsa_verify (&pubkey, SHA384_DIGEST_SIZE, digest, &signature); + mpz_clear(x); + mpz_clear(y); + nettle_ecc_point_clear(&pubkey); + break; + } + default: + return "unknown ECDSA algorithm"; + } + + // Clear and return + nettle_dsa_signature_clear(&signature); + if (!res) + return "ECDSA signature verification failed"; + else + return NULL; +} +#endif + +/** + * Check a canonical sig+rrset and signature against a dnskey + * @param buf: buffer with data to verify, the first rrsig part and the + * canonicalized rrset. + * @param algo: DNSKEY algorithm. + * @param sigblock: signature rdata field from RRSIG + * @param sigblock_len: length of sigblock data. + * @param key: public key data from DNSKEY RR. + * @param keylen: length of keydata. + * @param reason: bogus reason in more detail. + * @return secure if verification succeeded, bogus on crypto failure, + * unchecked on format errors and alloc failures. + */ +enum sec_status +verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, + unsigned int sigblock_len, unsigned char* key, unsigned int keylen, + char** reason) +{ + unsigned int digest_size = 0; + + if (sigblock_len == 0 || keylen == 0) { + *reason = "null signature"; + return sec_status_bogus; + } + + switch(algo) { + case LDNS_DSA: + case LDNS_DSA_NSEC3: + // Some of these signatures are non-standard + if (key[0] > 8 || sigblock_len != 41) { + *reason = "(custom) unknown DSA signature"; + return sec_status_unchecked; + } + *reason = _verify_nettle_dsa(buf, sigblock, sigblock_len, key, keylen); + if (*reason != NULL) + return sec_status_bogus; + else + return sec_status_secure; + + case LDNS_RSASHA1: + case LDNS_RSASHA1_NSEC3: + digest_size = (digest_size ? digest_size : SHA1_DIGEST_SIZE); +#ifdef USE_SHA2 + case LDNS_RSASHA256: + digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE); + case LDNS_RSASHA512: + digest_size = (digest_size ? digest_size : SHA512_DIGEST_SIZE); + +#endif + *reason = _verify_nettle_rsa(buf, digest_size, (char*)sigblock, + sigblock_len, key, keylen); + if (*reason != NULL) + return sec_status_bogus; + else + return sec_status_secure; + +#ifdef USE_ECDSA + case LDNS_ECDSAP256SHA256: + digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE); + case LDNS_ECDSAP384SHA384: + digest_size = (digest_size ? digest_size : SHA384_DIGEST_SIZE); + *reason = _verify_nettle_ecdsa(buf, digest_size, sigblock, + sigblock_len, key, keylen); + if (*reason != NULL) + return sec_status_bogus; + else + return sec_status_secure; +#endif + case LDNS_RSAMD5: + case LDNS_ECC_GOST: + default: + *reason = "unable to verify signature, unknown algorithm"; + return sec_status_bogus; + } +} + +#endif /* HAVE_SSL or HAVE_NSS or HAVE_NETTLE */ diff --git a/validator/val_sigcrypt.c b/validator/val_sigcrypt.c index a2f126529..1dd07b420 100644 --- a/validator/val_sigcrypt.c +++ b/validator/val_sigcrypt.c @@ -57,7 +57,7 @@ #include "sldns/wire2str.h" #include -#if !defined(HAVE_SSL) && !defined(HAVE_NSS) +#if !defined(HAVE_SSL) && !defined(HAVE_NSS) && !defined(HAVE_NETTLE) #error "Need crypto library to do digital signature cryptography" #endif