Commit ced42fc0 authored by Lubos Slovak's avatar Lubos Slovak

Changed TSIG signing API

refs #1360 @1.5h
parent 32b78edf
......@@ -1990,46 +1990,35 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig)
int res = 0;
size_t digest_real_size = xfr->digest_max_size;
/*! \note [TSIG] Generate TSIG if required (during XFR/IN). */
if (xfr->prev_digest_size > 0 && add_tsig) {
if (xfr->tsig_key && add_tsig) {
if (xfr->packet_nr == 0) {
/* Add key, digest and digest length. */
assert(0);
res = knot_tsig_sign(xfr->wire, &real_size,
xfr->wire_size, xfr->prev_digest,
xfr->prev_digest_size,
xfr->wire_size, xfr->digest,
xfr->digest_size, xfr->digest,
&digest_real_size,
xfr->tsig_key);
} else {
/* Add key, digest and digest length. */
assert(0);
res = knot_tsig_sign_next(xfr->wire, &real_size,
xfr->wire_size,
xfr->prev_digest,
xfr->prev_digest_size,
xfr->digest,
xfr->digest_size,
xfr->digest,
&digest_real_size,
xfr->tsig_key);
}
if (res != KNOT_EOK) {
return res;
}
// save the new previous digest
// Extract the digest from the TSIG RDATA and store it.
xfr->prev_digest = (uint8_t*)tsig_rdata_mac(xfr->tsig);
// the size should still be the same
/*! \todo [TSIG] Enable assert when API is complete. */
// assert(xfr->prev_digest_size ==
// tsig_alg_digest_length(tsig_rdata_alg(tsig)));
}
/*! \note [TSIG] Sign with TSIG if in XFR/OUT and TSIG was in query. */
if (add_tsig && xfr->tsig_key &&
(xfr->type == XFR_TYPE_AOUT || xfr->type == XFR_TYPE_IOUT)) {
res = knot_tsig_sign(xfr->wire, &real_size,
xfr->wire_size,
(const uint8_t *)tsig_rdata_mac(xfr->tsig),
tsig_alg_digest_length(tsig_rdata_alg(xfr->tsig)),
xfr->tsig_key);
assert(digest_real_size > 0);
// save the new previous digest size
xfr->digest_size = digest_real_size;
}
// Send the response
......@@ -2051,7 +2040,7 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig)
// increment the packet number
++xfr->packet_nr;
if (xfr->prev_digest_size > 0 && add_tsig) {
if (xfr->tsig_key && add_tsig) {
knot_packet_set_tsig_size(xfr->response, xfr->tsig_size);
} else {
knot_packet_set_tsig_size(xfr->response, 0);
......@@ -2993,9 +2982,8 @@ int knot_ns_answer_axfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
*/
/*! \todo [TSIG] Get the TSIG size from some API function. */
if (xfr->tsig != NULL) {
size_t tsig_size = 0;
knot_packet_set_tsig_size(xfr->response, tsig_size);
if (xfr->tsig_size > 0) {
knot_packet_set_tsig_size(xfr->response, xfr->tsig_size);
}
ret = ns_axfr_from_zone(contents, xfr);
......@@ -3056,9 +3044,8 @@ int knot_ns_answer_ixfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr)
*/
/*! \todo [TSIG] Get the TSIG size from some API function. */
if (xfr->tsig != NULL) {
size_t tsig_size = 0;
knot_packet_set_tsig_size(xfr->response, tsig_size);
if (xfr->tsig_size > 0) {
knot_packet_set_tsig_size(xfr->response, xfr->tsig_size);
}
ret = ns_ixfr(xfr);
......
......@@ -11,6 +11,9 @@
#include "util/error.h"
#include "util/debug.h"
const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest
static int knot_tsig_check_algorithm(const knot_rrset_t *tsig_rr)
{
const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr);
......@@ -50,33 +53,29 @@ static int knot_tsig_check_key(const knot_rrset_t *tsig_rr,
return KNOT_EOK;
}
static int knot_tsig_compute_digest(const knot_rrset_t *tsig_rr,
const uint8_t *wire, size_t wire_len,
uint8_t **digest, size_t *digest_len,
static int knot_tsig_compute_digest(const uint8_t *wire, size_t wire_len,
uint8_t *digest, size_t *digest_len,
const knot_key_t *key)
{
if (!tsig_rr || !wire || !digest || !digest_len || !key) {
if (!wire || !digest || !digest_len || !key) {
return KNOT_EBADARG;
}
/* Get the algorithm. */
const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr);
if (!alg_name) {
if (!key->name) {
return KNOT_EMALF;
}
tsig_algorithm_t tsig_alg = tsig_alg_from_name(alg_name);
tsig_algorithm_t tsig_alg = tsig_alg_from_name(key->name);
if (tsig_alg == 0) {
return KNOT_TSIG_EBADSIG;
}
/* Create digest, using length of the algorithm. */
*digest =
malloc(sizeof(uint8_t) * tsig_alg_digest_length(tsig_alg));
if (!digest) {
ERR_ALLOC_FAILED;
return KNOT_ENOMEM;
}
// *digest = malloc(sizeof(uint8_t) * tsig_alg_digest_length(tsig_alg));
// if (!digest) {
// ERR_ALLOC_FAILED;
// return KNOT_ENOMEM;
// }
/* Compute digest. */
HMAC_CTX ctx;
......@@ -91,7 +90,7 @@ static int knot_tsig_compute_digest(const knot_rrset_t *tsig_rr,
} /* switch */
HMAC_Update(&ctx, wire, wire_len);
HMAC_Final(&ctx, *digest, digest_len);
HMAC_Final(&ctx, digest, digest_len);
return KNOT_EOK;
}
......@@ -203,12 +202,15 @@ static int knot_tsig_wire_write_timers(uint8_t *wire,
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)
uint8_t *digest, size_t *digest_len,
const knot_key_t *key)
{
if (!msg || !msg_len || !key) {
if (!msg || !msg_len || !key || digest == NULL || digest_len == NULL) {
return KNOT_EBADARG;
}
uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
size_t digest_tmp_len = 0;
/* Create tmp TSIG. */
int ret = KNOT_EOK;
......@@ -247,20 +249,29 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
}
/* Compute digest. */
ret = knot_tsig_compute_digest(tsig_rr, wire, wire_len,
digest, digest_len, key);
ret = knot_tsig_compute_digest(wire, wire_len,
digest_tmp, &digest_tmp_len, key);
if (ret != KNOT_EOK) {
*digest_len = 0;
return ret;
}
assert(digest_tmp_len > 0);
free(wire);
if (digest_tmp_len > *digest_len) {
*digest_len = 0;
return KNOT_ESPACE;
}
/* Set the digest. */
size_t tsig_wire_len = 0;
tsig_rdata_set_mac(tmp_tsig, *digest_len, *digest);
size_t tsig_wire_len = msg_max_len - *msg_len;
int rr_count = 0;
tsig_rdata_set_mac(tmp_tsig, digest_tmp_len, digest_tmp);
ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
msg_max_len - *msg_len, &tsig_wire_len);
&tsig_wire_len, &rr_count);
if (ret != KNOT_EOK) {
*digest_len = 0;
return ret;
}
......@@ -270,18 +281,25 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len,
uint16_t arcount = knot_wire_get_arcount(msg);
knot_wire_set_arcount(msg, ++arcount);
// everything went ok, save the digest to the output parameter
memcpy(digest, digest_tmp, digest_tmp_len);
*digest_len = digest_tmp_len;
return KNOT_EOK;
}
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,
uint8_t *digest, size_t *digest_len,
const knot_key_t *key)
{
if (!msg || !msg_len || !key || !key) {
if (!msg || !msg_len || !key || !key || !digest || !digest_len) {
return KNOT_EBADARG;
}
uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
size_t digest_tmp_len = 0;
/* Create tmp TSIG. */
knot_rrset_t *tmp_tsig =
......@@ -309,21 +327,29 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
knot_tsig_wire_write_timers(msg + prev_digest_len + *msg_len, tmp_tsig);
int ret = 0;
ret = knot_tsig_compute_digest(tmp_tsig, wire, wire_len,
digest, digest_len, key);
ret = knot_tsig_compute_digest(wire, wire_len,
digest_tmp, &digest_tmp_len, key);
if (ret != KNOT_EOK) {
*digest_len = 0;
return ret;
}
if (digest_tmp_len > *digest_len) {
*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_len, digest);
size_t tsig_wire_size = 0;
size_t tsig_wire_size = msg_max_len - *msg_len;
int rr_count = 0;
ret = knot_rrset_to_wire(tmp_tsig, msg + *msg_len,
msg_max_len - *msg_len, &tsig_wire_size);
&tsig_wire_size, &rr_count);
if (ret != KNOT_EOK) {
*digest_len = 0;
return ret;
}
......@@ -332,6 +358,9 @@ int knot_tsig_sign_next(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
*msg_len += tsig_wire_size;
uint16_t arcount = knot_wire_get_arcount(msg);
knot_wire_set_arcount(msg, ++arcount);
memcpy(digest, digest_tmp, digest_tmp_len);
*digest_len = digest_tmp_len;
return KNOT_EOK;
}
......@@ -366,21 +395,22 @@ int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
/* Calculate the size of TSIG RR. */
size_t tsig_len = tsig_rdata_tsig_variables_length(tsig_rr);
/* TSIG variables do NOT contain MAC and its size. */
const uint16_t *tsig_mac = tsig_rdata_mac(tsig_rr);
const uint8_t *tsig_mac = tsig_rdata_mac(tsig_rr);
if (!tsig_mac) {
return KNOT_EMALF;
}
tsig_len += sizeof(uint16_t);
tsig_len += tsig_mac[0];
uint16_t mac_length = tsig_rdata_mac_length(tsig_rr);
tsig_len += mac_length;
/* Strip the TSIG. */
size -= tsig_len;
uint8_t *digest = NULL;
size_t digest_len = 0;
ret = knot_tsig_compute_digest(tsig_rr, wire, size, &digest,
&digest_len, tsig_key);
uint8_t digest_tmp[KNOT_TSIG_MAX_DIGEST_SIZE];
size_t digest_tmp_len = 0;
ret = knot_tsig_compute_digest(wire, size, digest_tmp,
&digest_tmp_len, tsig_key);
if (ret != KNOT_EOK) {
return ret;
}
......@@ -391,15 +421,16 @@ int knot_tsig_server_check(const knot_rrset_t *tsig_rr,
const knot_dname_t *alg_name = tsig_rdata_alg_name(tsig_rr);
tsig_algorithm_t alg = tsig_alg_from_name(alg_name);
uint16_t mac_length = tsig_mac[0];
/*! \todo [TSIG] TRUNCATION */
if (mac_length != tsig_alg_digest_length(alg)) {
return KNOT_TSIG_EBADSIG;
}
assert(tsig_alg_digest_length(alg) == mac_length);
// assert(tsig_alg_digest_length(alg) == mac_length);
if (strncasecmp((char *)(tsig_mac + 1), (char *)digest,
tsig_alg_digest_length(alg)) != 0) {
if (strncasecmp((char *)(tsig_mac + 1), (char *)digest_tmp,
mac_length) != 0) {
return KNOT_TSIG_EBADSIG;
}
......
......@@ -40,11 +40,17 @@
* the resulting TSIG RR to the message wire format and accordingly adjusts
* the message size.
*
* \note This function does not save the new digest to the 'digest' parameter
* unless everything went OK. This allows to sent the same buffer to
* the 'request_mac' and 'digest' parameters.
*
* \param msg Message to be signed.
* \param msg_len Size of the message in bytes.
* \param msg_max_len Maximum size of the message in bytes.
* \param request_mac Request MAC. (may be NULL).
* \param request_mac_len Size of the request MAC in bytes.
* \param digest Buffer to save the digest in.
* \param digest_len In: size of the buffer. Out: real size of the digest saved.
* \param tsig_rr RRSet containing the TSIG RR to be used. Data from the RR are
* appended to the signed message.
*
......@@ -56,7 +62,7 @@
*/
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,
uint8_t *digest, size_t *digest_len,
const knot_key_t *key);
/*!
......@@ -67,11 +73,17 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_len,
* the resulting TSIG RR to the message wire format and accordingly adjusts
* the message size.
*
* \note This function does not save the new digest to the 'digest' parameter
* unless everything went OK. This allows to sent the same buffer to
* the 'request_mac' and 'digest' parameters.
*
* \param msg Message to be signed.
* \param msg_len Size of the message in bytes.
* \param msg_max_len Maximum size of the message in bytes.
* \param prev_digest Previous digest sent by the server in the session.
* \param prev_digest_len Size of the previous digest in bytes.
* \param digest Buffer to save the digest in.
* \param digest_len In: size of the buffer. Out: real size of the digest saved.
* \param tsig_rr RRSet containing the TSIG RR to be used. Data from the RR are
* appended to the signed message.
*
......@@ -83,8 +95,8 @@ int knot_tsig_sign(uint8_t *msg, size_t *msg_len, size_t msg_max_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);
uint8_t *digest, size_t *digest_len,
const knot_key_t *key);
/*!
* \brief Checks incoming request.
......
......@@ -331,21 +331,21 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr,
return ret;
}
if (xfr->prev_digest_size > 0) {
if (xfr->tsig_key) {
if (tsig_req && tsig == NULL) {
// TSIG missing!!
return KNOT_EMALF;
} else if (tsig != NULL) {
// TSIG there, either required or not, process
if (xfr->packet_nr == 0) {
ret = knot_tsig_client_check(xfr->tsig,
ret = knot_tsig_client_check(tsig,
xfr->wire, xfr->wire_size,
xfr->prev_digest, xfr->prev_digest_size,
xfr->digest, xfr->digest_size,
NULL);
} else {
ret = knot_tsig_client_check_next(xfr->tsig,
ret = knot_tsig_client_check_next(tsig,
xfr->wire, xfr->wire_size,
xfr->prev_digest, xfr->prev_digest_size,
xfr->digest, xfr->digest_size,
NULL);
}
......@@ -360,11 +360,12 @@ static int xfrin_check_tsig(knot_packet_t *packet, knot_ns_xfr_t *xfr,
xfr->tsig_data_size = 0;
// Extract the digest from the TSIG RDATA and store it.
xfr->prev_digest = tsig_rdata_mac(tsig);
// the size should still be the same
/*! \todo [TSIG] Enable assert when API is complete. */
// assert(xfr->prev_digest_size ==
// tsig_alg_digest_length(tsig_rdata_alg(tsig)));
if (xfr->digest_max_size < tsig_rdata_mac_length(tsig)) {
return KNOT_ESPACE;
}
memcpy(xfr->digest, tsig_rdata_mac(tsig),
tsig_rdata_mac_length(tsig));
xfr->digest_size = tsig_rdata_mac_length(tsig);
} else { // TSIG not required and not there
// just append the wireformat to the TSIG data
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment