ac710f5da569746632c72bc75845eb592dc1c6fc
[tinc] / src / sptps.c
1 /*
2     sptps.c -- Simple Peer-to-Peer Security
3     Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>,
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 "cipher.h"
23 #include "crypto.h"
24 #include "digest.h"
25 #include "ecdh.h"
26 #include "ecdsa.h"
27 #include "prf.h"
28 #include "sptps.h"
29
30 char *logfilename;
31 #include "utils.c"
32
33 static bool error(sptps_t *s, int s_errno, const char *msg) {
34         fprintf(stderr, "SPTPS error: %s\n", msg);
35         errno = s_errno;
36         return false;
37 }
38
39 static bool send_record_priv(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
40         char plaintext[len + 23];
41         char ciphertext[len + 19];
42
43         // Create header with sequence number, length and record type
44         uint32_t seqno = htonl(s->outseqno++);
45         uint16_t netlen = htons(len);
46
47         memcpy(plaintext, &seqno, 4);
48         memcpy(plaintext + 4, &netlen, 2);
49         plaintext[6] = type;
50
51         // Add plaintext (TODO: avoid unnecessary copy)
52         memcpy(plaintext + 7, data, len);
53
54         if(s->state) {
55                 // If first handshake has finished, encrypt and HMAC
56                 if(!digest_create(&s->outdigest, plaintext, len + 7, plaintext + 7 + len))
57                         return false;
58
59                 if(!cipher_encrypt(&s->outcipher, plaintext + 4, sizeof ciphertext, ciphertext, NULL, false))
60                         return false;
61
62                 return s->send_data(s->handle, ciphertext, len + 19);
63         } else {
64                 // Otherwise send as plaintext
65                 return s->send_data(s->handle, plaintext + 4, len + 3);
66         }
67 }
68
69 bool send_record(sptps_t *s, uint8_t type, const char *data, uint16_t len) {
70         // Sanity checks: application cannot send data before handshake is finished,
71         // and only record types 0..127 are allowed.
72         if(!s->state)
73                 return error(s, EINVAL, "Handshake phase not finished yet");
74
75         if(type & 128)
76                 return error(s, EINVAL, "Invalid application record type");
77
78         return send_record_priv(s, type, data, len);
79 }
80
81 static bool send_kex(sptps_t *s) {
82         size_t keylen = ECDH_SIZE;
83         size_t siglen = ecdsa_size(&s->mykey);
84         char data[32 + keylen + siglen];
85
86         // Create a random nonce.
87         s->myrandom = realloc(s->myrandom, 32);
88         if(!s->myrandom)
89                 return error(s, errno, strerror(errno));
90
91         randomize(s->myrandom, 32);
92         memcpy(data, s->myrandom, 32);
93
94         // Create a new ECDH public key.
95         if(!ecdh_generate_public(&s->ecdh, data + 32))
96                 return false;
97
98         // Sign the former.
99         if(!ecdsa_sign(&s->mykey, data, 32 + keylen, data + 32 + keylen))
100                 return false;
101
102         // Send the handshake record.
103         return send_record_priv(s, 128, data, sizeof data);
104 }
105
106 static bool generate_key_material(sptps_t *s, const char *shared, size_t len, const char *hisrandom) {
107         // Initialise cipher and digest structures if necessary
108         if(!s->state) {
109                 bool result
110                         =  cipher_open_by_name(&s->incipher, "aes-256-ofb")
111                         && cipher_open_by_name(&s->outcipher, "aes-256-ofb")
112                         && digest_open_by_name(&s->indigest, "sha256", 16)
113                         && digest_open_by_name(&s->outdigest, "sha256", 16);
114                 if(!result)
115                         return false;
116         }
117
118         // Allocate memory for key material
119         size_t keylen = digest_keylength(&s->indigest) + digest_keylength(&s->outdigest) + cipher_keylength(&s->incipher) + cipher_keylength(&s->outcipher);
120
121         s->key = realloc(s->key, keylen);
122         if(!s->key)
123                 return error(s, errno, strerror(errno));
124
125         // Create the HMAC seed, which is "key expansion" + session label + server nonce + client nonce
126         char seed[s->labellen + 64 + 13];
127         strcpy(seed, "key expansion");
128         if(s->initiator) {
129                 memcpy(seed + 13, hisrandom, 32);
130                 memcpy(seed + 45, s->myrandom, 32);
131         } else {
132                 memcpy(seed + 13, s->myrandom, 32);
133                 memcpy(seed + 45, hisrandom, 32);
134         }
135         memcpy(seed + 78, s->label, s->labellen);
136
137         // Use PRF to generate the key material
138         if(!prf(shared, len, seed, s->labellen + 64 + 13, s->key, keylen))
139                 return false;
140
141         return true;
142 }
143
144 static bool send_ack(sptps_t *s) {
145         return send_record_priv(s, 128, "", 0);
146 }
147
148 static bool receive_ack(sptps_t *s, const char *data, uint16_t len) {
149         if(len)
150                 return false;
151
152         // TODO: set cipher/digest keys
153         return error(s, ENOSYS, "receive_ack() not completely implemented yet");
154 }
155
156 static bool receive_kex(sptps_t *s, const char *data, uint16_t len) {
157         size_t keylen = ECDH_SIZE;
158         size_t siglen = ecdsa_size(&s->hiskey);
159
160         // Verify length of KEX record.
161         if(len != 32 + keylen + siglen)
162                 return error(s, EIO, "Invalid KEX record length");
163
164         // Verify signature.
165         if(!ecdsa_verify(&s->hiskey, data, 32 + keylen, data + 32 + keylen))
166                 return false;
167
168         // Compute shared secret.
169         char shared[ECDH_SHARED_SIZE];
170         if(!ecdh_compute_shared(&s->ecdh, data + 32, shared))
171                 return false;
172
173         // Generate key material from shared secret.
174         if(!generate_key_material(s, shared, sizeof shared, data))
175                 return false;
176
177         // Send cipher change record if necessary
178         if(s->state)
179                 if(!send_ack(s))
180                         return false;
181
182         // TODO: set cipher/digest keys
183         if(s->initiator) {
184                 bool result
185                         =  cipher_set_key(&s->incipher, s->key, false)
186                         && digest_set_key(&s->indigest, s->key + cipher_keylength(&s->incipher), digest_keylength(&s->indigest))
187                         && cipher_set_key(&s->outcipher, s->key + cipher_keylength(&s->incipher) + digest_keylength(&s->indigest), true)
188                         && digest_set_key(&s->outdigest, s->key + cipher_keylength(&s->incipher) + digest_keylength(&s->indigest) + cipher_keylength(&s->outcipher), digest_keylength(&s->outdigest));
189                 if(!result)
190                         return false;
191         } else {
192                 bool result
193                         =  cipher_set_key(&s->outcipher, s->key, true)
194                         && digest_set_key(&s->outdigest, s->key + cipher_keylength(&s->outcipher), digest_keylength(&s->outdigest))
195                         && cipher_set_key(&s->incipher, s->key + cipher_keylength(&s->outcipher) + digest_keylength(&s->outdigest), false)
196                         && digest_set_key(&s->indigest, s->key + cipher_keylength(&s->outcipher) + digest_keylength(&s->outdigest) + cipher_keylength(&s->incipher), digest_keylength(&s->indigest));
197                 if(!result)
198                         return false;
199         }
200
201         return true;
202 }
203
204 static bool receive_handshake(sptps_t *s, const char *data, uint16_t len) {
205         // Only a few states to deal with handshaking.
206         switch(s->state) {
207                 case 0:
208                         // We have sent our public ECDH key, we expect our peer to sent one as well.
209                         if(!receive_kex(s, data, len))
210                                 return false;
211                         s->state = 1;
212                         return true;
213                 case 1:
214                         // We receive a secondary key exchange request, first respond by sending our own public ECDH key.
215                         if(!send_kex(s))
216                                 return false;
217                 case 2:
218                         // If we already sent our secondary public ECDH key, we expect the peer to send his.
219                         if(!receive_kex(s, data, len))
220                                 return false;
221                         s->state = 3;
222                         return true;
223                 case 3:
224                         // We expect an empty handshake message to indicate transition to the new keys.
225                         if(!receive_ack(s, data, len))
226                                 return false;
227                         s->state = 1;
228                         return true;
229                 default:
230                         return error(s, EIO, "Invalid session state");
231         }
232 }
233
234 bool receive_data(sptps_t *s, const char *data, size_t len) {
235         while(len) {
236                 // First read the 2 length bytes.
237                 if(s->buflen < 6) {
238                         size_t toread = 6 - s->buflen;
239                         if(toread > len)
240                                 toread = len;
241
242                         if(s->state) {
243                                 if(!cipher_decrypt(&s->incipher, data, toread, s->inbuf + s->buflen, NULL, false))
244                                         return false;
245                         } else {
246                                 memcpy(s->inbuf + s->buflen, data, toread);
247                         }
248
249                         s->buflen += toread;
250                         len -= toread;
251                         data += toread;
252
253                         // Exit early if we don't have the full length.
254                         if(s->buflen < 6)
255                                 return true;
256
257                         // If we have the length bytes, ensure our buffer can hold the whole request.
258                         uint16_t reclen;
259                         memcpy(&reclen, s->inbuf + 4, 2);
260                         reclen = htons(reclen);
261                         s->inbuf = realloc(s->inbuf, reclen + 23UL);
262                         if(!s->inbuf)
263                                 return error(s, errno, strerror(errno));
264
265                         // Add sequence number.
266                         uint32_t seqno = htonl(s->inseqno++);
267                         memcpy(s->inbuf, &seqno, 4);
268
269                         // Exit early if we have no more data to process.
270                         if(!len)
271                                 return true;
272                 }
273
274                 // Read up to the end of the record.
275                 uint16_t reclen;
276                 memcpy(&reclen, s->inbuf + 4, 2);
277                 reclen = htons(reclen);
278                 size_t toread = reclen + (s->state ? 23UL : 7UL) - s->buflen;
279                 if(toread > len)
280                         toread = len;
281
282                 if(s->state) {
283                         if(!cipher_decrypt(&s->incipher, data, toread, s->inbuf + s->buflen, NULL, false))
284                                 return false;
285                 } else {
286                         memcpy(s->inbuf + s->buflen, data, toread);
287                 }
288
289                 s->buflen += toread;
290                 len -= toread;
291                 data += toread;
292
293                 // If we don't have a whole record, exit.
294                 if(s->buflen < reclen + (s->state ? 23UL : 7UL))
295                         return true;
296
297                 // Check HMAC.
298                 if(s->state)
299                         if(!digest_verify(&s->indigest, s->inbuf, reclen + 7UL, s->inbuf + reclen + 7UL))
300                                 error(s, EIO, "Invalid HMAC");
301
302                 uint8_t type = s->inbuf[6];
303
304                 // Handle record.
305                 if(type < 128) {
306                         if(!s->receive_record(s->handle, type, s->inbuf + 7, reclen))
307                                 return false;
308                 } else if(type == 128) {
309                         if(!receive_handshake(s, s->inbuf + 7, reclen))
310                                 return false;
311                 } else {
312                         return error(s, EIO, "Invalid record type");
313                 }
314
315                 s->buflen = 4;
316         }
317
318         return true;
319 }
320
321 bool start_sptps(sptps_t *s, void *handle, bool initiator, ecdsa_t mykey, ecdsa_t hiskey, const char *label, size_t labellen, send_data_t send_data, receive_record_t receive_record) {
322         // Initialise struct sptps
323         memset(s, 0, sizeof *s);
324
325         s->handle = handle;
326         s->initiator = initiator;
327         s->mykey = mykey;
328         s->hiskey = hiskey;
329
330         s->label = malloc(labellen);
331         if(!s->label)
332                 return error(s, errno, strerror(errno));
333
334         s->inbuf = malloc(7);
335         if(!s->inbuf)
336                 return error(s, errno, strerror(errno));
337         s->buflen = 4;
338         memset(s->inbuf, 0, 4);
339
340         memcpy(s->label, label, labellen);
341         s->labellen = labellen;
342
343         s->send_data = send_data;
344         s->receive_record = receive_record;
345
346         // Do first KEX immediately
347         return send_kex(s);
348 }
349
350 bool stop_sptps(sptps_t *s) {
351         // Clean up any resources.
352         ecdh_free(&s->ecdh);
353         free(s->inbuf);
354         free(s->myrandom);
355         free(s->key);
356         free(s->label);
357         return true;
358 }