]> git.meshlink.io Git - meshlink/blob - src/protocol_key.c
Remove everything GPL that is not copyright Guus Sliepen, update copyright statements.
[meshlink] / src / protocol_key.c
1 /*
2     protocol_key.c -- handle the meta-protocol, key exchange
3     Copyright (C) 2014 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 "cipher.h"
23 #include "connection.h"
24 #include "crypto.h"
25 #include "logger.h"
26 #include "net.h"
27 #include "netutl.h"
28 #include "node.h"
29 #include "prf.h"
30 #include "protocol.h"
31 #include "sptps.h"
32 #include "utils.h"
33 #include "xalloc.h"
34
35 static bool mykeyused = false;
36
37 void send_key_changed(void) {
38         send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name);
39
40         /* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
41
42         for list_each(connection_t, c, connection_list)
43                 if(c->status.active && c->node && c->node->status.reachable && !c->node->status.sptps)
44                         send_ans_key(c->node);
45
46         /* Force key exchange for connections using SPTPS */
47
48         if(experimental) {
49                 for splay_each(node_t, n, node_tree)
50                         if(n->status.reachable && n->status.validkey && n->status.sptps)
51                                 sptps_force_kex(&n->sptps);
52         }
53 }
54
55 bool key_changed_h(connection_t *c, const char *request) {
56         char name[MAX_STRING_SIZE];
57         node_t *n;
58
59         if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) {
60                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED",
61                            c->name, c->hostname);
62                 return false;
63         }
64
65         if(seen_request(request))
66                 return true;
67
68         n = lookup_node(name);
69
70         if(!n) {
71                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist",
72                            "KEY_CHANGED", c->name, c->hostname, name);
73                 return true;
74         }
75
76         if(!n->status.sptps) {
77                 n->status.validkey = false;
78                 n->last_req_key = 0;
79         }
80
81         /* Tell the others */
82
83         forward_request(c, request);
84
85         return true;
86 }
87
88 static bool send_initial_sptps_data(void *handle, uint8_t type, const char *data, size_t len) {
89         node_t *to = handle;
90         to->sptps.send_data = send_sptps_data;
91         char buf[len * 4 / 3 + 5];
92         b64encode(data, buf, len);
93         return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_KEY, buf);
94 }
95
96 bool send_req_key(node_t *to) {
97         if(to->status.sptps) {
98                 if(!node_read_ecdsa_public_key(to)) {
99                         logger(DEBUG_PROTOCOL, LOG_DEBUG, "No ECDSA key known for %s (%s)", to->name, to->hostname);
100                         send_request(to->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, to->name, REQ_PUBKEY);
101                         return true;
102                 }
103
104                 if(to->sptps.label)
105                         logger(DEBUG_ALWAYS, LOG_DEBUG, "send_req_key(%s) called while sptps->label != NULL!", to->name);
106
107                 char label[25 + strlen(myself->name) + strlen(to->name)];
108                 snprintf(label, sizeof label, "tinc UDP key expansion %s %s", myself->name, to->name);
109                 sptps_stop(&to->sptps);
110                 to->status.validkey = false;
111                 to->status.waitingforkey = true;
112                 to->last_req_key = now.tv_sec;
113                 to->incompression = myself->incompression;
114                 return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, sizeof label, send_initial_sptps_data, receive_sptps_record);
115         }
116
117         return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
118 }
119
120 /* REQ_KEY is overloaded to allow arbitrary requests to be routed between two nodes. */
121
122 static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, int reqno) {
123         switch(reqno) {
124                 case REQ_PUBKEY: {
125                         char *pubkey = ecdsa_get_base64_public_key(myself->connection->ecdsa);
126                         send_request(from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, from->name, ANS_PUBKEY, pubkey);
127                         free(pubkey);
128                         return true;
129                 }
130
131                 case ANS_PUBKEY: {
132                         if(node_read_ecdsa_public_key(from)) {
133                                 logger(DEBUG_PROTOCOL, LOG_WARNING, "Got ANS_PUBKEY from %s (%s) even though we already have his pubkey", from->name, from->hostname);
134                                 return true;
135                         }
136
137                         char pubkey[MAX_STRING_SIZE];
138                         if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, pubkey) != 1 || !(from->ecdsa = ecdsa_set_base64_public_key(pubkey))) {
139                                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_PUBKEY", from->name, from->hostname, "invalid pubkey");
140                                 return true;
141                         }
142
143                         logger(DEBUG_PROTOCOL, LOG_INFO, "Learned ECDSA public key from %s (%s)", from->name, from->hostname);
144                         append_config_file(from->name, "ECDSAPublicKey", pubkey);
145                         return true;
146                 }
147
148                 case REQ_KEY: {
149                         if(!node_read_ecdsa_public_key(from)) {
150                                 logger(DEBUG_PROTOCOL, LOG_DEBUG, "No ECDSA key known for %s (%s)", from->name, from->hostname);
151                                 send_request(from->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, from->name, REQ_PUBKEY);
152                                 return true;
153                         }
154
155                         if(from->sptps.label)
156                                 logger(DEBUG_ALWAYS, LOG_DEBUG, "Got REQ_KEY from %s while we already started a SPTPS session!", from->name);
157
158                         char buf[MAX_STRING_SIZE];
159                         int len;
160
161                         if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
162                                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS_START", from->name, from->hostname, "invalid SPTPS data");
163                                 return true;
164                         }
165
166                         char label[25 + strlen(from->name) + strlen(myself->name)];
167                         snprintf(label, sizeof label, "tinc UDP key expansion %s %s", from->name, myself->name);
168                         sptps_stop(&from->sptps);
169                         from->status.validkey = false;
170                         from->status.waitingforkey = true;
171                         from->last_req_key = now.tv_sec;
172                         sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record);
173                         sptps_receive_data(&from->sptps, buf, len);
174                         return true;
175                 }
176
177                 case REQ_SPTPS: {
178                         if(!from->status.validkey) {
179                                 logger(DEBUG_PROTOCOL, LOG_ERR, "Got REQ_SPTPS from %s (%s) but we don't have a valid key yet", from->name, from->hostname);
180                                 return true;
181                         }
182
183                         char buf[MAX_STRING_SIZE];
184                         int len;
185                         if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
186                                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS", from->name, from->hostname, "invalid SPTPS data");
187                                 return true;
188                         }
189                         sptps_receive_data(&from->sptps, buf, len);
190                         return true;
191                 }
192
193                 default:
194                         logger(DEBUG_ALWAYS, LOG_ERR, "Unknown extended REQ_KEY request from %s (%s): %s", from->name, from->hostname, request);
195                         return true;
196         }
197 }
198
199 bool req_key_h(connection_t *c, const char *request) {
200         char from_name[MAX_STRING_SIZE];
201         char to_name[MAX_STRING_SIZE];
202         node_t *from, *to;
203         int reqno = 0;
204
205         if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING " %d", from_name, to_name, &reqno) < 2) {
206                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name,
207                            c->hostname);
208                 return false;
209         }
210
211         if(!check_id(from_name) || !check_id(to_name)) {
212                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_KEY", c->name, c->hostname, "invalid name");
213                 return false;
214         }
215
216         from = lookup_node(from_name);
217
218         if(!from) {
219                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
220                            "REQ_KEY", c->name, c->hostname, from_name);
221                 return true;
222         }
223
224         to = lookup_node(to_name);
225
226         if(!to) {
227                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
228                            "REQ_KEY", c->name, c->hostname, to_name);
229                 return true;
230         }
231
232         /* Check if this key request is for us */
233
234         if(to == myself) {                      /* Yes */
235                 /* Is this an extended REQ_KEY message? */
236                 if(experimental && reqno)
237                         return req_key_ext_h(c, request, from, reqno);
238
239                 /* No, just send our key back */
240                 send_ans_key(from);
241         } else {
242                 if(!to->status.reachable) {
243                         logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
244                                 "REQ_KEY", c->name, c->hostname, to_name);
245                         return true;
246                 }
247
248                 send_request(to->nexthop->connection, "%s", request);
249         }
250
251         return true;
252 }
253
254 bool send_ans_key(node_t *to) {
255         if(to->status.sptps)
256                 abort();
257
258         size_t keylen = cipher_keylength(myself->incipher);
259         char key[keylen * 2 + 1];
260
261         cipher_close(to->incipher);
262         digest_close(to->indigest);
263
264         to->incipher = cipher_open_by_nid(cipher_get_nid(myself->incipher));
265         to->indigest = digest_open_by_nid(digest_get_nid(myself->indigest), digest_length(myself->indigest));
266         to->incompression = myself->incompression;
267
268         if(!to->incipher || !to->indigest)
269                 abort();
270
271         randomize(key, keylen);
272         if(!cipher_set_key(to->incipher, key, false))
273                 abort();
274         if(!digest_set_key(to->indigest, key, keylen))
275                 abort();
276
277         bin2hex(key, key, keylen);
278
279         // Reset sequence number and late packet window
280         mykeyused = true;
281         to->received_seqno = 0;
282         to->received = 0;
283         if(replaywin) memset(to->late, 0, replaywin);
284
285         return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
286                                                 myself->name, to->name, key,
287                                                 cipher_get_nid(to->incipher),
288                                                 digest_get_nid(to->indigest),
289                                                 (int)digest_length(to->indigest),
290                                                 to->incompression);
291 }
292
293 bool ans_key_h(connection_t *c, const char *request) {
294         char from_name[MAX_STRING_SIZE];
295         char to_name[MAX_STRING_SIZE];
296         char key[MAX_STRING_SIZE];
297         char address[MAX_STRING_SIZE] = "";
298         char port[MAX_STRING_SIZE] = "";
299         int cipher, digest, maclength, compression, keylen;
300         node_t *from, *to;
301
302         if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
303                 from_name, to_name, key, &cipher, &digest, &maclength,
304                 &compression, address, port) < 7) {
305                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
306                            c->hostname);
307                 return false;
308         }
309
310         if(!check_id(from_name) || !check_id(to_name)) {
311                 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_KEY", c->name, c->hostname, "invalid name");
312                 return false;
313         }
314
315         from = lookup_node(from_name);
316
317         if(!from) {
318                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
319                            "ANS_KEY", c->name, c->hostname, from_name);
320                 return true;
321         }
322
323         to = lookup_node(to_name);
324
325         if(!to) {
326                 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
327                            "ANS_KEY", c->name, c->hostname, to_name);
328                 return true;
329         }
330
331         /* Forward it if necessary */
332
333         if(to != myself) {
334                 if(!to->status.reachable) {
335                         logger(DEBUG_ALWAYS, LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
336                                    "ANS_KEY", c->name, c->hostname, to_name);
337                         return true;
338                 }
339
340                 if(!*address && from->address.sa.sa_family != AF_UNSPEC) {
341                         char *address, *port;
342                         logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
343                         sockaddr2str(&from->address, &address, &port);
344                         send_request(to->nexthop->connection, "%s %s %s", request, address, port);
345                         free(address);
346                         free(port);
347                         return true;
348                 }
349
350                 return send_request(to->nexthop->connection, "%s", request);
351         }
352
353         /* Don't use key material until every check has passed. */
354         cipher_close(from->outcipher);
355         digest_close(from->outdigest);
356         from->status.validkey = false;
357
358         if(compression < 0 || compression > 11) {
359                 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
360                 return true;
361         }
362
363         from->outcompression = compression;
364
365         /* SPTPS or old-style key exchange? */
366
367         if(from->status.sptps) {
368                 char buf[strlen(key)];
369                 int len = b64decode(key, buf, strlen(key));
370
371                 if(!len || !sptps_receive_data(&from->sptps, buf, len))
372                         logger(DEBUG_ALWAYS, LOG_ERR, "Error processing SPTPS data from %s (%s)", from->name, from->hostname);
373
374                 if(from->status.validkey) {
375                         if(*address && *port) {
376                                 logger(DEBUG_PROTOCOL, LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
377                                 sockaddr_t sa = str2sockaddr(address, port);
378                                 update_node_udp(from, &sa);
379                         }
380
381                         if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
382                                 send_mtu_probe(from);
383                 }
384
385                 return true;
386         }
387
388         /* Check and lookup cipher and digest algorithms */
389
390         if(cipher) {
391                 if(!(from->outcipher = cipher_open_by_nid(cipher))) {
392                         logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
393                         return false;
394                 }
395         } else {
396                 from->outcipher = NULL;
397         }
398
399         if(digest) {
400                 if(!(from->outdigest = digest_open_by_nid(digest, maclength))) {
401                         logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
402                         return false;
403                 }
404         } else {
405                 from->outdigest = NULL;
406         }
407
408         if(maclength != digest_length(from->outdigest)) {
409                 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname);
410                 return false;
411         }
412
413         /* Process key */
414
415         keylen = hex2bin(key, key, sizeof key);
416
417         if(keylen != cipher_keylength(from->outcipher)) {
418                 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname);
419                 return true;
420         }
421
422         /* Update our copy of the origin's packet key */
423
424         if(!cipher_set_key(from->outcipher, key, true))
425                 return false;
426         if(!digest_set_key(from->outdigest, key, keylen))
427                 return false;
428
429         from->status.validkey = true;
430         from->sent_seqno = 0;
431
432         if(*address && *port) {
433                 logger(DEBUG_PROTOCOL, LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
434                 sockaddr_t sa = str2sockaddr(address, port);
435                 update_node_udp(from, &sa);
436         }
437
438         if(from->options & OPTION_PMTU_DISCOVERY && !(from->options & OPTION_TCPONLY))
439                 send_mtu_probe(from);
440
441         return true;
442 }