Skip to content
Snippets Groups Projects
Commit 639a486f authored by Karel Slaný's avatar Karel Slaný Committed by Ondřej Surý
Browse files

Started working on 'server' cookie code.

parent 9e7ae9fd
No related merge requests found
...@@ -24,84 +24,19 @@ ...@@ -24,84 +24,19 @@
#include <openssl/sha.h> #include <openssl/sha.h>
#include "contrib/fnv/fnv.h" #include "contrib/fnv/fnv.h"
#include "lib/cookies/algorithm.h" #include "lib/cookies/alg_clnt.h"
//#define CC_HASH_USE_CLIENT_ADDRESS /* When defined, client address will be used when generating client cookie. */ //#define CC_HASH_USE_CLIENT_ADDRESS /* When defined, client address will be used when generating client cookie. */
const struct kr_clnt_cookie_alg_descr kr_clnt_cookie_algs[] = { /**
{ kr_clnt_cookie_alg_fnv64, "FNV-64" }, * Compute client cookie using FNV-64.
{ kr_clnt_cookie_alg_hmac_sha256_64, "HMAC-SHA256-64" }, * @note At least one of the arguments must be non-null.
{ NULL, NULL } * @param input Input parameters.
}; * @param cc_out Buffer for computed client cookie.
* @return kr_ok() on success, error code else.
clnt_cookie_alg_t *kr_clnt_cookie_alg_func(const struct kr_clnt_cookie_alg_descr cc_algs[], */
const char *name) static int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input,
{ uint8_t cc_out[KNOT_OPT_COOKIE_CLNT])
if (!cc_algs || !name) {
return NULL;
}
const struct kr_clnt_cookie_alg_descr *aux_ptr = cc_algs;
while (aux_ptr && aux_ptr->func) {
assert(aux_ptr->name);
if (strcmp(aux_ptr->name, name) == 0) {
return aux_ptr->func;
}
++aux_ptr;
}
return NULL;
}
const char *kr_clnt_cookie_alg_name(const struct kr_clnt_cookie_alg_descr cc_algs[],
clnt_cookie_alg_t *func)
{
if (!cc_algs || !func) {
return NULL;
}
const struct kr_clnt_cookie_alg_descr *aux_ptr = cc_algs;
while (aux_ptr && aux_ptr->func) {
assert(aux_ptr->name);
if (aux_ptr->func == func) {
return aux_ptr->name;
}
++aux_ptr;
}
return NULL;
}
int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len)
{
if (!sockaddr || !addr || !len) {
return kr_error(EINVAL);
}
int addr_family = ((struct sockaddr *) sockaddr)->sa_family;
switch (addr_family) {
case AF_INET:
*addr = (uint8_t *) &((struct sockaddr_in *) sockaddr)->sin_addr;
*len = 4;
break;
case AF_INET6:
*addr = (uint8_t *) &((struct sockaddr_in6 *) sockaddr)->sin6_addr;
*len = 16;
break;
default:
*addr = NULL;
*len = 0;
addr_family = AF_UNSPEC;
return kr_error(EINVAL);
break;
}
return kr_ok();
}
int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input,
uint8_t cc_out[KNOT_OPT_COOKIE_CLNT])
{ {
if (!input || !cc_out) { if (!input || !cc_out) {
return kr_error(EINVAL); return kr_error(EINVAL);
...@@ -145,8 +80,15 @@ int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input, ...@@ -145,8 +80,15 @@ int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input,
return kr_ok(); return kr_ok();
} }
int kr_clnt_cookie_alg_hmac_sha256_64(const struct kr_clnt_cookie_input *input, /**
uint8_t cc_out[KNOT_OPT_COOKIE_CLNT]) * Compute client cookie using HMAC_SHA256-64.
* @note At least one of the arguments must be non-null.
* @param input Input parameters.
* @param cc_out Buffer for computed client cookie.
* @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])
{ {
if (!input || !cc_out) { if (!input || !cc_out) {
return kr_error(EINVAL); return kr_error(EINVAL);
...@@ -216,3 +158,79 @@ fail: ...@@ -216,3 +158,79 @@ fail:
HMAC_CTX_cleanup(&ctx); HMAC_CTX_cleanup(&ctx);
return ret; return ret;
} }
const struct kr_clnt_cookie_alg_descr kr_clnt_cookie_algs[] = {
{ "FNV-64", kr_clnt_cookie_alg_fnv64 },
{ "HMAC-SHA256-64", kr_clnt_cookie_alg_hmac_sha256_64 },
{ NULL, NULL }
};
const struct kr_clnt_cookie_alg_descr *kr_clnt_cookie_alg(const struct kr_clnt_cookie_alg_descr cc_algs[],
const char *name)
{
if (!cc_algs || !name) {
return NULL;
}
const struct kr_clnt_cookie_alg_descr *aux_ptr = cc_algs;
while (aux_ptr && aux_ptr->func) {
assert(aux_ptr->name);
if (strcmp(aux_ptr->name, name) == 0) {
return aux_ptr;
}
++aux_ptr;
}
return NULL;
}
int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len)
{
if (!sockaddr || !addr || !len) {
return kr_error(EINVAL);
}
int addr_family = ((struct sockaddr *) sockaddr)->sa_family;
switch (addr_family) {
case AF_INET:
*addr = (uint8_t *) &((struct sockaddr_in *) sockaddr)->sin_addr;
*len = 4;
break;
case AF_INET6:
*addr = (uint8_t *) &((struct sockaddr_in6 *) sockaddr)->sin6_addr;
*len = 16;
break;
default:
*addr = NULL;
*len = 0;
addr_family = AF_UNSPEC;
return kr_error(EINVAL);
break;
}
return kr_ok();
}
int kr_clnt_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
const struct kr_clnt_cookie_input *input,
const struct kr_clnt_cookie_alg_descr *cc_alg)
{
if (!cc || !input || !cc_alg || !cc_alg->func) {
return kr_error(EINVAL);
}
uint8_t generated_cc[KNOT_OPT_COOKIE_CLNT] = {0, };
int ret = cc_alg->func(input, generated_cc);
if (ret != kr_ok()) {
return ret;
}
ret = memcmp(cc, generated_cc, KNOT_OPT_COOKIE_CLNT);
if (ret == 0) {
return kr_ok();
}
return kr_error(EINVAL);
}
...@@ -28,17 +28,22 @@ struct kr_clnt_cookie_input { ...@@ -28,17 +28,22 @@ struct kr_clnt_cookie_input {
const void *clnt_sockaddr; /**< Client (local) socket address. */ const void *clnt_sockaddr; /**< Client (local) socket address. */
const void *srvr_sockaddr; /**< Server (remote) socket address. */ const void *srvr_sockaddr; /**< Server (remote) socket address. */
const uint8_t *secret_data; /**< Client secret data. */ const uint8_t *secret_data; /**< Client secret data. */
size_t secret_len; size_t secret_len; /**< Secret data length. */
}; };
/** Client cookie algorithm type. */ /**
* @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.
* @return kr_ok() or error code
*/
typedef int (clnt_cookie_alg_t)(const struct kr_clnt_cookie_input *input, typedef int (clnt_cookie_alg_t)(const struct kr_clnt_cookie_input *input,
uint8_t *); uint8_t *cc_out);
/** Holds description of client cookie hashing algorithms. */ /** Holds description of client cookie hashing algorithms. */
struct kr_clnt_cookie_alg_descr { struct kr_clnt_cookie_alg_descr {
clnt_cookie_alg_t *func; /**< Pointer to has function. */
const char *name; /**< Hash function name. */ const char *name; /**< Hash function name. */
clnt_cookie_alg_t *func; /**< Pointer to hash function. */
}; };
/** /**
...@@ -50,27 +55,17 @@ KR_EXPORT ...@@ -50,27 +55,17 @@ KR_EXPORT
extern const struct kr_clnt_cookie_alg_descr kr_clnt_cookie_algs[]; extern const struct kr_clnt_cookie_alg_descr kr_clnt_cookie_algs[];
/** /**
* @brief Return pointer to client cookie hash function with given name. * @brief Return pointer to client cookie algorithm with given name.
* @param cc_algs List of available algorithms. * @param cc_algs List of available algorithms.
* @param name Algorithm name. * @param name Algorithm name.
* @return pointer to function or NULL if not found. * @return pointer to algorithm or NULL if not found.
*/
KR_EXPORT
clnt_cookie_alg_t *kr_clnt_cookie_alg_func(const struct kr_clnt_cookie_alg_descr cc_algs[],
const char *name);
/**
* @brief Return name of given client cookie hash function.
* @param cc_algs List of available algorithms.
* @param func Sought algorithm function.
* @return pointer to string or NULL if not found.
*/ */
KR_EXPORT KR_EXPORT
const char *kr_clnt_cookie_alg_name(const struct kr_clnt_cookie_alg_descr cc_algs[], const struct kr_clnt_cookie_alg_descr *kr_clnt_cookie_alg(const struct kr_clnt_cookie_alg_descr cc_algs[],
clnt_cookie_alg_t *func); const char *name);
/** /**
* Get pointers to IP address bytes. * @brief Get pointers to IP address bytes.
* @param sockaddr socket address * @param sockaddr socket address
* @param addr pointer to address * @param addr pointer to address
* @param len address length * @param len address length
...@@ -79,23 +74,14 @@ const char *kr_clnt_cookie_alg_name(const struct kr_clnt_cookie_alg_descr cc_alg ...@@ -79,23 +74,14 @@ const char *kr_clnt_cookie_alg_name(const struct kr_clnt_cookie_alg_descr cc_alg
int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len); int kr_address_bytes(const void *sockaddr, const uint8_t **addr, size_t *len);
/** /**
* Compute client cookie using FNV-64. * @brief Check whether supplied client cookie was generated from given client
* @note At least one of the arguments must be non-null. * secret and address.
* @param input Input parameters. * @param cc Client cookie that should be checked.
* @param cc_out Buffer for computed client cookie. * @param input Input cookie algorithm parameters.
* @return kr_ok() on success, error code else. * @param cc_alg Client cookie algorithm.
*/ * @return kr_ok() or error code
KR_EXPORT
int kr_clnt_cookie_alg_fnv64(const struct kr_clnt_cookie_input *input,
uint8_t cc_out[KNOT_OPT_COOKIE_CLNT]);
/**
* Compute client cookie using HMAC_SHA256-64.
* @note At least one of the arguments must be non-null.
* @param input Input parameters.
* @param cc_out Buffer for computed client cookie.
* @return kr_ok() on success, error code else.
*/ */
KR_EXPORT KR_EXPORT
int kr_clnt_cookie_alg_hmac_sha256_64(const struct kr_clnt_cookie_input *input, int kr_clnt_cookie_check(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT]); const struct kr_clnt_cookie_input *input,
const struct kr_clnt_cookie_alg_descr *cc_alg);
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <arpa/inet.h> /* ntohl(), ... */
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include "contrib/fnv/fnv.h"
#include "lib/cookies/alg_clnt.h" /* kr_address_bytes() */
#include "lib/cookies/alg_srvr.h"
/**
* @brief Server cookie contains only hash value.
* @note DNS Cookies -- Appendix B.1
*/
static int srvr_cookie_parse_simple(const uint8_t *cookie_data, uint16_t data_len,
struct kr_srvr_cookie_inbound *inbound)
{
if (!cookie_data || !inbound) {
return kr_error(EINVAL);
}
const uint8_t *cc = NULL, *sc = NULL;
uint16_t cc_len = 0, sc_len = 0;
int ret = knot_edns_opt_cookie_parse(cookie_data, data_len,
&cc, &cc_len, &sc, &sc_len);
if (ret != KNOT_EOK || !sc) {
kr_error(EINVAL); /* Server cookie missing. */
}
assert(cc_len == KNOT_OPT_COOKIE_CLNT);
//memset(inbound, 0, sizeof(*inbound));
inbound->clnt_cookie = cc;
inbound->hash_data = sc; /* Entire server cookie contains data. */
inbound->hash_len = sc_len;
return kr_ok();
}
/**
* @brief Server cookie contains also additional values.
* @note DNS Cookies -- Appendix B.2
*/
static int srvr_cookie_parse(const uint8_t *cookie_data, uint16_t data_len,
struct kr_srvr_cookie_inbound *inbound)
{
if (!cookie_data || !inbound) {
return kr_error(EINVAL);
}
const uint8_t *cc = NULL, *sc = NULL;
uint16_t cc_len = 0, sc_len = 0;
int ret = knot_edns_opt_cookie_parse(cookie_data, data_len,
&cc, &cc_len, &sc, &sc_len);
if (ret != KNOT_EOK || !sc) {
kr_error(EINVAL); /* Server cookie missing. */
}
assert(cc_len == KNOT_OPT_COOKIE_CLNT);
if (sc_len <= (2 * sizeof(uint32_t))) { /* nonce + time */
return kr_error(EINVAL);
}
uint32_t aux;
inbound->clnt_cookie = cc;
memcpy(&aux, sc, sizeof(aux));
inbound->nonce = ntohl(aux);
memcpy(&aux, sc + sizeof(aux), sizeof(aux));
inbound->time = ntohl(aux);
inbound->hash_data = sc + (2 * sizeof(aux));
inbound->hash_len = sc_len - (2 * sizeof(aux));
return kr_ok();
}
#define SRVR_FNV64_SIMPLE_HASH_SIZE 8
/**
* @brief Compute server cookie using FNV-64 (hash only).
* @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)
{
if (!input || !sc_out ||
!sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
return kr_error(EINVAL);
}
const uint8_t *addr = NULL;
size_t alen = 0; /* Address length. */
Fnv64_t hash_val = FNV1A_64_INIT;
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr, &addr,
&alen)) {
assert(addr && alen);
hash_val = fnv_64a_buf((void *) addr, alen, hash_val);
}
hash_val = fnv_64a_buf((void *) input->clnt_cookie,
KNOT_OPT_COOKIE_CLNT, 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);
return kr_ok();
}
#define SRVR_FNV64_SIZE 16
/**
* @brief Compute server cookie using FNV-64.
* @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)
{
if (!input || !sc_out ||
!sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
return kr_error(EINVAL);
}
const uint8_t *addr = NULL;
size_t alen = 0; /* Address length. */
Fnv64_t hash_val = FNV1A_64_INIT;
if (input->srvr_data.clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr,
&addr, &alen)) {
assert(addr && alen);
hash_val = fnv_64a_buf((void *) addr, alen, hash_val);
}
}
hash_val = fnv_64a_buf((void *) &input->nonce, sizeof(input->nonce),
hash_val);
hash_val = fnv_64a_buf((void *) &input->time, sizeof(input->time),
hash_val);
hash_val = fnv_64a_buf((void *) input->clnt_cookie,
KNOT_OPT_COOKIE_CLNT, hash_val);
hash_val = fnv_64a_buf((void *) input->srvr_data.secret_data,
input->srvr_data.secret_len, hash_val);
uint32_t aux = htonl(input->nonce);
memcpy(sc_out, &aux, sizeof(aux));
aux = htonl(input->time);
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);
return kr_ok();
}
#define SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE 8
/**
* @brief Compute server cookie using HMAC-SHA256-64 (hash only).
* @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)
{
if (!input || !sc_out ||
!sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
return kr_error(EINVAL);
}
const uint8_t *addr = NULL;
size_t alen = 0; /* Address length. */
uint8_t digest[SHA256_DIGEST_LENGTH];
unsigned int digest_len = SHA256_DIGEST_LENGTH;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
int ret = HMAC_Init_ex(&ctx, input->srvr_data.secret_data,
input->srvr_data.secret_len,
EVP_sha256(), NULL);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
ret = HMAC_Update(&ctx, input->clnt_cookie, KNOT_OPT_COOKIE_CLNT);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
if (input->srvr_data.clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr,
&addr, &alen)) {
assert(addr && alen);
ret = HMAC_Update(&ctx, addr, alen);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
}
}
if (1 != HMAC_Final(&ctx, digest, &digest_len)) {
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;
ret = kr_ok();
fail:
HMAC_CTX_cleanup(&ctx);
return ret;
}
#define SRVR_HMAC_SHA256_64_SIZE 16
/**
* @brief Compute server cookie using HMAC-SHA256-64).
* @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)
{
if (!input || !sc_out ||
!sc_size || (*sc_size < SRVR_FNV64_SIMPLE_HASH_SIZE)) {
return kr_error(EINVAL);
}
if (!input->clnt_cookie ||
!input->srvr_data.secret_data || !input->srvr_data.secret_len) {
return kr_error(EINVAL);
}
const uint8_t *addr = NULL;
size_t alen = 0; /* Address length. */
uint8_t digest[SHA256_DIGEST_LENGTH];
unsigned int digest_len = SHA256_DIGEST_LENGTH;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
int ret = HMAC_Init_ex(&ctx, input->srvr_data.secret_data,
input->srvr_data.secret_len,
EVP_sha256(), NULL);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
ret = HMAC_Update(&ctx, input->clnt_cookie, KNOT_OPT_COOKIE_CLNT);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
ret = HMAC_Update(&ctx, (void *) &input->nonce, sizeof(input->nonce));
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
ret = HMAC_Update(&ctx, (void *) &input->time, sizeof(input->time));
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
if (input->srvr_data.clnt_sockaddr) {
if (kr_ok() == kr_address_bytes(input->srvr_data.clnt_sockaddr,
&addr, &alen)) {
assert(addr && alen);
ret = HMAC_Update(&ctx, addr, alen);
if (ret != 1) {
ret = kr_error(EINVAL);
goto fail;
}
}
}
if (1 != HMAC_Final(&ctx, digest, &digest_len)) {
ret = kr_error(EINVAL);
goto fail;
}
uint32_t aux = htonl(input->nonce);
memcpy(sc_out, &aux, sizeof(aux));
aux = htonl(input->time);
memcpy(sc_out + sizeof(aux), &aux, sizeof(aux));
assert(SRVR_HMAC_SHA256_64_SIMPLE_HASH_SIZE <= SHA256_DIGEST_LENGTH);
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);
ret = kr_ok();
fail:
HMAC_CTX_cleanup(&ctx);
return ret;
}
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <libknot/rrtype/opt_cookie.h>
#include "lib/defines.h"
/** Inbound server cookie checking context. */
struct kr_srvr_cookie_check_ctx {
const void *clnt_sockaddr; /**< Client (remote) socket address. */
const uint8_t *secret_data; /**< Server secret data. */
size_t secret_len; /**< Server secret data length. */
};
/** Inbound server cookie content structure. */
struct kr_srvr_cookie_inbound {
const uint8_t *clnt_cookie; /**< Client cookie, `KNOT_OPT_COOKIE_CLNT` bytes long. */
uint32_t nonce; /**< Some value. */
uint32_t time; /**< Time stamp. */
const uint8_t *hash_data; /**< Hash data. */
uint16_t hash_len; /**< Hash data length. */
};
/** Server cookie creation context. */
struct kr_srvr_cookie_input {
const uint8_t *clnt_cookie; /**< Client cookie, must be `KNOT_OPT_COOKIE_CLNT` bytes long. */
uint32_t nonce; /**< Some generated value. */
uint32_t time; /**< Cookie time stamp. */
struct kr_srvr_cookie_check_ctx srvr_data; /**< Data known to the server. */
};
/**
* @brief Server cookie parser function type.
* @param cookie_data Entire cookie option data (without option header).
* @param data_len Cookie data length.
* @param inbound Inbound cookie structure to be set.
* @return kr_ok() or error code.
*/
typedef int (srvr_cookie_parse_t)(const uint8_t *cookie_data, uint16_t data_len,
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.
* @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);
/** Holds description of server cookie hashing algorithms. */
struct kr_srvr_cookie_alg_descr {
const char *name; /** Server cookie algorithm name. */
const uint16_t srvr_cookie_size; /**< Size of the generated server cookie. */
const srvr_cookie_parse_t *opt_parse_func; /**< Cookie option parser function. */
const srvr_cookie_gen_t *gen_func; /*< Cookie generator function. */
};
/**
* List of available server cookie algorithms.
*
* Last element contains all null entries.
*/
KR_EXPORT
extern const struct kr_srvr_cookie_alg_descr kr_srvr_cookie_algs[];
/**
* @brief Check whether supplied client and server cookie match.
* @param cookie_opt Entire cookie option, must contain server cookie.
* @param check_ctx Data known to the server needed for cookie validation.
* @param sc_alg Server cookie algorithm.
* @return kr_ok() if check OK, error code else.
*/
KR_EXPORT
int kr_srvr_cookie_check(const uint8_t *cookie_opt,
const struct kr_srvr_cookie_check_ctx *check_ctx,
const struct kr_srvr_cookie_alg_descr *sc_alg);
...@@ -152,8 +152,8 @@ int kr_request_put_cookie(const struct kr_cookie_ctx *cntrl, ...@@ -152,8 +152,8 @@ int kr_request_put_cookie(const struct kr_cookie_ctx *cntrl,
.secret_len = cntrl->current_cs->size .secret_len = cntrl->current_cs->size
}; };
uint8_t cc[KNOT_OPT_COOKIE_CLNT]; uint8_t cc[KNOT_OPT_COOKIE_CLNT];
assert(cntrl->cc_alg_func); assert(cntrl->cc_alg && cntrl->cc_alg->func);
int ret = cntrl->cc_alg_func(&input, cc); int ret = cntrl->cc_alg->func(&input, cc);
if (ret != kr_ok()) { if (ret != kr_ok()) {
return ret; return ret;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <libknot/rrtype/opt_cookie.h> #include <libknot/rrtype/opt_cookie.h>
#include <stdbool.h> #include <stdbool.h>
#include "lib/cookies/algorithm.h" #include "lib/cookies/alg_clnt.h"
#include "lib/cache.h" #include "lib/cache.h"
#include "lib/defines.h" #include "lib/defines.h"
...@@ -46,7 +46,7 @@ struct kr_cookie_ctx { ...@@ -46,7 +46,7 @@ struct kr_cookie_ctx {
uint32_t cache_ttl; /**< TTL used when caching cookies */ uint32_t cache_ttl; /**< TTL used when caching cookies */
clnt_cookie_alg_t *cc_alg_func; /**< Client cookie hash computation callback. */ const struct kr_clnt_cookie_alg_descr *cc_alg; /**< Client cookie algorithm. */
}; };
/** Global cookie control context. */ /** Global cookie control context. */
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <string.h> #include <string.h>
#include "daemon/engine.h" #include "daemon/engine.h"
#include "lib/cookies/algorithm.h" #include "lib/cookies/alg_clnt.h"
#include "lib/cookies/cache.h" #include "lib/cookies/cache.h"
#include "lib/cookies/control.h" #include "lib/cookies/control.h"
#include "lib/module.h" #include "lib/module.h"
...@@ -38,37 +38,6 @@ ...@@ -38,37 +38,6 @@
/* TODO -- The context must store sent cookies and server addresses in order /* TODO -- The context must store sent cookies and server addresses in order
* to make the process more reliable. */ * to make the process more reliable. */
/**
* Check whether supplied client cookie was generated from given client secret
* and address.
* @param cc client cookie
* @param input input cookie algorithm parameters
* @param cc_alg_func function generating client cookie
* @return kr_ok() or error code
*/
static int check_client_cookie(const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
const struct kr_clnt_cookie_input *input,
clnt_cookie_alg_t *cc_alg_func)
{
if (!cc || !input || !cc_alg_func) {
return kr_error(EINVAL);
}
uint8_t generated_cc[KNOT_OPT_COOKIE_CLNT] = {0, };
int ret = cc_alg_func(input, generated_cc);
if (ret != kr_ok()) {
return ret;
}
ret = memcmp(cc, generated_cc, KNOT_OPT_COOKIE_CLNT);
if (ret == 0) {
return kr_ok();
}
return kr_error(EINVAL);
}
/** /**
* Obtain address from query/response context if if can be obtained. * Obtain address from query/response context if if can be obtained.
* @param qry query context * @param qry query context
...@@ -92,15 +61,15 @@ static const struct sockaddr *passed_server_sockaddr(const struct kr_query *qry) ...@@ -92,15 +61,15 @@ static const struct sockaddr *passed_server_sockaddr(const struct kr_query *qry)
* @param nsrep name server reputation context * @param nsrep name server reputation context
* @param cc client cookie data * @param cc client cookie data
* @param csecr client secret * @param csecr client secret
* @param cc_alg_func function generating client cookie * @param cc_alg client cookie algorithm
* @return pointer to address if a matching found, NULL if none matches * @return pointer to address if a matching found, NULL if none matches
*/ */
static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep, static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep,
const uint8_t cc[KNOT_OPT_COOKIE_CLNT], const uint8_t cc[KNOT_OPT_COOKIE_CLNT],
const struct kr_cookie_secret *csecr, const struct kr_cookie_secret *csecr,
clnt_cookie_alg_t *cc_alg_func) const struct kr_clnt_cookie_alg_descr *cc_alg)
{ {
assert(nsrep && cc && csecr && cc_alg_func); assert(nsrep && cc && csecr && cc_alg);
const struct sockaddr *sockaddr = NULL; const struct sockaddr *sockaddr = NULL;
...@@ -118,7 +87,7 @@ static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep, ...@@ -118,7 +87,7 @@ static const struct sockaddr *guess_server_addr(const struct kr_nsrep *nsrep,
} }
input.srvr_sockaddr = &nsrep->addr[i]; input.srvr_sockaddr = &nsrep->addr[i];
int ret = check_client_cookie(cc, &input, cc_alg_func); int ret = kr_clnt_cookie_check(cc, &input, cc_alg);
if (ret == kr_ok()) { if (ret == kr_ok()) {
sockaddr = (struct sockaddr *) &nsrep->addr[i]; sockaddr = (struct sockaddr *) &nsrep->addr[i];
break; break;
...@@ -155,13 +124,12 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr, ...@@ -155,13 +124,12 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr,
.secret_data = cntrl->current_cs->data, .secret_data = cntrl->current_cs->data,
.secret_len = cntrl->current_cs->size .secret_len = cntrl->current_cs->size
}; };
int ret = check_client_cookie(cc, &input, cntrl->cc_alg_func); int ret = kr_clnt_cookie_check(cc, &input, cntrl->cc_alg);
bool have_current = (ret == kr_ok()); bool have_current = (ret == kr_ok());
if ((ret != kr_ok()) && cntrl->recent_cs) { if ((ret != kr_ok()) && cntrl->recent_cs) {
input.secret_data = cntrl->recent_cs->data; input.secret_data = cntrl->recent_cs->data;
input.secret_len = cntrl->recent_cs->size; input.secret_len = cntrl->recent_cs->size;
ret = check_client_cookie(cc, &input, ret = kr_clnt_cookie_check(cc, &input, cntrl->cc_alg);
cntrl->cc_alg_func);
} }
if (ret == kr_ok()) { if (ret == kr_ok()) {
*sockaddr = tmp_sockaddr; *sockaddr = tmp_sockaddr;
...@@ -180,12 +148,12 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr, ...@@ -180,12 +148,12 @@ static int srvr_sockaddr_cc_check(const struct sockaddr **sockaddr,
/* Abusing name server reputation mechanism to guess IP addresses. */ /* Abusing name server reputation mechanism to guess IP addresses. */
const struct kr_nsrep *ns = &qry->ns; const struct kr_nsrep *ns = &qry->ns;
tmp_sockaddr = guess_server_addr(ns, cc, cntrl->current_cs, tmp_sockaddr = guess_server_addr(ns, cc, cntrl->current_cs,
cntrl->cc_alg_func); cntrl->cc_alg);
bool have_current = (tmp_sockaddr != NULL); bool have_current = (tmp_sockaddr != NULL);
if (!tmp_sockaddr && cntrl->recent_cs) { if (!tmp_sockaddr && cntrl->recent_cs) {
/* Try recent client secret to check obtained cookie. */ /* Try recent client secret to check obtained cookie. */
tmp_sockaddr = guess_server_addr(ns, cc, cntrl->recent_cs, tmp_sockaddr = guess_server_addr(ns, cc, cntrl->recent_cs,
cntrl->cc_alg_func); cntrl->cc_alg);
} }
if (tmp_sockaddr) { if (tmp_sockaddr) {
*sockaddr = tmp_sockaddr; *sockaddr = tmp_sockaddr;
......
...@@ -48,12 +48,14 @@ ifeq ($(HAS_libcrypto),yes) ...@@ -48,12 +48,14 @@ ifeq ($(HAS_libcrypto),yes)
libkres_SOURCES += \ libkres_SOURCES += \
contrib/fnv/hash_64a.c \ contrib/fnv/hash_64a.c \
lib/layer/cookiemonster.c \ lib/layer/cookiemonster.c \
lib/cookies/algorithm.c \ lib/cookies/alg_clnt.c \
lib/cookies/alg_srvr.c \
lib/cookies/cache.c \ lib/cookies/cache.c \
lib/cookies/control.c lib/cookies/control.c
libkres_HEADERS += \ libkres_HEADERS += \
lib/cookies/algorithm.h \ lib/cookies/alg_clnt.h \
lib/cookies/alg_srvr.h \
lib/cookies/cache.h \ lib/cookies/cache.h \
lib/cookies/control.h lib/cookies/control.h
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include <string.h> #include <string.h>
#include "daemon/engine.h" #include "daemon/engine.h"
#include "lib/cookies/algorithm.h" #include "lib/cookies/alg_clnt.h"
#include "lib/cookies/control.h" #include "lib/cookies/control.h"
#include "lib/layer.h" #include "lib/layer.h"
...@@ -133,12 +133,12 @@ static bool apply_client_hash_func(struct kr_cookie_ctx *cntrl, ...@@ -133,12 +133,12 @@ static bool apply_client_hash_func(struct kr_cookie_ctx *cntrl,
const JsonNode *node) const JsonNode *node)
{ {
if (node->tag == JSON_STRING) { if (node->tag == JSON_STRING) {
clnt_cookie_alg_t *cc_alg_func = kr_clnt_cookie_alg_func(kr_clnt_cookie_algs, const struct kr_clnt_cookie_alg_descr *cc_alg = kr_clnt_cookie_alg(kr_clnt_cookie_algs,
node->string_); node->string_);
if (!cc_alg_func) { if (!cc_alg) {
return false; return false;
} }
cntrl->cc_alg_func = cc_alg_func; cntrl->cc_alg = cc_alg;
return true; return true;
} }
...@@ -263,11 +263,9 @@ static char *cookiectl_config(void *env, struct kr_module *module, const char *a ...@@ -263,11 +263,9 @@ static char *cookiectl_config(void *env, struct kr_module *module, const char *a
read_secret(root_node, &kr_glob_cookie_ctx); read_secret(root_node, &kr_glob_cookie_ctx);
const char *name = kr_clnt_cookie_alg_name(kr_clnt_cookie_algs, assert(kr_glob_cookie_ctx.cc_alg->name);
kr_glob_cookie_ctx.cc_alg_func);
assert(name);
json_append_member(root_node, NAME_CLIENT_COOKIE_ALG, json_append_member(root_node, NAME_CLIENT_COOKIE_ALG,
json_mkstring(name)); json_mkstring(kr_glob_cookie_ctx.cc_alg->name));
read_available_cc_hashes(root_node, &kr_glob_cookie_ctx); read_available_cc_hashes(root_node, &kr_glob_cookie_ctx);
...@@ -293,7 +291,7 @@ int cookiectl_init(struct kr_module *module) ...@@ -293,7 +291,7 @@ int cookiectl_init(struct kr_module *module)
kr_glob_cookie_ctx.enabled = false; kr_glob_cookie_ctx.enabled = false;
kr_glob_cookie_ctx.current_cs = &dflt_cs; kr_glob_cookie_ctx.current_cs = &dflt_cs;
kr_glob_cookie_ctx.cache_ttl = DFLT_COOKIE_TTL; kr_glob_cookie_ctx.cache_ttl = DFLT_COOKIE_TTL;
kr_glob_cookie_ctx.cc_alg_func = kr_clnt_cookie_alg_fnv64; kr_glob_cookie_ctx.cc_alg = kr_clnt_cookie_alg(kr_clnt_cookie_algs, "FNV-64");
module->data = NULL; module->data = NULL;
......
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