UNBOUND_VERSION_MICRO=@UNBOUND_VERSION_MICRO@
ALLTARGET=@ALLTARGET@
INSTALLTARGET=@INSTALLTARGET@
+SSLLIB=@SSLLIB@
# _unbound.la if pyunbound enabled.
PYUNBOUND_TARGET=@PYUNBOUND_TARGET@
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)
$(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 > $@
#include <errno.h>
#include <unistd.h>
#include <time.h>
+
+#if defined(HAVE_SSL)
#include <openssl/sha.h>
+#elif defined(HAVE_NETTLE)
+#include <nettle/sha.h>
+#endif
#include <linux/types.h>
#include <linux/random.h>
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);
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;
}
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) {
# 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);
}
/* Define to 1 if you have the <netinet/in.h> header file. */
#undef HAVE_NETINET_IN_H
+/* Use libnettle for crypto */
+#undef HAVE_NETTLE
+
/* Use libnss for crypto */
#undef HAVE_NSS
staticexe
UNBOUND_EVENT_UNINSTALL
UNBOUND_EVENT_INSTALL
+SSLLIB
HAVE_SSL
CONFIG_DATE
NETBSD_LINTFLAGS
with_pyunbound
with_pythonmodule
with_nss
+with_nettle
with_ssl
enable_sha2
enable_gost
--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)
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.
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
fi
+
# Check whether --enable-sha2 was given.
if test "${enable_sha2+set}" = set; then :
enableval=$enable_sha2;
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)
;;
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 :
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])
#include <openssl/evp.h>
])
fi
+AC_SUBST(SSLLIB)
AC_ARG_ENABLE(sha2, AC_HELP_STRING([--disable-sha2], [Disable SHA256 and SHA512 RRSIG support]))
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)
;;
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"
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
+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.
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
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);
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");
/* nss3 */
#include "secport.h"
#include "pk11pub.h"
+#elif defined(HAVE_NETTLE)
+#include "yarrow.h"
#endif
/**
*/
#define MAX_VALUE 0x7fffffff
-#ifndef HAVE_NSS
+#if defined(HAVE_SSL)
void
ub_systemseed(unsigned int ATTR_UNUSED(seed))
{
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 {
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)
{
v = ub_random(state);
return (v % x);
}
-#endif /* HAVE_NSS */
+#endif /* HAVE_NSS or HAVE_NETTLE */
void
ub_randfree(struct ub_randstate* s)
#ifdef HAVE_NSS
/* nss3 */
#include "sechash.h"
+#elif defined(HAVE_NETTLE)
+#include "sha1.h"
#endif
#include "validator/val_nsec3.h"
#include "validator/validator.h"
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<iter; i++) {
sldns_buffer_clear(buf);
sldns_buffer_write(buf, res, 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*)res);
-# else
+ }
+ break;
+#elif defined(HAVE_NSS)
+ case NSEC3_HASH_SHA1:
+ hash_len = SHA1_LENGTH;
+ if(hash_len > 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<iter; i++) {
+ sldns_buffer_clear(buf);
+ sldns_buffer_write(buf, res, hash_len);
+ sldns_buffer_write(buf, salt, saltlen);
+ sldns_buffer_flip(buf);
(void)HASH_HashBuf(HASH_AlgSHA1,
(unsigned char*)res,
(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;
+ hash_len = SHA1_DIGEST_SIZE;
+ if(hash_len > 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; i<iter; i++) {
+ sldns_buffer_clear(buf);
+ sldns_buffer_write(buf, res, 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 *)res);
+ }
+ break;
+ }
+#endif /* HAVE_EVP_SHA1 or HAVE_NSS or HAVE_NETTLE*/
default:
log_err("nsec3 hash of unknown algo %d", algo);
return 0;
sldns_buffer_write(buf, salt, saltlen);
sldns_buffer_flip(buf);
switch(algo) {
-#if defined(HAVE_EVP_SHA1) || defined(HAVE_NSS)
- case NSEC3_HASH_SHA1:
#ifdef HAVE_SSL
+ case NSEC3_HASH_SHA1:
c->hash_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; i<iter; i++) {
sldns_buffer_clear(buf);
sldns_buffer_write(buf, c->hash, 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; i<iter; i++) {
+ sldns_buffer_clear(buf);
+ sldns_buffer_write(buf, c->hash, 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; i<iter; i++) {
+ sldns_buffer_clear(buf);
+ sldns_buffer_write(buf, c->hash, 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;
#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
/**
* 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)
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 */
#include "sldns/wire2str.h"
#include <ctype.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