From: Karel Slany Date: Mon, 6 Jun 2016 12:29:56 +0000 (+0200) Subject: Added HMAC-SHA256-64 hash function. X-Git-Tag: v1.1.0~2^2~108 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cab86aecbec852191c2face6740f3fe70b8269db;p=thirdparty%2Fknot-resolver.git Added HMAC-SHA256-64 hash function. --- diff --git a/Makefile b/Makefile index 883d0e980..f557a160e 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ $(eval $(call find_lib,libknot,2.1)) $(eval $(call find_lib,lmdb)) $(eval $(call find_lib,libzscanner,2.1)) $(eval $(call find_lib,libuv,1.0)) +$(eval $(call find_lib,libcrypto)) $(eval $(call find_alt,lua,luajit)) $(eval $(call find_lib,cmocka)) $(eval $(call find_bin,doxygen)) @@ -65,7 +66,7 @@ BUILD_CFLAGS += $(libknot_CFLAGS) $(libuv_CFLAGS) $(cmocka_CFLAGS) $(lua_CFLAGS) BUILD_CFLAGS += $(addprefix -I,$(wildcard contrib/ccan/*) contrib/murmurhash3) ifeq ($(ENABLE_cookies),yes) -BUILD_CFLAGS += -DENABLE_COOKIES +BUILD_CFLAGS += -DENABLE_COOKIES $(libcrypto_CFLAGS) endif # Overview @@ -94,6 +95,7 @@ info: $(info [$(HAS_lua)] luajit (daemon)) $(info [$(HAS_libuv)] libuv (daemon)) $(info [$(HAS_gnutls)] libgnutls (daemon)) + $(info [$(HAS_libcrypto)] crypto (DNS cookies)) $(info ) $(info Optional) $(info --------) diff --git a/lib/cookies/control.c b/lib/cookies/control.c index 062ebe504..e3ddb72ea 100644 --- a/lib/cookies/control.c +++ b/lib/cookies/control.c @@ -20,9 +20,11 @@ #include #include #include +#include +#include +#include #include #include -#include #include "contrib/fnv/fnv.h" #include "lib/cookies/cache.h" @@ -36,10 +38,12 @@ # define DEBUG_MSG(qry, fmt...) do { } while (0) #endif /* defined(MODULE_DEBUG_MSGS) */ +//#define CC_HASH_USE_CLIENT_ADDRESS /* When defined, client address will be used when generating client cookie. */ + /* Default client secret. */ struct kr_cookie_secret dflt_cs = { .size = KNOT_OPT_COOKIE_CLNT, - .data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + .data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; struct kr_cookie_ctx kr_glob_cookie_ctx = { @@ -127,51 +131,47 @@ int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len) WITH_DEBUG { char ns_str[INET6_ADDRSTRLEN]; inet_ntop(addr_family, *addr, ns_str, sizeof(ns_str)); - DEBUG_MSG(NULL, "obtaned IP address '%s'\n", ns_str); + DEBUG_MSG(NULL, "obtained IP address '%s'\n", ns_str); } return kr_ok(); } -int kr_client_cokie_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT], - const void *clnt_sockaddr, const void *srvr_sockaddr, - const struct kr_cookie_secret *secret) +int kr_cc_compute_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT], + const void *clnt_sockaddr, const void *srvr_sockaddr, + const struct kr_cookie_secret *secret) { if (!cc_buf) { return kr_error(EINVAL); } - if (!clnt_sockaddr && !srvr_sockaddr && + if ((!clnt_sockaddr && !srvr_sockaddr) || !(secret && secret->size && secret->data)) { return kr_error(EINVAL); } const uint8_t *addr = NULL; - size_t size = 0; + size_t alen = 0; /* Address length. */ Fnv64_t hash_val = FNV1A_64_INIT; - /* Client address currently always ignored. */ -#if 0 +#if defined(CC_HASH_USE_CLIENT_ADDRESS) if (clnt_sockaddr) { - if (kr_ok() == kr_address_bytes(clnt_sockaddr, &addr, &size)) { - assert(addr && size); - hash_val = fnv_64a_buf(addr, size, hash_val); + if (kr_ok() == kr_address_bytes(clnt_sockaddr, &addr, &alen)) { + assert(addr && alen); + hash_val = fnv_64a_buf(addr, alen, hash_val); } } -#endif +#endif /* defined(CC_HASH_USE_CLIENT_ADDRESS) */ if (srvr_sockaddr) { - if (kr_ok() == kr_address_bytes(srvr_sockaddr, &addr, &size)) { - assert(addr && size); - hash_val = fnv_64a_buf((void *) addr, size, hash_val); + if (kr_ok() == kr_address_bytes(srvr_sockaddr, &addr, &alen)) { + assert(addr && alen); + hash_val = fnv_64a_buf((void *) addr, alen, hash_val); } } - if (secret && secret->size && secret->data) { - DEBUG_MSG(NULL, "%s\n", "adding client secret into cookie"); - hash_val = fnv_64a_buf((void *) addr, size, hash_val); - } + hash_val = fnv_64a_buf((void *) secret->data, secret->size, hash_val); assert(KNOT_OPT_COOKIE_CLNT == sizeof(hash_val)); @@ -180,6 +180,77 @@ int kr_client_cokie_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT], return kr_ok(); } +int kr_cc_compute_hmac_sha256_64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT], + const void *clnt_sockaddr, const void *srvr_sockaddr, + const struct kr_cookie_secret *secret) +{ + if (!cc_buf) { + return kr_error(EINVAL); + } + + if ((!clnt_sockaddr && !srvr_sockaddr) || + !(secret && secret->size && secret->data)) { + return kr_error(EINVAL); + } + + const uint8_t *addr = NULL; + size_t alen = 0; /* Address length. */ + + uint8_t digest[SHA256_DIGEST_LENGTH]; + unsigned int digest_len = SHA256_DIGEST_LENGTH; + + /* text: (client IP | server IP) + * key: client secret */ + + HMAC_CTX ctx; + HMAC_CTX_init(&ctx); + + int ret = HMAC_Init_ex(&ctx, secret->data, secret->size, EVP_sha256(), + NULL); + if (ret != 1) { + ret = kr_error(EINVAL); + goto fail; + } + +#if defined(CC_HASH_USE_CLIENT_ADDRESS) + if (clnt_sockaddr) { + if (kr_ok() == kr_address_bytes(clnt_sockaddr, &addr, &alen)) { + assert(addr && alen); + ret = HMAC_Update(&ctx, addr, alen); + if (ret != 1) { + ret = kr_error(EINVAL); + goto fail; + } + } + } +#endif /* defined(CC_HASH_USE_CLIENT_ADDRESS) */ + + if (srvr_sockaddr) { + if (kr_ok() == kr_address_bytes(srvr_sockaddr, &addr, &alen)) { + assert(addr && alen); + ret = HMAC_Update(&ctx, addr, alen); + if (ret != 1) { + ret = kr_error(EINVAL); + goto fail; + } + } + } + + if (1 != HMAC_Final(&ctx, digest, &digest_len)) { + ret = kr_error(EINVAL); + goto fail; + } + + assert(KNOT_OPT_COOKIE_CLNT <= SHA256_DIGEST_LENGTH); + + memcpy(cc_buf, digest, KNOT_OPT_COOKIE_CLNT); + ret = kr_ok(); + +fail: + HMAC_CTX_cleanup(&ctx); + return ret; +} + /** * Check whether there is a cached cookie that matches the current client * cookie. @@ -233,8 +304,9 @@ int kr_request_put_cookie(const struct kr_cookie_ctx *cntrl, * TODO -- generate client cookie from client address, server address * and secret quantity. */ uint8_t cc[KNOT_OPT_COOKIE_CLNT]; - int ret = kr_client_cokie_fnv64(cc, clnt_sockaddr, srvr_sockaddr, - cntrl->current_cs); + assert(cntrl->cc_compute_func); + int ret = cntrl->cc_compute_func(cc, clnt_sockaddr, srvr_sockaddr, + cntrl->current_cs); if (ret != kr_ok()) { return ret; } diff --git a/lib/cookies/control.h b/lib/cookies/control.h index aae02f79c..d2ddc2bdf 100644 --- a/lib/cookies/control.h +++ b/lib/cookies/control.h @@ -39,6 +39,10 @@ extern struct kr_cookie_secret dflt_cs; /** Default cookie TTL. */ #define DFLT_COOKIE_TTL 72000 +/** Client cookie creation function type. */ +typedef int (cc_compute_func_t)(uint8_t *, const void *, const void *, + const struct kr_cookie_secret *); + /** DNS cookies controlling structure. */ struct kr_cookie_ctx { bool enabled; /**< Enabled/disables DNS cookies functionality. */ @@ -48,7 +52,8 @@ struct kr_cookie_ctx { uint32_t cache_ttl; /**< TTL used when caching cookies */ -// struct kr_cache cache; /*!< Server cookies cache. */ + /**< Client cookie computation callback. */ + cc_compute_func_t *cc_compute_func; }; /** Global cookie control context. */ @@ -64,17 +69,32 @@ extern struct kr_cookie_ctx kr_glob_cookie_ctx; int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len); /** - * Compute client cookie. - * @not At least one of the arguments must be non-null. + * Compute client cookie using FNV-64. + * @note At least one of the arguments must be non-null. * @param cc_buf Buffer to which to write the cookie into. * @param clnt_sockaddr Client address. * @param srvr_sockaddr Server address. * @param secret Client secret quantity. + * @return kr_ok() on success, error code else. */ KR_EXPORT -int kr_client_cokie_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT], - const void *clnt_sockaddr, const void *srvr_sockaddr, - const struct kr_cookie_secret *secret); +int kr_cc_compute_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT], + const void *clnt_sockaddr, const void *srvr_sockaddr, + const struct kr_cookie_secret *secret); + +/** + * Compute client cookie using HMAC_SHA256-64. + * @note At least one of the arguments must be non-null. + * @param cc_buf Buffer to which to write the cookie into. + * @param clnt_sockaddr Client address. + * @param srvr_sockaddr Server address. + * @param secret Client secret quantity. + * @return kr_ok() on success, error code else. + */ +KR_EXPORT +int kr_cc_compute_hmac_sha256_64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT], + const void *clnt_sockaddr, const void *srvr_sockaddr, + const struct kr_cookie_secret *secret); /** * Insert a DNS cookie into query packet. diff --git a/lib/layer/cookiemonster.c b/lib/layer/cookiemonster.c index 854504ba6..77e5a4c47 100644 --- a/lib/layer/cookiemonster.c +++ b/lib/layer/cookiemonster.c @@ -42,17 +42,19 @@ * @param clnt_sockaddr client socket address (i.e. resolver address) * @param srvr_sockaddr server socket address * @param csecr client secret + * @param cc_compute_func function generating client cookie * @return kr_ok() or error code */ static int check_client_cookie(const uint8_t cc[KNOT_OPT_COOKIE_CLNT], const void *clnt_sockaddr, const void *srvr_sockaddr, - const struct kr_cookie_secret *csecr) + const struct kr_cookie_secret *csecr, + cc_compute_func_t *cc_compute_func) { uint8_t generated_cc[KNOT_OPT_COOKIE_CLNT] = {0, }; - int ret = kr_client_cokie_fnv64(generated_cc, clnt_sockaddr, - srvr_sockaddr, csecr); + int ret = cc_compute_func(generated_cc, clnt_sockaddr, + srvr_sockaddr, csecr); if (ret != kr_ok()) { return ret; } @@ -88,13 +90,15 @@ static const struct sockaddr *passed_server_sockaddr(const struct kr_query *qry) * @param nsrep name server reputation context * @param cc client cookie data * @param csecr client secret + * @param cc_compute_func function generating client cookie * @return pointer to address if a matching found, NULL if none matches */ static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep, const uint8_t cc[KNOT_OPT_COOKIE_CLNT], - const struct kr_cookie_secret *csecr) + const struct kr_cookie_secret *csecr, + cc_compute_func_t *cc_compute_func) { - assert(nsrep && cc && csecr); + assert(nsrep && cc && csecr && cc_compute_func); const struct sockaddr *sockaddr = NULL; @@ -103,7 +107,8 @@ static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep, if (nsrep->addr[i].ip.sa_family == AF_UNSPEC) { break; } - int ret = check_client_cookie(cc, NULL, &nsrep->addr[i], csecr); + int ret = check_client_cookie(cc, NULL, &nsrep->addr[i], csecr, + cc_compute_func); if (ret == kr_ok()) { sockaddr = (struct sockaddr *) &nsrep->addr[i]; break; @@ -121,8 +126,8 @@ static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep, * @param cntr cookie control structure * @return kr_ok() if matching address found, error code else */ -static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr, bool *is_current, - const struct kr_query *qry, +static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr, + bool *is_current, const struct kr_query *qry, const uint8_t cc[KNOT_OPT_COOKIE_CLNT], const struct kr_cookie_ctx *cntrl) { @@ -133,11 +138,13 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr, bool *is_cur /* The address must correspond with the client cookie. */ if (tmp_sockaddr) { int ret = check_client_cookie(cc, NULL, tmp_sockaddr, - cntrl->current_cs); + cntrl->current_cs, + cntrl->cc_compute_func); bool have_current = (ret == kr_ok()); if ((ret != kr_ok()) && cntrl->recent_cs) { ret = check_client_cookie(cc, NULL, tmp_sockaddr, - cntrl->recent_cs); + cntrl->recent_cs, + cntrl->cc_compute_func); } if (ret == kr_ok()) { *sockaddr = tmp_sockaddr; @@ -155,11 +162,13 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr, bool *is_cur /* Abusing name server reputation mechanism to guess IP addresses. */ const struct kr_nsrep *ns = &qry->ns; - tmp_sockaddr = guess_server_addr(ns, cc, cntrl->current_cs); + tmp_sockaddr = guess_server_addr(ns, cc, cntrl->current_cs, + cntrl->cc_compute_func); bool have_current = (tmp_sockaddr != NULL); if (!tmp_sockaddr && cntrl->recent_cs) { /* Try recent client secret to check obtained cookie. */ - tmp_sockaddr = guess_server_addr(ns, cc, cntrl->recent_cs); + tmp_sockaddr = guess_server_addr(ns, cc, cntrl->recent_cs, + cntrl->cc_compute_func); } if (tmp_sockaddr) { *sockaddr = tmp_sockaddr; diff --git a/lib/lib.mk b/lib/lib.mk index 4120a2cc0..6b13c85c2 100644 --- a/lib/lib.mk +++ b/lib/lib.mk @@ -54,6 +54,8 @@ libkres_SOURCES += \ libkres_HEADERS += \ lib/cookies/cache.h \ lib/cookies/control.h + +libkres_LIBS += $(libcrypto_LIBS) endif # Make library diff --git a/modules/cookiectl/cookiectl.c b/modules/cookiectl/cookiectl.c index bf86bcaaa..93892e957 100644 --- a/modules/cookiectl/cookiectl.c +++ b/modules/cookiectl/cookiectl.c @@ -273,6 +273,8 @@ int cookiectl_init(struct kr_module *module) kr_glob_cookie_ctx.current_cs = &dflt_cs; kr_glob_cookie_ctx.cache_ttl = DFLT_COOKIE_TTL; + kr_glob_cookie_ctx.cc_compute_func = kr_cc_compute_fnv64; + // cookies_cache_init(&kr_glob_cookie_ctx.cache, engine); module->data = NULL;