summaryrefslogtreecommitdiff
path: root/src/libknot/tsig-op.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libknot/tsig-op.c')
-rw-r--r--src/libknot/tsig-op.c644
1 files changed, 301 insertions, 343 deletions
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
index 3178a23..edc68d8 100644
--- a/src/libknot/tsig-op.c
+++ b/src/libknot/tsig-op.c
@@ -25,305 +25,10 @@
#include "tsig.h"
#include "tsig-op.h"
#include "util/wire.h"
+#include "libknot/util/conv.h"
#include "util/error.h"
#include "util/debug.h"
-
-
-static const char Base64[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char Pad64 = '=';
-
-
-static int b64rmap_initialized = 0;
-static uint8_t b64rmap[256];
-
-static const uint8_t b64rmap_special = 0xf0;
-static const uint8_t b64rmap_end = 0xfd;
-static const uint8_t b64rmap_space = 0xfe;
-static const uint8_t b64rmap_invalid = 0xff;
-
-/**
- * Initializing the reverse map is not thread safe.
- * Which is fine for NSD. For now...
- **/
-void b64_initialize_rmap()
-{
- int i;
- char ch;
-
- /* Null: end of string, stop parsing */
- b64rmap[0] = b64rmap_end;
-
- for (i = 1; i < 256; ++i) {
- ch = (char)i;
- /* Whitespaces */
- if (isspace(ch)) {
- b64rmap[i] = b64rmap_space;
- }
- /* Padding: stop parsing */
- else if (ch == Pad64) {
- b64rmap[i] = b64rmap_end;
- }
- /* Non-base64 char */
- else {
- b64rmap[i] = b64rmap_invalid;
- }
- }
-
- /* Fill reverse mapping for base64 chars */
- for (i = 0; Base64[i] != '\0'; ++i) {
- b64rmap[(uint8_t)Base64[i]] = i;
- }
-
- b64rmap_initialized = 1;
-}
-
-int b64_pton_do(char const *src, uint8_t *target, size_t targsize)
-{
- int tarindex, state, ch;
- uint8_t ofs;
-
- state = 0;
- tarindex = 0;
-
- while (1) {
- ch = *src++;
- ofs = b64rmap[ch];
-
- if (ofs >= b64rmap_special) {
- /* Ignore whitespaces */
- if (ofs == b64rmap_space) {
- continue;
- }
- /* End of base64 characters */
- if (ofs == b64rmap_end) {
- break;
- }
- /* A non-base64 character. */
- return (-1);
- }
-
- switch (state) {
- case 0:
- if ((size_t)tarindex >= targsize) {
- return (-1);
- }
- target[tarindex] = ofs << 2;
- state = 1;
- break;
- case 1:
- if ((size_t)tarindex + 1 >= targsize) {
- return (-1);
- }
- target[tarindex] |= ofs >> 4;
- target[tarindex+1] = (ofs & 0x0f)
- << 4 ;
- tarindex++;
- state = 2;
- break;
- case 2:
- if ((size_t)tarindex + 1 >= targsize) {
- return (-1);
- }
- target[tarindex] |= ofs >> 2;
- target[tarindex+1] = (ofs & 0x03)
- << 6;
- tarindex++;
- state = 3;
- break;
- case 3:
- if ((size_t)tarindex >= targsize) {
- return (-1);
- }
- target[tarindex] |= ofs;
- tarindex++;
- state = 0;
- break;
- default:
- abort();
- }
- }
-
- /*
- * We are done decoding Base-64 chars. Let's see if we ended
- * on a byte boundary, and/or with erroneous trailing characters.
- */
-
- if (ch == Pad64) { /* We got a pad char. */
- ch = *src++; /* Skip it, get next. */
- switch (state) {
- case 0: /* Invalid = in first position */
- case 1: /* Invalid = in second position */
- return (-1);
-
- case 2: /* Valid, means one byte of info */
- /* Skip any number of spaces. */
- for ((void)NULL; ch != '\0'; ch = *src++)
- if (b64rmap[ch] != b64rmap_space) {
- break;
- }
- /* Make sure there is another trailing = sign. */
- if (ch != Pad64) {
- return (-1);
- }
- ch = *src++; /* Skip the = */
- /* Fall through to "single trailing =" case. */
- /* FALLTHROUGH */
-
- case 3: /* Valid, means two bytes of info */
- /*
- * We know this char is an =. Is there anything but
- * whitespace after it?
- */
- for ((void)NULL; ch != '\0'; ch = *src++)
- if (b64rmap[ch] != b64rmap_space) {
- return (-1);
- }
-
- /*
- * Now make sure for cases 2 and 3 that the "extra"
- * bits that slopped past the last full byte were
- * zeros. If we don't check them, they become a
- * subliminal channel.
- */
- if (target[tarindex] != 0) {
- return (-1);
- }
- }
- } else {
- /*
- * We ended by seeing the end of the string. Make sure we
- * have no partial bytes lying around.
- */
- if (state != 0) {
- return (-1);
- }
- }
-
- return (tarindex);
-}
-
-
-int b64_pton_len(char const *src)
-{
- int tarindex, state, ch;
- uint8_t ofs;
-
- state = 0;
- tarindex = 0;
-
- while (1) {
- ch = *src++;
- ofs = b64rmap[ch];
-
- if (ofs >= b64rmap_special) {
- /* Ignore whitespaces */
- if (ofs == b64rmap_space) {
- continue;
- }
- /* End of base64 characters */
- if (ofs == b64rmap_end) {
- break;
- }
- /* A non-base64 character. */
- return (-1);
- }
-
- switch (state) {
- case 0:
- state = 1;
- break;
- case 1:
- tarindex++;
- state = 2;
- break;
- case 2:
- tarindex++;
- state = 3;
- break;
- case 3:
- tarindex++;
- state = 0;
- break;
- default:
- abort();
- }
- }
-
- /*
- * We are done decoding Base-64 chars. Let's see if we ended
- * on a byte boundary, and/or with erroneous trailing characters.
- */
-
- if (ch == Pad64) { /* We got a pad char. */
- ch = *src++; /* Skip it, get next. */
- switch (state) {
- case 0: /* Invalid = in first position */
- case 1: /* Invalid = in second position */
- return (-1);
-
- case 2: /* Valid, means one byte of info */
- /* Skip any number of spaces. */
- for ((void)NULL; ch != '\0'; ch = *src++)
- if (b64rmap[ch] != b64rmap_space) {
- break;
- }
- /* Make sure there is another trailing = sign. */
- if (ch != Pad64) {
- return (-1);
- }
- ch = *src++; /* Skip the = */
- /* Fall through to "single trailing =" case. */
- /* FALLTHROUGH */
-
- case 3: /* Valid, means two bytes of info */
- /*
- * We know this char is an =. Is there anything but
- * whitespace after it?
- */
- for ((void)NULL; ch != '\0'; ch = *src++)
- if (b64rmap[ch] != b64rmap_space) {
- return (-1);
- }
-
- }
- } else {
- /*
- * We ended by seeing the end of the string. Make sure we
- * have no partial bytes lying around.
- */
- if (state != 0) {
- return (-1);
- }
- }
-
- return (tarindex);
-}
-
-int b64_pton(char const *src, uint8_t *target, size_t targsize)
-{
- if (!b64rmap_initialized) {
- b64_initialize_rmap();
- }
-
- if (target) {
- return b64_pton_do(src, target, targsize);
- } else {
- return b64_pton_len(src);
- }
-}
-
-#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */
-
-
-
-
-
-
-
-
-
-
+#include "consts.h"
const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest
@@ -354,7 +59,7 @@ static int knot_tsig_check_key(const knot_rrset_t *tsig_rr,
return KNOT_EMALF;
}
- const char *name = knot_dname_to_str(tsig_name);
+ char *name = knot_dname_to_str(tsig_name);
if (!name) {
return KNOT_EMALF;
}
@@ -362,9 +67,11 @@ static int knot_tsig_check_key(const knot_rrset_t *tsig_rr,
if (knot_dname_compare(tsig_name, tsig_key->name) != 0) {
/*!< \todo which error. */
dbg_tsig("TSIG: unknown key: %s\n", name);
+ free(name);
return KNOT_TSIG_EBADKEY;
}
+ free(name);
return KNOT_EOK;
}
@@ -402,15 +109,15 @@ static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len,
B64BUFSIZE);
if (decoded_key_size < 0) {
dbg_tsig("TSIG: Could not decode Base64\n");
- return KNOT_EMALF;
+ return KNOT_ERROR;
}
- dbg_tsig("TSIG: decoded key size: %d\n", decoded_key_size);
- dbg_tsig("TSIG: decoded key: '%*s'\n", decoded_key_size, decoded_key);
-
- dbg_tsig("TSIG: using this wire for digest calculation\n");
+ dbg_tsig_detail("TSIG: decoded key size: %d\n", decoded_key_size);
+ dbg_tsig_detail("TSIG: decoded key: '%*s'\n", decoded_key_size, decoded_key);
- //dbg_tsig_hex(wire, wire_len);
+// dbg_tsig_detail("TSIG: using this wire for digest calculation\n");
+// dbg_tsig_hex_detail(wire, wire_len);
+ dbg_tsig_detail("Wire for signing is %zu bytes long.\n", wire_len);
/* Compute digest. */
HMAC_CTX ctx;
@@ -420,6 +127,14 @@ static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len,
HMAC_Init(&ctx, decoded_key,
decoded_key_size, EVP_md5());
break;
+ case KNOT_TSIG_ALG_HMAC_SHA1:
+ HMAC_Init(&ctx, decoded_key,
+ decoded_key_size, EVP_sha1());
+ break;
+ case KNOT_TSIG_ALG_HMAC_SHA256:
+ HMAC_Init(&ctx, decoded_key,
+ decoded_key_size, EVP_sha256());
+ break;
default:
return KNOT_ENOTSUP;
} /* switch */
@@ -428,11 +143,14 @@ static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len,
HMAC_Update(&ctx, (const unsigned char *)wire, wire_len);
HMAC_Final(&ctx, digest, &tmp_dig_len);
*digest_len = tmp_dig_len;
+
+ HMAC_CTX_cleanup(&ctx);
return KNOT_EOK;
}
-static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr)
+static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr,
+ uint64_t prev_time_signed)
{
if (!tsig_rr) {
return KNOT_EBADARG;
@@ -452,7 +170,15 @@ static int knot_tsig_check_time_signed(const knot_rrset_t *tsig_rr)
time_t curr_time = time(NULL);
/*!< \todo bleeding eyes. */
- if (difftime(curr_time, (time_t)time_signed) > fudge) {
+ double diff = difftime(curr_time, (time_t)time_signed);
+
+ if (diff > fudge || diff < -fudge) {
+ return KNOT_TSIG_EBADTIME;
+ }
+
+ diff = difftime((time_t)time_signed, prev_time_signed);
+
+ if (diff < 0) {
return KNOT_TSIG_EBADTIME;
}
@@ -569,7 +295,7 @@ static int knot_tsig_wire_write_timers(uint8_t *wire,
return KNOT_EOK;
}
-int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len,
+static int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len,
/*size_t msg_max_len, */const uint8_t *request_mac,
size_t request_mac_len,
uint8_t *digest, size_t *digest_len,
@@ -635,6 +361,7 @@ int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len,
if (ret != KNOT_EOK) {
dbg_tsig("TSIG: create wire: failed to write TSIG "
"variables: %s\n", knot_strerror(ret));
+ free(wire);
return ret;
}
@@ -645,6 +372,7 @@ int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len,
dbg_tsig("TSIG: create wire: failed to compute digest: %s\n",
knot_strerror(ret));
*digest_len = 0;
+ free(wire);
return ret;
}
@@ -666,11 +394,11 @@ int knot_tsig_create_sign_wire(const uint8_t *msg, size_t msg_len,
}
static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len,
- const uint8_t *prev_mac,
- size_t prev_mac_len,
- uint8_t *digest, size_t *digest_len,
- const knot_rrset_t *tmp_tsig,
- const knot_key_t *key)
+ const uint8_t *prev_mac,
+ size_t prev_mac_len,
+ uint8_t *digest, size_t *digest_len,
+ const knot_rrset_t *tmp_tsig,
+ const knot_key_t *key)
{
if (!msg || !key || digest_len == NULL) {
dbg_tsig("TSIG: create wire: bad args.\n");
@@ -689,7 +417,7 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len,
tsig_rdata_tsig_timers_length());
size_t wire_len = sizeof(uint8_t) *
(msg_len + prev_mac_len +
- tsig_rdata_tsig_timers_length());
+ tsig_rdata_tsig_timers_length() + 2);
uint8_t *wire = malloc(wire_len);
if (!wire) {
ERR_ALLOC_FAILED;
@@ -699,19 +427,21 @@ static int knot_tsig_create_sign_wire_next(const uint8_t *msg, size_t msg_len,
memset(wire, 0, wire_len);
/* Copy the request MAC - should work even if NULL. */
+ dbg_tsig("Copying request mac size.\n");
+ knot_wire_write_u16(wire, prev_mac_len);
dbg_tsig("Copying request mac.\n");
- memcpy(wire, prev_mac, sizeof(uint8_t) * prev_mac_len);
+ memcpy(wire + 2, prev_mac, sizeof(uint8_t) * prev_mac_len);
dbg_tsig_detail("TSIG: create wire: request mac: ");
- dbg_tsig_hex_detail(wire, prev_mac_len);
+ dbg_tsig_hex_detail(wire + 2, prev_mac_len);
/* Copy the original message. */
dbg_tsig("Copying original message.\n");
- memcpy(wire + prev_mac_len, msg, msg_len);
+ memcpy(wire + prev_mac_len + 2, msg, msg_len);
dbg_tsig_detail("TSIG: create wire: original message: \n");
//dbg_tsig_hex_detail(wire + prev_mac_len, msg_len);
/* Copy TSIG variables. */
dbg_tsig("Writing TSIG timers.\n");
- ret = knot_tsig_write_tsig_timers(wire + prev_mac_len + msg_len,
+ ret = knot_tsig_write_tsig_timers(wire + prev_mac_len + msg_len + 2,
tmp_tsig);
// ret = knot_tsig_write_tsig_variables(wire + prev_mac_len + msg_len,
// tmp_tsig);
@@ -740,7 +470,8 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
size_t msg_max_len, const uint8_t *request_mac,
size_t request_mac_len,
uint8_t *digest, size_t *digest_len,
- const knot_key_t *key)
+ const knot_key_t *key, uint16_t tsig_rcode,
+ uint64_t request_time_signed)
{
if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) {
return KNOT_EBADARG;
@@ -755,6 +486,8 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
knot_rrset_t *tmp_tsig =
knot_rrset_new(key_name_copy,
KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0);
+ /* Should be retained by rrsig or freed, release. */
+ knot_dname_release(key_name_copy);
if (!tmp_tsig) {
dbg_tsig_detail("TSIG: tmp_tsig = NULL\n");
return KNOT_ENOMEM;
@@ -764,6 +497,7 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
knot_rdata_t *rdata = knot_rdata_new();
if (!rdata) {
dbg_tsig_detail("TSIG: rdata = NULL\n");
+ knot_rrset_free(&tmp_tsig);
return KNOT_ENOMEM;
}
@@ -779,6 +513,8 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
if (!items) {
dbg_tsig_detail("TSIG: items = NULL\n");
ERR_ALLOC_FAILED;
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_free(&rdata);
return KNOT_ENOMEM;
}
@@ -787,23 +523,42 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
int ret = knot_rdata_set_items(rdata, items, desc->length);
if (ret != KNOT_EOK) {
dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret));
+ free(items);
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_free(&rdata);
return ret;
}
free(items);
tsig_rdata_set_alg(tmp_tsig, key->algorithm);
- tsig_rdata_store_current_time(tmp_tsig);
- tsig_rdata_set_fudge(tmp_tsig, 300);
- /* Set original ID */
- tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
+ /* Distinguish BADTIME response. */
+ if (tsig_rcode == KNOT_TSIG_RCODE_BADTIME) {
+ /* Set error */
+ tsig_rdata_set_tsig_error(tmp_tsig, tsig_rcode);
+ /* Set client's time signed into the time signed field. */
+ tsig_rdata_set_time_signed(tmp_tsig, request_time_signed);
- /* Set error */
- /*! \todo [TSIG] Set error and other data if appropriate. */
- tsig_rdata_set_tsig_error(tmp_tsig, 0);
+ /* Store current time into Other data. */
+ uint8_t time_signed[3];
+ time_t curr_time = time(NULL);
- /* Set other len. */
- tsig_rdata_set_other_data(tmp_tsig, 0, 0);
+ /*! \todo bleeding eyes. */
+ knot_wire_write_u48(time_signed, (uint64_t)curr_time);
+
+ tsig_rdata_set_other_data(tmp_tsig, 6, time_signed);
+ } else {
+ tsig_rdata_store_current_time(tmp_tsig);
+ tsig_rdata_set_tsig_error(tmp_tsig, 0);
+
+ /* Set other len. */
+ tsig_rdata_set_other_data(tmp_tsig, 0, 0);
+ }
+
+ tsig_rdata_set_fudge(tmp_tsig, 300); /*! \todo Bleeding eyes :-) */
+
+ /* Set original ID */
+ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
size_t digest_tmp_len = 0;
@@ -818,6 +573,10 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
if (ret != KNOT_EOK) {
dbg_tsig("TSIG: could not create wire or sign wire: %s\n",
knot_strerror(ret));
+ free(items);
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_free(&rdata);
+
return ret;
}
@@ -834,6 +593,9 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
if (ret != KNOT_EOK) {
dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret));
*digest_len = 0;
+ free(items);
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_free(&rdata);
return ret;
}
@@ -854,7 +616,8 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
const uint8_t *prev_digest, size_t prev_digest_len,
uint8_t *digest, size_t *digest_len,
- const knot_key_t *key)
+ const knot_key_t *key, uint8_t *to_sign,
+ size_t to_sign_len)
{
if (!msg || !msg_len || !key || !key || !digest || !digest_len) {
return KNOT_EBADARG;
@@ -869,52 +632,135 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
if (!tmp_tsig) {
return KNOT_ENOMEM;
}
+
+ /* Create rdata for TSIG RR. */
+ knot_rdata_t *rdata = knot_rdata_new();
+ if (!rdata) {
+ dbg_tsig_detail("TSIG: rdata = NULL\n");
+ knot_rrset_free(&tmp_tsig);
+ return KNOT_ENOMEM;
+ }
+
+ int ret = 0;
- tsig_rdata_store_current_time(tmp_tsig);
+ ret = knot_rrset_add_rdata(tmp_tsig, rdata);
+ if (ret != KNOT_EOK) {
+ dbg_tsig_detail("TSIG: could not add rdata\n");
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_free(&rdata);
+ return ret;
+ }
+
+ /* Create items for TSIG RR. */
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(KNOT_RRTYPE_TSIG);
+ assert(desc);
+
+ knot_rdata_item_t *items =
+ malloc(sizeof(knot_rdata_item_t) * desc->length);
+ if (!items) {
+ dbg_tsig_detail("TSIG: items = NULL\n");
+ ERR_ALLOC_FAILED;
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_free(&rdata);
+ return KNOT_ENOMEM;
+ }
+
+ memset(items, 0, sizeof(knot_rdata_item_t) * desc->length);
+ ret = knot_rdata_set_items(rdata, items, desc->length);
+ if (ret != KNOT_EOK) {
+ dbg_tsig_detail("TSIG: rdata_set_items returned %s\n", knot_strerror(ret));
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_free(&rdata);
+ free(items);
+ return ret;
+ }
+ free(items);
+
+ tsig_rdata_store_current_time(tmp_tsig);
+ tsig_rdata_set_fudge(tmp_tsig, 300);
+
/* Create wire to be signed. */
- size_t wire_len = prev_digest_len + *msg_len + KNOT_TSIG_TIMERS_LENGTH;
+ size_t wire_len = prev_digest_len + to_sign_len
+ + KNOT_TSIG_TIMERS_LENGTH + 2;
uint8_t *wire = malloc(wire_len);
if (!wire) {
ERR_ALLOC_FAILED;
+ knot_rrset_free(&tmp_tsig);
+ knot_rdata_deep_free(&rdata, KNOT_RRTYPE_TSIG, 0);
return KNOT_ENOMEM;
}
memset(wire, 0, wire_len);
+ /* Write previous digest length. */
+ knot_wire_write_u16(wire, prev_digest_len);
/* Write previous digest. */
- memcpy(wire, prev_digest, sizeof(uint8_t) * prev_digest_len);
+ memcpy(wire + 2, prev_digest, sizeof(uint8_t) * prev_digest_len);
/* Write original message. */
- memcpy(msg + prev_digest_len, msg, *msg_len);
+ memcpy(wire + prev_digest_len + 2, to_sign, to_sign_len);
/* Write timers. */
- knot_tsig_wire_write_timers(msg + prev_digest_len + *msg_len, tmp_tsig);
+ knot_tsig_wire_write_timers(wire + prev_digest_len + to_sign_len + 2,
+ tmp_tsig);
+
+ dbg_tsig_detail("Previous digest: \n");
+ dbg_tsig_hex_detail(prev_digest, prev_digest_len);
+
+ dbg_tsig_detail("Timers: \n");
+ dbg_tsig_hex_detail(wire + prev_digest_len + *msg_len,
+ KNOT_TSIG_TIMERS_LENGTH);
- int ret = 0;
ret = knot_tsig_compute_digest(wire, wire_len,
digest_tmp, &digest_tmp_len, key);
+
+ /* No matter how the function did, this data is no longer needed. */
+ free(wire);
if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
*digest_len = 0;
return ret;
}
if (digest_tmp_len > *digest_len) {
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
*digest_len = 0;
return KNOT_ESPACE;
}
- free(wire);
-
/* Set the MAC. */
- tsig_rdata_set_mac(tmp_tsig, *digest_len, digest);
+ tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);
+
+ /* Set algorithm. */
+ tsig_rdata_set_alg(tmp_tsig, key->algorithm);
+
+ /* Set original id. */
+ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
+
+ /* Set TSIG error. */
+ tsig_rdata_set_tsig_error(tmp_tsig, 0);
+
+ /* Set other data. */
+ tsig_rdata_set_other_data(tmp_tsig, 0, NULL);
+
+ dbg_tsig_detail("Message max length: %zu, message length: %zu\n",
+ msg_max_len, *msg_len);
size_t tsig_wire_size = msg_max_len - *msg_len;
int rr_count = 0;
ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
&tsig_wire_size, &rr_count);
if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
*digest_len = 0;
return ret;
}
+ /* This should not happen, at least one rr has to be converted. */
+ if (rr_count == 0) {
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+ return KNOT_EBADARG;
+ }
+
knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
*msg_len += tsig_wire_size;
@@ -932,6 +778,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr,
const uint8_t *request_mac,
size_t request_mac_len,
const knot_key_t *tsig_key,
+ uint64_t prev_time_signed,
int use_times)
{
if (!tsig_rr || !wire || !tsig_key) {
@@ -939,7 +786,7 @@ static int knot_tsig_check_digest(const knot_rrset_t *tsig_rr,
}
/* Check time signed. */
- int ret = knot_tsig_check_time_signed(tsig_rr);
+ int ret = knot_tsig_check_time_signed(tsig_rr, prev_time_signed);
if (ret != KNOT_EOK) {
return ret;
}
@@ -1061,29 +908,140 @@ int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
const knot_key_t *tsig_key)
{
dbg_tsig_verb("tsig_server_check()\n");
- return knot_tsig_check_digest(tsig_rr, wire, size, NULL, 0, tsig_key, 0);
+ return knot_tsig_check_digest(tsig_rr, wire, size, NULL, 0, tsig_key,
+ 0, 0);
}
int knot_tsig_client_check(const knot_rrset_t *tsig_rr,
const uint8_t *wire, size_t size,
const uint8_t *request_mac, size_t request_mac_len,
- const knot_key_t *tsig_key)
+ const knot_key_t *tsig_key,
+ uint64_t prev_time_signed)
{
dbg_tsig_verb("tsig_client_check()\n");
return knot_tsig_check_digest(tsig_rr, wire, size, request_mac,
- request_mac_len, tsig_key, 0);
+ request_mac_len, tsig_key,
+ prev_time_signed, 0);
}
int knot_tsig_client_check_next(const knot_rrset_t *tsig_rr,
const uint8_t *wire, size_t size,
const uint8_t *prev_digest,
size_t prev_digest_len,
- const knot_key_t *tsig_key)
+ const knot_key_t *tsig_key,
+ uint64_t prev_time_signed)
{
// return knot_tsig_client_check(tsig_rr, wire, size, prev_digest,
// prev_digest_len, tsig_key);
dbg_tsig_verb("tsig_client_check_next()\n");
return knot_tsig_check_digest(tsig_rr, wire, size, prev_digest,
- prev_digest_len, tsig_key, 1);
+ prev_digest_len, tsig_key,
+ prev_time_signed, 1);
return KNOT_ENOTSUP;
}
+
+int knot_tsig_add(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
+ uint16_t tsig_rcode, const knot_rrset_t *tsig_rr)
+{
+ /*! \todo Revise!! */
+
+ if (!msg || !msg_len || !tsig_rr) {
+ return KNOT_EBADARG;
+ }
+
+ /*! \todo What key to use, when we do not sign? Does this even work? */
+ knot_dname_t *key_name =
+ knot_dname_deep_copy(knot_rrset_owner(tsig_rr));
+ if (key_name == NULL) {
+ dbg_tsig_detail("TSIG: failed to copy owner\n");
+ return KNOT_ERROR;
+ }
+
+ knot_rrset_t *tmp_tsig =
+ knot_rrset_new(key_name,
+ KNOT_RRTYPE_TSIG, KNOT_CLASS_ANY, 0);
+ if (!tmp_tsig) {
+ dbg_tsig_detail("TSIG: tmp_tsig = NULL\n");
+ knot_dname_free(&key_name);
+ return KNOT_ENOMEM;
+ }
+
+ /* Create rdata for TSIG RR. */
+ knot_rdata_t *rdata = knot_rdata_new();
+ if (!rdata) {
+ dbg_tsig_detail("TSIG: rdata = NULL\n");
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_add_rdata(tmp_tsig, rdata);
+
+ /* Create items for TSIG RR. */
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(KNOT_RRTYPE_TSIG);
+ assert(desc);
+
+ knot_rdata_item_t *items =
+ malloc(sizeof(knot_rdata_item_t) * desc->length);
+ if (!items) {
+ dbg_tsig_detail("TSIG: items = NULL\n");
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+ return KNOT_ENOMEM;
+ }
+
+ memset(items, 0, sizeof(knot_rdata_item_t) * desc->length);
+
+ int ret = knot_rdata_set_items(rdata, items, desc->length);
+ if (ret != KNOT_EOK) {
+ dbg_tsig_detail("TSIG: rdata_set_items returned %s\n",
+ knot_strerror(ret));
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+ return ret;
+ }
+ free(items);
+
+ knot_dname_t *alg_name =
+ knot_dname_deep_copy(tsig_rdata_alg_name(tsig_rr));
+ if (alg_name == NULL) {
+ dbg_tsig_detail("TSIG: failed to copy alg name\n");
+ return KNOT_ERROR;
+ }
+
+ tsig_rdata_set_alg_name(tmp_tsig, alg_name);
+ tsig_rdata_set_time_signed(tmp_tsig, tsig_rdata_time_signed(tsig_rr));
+ tsig_rdata_set_fudge(tmp_tsig, tsig_rdata_fudge(tsig_rr));
+ tsig_rdata_set_mac(tmp_tsig, 0, NULL);
+
+ /* Set original ID */
+ tsig_rdata_set_orig_id(tmp_tsig, knot_wire_get_id(msg));
+
+ /* Set error */
+ tsig_rdata_set_tsig_error(tmp_tsig, tsig_rcode);
+
+ assert(tsig_rcode != KNOT_TSIG_RCODE_BADTIME);
+ /* Set other len. */
+ tsig_rdata_set_other_data(tmp_tsig, 0, 0);
+
+ size_t tsig_wire_len = msg_max_len - *msg_len;
+ int rr_count = 0;
+
+ /* Write RRSet to wire */
+ ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
+ &tsig_wire_len, &rr_count);
+ if (ret != KNOT_EOK) {
+ dbg_tsig_detail("TSIG: rrset_to_wire = %s\n", knot_strerror(ret));
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+ return ret;
+ }
+
+ knot_rrset_deep_free(&tmp_tsig, 1, 1, 1);
+
+ *msg_len += tsig_wire_len;
+
+ uint16_t arcount = knot_wire_get_arcount(msg);
+ knot_wire_set_arcount(msg, ++arcount);
+
+ return KNOT_EOK;
+}
+