]> git.meshlink.io Git - meshlink/blob - src/sptps.c
Add support for sendmmsg().
[meshlink] / src / sptps.c
1 /*
2     sptps.c -- Simple Peer-to-Peer Security
3     Copyright (C) 2014-2017 Guus Sliepen <guus@meshlink.io>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "chacha-poly1305/chacha-poly1305.h"
23 #include "crypto.h"
24 #include "ecdh.h"
25 #include "ecdsa.h"
26 #include "logger.h"
27 #include "prf.h"
28 #include "sptps.h"
29
30 /*
31    Nonce MUST be exchanged first (done)
32    Signatures MUST be done over both nonces, to guarantee the signature is fresh
33    Otherwise: if ECDHE key of one side is compromised, it can be reused!
34
35    Add explicit tag to beginning of structure to distinguish the client and server when signing. (done)
36
37    Sign all handshake messages up to ECDHE kex with long-term public keys. (done)
38
39    HMACed KEX finished message to prevent downgrade attacks and prove you have the right key material (done by virtue of ECDSA over the whole ECDHE exchange?)
40
41    Explicit close message needs to be added.
42
43    Maybe do add some alert messages to give helpful error messages? Not more than TLS sends.
44
45    Use counter mode instead of OFB. (done)
46
47    Make sure ECC operations are fixed time (aka prevent side-channel attacks).
48 */
49
50 void sptps_log_quiet(sptps_t *s, int s_errno, const char *format, va_list ap) {
51         (void)s;
52         (void)s_errno;
53         (void)format;
54         (void)ap;
55
56         assert(format);
57 }
58
59 void sptps_log_stderr(sptps_t *s, int s_errno, const char *format, va_list ap) {
60         (void)s;
61         (void)s_errno;
62
63         assert(format);
64
65         vfprintf(stderr, format, ap);
66         fputc('\n', stderr);
67 }
68
69 void (*sptps_log)(sptps_t *s, int s_errno, const char *format, va_list ap) = sptps_log_quiet;
70
71 // Log an error message.
72 static bool error(sptps_t *s, int s_errno, const char *format, ...) {
73         assert(s_errno);
74         assert(format);
75
76         if(format) {
77                 va_list ap;
78                 va_start(ap, format);
79                 sptps_log(s, s_errno, format, ap);
80                 va_end(ap);
81         }
82
83         errno = s_errno;
84         return false;
85 }
86
87 static void warning(sptps_t *s, const char *format, ...) {
88         assert(format);
89
90         va_list ap;
91         va_start(ap, format);
92         sptps_log(s, 0, format, ap);
93         va_end(ap);
94 }
95
96 // Send a record (datagram version, accepts all record types, handles encryption and authentication).
97 static bool send_record_priv_datagram(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
98         char *buffer = s->outbuf;
99         char local_buffer[len + 21UL];
100
101         if(!buffer || (len + 21UL) > s->outbuflen) {
102                 buffer = local_buffer;
103         }
104
105         // Create header with sequence number, length and record type
106         uint32_t seqno = s->outseqno++;
107         uint32_t netseqno = ntohl(seqno);
108
109         memcpy(buffer, &netseqno, 4);
110         buffer[4] = type;
111         memcpy(buffer + 5, data, len);
112
113         if(s->outstate) {
114                 // If first handshake has finished, encrypt and HMAC
115                 chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 4, len + 1, buffer + 4, NULL);
116                 return s->send_data(s->handle, type, buffer, len + 21UL);
117         } else {
118                 // Otherwise send as plaintext
119                 return s->send_data(s->handle, type, buffer, len + 5UL);
120         }
121 }
122 // Send a record (private version, accepts all record types, handles encryption and authentication).
123 static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
124         if(s->datagram) {
125                 return send_record_priv_datagram(s, type, data, len);
126         }
127
128         char buffer[len + 19UL];
129
130         // Create header with sequence number, length and record type
131         uint32_t seqno = s->outseqno++;
132         uint16_t netlen = htons(len);
133
134         memcpy(buffer, &netlen, 2);
135         buffer[2] = type;
136         memcpy(buffer + 3, data, len);
137
138         if(s->outstate) {
139                 // If first handshake has finished, encrypt and HMAC
140                 chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 2, len + 1, buffer + 2, NULL);
141                 return s->send_data(s->handle, type, buffer, len + 19UL);
142         } else {
143                 // Otherwise send as plaintext
144                 return s->send_data(s->handle, type, buffer, len + 3UL);
145         }
146 }
147
148 // Send an application record.
149 bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
150         assert(!len || data);
151
152         // Sanity checks: application cannot send data before handshake is finished,
153         // and only record types 0..127 are allowed.
154         if(!s->outstate) {
155                 return error(s, EINVAL, "Handshake phase not finished yet");
156         }
157
158         if(type >= SPTPS_HANDSHAKE) {
159                 return error(s, EINVAL, "Invalid application record type");
160         }
161
162         return send_record_priv(s, type, data, len);
163 }
164
165 // Send a Key EXchange record, containing a random nonce and an ECDHE public key.
166 static bool send_kex(sptps_t *s) {
167         size_t keylen = ECDH_SIZE;
168
169         // Make room for our KEX message, which we will keep around since send_sig() needs it.
170         if(s->mykex) {
171                 return false;
172         }
173
174         s->mykex = realloc(s->mykex, 1 + 32 + keylen);
175
176         if(!s->mykex) {
177                 return error(s, errno, strerror(errno));
178         }
179
180         // Set version byte to zero.
181         s->mykex[0] = SPTPS_VERSION;
182
183         // Create a random nonce.
184         randomize(s->mykex + 1, 32);
185
186         // Create a new ECDH public key.
187         if(!(s->ecdh = ecdh_generate_public(s->mykex + 1 + 32))) {
188                 return error(s, EINVAL, "Failed to generate ECDH public key");
189         }
190
191         return send_record_priv(s, SPTPS_HANDSHAKE, s->mykex, 1 + 32 + keylen);
192 }
193
194 // Send a SIGnature record, containing an ECDSA signature over both KEX records.
195 static bool send_sig(sptps_t *s) {
196         size_t keylen = ECDH_SIZE;
197         size_t siglen = ecdsa_size(s->mykey);
198
199         // Concatenate both KEX messages, plus tag indicating if it is from the connection originator, plus label
200         char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
201         char sig[siglen];
202
203         msg[0] = s->initiator;
204         memcpy(msg + 1, s->mykex, 1 + 32 + keylen);
205         memcpy(msg + 1 + 33 + keylen, s->hiskex, 1 + 32 + keylen);
206         memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
207
208         // Sign the result.
209         if(!ecdsa_sign(s->mykey, msg, sizeof(msg), sig)) {
210                 return error(s, EINVAL, "Failed to sign SIG record");
211         }
212
213         // Send the SIG exchange record.
214         return send_record_priv(s, SPTPS_HANDSHAKE, sig, sizeof(sig));
215 }
216
217 // Generate key material from the shared secret created from the ECDHE key exchange.
218 static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
219         assert(shared);
220         assert(len);
221
222         // Initialise cipher and digest structures if necessary
223         if(!s->outstate) {
224                 s->incipher = chacha_poly1305_init();
225                 s->outcipher = chacha_poly1305_init();
226
227                 if(!s->incipher || !s->outcipher) {
228                         return error(s, EINVAL, "Failed to open cipher");
229                 }
230         }
231
232         // Allocate memory for key material
233         size_t keylen = 2 * CHACHA_POLY1305_KEYLEN;
234
235         s->key = realloc(s->key, keylen);
236
237         if(!s->key) {
238                 return error(s, errno, strerror(errno));
239         }
240
241         // Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
242         char seed[s->labellen + 64 + 13];
243         strcpy(seed, "key expansion");
244
245         if(s->initiator) {
246                 memcpy(seed + 13, s->mykex + 1, 32);
247                 memcpy(seed + 45, s->hiskex + 1, 32);
248         } else {
249                 memcpy(seed + 13, s->hiskex + 1, 32);
250                 memcpy(seed + 45, s->mykex + 1, 32);
251         }
252
253         memcpy(seed + 77, s->label, s->labellen);
254
255         // Use PRF to generate the key material
256         if(!prf(shared, len, seed, s->labellen + 64 + 13, s->key, keylen)) {
257                 return error(s, EINVAL, "Failed to generate key material");
258         }
259
260         return true;
261 }
262
263 // Send an ACKnowledgement record.
264 static bool send_ack(sptps_t *s) {
265         return send_record_priv(s, SPTPS_HANDSHAKE, "", 0);
266 }
267
268 // Receive an ACKnowledgement record.
269 static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
270         (void)data;
271
272         if(len) {
273                 return error(s, EIO, "Invalid ACK record length");
274         }
275
276         if(s->initiator) {
277                 if(!chacha_poly1305_set_key(s->incipher, s->key)) {
278                         return error(s, EINVAL, "Failed to set counter");
279                 }
280         } else {
281                 if(!chacha_poly1305_set_key(s->incipher, s->key + CHACHA_POLY1305_KEYLEN)) {
282                         return error(s, EINVAL, "Failed to set counter");
283                 }
284         }
285
286         free(s->key);
287         s->key = NULL;
288         s->instate = true;
289
290         return true;
291 }
292
293 // Receive a Key EXchange record, respond by sending a SIG record.
294 static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
295         // Verify length of the HELLO record
296         if(len != 1 + 32 + ECDH_SIZE) {
297                 return error(s, EIO, "Invalid KEX record length");
298         }
299
300         // Ignore version number for now.
301
302         // Make a copy of the KEX message, send_sig() and receive_sig() need it
303         if(s->hiskex) {
304                 return error(s, EINVAL, "Received a second KEX message before first has been processed");
305         }
306
307         s->hiskex = realloc(s->hiskex, len);
308
309         if(!s->hiskex) {
310                 return error(s, errno, strerror(errno));
311         }
312
313         memcpy(s->hiskex, data, len);
314
315         return send_sig(s);
316 }
317
318 // Receive a SIGnature record, verify it, if it passed, compute the shared secret and calculate the session keys.
319 static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
320         size_t keylen = ECDH_SIZE;
321         size_t siglen = ecdsa_size(s->hiskey);
322
323         // Verify length of KEX record.
324         if(len != siglen) {
325                 return error(s, EIO, "Invalid KEX record length");
326         }
327
328         // Concatenate both KEX messages, plus tag indicating if it is from the connection originator
329         char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
330
331         msg[0] = !s->initiator;
332         memcpy(msg + 1, s->hiskex, 1 + 32 + keylen);
333         memcpy(msg + 1 + 33 + keylen, s->mykex, 1 + 32 + keylen);
334         memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
335
336         // Verify signature.
337         if(!ecdsa_verify(s->hiskey, msg, sizeof(msg), data)) {
338                 return error(s, EIO, "Failed to verify SIG record");
339         }
340
341         // Compute shared secret.
342         char shared[ECDH_SHARED_SIZE];
343
344         if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared)) {
345                 return error(s, EINVAL, "Failed to compute ECDH shared secret");
346         }
347
348         s->ecdh = NULL;
349
350         // Generate key material from shared secret.
351         if(!generate_key_material(s, shared, sizeof(shared))) {
352                 return false;
353         }
354
355         free(s->mykex);
356         free(s->hiskex);
357
358         s->mykex = NULL;
359         s->hiskex = NULL;
360
361         // Send cipher change record
362         if(s->outstate && !send_ack(s)) {
363                 return false;
364         }
365
366         // TODO: only set new keys after ACK has been set/received
367         if(s->initiator) {
368                 if(!chacha_poly1305_set_key(s->outcipher, s->key + CHACHA_POLY1305_KEYLEN)) {
369                         return error(s, EINVAL, "Failed to set key");
370                 }
371         } else {
372                 if(!chacha_poly1305_set_key(s->outcipher, s->key)) {
373                         return error(s, EINVAL, "Failed to set key");
374                 }
375         }
376
377         return true;
378 }
379
380 // Force another Key EXchange (for testing purposes).
381 bool sptps_force_kex(sptps_t *s) {
382         if(!s->outstate || s->state != SPTPS_SECONDARY_KEX) {
383                 return error(s, EINVAL, "Cannot force KEX in current state");
384         }
385
386         s->state = SPTPS_KEX;
387         return send_kex(s);
388 }
389
390 // Receive a handshake record.
391 static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
392         // Only a few states to deal with handshaking.
393         switch(s->state) {
394         case SPTPS_SECONDARY_KEX:
395
396                 // We receive a secondary KEX request, first respond by sending our own.
397                 if(!send_kex(s)) {
398                         return false;
399                 }
400
401         // fallthrough
402         case SPTPS_KEX:
403
404                 // We have sent our KEX request, we expect our peer to sent one as well.
405                 if(!receive_kex(s, data, len)) {
406                         return false;
407                 }
408
409                 s->state = SPTPS_SIG;
410                 return true;
411
412         case SPTPS_SIG:
413
414                 // If we already sent our secondary public ECDH key, we expect the peer to send his.
415                 if(!receive_sig(s, data, len)) {
416                         return false;
417                 }
418
419                 if(s->outstate) {
420                         s->state = SPTPS_ACK;
421                 } else {
422                         s->outstate = true;
423
424                         if(!receive_ack(s, NULL, 0)) {
425                                 return false;
426                         }
427
428                         s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
429                         s->state = SPTPS_SECONDARY_KEX;
430                 }
431
432                 return true;
433
434         case SPTPS_ACK:
435
436                 // We expect a handshake message to indicate transition to the new keys.
437                 if(!receive_ack(s, data, len)) {
438                         return false;
439                 }
440
441                 s->receive_record(s->handle, SPTPS_HANDSHAKE, NULL, 0);
442                 s->state = SPTPS_SECONDARY_KEX;
443                 return true;
444
445         // TODO: split ACK into a VERify and ACK?
446         default:
447                 return error(s, EIO, "Invalid session state %d", s->state);
448         }
449 }
450
451 // Check datagram for valid HMAC
452 bool sptps_verify_datagram(sptps_t *s, const void *data, size_t len) {
453         if(!s->instate) {
454                 return error(s, EIO, "SPTPS state not ready to verify this datagram");
455         }
456
457         if(len < 21) {
458                 return error(s, EIO, "Received short packet in sptps_verify_datagram");
459         }
460
461         uint32_t seqno;
462         memcpy(&seqno, data, 4);
463         seqno = ntohl(seqno);
464         // TODO: check whether seqno makes sense, to avoid CPU intensive decrypt
465
466         return chacha_poly1305_verify(s->incipher, seqno, (const char *)data + 4, len - 4);
467 }
468
469 // Receive incoming data, datagram version.
470 static bool sptps_receive_data_datagram(sptps_t *s, const void *vdata, size_t len) {
471         const char *data = vdata;
472
473         if(len < (s->instate ? 21 : 5)) {
474                 return error(s, EIO, "Received short packet in sptps_receive_data_datagram");
475         }
476
477         uint32_t seqno;
478         memcpy(&seqno, data, 4);
479         seqno = ntohl(seqno);
480
481         if(!s->instate) {
482                 if(seqno != s->inseqno) {
483                         return error(s, EIO, "Invalid packet seqno: %d != %d", seqno, s->inseqno);
484                 }
485
486                 s->inseqno = seqno + 1;
487
488                 uint8_t type = data[4];
489
490                 if(type != SPTPS_HANDSHAKE) {
491                         return error(s, EIO, "Application record received before handshake finished");
492                 }
493
494                 return receive_handshake(s, data + 5, len - 5);
495         }
496
497         // Decrypt
498
499         if(len > s->decrypted_buffer_len) {
500                 s->decrypted_buffer_len *= 2;
501                 char *new_buffer = realloc(s->decrypted_buffer, s->decrypted_buffer_len);
502
503                 if(!new_buffer) {
504                         return error(s, errno, strerror(errno));
505                 }
506
507                 s->decrypted_buffer = new_buffer;
508         }
509
510         size_t outlen;
511
512         if(!chacha_poly1305_decrypt(s->incipher, seqno, data + 4, len - 4, s->decrypted_buffer, &outlen)) {
513                 return error(s, EIO, "Failed to decrypt and verify packet");
514         }
515
516         // Replay protection using a sliding window of configurable size.
517         // s->inseqno is expected sequence number
518         // seqno is received sequence number
519         // s->late[] is a circular buffer, a 1 bit means a packet has not been received yet
520         // The circular buffer contains bits for sequence numbers from s->inseqno - s->replaywin * 8 to (but excluding) s->inseqno.
521         if(s->replaywin) {
522                 if(seqno != s->inseqno) {
523                         if(seqno >= s->inseqno + s->replaywin * 8) {
524                                 // TODO: Prevent packets that jump far ahead of the queue from causing many others to be dropped.
525                                 warning(s, "Lost %d packets\n", seqno - s->inseqno);
526                                 // Mark all packets in the replay window as being late.
527                                 memset(s->late, 255, s->replaywin);
528                         } else if(seqno < s->inseqno) {
529                                 // If the sequence number is farther in the past than the bitmap goes, or if the packet was already received, drop it.
530                                 if((s->inseqno >= s->replaywin * 8 && seqno < s->inseqno - s->replaywin * 8) || !(s->late[(seqno / 8) % s->replaywin] & (1 << seqno % 8))) {
531                                         return error(s, EIO, "Received late or replayed packet, seqno %d, last received %d\n", seqno, s->inseqno);
532                                 }
533                         } else {
534                                 // We missed some packets. Mark them in the bitmap as being late.
535                                 for(uint32_t i = s->inseqno; i < seqno; i++) {
536                                         s->late[(i / 8) % s->replaywin] |= 1 << i % 8;
537                                 }
538                         }
539                 }
540
541                 // Mark the current packet as not being late.
542                 s->late[(seqno / 8) % s->replaywin] &= ~(1 << seqno % 8);
543         }
544
545         if(seqno >= s->inseqno) {
546                 s->inseqno = seqno + 1;
547         }
548
549         if(!s->inseqno) {
550                 s->received = 0;
551         } else {
552                 s->received++;
553         }
554
555         // Append a NULL byte for safety.
556         s->decrypted_buffer[len - 20] = 0;
557
558         uint8_t type = s->decrypted_buffer[0];
559
560         if(type < SPTPS_HANDSHAKE) {
561                 if(!s->instate) {
562                         return error(s, EIO, "Application record received before handshake finished");
563                 }
564
565                 if(!s->receive_record(s->handle, type, s->decrypted_buffer + 1, len - 21)) {
566                         abort();
567                 }
568         } else if(type == SPTPS_HANDSHAKE) {
569                 if(!receive_handshake(s, s->decrypted_buffer + 1, len - 21)) {
570                         abort();
571                 }
572         } else {
573                 return error(s, EIO, "Invalid record type %d", type);
574         }
575
576         return true;
577 }
578
579 // Receive incoming data. Check if it contains a complete record, if so, handle it.
580 bool sptps_receive_data(sptps_t *s, const void *data, size_t len) {
581         if(!s->state) {
582                 return error(s, EIO, "Invalid session state zero");
583         }
584
585         if(s->datagram) {
586                 return sptps_receive_data_datagram(s, data, len);
587         }
588
589         const char *ptr = data;
590
591         while(len) {
592                 // First read the 2 length bytes.
593                 if(s->inbuflen < 2) {
594                         size_t toread = 2 - s->inbuflen;
595
596                         if(toread > len) {
597                                 toread = len;
598                         }
599
600                         memcpy(s->inbuf + s->inbuflen, ptr, toread);
601
602                         s->inbuflen += toread;
603                         len -= toread;
604                         ptr += toread;
605
606                         // Exit early if we don't have the full length.
607                         if(s->inbuflen < 2) {
608                                 return true;
609                         }
610
611                         // Get the length bytes
612
613                         memcpy(&s->reclen, s->inbuf, 2);
614                         s->reclen = ntohs(s->reclen);
615
616                         // If we have the length bytes, ensure our buffer can hold the whole request.
617                         s->inbuf = realloc(s->inbuf, s->reclen + 19UL);
618
619                         if(!s->inbuf) {
620                                 return error(s, errno, strerror(errno));
621                         }
622
623                         // Exit early if we have no more data to process.
624                         if(!len) {
625                                 return true;
626                         }
627                 }
628
629                 // Read up to the end of the record.
630                 size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->inbuflen;
631
632                 if(toread > len) {
633                         toread = len;
634                 }
635
636                 memcpy(s->inbuf + s->inbuflen, ptr, toread);
637                 s->inbuflen += toread;
638                 len -= toread;
639                 ptr += toread;
640
641                 // If we don't have a whole record, exit.
642                 if(s->inbuflen < s->reclen + (s->instate ? 19UL : 3UL)) {
643                         return true;
644                 }
645
646                 // Update sequence number.
647
648                 uint32_t seqno = s->inseqno++;
649
650                 // Check HMAC and decrypt.
651                 if(s->instate) {
652                         if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) {
653                                 return error(s, EINVAL, "Failed to decrypt and verify record");
654                         }
655                 }
656
657                 // Append a NULL byte for safety.
658                 s->inbuf[s->reclen + 3UL] = 0;
659
660                 uint8_t type = s->inbuf[2];
661
662                 if(type < SPTPS_HANDSHAKE) {
663                         if(!s->instate) {
664                                 return error(s, EIO, "Application record received before handshake finished");
665                         }
666
667                         if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) {
668                                 return false;
669                         }
670                 } else if(type == SPTPS_HANDSHAKE) {
671                         if(!receive_handshake(s, s->inbuf + 3, s->reclen)) {
672                                 return false;
673                         }
674                 } else {
675                         return error(s, EIO, "Invalid record type %d", type);
676                 }
677
678                 s->inbuflen = 0;
679         }
680
681         return true;
682 }
683
684 // Start a SPTPS session.
685 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) {
686         if(!s || !mykey || !hiskey || !label || !labellen || !send_data || !receive_record) {
687                 return error(s, EINVAL, "Invalid argument to sptps_start()");
688         }
689
690         // Initialise struct sptps
691         memset(s, 0, sizeof(*s));
692
693         s->handle = handle;
694         s->initiator = initiator;
695         s->datagram = datagram;
696         s->mykey = mykey;
697         s->hiskey = hiskey;
698         s->replaywin = 32;
699         s->decrypted_buffer_len = 1024;
700         s->decrypted_buffer = malloc(s->decrypted_buffer_len);
701
702         if(!s->decrypted_buffer) {
703                 return error(s, errno, strerror(errno));
704         }
705
706         if(s->replaywin) {
707                 s->late = malloc(s->replaywin);
708
709                 if(!s->late) {
710                         return error(s, errno, strerror(errno));
711                 }
712
713                 memset(s->late, 0, s->replaywin);
714         }
715
716         s->label = malloc(labellen);
717
718         if(!s->label) {
719                 return error(s, errno, strerror(errno));
720         }
721
722         if(!datagram) {
723                 s->inbuf = malloc(7);
724
725                 if(!s->inbuf) {
726                         return error(s, errno, strerror(errno));
727                 }
728
729                 s->inbuflen = 0;
730         }
731
732         memcpy(s->label, label, labellen);
733         s->labellen = labellen;
734
735         s->send_data = send_data;
736         s->receive_record = receive_record;
737
738         // Do first KEX immediately
739         s->state = SPTPS_KEX;
740         return send_kex(s);
741 }
742
743 // Stop a SPTPS session.
744 bool sptps_stop(sptps_t *s) {
745         // Clean up any resources.
746         chacha_poly1305_exit(s->incipher);
747         chacha_poly1305_exit(s->outcipher);
748         ecdh_free(s->ecdh);
749         free(s->inbuf);
750         free(s->mykex);
751         free(s->hiskex);
752         free(s->key);
753         free(s->label);
754         free(s->late);
755         memset(s->decrypted_buffer, 0, s->decrypted_buffer_len);
756         free(s->decrypted_buffer);
757         memset(s, 0, sizeof(*s));
758         return true;
759 }
760
761 // Set the buffer to use for outgoing packets.
762 void sptps_set_send_buffer(sptps_t *s, void *data, size_t len) {
763         s->outbuf = data;
764         s->outbuflen = len;
765 }