|  | @@ -118,7 +118,6 @@ read_encrypted_secret_key(ed25519_secret_key_t *out,
 | 
	
		
			
				|  |  |                                   pwbuf, pwlen);
 | 
	
		
			
				|  |  |      if (r == UNPWBOX_CORRUPTED) {
 | 
	
		
			
				|  |  |        log_err(LD_OR, "%s is corrupted.", fname);
 | 
	
		
			
				|  |  | -            puts("E");
 | 
	
		
			
				|  |  |        saved_errno = EINVAL;
 | 
	
		
			
				|  |  |        goto done;
 | 
	
		
			
				|  |  |      } else if (r == UNPWBOX_OKAY) {
 | 
	
	
		
			
				|  | @@ -245,7 +244,8 @@ write_secret_key(const ed25519_secret_key_t *key, int encrypted,
 | 
	
		
			
				|  |  |   * and consider encrypting any new secret key.
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * If INIT_ED_KEY_NO_REPAIR is set, and there is any issue loading the keys
 | 
	
		
			
				|  |  | - * from disk _other than their absence_, we do not try to replace them.
 | 
	
		
			
				|  |  | + * from disk _other than their absence_ (full or partial), we do not try to
 | 
	
		
			
				|  |  | + * replace them.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  ed25519_keypair_t *
 | 
	
		
			
				|  |  |  ed_key_init_from_file(const char *fname, uint32_t flags,
 | 
	
	
		
			
				|  | @@ -266,6 +266,7 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
 | 
	
		
			
				|  |  |    const int encrypt_key = !! (flags & INIT_ED_KEY_TRY_ENCRYPTED);
 | 
	
		
			
				|  |  |    const int norepair = !! (flags & INIT_ED_KEY_NO_REPAIR);
 | 
	
		
			
				|  |  |    const int split = !! (flags & INIT_ED_KEY_SPLIT);
 | 
	
		
			
				|  |  | +  const int omit_secret = !! (flags &  INIT_ED_KEY_OMIT_SECRET);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* we don't support setting both of these flags at once. */
 | 
	
		
			
				|  |  |    tor_assert((flags & (INIT_ED_KEY_NO_REPAIR|INIT_ED_KEY_NEEDCERT)) !=
 | 
	
	
		
			
				|  | @@ -285,8 +286,7 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Try to read the secret key. */
 | 
	
		
			
				|  |  |    int have_secret = 0;
 | 
	
		
			
				|  |  | -  if (try_to_load &&
 | 
	
		
			
				|  |  | -      !(flags & INIT_ED_KEY_OMIT_SECRET)) {
 | 
	
		
			
				|  |  | +  if (try_to_load && (!omit_secret || file_status(public_fname)==FN_NOENT )) {
 | 
	
		
			
				|  |  |      int rv = ed25519_seckey_read_from_file(&keypair->seckey,
 | 
	
		
			
				|  |  |                                             &got_tag, secret_fname);
 | 
	
		
			
				|  |  |      if (rv == 0) {
 | 
	
	
		
			
				|  | @@ -302,18 +302,26 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Should we try for an encrypted key? */
 | 
	
		
			
				|  |  | +  int have_encrypted_secret_file = 0;
 | 
	
		
			
				|  |  |    if (!have_secret && try_to_load && encrypt_key) {
 | 
	
		
			
				|  |  |      int r = read_encrypted_secret_key(&keypair->seckey,
 | 
	
		
			
				|  |  |                                        encrypted_secret_fname);
 | 
	
		
			
				|  |  |      if (r > 0) {
 | 
	
		
			
				|  |  |        have_secret = 1;
 | 
	
		
			
				|  |  | +      have_encrypted_secret_file = 1;
 | 
	
		
			
				|  |  |        got_tag = tor_strdup(tag);
 | 
	
		
			
				|  |  |        loaded_secret_fname = encrypted_secret_fname;
 | 
	
		
			
				|  |  |      } else if (errno != ENOENT && norepair) {
 | 
	
		
			
				|  |  | -      tor_log(severity, LD_OR, "Unable to read %s: %s", encrypted_secret_fname,
 | 
	
		
			
				|  |  | -              strerror(errno));
 | 
	
		
			
				|  |  | +      tor_log(severity, LD_OR, "Unable to read %s: %s",
 | 
	
		
			
				|  |  | +              encrypted_secret_fname, strerror(errno));
 | 
	
		
			
				|  |  |        goto err;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    if (try_to_load) {
 | 
	
		
			
				|  |  | +      /* Check if it's there anyway, so we don't replace it. */
 | 
	
		
			
				|  |  | +      if (file_status(encrypted_secret_fname) != FN_NOENT)
 | 
	
		
			
				|  |  | +        have_encrypted_secret_file = 1;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (have_secret) {
 | 
	
	
		
			
				|  | @@ -329,10 +337,9 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* If it's absent and that's okay, or if we do split keys here, try to re
 | 
	
		
			
				|  |  | -   * the pubkey. */
 | 
	
		
			
				|  |  | +  /* If we do split keys here, try to read the pubkey. */
 | 
	
		
			
				|  |  |    int found_public = 0;
 | 
	
		
			
				|  |  | -  if ((!have_secret && try_to_load) || (have_secret && split)) {
 | 
	
		
			
				|  |  | +  if (try_to_load && (!have_secret || split)) {
 | 
	
		
			
				|  |  |      ed25519_public_key_t pubkey_tmp;
 | 
	
		
			
				|  |  |      tor_free(got_tag);
 | 
	
		
			
				|  |  |      found_public = ed25519_pubkey_read_from_file(&pubkey_tmp,
 | 
	
	
		
			
				|  | @@ -356,9 +363,23 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
 | 
	
		
			
				|  |  |            goto err;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        } else {
 | 
	
		
			
				|  |  | +        /* We only have the public key; better use that. */
 | 
	
		
			
				|  |  |          tor_assert(split);
 | 
	
		
			
				|  |  |          memcpy(&keypair->pubkey, &pubkey_tmp, sizeof(pubkey_tmp));
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      /* We have no public key file, but we do have a secret key, make the
 | 
	
		
			
				|  |  | +       * public key file! */
 | 
	
		
			
				|  |  | +      if (have_secret) {
 | 
	
		
			
				|  |  | +        if (ed25519_pubkey_write_to_file(&keypair->pubkey, public_fname, tag)
 | 
	
		
			
				|  |  | +            < 0) {
 | 
	
		
			
				|  |  | +          tor_log(severity, LD_OR, "Couldn't repair %s", public_fname);
 | 
	
		
			
				|  |  | +          goto err;
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          tor_log(severity, LD_OR, "Found secret key but not %s. Regenerating.",
 | 
	
		
			
				|  |  | +                  public_fname);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -370,6 +391,15 @@ ed_key_init_from_file(const char *fname, uint32_t flags,
 | 
	
		
			
				|  |  |    if (!have_secret && !found_public && !(flags & INIT_ED_KEY_CREATE))
 | 
	
		
			
				|  |  |      goto err;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /* If the secret key is absent, but the encrypted key would be present,
 | 
	
		
			
				|  |  | +   * that's an error */
 | 
	
		
			
				|  |  | +  if (!have_secret && !found_public && have_encrypted_secret_file) {
 | 
	
		
			
				|  |  | +    tor_assert(!encrypt_key);
 | 
	
		
			
				|  |  | +    tor_log(severity, LD_OR, "Found an encrypted secret key, "
 | 
	
		
			
				|  |  | +            "but not public key file %s!", public_fname);
 | 
	
		
			
				|  |  | +    goto err;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    /* if it's absent, make a new keypair and save it. */
 | 
	
		
			
				|  |  |    if (!have_secret && !found_public) {
 | 
	
		
			
				|  |  |      tor_free(keypair);
 | 
	
	
		
			
				|  | @@ -610,8 +640,10 @@ load_ed_keys(const or_options_t *options, time_t now)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      uint32_t flags =
 | 
	
		
			
				|  |  | -      (INIT_ED_KEY_CREATE|INIT_ED_KEY_SPLIT|
 | 
	
		
			
				|  |  | +      (INIT_ED_KEY_SPLIT|
 | 
	
		
			
				|  |  |         INIT_ED_KEY_EXTRA_STRONG|INIT_ED_KEY_NO_REPAIR);
 | 
	
		
			
				|  |  | +    if (! use_signing)
 | 
	
		
			
				|  |  | +      flags |= INIT_ED_KEY_CREATE;
 | 
	
		
			
				|  |  |      if (! need_new_signing_key)
 | 
	
		
			
				|  |  |        flags |= INIT_ED_KEY_MISSING_SECRET_OK;
 | 
	
		
			
				|  |  |      if (! want_new_signing_key)
 | 
	
	
		
			
				|  | @@ -638,8 +670,18 @@ load_ed_keys(const or_options_t *options, time_t now)
 | 
	
		
			
				|  |  |               flags,
 | 
	
		
			
				|  |  |               LOG_WARN, NULL, 0, 0, 0, NULL);
 | 
	
		
			
				|  |  |      tor_free(fname);
 | 
	
		
			
				|  |  | -    if (!id)
 | 
	
		
			
				|  |  | -      FAIL("Missing identity key");
 | 
	
		
			
				|  |  | +    if (!id) {
 | 
	
		
			
				|  |  | +      if (need_new_signing_key) {
 | 
	
		
			
				|  |  | +        FAIL("Missing identity key");
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        log_warn(LD_OR, "master public key was absent; inferring from "
 | 
	
		
			
				|  |  | +                 "public key in signing certificate");
 | 
	
		
			
				|  |  | +        tor_assert(check_signing_cert);
 | 
	
		
			
				|  |  | +        id = tor_malloc_zero(sizeof(*id));
 | 
	
		
			
				|  |  | +        memcpy(&id->pubkey, &check_signing_cert->signing_key,
 | 
	
		
			
				|  |  | +               sizeof(ed25519_public_key_t));
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey)))
 | 
	
		
			
				|  |  |        sign_signing_key_with_id = NULL;
 | 
	
		
			
				|  |  |      else
 |