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