Merge branch 'devel/codebase-maintenance2' into release/v1.0.0beta

This commit is contained in:
Willem Toorop 2016-03-24 16:53:15 +01:00
commit 7df26b6068
16 changed files with 720 additions and 83 deletions

View File

@ -223,7 +223,7 @@ else
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_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode])
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])
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
@ -404,6 +404,18 @@ case "$enable_ecdsa" in
;;
esac
AC_ARG_ENABLE(dsa, AC_HELP_STRING([--disable-dsa], [Disable DSA support]))
case "$enable_dsa" in
no)
;;
*) dnl default
# detect if DSA is supported, and turn it off if not.
AC_CHECK_FUNC(EVP_dss1, [
AC_DEFINE_UNQUOTED([USE_DSA], [1], [Define this to enable DSA support.])
], [if test "x$enable_dsa" = "xyes"; then AC_MSG_ERROR([OpenSSL does not support DSA and you used --enable-dsa.])
fi ])
;;
esac
AC_ARG_ENABLE(draft-dnssec-roadblock-avoidance, AC_HELP_STRING([--enable-draft-dnssec-roadblock-avoidance], [Enable experimental dnssec roadblock avoidance]))
AC_ARG_ENABLE(draft-edns-cookies, AC_HELP_STRING([--enable-draft-edns-cookies], [Enable experimental edns cookies]))

View File

@ -47,16 +47,16 @@ AC_DEFUN([ACX_SSL_CHECKS], [
ACX_RUNTIME_PATH_ADD([$ssldir/lib])
fi
AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto])
AC_MSG_CHECKING([for HMAC_Update in -lcrypto])
LIBS="-lssl -lcrypto $LIBS"
LIBSSL_LIBS="-lssl -lcrypto $LIBSSL_LIBS"
AC_TRY_LINK(, [
int HMAC_CTX_init(void);
(void)HMAC_CTX_init();
int HMAC_Update(void);
(void)HMAC_Update();
], [
AC_DEFINE([HAVE_HMAC_UPDATE], 1,
[If you have HMAC_Update])
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_HMAC_CTX_INIT], 1,
[If you have HMAC_CTX_init])
], [
AC_MSG_RESULT(no)
# check if -lwsock32 or -lgdi32 are needed.
@ -66,11 +66,11 @@ AC_DEFUN([ACX_SSL_CHECKS], [
LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32"
AC_MSG_CHECKING([if -lcrypto needs -lgdi32])
AC_TRY_LINK([], [
int HMAC_CTX_init(void);
(void)HMAC_CTX_init();
int HMAC_Update(void);
(void)HMAC_Update();
],[
AC_DEFINE([HAVE_HMAC_CTX_INIT], 1,
[If you have HMAC_CTX_init])
AC_DEFINE([HAVE_HMAC_UPDATE], 1,
[If you have HMAC_Update])
AC_MSG_RESULT(yes)
],[
AC_MSG_RESULT(no)
@ -80,11 +80,11 @@ AC_DEFUN([ACX_SSL_CHECKS], [
LIBSSL_LIBS="$LIBSSL_LIBS -ldl"
AC_MSG_CHECKING([if -lcrypto needs -ldl])
AC_TRY_LINK([], [
int HMAC_CTX_init(void);
(void)HMAC_CTX_init();
int HMAC_Update(void);
(void)HMAC_Update();
],[
AC_DEFINE([HAVE_HMAC_CTX_INIT], 1,
[If you have HMAC_CTX_init])
AC_DEFINE([HAVE_HMAC_UPDATE], 1,
[If you have HMAC_Update])
AC_MSG_RESULT(yes)
],[
AC_MSG_RESULT(no)

View File

@ -1942,7 +1942,8 @@ getdns_return_t
getdns_context_set_dns_root_servers(
getdns_context *context, getdns_list *addresses)
{
#if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB)
#ifdef HAVE_LIBUNBOUND
# ifndef HAVE_UB_CTX_SET_STUB
char tmpfn[FILENAME_MAX] = P_tmpdir "/getdns-root-dns-servers-XXXXXX";
FILE *fh;
int fd;
@ -1953,6 +1954,7 @@ getdns_context_set_dns_root_servers(
getdns_return_t r;
getdns_bindata *addr_bd;
char dst[2048];
#endif
getdns_list *newlist;
if (!context)
@ -2909,9 +2911,22 @@ _getdns_context_prepare_for_resolution(struct 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)
return GETDNS_RETURN_BAD_CONTEXT;
# ifdef HAVE_TLS_CLIENT_METHOD
if (!SSL_CTX_set_min_proto_version(
context->tls_ctx, TLS1_2_VERSION)) {
SSL_CTX_free(context->tls_ctx);
context->tls_ctx = NULL;
return GETDNS_RETURN_BAD_CONTEXT;
}
# endif
/* Be strict and only use the cipher suites recommended in RFC7525
Unless we later fallback to opportunistic. */
const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM";

View File

@ -144,6 +144,12 @@ static const gldns_rdf_type type_dhcid_wireformat[] = {
static const gldns_rdf_type type_talink_wireformat[] = {
GLDNS_RDF_TYPE_DNAME, GLDNS_RDF_TYPE_DNAME
};
static const gldns_rdf_type type_openpgpkey_wireformat[] = {
GLDNS_RDF_TYPE_B64
};
static const gldns_rdf_type type_csync_wireformat[] = {
GLDNS_RDF_TYPE_INT32, GLDNS_RDF_TYPE_INT16, GLDNS_RDF_TYPE_NSEC
};
/* nsec3 is some vars, followed by same type of data of nsec */
static const gldns_rdf_type type_nsec3_wireformat[] = {
/* GLDNS_RDF_TYPE_NSEC3_VARS, GLDNS_RDF_TYPE_NSEC3_NEXT_OWNER, GLDNS_RDF_TYPE_NSEC*/
@ -361,8 +367,10 @@ static gldns_rr_descriptor rdata_field_descriptors[] = {
{GLDNS_RR_TYPE_CDS, "CDS", 4, 4, type_ds_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
/* 60 */
{GLDNS_RR_TYPE_CDNSKEY, "CDNSKEY", 4, 4, type_dnskey_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
{GLDNS_RR_TYPE_NULL, "TYPE61", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
{GLDNS_RR_TYPE_NULL, "TYPE62", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
/* 61 */
{GLDNS_RR_TYPE_OPENPGPKEY, "OPENPGPKEY", 1, 1, type_openpgpkey_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
/* 62 */
{GLDNS_RR_TYPE_CSYNC, "CSYNC", 3, 3, type_csync_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
{GLDNS_RR_TYPE_NULL, "TYPE63", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
{GLDNS_RR_TYPE_NULL, "TYPE64", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },
{GLDNS_RR_TYPE_NULL, "TYPE65", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 },

View File

@ -182,6 +182,8 @@ enum gldns_enum_rr_type
GLDNS_RR_TYPE_NSEC3PARAM = 51, /* RFC 5155 */
GLDNS_RR_TYPE_NSEC3PARAMS = 51,
GLDNS_RR_TYPE_TLSA = 52, /* RFC 6698 */
GLDNS_RR_TYPE_SMIMEA = 53, /* draft-ietf-dane-smime, TLSA-like but may
be extended */
GLDNS_RR_TYPE_HIP = 55, /* RFC 5205 */
@ -193,6 +195,8 @@ enum gldns_enum_rr_type
GLDNS_RR_TYPE_TALINK = 58,
GLDNS_RR_TYPE_CDS = 59, /** RFC 7344 */
GLDNS_RR_TYPE_CDNSKEY = 60, /** RFC 7344 */
GLDNS_RR_TYPE_OPENPGPKEY = 61, /* draft-ietf-dane-openpgpkey */
GLDNS_RR_TYPE_CSYNC = 62, /* RFC 7477 */
GLDNS_RR_TYPE_SPF = 99, /* RFC 4408 */

View File

@ -204,7 +204,7 @@ rrinternal_get_owner(gldns_buffer* strbuf, uint8_t* rr, size_t* len,
return RET_ERR(GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
gldns_buffer_position(strbuf));
memmove(rr, tocopy, *dname_len);
} else if(strlen(token) == 0) {
} else if(*token == '\0') {
/* no ownername was given, try prev, if that fails
* origin, else default to root */
uint8_t* tocopy;
@ -1091,7 +1091,7 @@ int gldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len)
uint8_t prefix;
size_t i;
if(strlen(my_str) == 0) {
if(*my_str == '\0') {
/* empty APL element, no data, no string */
*len = 0;
return GLDNS_WIREPARSE_ERR_OK;

View File

@ -393,18 +393,13 @@ _getdns_verify_pinset_match(const sha256_pin_t *pinset,
}
x = sk_X509_value(store->untrusted, i);
if (x->cert_info == NULL)
continue;
#if defined(STUB_DEBUG) && STUB_DEBUG
DEBUG_STUB("%s %-35s: Name of cert: %d ",
STUB_DEBUG_SETUP_TLS, __FUNCTION__, i);
if (x->cert_info->subject != NULL)
X509_NAME_print_ex_fp(stderr, x->cert_info->subject, 1, XN_FLAG_ONELINE);
X509_NAME_print_ex_fp(stderr, X509_get_subject_name(x), 1, XN_FLAG_ONELINE);
fprintf(stderr, "\n");
#endif
if (x->cert_info->key == NULL)
continue;
/* digest the cert with sha256 */
len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), NULL);
if (len > sizeof(raw)) {

View File

@ -461,7 +461,10 @@ _getdns_network_validate_tsig(getdns_network_req *req)
unsigned int result_mac_len = EVP_MAX_MD_SIZE;
uint16_t original_id;
const EVP_MD *digester;
HMAC_CTX ctx;
HMAC_CTX *ctx;
#ifndef HAVE_HMAC_CTX_NEW
HMAC_CTX ctx_space;
#endif
DEBUG_STUB("%s %-35s: Validate TSIG\n", STUB_DEBUG_TSIG, __FUNCTION__);
for ( rr = _getdns_rr_iter_init(&rr_spc, req->query,
@ -589,14 +592,18 @@ _getdns_network_validate_tsig(getdns_network_req *req)
#endif
default : return;
}
HMAC_CTX_init(&ctx);
(void) HMAC_Init_ex(&ctx, req->upstream->tsig_key,
#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);
(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);
DEBUG_STUB("%s %-35s: Result MAC length: %d\n",
STUB_DEBUG_TSIG, __FUNCTION__, (int)(result_mac_len));
@ -604,8 +611,11 @@ _getdns_network_validate_tsig(getdns_network_req *req)
memcmp(result_mac, response_mac, result_mac_len) == 0)
req->tsig_status = GETDNS_DNSSEC_SECURE;
HMAC_CTX_cleanup(&ctx);
#ifdef HAVE_HMAC_CTX_FREE
HMAC_CTX_free(ctx);
#else
HMAC_CTX_cleanup(ctx);
#endif
gldns_write_uint16(req->response, gldns_read_uint16(req->query));
gldns_write_uint16(req->response + 10,
gldns_read_uint16(req->response + 10) + 1);

View File

@ -57,7 +57,9 @@ typedef struct getdns_sync_data {
static getdns_return_t
getdns_sync_data_init(getdns_context *context, getdns_sync_data *data)
{
#ifdef HAVE_LIBUNBOUND
getdns_eventloop *ext = &context->sync_eventloop.loop;
#endif
data->context = context;
data->to_run = 1;

View File

@ -154,10 +154,10 @@ nolibcheck:
test: $(NOLIBCHECK) all
(cd $(srcdir)/../.. && find . -type f -executable -and \( -name "*.[ch]" -or -name "*.html" -or -name "*.in" -or -name "*.good" -or -name "*.ac" \) | awk 'BEGIN{e=0}{print("ERROR! Executable bit found on", $$0);e=1}END{exit(e)}')
rm -f fails
CK_LOG_FILE_NAME="$(CHECK_GETDNS).log" ./$(CHECK_GETDNS) || echo "$(CHECK_GETDNS) failed" >> fails
if test $(have_libevent) = 1 ; then CK_LOG_FILE_NAME="$(CHECK_EVENT_PROG).log" ./$(CHECK_EVENT_PROG) || echo "$(CHECK_EVENT_PROG) failed" >> fails; fi
if test $(have_libev) = 1 ; then CK_LOG_FILE_NAME="$(CHECK_EV_PROG).log" ./$(CHECK_EV_PROG) || echo "$(CHECK_EV_PROG) failed" >> fails; fi
if test $(have_libuv) = 1 ; then CK_LOG_FILE_NAME="$(CHECK_UV_PROG).log" ./$(CHECK_UV_PROG) || echo "$(CHECK_UV_PROG) failed" >> fails; fi
CK_TIMEOUT_MULTIPLIER=2 CK_LOG_FILE_NAME="$(CHECK_GETDNS).log" ./$(CHECK_GETDNS) || echo "$(CHECK_GETDNS) failed" >> fails
if test $(have_libevent) = 1 ; then CK_TIMEOUT_MULTIPLIER=2 CK_LOG_FILE_NAME="$(CHECK_EVENT_PROG).log" ./$(CHECK_EVENT_PROG) || echo "$(CHECK_EVENT_PROG) failed" >> fails; fi
if test $(have_libev) = 1 ; then CK_TIMEOUT_MULTIPLIER=2 CK_LOG_FILE_NAME="$(CHECK_EV_PROG).log" ./$(CHECK_EV_PROG) || echo "$(CHECK_EV_PROG) failed" >> fails; fi
if test $(have_libuv) = 1 ; then CK_TIMEOUT_MULTIPLIER=2 CK_LOG_FILE_NAME="$(CHECK_UV_PROG).log" ./$(CHECK_UV_PROG) || echo "$(CHECK_UV_PROG) failed" >> fails; fi
test ! -e fails
@echo "All tests OK"

View File

@ -401,7 +401,7 @@
struct getdns_context *context = NULL;
struct getdns_dict *address = NULL;
struct getdns_bindata address_type = { 5, (void *)"IPv6" };
struct getdns_bindata address_data = { 16, (void *)"\x2a\x04\xb9\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x37" };
struct getdns_bindata address_data = { 16, (void *)"\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88" };
void* eventloop = NULL;
getdns_transaction_t transaction_id = 0;

View File

@ -338,7 +338,7 @@
struct getdns_context *context = NULL;
struct getdns_dict *address = NULL;
struct getdns_bindata address_type = { 5, (void *)"IPv6" };
struct getdns_bindata address_data = { 16, (void *)"\x2a\x04\xb9\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x37" };
struct getdns_bindata address_data = { 16, (void *)"\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88" };
struct getdns_dict *response = NULL;
CONTEXT_CREATE(TRUE);

View File

@ -39,6 +39,7 @@ do
-e '/^#include "util\/data\/packed_rrset.h"$/d' \
-e 's/^#include "validator/#include "util/g' \
-e 's/^#include "gldns\/sbuffer/#include "gldns\/gbuffer/g' \
-e 's/^#include "util\/val_nsec3.h"/#define NSEC3_HASH_SHA1 0x01/g' \
-e 's/ds_digest_size_supported/_getdns_ds_digest_size_supported/g' \
-e 's/secalgo_ds_digest/_getdns_secalgo_ds_digest/g' \
-e 's/dnskey_algo_id_is_supported/_getdns_dnskey_algo_id_is_supported/g' \

View File

@ -68,7 +68,7 @@ static void _getdns_rbtree_insert_fixup(_getdns_rbtree_t *rbtree, _getdns_rbnode
static void _getdns_rbtree_delete_fixup(_getdns_rbtree_t* rbtree, _getdns_rbnode_t* child, _getdns_rbnode_t* child_parent);
/*
* Creates a new red black tree, intializes and returns a pointer to it.
* Creates a new red black tree, initializes and returns a pointer to it.
*
* Return NULL on failure.
*

View File

@ -42,12 +42,13 @@
*/
#include "config.h"
#include "util/val_secalgo.h"
#define NSEC3_HASH_SHA1 0x01
#include "util/log.h"
#include "gldns/rrdef.h"
#include "gldns/keyraw.h"
#include "gldns/gbuffer.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
@ -69,6 +70,32 @@
#include <openssl/engine.h>
#endif
/* return size of digest if supported, or 0 otherwise */
size_t
nsec3_hash_algo_size_supported(int id)
{
switch(id) {
case NSEC3_HASH_SHA1:
return SHA_DIGEST_LENGTH;
default:
return 0;
}
}
/* perform nsec3 hash. return false on failure */
int
secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
unsigned char* res)
{
switch(algo) {
case NSEC3_HASH_SHA1:
(void)SHA1(buf, len, res);
return 1;
default:
return 0;
}
}
/**
* Return size of DS digest according to its hash algorithm.
* @param algo: DS digest algo.
@ -88,6 +115,7 @@ _getdns_ds_digest_size_supported(int algo)
#endif
#ifdef USE_GOST
case GLDNS_HASH_GOST:
/* we support GOST if it can be loaded */
(void)gldns_key_EVP_load_gost_id();
if(EVP_get_digestbyname("md_gost94"))
return 32;
@ -156,8 +184,10 @@ _getdns_dnskey_algo_id_is_supported(int id)
case GLDNS_RSAMD5:
/* RFC 6725 deprecates RSAMD5 */
return 0;
#ifdef USE_DSA
case GLDNS_DSA:
case GLDNS_DSA_NSEC3:
#endif
case GLDNS_RSASHA1:
case GLDNS_RSASHA1_NSEC3:
#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2)
@ -197,6 +227,7 @@ log_crypto_error(const char* str, unsigned long e)
log_err("%s crypto %s", str, buf);
}
#ifdef USE_DSA
/**
* Setup DSA key digest in DER encoding ...
* @param sig: input is signature output alloced ptr (unless failure).
@ -238,6 +269,7 @@ setup_dsa_sig(unsigned char** sig, unsigned int* len)
DSA_SIG_free(dsasig);
return 1;
}
#endif /* USE_DSA */
#ifdef USE_ECDSA
/**
@ -251,32 +283,61 @@ setup_dsa_sig(unsigned char** sig, unsigned int* len)
static int
setup_ecdsa_sig(unsigned char** sig, unsigned int* len)
{
ECDSA_SIG* ecdsa_sig;
int newlen;
/* convert from two BIGNUMs in the rdata buffer, to ASN notation.
* ASN preable: 30440220 <R 32bytefor256> 0220 <S 32bytefor256>
* the '20' is the length of that field (=bnsize).
i * the '44' is the total remaining length.
* if negative, start with leading zero.
* if starts with 00s, remove them from the number.
*/
uint8_t pre[] = {0x30, 0x44, 0x02, 0x20};
int pre_len = 4;
uint8_t mid[] = {0x02, 0x20};
int mid_len = 2;
int raw_sig_len, r_high, s_high, r_rem=0, s_rem=0;
int bnsize = (int)((*len)/2);
unsigned char* d = *sig;
uint8_t* p;
/* if too short or not even length, fails */
if(*len < 16 || bnsize*2 != (int)*len)
return 0;
/* use the raw data to parse two evenly long BIGNUMs, "r | s". */
ecdsa_sig = ECDSA_SIG_new();
if(!ecdsa_sig) return 0;
ecdsa_sig->r = BN_bin2bn(*sig, bnsize, ecdsa_sig->r);
ecdsa_sig->s = BN_bin2bn(*sig+bnsize, bnsize, ecdsa_sig->s);
if(!ecdsa_sig->r || !ecdsa_sig->s) {
ECDSA_SIG_free(ecdsa_sig);
return 0;
}
/* spool it into ASN format */
*sig = NULL;
newlen = i2d_ECDSA_SIG(ecdsa_sig, sig);
if(newlen <= 0) {
ECDSA_SIG_free(ecdsa_sig);
free(*sig);
/* strip leading zeroes from r (but not last one) */
while(r_rem < bnsize-1 && d[r_rem] == 0)
r_rem++;
/* strip leading zeroes from s (but not last one) */
while(s_rem < bnsize-1 && d[bnsize+s_rem] == 0)
s_rem++;
r_high = ((d[0+r_rem]&0x80)?1:0);
s_high = ((d[bnsize+s_rem]&0x80)?1:0);
raw_sig_len = pre_len + r_high + bnsize - r_rem + mid_len +
s_high + bnsize - s_rem;
*sig = (unsigned char*)malloc((size_t)raw_sig_len);
if(!*sig)
return 0;
p = (uint8_t*)*sig;
p[0] = pre[0];
p[1] = (uint8_t)(raw_sig_len-2);
p[2] = pre[2];
p[3] = (uint8_t)(bnsize + r_high - r_rem);
p += 4;
if(r_high) {
*p = 0;
p += 1;
}
*len = (unsigned int)newlen;
ECDSA_SIG_free(ecdsa_sig);
memmove(p, d+r_rem, (size_t)bnsize-r_rem);
p += bnsize-r_rem;
memmove(p, mid, (size_t)mid_len-1);
p += mid_len-1;
*p = (uint8_t)(bnsize + s_high - s_rem);
p += 1;
if(s_high) {
*p = 0;
p += 1;
}
memmove(p, d+bnsize+s_rem, (size_t)bnsize-s_rem);
*len = (unsigned int)raw_sig_len;
return 1;
}
#endif /* USE_ECDSA */
@ -295,10 +356,13 @@ static int
setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
unsigned char* key, size_t keylen)
{
#ifdef USE_DSA
DSA* dsa;
#endif
RSA* rsa;
switch(algo) {
#ifdef USE_DSA
case GLDNS_DSA:
case GLDNS_DSA_NSEC3:
*evp_key = EVP_PKEY_new();
@ -320,6 +384,7 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
*digest_type = EVP_dss1();
break;
#endif /* USE_DSA */
case GLDNS_RSASHA1:
case GLDNS_RSASHA1_NSEC3:
#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2)
@ -478,7 +543,7 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
char** reason)
{
const EVP_MD *digest_type;
EVP_MD_CTX ctx;
EVP_MD_CTX* ctx;
int res, dofree = 0;
EVP_PKEY *evp_key = NULL;
@ -488,6 +553,7 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
EVP_PKEY_free(evp_key);
return 0;
}
#ifdef USE_DSA
/* if it is a DSA signature in bind format, convert to DER format */
if((algo == GLDNS_DSA || algo == GLDNS_DSA_NSEC3) &&
sigblock_len == 1+2*SHA_DIGEST_LENGTH) {
@ -499,8 +565,12 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
}
dofree = 1;
}
#endif
#if defined(USE_ECDSA) && defined(USE_DSA)
else
#endif
#ifdef USE_ECDSA
else if(algo == GLDNS_ECDSAP256SHA256 || algo == GLDNS_ECDSAP384SHA384) {
if(algo == GLDNS_ECDSAP256SHA256 || algo == GLDNS_ECDSAP384SHA384) {
/* EVP uses ASN prefix on sig, which is not in the wire data */
if(!setup_ecdsa_sig(&sigblock, &sigblock_len)) {
verbose(VERB_QUERY, "verify: failed to setup ECDSA sig");
@ -513,28 +583,36 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
#endif /* USE_ECDSA */
/* do the signature cryptography work */
EVP_MD_CTX_init(&ctx);
if(EVP_VerifyInit(&ctx, digest_type) == 0) {
verbose(VERB_QUERY, "verify: EVP_VerifyInit failed");
#ifdef HAVE_EVP_MD_CTX_NEW
ctx = EVP_MD_CTX_new();
#else
ctx = (EVP_MD_CTX*)malloc(sizeof(*ctx));
if(ctx) EVP_MD_CTX_init(ctx);
#endif
if(!ctx) {
log_err("EVP_MD_CTX_new: malloc failure");
EVP_PKEY_free(evp_key);
if(dofree) free(sigblock);
return 0;
}
if(EVP_VerifyUpdate(&ctx, (unsigned char*)gldns_buffer_begin(buf),
if(EVP_VerifyInit(ctx, digest_type) == 0) {
verbose(VERB_QUERY, "verify: EVP_VerifyInit failed");
EVP_MD_CTX_destroy(ctx);
EVP_PKEY_free(evp_key);
if(dofree) free(sigblock);
return 0;
}
if(EVP_VerifyUpdate(ctx, (unsigned char*)gldns_buffer_begin(buf),
(unsigned int)gldns_buffer_limit(buf)) == 0) {
verbose(VERB_QUERY, "verify: EVP_VerifyUpdate failed");
EVP_MD_CTX_destroy(ctx);
EVP_PKEY_free(evp_key);
if(dofree) free(sigblock);
return 0;
}
res = EVP_VerifyFinal(&ctx, sigblock, sigblock_len, evp_key);
if(EVP_MD_CTX_cleanup(&ctx) == 0) {
verbose(VERB_QUERY, "verify: EVP_MD_CTX_cleanup failed");
EVP_PKEY_free(evp_key);
if(dofree) free(sigblock);
return 0;
}
res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key);
EVP_MD_CTX_destroy(ctx);
EVP_PKEY_free(evp_key);
if(dofree)
@ -564,6 +642,32 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
/* nspr4 */
#include "prerror.h"
/* return size of digest if supported, or 0 otherwise */
size_t
nsec3_hash_algo_size_supported(int id)
{
switch(id) {
case NSEC3_HASH_SHA1:
return SHA1_LENGTH;
default:
return 0;
}
}
/* perform nsec3 hash. return false on failure */
int
secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
unsigned char* res)
{
switch(algo) {
case NSEC3_HASH_SHA1:
(void)HASH_HashBuf(HASH_AlgSHA1, res, buf, (unsigned long)len);
return 1;
default:
return 0;
}
}
size_t
_getdns_ds_digest_size_supported(int algo)
{
@ -622,8 +726,10 @@ _getdns_dnskey_algo_id_is_supported(int id)
case GLDNS_RSAMD5:
/* RFC 6725 deprecates RSAMD5 */
return 0;
#ifdef USE_DSA
case GLDNS_DSA:
case GLDNS_DSA_NSEC3:
#endif
case GLDNS_RSASHA1:
case GLDNS_RSASHA1_NSEC3:
#ifdef USE_SHA2
@ -864,6 +970,7 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
*/
switch(algo) {
#ifdef USE_DSA
case GLDNS_DSA:
case GLDNS_DSA_NSEC3:
*pubkey = nss_buf2dsa(key, keylen);
@ -874,6 +981,7 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
*htype = HASH_AlgSHA1;
/* no prefix for DSA verification */
break;
#endif
case GLDNS_RSASHA1:
case GLDNS_RSASHA1_NSEC3:
#ifdef USE_SHA2
@ -990,6 +1098,7 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
return 0;
}
#ifdef USE_DSA
/* need to convert DSA, ECDSA signatures? */
if((algo == GLDNS_DSA || algo == GLDNS_DSA_NSEC3)) {
if(sigblock_len == 1+2*SHA1_LENGTH) {
@ -1012,6 +1121,7 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
SECITEM_FreeItem(p, PR_TRUE);
}
}
#endif /* USE_DSA */
/* do the signature cryptography work */
/* hash the data */
@ -1068,5 +1178,470 @@ _getdns_verify_canonrrset(gldns_buffer* buf, int algo, unsigned char* sigblock,
return 0;
}
#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"
#include "asn1.h"
#ifdef USE_ECDSA
#include "ecdsa.h"
#include "ecc-curve.h"
#endif
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;
}
/* return size of digest if supported, or 0 otherwise */
size_t
nsec3_hash_algo_size_supported(int id)
{
switch(id) {
case NSEC3_HASH_SHA1:
return SHA1_DIGEST_SIZE;
default:
return 0;
}
}
/* perform nsec3 hash. return false on failure */
int
secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
unsigned char* res)
{
switch(algo) {
case NSEC3_HASH_SHA1:
return _digest_nettle(SHA1_DIGEST_SIZE, (uint8_t*)buf, len,
res);
default:
return 0;
}
}
/**
* 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
_getdns_ds_digest_size_supported(int algo)
{
switch(algo) {
case GLDNS_SHA1:
return SHA1_DIGEST_SIZE;
#ifdef USE_SHA2
case GLDNS_SHA256:
return SHA256_DIGEST_SIZE;
#endif
#ifdef USE_ECDSA
case GLDNS_SHA384:
return SHA384_DIGEST_SIZE;
#endif
/* GOST not supported */
case GLDNS_HASH_GOST:
default:
break;
}
return 0;
}
int
_getdns_secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
unsigned char* res)
{
switch(algo) {
case GLDNS_SHA1:
return _digest_nettle(SHA1_DIGEST_SIZE, buf, len, res);
#if defined(USE_SHA2)
case GLDNS_SHA256:
return _digest_nettle(SHA256_DIGEST_SIZE, buf, len, res);
#endif
#ifdef USE_ECDSA
case GLDNS_SHA384:
return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res);
#endif
case GLDNS_HASH_GOST:
default:
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
algo);
break;
}
return 0;
}
int
_getdns_dnskey_algo_id_is_supported(int id)
{
/* uses libnettle */
switch(id) {
#ifdef USE_DSA
case GLDNS_DSA:
case GLDNS_DSA_NSEC3:
#endif
case GLDNS_RSASHA1:
case GLDNS_RSASHA1_NSEC3:
#ifdef USE_SHA2
case GLDNS_RSASHA256:
case GLDNS_RSASHA512:
#endif
#ifdef USE_ECDSA
case GLDNS_ECDSAP256SHA256:
case GLDNS_ECDSAP384SHA384:
#endif
return 1;
case GLDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */
case GLDNS_ECC_GOST:
default:
return 0;
}
}
static char *
_verify_nettle_dsa(gldns_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;
/* Extract DSA signature from the record */
nettle_dsa_signature_init(&signature);
/* Signature length: 41 bytes - RFC 2536 sec. 3 */
if(sigblock_len == 41) {
if(key[0] != sigblock[0])
return "invalid T value in DSA signature or pubkey";
nettle_mpz_set_str_256_u(signature.r, 20, sigblock+1);
nettle_mpz_set_str_256_u(signature.s, 20, sigblock+1+20);
} else {
/* DER encoded, decode the ASN1 notated R and S bignums */
/* SEQUENCE { r INTEGER, s INTEGER } */
struct asn1_der_iterator i, seq;
if(asn1_der_iterator_first(&i, sigblock_len,
(uint8_t*)sigblock) != ASN1_ITERATOR_CONSTRUCTED
|| i.type != ASN1_SEQUENCE)
return "malformed DER encoded DSA signature";
/* decode this element of i using the seq iterator */
if(asn1_der_decode_constructed(&i, &seq) !=
ASN1_ITERATOR_PRIMITIVE || seq.type != ASN1_INTEGER)
return "malformed DER encoded DSA signature";
if(!asn1_der_get_bignum(&seq, signature.r, 20*8))
return "malformed DER encoded DSA signature";
if(asn1_der_iterator_next(&seq) != ASN1_ITERATOR_PRIMITIVE
|| seq.type != ASN1_INTEGER)
return "malformed DER encoded DSA signature";
if(!asn1_der_get_bignum(&seq, signature.s, 20*8))
return "malformed DER encoded DSA signature";
if(asn1_der_iterator_next(&i) != ASN1_ITERATOR_END)
return "malformed DER encoded DSA signature";
}
/* Validate T values constraints - RFC 2536 sec. 2 & sec. 3 */
key_t = key[0];
if (key_t > 8) {
return "invalid T value in DSA pubkey";
}
/* 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);
/* Digest content of "buf" and verify its DSA signature in "sigblock"*/
res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)gldns_buffer_begin(buf),
(unsigned int)gldns_buffer_limit(buf), (unsigned char*)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(gldns_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*)gldns_buffer_begin(buf),
(unsigned int)gldns_buffer_limit(buf), (unsigned char*)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*)gldns_buffer_begin(buf),
(unsigned int)gldns_buffer_limit(buf), (unsigned char*)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*)gldns_buffer_begin(buf),
(unsigned int)gldns_buffer_limit(buf), (unsigned char*)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(gldns_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*)gldns_buffer_begin(buf),
(unsigned int)gldns_buffer_limit(buf), (unsigned char*)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*)gldns_buffer_begin(buf),
(unsigned int)gldns_buffer_limit(buf), (unsigned char*)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.
*/
int
_getdns_verify_canonrrset(gldns_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 0;
}
switch(algo) {
#ifdef USE_DSA
case GLDNS_DSA:
case GLDNS_DSA_NSEC3:
*reason = _verify_nettle_dsa(buf, sigblock, sigblock_len, key, keylen);
if (*reason != NULL)
return 0;
else
return 1;
#endif /* USE_DSA */
case GLDNS_RSASHA1:
case GLDNS_RSASHA1_NSEC3:
digest_size = (digest_size ? digest_size : SHA1_DIGEST_SIZE);
#ifdef USE_SHA2
case GLDNS_RSASHA256:
digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE);
case GLDNS_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 0;
else
return 1;
#ifdef USE_ECDSA
case GLDNS_ECDSAP256SHA256:
digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE);
case GLDNS_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 0;
else
return 1;
#endif
case GLDNS_RSAMD5:
case GLDNS_ECC_GOST:
default:
*reason = "unable to verify signature, unknown algorithm";
return 0;
}
}
#endif /* HAVE_SSL or HAVE_NSS or HAVE_NETTLE */

View File

@ -44,6 +44,21 @@
#define VALIDATOR_VAL_SECALGO_H
struct gldns_buffer;
/** Return size of nsec3 hash algorithm, 0 if not supported */
size_t nsec3_hash_algo_size_supported(int id);
/**
* Hash a single hash call of an NSEC3 hash algorithm.
* Iterations and salt are done by the caller.
* @param algo: nsec3 hash algorithm.
* @param buf: the buffer to digest
* @param len: length of buffer to digest.
* @param res: result stored here (must have sufficient space).
* @return false on failure.
*/
int secalgo_nsec3_hash(int algo, unsigned char* buf, size_t len,
unsigned char* res);
/**
* Return size of DS digest according to its hash algorithm.
* @param algo: DS digest algo.