-- 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
.. 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.
#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>
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;
}
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;
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,