* @note At least one of the arguments must be non-null.
* @param input Input parameters.
* @param cc_out Buffer for computed client cookie.
+ * @param cc_len Size of buffre/written data.
* @return kr_ok() on success, error code else.
*/
static int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input,
- uint8_t cc_out[KNOT_OPT_COOKIE_CLNT])
+ uint8_t *cc_out, uint16_t *cc_len)
{
- if (!input || !cc_out) {
+ if (!input || !cc_out || !cc_len) {
return kr_error(EINVAL);
}
hash_val);
assert(KNOT_OPT_COOKIE_CLNT == sizeof(hash_val));
+ if (*cc_len < KNOT_OPT_COOKIE_CLNT) {
+ return kr_error(ENOSPC);
+ }
- memcpy(cc_out, &hash_val, KNOT_OPT_COOKIE_CLNT);
+ *cc_len = KNOT_OPT_COOKIE_CLNT;
+ memcpy(cc_out, &hash_val, *cc_len);
return kr_ok();
}
* @note At least one of the arguments must be non-null.
* @param input Input parameters.
* @param cc_out Buffer for computed client cookie.
+ * @param cc_len Size of buffre/written data.
* @return kr_ok() on success, error code else.
*/
static int kr_clnt_cookie_alg_hmac_sha256_64(const struct kr_clnt_cookie_input *input,
- uint8_t cc_out[KNOT_OPT_COOKIE_CLNT])
+ uint8_t *cc_out, uint16_t *cc_len)
{
- if (!input || !cc_out) {
+ if (!input || !cc_out || !cc_len) {
return kr_error(EINVAL);
}
}
assert(KNOT_OPT_COOKIE_CLNT <= SHA256_DIGEST_LENGTH);
+ if (*cc_len < KNOT_OPT_COOKIE_CLNT) {
+ return kr_error(ENOSPC);
+ }
- memcpy(cc_out, digest, KNOT_OPT_COOKIE_CLNT);
+ *cc_len = KNOT_OPT_COOKIE_CLNT;
+ memcpy(cc_out, digest, *cc_len);
ret = kr_ok();
fail:
return kr_ok();
}
-int kr_clnt_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
+int kr_clnt_cookie_check(const uint8_t *cc, uint16_t cc_len,
const struct kr_clnt_cookie_input *input,
const struct kr_clnt_cookie_alg_descr *cc_alg)
{
- if (!cc || !input || !cc_alg || !cc_alg->func) {
+ if (!cc || !cc_len || !input || !cc_alg || !cc_alg->func) {
return kr_error(EINVAL);
}
uint8_t generated_cc[KNOT_OPT_COOKIE_CLNT] = {0, };
+ uint16_t generated_cc_len = KNOT_OPT_COOKIE_CLNT;
- int ret = cc_alg->func(input, generated_cc);
+ int ret = cc_alg->func(input, generated_cc, &generated_cc_len);
if (ret != kr_ok()) {
return ret;
}
- ret = memcmp(cc, generated_cc, KNOT_OPT_COOKIE_CLNT);
+ if (generated_cc_len != cc_len) {
+ return kr_error(EINVAL);
+ }
+
+ ret = memcmp(cc, generated_cc, generated_cc_len);
if (ret == 0) {
return kr_ok();
}
* @brief Client cookie generator function type.
* @param input Data which to generate the cookie from.
* @param cc_out Buffer to write the resulting client cookie data into.
+ * @param cc_len Set to length of buffer. After successful return contains size of client cookie.
* @return kr_ok() or error code
*/
typedef int (clnt_cookie_alg_t)(const struct kr_clnt_cookie_input *input,
- uint8_t *cc_out);
+ uint8_t *cc_out, uint16_t *cc_len);
/** Holds description of client cookie hashing algorithms. */
struct kr_clnt_cookie_alg_descr {
* @brief Check whether supplied client cookie was generated from given client
* secret and address.
* @param cc Client cookie that should be checked.
+ * @param cc_len Client cookie size.
* @param input Input cookie algorithm parameters.
* @param cc_alg Client cookie algorithm.
* @return kr_ok() or error code
*/
KR_EXPORT
-int kr_clnt_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
+int kr_clnt_cookie_check(const uint8_t *cc, uint16_t cc_len,
const struct kr_clnt_cookie_input *input,
const struct kr_clnt_cookie_alg_descr *cc_alg);
* @note Server cookie = FNV-64( client IP | client cookie | server secret )
*/
static int kr_srvr_cookie_alg_fnv64_simple(const struct kr_srvr_cookie_input *input,
- uint8_t sc_out[KNOT_OPT_COOKIE_SRVR_MAX],
- size_t *sc_size)
+ uint8_t *sc_out, uint16_t *sc_len)
{
if (!input || !sc_out ||
- !sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
+ !sc_len || (*sc_len < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
return kr_error(EINVAL);
}
- if (!input->clnt_cookie || !input->srvr_data ||
+ if (!input->clnt_cookie || !input->clnt_cookie_len ||
+ !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
}
hash_val = fnv_64a_buf((void *) input->clnt_cookie,
- KNOT_OPT_COOKIE_CLNT, hash_val);
+ input->clnt_cookie_len, hash_val);
hash_val = fnv_64a_buf((void *) input->srvr_data->secret_data,
input->srvr_data->secret_len, hash_val);
memcpy(sc_out, &hash_val, sizeof(hash_val));
- *sc_size = sizeof(hash_val);
- assert(SRVR_FNV64_SIMPLE_HASH_SIZE == *sc_size);
+ *sc_len = sizeof(hash_val);
+ assert(SRVR_FNV64_SIMPLE_HASH_SIZE == *sc_len);
return kr_ok();
}
* @note Server cookie = nonce | time | FNV-64( client IP | nonce| time | client cookie | server secret )
*/
static int kr_srvr_cookie_alg_fnv64(const struct kr_srvr_cookie_input *input,
- uint8_t sc_out[KNOT_OPT_COOKIE_SRVR_MAX],
- size_t *sc_size)
+ uint8_t *sc_out, uint16_t *sc_len)
{
if (!input || !sc_out ||
- !sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
+ !sc_len || (*sc_len < SRVR_FNV64_SIZE)) {
return kr_error(EINVAL);
}
- if (!input->clnt_cookie || !input->srvr_data ||
+ if (!input->clnt_cookie || !input->clnt_cookie_len ||
+ !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
hash_val);
hash_val = fnv_64a_buf((void *) input->clnt_cookie,
- KNOT_OPT_COOKIE_CLNT, hash_val);
+ input->clnt_cookie_len, hash_val);
hash_val = fnv_64a_buf((void *) input->srvr_data->secret_data,
input->srvr_data->secret_len, hash_val);
memcpy(sc_out + sizeof(aux), &aux, sizeof(aux));
memcpy(sc_out + (2 * sizeof(aux)), &hash_val, sizeof(hash_val));
- *sc_size = (2 * sizeof(aux)) + sizeof(hash_val);
- assert(SRVR_FNV64_SIZE == *sc_size);
+ *sc_len = (2 * sizeof(aux)) + sizeof(hash_val);
+ assert(SRVR_FNV64_SIZE == *sc_len);
return kr_ok();
}
* @note Server cookie = HMAC-SHA256-64( server secret, client cookie | client IP )
*/
static int kr_srvr_cookie_alg_hmac_sha256_64_simple(const struct kr_srvr_cookie_input *input,
- uint8_t sc_out[KNOT_OPT_COOKIE_SRVR_MAX],
- size_t *sc_size)
+ uint8_t *sc_out,
+ uint16_t *sc_len)
{
if (!input || !sc_out ||
- !sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
+ !sc_len || (*sc_len < SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE)) {
return kr_error(EINVAL);
}
- if (!input->clnt_cookie || !input->srvr_data ||
+ if (!input->clnt_cookie || !input->clnt_cookie_len ||
+ !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
goto fail;
}
- ret = HMAC_Update(&ctx, input->clnt_cookie, KNOT_OPT_COOKIE_CLNT);
+ ret = HMAC_Update(&ctx, input->clnt_cookie, input->clnt_cookie_len);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
assert(SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE <= SHA256_DIGEST_LENGTH);
memcpy(sc_out, digest, SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE);
- *sc_size = SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE;
+ *sc_len = SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE;
ret = kr_ok();
* @note Server cookie = nonce | time | HMAC-SHA256-64( server secret, client cookie | nonce| time | client IP )
*/
static int kr_srvr_cookie_alg_hmac_sha256_64(const struct kr_srvr_cookie_input *input,
- uint8_t sc_out[KNOT_OPT_COOKIE_SRVR_MAX],
- size_t *sc_size)
+ uint8_t *sc_out, uint16_t *sc_len)
{
if (!input || !sc_out ||
- !sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
+ !sc_len || (*sc_len < SRVR_HMAC_SHA256_64_SIZE)) {
return kr_error(EINVAL);
}
- if (!input->clnt_cookie || !input->srvr_data ||
+ if (!input->clnt_cookie || !input->clnt_cookie_len ||
+ !input->srvr_data ||
!input->srvr_data->secret_data || !input->srvr_data->secret_len) {
return kr_error(EINVAL);
}
goto fail;
}
- ret = HMAC_Update(&ctx, input->clnt_cookie, KNOT_OPT_COOKIE_CLNT);
+ ret = HMAC_Update(&ctx, input->clnt_cookie, input->clnt_cookie_len);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
memcpy(sc_out + (2 * sizeof(aux)), digest,
SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE);
- *sc_size = (2 * sizeof(aux)) + SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE;
- assert(SRVR_HMAC_SHA256_64_SIZE == *sc_size);
+ *sc_len = (2 * sizeof(aux)) + SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE;
+ assert(SRVR_HMAC_SHA256_64_SIZE == *sc_len);
ret = kr_ok();
return NULL;
}
-int kr_srvr_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
+int kr_srvr_cookie_check(const uint8_t *cc, uint16_t cc_len,
const uint8_t *sc, uint16_t sc_len,
const struct kr_srvr_cookie_check_ctx *check_ctx,
const struct kr_srvr_cookie_alg_descr *sc_alg)
}
uint8_t generated_sc[KNOT_OPT_COOKIE_SRVR_MAX] = { 0, };
- size_t generated_sc_len = KNOT_OPT_COOKIE_SRVR_MAX;
+ uint16_t generated_sc_len = KNOT_OPT_COOKIE_SRVR_MAX;
struct kr_srvr_cookie_input sc_input = {
.clnt_cookie = cc,
+ .clnt_cookie_len = cc_len,
.nonce = inbound_sc.nonce,
.time = inbound_sc.time,
.srvr_data = check_ctx
/** Server cookie creation context. */
struct kr_srvr_cookie_input {
- const uint8_t *clnt_cookie; /**< Client cookie, must be `KNOT_OPT_COOKIE_CLNT` bytes long. */
+ const uint8_t *clnt_cookie; /**< Client cookie. */
+ uint16_t clnt_cookie_len; /**< Client cookie size. */
uint32_t nonce; /**< Some generated value. */
uint32_t time; /**< Cookie time stamp. */
const struct kr_srvr_cookie_check_ctx *srvr_data; /**< Data known to the server. */
struct kr_srvr_cookie_inbound *inbound);
/**
* @brief Server cookie generator function type.
- * @param input Data which to generate the cookie from.
- * @param sc_out Buffer to write the resulting client cookie data into.
- * @param sc_size On input must contain size of the buffer, on successful return contains size of actual written data.
+ * @param input Data which to generate the cookie from.
+ * @param sc_out Buffer to write the resulting client cookie data into.
+ * @param sc_len On input must contain size of the buffer, on successful return contains size of actual written data.
* @return kr_ok() or error code
*/
typedef int (srvr_cookie_gen_t)(const struct kr_srvr_cookie_input *input,
- uint8_t *sc_out, size_t *sc_size);
+ uint8_t *sc_out, uint16_t *sc_len);
/** Holds description of server cookie hashing algorithms. */
struct kr_srvr_cookie_alg_descr {
/**
* @brief Check whether supplied client and server cookie match.
* @param cc Client cookie.
+ * @param cc_len Client cookie length.
* @param sc Server cookie that should be checked.
* @param sc_len Server cookie length.
* @param check_ctx Data known to the server needed for cookie validation.
* @return kr_ok() if check OK, error code else.
*/
KR_EXPORT
-int kr_srvr_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
+int kr_srvr_cookie_check(const uint8_t *cc, uint16_t cc_len,
const uint8_t *sc, uint16_t sc_len,
const struct kr_srvr_cookie_check_ctx *check_ctx,
const struct kr_srvr_cookie_alg_descr *sc_alg);
};
static int opt_rr_add_cookies(knot_rrset_t *opt_rr,
- uint8_t cc[KNOT_OPT_COOKIE_CLNT],
+ uint8_t *cc, uint16_t cc_len,
uint8_t *sc, uint16_t sc_len,
knot_mm_t *mm)
{
uint16_t cookies_size = 0;
uint8_t *cookies_data = NULL;
- cookies_size = knot_edns_opt_cookie_data_len(sc_len);
+ cookies_size = knot_edns_opt_cookie_data_len(cc_len, sc_len);
int ret = knot_edns_reserve_option(opt_rr, KNOT_EDNS_OPTION_COOKIE,
cookies_size, &cookies_data, mm);
}
assert(cookies_data != NULL);
- ret = knot_edns_opt_cookie_create(cc, sc, sc_len,
- cookies_data, &cookies_size);
+ ret = knot_edns_opt_cookie_write(cc, cc_len, sc, sc_len,
+ cookies_data, &cookies_size);
if (ret != KNOT_EOK) {
return ret;
}
- assert(cookies_size == knot_edns_opt_cookie_data_len(sc_len));
+ assert(cookies_size == knot_edns_opt_cookie_data_len(cc_len, sc_len));
return KNOT_EOK;
}
*/
static const uint8_t *peek_and_check_cc(struct kr_cache *cache,
const void *sockaddr,
- const uint8_t cc[KNOT_OPT_COOKIE_CLNT])
+ const uint8_t *cc, uint16_t cc_len)
{
- assert(cache && sockaddr && cc);
+ assert(cache && sockaddr && cc && cc_len);
uint32_t timestamp = 0;
struct timed_cookie timed_cookie = { 0, };
const uint8_t *cached_cc = knot_edns_opt_get_data((uint8_t *) timed_cookie.cookie_opt);
- if (0 == memcmp(cc, cached_cc, KNOT_OPT_COOKIE_CLNT)) {
+ if (cc_len == KNOT_OPT_COOKIE_CLNT &&
+ 0 == memcmp(cc, cached_cc, cc_len)) {
return timed_cookie.cookie_opt;
}
.secret_len = clnt_cntrl->csec->size
};
uint8_t cc[KNOT_OPT_COOKIE_CLNT];
+ uint16_t cc_len = KNOT_OPT_COOKIE_CLNT;
assert(clnt_cntrl->calg && clnt_cntrl->calg->func);
- int ret = clnt_cntrl->calg->func(&input, cc);
+ int ret = clnt_cntrl->calg->func(&input, cc, &cc_len);
if (ret != kr_ok()) {
return ret;
}
+ assert(cc_len == KNOT_OPT_COOKIE_CLNT);
const uint8_t *cached_cookie = peek_and_check_cc(cookie_cache,
- srvr_sockaddr, cc);
+ srvr_sockaddr,
+ cc, cc_len);
/* This is a very nasty hack that prevents the packet to be corrupted
* when using contemporary 'Cookie interface'. */
ret = opt_rr_add_option(pkt->opt_rr, (uint8_t *) cached_cookie,
&pkt->mm);
} else {
- ret = opt_rr_add_cookies(pkt->opt_rr, cc, NULL, 0, &pkt->mm);
+ ret = opt_rr_add_cookies(pkt->opt_rr, cc, cc_len,
+ NULL, 0, &pkt->mm);
}
/* Write to packet. */
* Tries to guess the name server address from the reputation mechanism.
* @param nsrep name server reputation context
* @param cc client cookie data
+ * @param cc_len client cookie size
* @param csecr client secret
* @param cc_alg client cookie algorithm
* @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 uint8_t *cc, uint16_t cc_len,
const struct kr_cookie_secret *csecr,
const struct kr_clnt_cookie_alg_descr *cc_alg)
{
- assert(nsrep && cc && csecr && cc_alg);
+ assert(nsrep && cc && cc_len && csecr && cc_alg);
const struct sockaddr *sockaddr = NULL;
}
input.srvr_sockaddr = &nsrep->addr[i];
- int ret = kr_clnt_cookie_check(cc, &input, cc_alg);
+ int ret = kr_clnt_cookie_check(cc, cc_len, &input, cc_alg);
if (ret == kr_ok()) {
sockaddr = (struct sockaddr *) &nsrep->addr[i];
break;
* @param sockaddr pointer to socket address to be set
* @param is_current set to true if the cookie was generate from current secret
* @param cc client cookie from the response
+ * @param cc_len client cookie size
* @param clnt_cntr client 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,
- const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
+ const uint8_t *cc, uint16_t cc_len,
const struct kr_clnt_cookie_ctx *clnt_cntrl)
{
- assert(sockaddr && is_current && qry && cc && clnt_cntrl);
+ assert(sockaddr && is_current && qry && cc && cc_len && clnt_cntrl);
const struct sockaddr *tmp_sockaddr = passed_server_sockaddr(qry);
.secret_data = clnt_cntrl->current.csec->data,
.secret_len = clnt_cntrl->current.csec->size
};
- int ret = kr_clnt_cookie_check(cc, &input,
+ int ret = kr_clnt_cookie_check(cc, cc_len, &input,
clnt_cntrl->current.calg);
bool have_current = (ret == kr_ok());
if ((ret != kr_ok()) &&
clnt_cntrl->recent.csec && clnt_cntrl->recent.calg) {
input.secret_data = clnt_cntrl->recent.csec->data;
input.secret_len = clnt_cntrl->recent.csec->size;
- ret = kr_clnt_cookie_check(cc, &input,
+ ret = kr_clnt_cookie_check(cc, cc_len, &input,
clnt_cntrl->recent.calg);
}
if (ret == kr_ok()) {
/* Abusing name server reputation mechanism to guess IP addresses. */
const struct kr_nsrep *ns = &qry->ns;
- tmp_sockaddr = guess_server_addr(ns, cc, clnt_cntrl->current.csec,
+ tmp_sockaddr = guess_server_addr(ns, cc, cc_len,
+ clnt_cntrl->current.csec,
clnt_cntrl->current.calg);
bool have_current = (tmp_sockaddr != NULL);
if (!tmp_sockaddr &&
clnt_cntrl->recent.csec && clnt_cntrl->recent.calg) {
/* Try recent client secret to check obtained cookie. */
- tmp_sockaddr = guess_server_addr(ns, cc,
+ tmp_sockaddr = guess_server_addr(ns, cc, cc_len,
clnt_cntrl->recent.csec,
clnt_cntrl->recent.calg);
}
const struct sockaddr *srvr_sockaddr = NULL;
bool returned_current = false;
ret = srvr_sockaddr_cc_check(&srvr_sockaddr, &returned_current, qry,
- pkt_cc, clnt_cntrl);
+ pkt_cc, pkt_cc_len, clnt_cntrl);
if (ret != kr_ok()) {
DEBUG_MSG(NULL, "%s\n", "could not match received cookie");
return false;
{
assert(answer && input && alg);
- size_t cookie_size = KNOT_OPT_COOKIE_CLNT + alg->srvr_cookie_size;
+ size_t cookie_size = input->clnt_cookie_len + alg->srvr_cookie_size;
uint8_t *data = NULL;
if (!answer->opt_rr) {
return kr_error(ret);
}
- memcpy(data, input->clnt_cookie, KNOT_OPT_COOKIE_CLNT);
+ memcpy(data, input->clnt_cookie, input->clnt_cookie_len);
cookie_size = alg->srvr_cookie_size;
- ret = alg->gen_func(input, data + KNOT_OPT_COOKIE_CLNT, &cookie_size);
+ ret = alg->gen_func(input, data + input->clnt_cookie_len, &cookie_size);
if (ret != kr_ok()) {
/* TODO -- Delete COOKIE option. */
return ret;
.secret_len = srvr_cntrl->current.ssec->size
};
- ret = kr_srvr_cookie_check(req_cc, req_sc, req_sc_len, &check_ctx,
- srvr_cntrl->current.salg);
+ ret = kr_srvr_cookie_check(req_cc, req_cc_len, req_sc, req_sc_len,
+ &check_ctx, srvr_cntrl->current.salg);
if (ret == kr_error(EBADMSG) &&
srvr_cntrl->recent.ssec && srvr_cntrl->recent.salg) {
/* Try recent algorithm. */
.secret_data = srvr_cntrl->recent.ssec->data,
.secret_len = srvr_cntrl->recent.ssec->size
};
- ret = kr_srvr_cookie_check(req_cc, req_sc, req_sc_len,
- &recent_ctx,
+ ret = kr_srvr_cookie_check(req_cc, req_cc_len, req_sc,
+ req_sc_len, &recent_ctx,
srvr_cntrl->recent.salg);
}
if (ret != kr_ok()) {
/* Add server cookie into response. */
struct kr_srvr_cookie_input input = {
.clnt_cookie = req_cc,
+ .clnt_cookie_len = req_cc_len,
.nonce = 0, /*TODO -- Some pseudo-random value? */
.time = req->current_query->timestamp.tv_sec,
.srvr_data = &check_ctx