X-Git-Url: https://www.tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Fsptps.c;h=fe978441a912b62249a4f7192b1fecd189afe3a2;hb=cc3c69c892b0dad9a6ece0a0f4ccd429a22fcbff;hp=3b9498c795122085857d68779185833b292e2ce2;hpb=47f33e07ff90b557cfa96999e921d35ea537ca80;p=tinc diff --git a/src/sptps.c b/src/sptps.c index 3b9498c7..fe978441 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -1,6 +1,6 @@ /* sptps.c -- Simple Peer-to-Peer Security - Copyright (C) 2011-2012 Guus Sliepen , + Copyright (C) 2011-2013 Guus Sliepen , 2010 Brandon L. Black This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@ #include "digest.h" #include "ecdh.h" #include "ecdsa.h" +#include "logger.h" #include "prf.h" #include "sptps.h" @@ -50,13 +51,36 @@ unsigned int sptps_replaywin = 16; Make sure ECC operations are fixed time (aka prevent side-channel attacks). */ +void sptps_log_quiet(sptps_t *s, int s_errno, const char *format, va_list ap) { +} + +void sptps_log_stderr(sptps_t *s, int s_errno, const char *format, va_list ap) { + vfprintf(stderr, format, ap); + fputc('\n', stderr); +} + +void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap) = sptps_log_stderr; + // Log an error message. -static bool error(sptps_t *s, int s_errno, const char *msg) { - fprintf(stderr, "SPTPS error: %s\n", msg); +static bool error(sptps_t *s, int s_errno, const char *format, ...) { + if(format) { + va_list ap; + va_start(ap, format); + sptps_log(s, s_errno, format, ap); + va_end(ap); + } + errno = s_errno; return false; } +static void warning(sptps_t *s, const char *format, ...) { + va_list ap; + va_start(ap, format); + sptps_log(s, 0, format, ap); + va_end(ap); +} + // Send a record (datagram version, accepts all record types, handles encryption and authentication). static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const char *data, uint16_t len) { char buffer[len + 23UL]; @@ -339,7 +363,6 @@ bool sptps_force_kex(sptps_t *s) { // Receive a handshake record. static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) { // Only a few states to deal with handshaking. - fprintf(stderr, "Received handshake message, current state %d\n", s->state); switch(s->state) { case SPTPS_SECONDARY_KEX: // We receive a secondary KEX request, first respond by sending our own. @@ -403,10 +426,8 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len seqno = ntohl(seqno); if(!s->instate) { - if(seqno != s->inseqno) { - fprintf(stderr, "Received invalid packet seqno: %d != %d\n", seqno, s->inseqno); - return error(s, EIO, "Invalid packet seqno"); - } + if(seqno != s->inseqno) + return error(s, EIO, "Invalid packet seqno: %d != %d", seqno, s->inseqno); s->inseqno = seqno + 1; @@ -418,6 +439,19 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len return receive_handshake(s, data + 5, len - 5); } + // Check HMAC. + uint16_t netlen = htons(len - 21); + + char buffer[len + 23]; + + memcpy(buffer, &netlen, 2); + memcpy(buffer + 2, data, len); + + memcpy(&seqno, buffer + 2, 4); + + if(!digest_verify(&s->indigest, buffer, len - 14, buffer + len - 14)) + return error(s, EIO, "Invalid HMAC"); + // Replay protection using a sliding window of configurable size. // s->inseqno is expected sequence number // seqno is received sequence number @@ -427,19 +461,16 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len 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; - } + if(s->farfuture++ < s->replaywin >> 2) + return error(s, EIO, "Packet is %d seqs in the future, dropped (%u)\n", seqno - s->inseqno, s->farfuture); + // Unless we have seen lots of them, in which case we consider the others lost. - fprintf(stderr, "Lost %d packets\n", seqno - s->inseqno); + warning(s, "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; - } + if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8))) + return error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno); } else { // We missed some packets. Mark them in the bitmap as being late. for(int i = s->inseqno; i < seqno; i++) @@ -455,19 +486,12 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len if(seqno > s->inseqno) s->inseqno = seqno + 1; - uint16_t netlen = htons(len - 21); - - char buffer[len + 23]; - - memcpy(buffer, &netlen, 2); - memcpy(buffer + 2, data, len); - - memcpy(&seqno, buffer + 2, 4); - - // Check HMAC and decrypt. - if(!digest_verify(&s->indigest, buffer, len - 14, buffer + len - 14)) - return error(s, EIO, "Invalid HMAC"); + if(!s->inseqno) + s->received = 0; + else + s->received++; + // Decrypt. cipher_set_counter(&s->incipher, &seqno, sizeof seqno); if(!cipher_counter_xor(&s->incipher, buffer + 6, len - 4, buffer + 6)) return false; @@ -509,7 +533,7 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) { s->buflen += toread; len -= toread; data += toread; - + // Exit early if we don't have the full length. if(s->buflen < 6) return true; @@ -628,18 +652,17 @@ bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_ // Stop a SPTPS session. bool sptps_stop(sptps_t *s) { // Clean up any resources. + cipher_close(&s->incipher); + cipher_close(&s->outcipher); + digest_close(&s->indigest); + digest_close(&s->outdigest); ecdh_free(&s->ecdh); free(s->inbuf); - s->inbuf = NULL; free(s->mykex); - s->mykex = NULL; free(s->hiskex); - s->hiskex = NULL; free(s->key); - s->key = NULL; free(s->label); - s->label = NULL; free(s->late); - s->late = NULL; + memset(s, 0, sizeof *s); return true; }