X-Git-Url: https://tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Fsptps.c;h=e5946ed6fd8cc8cb9211141063f159188e0c6e8f;hb=23fda4db6d1bb400a97f6d2a07d9b700f9546129;hp=e9ce94aef85ef361a706de4322a1117d5475160e;hpb=53036a58790168e18f524bd923f9a7d34691ba2d;p=tinc diff --git a/src/sptps.c b/src/sptps.c index e9ce94ae..e5946ed6 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -1,6 +1,6 @@ /* sptps.c -- Simple Peer-to-Peer Security - Copyright (C) 2011-2013 Guus Sliepen , + Copyright (C) 2011-2014 Guus Sliepen , 2010 Brandon L. Black This program is free software; you can redistribute it and/or modify @@ -81,7 +81,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 @@ -102,7 +102,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); @@ -127,7 +127,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) @@ -424,7 +424,7 @@ static bool sptps_check_seqno(sptps_t *s, uint32_t seqno, bool update_state) { } // Check datagram for valid HMAC -bool sptps_verify_datagram(sptps_t *s, const char *data, size_t len) { +bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) { if(!s->instate || len < 21) return error(s, EIO, "Received short packet"); @@ -483,10 +483,10 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len if(!s->instate) return error(s, EIO, "Application record received before handshake finished"); if(!s->receive_record(s->handle, type, buffer + 1, len - 21)) - abort(); + return false; } else if(type == SPTPS_HANDSHAKE) { if(!receive_handshake(s, buffer + 1, len - 21)) - abort(); + return false; } else { return error(s, EIO, "Invalid record type %d", type); } @@ -495,94 +495,96 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len } // 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) { +size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) { + size_t total_read = 0; + if(!s->state) return error(s, EIO, "Invalid session state zero"); if(s->datagram) - return sptps_receive_data_datagram(s, data, len); - - while(len) { - // First read the 2 length bytes. - if(s->buflen < 2) { - size_t toread = 2 - s->buflen; - if(toread > len) - toread = len; + return sptps_receive_data_datagram(s, data, len) ? len : false; - memcpy(s->inbuf + s->buflen, data, toread); + // First read the 2 length bytes. + if(s->buflen < 2) { + size_t toread = 2 - s->buflen; + if(toread > len) + toread = len; - s->buflen += toread; - len -= toread; - data += toread; + memcpy(s->inbuf + s->buflen, data, toread); - // Exit early if we don't have the full length. - if(s->buflen < 2) - return true; + total_read += toread; + s->buflen += toread; + len -= toread; + data += toread; - // Get the length bytes + // Exit early if we don't have the full length. + if(s->buflen < 2) + return total_read; - memcpy(&s->reclen, s->inbuf, 2); - s->reclen = ntohs(s->reclen); + // Get the length bytes - // If we have the length bytes, ensure our buffer can hold the whole request. - s->inbuf = realloc(s->inbuf, s->reclen + 19UL); - if(!s->inbuf) - return error(s, errno, strerror(errno)); + memcpy(&s->reclen, s->inbuf, 2); + s->reclen = ntohs(s->reclen); - // Exit early if we have no more data to process. - if(!len) - return true; - } + // If we have the length bytes, ensure our buffer can hold the whole request. + s->inbuf = realloc(s->inbuf, s->reclen + 19UL); + if(!s->inbuf) + return error(s, errno, strerror(errno)); - // Read up to the end of the record. - size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen; - if(toread > len) - toread = len; + // Exit early if we have no more data to process. + if(!len) + return total_read; + } - memcpy(s->inbuf + s->buflen, data, toread); - s->buflen += toread; - len -= toread; - data += toread; + // Read up to the end of the record. + size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen; + if(toread > len) + toread = len; - // If we don't have a whole record, exit. - if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) - return true; + memcpy(s->inbuf + s->buflen, data, toread); + total_read += toread; + s->buflen += toread; + len -= toread; + data += toread; - // Update sequence number. + // If we don't have a whole record, exit. + if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) + return total_read; - uint32_t seqno = s->inseqno++; + // Update sequence number. - // Check HMAC and decrypt. - if(s->instate) { - if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) - return error(s, EINVAL, "Failed to decrypt and verify record"); - } + uint32_t seqno = s->inseqno++; - // Append a NULL byte for safety. - s->inbuf[s->reclen + 3UL] = 0; + // Check HMAC and decrypt. + if(s->instate) { + if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) + return error(s, EINVAL, "Failed to decrypt and verify record"); + } - uint8_t type = s->inbuf[2]; + // Append a NULL byte for safety. + s->inbuf[s->reclen + 3UL] = 0; - if(type < SPTPS_HANDSHAKE) { - if(!s->instate) - return error(s, EIO, "Application record received before handshake finished"); - if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) - return false; - } else if(type == SPTPS_HANDSHAKE) { - if(!receive_handshake(s, s->inbuf + 3, s->reclen)) - return false; - } else { - return error(s, EIO, "Invalid record type %d", type); - } + uint8_t type = s->inbuf[2]; - s->buflen = 0; + if(type < SPTPS_HANDSHAKE) { + if(!s->instate) + return error(s, EIO, "Application record received before handshake finished"); + if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) + return false; + } else if(type == SPTPS_HANDSHAKE) { + if(!receive_handshake(s, s->inbuf + 3, s->reclen)) + return false; + } else { + return error(s, EIO, "Invalid record type %d", type); } - return true; + s->buflen = 0; + + return total_read; } // 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) { +bool sptps_start(sptps_t *s, void *handle, bool initiator, bool datagram, ecdsa_t *mykey, ecdsa_t *hiskey, const void *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) { // Initialise struct sptps memset(s, 0, sizeof *s);