]> git.meshlink.io Git - meshlink/blobdiff - src/sptps.c
Fix compiling with -Wall -W.
[meshlink] / src / sptps.c
index 133f2b7e043b24235a16db83692aa1a32f7d0c34..01fb438f2e3469fc6c186b3201db66e96d1a82c9 100644 (file)
@@ -1,6 +1,6 @@
 /*
     sptps.c -- Simple Peer-to-Peer Security
-    Copyright (C) 2014 Guus Sliepen <guus@meshlink.io>
+    Copyright (C) 2014-2017 Guus Sliepen <guus@meshlink.io>
 
     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,7 +27,7 @@
 #include "prf.h"
 #include "sptps.h"
 
-unsigned int sptps_replaywin = 16;
+unsigned int sptps_replaywin = 32;
 
 /*
    Nonce MUST be exchanged first (done)
@@ -50,9 +50,15 @@ unsigned int sptps_replaywin = 16;
 */
 
 void sptps_log_quiet(sptps_t *s, int s_errno, const char *format, va_list ap) {
+       (void)s;
+       (void)s_errno;
+       (void)format;
+       (void)ap;
 }
 
 void sptps_log_stderr(sptps_t *s, int s_errno, const char *format, va_list ap) {
+       (void)s;
+       (void)s_errno;
        vfprintf(stderr, format, ap);
        fputc('\n', stderr);
 }
@@ -80,7 +86,7 @@ static void warning(sptps_t *s, const char *format, ...) {
 }
 
 // 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) {
+static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
        char buffer[len + 21UL];
 
        // Create header with sequence number, length and record type
@@ -101,7 +107,7 @@ static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const char *data
        }
 }
 // Send a record (private version, accepts all record types, handles encryption and authentication).
-static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
+static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
        if(s->datagram)
                return send_record_priv_datagram(s, type, data, len);
 
@@ -126,7 +132,7 @@ static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_
 }
 
 // Send an application record.
-bool sptps_send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
+bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
        // Sanity checks: application cannot send data before handshake is finished,
        // and only record types 0..127 are allowed.
        if(!s->outstate)
@@ -177,11 +183,11 @@ static bool send_sig(sptps_t *s) {
        memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
 
        // Sign the result.
-       if(!ecdsa_sign(s->mykey, msg, sizeof msg, sig))
+       if(!ecdsa_sign(s->mykey, msg, sizeof(msg), sig))
                return error(s, EINVAL, "Failed to sign SIG record");
 
        // Send the SIG exchange record.
-       return send_record_priv(s, SPTPS_HANDSHAKE, sig, sizeof sig);
+       return send_record_priv(s, SPTPS_HANDSHAKE, sig, sizeof(sig));
 }
 
 // Generate key material from the shared secret created from the ECDHE key exchange.
@@ -227,6 +233,7 @@ static bool send_ack(sptps_t *s) {
 
 // Receive an ACKnowledgement record.
 static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
+       (void)data;
        if(len)
                return error(s, EIO, "Invalid ACK record length");
 
@@ -283,7 +290,7 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
        memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
 
        // Verify signature.
-       if(!ecdsa_verify(s->hiskey, msg, sizeof msg, data))
+       if(!ecdsa_verify(s->hiskey, msg, sizeof(msg), data))
                return error(s, EIO, "Failed to verify SIG record");
 
        // Compute shared secret.
@@ -293,7 +300,7 @@ static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
        s->ecdh = NULL;
 
        // Generate key material from shared secret.
-       if(!generate_key_material(s, shared, sizeof shared))
+       if(!generate_key_material(s, shared, sizeof(shared)))
                return false;
 
        free(s->mykex);
@@ -331,58 +338,69 @@ bool sptps_force_kex(sptps_t *s) {
 static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
        // Only a few states to deal with handshaking.
        switch(s->state) {
-               case SPTPS_SECONDARY_KEX:
-                       // We receive a secondary KEX request, first respond by sending our own.
-                       if(!send_kex(s))
-                               return false;
-               case SPTPS_KEX:
-                       // We have sent our KEX request, we expect our peer to sent one as well.
-                       if(!receive_kex(s, data, len))
-                               return false;
-                       s->state = SPTPS_SIG;
-                       return true;
-               case SPTPS_SIG:
-                       // If we already sent our secondary public ECDH key, we expect the peer to send his.
-                       if(!receive_sig(s, data, len))
-                               return false;
-                       if(s->outstate)
-                               s->state = SPTPS_ACK;
-                       else {
-                               s->outstate = true;
-                               if(!receive_ack(s, NULL, 0))
-                                       return false;
-                               s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
-                               s->state = SPTPS_SECONDARY_KEX;
-                       }
-
-                       return true;
-               case SPTPS_ACK:
-                       // We expect a handshake message to indicate transition to the new keys.
-                       if(!receive_ack(s, data, len))
+       case SPTPS_SECONDARY_KEX:
+               // We receive a secondary KEX request, first respond by sending our own.
+               if(!send_kex(s))
+                       return false;
+               // fallthrough
+       case SPTPS_KEX:
+               // We have sent our KEX request, we expect our peer to sent one as well.
+               if(!receive_kex(s, data, len))
+                       return false;
+               s->state = SPTPS_SIG;
+               return true;
+       case SPTPS_SIG:
+               // If we already sent our secondary public ECDH key, we expect the peer to send his.
+               if(!receive_sig(s, data, len))
+                       return false;
+               if(s->outstate)
+                       s->state = SPTPS_ACK;
+               else {
+                       s->outstate = true;
+                       if(!receive_ack(s, NULL, 0))
                                return false;
                        s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
                        s->state = SPTPS_SECONDARY_KEX;
-                       return true;
-               // TODO: split ACK into a VERify and ACK?
-               default:
-                       return error(s, EIO, "Invalid session state %d", s->state);
+               }
+
+               return true;
+       case SPTPS_ACK:
+               // We expect a handshake message to indicate transition to the new keys.
+               if(!receive_ack(s, data, len))
+                       return false;
+               s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
+               s->state = SPTPS_SECONDARY_KEX;
+               return true;
+       // TODO: split ACK into a VERify and ACK?
+       default:
+               return error(s, EIO, "Invalid session state %d", s->state);
        }
 }
 
 // Check datagram for valid HMAC
-bool sptps_verify_datagram(sptps_t *s, const char *data, size_t len) {
-       if(!s->instate || len < 21)
-               return error(s, EIO, "Received short packet");
+bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
+       if(!s->instate)
+               return error(s, EIO, "SPTPS state not ready to verify this datagram");
 
-       // TODO: just decrypt without updating the replay window
+       if(len < 21)
+               return error(s, EIO, "Received short packet in sptps_verify_datagram");
 
-       return true;
+       uint32_t seqno;
+       memcpy(&seqno, data, 4);
+       seqno = ntohl(seqno);
+       // TODO: check whether seqno makes sense, to avoid CPU intensive decrypt
+
+       char buffer[len];
+       size_t outlen;
+       return chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, buffer, &outlen);
 }
 
 // Receive incoming data, datagram version.
-static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len) {
+static bool sptps_receive_data_datagram(sptps_t *s, const void *vdata, size_t len) {
+       const char *data = vdata;
+
        if(len < (s->instate ? 21 : 5))
-               return error(s, EIO, "Received short packet");
+               return error(s, EIO, "Received short packet in sptps_receive_data_datagram");
 
        uint32_t seqno;
        memcpy(&seqno, data, 4);
@@ -423,13 +441,13 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
                                warning(s, "Lost %d packets\n", seqno - s->inseqno);
                                // Mark all packets in the replay window as being late.
                                memset(s->late, 255, s->replaywin);
-                       } else if (seqno < s->inseqno) {
+                       } 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)))
                                        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++)
+                               for(uint32_t i = s->inseqno; i < seqno; i++)
                                        s->late[(i / 8) % s->replaywin] |= 1 << i % 8;
                        }
                }
@@ -459,15 +477,14 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len
        } else if(type == SPTPS_HANDSHAKE) {
                if(!receive_handshake(s, buffer + 1, len - 21))
                        abort();
-       } else {
+       } else
                return error(s, EIO, "Invalid record type %d", type);
-       }
 
        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) {
+bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
        if(!s->state)
                return error(s, EIO, "Invalid session state zero");
 
@@ -543,9 +560,8 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
                } else if(type == SPTPS_HANDSHAKE) {
                        if(!receive_handshake(s, s->inbuf + 3, s->reclen))
                                return false;
-               } else {
+               } else
                        return error(s, EIO, "Invalid record type %d", type);
-               }
 
                s->buflen = 0;
        }
@@ -555,8 +571,11 @@ bool sptps_receive_data(sptps_t *s, const char *data, size_t len) {
 
 // Start a SPTPS session.
 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) {
+       if(!s || !mykey || !hiskey || !label || !labellen || !send_data || !receive_record)
+               return error(s, EINVAL, "Invalid argument to sptps_start()");
+
        // Initialise struct sptps
-       memset(s, 0, sizeof *s);
+       memset(s, 0, sizeof(*s));
 
        s->handle = handle;
        s->initiator = initiator;
@@ -605,6 +624,6 @@ bool sptps_stop(sptps_t *s) {
        free(s->key);
        free(s->label);
        free(s->late);
-       memset(s, 0, sizeof *s);
+       memset(s, 0, sizeof(*s));
        return true;
 }