diff --git a/include/header_encryption.h b/include/header_encryption.h index 0e8a708..9ed7eaf 100644 --- a/include/header_encryption.h +++ b/include/header_encryption.h @@ -19,10 +19,12 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, char * community_name, he_context_t * ctx, - he_context_t * ctx_iv, uint16_t * checksum); + he_context_t * ctx_iv, + uint64_t * stamp, uint16_t * checksum); int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx, - he_context_t * ctx_iv, uint16_t checksum); + he_context_t * ctx_iv, + uint64_t stamp, uint16_t checksum); void packet_header_setup_key (const char * community_name, he_context_t ** ctx, diff --git a/include/n2n.h b/include/n2n.h index e4b3b4a..547c585 100644 --- a/include/n2n.h +++ b/include/n2n.h @@ -428,6 +428,10 @@ SOCKET open_socket(int local_port, int bind_any); int sock_equal( const n2n_sock_t * a, const n2n_sock_t * b ); +/* Header encryption */ +uint64_t time_stamp(void); +int time_stamp_verify (uint64_t stamp, uint64_t * previous_stamp); + /* Operations on peer_info lists. */ size_t purge_peer_list( struct peer_info ** peer_list, time_t purge_before ); diff --git a/src/edge_utils.c b/src/edge_utils.c index 1389ab8..ca97d34 100644 --- a/src/edge_utils.c +++ b/src/edge_utils.c @@ -17,7 +17,6 @@ */ #include "n2n.h" -#include "header_encryption.h" #include "edge_utils_win32.h" /* heap allocation for compression as per lzo example doc */ @@ -731,7 +730,8 @@ static void send_register_super(n2n_edge_t * eee, if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, pearson_hash_16 (pktbuf, idx)); + eee->conf.header_iv_ctx, + time_stamp (), pearson_hash_16 (pktbuf, idx)); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, supernode); } @@ -763,7 +763,8 @@ static void send_query_peer( n2n_edge_t * eee, if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED){ packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, pearson_hash_16 (pktbuf, idx)); + eee->conf.header_iv_ctx, + time_stamp (), pearson_hash_16 (pktbuf, idx)); } sendto_sock( eee->udp_sock, pktbuf, idx, &(eee->supernode) ); } @@ -810,7 +811,8 @@ static void send_register(n2n_edge_t * eee, if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, pearson_hash_16 (pktbuf, idx)); + eee->conf.header_iv_ctx, + time_stamp (), pearson_hash_16 (pktbuf, idx)); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); } @@ -853,7 +855,8 @@ static void send_register_ack(n2n_edge_t * eee, if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (pktbuf, idx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, pearson_hash_16 (pktbuf, idx)); + eee->conf.header_iv_ctx, + time_stamp (), pearson_hash_16 (pktbuf, idx)); /* sent = */ sendto_sock(eee->udp_sock, pktbuf, idx, remote_peer); } @@ -1471,7 +1474,8 @@ void edge_send_packet2net(n2n_edge_t * eee, if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (pktbuf, headerIdx, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, pearson_hash_16 (pktbuf, idx)); + eee->conf.header_iv_ctx, + time_stamp (), pearson_hash_16 (pktbuf, idx)); #ifdef MTU_ASSERT_VALUE { @@ -1564,6 +1568,7 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { n2n_sock_t sender; n2n_sock_t * orig_sender=NULL; time_t now=0; + uint64_t stamp = 0; size_t i; @@ -1601,10 +1606,16 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { uint16_t checksum = 0; if( packet_header_decrypt (udp_buf, recvlen, (char *)eee->conf.community_name, eee->conf.header_encryption_ctx, - eee->conf.header_iv_ctx, &checksum) == 0) { + eee->conf.header_iv_ctx, + &stamp, &checksum) == 0) { traceEvent(TRACE_DEBUG, "readFromIPSocket failed to decrypt header."); return; } + + // time stamp verification follows in the packet specific section as it requires to determine the + // sender from the hash list by its MAC, or the packet might be from the supernode, this all depends + // on packet type, path taken (via supernode) and packet structure (MAC is not always in the same place) + if (checksum != pearson_hash_16 (udp_buf, recvlen)) { traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to checksum error."); return; @@ -1635,6 +1646,15 @@ static void readFromIPSocket(n2n_edge_t * eee, int in_sock) { decode_PACKET(&pkt, &cmn, udp_buf, &rem, &idx); +// !!! +/* if(eee->conf.header_encryption == HEADER_ENCRYPTION_ENABLED) { + + if ( !time_stamp_verify (stamp, &... !!!) ) { + traceEvent(TRACE_DEBUG, "readFromIPSocket dropped packet due to time stamp error."); + return; + } + } +*/ if(is_valid_peer_sock(&pkt.sock)) orig_sender = &(pkt.sock); diff --git a/src/header_encryption.c b/src/header_encryption.c index 32b6654..c526726 100644 --- a/src/header_encryption.c +++ b/src/header_encryption.c @@ -25,7 +25,7 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, char * community_name, he_context_t * ctx, - he_context_t * ctx_iv, uint16_t * checksum) { + he_context_t * ctx_iv, uint64_t * stamp, uint16_t * checksum) { // assemble IV // the last four are ASCII "n2n!" and do not get overwritten @@ -35,9 +35,10 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, // to full 128 bit IV memcpy (iv, packet, 12); - // extract checksum (last 16 bit) blended in IV + // extract time stamp (first 64 bit) and checksum (last 16 bit) blended in IV speck_he_iv_decrypt (iv, (speck_context_t*)ctx_iv); *checksum = be16toh (((uint16_t*)iv)[5]); + *stamp = be64toh (((uint64_t*)iv)[0]); memcpy (iv, packet, 12); @@ -64,7 +65,7 @@ uint32_t packet_header_decrypt (uint8_t packet[], uint16_t packet_len, /* ********************************************************************** */ int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_t * ctx, - he_context_t * ctx_iv, uint16_t checksum) { + he_context_t * ctx_iv, uint64_t stamp, uint16_t checksum) { uint8_t iv[16]; uint16_t *iv16 = (uint16_t*)&iv; @@ -79,7 +80,7 @@ int32_t packet_header_encrypt (uint8_t packet[], uint8_t header_len, he_context_ memcpy (&packet[16], &packet[00], 4); - iv64[0] = n2n_rand (); + iv64[0] = htobe64 (stamp); iv16[4] = n2n_rand (); iv16[5] = htobe16 (checksum); iv32[3] = htobe32 (magic); diff --git a/src/n2n.c b/src/n2n.c index 85a1db2..59f27db 100644 --- a/src/n2n.c +++ b/src/n2n.c @@ -427,14 +427,14 @@ uint64_t time_stamp (void) { // checks if a provided time stamp is consistent with current time and previously valid time stamps -// returns the time stamp to store as "last valid time stamp" or zero in case of invalid time stamp +// and, in case of validity, replaces the "last valid time stamp" // REVISIT during the years 2035...2038 -uint64_t time_stamp_verify (uint64_t stamp, uint64_t previous_stamp) { +int time_stamp_verify (uint64_t stamp, uint64_t * previous_stamp) { int64_t diff; // do not change to unsigned // is it higher than previous time stamp (including allowed deviation of TIME_STAMP_JITTER)? - diff = stamp - previous_stamp + TIME_STAMP_JITTER; + diff = stamp - *previous_stamp + TIME_STAMP_JITTER; if(diff > 0) { // is it around current time (+/- allowed deviation TIME_STAMP_FRAME)? @@ -445,16 +445,17 @@ uint64_t time_stamp_verify (uint64_t stamp, uint64_t previous_stamp) { if(diff < TIME_STAMP_FRAME) { // for not allowing to exploit the allowed TIME_STAMP_JITTER to "turn the clock backwards", - // return the higher value, max() - return (stamp > previous_stamp ? stamp : previous_stamp); + // set the higher of the values + *previous_stamp = (stamp > *previous_stamp ? stamp : *previous_stamp); + return (1); // success } else { traceEvent(TRACE_DEBUG, "time_stamp_verify found a timestamp out of allowed frame."); - return (0); + return (0); // failure } } else { traceEvent(TRACE_DEBUG, "time_stamp_verify found a timestamp too old / older than previous."); - return (0); + return (0); // failure } } diff --git a/src/sn_utils.c b/src/sn_utils.c index 4ea34f6..8cf5821 100644 --- a/src/sn_utils.c +++ b/src/sn_utils.c @@ -1,5 +1,4 @@ #include "n2n.h" -#include "header_encryption.h" #define HASH_FIND_COMMUNITY(head, name, out) HASH_FIND_STR(head, name, out) @@ -391,6 +390,7 @@ static int process_udp(n2n_sn_t * sss, n2n_sock_str_t sockbuf; char buf[32]; struct sn_community *comm, *tmp; + uint64_t stamp; traceEvent(TRACE_DEBUG, "Processing incoming UDP packet [len: %lu][sender: %s:%u]", udp_size, intoa(ntohl(sender_sock->sin_addr.s_addr), buf, sizeof(buf)), @@ -437,7 +437,8 @@ static int process_udp(n2n_sn_t * sss, continue; uint16_t checksum = 0; if ( (ret = packet_header_decrypt (udp_buf, udp_size, comm->community, comm->header_encryption_ctx, - comm->header_iv_ctx, &checksum)) ) { + comm->header_iv_ctx, + &stamp, &checksum)) ) { if (checksum != pearson_hash_16 (udp_buf, udp_size)) { traceEvent(TRACE_DEBUG, "process_udp dropped packet due to checksum error."); return -1; @@ -537,7 +538,8 @@ static int process_udp(n2n_sn_t * sss, if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (rec_buf, oldEncx, comm->header_encryption_ctx, - comm->header_iv_ctx, pearson_hash_16 (rec_buf, encx)); + comm->header_iv_ctx, + time_stamp (), pearson_hash_16 (rec_buf, encx)); } else { /* Already from a supernode. Nothing to modify, just pass to @@ -550,7 +552,8 @@ static int process_udp(n2n_sn_t * sss, if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (rec_buf, idx, comm->header_encryption_ctx, - comm->header_iv_ctx, pearson_hash_16 (rec_buf, udp_size)); + comm->header_iv_ctx, + time_stamp (), pearson_hash_16 (rec_buf, udp_size)); } /* Common section to forward the final product. */ @@ -611,7 +614,8 @@ static int process_udp(n2n_sn_t * sss, if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (rec_buf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, pearson_hash_16 (rec_buf, encx)); + comm->header_iv_ctx, + time_stamp (), pearson_hash_16 (rec_buf, encx)); try_forward(sss, comm, &cmn, reg.dstMac, rec_buf, encx); /* unicast only */ } else @@ -683,7 +687,8 @@ static int process_udp(n2n_sn_t * sss, if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (ackbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, pearson_hash_16 (ackbuf, encx)); + comm->header_iv_ctx, + time_stamp (), pearson_hash_16 (ackbuf, encx)); sendto(sss->sock, ackbuf, encx, 0, (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in)); @@ -731,7 +736,8 @@ static int process_udp(n2n_sn_t * sss, if (comm->header_encryption == HEADER_ENCRYPTION_ENABLED) packet_header_encrypt (encbuf, encx, comm->header_encryption_ctx, - comm->header_iv_ctx, pearson_hash_16 (encbuf, encx)); + comm->header_iv_ctx, + time_stamp (), pearson_hash_16 (encbuf, encx)); sendto( sss->sock, encbuf, encx, 0, (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );