]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
Using a hex string to configure secret values.
authorKarel Slany <karel.slany@nic.cz>
Wed, 13 Jul 2016 13:06:57 +0000 (15:06 +0200)
committerOndřej Surý <ondrej@sury.org>
Thu, 11 Aug 2016 12:06:45 +0000 (14:06 +0200)
modules/cookies/README.rst
modules/cookies/cookiectl.c

index 13eed5286f4ff4f11ac22a2d52ba949b528eeb16..286629c2264c6fbcddcdbd01e04258b71755f543 100644 (file)
@@ -17,12 +17,12 @@ Example Configuration
 
        -- Configure the client part of the resolver. Set 8 bytes of the client
        -- secret and choose the hashing algorithm to be used.
-       cookies.config( { ['client_secret'] = { 0, 1, 2, 3, 4, 5, 6, 7 },
+       -- Use a string composed of hexadecimal digits to set the secret.
+       cookies.config( { ['client_secret'] = '0123456789ABCDEF',
                          ['client_cookie_alg'] = 'FNV-64' } )
 
-       -- Configure the server part of the resolver. Sets a string to be used
-       -- as server secret. Also chooses the hashing algorithm to be used.
-       cookies.config( { ['server_secret'] = 'secret key',
+       -- Configure the server part of the resolver.
+       cookies.config( { ['server_secret'] = 'FEDCBA9876543210',
                          ['server_cookie_alg'] = 'FNV-64' } )
 
        -- Enable client cookie functionality. (Add cookies into outbound
@@ -43,7 +43,7 @@ Properties
 .. function:: cookies.config(configuration)
 
   :param table configuration: part of cookie configuration to be changed, may be called without parameter
-  :return: JSON dictionary containing corrent configuration
+  :return: JSON dictionary containing current configuration
 
   The function may be called without any parameter. In such case it only returns current configuration. The returned JSON alsao contains available algorithm choices.
 
index fbb87e9bace989097d04f92b6dcfa39bcc049c85..8ffaf2d2eb3cdaae1d511933762d2bcacf06451f 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <assert.h>
 #include <ccan/json/json.h>
+#include <ctype.h>
 #include <libknot/rrtype/opt-cookie.h>
 #include <libknot/db/db_lmdb.h>
 #include <stdlib.h>
@@ -86,48 +87,126 @@ static struct kr_cookie_secret *new_cookie_secret(size_t size, bool zero)
        return sq;
 }
 
-static struct kr_cookie_secret *new_sq_str(const JsonNode *node)
+static int hexchar2val(int d)
 {
-       assert(node && node->tag == JSON_STRING);
+       if (('0' <= d) && (d <= '9')) {
+               return d - '0';
+       } else if (('a' <= d) && (d <= 'f')) {
+               return d - 'a' + 0x0a;
+       } else {
+               return -1;
+       }
+}
 
-       size_t len = strlen(node->string_);
+static int hexval2char(int i)
+{
+       if ((0 <= i) && (i <= 9)) {
+               return i + '0';
+       } if ((0x0a <= i) && (i <= 0x0f)) {
+               return i - 0x0a + 'A';
+       } else {
+               return -1;
+       }
+}
 
-       struct kr_cookie_secret *sq = new_cookie_secret(len, false);
-       if (!sq) {
-               return NULL;
+/**
+ * @brief Converts string containing two-digit hexadecimal number into int.
+ * @param hexstr hexadecimal string
+ * @return -1 on error, value from 0 to 255 else.
+ */
+static int hexbyte2int(const char *hexstr)
+{
+       if (!hexstr) {
+               return -1;
        }
-       memcpy(sq->data, node->string_, len);
 
-       return sq;
+       int dhi = tolower(hexstr[0]);
+       if (!isxdigit(dhi)) {
+               /* Exit also on empty string. */
+               return -1;
+       }
+       int dlo = tolower(hexstr[1]);
+       if (!isxdigit(dlo)) {
+               return -1;
+       }
+
+       dhi = hexchar2val(dhi);
+       assert(dhi != -1);
+       dlo = hexchar2val(dlo);
+       assert(dlo != -1);
+
+       return (dhi << 4) | dlo;
 }
 
-#define holds_char(x) ((x) >= 0 && (x) <= 255)
+/**
+ * @brief Writes two hexadecimal digits (two byes) into given memory location.
+ * @param tgt target location
+ * @param i number from 0 to 255
+ * @return 0 on success, -1 on failure
+ */
+static int int2hexbyte(char *tgt, int i)
+{
+       if (!tgt || i < 0x00 || i > 0xff) {
+               return -1;
+       }
+
+       int ilo = hexval2char(i & 0x0f);
+       assert(ilo != -1);
+       int ihi = hexval2char((i >> 4) & 0x0f);
+       assert(ihi != -1);
 
-static struct kr_cookie_secret *new_sq_array(const JsonNode *node)
+       tgt[0] = ihi;
+       tgt[1] = ilo;
+
+       return 0;
+}
+
+/**
+ * @brief Reads a string containing hexadecimal values.
+ * @note String must consist of hexadecimal digits only and must have even
+ *       non-zero length.
+ */
+static struct kr_cookie_secret *new_sq_from_hexstr(const JsonNode *node)
 {
-       assert(node && node->tag == JSON_ARRAY);
+       assert(node && node->tag == JSON_STRING);
 
-       const JsonNode *element = NULL;
-       size_t cnt = 0;
-       json_foreach(element, node) {
-               if (element->tag != JSON_NUMBER || !holds_char(element->number_)) {
-                       return NULL;
-               }
-               ++cnt;
-       }
-       if (cnt == 0) {
+       size_t len = strlen(node->string_);
+       if ((len % 2) != 0) {
                return NULL;
        }
 
-       struct kr_cookie_secret *sq = new_cookie_secret(cnt, false);
+       struct kr_cookie_secret *sq = new_cookie_secret(len / 2, false);
        if (!sq) {
                return NULL;
        }
 
-       cnt = 0;
-       json_foreach(element, node) {
-               sq->data[cnt++] = (uint8_t) element->number_;
+       const char *hexstr = node->string_;
+       uint8_t *data = sq->data;
+       for (int i = 0; i < len; i += 2) {
+               int num = hexbyte2int(hexstr + i);
+               if (num == -1) {
+                       free(sq);
+                       return NULL;
+               }
+               assert(0x00 <= num && num <= 0xff);
+               *data = num;
+               ++data;
+       }
+
+       return sq;
+}
+
+static struct kr_cookie_secret *new_sq_str(const JsonNode *node)
+{
+       assert(node && node->tag == JSON_STRING);
+
+       size_t len = strlen(node->string_);
+
+       struct kr_cookie_secret *sq = new_cookie_secret(len, false);
+       if (!sq) {
+               return NULL;
        }
+       memcpy(sq->data, node->string_, len);
 
        return sq;
 }
@@ -147,10 +226,7 @@ static bool apply_secret_shallow(struct kr_cookie_secret **sec,
 
        switch (node->tag) {
        case JSON_STRING:
-               sq = new_sq_str(node);
-               break;
-       case JSON_ARRAY:
-               sq = new_sq_array(node);
+               sq = new_sq_from_hexstr(node);
                break;
        default:
                break;
@@ -224,33 +300,55 @@ static bool apply_configuration_shallow(struct kr_cookie_ctx *cntrl,
        return false;
 }
 
+/**
+ * @brief Creates a new string from secret quantity.
+ * @param sq secret quantity
+ * @return newly allocated string or NULL on error
+ */
+static char *new_hexstr_from_sq(const struct kr_cookie_secret *sq)
+{
+       if (!sq) {
+               return NULL;
+       }
+
+       char *new_str = malloc((sq->size * 2) + 1);
+       if (!new_str) {
+               return NULL;
+       }
+
+       char *tgt = new_str;
+       for (size_t i = 0; i < sq->size; ++i) {
+               if (0 != int2hexbyte(tgt, sq->data[i])) {
+                       free(new_str);
+                       return NULL;
+               }
+               tgt += 2;
+       }
+
+       *tgt = '\0';
+       return new_str;
+}
+
 static bool read_secret(JsonNode *root, const char *node_name,
                         const struct kr_cookie_secret *secret)
 {
        assert(root && node_name && secret);
 
-       JsonNode *array = json_mkarray();
-       if (!array) {
+       char *secret_str = new_hexstr_from_sq(secret);
+       if (!secret_str) {
                return false;
        }
 
-       for (size_t i = 0; i < secret->size; ++i) {
-               JsonNode *element = json_mknumber(secret->data[i]);
-               if (!element) {
-                       goto fail;
-               }
-               json_append_element(array, element);
+       JsonNode *str_node = json_mkstring(secret_str);
+       if (!str_node) {
+               free(secret_str);
+               return false;
        }
 
-       json_append_member(root, node_name, array);
+       json_append_member(root, node_name, str_node);
 
+       free(secret_str);
        return true;
-
-fail:
-       if (array) {
-               json_delete(array);
-       }
-       return false;
 }
 
 static bool read_available_hashes(JsonNode *root, const char *root_name,