Big header file cleanup: everything that has to do with standard system
[tinc] / src / protocol_key.c
1 /*
2     protocol_key.c -- handle the meta-protocol, key exchange
3     Copyright (C) 1999-2003 Ivo Timmermans <ivo@o2w.nl>,
4                   2000-2003 Guus Sliepen <guus@sliepen.eu.org>
5
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.
10
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.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: protocol_key.c,v 1.1.4.19 2003/07/17 15:06:26 guus Exp $
21 */
22
23 #include "system.h"
24
25 #include "avl_tree.h"
26 #include "connection.h"
27 #include "logger.h"
28 #include "net.h"
29 #include "netutl.h"
30 #include "node.h"
31 #include "protocol.h"
32 #include "utils.h"
33 #include "xalloc.h"
34
35 int mykeyused = 0;
36
37 int send_key_changed(connection_t *c, node_t *n)
38 {
39         cp();
40
41         /* Only send this message if some other daemon requested our key previously.
42            This reduces unnecessary key_changed broadcasts.
43          */
44
45         if(n == myself && !mykeyused)
46                 return 0;
47
48         return send_request(c, "%d %lx %s", KEY_CHANGED, random(), n->name);
49 }
50
51 int key_changed_h(connection_t *c)
52 {
53         char name[MAX_STRING_SIZE];
54         node_t *n;
55
56         cp();
57
58         if(sscanf(c->buffer, "%*d %*x " MAX_STRING, name) != 1) {
59                 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "KEY_CHANGED",
60                            c->name, c->hostname);
61                 return -1;
62         }
63
64         if(seen_request(c->buffer))
65                 return 0;
66
67         n = lookup_node(name);
68
69         if(!n) {
70                 logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist"),
71                            "KEY_CHANGED", c->name, c->hostname, name);
72                 return -1;
73         }
74
75         n->status.validkey = 0;
76         n->status.waitingforkey = 0;
77
78         /* Tell the others */
79
80         forward_request(c);
81
82         return 0;
83 }
84
85 int send_req_key(connection_t *c, node_t *from, node_t *to)
86 {
87         cp();
88
89         return send_request(c, "%d %s %s", REQ_KEY, from->name, to->name);
90 }
91
92 int req_key_h(connection_t *c)
93 {
94         char from_name[MAX_STRING_SIZE];
95         char to_name[MAX_STRING_SIZE];
96         node_t *from, *to;
97
98         cp();
99
100         if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, from_name, to_name) != 2) {
101                 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "REQ_KEY", c->name,
102                            c->hostname);
103                 return -1;
104         }
105
106         from = lookup_node(from_name);
107
108         if(!from) {
109                 logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"),
110                            "REQ_KEY", c->name, c->hostname, from_name);
111                 return -1;
112         }
113
114         to = lookup_node(to_name);
115
116         if(!to) {
117                 logger(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"),
118                            "REQ_KEY", c->name, c->hostname, to_name);
119                 return -1;
120         }
121
122         /* Check if this key request is for us */
123
124         if(to == myself) {                      /* Yes, send our own key back */
125                 mykeyused = 1;
126                 from->received_seqno = 0;
127                 memset(from->late, 0, sizeof(from->late));
128                 send_ans_key(c, myself, from);
129         } else {
130                 send_req_key(to->nexthop->connection, from, to);
131         }
132
133         return 0;
134 }
135
136 int send_ans_key(connection_t *c, node_t *from, node_t *to)
137 {
138         char key[MAX_STRING_SIZE];
139
140         cp();
141
142         bin2hex(from->key, key, from->keylength);
143         key[from->keylength * 2] = '\0';
144
145         return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY,
146                                                 from->name, to->name, key,
147                                                 from->cipher ? from->cipher->nid : 0,
148                                                 from->digest ? from->digest->type : 0, from->maclength,
149                                                 from->compression);
150 }
151
152 int ans_key_h(connection_t *c)
153 {
154         char from_name[MAX_STRING_SIZE];
155         char to_name[MAX_STRING_SIZE];
156         char key[MAX_STRING_SIZE];
157         int cipher, digest, maclength, compression;
158         node_t *from, *to;
159
160         cp();
161
162         if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d %d %d",
163                 from_name, to_name, key, &cipher, &digest, &maclength,
164                 &compression) != 7) {
165                 logger(LOG_ERR, _("Got bad %s from %s (%s)"), "ANS_KEY", c->name,
166                            c->hostname);
167                 return -1;
168         }
169
170         from = lookup_node(from_name);
171
172         if(!from) {
173                 logger(LOG_ERR, _("Got %s from %s (%s) origin %s which does not exist in our connection list"),
174                            "ANS_KEY", c->name, c->hostname, from_name);
175                 return -1;
176         }
177
178         to = lookup_node(to_name);
179
180         if(!to) {
181                 logger(LOG_ERR, _("Got %s from %s (%s) destination %s which does not exist in our connection list"),
182                            "ANS_KEY", c->name, c->hostname, to_name);
183                 return -1;
184         }
185
186         /* Forward it if necessary */
187
188         if(to != myself) {
189                 return send_request(to->nexthop->connection, "%s", c->buffer);
190         }
191
192         /* Update our copy of the origin's packet key */
193
194         if(from->key)
195                 free(from->key);
196
197         from->key = xstrdup(key);
198         from->keylength = strlen(key) / 2;
199         hex2bin(from->key, from->key, from->keylength);
200         from->key[from->keylength] = '\0';
201
202         from->status.validkey = 1;
203         from->status.waitingforkey = 0;
204         from->sent_seqno = 0;
205
206         /* Check and lookup cipher and digest algorithms */
207
208         if(cipher) {
209                 from->cipher = EVP_get_cipherbynid(cipher);
210
211                 if(!from->cipher) {
212                         logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name,
213                                    from->hostname);
214                         return -1;
215                 }
216
217                 if(from->keylength != from->cipher->key_len + from->cipher->iv_len) {
218                         logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name,
219                                    from->hostname);
220                         return -1;
221                 }
222         } else {
223                 from->cipher = NULL;
224         }
225
226         from->maclength = maclength;
227
228         if(digest) {
229                 from->digest = EVP_get_digestbynid(digest);
230
231                 if(!from->digest) {
232                         logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name,
233                                    from->hostname);
234                         return -1;
235                 }
236
237                 if(from->maclength > from->digest->md_size || from->maclength < 0) {
238                         logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"),
239                                    from->name, from->hostname);
240                         return -1;
241                 }
242         } else {
243                 from->digest = NULL;
244         }
245
246         if(compression < 0 || compression > 11) {
247                 logger(LOG_ERR, _("Node %s (%s) uses bogus compression level!"), from->name, from->hostname);
248                 return -1;
249         }
250         
251         from->compression = compression;
252
253         EVP_EncryptInit_ex(&from->packet_ctx, from->cipher, NULL, from->key, from->key + from->cipher->key_len);
254
255         flush_queue(from);
256
257         return 0;
258 }