84bd07198e4de0f71a03fd2428a1d6062a6ac4e0
[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         size_t 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_WINDOWS
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_WINDOWS
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_WINDOWS
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                 fclose(fp);
138                 return false;
139         }
140
141         if(s.st_mode & ~0100700u) {
142                 logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for Ed25519 private key file `%s'!", fname);
143         }
144
145 #endif
146
147         ecdsa_t *key = ecdsa_read_pem_private_key(fp);
148         fclose(fp);
149
150         if(!key) {
151                 logger(DEBUG_ALWAYS, LOG_ERR, "Reading Ed25519 private key file `%s' failed", fname);
152                 free(fname);
153                 return NULL;
154         }
155
156         if(keyfile) {
157                 *keyfile = fname;
158         } else {
159                 free(fname);
160         }
161
162         return key;
163 }
164
165 bool read_ecdsa_public_key(ecdsa_t **ecdsa, splay_tree_t **config_tree, const char *name) {
166         if(ecdsa_active(*ecdsa)) {
167                 return true;
168         }
169
170         FILE *fp;
171         char *fname;
172         char *p;
173
174         if(!*config_tree) {
175                 *config_tree = create_configuration();
176
177                 if(!read_host_config(*config_tree, name, true)) {
178                         return false;
179                 }
180         }
181
182         /* First, check for simple Ed25519PublicKey statement */
183
184         if(get_config_string(lookup_config(*config_tree, "Ed25519PublicKey"), &p)) {
185                 *ecdsa = ecdsa_set_base64_public_key(p);
186                 free(p);
187                 return *ecdsa != NULL;
188         }
189
190         /* Else, check for Ed25519PublicKeyFile statement and read it */
191
192         if(!get_config_string(lookup_config(*config_tree, "Ed25519PublicKeyFile"), &fname)) {
193                 xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
194         }
195
196         fp = fopen(fname, "r");
197
198         if(!fp) {
199                 logger(DEBUG_ALWAYS, LOG_ERR, "Error reading Ed25519 public key file `%s': %s",
200                        fname, strerror(errno));
201                 free(fname);
202                 return false;
203         }
204
205         *ecdsa = ecdsa_read_pem_public_key(fp);
206
207         if(!*ecdsa && errno != ENOENT) {
208                 logger(DEBUG_ALWAYS, LOG_ERR, "Parsing Ed25519 public key file `%s' failed.", fname);
209         }
210
211         fclose(fp);
212         free(fname);
213
214         return *ecdsa != NULL;
215 }
216
217 #ifndef DISABLE_LEGACY
218 rsa_t *read_rsa_private_key(splay_tree_t *config_tree, char **keyfile) {
219         FILE *fp;
220         char *fname;
221         char *n, *d;
222         rsa_t *key;
223
224         /* First, check for simple PrivateKey statement */
225
226         config_t *rsa_priv_conf = lookup_config(config_tree, "PrivateKey");
227
228         if(get_config_string(rsa_priv_conf, &d)) {
229                 if(!get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
230                         logger(DEBUG_ALWAYS, LOG_ERR, "PrivateKey used but no PublicKey found!");
231                         free_string(d);
232                         return NULL;
233                 }
234
235                 key = rsa_set_hex_private_key(n, "FFFF", d);
236                 free(n);
237                 free_string(d);
238
239                 if(key && keyfile && rsa_priv_conf->file) {
240                         *keyfile = xstrdup(rsa_priv_conf->file);
241                 }
242
243                 return key;
244         }
245
246         /* Else, check for PrivateKeyFile statement and read it */
247
248         if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname)) {
249                 xasprintf(&fname, "%s" SLASH "rsa_key.priv", confbase);
250         }
251
252         fp = fopen(fname, "r");
253
254         if(!fp) {
255                 logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA private key file `%s': %s",
256                        fname, strerror(errno));
257
258                 if(errno == ENOENT) {
259                         logger(DEBUG_ALWAYS, LOG_INFO, "Create an RSA key pair with `tinc -n %s generate-rsa-keys'.", netname ? netname : ".");
260                 }
261
262                 free(fname);
263                 return NULL;
264         }
265
266 #ifndef HAVE_WINDOWS
267         struct stat s;
268
269         if(fstat(fileno(fp), &s)) {
270                 logger(DEBUG_ALWAYS, LOG_ERR, "Could not stat RSA private key file `%s': %s'", fname, strerror(errno));
271                 free(fname);
272                 fclose(fp);
273                 return NULL;
274         }
275
276         if(s.st_mode & ~0100700u) {
277                 logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: insecure file permissions for RSA private key file `%s'!", fname);
278         }
279
280 #endif
281
282         key = rsa_read_pem_private_key(fp);
283         fclose(fp);
284
285         if(!key) {
286                 logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA private key file `%s' failed: %s", fname, strerror(errno));
287                 free(fname);
288                 return NULL;
289         }
290
291         if(keyfile) {
292                 *keyfile = fname;
293         } else {
294                 free(fname);
295         }
296
297         return key;
298 }
299
300 rsa_t *read_rsa_public_key(splay_tree_t *config_tree, const char *name) {
301         FILE *fp;
302         char *fname;
303         char *n;
304
305         /* First, check for simple PublicKey statement */
306
307         if(get_config_string(lookup_config(config_tree, "PublicKey"), &n)) {
308                 rsa_t *rsa = rsa_set_hex_public_key(n, "FFFF");
309                 free(n);
310                 return rsa;
311         }
312
313         /* Else, check for PublicKeyFile statement and read it */
314
315         if(!get_config_string(lookup_config(config_tree, "PublicKeyFile"), &fname)) {
316                 xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
317         }
318
319         fp = fopen(fname, "r");
320
321         if(!fp) {
322                 logger(DEBUG_ALWAYS, LOG_ERR, "Error reading RSA public key file `%s': %s", fname, strerror(errno));
323                 free(fname);
324                 return false;
325         }
326
327         rsa_t *rsa = rsa_read_pem_public_key(fp);
328         fclose(fp);
329
330         if(!rsa) {
331                 logger(DEBUG_ALWAYS, LOG_ERR, "Reading RSA public key file `%s' failed: %s", fname, strerror(errno));
332         }
333
334         free(fname);
335
336         return rsa;
337 }
338 #endif