]> git.meshlink.io Git - meshlink/blob - src/sptps.c
Allow a different location for the lock file.
[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[len + 21UL];
99
100         // Create header with sequence number, length and record type
101         uint32_t seqno = s->outseqno++;
102         uint32_t netseqno = ntohl(seqno);
103
104         memcpy(buffer, &netseqno, 4);
105         buffer[4] = type;
106         memcpy(buffer + 5, data, len);
107
108         if(s->outstate) {
109                 // If first handshake has finished, encrypt and HMAC
110                 chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 4, len + 1, buffer + 4, NULL);
111                 return s->send_data(s->handle, type, buffer, len + 21UL);
112         } else {
113                 // Otherwise send as plaintext
114                 return s->send_data(s->handle, type, buffer, len + 5UL);
115         }
116 }
117 // Send a record (private version, accepts all record types, handles encryption and authentication).
118 static bool send_record_priv(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
119         if(s->datagram) {
120                 return send_record_priv_datagram(s, type, data, len);
121         }
122
123         char buffer[len + 19UL];
124
125         // Create header with sequence number, length and record type
126         uint32_t seqno = s->outseqno++;
127         uint16_t netlen = htons(len);
128
129         memcpy(buffer, &netlen, 2);
130         buffer[2] = type;
131         memcpy(buffer + 3, data, len);
132
133         if(s->outstate) {
134                 // If first handshake has finished, encrypt and HMAC
135                 chacha_poly1305_encrypt(s->outcipher, seqno, buffer + 2, len + 1, buffer + 2, NULL);
136                 return s->send_data(s->handle, type, buffer, len + 19UL);
137         } else {
138                 // Otherwise send as plaintext
139                 return s->send_data(s->handle, type, buffer, len + 3UL);
140         }
141 }
142
143 // Send an application record.
144 bool sptps_send_record(sptps_t *s, uint8_t type, const void *data, uint16_t len) {
145         assert(!len || data);
146
147         // Sanity checks: application cannot send data before handshake is finished,
148         // and only record types 0..127 are allowed.
149         if(!s->outstate) {
150                 return error(s, EINVAL, "Handshake phase not finished yet");
151         }
152
153         if(type >= SPTPS_HANDSHAKE) {
154                 return error(s, EINVAL, "Invalid application record type");
155         }
156
157         return send_record_priv(s, type, data, len);
158 }
159
160 // Send a Key EXchange record, containing a random nonce and an ECDHE public key.
161 static bool send_kex(sptps_t *s) {
162         size_t keylen = ECDH_SIZE;
163
164         // Make room for our KEX message, which we will keep around since send_sig() needs it.
165         if(s->mykex) {
166                 return false;
167         }
168
169         s->mykex = realloc(s->mykex, 1 + 32 + keylen);
170
171         if(!s->mykex) {
172                 return error(s, errno, strerror(errno));
173         }
174
175         // Set version byte to zero.
176         s->mykex[0] = SPTPS_VERSION;
177
178         // Create a random nonce.
179         randomize(s->mykex + 1, 32);
180
181         // Create a new ECDH public key.
182         if(!(s->ecdh = ecdh_generate_public(s->mykex + 1 + 32))) {
183                 return error(s, EINVAL, "Failed to generate ECDH public key");
184         }
185
186         return send_record_priv(s, SPTPS_HANDSHAKE, s->mykex, 1 + 32 + keylen);
187 }
188
189 // Send a SIGnature record, containing an ECDSA signature over both KEX records.
190 static bool send_sig(sptps_t *s) {
191         size_t keylen = ECDH_SIZE;
192         size_t siglen = ecdsa_size(s->mykey);
193
194         // Concatenate both KEX messages, plus tag indicating if it is from the connection originator, plus label
195         char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
196         char sig[siglen];
197
198         msg[0] = s->initiator;
199         memcpy(msg + 1, s->mykex, 1 + 32 + keylen);
200         memcpy(msg + 1 + 33 + keylen, s->hiskex, 1 + 32 + keylen);
201         memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
202
203         // Sign the result.
204         if(!ecdsa_sign(s->mykey, msg, sizeof(msg), sig)) {
205                 return error(s, EINVAL, "Failed to sign SIG record");
206         }
207
208         // Send the SIG exchange record.
209         return send_record_priv(s, SPTPS_HANDSHAKE, sig, sizeof(sig));
210 }
211
212 // Generate key material from the shared secret created from the ECDHE key exchange.
213 static bool generate_key_material(sptps_t *s, const char *shared, size_t len) {
214         assert(shared);
215         assert(len);
216
217         // Initialise cipher and digest structures if necessary
218         if(!s->outstate) {
219                 s->incipher = chacha_poly1305_init();
220                 s->outcipher = chacha_poly1305_init();
221
222                 if(!s->incipher || !s->outcipher) {
223                         return error(s, EINVAL, "Failed to open cipher");
224                 }
225         }
226
227         // Allocate memory for key material
228         size_t keylen = 2 * CHACHA_POLY1305_KEYLEN;
229
230         s->key = realloc(s->key, keylen);
231
232         if(!s->key) {
233                 return error(s, errno, strerror(errno));
234         }
235
236         // Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
237         char seed[s->labellen + 64 + 13];
238         strcpy(seed, "key expansion");
239
240         if(s->initiator) {
241                 memcpy(seed + 13, s->mykex + 1, 32);
242                 memcpy(seed + 45, s->hiskex + 1, 32);
243         } else {
244                 memcpy(seed + 13, s->hiskex + 1, 32);
245                 memcpy(seed + 45, s->mykex + 1, 32);
246         }
247
248         memcpy(seed + 77, s->label, s->labellen);
249
250         // Use PRF to generate the key material
251         if(!prf(shared, len, seed, s->labellen + 64 + 13, s->key, keylen)) {
252                 return error(s, EINVAL, "Failed to generate key material");
253         }
254
255         return true;
256 }
257
258 // Send an ACKnowledgement record.
259 static bool send_ack(sptps_t *s) {
260         return send_record_priv(s, SPTPS_HANDSHAKE, "", 0);
261 }
262
263 // Receive an ACKnowledgement record.
264 static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
265         (void)data;
266
267         if(len) {
268                 return error(s, EIO, "Invalid ACK record length");
269         }
270
271         if(s->initiator) {
272                 if(!chacha_poly1305_set_key(s->incipher, s->key)) {
273                         return error(s, EINVAL, "Failed to set counter");
274                 }
275         } else {
276                 if(!chacha_poly1305_set_key(s->incipher, s->key + CHACHA_POLY1305_KEYLEN)) {
277                         return error(s, EINVAL, "Failed to set counter");
278                 }
279         }
280
281         free(s->key);
282         s->key = NULL;
283         s->instate = true;
284
285         return true;
286 }
287
288 // Receive a Key EXchange record, respond by sending a SIG record.
289 static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
290         // Verify length of the HELLO record
291         if(len != 1 + 32 + ECDH_SIZE) {
292                 return error(s, EIO, "Invalid KEX record length");
293         }
294
295         // Ignore version number for now.
296
297         // Make a copy of the KEX message, send_sig() and receive_sig() need it
298         if(s->hiskex) {
299                 return error(s, EINVAL, "Received a second KEX message before first has been processed");
300         }
301
302         s->hiskex = realloc(s->hiskex, len);
303
304         if(!s->hiskex) {
305                 return error(s, errno, strerror(errno));
306         }
307
308         memcpy(s->hiskex, data, len);
309
310         return send_sig(s);
311 }
312
313 // Receive a SIGnature record, verify it, if it passed, compute the shared secret and calculate the session keys.
314 static bool receive_sig(sptps_t *s, const char *data, uint16_t len) {
315         size_t keylen = ECDH_SIZE;
316         size_t siglen = ecdsa_size(s->hiskey);
317
318         // Verify length of KEX record.
319         if(len != siglen) {
320                 return error(s, EIO, "Invalid KEX record length");
321         }
322
323         // Concatenate both KEX messages, plus tag indicating if it is from the connection originator
324         char msg[(1 + 32 + keylen) * 2 + 1 + s->labellen];
325
326         msg[0] = !s->initiator;
327         memcpy(msg + 1, s->hiskex, 1 + 32 + keylen);
328         memcpy(msg + 1 + 33 + keylen, s->mykex, 1 + 32 + keylen);
329         memcpy(msg + 1 + 2 * (33 + keylen), s->label, s->labellen);
330
331         // Verify signature.
332         if(!ecdsa_verify(s->hiskey, msg, sizeof(msg), data)) {
333                 return error(s, EIO, "Failed to verify SIG record");
334         }
335
336         // Compute shared secret.
337         char shared[ECDH_SHARED_SIZE];
338
339         if(!ecdh_compute_shared(s->ecdh, s->hiskex + 1 + 32, shared)) {
340                 return error(s, EINVAL, "Failed to compute ECDH shared secret");
341         }
342
343         s->ecdh = NULL;
344
345         // Generate key material from shared secret.
346         if(!generate_key_material(s, shared, sizeof(shared))) {
347                 return false;
348         }
349
350         free(s->mykex);
351         free(s->hiskex);
352
353         s->mykex = NULL;
354         s->hiskex = NULL;
355
356         // Send cipher change record
357         if(s->outstate && !send_ack(s)) {
358                 return false;
359         }
360
361         // TODO: only set new keys after ACK has been set/received
362         if(s->initiator) {
363                 if(!chacha_poly1305_set_key(s->outcipher, s->key + CHACHA_POLY1305_KEYLEN)) {
364                         return error(s, EINVAL, "Failed to set key");
365                 }
366         } else {
367                 if(!chacha_poly1305_set_key(s->outcipher, s->key)) {
368                         return error(s, EINVAL, "Failed to set key");
369                 }
370         }
371
372         return true;
373 }
374
375 // Force another Key EXchange (for testing purposes).
376 bool sptps_force_kex(sptps_t *s) {
377         if(!s->outstate) {
378                 return error(s, EINVAL, "Cannot force KEX in current state");
379         }
380
381         if(s->state != SPTPS_SECONDARY_KEX) {
382                 // We are already in the middle of a key exchange
383                 return true;
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->buflen < 2) {
594                         size_t toread = 2 - s->buflen;
595
596                         if(toread > len) {
597                                 toread = len;
598                         }
599
600                         memcpy(s->inbuf + s->buflen, ptr, toread);
601
602                         s->buflen += toread;
603                         len -= toread;
604                         ptr += toread;
605
606                         // Exit early if we don't have the full length.
607                         if(s->buflen < 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->buflen;
631
632                 if(toread > len) {
633                         toread = len;
634                 }
635
636                 memcpy(s->inbuf + s->buflen, ptr, toread);
637                 s->buflen += toread;
638                 len -= toread;
639                 ptr += toread;
640
641                 // If we don't have a whole record, exit.
642                 if(s->buflen < 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->buflen = 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->buflen = 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 }