]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
Added HMAC-SHA256-64 hash function.
authorKarel Slany <karel.slany@nic.cz>
Mon, 6 Jun 2016 12:29:56 +0000 (14:29 +0200)
committerOndřej Surý <ondrej@sury.org>
Thu, 11 Aug 2016 12:06:45 +0000 (14:06 +0200)
Makefile
lib/cookies/control.c
lib/cookies/control.h
lib/layer/cookiemonster.c
lib/lib.mk
modules/cookiectl/cookiectl.c

index 883d0e9808281f221892534f1e2f16799a0d6236..f557a160eb829c1d8bd6a2e703eaf87d29ac1911 100644 (file)
--- 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 --------)
index 062ebe504c5d43f21b893876aa0d868fafb8df2d..e3ddb72eab848ac111c266dfb597d9afa2319826 100644 (file)
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <assert.h>
+#include <libknot/error.h>
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
 #include <stdint.h>
 #include <string.h>
-#include <libknot/error.h>
 
 #include "contrib/fnv/fnv.h"
 #include "lib/cookies/cache.h"
 #  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;
        }
index aae02f79c1af9dcd93fad7c5bab49fff53c09561..d2ddc2bdf768965056523aed4269cdb5d5fd7ad1 100644 (file)
@@ -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.
index 854504ba689091c57698a24e0a84318e827bcbc5..77e5a4c47180793e7dbb83749a452b62ef31b58d 100644 (file)
  * @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;
index 4120a2cc09e8dc5db9f6bd7df4ab9ac213fc1916..6b13c85c21173440048d60fd7d98f917959308c2 100644 (file)
@@ -54,6 +54,8 @@ libkres_SOURCES += \
 libkres_HEADERS += \
        lib/cookies/cache.h    \
        lib/cookies/control.h
+
+libkres_LIBS += $(libcrypto_LIBS)
 endif
 
 # Make library
index bf86bcaaaa09245ff83fd4c60373cb8469cb320c..93892e9571c9b343c418eb72e85dcd9beecd6610 100644 (file)
@@ -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;