diff --git a/config.h.in b/config.h.in index 2713bcdab..20fdf9861 100644 --- a/config.h.in +++ b/config.h.in @@ -79,6 +79,10 @@ don't. */ #undef HAVE_DECL_INET_PTON +/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you + don't. */ +#undef HAVE_DECL_NID_ED25519 + /* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you don't. */ #undef HAVE_DECL_NID_SECP384R1 @@ -157,6 +161,9 @@ /* Define to 1 if you have the `EVP_cleanup' function. */ #undef HAVE_EVP_CLEANUP +/* Define to 1 if you have the `EVP_DigestVerify' function. */ +#undef HAVE_EVP_DIGESTVERIFY + /* Define to 1 if you have the `EVP_dss1' function. */ #undef HAVE_EVP_DSS1 @@ -678,6 +685,9 @@ /* Define this to enable an EVP workaround for older openssl */ #undef USE_ECDSA_EVP_WORKAROUND +/* Define this to enable ED25519 support. */ +#undef USE_ED25519 + /* Define this to enable GOST support. */ #undef USE_GOST diff --git a/configure b/configure index 16297e06f..c27c35d76 100755 --- a/configure +++ b/configure @@ -856,6 +856,7 @@ enable_subnet enable_gost enable_ecdsa enable_dsa +enable_ed25519 enable_event_api enable_tfo_client enable_tfo_server @@ -1537,6 +1538,7 @@ Optional Features: --disable-gost Disable GOST support --disable-ecdsa Disable ECDSA support --disable-dsa Disable DSA support + --disable-ed25519 Disable ED25519 support --enable-event-api Enable (experimental) pluggable event base libunbound API installed to unbound-event.h --enable-tfo-client Enable TCP Fast Open for client mode @@ -17617,7 +17619,7 @@ fi done -for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 +for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -18065,6 +18067,47 @@ fi ;; esac +# Check whether --enable-ed25519 was given. +if test "${enable_ed25519+set}" = set; then : + enableval=$enable_ed25519; +fi + +use_ed25519="no" +case "$enable_ed25519" in + no) + ;; + *) + if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then + ac_fn_c_check_decl "$LINENO" "NID_ED25519" "ac_cv_have_decl_NID_ED25519" "$ac_includes_default +#include + +" +if test "x$ac_cv_have_decl_NID_ED25519" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_NID_ED25519 $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + + +cat >>confdefs.h <<_ACEOF +#define USE_ED25519 1 +_ACEOF + + use_ed25519="yes" + +else + if test "x$enable_ed25519" = "xyes"; then as_fn_error $? "OpenSSL does not support ED25519 and you used --enable-ed25519." "$LINENO" 5 + fi +fi + + fi + ;; +esac # Check whether --enable-event-api was given. if test "${enable_event_api+set}" = set; then : diff --git a/configure.ac b/configure.ac index 059243c3d..3652deecc 100644 --- a/configure.ac +++ b/configure.ac @@ -691,7 +691,7 @@ else AC_MSG_RESULT([no]) fi AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h],,, [AC_INCLUDES_DEFAULT]) -AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1]) +AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify]) # these check_funcs need -lssl BAKLIBS="$LIBS" @@ -917,6 +917,23 @@ case "$enable_dsa" in ;; esac +AC_ARG_ENABLE(ed25519, AC_HELP_STRING([--disable-ed25519], [Disable ED25519 support])) +use_ed25519="no" +case "$enable_ed25519" in + no) + ;; + *) + if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then + AC_CHECK_DECLS([NID_ED25519], [ + AC_DEFINE_UNQUOTED([USE_ED25519], [1], [Define this to enable ED25519 support.]) + use_ed25519="yes" + ], [ if test "x$enable_ed25519" = "xyes"; then AC_MSG_ERROR([OpenSSL does not support ED25519 and you used --enable-ed25519.]) + fi ], [AC_INCLUDES_DEFAULT +#include + ]) + fi + ;; +esac AC_ARG_ENABLE(event-api, AC_HELP_STRING([--enable-event-api], [Enable (experimental) pluggable event base libunbound API installed to unbound-event.h])) case "$enable_event_api" in diff --git a/doc/Changelog b/doc/Changelog index c08f4b5db..291a13ec1 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +30 May 2017: Wouter + - Support for openssl EVP_DigestVerify. + - Support for the ED25519 algorithm with openssl (from openssl 1.1.1). + 29 May 2017: Wouter - Fix assertion for low buffer size and big edns payload when worker overrides udpsize. diff --git a/sldns/keyraw.c b/sldns/keyraw.c index e8f2da089..e2f14f2a4 100644 --- a/sldns/keyraw.c +++ b/sldns/keyraw.c @@ -388,6 +388,27 @@ sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo) } #endif /* USE_ECDSA */ +#ifdef USE_ED25519 +EVP_PKEY* +sldns_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 */ + int sldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest, const EVP_MD* md) diff --git a/sldns/keyraw.h b/sldns/keyraw.h index 8abe23509..19653b46c 100644 --- a/sldns/keyraw.h +++ b/sldns/keyraw.h @@ -92,6 +92,15 @@ EVP_PKEY* sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo); */ RSA *sldns_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* sldns_ed255192pkey_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. diff --git a/testcode/unitverify.c b/testcode/unitverify.c index 37994a377..e5e5b0f7b 100644 --- a/testcode/unitverify.c +++ b/testcode/unitverify.c @@ -537,6 +537,11 @@ verify_test(void) } dstest_file("testdata/test_ds.sha384"); #endif +#ifdef USE_ED25519 + if(dnskey_algo_id_is_supported(LDNS_ED25519)) { + verifytest_file("testdata/test_sigs.ed25519", "20170530140439"); + } +#endif #ifdef USE_SHA1 dstest_file("testdata/test_ds.sha1"); #endif diff --git a/testdata/test_sigs.ed25519 b/testdata/test_sigs.ed25519 new file mode 100644 index 000000000..b1592251e --- /dev/null +++ b/testdata/test_sigs.ed25519 @@ -0,0 +1,21 @@ +; Signature test file + +; first entry is a DNSKEY answer, with the DNSKEY rrset used for verification. +; later entries are verified with it. + +ENTRY_BEGIN +SECTION QUESTION +example.com. IN DNSKEY +SECTION ANSWER +example.com. 3600 IN DNSKEY 256 3 15 +sZnc8HII6xxA9Ili5bboiKH0Ipv/Ap1aucIt/CVF2M= ;{id = 57147 (zsk), size = 256b} +ENTRY_END + +; entry to test +ENTRY_BEGIN +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 3600 IN A 10.0.0.1 +www.example.com. 3600 IN RRSIG A 15 3 3600 20170627103620 20170530103620 57147 example.com. daYG6zZJ3BJwGOS4PC0tDnxssVNYoenOHocoIfx0GeXNkKHSyXF+XHgD5LKbG3ZN0dZJ/4To5eni9QXOXiR4CA== +ENTRY_END + diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c index 508bca6f5..88d234721 100644 --- a/validator/val_secalgo.c +++ b/validator/val_secalgo.c @@ -228,6 +228,9 @@ dnskey_algo_id_is_supported(int id) case LDNS_ECDSAP256SHA256: case LDNS_ECDSAP384SHA384: #endif +#ifdef USE_ED25519 + case LDNS_ED25519: +#endif #if (defined(HAVE_EVP_SHA256) && defined(USE_SHA2)) || (defined(HAVE_EVP_SHA512) && defined(USE_SHA2)) || defined(USE_ECDSA) return 1; #endif @@ -555,6 +558,17 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, #endif break; #endif /* USE_ECDSA */ +#ifdef USE_ED25519 + case LDNS_ED25519: + *evp_key = sldns_ed255192pkey_raw(key, keylen); + if(!*evp_key) { + verbose(VERB_QUERY, "verify: " + "sldns_ed255192pkey_raw failed"); + return 0; + } + *digest_type = NULL; + break; +#endif /* USE_ED25519 */ default: verbose(VERB_QUERY, "verify: unknown algorithm %d", algo); @@ -644,9 +658,15 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, else if(docrypto_free) OPENSSL_free(sigblock); return sec_status_unchecked; } +#ifndef HAVE_EVP_DIGESTVERIFY if(EVP_DigestInit(ctx, digest_type) == 0) { verbose(VERB_QUERY, "verify: EVP_DigestInit failed"); +#ifdef HAVE_EVP_MD_CTX_NEW EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_cleanup(ctx); + free(ctx); +#endif EVP_PKEY_free(evp_key); if(dofree) free(sigblock); else if(docrypto_free) OPENSSL_free(sigblock); @@ -655,7 +675,12 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, if(EVP_DigestUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf), (unsigned int)sldns_buffer_limit(buf)) == 0) { verbose(VERB_QUERY, "verify: EVP_DigestUpdate failed"); +#ifdef HAVE_EVP_MD_CTX_NEW EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_cleanup(ctx); + free(ctx); +#endif EVP_PKEY_free(evp_key); if(dofree) free(sigblock); else if(docrypto_free) OPENSSL_free(sigblock); @@ -663,6 +688,24 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, } res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key); +#else /* HAVE_EVP_DIGESTVERIFY */ + if(EVP_DigestVerifyInit(ctx, NULL, digest_type, NULL, evp_key) == 0) { + verbose(VERB_QUERY, "verify: EVP_DigestVerifyInit failed"); +#ifdef HAVE_EVP_MD_CTX_NEW + EVP_MD_CTX_destroy(ctx); +#else + EVP_MD_CTX_cleanup(ctx); + free(ctx); +#endif + EVP_PKEY_free(evp_key); + if(dofree) free(sigblock); + else if(docrypto_free) OPENSSL_free(sigblock); + return sec_status_unchecked; + } + res = EVP_DigestVerify(ctx, sigblock, sigblock_len, + (unsigned char*)sldns_buffer_begin(buf), + sldns_buffer_limit(buf)); +#endif #ifdef HAVE_EVP_MD_CTX_NEW EVP_MD_CTX_destroy(ctx); #else