/src/tor/src/feature/keymgt/loadkey.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2001 Matej Pfajfar. |
2 | | * Copyright (c) 2001-2004, Roger Dingledine. |
3 | | * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. |
4 | | * Copyright (c) 2007-2021, The Tor Project, Inc. */ |
5 | | /* See LICENSE for licensing information */ |
6 | | |
7 | | /** |
8 | | * \file loadkey.c |
9 | | * \brief Read keys from disk, creating as needed |
10 | | * |
11 | | * This code is shared by relays and onion services, which both need |
12 | | * this functionality. |
13 | | **/ |
14 | | |
15 | | #include "core/or/or.h" |
16 | | #include "app/config/config.h" |
17 | | #include "app/main/main.h" |
18 | | #include "feature/keymgt/loadkey.h" |
19 | | #include "feature/nodelist/torcert.h" |
20 | | |
21 | | #include "lib/crypt_ops/crypto_pwbox.h" |
22 | | #include "lib/crypt_ops/crypto_util.h" |
23 | | #include "lib/term/getpass.h" |
24 | | #include "lib/crypt_ops/crypto_format.h" |
25 | | |
26 | 0 | #define ENC_KEY_HEADER "Boxed Ed25519 key" |
27 | 0 | #define ENC_KEY_TAG "master" |
28 | | |
29 | | #ifdef HAVE_UNISTD_H |
30 | | #include <unistd.h> |
31 | | #endif |
32 | | |
33 | | /** Try to read an RSA key from <b>fname</b>. If <b>fname</b> doesn't exist |
34 | | * and <b>generate</b> is true, create a new RSA key and save it in |
35 | | * <b>fname</b>. Return the read/created key, or NULL on error. Log all |
36 | | * errors at level <b>severity</b>. If <b>created_out</b> is non-NULL and a |
37 | | * new key was created, set *<b>created_out</b> to true. |
38 | | */ |
39 | | crypto_pk_t * |
40 | | init_key_from_file(const char *fname, int generate, int severity, |
41 | | bool *created_out) |
42 | 0 | { |
43 | 0 | crypto_pk_t *prkey = NULL; |
44 | |
|
45 | 0 | if (created_out) { |
46 | 0 | *created_out = false; |
47 | 0 | } |
48 | |
|
49 | 0 | if (!(prkey = crypto_pk_new())) { |
50 | 0 | tor_log(severity, LD_GENERAL,"Error constructing key"); |
51 | 0 | goto error; |
52 | 0 | } |
53 | | |
54 | 0 | switch (file_status(fname)) { |
55 | 0 | case FN_DIR: |
56 | 0 | case FN_ERROR: |
57 | 0 | tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname); |
58 | 0 | goto error; |
59 | | /* treat empty key files as if the file doesn't exist, and, |
60 | | * if generate is set, replace the empty file in |
61 | | * crypto_pk_write_private_key_to_filename() */ |
62 | 0 | case FN_NOENT: |
63 | 0 | case FN_EMPTY: |
64 | 0 | if (generate) { |
65 | 0 | if (!have_lockfile()) { |
66 | 0 | if (try_locking(get_options(), 0)<0) { |
67 | | /* Make sure that --list-fingerprint only creates new keys |
68 | | * if there is no possibility for a deadlock. */ |
69 | 0 | tor_log(severity, LD_FS, "Another Tor process has locked \"%s\". " |
70 | 0 | "Not writing any new keys.", fname); |
71 | | /*XXXX The 'other process' might make a key in a second or two; |
72 | | * maybe we should wait for it. */ |
73 | 0 | goto error; |
74 | 0 | } |
75 | 0 | } |
76 | 0 | log_info(LD_GENERAL, "No key found in \"%s\"; generating fresh key.", |
77 | 0 | fname); |
78 | 0 | if (crypto_pk_generate_key(prkey)) { |
79 | 0 | tor_log(severity, LD_GENERAL,"Error generating onion key"); |
80 | 0 | goto error; |
81 | 0 | } |
82 | 0 | if (! crypto_pk_is_valid_private_key(prkey)) { |
83 | 0 | tor_log(severity, LD_GENERAL,"Generated key seems invalid"); |
84 | 0 | goto error; |
85 | 0 | } |
86 | 0 | log_info(LD_GENERAL, "Generated key seems valid"); |
87 | 0 | if (created_out) { |
88 | 0 | *created_out = true; |
89 | 0 | } |
90 | 0 | if (crypto_pk_write_private_key_to_filename(prkey, fname)) { |
91 | 0 | tor_log(severity, LD_FS, |
92 | 0 | "Couldn't write generated key to \"%s\".", fname); |
93 | 0 | goto error; |
94 | 0 | } |
95 | 0 | } else { |
96 | 0 | tor_log(severity, LD_GENERAL, "No key found in \"%s\"", fname); |
97 | 0 | goto error; |
98 | 0 | } |
99 | 0 | return prkey; |
100 | 0 | case FN_FILE: |
101 | 0 | if (crypto_pk_read_private_key_from_filename(prkey, fname)) { |
102 | 0 | tor_log(severity, LD_GENERAL,"Error loading private key."); |
103 | 0 | goto error; |
104 | 0 | } |
105 | 0 | return prkey; |
106 | 0 | default: |
107 | 0 | tor_assert(0); |
108 | 0 | } |
109 | | |
110 | 0 | error: |
111 | 0 | if (prkey) |
112 | 0 | crypto_pk_free(prkey); |
113 | 0 | return NULL; |
114 | 0 | } |
115 | | |
116 | | /* DOCDOC */ |
117 | | static ssize_t |
118 | | do_getpass(const char *prompt, char *buf, size_t buflen, |
119 | | int twice, const or_options_t *options) |
120 | 0 | { |
121 | 0 | if (options->keygen_force_passphrase == FORCE_PASSPHRASE_OFF) { |
122 | 0 | tor_assert(buflen); |
123 | 0 | buf[0] = 0; |
124 | 0 | return 0; |
125 | 0 | } |
126 | | |
127 | 0 | char *prompt2 = NULL; |
128 | 0 | char *buf2 = NULL; |
129 | 0 | int fd = -1; |
130 | 0 | ssize_t length = -1; |
131 | |
|
132 | 0 | if (options->use_keygen_passphrase_fd) { |
133 | 0 | twice = 0; |
134 | 0 | fd = options->keygen_passphrase_fd; |
135 | 0 | length = read_all_from_fd(fd, buf, buflen-1); |
136 | 0 | if (length >= 0) |
137 | 0 | buf[length] = 0; |
138 | 0 | goto done_reading; |
139 | 0 | } |
140 | | |
141 | 0 | if (twice) { |
142 | 0 | const char msg[] = "One more time:"; |
143 | 0 | size_t p2len = strlen(prompt) + 1; |
144 | 0 | if (p2len < sizeof(msg)) |
145 | 0 | p2len = sizeof(msg); |
146 | 0 | prompt2 = tor_malloc(p2len); |
147 | 0 | memset(prompt2, ' ', p2len); |
148 | 0 | memcpy(prompt2 + p2len - sizeof(msg), msg, sizeof(msg)); |
149 | |
|
150 | 0 | buf2 = tor_malloc_zero(buflen); |
151 | 0 | } |
152 | |
|
153 | 0 | while (1) { |
154 | 0 | length = tor_getpass(prompt, buf, buflen); |
155 | 0 | if (length < 0) |
156 | 0 | goto done_reading; |
157 | | |
158 | 0 | if (! twice) |
159 | 0 | break; |
160 | | |
161 | 0 | ssize_t length2 = tor_getpass(prompt2, buf2, buflen); |
162 | |
|
163 | 0 | if (length != length2 || tor_memneq(buf, buf2, length)) { |
164 | 0 | fprintf(stderr, "That didn't match.\n"); |
165 | 0 | } else { |
166 | 0 | break; |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | 0 | done_reading: |
171 | 0 | if (twice) { |
172 | 0 | tor_free(prompt2); |
173 | 0 | memwipe(buf2, 0, buflen); |
174 | 0 | tor_free(buf2); |
175 | 0 | } |
176 | |
|
177 | 0 | if (options->keygen_force_passphrase == FORCE_PASSPHRASE_ON && length == 0) |
178 | 0 | return -1; |
179 | | |
180 | 0 | return length; |
181 | 0 | } |
182 | | |
183 | | /* DOCDOC */ |
184 | | int |
185 | | read_encrypted_secret_key(ed25519_secret_key_t *out, |
186 | | const char *fname) |
187 | 0 | { |
188 | 0 | int r = -1; |
189 | 0 | uint8_t *secret = NULL; |
190 | 0 | size_t secret_len = 0; |
191 | 0 | char pwbuf[256]; |
192 | 0 | uint8_t encrypted_key[256]; |
193 | 0 | char *tag = NULL; |
194 | 0 | int saved_errno = 0; |
195 | |
|
196 | 0 | ssize_t encrypted_len = crypto_read_tagged_contents_from_file(fname, |
197 | 0 | ENC_KEY_HEADER, |
198 | 0 | &tag, |
199 | 0 | encrypted_key, |
200 | 0 | sizeof(encrypted_key)); |
201 | 0 | if (encrypted_len < 0) { |
202 | 0 | saved_errno = errno; |
203 | 0 | log_info(LD_OR, "%s is missing", fname); |
204 | 0 | r = 0; |
205 | 0 | goto done; |
206 | 0 | } |
207 | 0 | if (strcmp(tag, ENC_KEY_TAG)) { |
208 | 0 | saved_errno = EINVAL; |
209 | 0 | goto done; |
210 | 0 | } |
211 | | |
212 | 0 | while (1) { |
213 | 0 | ssize_t pwlen = |
214 | 0 | do_getpass("Enter passphrase for master key:", pwbuf, sizeof(pwbuf), 0, |
215 | 0 | get_options()); |
216 | 0 | if (pwlen < 0) { |
217 | 0 | saved_errno = EINVAL; |
218 | 0 | goto done; |
219 | 0 | } |
220 | 0 | const int r_unbox = crypto_unpwbox(&secret, &secret_len, |
221 | 0 | encrypted_key, encrypted_len, |
222 | 0 | pwbuf, pwlen); |
223 | 0 | if (r_unbox == UNPWBOX_CORRUPTED) { |
224 | 0 | log_err(LD_OR, "%s is corrupted.", fname); |
225 | 0 | saved_errno = EINVAL; |
226 | 0 | goto done; |
227 | 0 | } else if (r_unbox == UNPWBOX_OKAY) { |
228 | 0 | break; |
229 | 0 | } |
230 | | |
231 | | /* Otherwise, passphrase is bad, so try again till user does ctrl-c or gets |
232 | | * it right. */ |
233 | 0 | } |
234 | | |
235 | 0 | if (secret_len != ED25519_SECKEY_LEN) { |
236 | 0 | log_err(LD_OR, "%s is corrupted.", fname); |
237 | 0 | saved_errno = EINVAL; |
238 | 0 | goto done; |
239 | 0 | } |
240 | 0 | memcpy(out->seckey, secret, ED25519_SECKEY_LEN); |
241 | 0 | r = 1; |
242 | |
|
243 | 0 | done: |
244 | 0 | memwipe(encrypted_key, 0, sizeof(encrypted_key)); |
245 | 0 | memwipe(pwbuf, 0, sizeof(pwbuf)); |
246 | 0 | tor_free(tag); |
247 | 0 | if (secret) { |
248 | 0 | memwipe(secret, 0, secret_len); |
249 | 0 | tor_free(secret); |
250 | 0 | } |
251 | 0 | if (saved_errno) |
252 | 0 | errno = saved_errno; |
253 | 0 | return r; |
254 | 0 | } |
255 | | |
256 | | /* DOCDOC */ |
257 | | int |
258 | | write_encrypted_secret_key(const ed25519_secret_key_t *key, |
259 | | const char *fname) |
260 | 0 | { |
261 | 0 | int r = -1; |
262 | 0 | char pwbuf0[256]; |
263 | 0 | uint8_t *encrypted_key = NULL; |
264 | 0 | size_t encrypted_len = 0; |
265 | |
|
266 | 0 | if (do_getpass("Enter new passphrase:", pwbuf0, sizeof(pwbuf0), 1, |
267 | 0 | get_options()) < 0) { |
268 | 0 | log_warn(LD_OR, "NO/failed passphrase"); |
269 | 0 | return -1; |
270 | 0 | } |
271 | | |
272 | 0 | if (strlen(pwbuf0) == 0) { |
273 | 0 | if (get_options()->keygen_force_passphrase == FORCE_PASSPHRASE_ON) |
274 | 0 | return -1; |
275 | 0 | else |
276 | 0 | return 0; |
277 | 0 | } |
278 | | |
279 | 0 | if (crypto_pwbox(&encrypted_key, &encrypted_len, |
280 | 0 | key->seckey, sizeof(key->seckey), |
281 | 0 | pwbuf0, strlen(pwbuf0), 0) < 0) { |
282 | 0 | log_warn(LD_OR, "crypto_pwbox failed!?"); |
283 | 0 | goto done; |
284 | 0 | } |
285 | 0 | if (crypto_write_tagged_contents_to_file(fname, |
286 | 0 | ENC_KEY_HEADER, |
287 | 0 | ENC_KEY_TAG, |
288 | 0 | encrypted_key, encrypted_len) < 0) |
289 | 0 | goto done; |
290 | 0 | r = 1; |
291 | 0 | done: |
292 | 0 | if (encrypted_key) { |
293 | 0 | memwipe(encrypted_key, 0, encrypted_len); |
294 | 0 | tor_free(encrypted_key); |
295 | 0 | } |
296 | 0 | memwipe(pwbuf0, 0, sizeof(pwbuf0)); |
297 | 0 | return r; |
298 | 0 | } |
299 | | |
300 | | /* DOCDOC */ |
301 | | static int |
302 | | write_secret_key(const ed25519_secret_key_t *key, int encrypted, |
303 | | const char *fname, |
304 | | const char *fname_tag, |
305 | | const char *encrypted_fname) |
306 | 0 | { |
307 | 0 | if (encrypted) { |
308 | 0 | int r = write_encrypted_secret_key(key, encrypted_fname); |
309 | 0 | if (r == 1) { |
310 | | /* Success! */ |
311 | | |
312 | | /* Try to unlink the unencrypted key, if any existed before */ |
313 | 0 | if (strcmp(fname, encrypted_fname)) |
314 | 0 | unlink(fname); |
315 | 0 | return r; |
316 | 0 | } else if (r != 0) { |
317 | | /* Unrecoverable failure! */ |
318 | 0 | return r; |
319 | 0 | } |
320 | | |
321 | 0 | fprintf(stderr, "Not encrypting the secret key.\n"); |
322 | 0 | } |
323 | 0 | return ed25519_seckey_write_to_file(key, fname, fname_tag); |
324 | 0 | } |
325 | | |
326 | | /** |
327 | | * Read an ed25519 key and associated certificates from files beginning with |
328 | | * <b>fname</b>, with certificate type <b>cert_type</b>. On failure, return |
329 | | * NULL; on success return the keypair. |
330 | | * |
331 | | * The <b>options</b> is used to look at the change_key_passphrase value when |
332 | | * writing to disk a secret key. It is safe to be NULL even in that case. |
333 | | * |
334 | | * If INIT_ED_KEY_CREATE is set in <b>flags</b>, then create the key (and |
335 | | * certificate if requested) if it doesn't exist, and save it to disk. |
336 | | * |
337 | | * If INIT_ED_KEY_NEEDCERT is set in <b>flags</b>, load/create a certificate |
338 | | * too and store it in *<b>cert_out</b>. Fail if the cert can't be |
339 | | * found/created. To create a certificate, <b>signing_key</b> must be set to |
340 | | * the key that should sign it; <b>now</b> to the current time, and |
341 | | * <b>lifetime</b> to the lifetime of the key. |
342 | | * |
343 | | * If INIT_ED_KEY_REPLACE is set in <b>flags</b>, then create and save new key |
344 | | * whether we can read the old one or not. |
345 | | * |
346 | | * If INIT_ED_KEY_EXTRA_STRONG is set in <b>flags</b>, set the extra_strong |
347 | | * flag when creating the secret key. |
348 | | * |
349 | | * If INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT is set in <b>flags</b>, and |
350 | | * we create a new certificate, create it with the signing key embedded. |
351 | | * |
352 | | * If INIT_ED_KEY_SPLIT is set in <b>flags</b>, and we create a new key, |
353 | | * store the public key in a separate file from the secret key. |
354 | | * |
355 | | * If INIT_ED_KEY_MISSING_SECRET_OK is set in <b>flags</b>, and we find a |
356 | | * public key file but no secret key file, return successfully anyway. |
357 | | * |
358 | | * If INIT_ED_KEY_OMIT_SECRET is set in <b>flags</b>, do not try to load a |
359 | | * secret key unless no public key is found. Do not return a secret key. (but |
360 | | * create and save one if needed). |
361 | | * |
362 | | * If INIT_ED_KEY_TRY_ENCRYPTED is set, we look for an encrypted secret key |
363 | | * and consider encrypting any new secret key. |
364 | | * |
365 | | * If INIT_ED_KEY_NO_REPAIR is set, and there is any issue loading the keys |
366 | | * from disk _other than their absence_ (full or partial), we do not try to |
367 | | * replace them. |
368 | | * |
369 | | * If INIT_ED_KEY_SUGGEST_KEYGEN is set, have log messages about failures |
370 | | * refer to the --keygen option. |
371 | | * |
372 | | * If INIT_ED_KEY_EXPLICIT_FNAME is set, use the provided file name for the |
373 | | * secret key file, encrypted or not. |
374 | | * |
375 | | * If INIT_ED_KEY_OFFLINE_SECRET is set, we won't try to load the master |
376 | | * secret key and we log a message at <b>severity</b> that we've done so. |
377 | | */ |
378 | | ed25519_keypair_t * |
379 | | ed_key_init_from_file(const char *fname, uint32_t flags, |
380 | | int severity, |
381 | | const ed25519_keypair_t *signing_key, |
382 | | time_t now, |
383 | | time_t lifetime, |
384 | | uint8_t cert_type, |
385 | | struct tor_cert_st **cert_out, |
386 | | const or_options_t *options) |
387 | 0 | { |
388 | 0 | char *secret_fname = NULL; |
389 | 0 | char *encrypted_secret_fname = NULL; |
390 | 0 | char *public_fname = NULL; |
391 | 0 | char *cert_fname = NULL; |
392 | 0 | const char *loaded_secret_fname = NULL; |
393 | 0 | int created_pk = 0, created_sk = 0, created_cert = 0; |
394 | 0 | const int try_to_load = ! (flags & INIT_ED_KEY_REPLACE); |
395 | 0 | const int encrypt_key = !! (flags & INIT_ED_KEY_TRY_ENCRYPTED); |
396 | 0 | const int norepair = !! (flags & INIT_ED_KEY_NO_REPAIR); |
397 | 0 | const int split = !! (flags & INIT_ED_KEY_SPLIT); |
398 | 0 | const int omit_secret = !! (flags & INIT_ED_KEY_OMIT_SECRET); |
399 | 0 | const int offline_secret = !! (flags & INIT_ED_KEY_OFFLINE_SECRET); |
400 | 0 | const int explicit_fname = !! (flags & INIT_ED_KEY_EXPLICIT_FNAME); |
401 | | |
402 | | /* we don't support setting both of these flags at once. */ |
403 | 0 | tor_assert((flags & (INIT_ED_KEY_NO_REPAIR|INIT_ED_KEY_NEEDCERT)) != |
404 | 0 | (INIT_ED_KEY_NO_REPAIR|INIT_ED_KEY_NEEDCERT)); |
405 | | |
406 | 0 | char tag[8]; |
407 | 0 | tor_snprintf(tag, sizeof(tag), "type%d", (int)cert_type); |
408 | |
|
409 | 0 | tor_cert_t *cert = NULL; |
410 | 0 | char *got_tag = NULL; |
411 | 0 | ed25519_keypair_t *keypair = tor_malloc_zero(sizeof(ed25519_keypair_t)); |
412 | |
|
413 | 0 | if (explicit_fname) { |
414 | 0 | secret_fname = tor_strdup(fname); |
415 | 0 | encrypted_secret_fname = tor_strdup(fname); |
416 | 0 | } else { |
417 | 0 | tor_asprintf(&secret_fname, "%s_secret_key", fname); |
418 | 0 | tor_asprintf(&encrypted_secret_fname, "%s_secret_key_encrypted", fname); |
419 | 0 | } |
420 | 0 | tor_asprintf(&public_fname, "%s_public_key", fname); |
421 | 0 | tor_asprintf(&cert_fname, "%s_cert", fname); |
422 | | |
423 | | /* Try to read the secret key. */ |
424 | 0 | int have_secret = 0; |
425 | 0 | int load_secret = try_to_load && |
426 | 0 | !offline_secret && |
427 | 0 | (!omit_secret || file_status(public_fname)==FN_NOENT); |
428 | 0 | if (load_secret) { |
429 | 0 | int rv = ed25519_seckey_read_from_file(&keypair->seckey, |
430 | 0 | &got_tag, secret_fname); |
431 | 0 | if (rv == 0) { |
432 | 0 | have_secret = 1; |
433 | 0 | loaded_secret_fname = secret_fname; |
434 | 0 | tor_assert(got_tag); |
435 | 0 | } else { |
436 | 0 | if (errno != ENOENT && norepair) { |
437 | 0 | tor_log(severity, LD_OR, "Unable to read %s: %s", secret_fname, |
438 | 0 | strerror(errno)); |
439 | 0 | goto err; |
440 | 0 | } |
441 | 0 | } |
442 | 0 | } |
443 | | |
444 | | /* Should we try for an encrypted key? */ |
445 | 0 | int have_encrypted_secret_file = 0; |
446 | 0 | if (!have_secret && try_to_load && encrypt_key) { |
447 | 0 | int r = read_encrypted_secret_key(&keypair->seckey, |
448 | 0 | encrypted_secret_fname); |
449 | 0 | if (r > 0) { |
450 | 0 | have_secret = 1; |
451 | 0 | have_encrypted_secret_file = 1; |
452 | 0 | tor_free(got_tag); /* convince coverity we aren't leaking */ |
453 | 0 | got_tag = tor_strdup(tag); |
454 | 0 | loaded_secret_fname = encrypted_secret_fname; |
455 | 0 | } else if (errno != ENOENT && norepair) { |
456 | 0 | tor_log(severity, LD_OR, "Unable to read %s: %s", |
457 | 0 | encrypted_secret_fname, strerror(errno)); |
458 | 0 | goto err; |
459 | 0 | } |
460 | 0 | } else { |
461 | 0 | if (try_to_load) { |
462 | | /* Check if it's there anyway, so we don't replace it. */ |
463 | 0 | if (file_status(encrypted_secret_fname) != FN_NOENT) |
464 | 0 | have_encrypted_secret_file = 1; |
465 | 0 | } |
466 | 0 | } |
467 | | |
468 | 0 | if (have_secret) { |
469 | 0 | if (strcmp(got_tag, tag)) { |
470 | 0 | tor_log(severity, LD_OR, "%s has wrong tag", loaded_secret_fname); |
471 | 0 | goto err; |
472 | 0 | } |
473 | | /* Derive the public key */ |
474 | 0 | if (ed25519_public_key_generate(&keypair->pubkey, &keypair->seckey)<0) { |
475 | 0 | tor_log(severity, LD_OR, "%s can't produce a public key", |
476 | 0 | loaded_secret_fname); |
477 | 0 | goto err; |
478 | 0 | } |
479 | 0 | } |
480 | | |
481 | | /* If we do split keys here, try to read the pubkey. */ |
482 | 0 | int found_public = 0; |
483 | 0 | if (try_to_load && (!have_secret || split)) { |
484 | 0 | ed25519_public_key_t pubkey_tmp; |
485 | 0 | tor_free(got_tag); |
486 | 0 | found_public = ed25519_pubkey_read_from_file(&pubkey_tmp, |
487 | 0 | &got_tag, public_fname) == 0; |
488 | 0 | if (!found_public && errno != ENOENT && norepair) { |
489 | 0 | tor_log(severity, LD_OR, "Unable to read %s: %s", public_fname, |
490 | 0 | strerror(errno)); |
491 | 0 | goto err; |
492 | 0 | } |
493 | 0 | if (found_public && strcmp(got_tag, tag)) { |
494 | 0 | tor_log(severity, LD_OR, "%s has wrong tag", public_fname); |
495 | 0 | goto err; |
496 | 0 | } |
497 | 0 | if (found_public) { |
498 | 0 | if (have_secret) { |
499 | | /* If we have a secret key and we're reloading the public key, |
500 | | * the key must match! */ |
501 | 0 | if (! ed25519_pubkey_eq(&keypair->pubkey, &pubkey_tmp)) { |
502 | 0 | tor_log(severity, LD_OR, "%s does not match %s! If you are trying " |
503 | 0 | "to restore from backup, make sure you didn't mix up the " |
504 | 0 | "key files. If you are absolutely sure that %s is the right " |
505 | 0 | "key for this relay, delete %s or move it out of the way.", |
506 | 0 | public_fname, loaded_secret_fname, |
507 | 0 | loaded_secret_fname, public_fname); |
508 | 0 | goto err; |
509 | 0 | } |
510 | 0 | } else { |
511 | | /* We only have the public key; better use that. */ |
512 | 0 | tor_assert(split); |
513 | 0 | memcpy(&keypair->pubkey, &pubkey_tmp, sizeof(pubkey_tmp)); |
514 | 0 | } |
515 | 0 | } else { |
516 | | /* We have no public key file, but we do have a secret key, make the |
517 | | * public key file! */ |
518 | 0 | if (have_secret) { |
519 | 0 | if (ed25519_pubkey_write_to_file(&keypair->pubkey, public_fname, tag) |
520 | 0 | < 0) { |
521 | 0 | tor_log(severity, LD_OR, "Couldn't repair %s", public_fname); |
522 | 0 | goto err; |
523 | 0 | } else { |
524 | 0 | tor_log(LOG_NOTICE, LD_OR, |
525 | 0 | "Found secret key but not %s. Regenerating.", |
526 | 0 | public_fname); |
527 | 0 | } |
528 | 0 | } |
529 | 0 | } |
530 | 0 | } |
531 | | |
532 | | /* If the secret key is absent and it's not allowed to be, fail. */ |
533 | 0 | if (!have_secret && found_public && |
534 | 0 | !(flags & INIT_ED_KEY_MISSING_SECRET_OK)) { |
535 | 0 | if (have_encrypted_secret_file) { |
536 | 0 | tor_log(severity, LD_OR, "We needed to load a secret key from %s, " |
537 | 0 | "but it was encrypted. Try 'tor --keygen' instead, so you " |
538 | 0 | "can enter the passphrase.", |
539 | 0 | secret_fname); |
540 | 0 | } else if (offline_secret) { |
541 | 0 | tor_log(severity, LD_OR, "We wanted to load a secret key from %s, " |
542 | 0 | "but you're keeping it offline. (OfflineMasterKey is set.)", |
543 | 0 | secret_fname); |
544 | 0 | } else { |
545 | 0 | tor_log(severity, LD_OR, "We needed to load a secret key from %s, " |
546 | 0 | "but couldn't find it. %s", secret_fname, |
547 | 0 | (flags & INIT_ED_KEY_SUGGEST_KEYGEN) ? |
548 | 0 | "If you're keeping your master secret key offline, you will " |
549 | 0 | "need to run 'tor --keygen' to generate new signing keys." : |
550 | 0 | "Did you forget to copy it over when you copied the rest of the " |
551 | 0 | "signing key material?"); |
552 | 0 | } |
553 | 0 | goto err; |
554 | 0 | } |
555 | | |
556 | | /* If it's absent, and we're not supposed to make a new keypair, fail. */ |
557 | 0 | if (!have_secret && !found_public && !(flags & INIT_ED_KEY_CREATE)) { |
558 | 0 | if (split) { |
559 | 0 | tor_log(severity, LD_OR, "No key found in %s or %s.", |
560 | 0 | secret_fname, public_fname); |
561 | 0 | } else { |
562 | 0 | tor_log(severity, LD_OR, "No key found in %s.", secret_fname); |
563 | 0 | } |
564 | 0 | goto err; |
565 | 0 | } |
566 | | |
567 | | /* If the secret key is absent, but the encrypted key would be present, |
568 | | * that's an error */ |
569 | 0 | if (!have_secret && !found_public && have_encrypted_secret_file) { |
570 | 0 | tor_assert(!encrypt_key); |
571 | 0 | tor_log(severity, LD_OR, "Found an encrypted secret key, " |
572 | 0 | "but not public key file %s!", public_fname); |
573 | 0 | goto err; |
574 | 0 | } |
575 | | |
576 | | /* if it's absent, make a new keypair... */ |
577 | 0 | if (!have_secret && !found_public) { |
578 | 0 | tor_free(keypair); |
579 | 0 | keypair = ed_key_new(signing_key, flags, now, lifetime, |
580 | 0 | cert_type, &cert); |
581 | 0 | if (!keypair) { |
582 | 0 | tor_log(severity, LD_OR, "Couldn't create keypair"); |
583 | 0 | goto err; |
584 | 0 | } |
585 | 0 | created_pk = created_sk = created_cert = 1; |
586 | 0 | } |
587 | | |
588 | | /* Write it to disk if we're supposed to do with a new passphrase, or if |
589 | | * we just created it. */ |
590 | 0 | if (created_sk || (have_secret && options != NULL && |
591 | 0 | options->change_key_passphrase)) { |
592 | 0 | if (write_secret_key(&keypair->seckey, |
593 | 0 | encrypt_key, |
594 | 0 | secret_fname, tag, encrypted_secret_fname) < 0 |
595 | 0 | || |
596 | 0 | (split && |
597 | 0 | ed25519_pubkey_write_to_file(&keypair->pubkey, public_fname, tag) < 0) |
598 | 0 | || |
599 | 0 | (cert && |
600 | 0 | crypto_write_tagged_contents_to_file(cert_fname, "ed25519v1-cert", |
601 | 0 | tag, cert->encoded, cert->encoded_len) < 0)) { |
602 | 0 | tor_log(severity, LD_OR, "Couldn't write keys or cert to file."); |
603 | 0 | goto err; |
604 | 0 | } |
605 | 0 | goto done; |
606 | 0 | } |
607 | | |
608 | | /* If we're not supposed to get a cert, we're done. */ |
609 | 0 | if (! (flags & INIT_ED_KEY_NEEDCERT)) |
610 | 0 | goto done; |
611 | | |
612 | | /* Read a cert. */ |
613 | 0 | tor_free(got_tag); |
614 | 0 | uint8_t certbuf[256]; |
615 | 0 | ssize_t cert_body_len = crypto_read_tagged_contents_from_file( |
616 | 0 | cert_fname, "ed25519v1-cert", |
617 | 0 | &got_tag, certbuf, sizeof(certbuf)); |
618 | 0 | if (cert_body_len >= 0 && !strcmp(got_tag, tag)) |
619 | 0 | cert = tor_cert_parse(certbuf, cert_body_len); |
620 | | |
621 | | /* If we got it, check it to the extent we can. */ |
622 | 0 | int bad_cert = 0; |
623 | |
|
624 | 0 | if (! cert) { |
625 | 0 | tor_log(severity, LD_OR, "Cert was unparseable"); |
626 | 0 | bad_cert = 1; |
627 | 0 | } else if (!tor_memeq(cert->signed_key.pubkey, keypair->pubkey.pubkey, |
628 | 0 | ED25519_PUBKEY_LEN)) { |
629 | 0 | tor_log(severity, LD_OR, "Cert was for wrong key"); |
630 | 0 | bad_cert = 1; |
631 | 0 | } else if (signing_key && |
632 | 0 | tor_cert_checksig(cert, &signing_key->pubkey, now) < 0) { |
633 | 0 | tor_log(severity, LD_OR, "Can't check certificate: %s", |
634 | 0 | tor_cert_describe_signature_status(cert)); |
635 | 0 | bad_cert = 1; |
636 | 0 | } else if (cert->cert_expired) { |
637 | 0 | tor_log(severity, LD_OR, "Certificate is expired"); |
638 | 0 | bad_cert = 1; |
639 | 0 | } else if (signing_key && cert->signing_key_included && |
640 | 0 | ! ed25519_pubkey_eq(&signing_key->pubkey, &cert->signing_key)) { |
641 | 0 | tor_log(severity, LD_OR, "Certificate signed by unexpected key!"); |
642 | 0 | bad_cert = 1; |
643 | 0 | } |
644 | |
|
645 | 0 | if (bad_cert) { |
646 | 0 | tor_cert_free(cert); |
647 | 0 | cert = NULL; |
648 | 0 | } |
649 | | |
650 | | /* If we got a cert, we're done. */ |
651 | 0 | if (cert) |
652 | 0 | goto done; |
653 | | |
654 | | /* If we didn't get a cert, and we're not supposed to make one, fail. */ |
655 | 0 | if (!signing_key || !(flags & INIT_ED_KEY_CREATE)) { |
656 | 0 | tor_log(severity, LD_OR, "Without signing key, can't create certificate"); |
657 | 0 | goto err; |
658 | 0 | } |
659 | | |
660 | | /* We have keys but not a certificate, so make one. */ |
661 | 0 | uint32_t cert_flags = 0; |
662 | 0 | if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT) |
663 | 0 | cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY; |
664 | 0 | cert = tor_cert_create_ed25519(signing_key, cert_type, |
665 | 0 | &keypair->pubkey, |
666 | 0 | now, lifetime, |
667 | 0 | cert_flags); |
668 | |
|
669 | 0 | if (! cert) { |
670 | 0 | tor_log(severity, LD_OR, "Couldn't create certificate"); |
671 | 0 | goto err; |
672 | 0 | } |
673 | | |
674 | | /* Write it to disk. */ |
675 | 0 | created_cert = 1; |
676 | 0 | if (crypto_write_tagged_contents_to_file(cert_fname, "ed25519v1-cert", |
677 | 0 | tag, cert->encoded, cert->encoded_len) < 0) { |
678 | 0 | tor_log(severity, LD_OR, "Couldn't write cert to disk."); |
679 | 0 | goto err; |
680 | 0 | } |
681 | | |
682 | 0 | done: |
683 | 0 | if (cert_out) |
684 | 0 | *cert_out = cert; |
685 | 0 | else |
686 | 0 | tor_cert_free(cert); |
687 | |
|
688 | 0 | goto cleanup; |
689 | | |
690 | 0 | err: |
691 | 0 | if (keypair) |
692 | 0 | memwipe(keypair, 0, sizeof(*keypair)); |
693 | 0 | tor_free(keypair); |
694 | 0 | tor_cert_free(cert); |
695 | 0 | if (cert_out) |
696 | 0 | *cert_out = NULL; |
697 | 0 | if (created_sk) |
698 | 0 | unlink(secret_fname); |
699 | 0 | if (created_pk) |
700 | 0 | unlink(public_fname); |
701 | 0 | if (created_cert) |
702 | 0 | unlink(cert_fname); |
703 | |
|
704 | 0 | cleanup: |
705 | 0 | tor_free(encrypted_secret_fname); |
706 | 0 | tor_free(secret_fname); |
707 | 0 | tor_free(public_fname); |
708 | 0 | tor_free(cert_fname); |
709 | 0 | tor_free(got_tag); |
710 | |
|
711 | 0 | return keypair; |
712 | 0 | } |
713 | | |
714 | | /** |
715 | | * Create a new signing key and (optionally) certificate; do not read or write |
716 | | * from disk. See ed_key_init_from_file() for more information. |
717 | | */ |
718 | | ed25519_keypair_t * |
719 | | ed_key_new(const ed25519_keypair_t *signing_key, |
720 | | uint32_t flags, |
721 | | time_t now, |
722 | | time_t lifetime, |
723 | | uint8_t cert_type, |
724 | | struct tor_cert_st **cert_out) |
725 | 0 | { |
726 | 0 | if (cert_out) |
727 | 0 | *cert_out = NULL; |
728 | |
|
729 | 0 | const int extra_strong = !! (flags & INIT_ED_KEY_EXTRA_STRONG); |
730 | 0 | ed25519_keypair_t *keypair = tor_malloc_zero(sizeof(ed25519_keypair_t)); |
731 | 0 | if (ed25519_keypair_generate(keypair, extra_strong) < 0) |
732 | 0 | goto err; |
733 | | |
734 | 0 | if (! (flags & INIT_ED_KEY_NEEDCERT)) |
735 | 0 | return keypair; |
736 | | |
737 | 0 | tor_assert(signing_key); |
738 | 0 | tor_assert(cert_out); |
739 | 0 | uint32_t cert_flags = 0; |
740 | 0 | if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT) |
741 | 0 | cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY; |
742 | 0 | tor_cert_t *cert = tor_cert_create_ed25519(signing_key, cert_type, |
743 | 0 | &keypair->pubkey, |
744 | 0 | now, lifetime, |
745 | 0 | cert_flags); |
746 | 0 | if (! cert) |
747 | 0 | goto err; |
748 | | |
749 | 0 | *cert_out = cert; |
750 | 0 | return keypair; |
751 | | |
752 | 0 | err: |
753 | 0 | tor_free(keypair); |
754 | 0 | return NULL; |
755 | 0 | } |