c857fb63503b5cfdf3bdd952b155b47f99417c92
[tinc] / src / keys.c
1 #include "system.h"
2 #include "keys.h"
3 #include "conf.h"
4 #include "logger.h"
5 #include "names.h"
6 #include "xalloc.h"
7 #include "ecdsa.h"
8 #include "utils.h"
9
10 bool disable_old_keys(const char *filename, const char *what) {
11         char tmpfile[PATH_MAX] = "";
12         char buf[1024];
13         bool disabled = false;
14         bool block = false;
15         bool error = false;
16
17         FILE *r = fopen(filename, "r");
18         FILE *w = NULL;
19
20         if(!r) {
21                 return false;
22         }
23
24         int result = snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
25
26         if(result < sizeof(tmpfile)) {
27                 struct stat st = {.st_mode = 0600};
28                 fstat(fileno(r), &st);
29                 w = fopenmask(tmpfile, "w", st.st_mode);
30         }
31
32         while(fgets(buf, sizeof(buf), r)) {
33                 if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
34                         if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
35                                 disabled = true;
36                                 block = true;
37                         }
38                 }
39
40                 bool ed25519pubkey = !strncasecmp(buf, "Ed25519PublicKey", 16) && strchr(" \t=", buf[16]) && strstr(what, "Ed25519");
41
42                 if(ed25519pubkey) {
43                         disabled = true;
44                 }
45
46                 if(w) {
47                         if(block || ed25519pubkey) {
48                                 fputc('#', w);
49                         }
50
51                         if(fputs(buf, w) < 0) {
52                                 error = true;
53                                 break;
54                         }
55                 }
56
57                 if(block && !strncmp(buf, "-----END ", 9)) {
58                         block = false;
59                 }
60         }
61
62         if(w)
63                 if(fclose(w) < 0) {
64                         error = true;
65                 }
66
67         if(ferror(r) || fclose(r) < 0) {
68                 error = true;
69         }
70
71         if(disabled) {
72                 if(!w || error) {
73                         fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
74
75                         if(w) {
76                                 unlink(tmpfile);
77                         }
78
79                         return false;
80                 }
81
82 #ifdef HAVE_MINGW
83                 // We cannot atomically replace files on Windows.
84                 char bakfile[PATH_MAX] = "";
85                 snprintf(bakfile, sizeof(bakfile), "%s.bak", filename);
86
87                 if(rename(filename, bakfile) || rename(tmpfile, filename)) {
88                         rename(bakfile, filename);
89 #else
90
91                 if(rename(tmpfile, filename)) {
92 #endif
93                         fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
94                         unlink(tmpfile);
95                         return false;
96                 }
97
98 #ifdef HAVE_MINGW
99                 unlink(bakfile);
100 #endif
101                 fprintf(stderr, "Warning: old key(s) found and disabled.\n");
102         }
103
104         unlink(tmpfile);
105         return true;
106 }
107
108 ecdsa_t *read_ecdsa_private_key(splay_tree_t *config_tree, char **keyfile) {
109         FILE *fp;
110         char *fname;
111
112         /* Check for PrivateKeyFile statement and read it */
113
114         if(!get_config_string(lookup_config(config_tree, "Ed25519PrivateKeyFile"), &fname)) {
115                 xasprintf(&fname, "%s" SLASH "ed25519_key.priv", confbase);
116         }
117
118         fp = fopen(fname, "r");
119
120         if(!fp) {
121                 logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 private key file `%s': %s", fname, strerror(errno));
122
123                 if(errno == ENOENT) {
124                         logger(DEBUG_ALWAYS, LOG_INFO, "Create an Ed25519 key pair with `tinc -n %s generate-ed25519-keys'.", netname ? netname : ".");
125                 }
126
127                 free(fname);
128                 return NULL;
129         }
130
131 #ifndef HAVE_MINGW
132         struct stat s;
133
134         if(fstat(fileno(fp), &s)) {
135                 logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat Ed25519 private key file `%s': %s'", fname, strerror(errno));
136                 free(fname);
137                 return false;
138         }
139
140         if(s.st_mode & ~0100700u) {
141                 logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for Ed25519 private key file `%s'!", fname);
142         }
143
144 #endif
145
146         ecdsa_t *key = ecdsa_read_pem_private_key(fp);
147         fclose(fp);
148
149         if(!key) {
150                 logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname);
151                 free(fname);
152                 return NULL;
153         }
154
155         if(keyfile) {
156                 *keyfile = fname;
157         } else {
158                 free(fname);
159         }
160
161         return key;
162 }
163
164 bool read_ecdsa_public_key(ecdsa_t **ecdsa, splay_tree_t **config_tree, const char *name) {
165         if(ecdsa_active(*ecdsa)) {
166                 return true;
167         }
168
169         FILE *fp;
170         char *fname;
171         char *p;
172
173         if(!*config_tree) {
174                 init_configuration(config_tree);
175
176                 if(!read_host_config(*config_tree, name, true)) {
177                         return false;
178                 }
179         }
180
181         /* First, check for simple Ed25519PublicKey statement */
182
183         if(get_config_string(lookup_config(*config_tree, "Ed25519PublicKey"), &p)) {
184                 *ecdsa = ecdsa_set_base64_public_key(p);
185                 free(p);
186                 return *ecdsa != NULL;
187         }
188
189         /* Else, check for Ed25519PublicKeyFile statement and read it */
190
191         if(!get_config_string(lookup_config(*config_tree, "Ed25519PublicKeyFile"), &fname)) {
192                 xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
193         }
194
195         fp = fopen(fname, "r");
196
197         if(!fp) {
198                 logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 public key file `%s': %s",
199                        fname, strerror(errno));
200                 free(fname);
201                 return false;
202         }
203
204         *ecdsa = ecdsa_read_pem_public_key(fp);
205
206         if(!*ecdsa && errno != ENOENT) {
207                 logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname);
208         }
209
210         fclose(fp);
211         free(fname);
212
213         return *ecdsa != NULL;
214 }
215
216 #ifndef DISABLE_LEGACY
217 rsa_t *read_rsa_private_key(splay_tree_t *config_tree, char **keyfile) {
218         FILE *fp;
219         char *fname;
220         char *n, *d;
221         rsa_t *key;
222
223         /* First, check for simple PrivateKey statement */
224
225         config_t *rsa_priv_conf = lookup_config(config_tree, "PrivateKey");
226
227         if(get_config_string(rsa_priv_conf, &d)) {
228                 if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
229                         logger(DEBUG_ALWAYS, LOG_ERR, "PrivateKey used but no PublicKey found!");
230                         free(d);
231                         return NULL;
232                 }
233
234                 key = rsa_set_hex_private_key(n, "FFFF", d);
235                 free(n);
236                 free(d);
237
238                 if(key && keyfile && rsa_priv_conf->file) {
239                         *keyfile = xstrdup(rsa_priv_conf->file);
240                 }
241
242                 return key;
243         }
244
245         /* Else, check for PrivateKeyFile statement and read it */
246
247         if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) {
248                 xasprintf(&fname, "%s" SLASH "rsa_key.priv", confbase);
249         }
250
251         fp = fopen(fname, "r");
252
253         if(!fp) {
254                 logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA private key file `%s': %s",
255                        fname, strerror(errno));
256
257                 if(errno == ENOENT) {
258                         logger(DEBUG_ALWAYS, LOG_INFO, "Create an RSA key pair with `tinc -n %s generate-rsa-keys'.", netname ? netname : ".");
259                 }
260
261                 free(fname);
262                 return NULL;
263         }
264
265 #ifndef HAVE_MINGW
266         struct stat s;
267
268         if(fstat(fileno(fp), &s)) {
269                 logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
270                 free(fname);
271                 return NULL;
272         }
273
274         if(s.st_mode & ~0100700u) {
275                 logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
276         }
277
278 #endif
279
280         key = rsa_read_pem_private_key(fp);
281         fclose(fp);
282
283         if(!key) {
284                 logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
285                 free(fname);
286                 return NULL;
287         }
288
289         if(keyfile) {
290                 *keyfile = fname;
291         } else {
292                 free(fname);
293         }
294
295         return key;
296 }
297
298 bool read_rsa_public_key(rsa_t **rsa, splay_tree_t *config_tree, const char *name) {
299         FILE *fp;
300         char *fname;
301         char *n;
302
303         /* First, check for simple PublicKey statement */
304
305         if(get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
306                 *rsa = rsa_set_hex_public_key(n, "FFFF");
307                 free(n);
308                 return *rsa != NULL;
309         }
310
311         /* Else, check for PublicKeyFile statement and read it */
312
313         if(!get_config_string(lookup_config(config_tree, "PublicKeyFile"), &fname)) {
314                 xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
315         }
316
317         fp = fopen(fname, "r");
318
319         if(!fp) {
320                 logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
321                 free(fname);
322                 return false;
323         }
324
325         *rsa = rsa_read_pem_public_key(fp);
326         fclose(fp);
327
328         if(!*rsa) {
329                 logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
330         }
331
332         free(fname);
333
334         return *rsa != NULL;
335 }
336 #endif