2 protocol_key.c -- handle the meta-protocol, key exchange
3 Copyright (C) 1999-2005 Ivo Timmermans,
4 2000-2017 Guus Sliepen <guus@tinc-vpn.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "connection.h"
37 static bool mykeyused = false;
39 void send_key_changed(void) {
40 #ifndef DISABLE_LEGACY
41 send_request(everyone, "%d %x %s", KEY_CHANGED, rand(), myself->name);
43 /* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
45 for list_each(connection_t, c, connection_list)
46 if(c->edge && c->node && c->node->status.reachable && !c->node->status.sptps) {
47 send_ans_key(c->node);
52 /* Force key exchange for connections using SPTPS */
55 for splay_each(node_t, n, node_tree)
56 if(n->status.reachable && n->status.validkey && n->status.sptps) {
57 sptps_force_kex(&n->sptps);
62 bool key_changed_h(connection_t *c, const char *request) {
63 char name[MAX_STRING_SIZE];
66 if(sscanf(request, "%*d %*x " MAX_STRING, name) != 1) {
67 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "KEY_CHANGED",
68 c->name, c->hostname);
72 if(seen_request(request)) {
76 n = lookup_node(name);
79 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist",
80 "KEY_CHANGED", c->name, c->hostname, name);
84 if(!n->status.sptps) {
85 n->status.validkey = false;
92 forward_request(c, request);
98 static bool send_sptps_data_myself(void *handle, uint8_t type, const void *data, size_t len) {
99 return send_sptps_data(handle, myself, type, data, len);
102 static bool send_initial_sptps_data(void *handle, uint8_t type, const void *data, size_t len) {
104 to->sptps.send_data = send_sptps_data_myself;
105 char buf[len * 4 / 3 + 5];
106 b64encode(data, buf, len);
107 return send_request(to->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, to->name, REQ_KEY, buf);
110 bool send_req_key(node_t *to) {
111 if(to->status.sptps) {
112 if(!node_read_ecdsa_public_key(to)) {
113 logger(DEBUG_PROTOCOL, LOG_DEBUG, "No Ed25519 key known for %s (%s)", to->name, to->hostname);
114 send_request(to->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, to->name, REQ_PUBKEY);
118 char label[25 + strlen(myself->name) + strlen(to->name)];
119 snprintf(label, sizeof(label), "tinc UDP key expansion %s %s", myself->name, to->name);
120 sptps_stop(&to->sptps);
121 to->status.validkey = false;
122 to->status.waitingforkey = true;
123 to->last_req_key = now.tv_sec;
124 to->incompression = myself->incompression;
125 return sptps_start(&to->sptps, to, true, true, myself->connection->ecdsa, to->ecdsa, label, sizeof(label), send_initial_sptps_data, receive_sptps_record);
128 return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
131 /* REQ_KEY is overloaded to allow arbitrary requests to be routed between two nodes. */
133 static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, node_t *to, int reqno) {
134 /* If this is a SPTPS packet, see if sending UDP info helps.
135 Note that we only do this if we're the destination or the static relay;
136 otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
137 if((reqno == REQ_KEY || reqno == SPTPS_PACKET) && to->via == myself) {
138 send_udp_info(myself, from);
141 if(reqno == SPTPS_PACKET) {
142 /* This is a SPTPS data packet. */
144 char buf[MAX_STRING_SIZE];
147 if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
148 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s) to %s (%s): %s", "SPTPS_PACKET", from->name, from->hostname, to->name, to->hostname, "invalid SPTPS data");
153 /* We don't just forward the request, because we want to use UDP if it's available. */
154 if(forwarding_mode == FMODE_INTERNAL) {
155 send_sptps_data(to, from, 0, buf, len);
159 /* The packet is for us */
160 if(!sptps_receive_data(&from->sptps, buf, len)) {
161 /* Uh-oh. It might be that the tunnel is stuck in some corrupted state,
162 so let's restart SPTPS in case that helps. But don't do that too often
163 to prevent storms. */
164 if(from->last_req_key < now.tv_sec - 10) {
165 logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname);
172 send_mtu_info(myself, from, MTU);
178 /* Requests that are not SPTPS data packets are forwarded as-is. */
181 return send_request(to->nexthop->connection, "%s", request);
184 /* The request is for us */
188 if(!node_read_ecdsa_public_key(from)) {
189 /* Request their key *before* we send our key back. Otherwise the first SPTPS packet from them will get dropped. */
190 logger(DEBUG_PROTOCOL, LOG_DEBUG, "Preemptively requesting Ed25519 key for %s (%s)", from->name, from->hostname);
191 send_request(from->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, from->name, REQ_PUBKEY);
194 char *pubkey = ecdsa_get_base64_public_key(myself->connection->ecdsa);
195 send_request(from->nexthop->connection, "%d %s %s %d %s", REQ_KEY, myself->name, from->name, ANS_PUBKEY, pubkey);
201 if(node_read_ecdsa_public_key(from)) {
202 logger(DEBUG_PROTOCOL, LOG_WARNING, "Got ANS_PUBKEY from %s (%s) even though we already have his pubkey", from->name, from->hostname);
206 char pubkey[MAX_STRING_SIZE];
208 if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, pubkey) != 1 || !(from->ecdsa = ecdsa_set_base64_public_key(pubkey))) {
209 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_PUBKEY", from->name, from->hostname, "invalid pubkey");
213 logger(DEBUG_PROTOCOL, LOG_INFO, "Learned Ed25519 public key from %s (%s)", from->name, from->hostname);
214 append_config_file(from->name, "Ed25519PublicKey", pubkey);
219 if(!node_read_ecdsa_public_key(from)) {
220 logger(DEBUG_PROTOCOL, LOG_DEBUG, "No Ed25519 key known for %s (%s)", from->name, from->hostname);
221 send_request(from->nexthop->connection, "%d %s %s %d", REQ_KEY, myself->name, from->name, REQ_PUBKEY);
225 if(from->sptps.label) {
226 logger(DEBUG_ALWAYS, LOG_DEBUG, "Got REQ_KEY from %s while we already started a SPTPS session!", from->name);
229 char buf[MAX_STRING_SIZE];
232 if(sscanf(request, "%*d %*s %*s %*d " MAX_STRING, buf) != 1 || !(len = b64decode(buf, buf, strlen(buf)))) {
233 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_SPTPS_START", from->name, from->hostname, "invalid SPTPS data");
237 char label[25 + strlen(from->name) + strlen(myself->name)];
238 snprintf(label, sizeof(label), "tinc UDP key expansion %s %s", from->name, myself->name);
239 sptps_stop(&from->sptps);
240 from->status.validkey = false;
241 from->status.waitingforkey = true;
242 from->last_req_key = now.tv_sec;
243 sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof(label), send_sptps_data_myself, receive_sptps_record);
244 sptps_receive_data(&from->sptps, buf, len);
245 send_mtu_info(myself, from, MTU);
250 logger(DEBUG_ALWAYS, LOG_ERR, "Unknown extended REQ_KEY request from %s (%s): %s", from->name, from->hostname, request);
255 bool req_key_h(connection_t *c, const char *request) {
256 char from_name[MAX_STRING_SIZE];
257 char to_name[MAX_STRING_SIZE];
261 if(sscanf(request, "%*d " MAX_STRING " " MAX_STRING " %d", from_name, to_name, &reqno) < 2) {
262 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "REQ_KEY", c->name,
267 if(!check_id(from_name) || !check_id(to_name)) {
268 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "REQ_KEY", c->name, c->hostname, "invalid name");
272 from = lookup_node(from_name);
275 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
276 "REQ_KEY", c->name, c->hostname, from_name);
280 to = lookup_node(to_name);
283 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
284 "REQ_KEY", c->name, c->hostname, to_name);
288 /* Check if this key request is for us */
290 if(to == myself) { /* Yes */
291 /* Is this an extended REQ_KEY message? */
292 if(experimental && reqno) {
293 return req_key_ext_h(c, request, from, to, reqno);
296 /* No, just send our key back */
303 if(!to->status.reachable) {
304 logger(DEBUG_PROTOCOL, LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
305 "REQ_KEY", c->name, c->hostname, to_name);
309 /* Is this an extended REQ_KEY message? */
310 if(experimental && reqno) {
311 return req_key_ext_h(c, request, from, to, reqno);
314 send_request(to->nexthop->connection, "%s", request);
320 bool send_ans_key(node_t *to) {
321 if(to->status.sptps) {
325 #ifdef DISABLE_LEGACY
328 size_t keylen = myself->incipher ? cipher_keylength(myself->incipher) : 1;
329 char key[keylen * 2 + 1];
331 randomize(key, keylen);
333 cipher_close(to->incipher);
334 digest_close(to->indigest);
336 if(myself->incipher) {
337 to->incipher = cipher_open_by_nid(cipher_get_nid(myself->incipher));
343 if(!cipher_set_key(to->incipher, key, false)) {
348 if(myself->indigest) {
349 to->indigest = digest_open_by_nid(digest_get_nid(myself->indigest), digest_length(myself->indigest));
355 if(!digest_set_key(to->indigest, key, keylen)) {
360 to->incompression = myself->incompression;
362 bin2hex(key, key, keylen);
364 // Reset sequence number and late packet window
366 to->received_seqno = 0;
370 memset(to->late, 0, replaywin);
373 to->status.validkey_in = true;
375 return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
376 myself->name, to->name, key,
377 cipher_get_nid(to->incipher),
378 digest_get_nid(to->indigest),
379 (int)digest_length(to->indigest),
384 bool ans_key_h(connection_t *c, const char *request) {
385 char from_name[MAX_STRING_SIZE];
386 char to_name[MAX_STRING_SIZE];
387 char key[MAX_STRING_SIZE];
388 char address[MAX_STRING_SIZE] = "";
389 char port[MAX_STRING_SIZE] = "";
390 int cipher, digest, maclength, compression;
393 if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d "MAX_STRING" "MAX_STRING,
394 from_name, to_name, key, &cipher, &digest, &maclength,
395 &compression, address, port) < 7) {
396 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "ANS_KEY", c->name,
401 if(!check_id(from_name) || !check_id(to_name)) {
402 logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "ANS_KEY", c->name, c->hostname, "invalid name");
406 from = lookup_node(from_name);
409 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list",
410 "ANS_KEY", c->name, c->hostname, from_name);
414 to = lookup_node(to_name);
417 logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list",
418 "ANS_KEY", c->name, c->hostname, to_name);
422 /* Forward it if necessary */
429 if(!to->status.reachable) {
430 logger(DEBUG_ALWAYS, LOG_WARNING, "Got %s from %s (%s) destination %s which is not reachable",
431 "ANS_KEY", c->name, c->hostname, to_name);
435 if(!*address && from->address.sa.sa_family != AF_UNSPEC && to->minmtu) {
436 char *address, *port;
437 logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
438 sockaddr2str(&from->address, &address, &port);
439 send_request(to->nexthop->connection, "%s %s %s", request, address, port);
445 return send_request(to->nexthop->connection, "%s", request);
448 #ifndef DISABLE_LEGACY
449 /* Don't use key material until every check has passed. */
450 cipher_close(from->outcipher);
451 digest_close(from->outdigest);
454 if(!from->status.sptps) {
455 from->status.validkey = false;
458 if(compression < 0 || compression > 11) {
459 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
463 from->outcompression = compression;
465 /* SPTPS or old-style key exchange? */
467 if(from->status.sptps) {
468 char buf[strlen(key)];
469 int len = b64decode(key, buf, strlen(key));
471 if(!len || !sptps_receive_data(&from->sptps, buf, len)) {
472 /* Uh-oh. It might be that the tunnel is stuck in some corrupted state,
473 so let's restart SPTPS in case that helps. But don't do that too often
475 Note that simply relying on handshake timeout is not enough, because
476 that doesn't apply to key regeneration. */
477 if(from->last_req_key < now.tv_sec - 10) {
478 logger(DEBUG_PROTOCOL, LOG_ERR, "Failed to decode handshake TCP packet from %s (%s), restarting SPTPS", from->name, from->hostname);
485 if(from->status.validkey) {
486 if(*address && *port) {
487 logger(DEBUG_PROTOCOL, LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
488 sockaddr_t sa = str2sockaddr(address, port);
489 update_node_udp(from, &sa);
493 send_mtu_info(myself, from, MTU);
498 #ifdef DISABLE_LEGACY
499 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses legacy protocol!", from->name, from->hostname);
502 /* Check and lookup cipher and digest algorithms */
505 if(!(from->outcipher = cipher_open_by_nid(cipher))) {
506 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown cipher!", from->name, from->hostname);
510 from->outcipher = NULL;
514 if(!(from->outdigest = digest_open_by_nid(digest, maclength))) {
515 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses unknown digest!", from->name, from->hostname);
519 from->outdigest = NULL;
522 if(maclength != digest_length(from->outdigest)) {
523 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus MAC length!", from->name, from->hostname);
529 int keylen = hex2bin(key, key, sizeof(key));
531 if(keylen != (from->outcipher ? cipher_keylength(from->outcipher) : 1)) {
532 logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses wrong keylength!", from->name, from->hostname);
536 /* Update our copy of the origin's packet key */
538 if(from->outcipher && !cipher_set_key(from->outcipher, key, true)) {
542 if(from->outdigest && !digest_set_key(from->outdigest, key, keylen)) {
546 from->status.validkey = true;
547 from->sent_seqno = 0;
549 if(*address && *port) {
550 logger(DEBUG_PROTOCOL, LOG_DEBUG, "Using reflexive UDP address from %s: %s port %s", from->name, address, port);
551 sockaddr_t sa = str2sockaddr(address, port);
552 update_node_udp(from, &sa);