Ejemplo n.º 1
0
static void
test_routerkeys_write_fingerprint(void *arg)
{
  crypto_pk_t *key = pk_generate(2);
  or_options_t *options = get_options_mutable();
  const char *ddir = get_fname("write_fingerprint");
  char *cp = NULL, *cp2 = NULL;
  char fp[FINGERPRINT_LEN+1];

  (void)arg;

  tt_assert(key);

  options->ORPort_set = 1; /* So that we can get the server ID key */
  tor_free(options->DataDirectory);
  options->DataDirectory = tor_strdup(ddir);
  options->Nickname = tor_strdup("haflinger");
  set_server_identity_key(key);
  set_client_identity_key(crypto_pk_dup_key(key));

  tt_int_op(0, OP_EQ, check_private_dir(ddir, CPD_CREATE, NULL));
  tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),OP_EQ,0);

  /* Write fingerprint file */
  tt_int_op(0, OP_EQ, router_write_fingerprint(0));
  cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"),
                        0, NULL);
  crypto_pk_get_fingerprint(key, fp, 0);
  tor_asprintf(&cp2, "haflinger %s\n", fp);
  tt_str_op(cp, OP_EQ, cp2);
  tor_free(cp);
  tor_free(cp2);

  /* Write hashed-fingerprint file */
  tt_int_op(0, OP_EQ, router_write_fingerprint(1));
  cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
                        0, NULL);
  crypto_pk_get_hashed_fingerprint(key, fp);
  tor_asprintf(&cp2, "haflinger %s\n", fp);
  tt_str_op(cp, OP_EQ, cp2);
  tor_free(cp);
  tor_free(cp2);

  /* Replace outdated file */
  write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"),
                    "junk goes here", 0);
  tt_int_op(0, OP_EQ, router_write_fingerprint(1));
  cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
                        0, NULL);
  crypto_pk_get_hashed_fingerprint(key, fp);
  tor_asprintf(&cp2, "haflinger %s\n", fp);
  tt_str_op(cp, OP_EQ, cp2);
  tor_free(cp);
  tor_free(cp2);

 done:
  crypto_pk_free(key);
  set_client_identity_key(NULL);
  tor_free(cp);
  tor_free(cp2);
}
Ejemplo n.º 2
0
/**
 * Running as a server: load, reload, or refresh our ed25519 keys and
 * certificates, creating and saving new ones as needed.
 *
 * Return -1 on failure; 0 on success if the signing key was not replaced;
 * and 1 on success if the signing key was replaced.
 */
int
load_ed_keys(const or_options_t *options, time_t now)
{
  ed25519_keypair_t *id = NULL;
  ed25519_keypair_t *sign = NULL;
  ed25519_keypair_t *auth = NULL;
  const ed25519_keypair_t *sign_signing_key_with_id = NULL;
  const ed25519_keypair_t *use_signing = NULL;
  const tor_cert_t *check_signing_cert = NULL;
  tor_cert_t *sign_cert = NULL;
  tor_cert_t *auth_cert = NULL;
  int signing_key_changed = 0;

  // It is later than 1972, since otherwise there would be no C compilers.
  // (Try to diagnose #22466.)
  tor_assert_nonfatal(now >= 2 * 365 * 86400);

#define FAIL(msg) do {                          \
    log_warn(LD_OR, (msg));                     \
    goto err;                                   \
  } while (0)
#define SET_KEY(key, newval) do {               \
    if ((key) != (newval))                      \
      ed25519_keypair_free(key);                \
    key = (newval);                             \
  } while (0)
#define SET_CERT(cert, newval) do {             \
    if ((cert) != (newval))                     \
      tor_cert_free(cert);                      \
    cert = (newval);                            \
  } while (0)
#define HAPPENS_SOON(when, interval)            \
  ((when) < now + (interval))
#define EXPIRES_SOON(cert, interval)            \
  (!(cert) || HAPPENS_SOON((cert)->valid_until, (interval)))

  /* XXXX support encrypted identity keys fully */

  /* First try to get the signing key to see how it is. */
  {
    char *fname =
      options_get_keydir_fname(options, "ed25519_signing");
    sign = ed_key_init_from_file(
               fname,
               INIT_ED_KEY_NEEDCERT|
               INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT,
               LOG_INFO,
               NULL, 0, 0, CERT_TYPE_ID_SIGNING, &sign_cert);
    tor_free(fname);
    check_signing_cert = sign_cert;
    use_signing = sign;
  }

  if (use_signing) {
    /* We loaded a signing key with its certificate.  */
    if (! master_signing_key) {
      /* We didn't know one before! */
      signing_key_changed = 1;
    } else if (! ed25519_pubkey_eq(&use_signing->pubkey,
                                   &master_signing_key->pubkey) ||
               ! tor_memeq(use_signing->seckey.seckey,
                           master_signing_key->seckey.seckey,
                           ED25519_SECKEY_LEN)) {
      /* We loaded a different signing key than the one we knew before. */
      signing_key_changed = 1;
    }
  }

  if (!use_signing && master_signing_key) {
    /* We couldn't load a signing key, but we already had one loaded */
    check_signing_cert = signing_key_cert;
    use_signing = master_signing_key;
  }

  const int offline_master =
    options->OfflineMasterKey && options->command != CMD_KEYGEN;
  const int need_new_signing_key =
    NULL == use_signing ||
    EXPIRES_SOON(check_signing_cert, 0) ||
    (options->command == CMD_KEYGEN && ! options->change_key_passphrase);
  const int want_new_signing_key =
    need_new_signing_key ||
    EXPIRES_SOON(check_signing_cert, options->TestingSigningKeySlop);

  /* We can only create a master key if we haven't been told that the
   * master key will always be offline.  Also, if we have a signing key,
   * then we shouldn't make a new master ID key. */
  const int can_make_master_id_key = !offline_master &&
    NULL == use_signing;

  if (need_new_signing_key) {
    log_notice(LD_OR, "It looks like I need to generate and sign a new "
               "medium-term signing key, because %s. To do that, I "
               "need to load%s the permanent master identity key. "
               "If the master identity key was not moved or encrypted "
               "with a passphrase, this will be done automatically and "
               "no further action is required. Otherwise, provide the "
               "necessary data using 'tor --keygen' to do it manually.",
            (NULL == use_signing) ? "I don't have one" :
            EXPIRES_SOON(check_signing_cert, 0) ? "the one I have is expired" :
               "you asked me to make one with --keygen",
            can_make_master_id_key ? " (or create)" : "");
  } else if (want_new_signing_key && !offline_master) {
    log_notice(LD_OR, "It looks like I should try to generate and sign a "
               "new medium-term signing key, because the one I have is "
               "going to expire soon. To do that, I'm going to have to "
               "try to load the permanent master identity key. "
               "If the master identity key was not moved or encrypted "
               "with a passphrase, this will be done automatically and "
               "no further action is required. Otherwise, provide the "
               "necessary data using 'tor --keygen' to do it manually.");
  } else if (want_new_signing_key) {
    log_notice(LD_OR, "It looks like I should try to generate and sign a "
               "new medium-term signing key, because the one I have is "
               "going to expire soon. But OfflineMasterKey is set, so I "
               "won't try to load a permanent master identity key. You "
               "will need to use 'tor --keygen' to make a new signing "
               "key and certificate.");
  }

  {
    uint32_t flags =
      (INIT_ED_KEY_SPLIT|
       INIT_ED_KEY_EXTRA_STRONG|INIT_ED_KEY_NO_REPAIR);
    if (can_make_master_id_key)
      flags |= INIT_ED_KEY_CREATE;
    if (! need_new_signing_key)
      flags |= INIT_ED_KEY_MISSING_SECRET_OK;
    if (! want_new_signing_key || offline_master)
      flags |= INIT_ED_KEY_OMIT_SECRET;
    if (offline_master)
      flags |= INIT_ED_KEY_OFFLINE_SECRET;
    if (options->command == CMD_KEYGEN)
      flags |= INIT_ED_KEY_TRY_ENCRYPTED;

    /* Check/Create the key directory */
    if (create_keys_directory(options) < 0)
      return -1;

    char *fname;
    if (options->master_key_fname) {
      fname = tor_strdup(options->master_key_fname);
      flags |= INIT_ED_KEY_EXPLICIT_FNAME;
    } else {
      fname = options_get_keydir_fname(options, "ed25519_master_id");
    }
    id = ed_key_init_from_file(
             fname,
             flags,
             LOG_WARN, NULL, 0, 0, 0, NULL);
    tor_free(fname);
    if (!id) {
      if (need_new_signing_key) {
        if (offline_master)
          FAIL("Can't load master identity key; OfflineMasterKey is set.");
        else
          FAIL("Missing identity key");
      } else {
        log_warn(LD_OR, "Master public key was absent; inferring from "
                 "public key in signing certificate and saving to disk.");
        tor_assert(check_signing_cert);
        id = tor_malloc_zero(sizeof(*id));
        memcpy(&id->pubkey, &check_signing_cert->signing_key,
               sizeof(ed25519_public_key_t));
        fname = options_get_keydir_fname(options,
                                         "ed25519_master_id_public_key");
        if (ed25519_pubkey_write_to_file(&id->pubkey, fname, "type0") < 0) {
          log_warn(LD_OR, "Error while attempting to write master public key "
                   "to disk");
          tor_free(fname);
          goto err;
        }
        tor_free(fname);
      }
    }
    if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey)))
      sign_signing_key_with_id = NULL;
    else
      sign_signing_key_with_id = id;
  }

  if (master_identity_key &&
      !ed25519_pubkey_eq(&id->pubkey, &master_identity_key->pubkey)) {
    FAIL("Identity key on disk does not match key we loaded earlier!");
  }

  if (need_new_signing_key && NULL == sign_signing_key_with_id)
    FAIL("Can't load master key make a new signing key.");

  if (sign_cert) {
    if (! sign_cert->signing_key_included)
      FAIL("Loaded a signing cert with no key included!");
    if (! ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey))
      FAIL("The signing cert we have was not signed with the master key "
           "we loaded!");
    if (tor_cert_checksig(sign_cert, &id->pubkey, 0) < 0) {
      log_warn(LD_OR, "The signing cert we loaded was not signed "
               "correctly: %s!",
               tor_cert_describe_signature_status(sign_cert));
      goto err;
    }
  }

  if (want_new_signing_key && sign_signing_key_with_id) {
    uint32_t flags = (INIT_ED_KEY_CREATE|
                      INIT_ED_KEY_REPLACE|
                      INIT_ED_KEY_EXTRA_STRONG|
                      INIT_ED_KEY_NEEDCERT|
                      INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT);
    char *fname =
      options_get_keydir_fname(options, "ed25519_signing");
    ed25519_keypair_free(sign);
    tor_cert_free(sign_cert);
    sign = ed_key_init_from_file(fname,
                                 flags, LOG_WARN,
                                 sign_signing_key_with_id, now,
                                 options->SigningKeyLifetime,
                                 CERT_TYPE_ID_SIGNING, &sign_cert);
    tor_free(fname);
    if (!sign)
      FAIL("Missing signing key");
    use_signing = sign;
    signing_key_changed = 1;

    tor_assert(sign_cert->signing_key_included);
    tor_assert(ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey));
    tor_assert(ed25519_pubkey_eq(&sign_cert->signed_key, &sign->pubkey));
  } else if (want_new_signing_key) {
    static ratelim_t missing_master = RATELIM_INIT(3600);
    log_fn_ratelim(&missing_master, LOG_WARN, LD_OR,
                   "Signing key will expire soon, but I can't load the "
                   "master key to sign a new one!");
  }

  tor_assert(use_signing);

  /* At this point we no longer need our secret identity key.  So wipe
   * it, if we loaded it in the first place. */
  memwipe(id->seckey.seckey, 0, sizeof(id->seckey));

  if (options->command == CMD_KEYGEN)
    goto end;

  if (server_mode(options) &&
      (!rsa_ed_crosscert ||
       HAPPENS_SOON(rsa_ed_crosscert_expiration, 30*86400))) {
    uint8_t *crosscert;
    time_t expiration = now+6*30*86400; /* 6 months in the future. */
    ssize_t crosscert_len = tor_make_rsa_ed25519_crosscert(&id->pubkey,
                                                   get_server_identity_key(),
                                                   expiration,
                                                   &crosscert);
    tor_free(rsa_ed_crosscert);
    rsa_ed_crosscert_len = crosscert_len;
    rsa_ed_crosscert = crosscert;
    rsa_ed_crosscert_expiration = expiration;
  }

  if (!current_auth_key ||
      signing_key_changed ||
      EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop)) {
    auth = ed_key_new(use_signing, INIT_ED_KEY_NEEDCERT,
                      now,
                      options->TestingAuthKeyLifetime,
                      CERT_TYPE_SIGNING_AUTH, &auth_cert);

    if (!auth)
      FAIL("Can't create auth key");
  }

  /* We've generated or loaded everything.  Put them in memory. */

 end:
  if (! master_identity_key) {
    SET_KEY(master_identity_key, id);
  } else {
    tor_free(id);
  }
  if (sign) {
    SET_KEY(master_signing_key, sign);
    SET_CERT(signing_key_cert, sign_cert);
  }
  if (auth) {
    SET_KEY(current_auth_key, auth);
    SET_CERT(auth_key_cert, auth_cert);
  }

  return signing_key_changed;
 err:
  ed25519_keypair_free(id);
  ed25519_keypair_free(sign);
  ed25519_keypair_free(auth);
  tor_cert_free(sign_cert);
  tor_cert_free(auth_cert);
  return -1;
}
Ejemplo n.º 3
0
/**
 * Running as a server: load, reload, or refresh our ed25519 keys and
 * certificates, creating and saving new ones as needed.
 */
int
load_ed_keys(const or_options_t *options, time_t now)
{
  ed25519_keypair_t *id = NULL;
  ed25519_keypair_t *sign = NULL;
  ed25519_keypair_t *auth = NULL;
  const ed25519_keypair_t *sign_signing_key_with_id = NULL;
  const ed25519_keypair_t *use_signing = NULL;
  const tor_cert_t *check_signing_cert = NULL;
  tor_cert_t *sign_cert = NULL;
  tor_cert_t *auth_cert = NULL;

#define FAIL(msg) do {                          \
    log_warn(LD_OR, (msg));                     \
    goto err;                                   \
  } while (0)
#define SET_KEY(key, newval) do {               \
    if ((key) != (newval))                      \
      ed25519_keypair_free(key);                \
    key = (newval);                             \
  } while (0)
#define SET_CERT(cert, newval) do {             \
    if ((cert) != (newval))                     \
      tor_cert_free(cert);                      \
    cert = (newval);                            \
  } while (0)
#define EXPIRES_SOON(cert, interval)            \
  (!(cert) || (cert)->valid_until < now + (interval))

  /* XXXX support encrypted identity keys fully */

  /* First try to get the signing key to see how it is. */
  {
    char *fname =
      options_get_datadir_fname2(options, "keys", "ed25519_signing");
    sign = ed_key_init_from_file(
               fname,
               INIT_ED_KEY_NEEDCERT|
               INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT,
               LOG_INFO,
               NULL, 0, 0, CERT_TYPE_ID_SIGNING, &sign_cert);
    tor_free(fname);
    check_signing_cert = sign_cert;
    use_signing = sign;
  }

  if (!use_signing && master_signing_key) {
    check_signing_cert = signing_key_cert;
    use_signing = master_signing_key;
  }

  const int offline_master =
    options->OfflineMasterKey && options->command != CMD_KEYGEN;
  const int need_new_signing_key =
    NULL == use_signing ||
    EXPIRES_SOON(check_signing_cert, 0) ||
    (options->command == CMD_KEYGEN && ! options->change_key_passphrase);
  const int want_new_signing_key =
    need_new_signing_key ||
    EXPIRES_SOON(check_signing_cert, options->TestingSigningKeySlop);

  /* We can only create a master key if we haven't been told that the
   * master key will always be offline.  Also, if we have a signing key,
   * then we shouldn't make a new master ID key. */
  const int can_make_master_id_key = !offline_master &&
    NULL == use_signing;

  if (need_new_signing_key) {
    log_notice(LD_OR, "It looks like I need to generate and sign a new "
               "medium-term signing key, because %s. To do that, I need to "
               "load%s the permanent master identity key.",
            (NULL == use_signing) ? "I don't have one" :
            EXPIRES_SOON(check_signing_cert, 0) ? "the one I have is expired" :
               "you asked me to make one with --keygen",
            can_make_master_id_key ? " (or create)" : "");
  } else if (want_new_signing_key && !offline_master) {
    log_notice(LD_OR, "It looks like I should try to generate and sign a "
               "new medium-term signing key, because the one I have is "
               "going to expire soon. To do that, I'm going to have to try to "
               "load the permanent master identity key.");
  } else if (want_new_signing_key) {
    log_notice(LD_OR, "It looks like I should try to generate and sign a "
               "new medium-term signing key, because the one I have is "
               "going to expire soon. But OfflineMasterKey is set, so I "
               "won't try to load a permanent master identity key is set. "
               "You will need to use 'tor --keygen' make a new signing key "
               "and certificate.");
  }

  {
    uint32_t flags =
      (INIT_ED_KEY_SPLIT|
       INIT_ED_KEY_EXTRA_STRONG|INIT_ED_KEY_NO_REPAIR);
    if (can_make_master_id_key)
      flags |= INIT_ED_KEY_CREATE;
    if (! need_new_signing_key)
      flags |= INIT_ED_KEY_MISSING_SECRET_OK;
    if (! want_new_signing_key || offline_master)
      flags |= INIT_ED_KEY_OMIT_SECRET;
    if (offline_master)
      flags |= INIT_ED_KEY_OFFLINE_SECRET;
    if (options->command == CMD_KEYGEN)
      flags |= INIT_ED_KEY_TRY_ENCRYPTED;

    /* Check the key directory */
    if (check_private_dir(options->DataDirectory, CPD_CREATE, options->User)) {
      log_err(LD_OR, "Can't create/check datadirectory %s",
              options->DataDirectory);
      goto err;
    }
    char *fname = get_datadir_fname("keys");
    if (check_private_dir(fname, CPD_CREATE, options->User) < 0) {
      log_err(LD_OR, "Problem creating/checking key directory %s", fname);
      tor_free(fname);
      goto err;
    }
    tor_free(fname);
    if (options->master_key_fname) {
      fname = tor_strdup(options->master_key_fname);
      flags |= INIT_ED_KEY_EXPLICIT_FNAME;
    } else {
      fname = options_get_datadir_fname2(options, "keys", "ed25519_master_id");
    }
    id = ed_key_init_from_file(
             fname,
             flags,
             LOG_WARN, NULL, 0, 0, 0, NULL);
    tor_free(fname);
    if (!id) {
      if (need_new_signing_key) {
        if (offline_master)
          FAIL("Can't load master identity key; OfflineMasterKey is set.");
        else
          FAIL("Missing identity key");
      } else {
        log_warn(LD_OR, "Master public key was absent; inferring from "
                 "public key in signing certificate and saving to disk.");
        tor_assert(check_signing_cert);
        id = tor_malloc_zero(sizeof(*id));
        memcpy(&id->pubkey, &check_signing_cert->signing_key,
               sizeof(ed25519_public_key_t));
        fname = options_get_datadir_fname2(options, "keys",
                                           "ed25519_master_id_public_key");
        if (ed25519_pubkey_write_to_file(&id->pubkey, fname, "type0") < 0) {
          log_warn(LD_OR, "Error while attempting to write master public key "
                   "to disk");
          tor_free(fname);
          goto err;
        }
        tor_free(fname);
      }
    }
    if (tor_mem_is_zero((char*)id->seckey.seckey, sizeof(id->seckey)))
      sign_signing_key_with_id = NULL;
    else
      sign_signing_key_with_id = id;
  }

  if (master_identity_key &&
      !ed25519_pubkey_eq(&id->pubkey, &master_identity_key->pubkey)) {
    FAIL("Identity key on disk does not match key we loaded earlier!");
  }

  if (need_new_signing_key && NULL == sign_signing_key_with_id)
    FAIL("Can't load master key make a new signing key.");

  if (sign_cert) {
    if (! sign_cert->signing_key_included)
      FAIL("Loaded a signing cert with no key included!");
    if (! ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey))
      FAIL("The signing cert we have was not signed with the master key "
           "we loaded!");
    if (tor_cert_checksig(sign_cert, &id->pubkey, 0) < 0)
      FAIL("The signing cert we loaded was not signed correctly!");
  }

  if (want_new_signing_key && sign_signing_key_with_id) {
    uint32_t flags = (INIT_ED_KEY_CREATE|
                      INIT_ED_KEY_REPLACE|
                      INIT_ED_KEY_EXTRA_STRONG|
                      INIT_ED_KEY_NEEDCERT|
                      INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT);
    char *fname =
      options_get_datadir_fname2(options, "keys", "ed25519_signing");
    ed25519_keypair_free(sign);
    tor_cert_free(sign_cert);
    sign = ed_key_init_from_file(fname,
                                 flags, LOG_WARN,
                                 sign_signing_key_with_id, now,
                                 options->SigningKeyLifetime,
                                 CERT_TYPE_ID_SIGNING, &sign_cert);
    tor_free(fname);
    if (!sign)
      FAIL("Missing signing key");
    use_signing = sign;

    tor_assert(sign_cert->signing_key_included);
    tor_assert(ed25519_pubkey_eq(&sign_cert->signing_key, &id->pubkey));
    tor_assert(ed25519_pubkey_eq(&sign_cert->signed_key, &sign->pubkey));
  } else if (want_new_signing_key) {
    static ratelim_t missing_master = RATELIM_INIT(3600);
    log_fn_ratelim(&missing_master, LOG_WARN, LD_OR,
                   "Signing key will expire soon, but I can't load the "
                   "master key to sign a new one!");
  }

  tor_assert(use_signing);

  /* At this point we no longer need our secret identity key.  So wipe
   * it, if we loaded it in the first place. */
  memwipe(id->seckey.seckey, 0, sizeof(id->seckey));

  if (options->command == CMD_KEYGEN)
    goto end;

  if (!rsa_ed_crosscert && server_mode(options)) {
    uint8_t *crosscert;
    ssize_t crosscert_len = tor_make_rsa_ed25519_crosscert(&id->pubkey,
                                                   get_server_identity_key(),
                                                   now+10*365*86400,/*XXXX*/
                                                   &crosscert);
    rsa_ed_crosscert_len = crosscert_len;
    rsa_ed_crosscert = crosscert;
  }

  if (!current_auth_key ||
      EXPIRES_SOON(auth_key_cert, options->TestingAuthKeySlop)) {
    auth = ed_key_new(use_signing, INIT_ED_KEY_NEEDCERT,
                      now,
                      options->TestingAuthKeyLifetime,
                      CERT_TYPE_SIGNING_AUTH, &auth_cert);

    if (!auth)
      FAIL("Can't create auth key");
  }

  /* We've generated or loaded everything.  Put them in memory. */

 end:
  if (! master_identity_key) {
    SET_KEY(master_identity_key, id);
  } else {
    tor_free(id);
  }
  if (sign) {
    SET_KEY(master_signing_key, sign);
    SET_CERT(signing_key_cert, sign_cert);
  }
  if (auth) {
    SET_KEY(current_auth_key, auth);
    SET_CERT(auth_key_cert, auth_cert);
  }

  return 0;
 err:
  ed25519_keypair_free(id);
  ed25519_keypair_free(sign);
  ed25519_keypair_free(auth);
  tor_cert_free(sign_cert);
  tor_cert_free(auth_cert);
  return -1;
}
Ejemplo n.º 4
0
/** Based on our interval and our estimated bandwidth, choose a
 * deterministic (but random-ish) time to wake up. */
static void
accounting_set_wakeup_time(void)
{
  char digest[DIGEST_LEN];
  crypto_digest_t *d_env;
  uint64_t time_to_exhaust_bw;
  int time_to_consider;

  if (! server_identity_key_is_set()) {
    if (init_keys() < 0) {
      log_err(LD_BUG, "Error initializing keys");
      tor_assert(0);
    }
  }

  if (server_identity_key_is_set()) {
    char buf[ISO_TIME_LEN+1];
    format_iso_time(buf, interval_start_time);

    crypto_pk_get_digest(get_server_identity_key(), digest);

    d_env = crypto_digest_new();
    crypto_digest_add_bytes(d_env, buf, ISO_TIME_LEN);
    crypto_digest_add_bytes(d_env, digest, DIGEST_LEN);
    crypto_digest_get_digest(d_env, digest, DIGEST_LEN);
    crypto_digest_free(d_env);
  } else {
    crypto_rand(digest, DIGEST_LEN);
  }

  if (!expected_bandwidth_usage) {
    char buf1[ISO_TIME_LEN+1];
    char buf2[ISO_TIME_LEN+1];
    format_local_iso_time(buf1, interval_start_time);
    format_local_iso_time(buf2, interval_end_time);
    interval_wakeup_time = interval_start_time;

    log_notice(LD_ACCT,
           "Configured hibernation. This interval begins at %s "
           "and ends at %s. We have no prior estimate for bandwidth, so "
           "we will start out awake and hibernate when we exhaust our quota.",
           buf1, buf2);
    return;
  }

  time_to_exhaust_bw =
    (get_options()->AccountingMax/expected_bandwidth_usage)*60;
  if (time_to_exhaust_bw > INT_MAX) {
    time_to_exhaust_bw = INT_MAX;
    time_to_consider = 0;
  } else {
    time_to_consider = accounting_get_interval_length() -
                       (int)time_to_exhaust_bw;
  }

  if (time_to_consider<=0) {
    interval_wakeup_time = interval_start_time;
  } else {
    /* XXX can we simplify this just by picking a random (non-deterministic)
     * time to be up? If we go down and come up, then we pick a new one. Is
     * that good enough? -RD */

    /* This is not a perfectly unbiased conversion, but it is good enough:
     * in the worst case, the first half of the day is 0.06 percent likelier
     * to be chosen than the last half. */
    interval_wakeup_time = interval_start_time +
      (get_uint32(digest) % time_to_consider);
  }

  {
    char buf1[ISO_TIME_LEN+1];
    char buf2[ISO_TIME_LEN+1];
    char buf3[ISO_TIME_LEN+1];
    char buf4[ISO_TIME_LEN+1];
    time_t down_time;
    if (interval_wakeup_time+time_to_exhaust_bw > TIME_MAX)
      down_time = TIME_MAX;
    else
      down_time = (time_t)(interval_wakeup_time+time_to_exhaust_bw);
    if (down_time>interval_end_time)
      down_time = interval_end_time;
    format_local_iso_time(buf1, interval_start_time);
    format_local_iso_time(buf2, interval_wakeup_time);
    format_local_iso_time(buf3, down_time);
    format_local_iso_time(buf4, interval_end_time);

    log_notice(LD_ACCT,
           "Configured hibernation.  This interval began at %s; "
           "the scheduled wake-up time %s %s; "
           "we expect%s to exhaust our quota for this interval around %s; "
           "the next interval begins at %s (all times local)",
           buf1,
           time(NULL)<interval_wakeup_time?"is":"was", buf2,
           time(NULL)<down_time?"":"ed", buf3,
           buf4);
  }
}