Move mud_keyx in mud_conf

This commit is contained in:
Adrien Gallouët
2017-01-18 10:49:45 +00:00
parent 82299973e0
commit f6b6610980

148
mud.c
View File

@@ -112,11 +112,6 @@ struct mud_path {
struct mud_path *next; struct mud_path *next;
}; };
struct mud_crypto_pub {
unsigned char send[MUD_PUB_SIZE + 1];
unsigned char recv[MUD_PUB_SIZE + 1];
};
struct mud_crypto_opt { struct mud_crypto_opt {
unsigned char *dst; unsigned char *dst;
struct { struct {
@@ -137,7 +132,6 @@ struct mud_crypto_key {
enum mud_packet_code { enum mud_packet_code {
mud_conf, mud_conf,
mud_stat, mud_stat,
mud_keyx,
}; };
struct mud_packet { struct mud_packet {
@@ -151,13 +145,14 @@ struct mud_packet {
unsigned char kiss[MUD_SID_SIZE]; unsigned char kiss[MUD_SID_SIZE];
unsigned char mtu[MUD_U48_SIZE]; unsigned char mtu[MUD_U48_SIZE];
unsigned char backup; unsigned char backup;
unsigned char public[MUD_PUB_SIZE];
unsigned char aes;
} conf; } conf;
struct { struct {
unsigned char sdt[MUD_U48_SIZE]; unsigned char sdt[MUD_U48_SIZE];
unsigned char rdt[MUD_U48_SIZE]; unsigned char rdt[MUD_U48_SIZE];
unsigned char rst[MUD_U48_SIZE]; unsigned char rst[MUD_U48_SIZE];
} stat; } stat;
struct mud_crypto_pub public;
} data; } data;
unsigned char _do_not_use_[MUD_MAC_SIZE]; unsigned char _do_not_use_[MUD_MAC_SIZE];
}; };
@@ -168,10 +163,14 @@ struct mud {
uint64_t time_tolerance; uint64_t time_tolerance;
struct mud_path *path; struct mud_path *path;
struct { struct {
uint64_t recv_time; uint64_t time;
unsigned char secret[crypto_scalarmult_SCALARBYTES]; unsigned char secret[crypto_scalarmult_SCALARBYTES];
struct mud_crypto_pub public; struct {
unsigned char local[MUD_PUB_SIZE];
unsigned char remote[MUD_PUB_SIZE];
} public;
struct mud_crypto_key private, last, next, current; struct mud_crypto_key private, last, next, current;
int ready;
int use_next; int use_next;
int aes; int aes;
} crypto; } crypto;
@@ -696,13 +695,23 @@ mud_create_socket(int port, int v4, int v6)
return fd; return fd;
} }
static void static int
mud_keyx_init(struct mud *mud) mud_keyx_init(struct mud *mud, uint64_t now)
{ {
if (!mud_timeout(now, mud->crypto.time, MUD_KEYX_TIMEOUT))
return -1;
mud->crypto.time = now ?: mud_now();
if (mud->crypto.ready)
return 0;
randombytes_buf(mud->crypto.secret, sizeof(mud->crypto.secret)); randombytes_buf(mud->crypto.secret, sizeof(mud->crypto.secret));
crypto_scalarmult_base(mud->crypto.public.send, mud->crypto.secret); crypto_scalarmult_base(mud->crypto.public.local, mud->crypto.secret);
memset(mud->crypto.public.recv, 0, sizeof(mud->crypto.public.recv));
mud->crypto.public.send[MUD_PUB_SIZE] = mud->crypto.aes; mud->crypto.ready = 1;
return 0;
} }
struct mud * struct mud *
@@ -733,7 +742,7 @@ mud_create(int port, int v4, int v6, int aes, int mtu)
mud_set_key(mud, key, sizeof(key)); mud_set_key(mud, key, sizeof(key));
mud->crypto.aes = aes && crypto_aead_aes256gcm_is_available(); mud->crypto.aes = aes && crypto_aead_aes256gcm_is_available();
mud_keyx_init(mud); mud_keyx_init(mud, 0);
randombytes_buf(mud->kiss, sizeof(mud->kiss)); randombytes_buf(mud->kiss, sizeof(mud->kiss));
@@ -830,7 +839,6 @@ mud_decrypt(struct mud *mud,
if (mud_decrypt_opt(&mud->crypto.current, &opt)) { if (mud_decrypt_opt(&mud->crypto.current, &opt)) {
if (!mud_decrypt_opt(&mud->crypto.next, &opt)) { if (!mud_decrypt_opt(&mud->crypto.next, &opt)) {
mud_keyx_init(mud);
mud->crypto.last = mud->crypto.current; mud->crypto.last = mud->crypto.current;
mud->crypto.current = mud->crypto.next; mud->crypto.current = mud->crypto.next;
mud->crypto.use_next = 0; mud->crypto.use_next = 0;
@@ -898,6 +906,9 @@ mud_packet_send(struct mud *mud, enum mud_packet_code code,
memcpy(&packet.data.conf.kiss, &mud->kiss, size); memcpy(&packet.data.conf.kiss, &mud->kiss, size);
mud_write48(packet.data.conf.mtu, path->conf.mtu.local); mud_write48(packet.data.conf.mtu, path->conf.mtu.local);
packet.data.conf.backup = (unsigned char)path->state.backup; packet.data.conf.backup = (unsigned char)path->state.backup;
memcpy(&packet.data.conf.public, &mud->crypto.public.local,
sizeof(mud->crypto.public.local));
packet.data.conf.aes = (unsigned char)mud->crypto.aes;
break; break;
case mud_stat: case mud_stat:
size = sizeof(packet.data.stat); size = sizeof(packet.data.stat);
@@ -905,10 +916,6 @@ mud_packet_send(struct mud *mud, enum mud_packet_code code,
mud_write48(packet.data.stat.rdt, path->rdt); mud_write48(packet.data.stat.rdt, path->rdt);
mud_write48(packet.data.stat.rst, path->rst); mud_write48(packet.data.stat.rst, path->rst);
break; break;
case mud_keyx:
size = sizeof(packet.data.public);
memcpy(&packet.data.public, &mud->crypto.public, size);
break;
} }
struct mud_crypto_opt opt = { struct mud_crypto_opt opt = {
@@ -924,62 +931,51 @@ mud_packet_send(struct mud *mud, enum mud_packet_code code,
} }
static void static void
mud_recv_keyx(struct mud *mud, struct mud_path *path, uint64_t now, mud_keyx_set(struct mud *mud, unsigned char *key, unsigned char *secret,
struct mud_crypto_pub *public) unsigned char *pub0, unsigned char *pub1)
{ {
struct mud_crypto_key *key = &mud->crypto.next; crypto_generichash_state state;
struct { crypto_generichash_init(&state, mud->crypto.private.encrypt.key,
unsigned char secret[crypto_scalarmult_BYTES]; MUD_KEY_SIZE, MUD_KEY_SIZE);
struct mud_crypto_pub public;
} shared_send, shared_recv;
memcpy(&shared_recv.public, public, sizeof(shared_recv.public)); crypto_generichash_update(&state, secret, crypto_scalarmult_BYTES);
crypto_generichash_update(&state, pub0, MUD_PUB_SIZE);
crypto_generichash_update(&state, pub1, MUD_PUB_SIZE);
int sync_send = memcmp(shared_recv.public.recv, mud->crypto.public.send, crypto_generichash_final(&state, key, MUD_KEY_SIZE);
sizeof(shared_recv.public.recv)); }
memcpy(shared_recv.public.recv, mud->crypto.public.send, static void
sizeof(shared_recv.public.recv)); mud_keyx(struct mud *mud, unsigned char *public, int aes)
{
unsigned char secret[crypto_scalarmult_BYTES];
memcpy(mud->crypto.public.recv, shared_recv.public.send, // XXX keyx init ?
sizeof(mud->crypto.public.recv));
mud->crypto.use_next = !sync_send; if (crypto_scalarmult(secret, mud->crypto.secret, public))
if (sync_send)
mud_packet_send(mud, mud_keyx, path, now);
if (crypto_scalarmult(shared_recv.secret, mud->crypto.secret,
shared_recv.public.send))
return; return;
memcpy(shared_send.secret, shared_recv.secret, mud_keyx_set(mud, mud->crypto.next.encrypt.key,
sizeof(shared_send.secret)); secret, public, mud->crypto.public.local);
memcpy(shared_send.public.send, shared_recv.public.recv, mud_keyx_set(mud, mud->crypto.next.decrypt.key,
sizeof(shared_send.public.send)); secret, mud->crypto.public.local, public);
memcpy(shared_send.public.recv, shared_recv.public.send, memcpy(mud->crypto.public.remote, public, MUD_PUB_SIZE);
sizeof(shared_send.public.recv)); mud->crypto.ready = 0;
crypto_generichash(key->encrypt.key, MUD_KEY_SIZE, mud->crypto.next.aes = mud->crypto.aes && aes;
(unsigned char *)&shared_send, sizeof(shared_send),
mud->crypto.private.encrypt.key, MUD_KEY_SIZE);
crypto_generichash(key->decrypt.key, MUD_KEY_SIZE, if (mud->crypto.next.aes) {
(unsigned char *)&shared_recv, sizeof(shared_recv), crypto_aead_aes256gcm_beforenm((crypto_aead_aes256gcm_state *)
mud->crypto.private.encrypt.key, MUD_KEY_SIZE); mud->crypto.next.encrypt.state,
mud->crypto.next.encrypt.key);
key->aes = (shared_recv.public.send[MUD_PUB_SIZE] == 1) && crypto_aead_aes256gcm_beforenm((crypto_aead_aes256gcm_state *)
(shared_recv.public.recv[MUD_PUB_SIZE] == 1); mud->crypto.next.decrypt.state,
mud->crypto.next.decrypt.key);
if (key->aes) {
crypto_aead_aes256gcm_beforenm(&key->encrypt.state, key->encrypt.key);
crypto_aead_aes256gcm_beforenm(&key->decrypt.state, key->decrypt.key);
} }
mud->crypto.recv_time = now;
} }
static void static void
@@ -1014,7 +1010,6 @@ mud_packet_check_size(unsigned char *data, size_t size)
const size_t sizes[] = { const size_t sizes[] = {
[mud_conf] = MUD_PACKET_SIZE(sizeof(packet->data.conf)), [mud_conf] = MUD_PACKET_SIZE(sizeof(packet->data.conf)),
[mud_stat] = MUD_PACKET_SIZE(sizeof(packet->data.stat)), [mud_stat] = MUD_PACKET_SIZE(sizeof(packet->data.stat)),
[mud_keyx] = MUD_PACKET_SIZE(sizeof(packet->data.public)),
}; };
// clang-format on // clang-format on
@@ -1048,13 +1043,22 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
{ {
struct mud_packet *packet = (struct mud_packet *)data; struct mud_packet *packet = (struct mud_packet *)data;
int new_keyx = 0;
switch (packet->hdr.code) { switch (packet->hdr.code) {
case mud_conf: case mud_conf:
path->conf.mtu.remote = mud_read48(packet->data.conf.mtu); path->conf.mtu.remote = mud_read48(packet->data.conf.mtu);
path->conf.remote = !memcmp(path->conf.kiss, packet->data.conf.kiss, path->conf.remote = !memcmp(path->conf.kiss, packet->data.conf.kiss,
sizeof(path->conf.kiss)); sizeof(path->conf.kiss));
if (path->state.active) new_keyx = memcmp(mud->crypto.public.remote, packet->data.conf.public,
sizeof(mud->crypto.public.remote));
if (new_keyx)
mud_keyx(mud, packet->data.conf.public, packet->data.conf.aes);
if (path->state.active) {
if (new_keyx)
mud->crypto.use_next = 1;
break; break;
}
if (!path->conf.remote) { if (!path->conf.remote) {
memcpy(path->conf.kiss, packet->data.conf.kiss, memcpy(path->conf.kiss, packet->data.conf.kiss,
sizeof(path->conf.kiss)); sizeof(path->conf.kiss));
@@ -1071,9 +1075,6 @@ mud_packet_recv(struct mud *mud, struct mud_path *path,
path->r_dt = path->rst - path->r_rst; path->r_dt = path->rst - path->r_rst;
path->rtt = now - path->r_rst; path->rtt = now - path->r_rst;
break; break;
case mud_keyx:
mud_recv_keyx(mud, path, now, &packet->data.public);
break;
default: default:
break; break;
} }
@@ -1175,29 +1176,22 @@ mud_recv(struct mud *mud, void *data, size_t size)
static void static void
mud_update(struct mud *mud) mud_update(struct mud *mud)
{ {
uint64_t now = mud_now();
int update_keyx = !mud_keyx_init(mud, now);
struct mud_path *path; struct mud_path *path;
for (path = mud->path; path; path = path->next) { for (path = mud->path; path; path = path->next) {
if (!path->state.active) if (!path->state.active)
continue; continue;
uint64_t now = mud_now(); if (update_keyx || mud_timeout(now, path->recv_time, mud->send_timeout))
if (mud_timeout(now, path->recv_time, mud->send_timeout))
path->conf.remote = 0; path->conf.remote = 0;
if ((!path->conf.remote) && if ((!path->conf.remote) &&
(mud_timeout(now, path->conf.send_time, mud->send_timeout))) { (mud_timeout(now, path->conf.send_time, mud->send_timeout))) {
mud_packet_send(mud, mud_conf, path, now); mud_packet_send(mud, mud_conf, path, now);
path->conf.send_time = now; path->conf.send_time = now;
continue;
}
if ((mud_timeout(now, path->public.send_time, mud->send_timeout)) &&
(mud_timeout(now, mud->crypto.recv_time, MUD_KEYX_TIMEOUT))) {
mud_packet_send(mud, mud_keyx, path, now);
path->public.send_time = now;
continue;
} }
} }
} }