fortified user/pw auth scheme (#731)

This commit is contained in:
Logan oos Even 2021-07-20 23:07:38 +02:00 committed by GitHub
parent 045f6a7386
commit 84d0991977
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 19 deletions

View File

@ -105,6 +105,9 @@ enum sn_purge{SN_PURGEABLE = 0, SN_UNPURGEABLE = 1};
#define HEADER_ENCRYPTION_NONE 1
#define HEADER_ENCRYPTION_ENABLED 2
/* REGISTER_SUPER_ACK packet hash length with user/pw auth, up to 16 bytes */
#define N2N_REG_SUP_HASH_CHECK_LEN 16
#define DEFAULT_MTU 1290
#define HASH_ADD_PEER(head,add) \

View File

@ -1141,6 +1141,7 @@ void send_query_peer (n2n_edge_t * eee,
void send_register_super (n2n_edge_t *eee) {
uint8_t pktbuf[N2N_PKT_BUF_SIZE] = {0};
uint8_t hash_buf[16] = {0};
size_t idx;
/* ssize_t sent; */
n2n_common_t cmn;
@ -1172,11 +1173,18 @@ void send_register_super (n2n_edge_t *eee) {
traceEvent(TRACE_DEBUG, "send REGISTER_SUPER to %s",
sock_to_cstr(sockbuf, &(eee->curr_sn->sock)));
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED)
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
packet_header_encrypt(pktbuf, idx, idx,
eee->conf.header_encryption_ctx_static, eee->conf.header_iv_ctx_static,
time_stamp());
if(eee->conf.shared_secret) {
pearson_hash_128(hash_buf, pktbuf, idx);
speck_128_encrypt(hash_buf, (speck_context_t*)eee->conf.shared_secret_ctx);
encode_buf(pktbuf, &idx, hash_buf, N2N_REG_SUP_HASH_CHECK_LEN);
}
}
/* sent = */ sendto_sock(eee, pktbuf, idx, &(eee->curr_sn->sock));
}
@ -2259,6 +2267,7 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const
n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */
macstr_t mac_buf1;
macstr_t mac_buf2;
uint8_t hash_buf[16];
size_t rem;
size_t idx;
size_t msg_type;
@ -2295,16 +2304,24 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const
if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) {
// match with static (1) or dynamic (2) ctx?
header_enc = packet_header_decrypt(udp_buf, udp_size,
(char *)eee->conf.community_name,
eee->conf.header_encryption_ctx_static, eee->conf.header_iv_ctx_static,
&stamp);
if(!header_enc)
if(packet_header_decrypt(udp_buf, udp_size,
// check dynamic first as it is identical to static in normal header encryption mode
if(packet_header_decrypt(udp_buf, udp_size,
(char *)eee->conf.community_name,
eee->conf.header_encryption_ctx_dynamic, eee->conf.header_iv_ctx_dynamic,
&stamp)) {
header_enc = 2;
header_enc = 2; /* not accurate with normal header encryption but does not matter */
}
if(!header_enc) {
// check static now (very likely to be REGISTER_SUPER_ACK, REGISTER_SUPER_NAK or invalid)
if(eee->conf.shared_secret) {
// hash the still encrypted packet to eventually be able to check it later (required for REGISTER_SUPER_ACK with user/pw auth)
pearson_hash_128(hash_buf, udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN));
}
header_enc = packet_header_decrypt(udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN),
(char *)eee->conf.community_name,
eee->conf.header_encryption_ctx_static, eee->conf.header_iv_ctx_static,
&stamp);
header_enc = 1;
}
if(!header_enc) {
traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header.");
@ -2500,6 +2517,15 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const
}
}
// hash check (user/pw auth only)
if(eee->conf.shared_secret) {
speck_128_encrypt(hash_buf, (speck_context_t*)eee->conf.shared_secret_ctx);
if(memcmp(hash_buf, udp_buf + udp_size - N2N_REG_SUP_HASH_CHECK_LEN /* length is has already been checked */, N2N_REG_SUP_HASH_CHECK_LEN)) {
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong hash.");
return;
}
}
if(memcmp(ra.cookie, eee->curr_sn->last_cookie, N2N_COOKIE_SIZE)) {
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER_ACK with wrong or old cookie.");
return;
@ -2624,7 +2650,9 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const
} else {
traceEvent(TRACE_ERROR, "Authentication error. MAC or IP address already in use or not released yet by supernode.");
}
exit(1);
// REVISIT: the following portion is too harsh, repeated error warning should be sufficient until it eventually is resolved,
// preventing de-auth attacks
/* exit(1); this is too harsh, repeated error warning should be sufficient until it eventually is resolved, preventing de-auth attacks
} else {
HASH_FIND_PEER(eee->known_peers, nak.srcMac, peer);
if(peer != NULL) {
@ -2633,7 +2661,7 @@ void process_udp (n2n_edge_t *eee, const struct sockaddr_in *sender_sock, const
HASH_FIND_PEER(eee->pending_peers, nak.srcMac, scan);
if(scan != NULL) {
HASH_DEL(eee->pending_peers, scan);
}
} */
}
break;
}

View File

@ -1240,6 +1240,8 @@ static int process_udp (n2n_sn_t * sss,
macstr_t mac_buf2;
n2n_sock_str_t sockbuf;
char buf[32];
uint8_t hash_buf[16] = {0}; /* always size of 16 (max) despite the actual value of N2N_REG_SUP_HASH_CHECK_LEN (<= 16) */
struct sn_community *comm, *tmp;
uint32_t header_enc = 0; /* 1 == encrypted by static key, 2 == encrypted by dynamic key */
uint64_t stamp;
@ -1289,17 +1291,20 @@ static int process_udp (n2n_sn_t * sss,
if(comm->header_encryption == HEADER_ENCRYPTION_NONE) {
continue;
}
// match with static (1) or dynamic (2) ctx?
header_enc = packet_header_decrypt(udp_buf, udp_size,
comm->community,
comm->header_encryption_ctx_static, comm->header_iv_ctx_static,
&stamp);
if(!header_enc)
if(packet_header_decrypt(udp_buf, udp_size,
comm->community,
comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic,
&stamp))
// check dynamic first as it is identical to static in normal header encryption mode
if(packet_header_decrypt(udp_buf, udp_size,
comm->community,
comm->header_encryption_ctx_dynamic, comm->header_iv_ctx_dynamic,
&stamp)) {
header_enc = 2;
}
if(!header_enc) {
pearson_hash_128(hash_buf, udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN));
header_enc = packet_header_decrypt(udp_buf, max(0, (int)udp_size - (int)N2N_REG_SUP_HASH_CHECK_LEN), comm->community,
comm->header_encryption_ctx_static, comm->header_iv_ctx_static, &stamp);
}
if(header_enc) {
// time stamp verification follows in the packet specific section as it requires to determine the
@ -1338,6 +1343,7 @@ static int process_udp (n2n_sn_t * sss,
rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
idx = 0; /* marches through packet header as parts are decoded. */
if(decode_common(&cmn, udp_buf, &rem, &idx) < 0) {
traceEvent(TRACE_ERROR, "Failed to decode common section");
return -1; /* failed to decode packet */
@ -1563,6 +1569,7 @@ static int process_udp (n2n_sn_t * sss,
int num = 0;
int skip;
int ret_value;
sn_user_t *user = NULL;
memset(&ack, 0, sizeof(n2n_REGISTER_SUPER_ACK_t));
memset(&nak, 0, sizeof(n2n_REGISTER_SUPER_NAK_t));
@ -1631,6 +1638,22 @@ static int process_udp (n2n_sn_t * sss,
return -1;
}
// hash check (user/pw auth only)
if(comm->allowed_users) {
// check if submitted public key is in list of allowed users
HASH_FIND(hh, comm->allowed_users, &reg.auth.token, sizeof(n2n_private_public_key_t), user);
if(user) {
speck_128_encrypt(hash_buf, (speck_context_t*)user->shared_secret_ctx);
if(memcmp(hash_buf, udp_buf + udp_size - N2N_REG_SUP_HASH_CHECK_LEN /* length has already been checked */, N2N_REG_SUP_HASH_CHECK_LEN)) {
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER with wrong hash.");
return -1;
}
} else {
traceEvent(TRACE_INFO, "Rx REGISTER_SUPER from unknown user.");
// continue and let auth check do the rest (otherwise, no NAK is sent)
}
}
cmn2.ttl = N2N_DEFAULT_TTL;
cmn2.pc = n2n_register_super_ack;
cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
@ -1715,6 +1738,10 @@ static int process_udp (n2n_sn_t * sss,
packet_header_encrypt(ackbuf, encx, encx,
comm->header_encryption_ctx_static, comm->header_iv_ctx_static,
time_stamp());
// if user-password-auth
if(comm->allowed_users) {
encode_buf(ackbuf, &encx, hash_buf /* no matter what content */, N2N_REG_SUP_HASH_CHECK_LEN);
}
}
sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, ackbuf, encx);
@ -1753,6 +1780,14 @@ static int process_udp (n2n_sn_t * sss,
packet_header_encrypt(ackbuf, encx, encx,
comm->header_encryption_ctx_static, comm->header_iv_ctx_static,
time_stamp());
// if user-password-auth
if(comm->allowed_users) {
// append an encrypted packet hash
pearson_hash_128(hash_buf, ackbuf, encx);
// same 'user' as above
speck_128_encrypt(hash_buf, (speck_context_t*)user->shared_secret_ctx);
encode_buf(ackbuf, &encx, hash_buf, N2N_REG_SUP_HASH_CHECK_LEN);
}
}
sendto_sock(sss, socket_fd, (struct sockaddr *)sender_sock, ackbuf, encx);
@ -1953,6 +1988,10 @@ static int process_udp (n2n_sn_t * sss,
packet_header_encrypt(nakbuf, encx, encx,
comm->header_encryption_ctx_static, comm->header_iv_ctx_static,
time_stamp());
// if user-password-auth
if(comm->allowed_users) {
encode_buf(nakbuf, &encx, hash_buf /* no matter what content */, N2N_REG_SUP_HASH_CHECK_LEN);
}
}
sendto_peer(sss, peer, nakbuf, encx);