From: Guus Sliepen Date: Tue, 31 Jul 2012 18:39:15 +0000 (+0200) Subject: Add Brandon Black's replay window code to SPTPS. X-Git-Tag: import-tinc-1.1~324 X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=6bc8df3e010509f69af95d2cc14ec893def6f644;p=meshlink Add Brandon Black's replay window code to SPTPS. --- diff --git a/src/sptps.c b/src/sptps.c index 12c6c7f0..b907dadf 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -1,6 +1,7 @@ /* sptps.c -- Simple Peer-to-Peer Security - Copyright (C) 2011 Guus Sliepen , + Copyright (C) 2011-2012 Guus Sliepen , + 2010 Brandon L. Black 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 @@ -27,6 +28,8 @@ #include "prf.h" #include "sptps.h" +unsigned int sptps_replaywin = 16; + /* Nonce MUST be exchanged first (done) Signatures MUST be done over both nonces, to guarantee the signature is fresh @@ -415,15 +418,42 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len return receive_handshake(s, data + 5, len - 5); } - if(seqno < s->inseqno) { - fprintf(stderr, "Received late or replayed packet: %d < %d\n", seqno, s->inseqno); - return true; + // Replay protection using a sliding window of configurable size. + // s->inseqno is expected sequence number + // seqno is received sequence number + // s->late[] is a circular buffer, a 1 bit means a packet has not been received yet + // The circular buffer contains bits for sequence numbers from s->inseqno - s->replaywin * 8 to (but excluding) s->inseqno. + if(s->replaywin) { + if(seqno != s->inseqno) { + if(seqno >= s->inseqno + s->replaywin * 8) { + // Prevent packets that jump far ahead of the queue from causing many others to be dropped. + if(s->farfuture++ < s->replaywin >> 2) { + fprintf(stderr, "Packet is %d seqs in the future, dropped (%u)\n", seqno - s->inseqno, s->farfuture); + return false; + } + // Unless we have seen lots of them, in which case we consider the others lost. + fprintf(stderr, "Lost %d packets\n", seqno - s->inseqno); + memset(s->late, 0, s->replaywin); + } else if (seqno < s->inseqno) { + // If the sequence number is farther in the past than the bitmap goes, or if the packet was already received, drop it. + if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8))) { + fprintf(stderr, "Received late or replayed packet, seqno %d, last received %d", seqno, s->inseqno); + return false; + } + } else { + // We missed some packets. Mark them in the bitmap as being late. + for(int i = s->inseqno; i < seqno; i++) + s->late[(i / 8) % s->replaywin] |= 1 << i % 8; + } + } + + // Mark the current packet as not being late. + s->late[(seqno / 8) % s->replaywin] &= ~(1 << seqno % 8); + s->farfuture = 0; } if(seqno > s->inseqno) - fprintf(stderr, "Missed %d packets\n", seqno - s->inseqno); - - s->inseqno = seqno + 1; + s->inseqno = seqno + 1; uint16_t netlen = htons(len - 21); @@ -461,6 +491,7 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len return true; } + // Receive incoming data. Check if it contains a complete record, if so, handle it. bool sptps_receive_data(sptps_t *s, const char *data, size_t len) { if(s->datagram) @@ -564,6 +595,12 @@ bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_ s->datagram = datagram; s->mykey = mykey; s->hiskey = hiskey; + s->replaywin = sptps_replaywin; + if(s->replaywin) { + s->late = malloc(s->replaywin); + if(!s->late) + return error(s, errno, strerror(errno)); + } s->label = malloc(labellen); if(!s->label) @@ -602,5 +639,7 @@ bool sptps_stop(sptps_t *s) { s->key = NULL; free(s->label); s->label = NULL; + free(s->late); + s->late = NULL; return true; } diff --git a/src/sptps.h b/src/sptps.h index 0616ac7a..5037c46f 100644 --- a/src/sptps.h +++ b/src/sptps.h @@ -56,6 +56,9 @@ typedef struct sptps { cipher_t incipher; digest_t indigest; uint32_t inseqno; + unsigned int replaywin; + unsigned int farfuture; + char *late; bool outstate; cipher_t outcipher; @@ -77,6 +80,7 @@ typedef struct sptps { receive_record_t receive_record; } sptps_t; +extern unsigned int sptps_replaywin; extern bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t mykey, ecdsa_t hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record); extern bool sptps_stop(sptps_t *s); extern bool sptps_send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len);