Example #1
0
void
routerkeys_free_all(void)
{
  ed25519_keypair_free(master_identity_key);
  ed25519_keypair_free(master_signing_key);
  ed25519_keypair_free(current_auth_key);
  tor_cert_free(signing_key_cert);
  tor_cert_free(link_cert_cert);
  tor_cert_free(auth_key_cert);

  master_identity_key = master_signing_key = NULL;
  current_auth_key = NULL;
  signing_key_cert = link_cert_cert = auth_key_cert = NULL;
}
Example #2
0
static void
test_routerkeys_cross_certify_ntor(void *args)
{
  (void) args;

  tor_cert_t *cert = NULL;
  curve25519_keypair_t onion_keys;
  ed25519_public_key_t master_key;
  ed25519_public_key_t onion_check_key;
  time_t now = time(NULL);
  int sign;

  tt_int_op(0, OP_EQ, ed25519_public_from_base64(&master_key,
                               "IamwritingthesetestsOnARainyAfternoonin2014"));
  tt_int_op(0, OP_EQ, curve25519_keypair_generate(&onion_keys, 0));
  cert = make_ntor_onion_key_crosscert(&onion_keys,
                                       &master_key,
                                       now, 10000,
                                       &sign);
  tt_assert(cert);
  tt_assert(sign == 0 || sign == 1);
  tt_int_op(cert->cert_type, OP_EQ, CERT_TYPE_ONION_ID);
  tt_int_op(1, OP_EQ, ed25519_pubkey_eq(&cert->signed_key, &master_key));
  tt_int_op(0, OP_EQ, ed25519_public_key_from_curve25519_public_key(
                               &onion_check_key, &onion_keys.pubkey, sign));
  tt_int_op(0, OP_EQ, tor_cert_checksig(cert, &onion_check_key, now));

 done:
  tor_cert_free(cert);
}
Example #3
0
static void
test_routerkeys_ed_key_create(void *arg)
{
  (void)arg;
  tor_cert_t *cert = NULL;
  ed25519_keypair_t *kp1 = NULL, *kp2 = NULL;
  time_t now = time(NULL);

  /* This is a simple alias for 'make a new keypair' */
  kp1 = ed_key_new(NULL, 0, 0, 0, 0, &cert);
  tt_assert(kp1);

  /* Create a new certificate signed by kp1. */
  kp2 = ed_key_new(kp1, INIT_ED_KEY_NEEDCERT, now, 3600, 4, &cert);
  tt_assert(kp2);
  tt_assert(cert);
  tt_mem_op(&cert->signed_key, OP_EQ, &kp2->pubkey,
            sizeof(ed25519_public_key_t));
  tt_assert(! cert->signing_key_included);

  tt_int_op(cert->valid_until, OP_GE, now);
  tt_int_op(cert->valid_until, OP_LE, now+7200);

  /* Create a new key-including certificate signed by kp1 */
  ed25519_keypair_free(kp2);
  tor_cert_free(cert);
  cert = NULL; kp2 = NULL;
  kp2 = ed_key_new(kp1, (INIT_ED_KEY_NEEDCERT|
                         INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT),
                   now, 3600, 4, &cert);
  tt_assert(kp2);
  tt_assert(cert);
  tt_assert(cert->signing_key_included);
  tt_mem_op(&cert->signed_key, OP_EQ, &kp2->pubkey,
            sizeof(ed25519_public_key_t));
  tt_mem_op(&cert->signing_key, OP_EQ, &kp1->pubkey,
            sizeof(ed25519_public_key_t));

 done:
  ed25519_keypair_free(kp1);
  ed25519_keypair_free(kp2);
  tor_cert_free(cert);
}
Example #4
0
/** Parse a certificate encoded with <b>len</b> bytes in <b>encoded</b>. */
tor_cert_t *
tor_cert_parse(const uint8_t *encoded, const size_t len)
{
  tor_cert_t *cert = NULL;
  ed25519_cert_t *parsed = NULL;
  ssize_t got_len = ed25519_cert_parse(&parsed, encoded, len);
  if (got_len < 0 || (size_t) got_len != len)
    goto err;

  cert = tor_malloc_zero(sizeof(tor_cert_t));
  cert->encoded = tor_memdup(encoded, len);
  cert->encoded_len = len;

  memcpy(cert->signed_key.pubkey, parsed->certified_key, 32);
  int64_t valid_until_64 = ((int64_t)parsed->exp_field) * 3600;
#if SIZEOF_TIME_T < SIZEOF_INT64_T
  if (valid_until_64 > TIME_MAX)
    valid_until_64 = TIME_MAX - 1;
#endif
  cert->valid_until = (time_t) valid_until_64;
  cert->cert_type = parsed->cert_type;

  for (unsigned i = 0; i < ed25519_cert_getlen_ext(parsed); ++i) {
    ed25519_cert_extension_t *ext = ed25519_cert_get_ext(parsed, i);
    if (ext->ext_type == CERTEXT_SIGNED_WITH_KEY) {
      if (cert->signing_key_included)
        goto err;

      cert->signing_key_included = 1;
      memcpy(cert->signing_key.pubkey, ext->un_signing_key, 32);
    } else if (ext->ext_flags & CERTEXT_FLAG_AFFECTS_VALIDATION) {
      /* Unrecognized extension with affects_validation set */
      goto err;
    }
  }

  goto done;
 err:
  tor_cert_free(cert);
  cert = NULL;
 done:
  ed25519_cert_free(parsed);
  return cert;
}
Example #5
0
/** Process a CERTS cell from an OR connection.
 *
 * If the other side should not have sent us a CERTS cell, or the cell is
 * malformed, or it is supposed to authenticate the TLS key but it doesn't,
 * then mark the connection.
 *
 * If the cell has a good cert chain and we're doing a v3 handshake, then
 * store the certificates in or_handshake_state.  If this is the client side
 * of the connection, we then authenticate the server or mark the connection.
 * If it's the server side, wait for an AUTHENTICATE cell.
 */
static void
command_process_certs_cell(var_cell_t *cell, or_connection_t *conn)
{
#define ERR(s)                                                  \
  do {                                                          \
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,                      \
           "Received a bad CERTS cell from %s:%d: %s",          \
           safe_str(conn->_base.address), conn->_base.port, (s)); \
    connection_mark_for_close(TO_CONN(conn));                   \
    goto err;                                                   \
  } while (0)

  tor_cert_t *link_cert = NULL;
  tor_cert_t *id_cert = NULL;
  tor_cert_t *auth_cert = NULL;

  uint8_t *ptr;
  int n_certs, i;

  if (conn->_base.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
    ERR("We're not doing a v3 handshake!");
  if (conn->link_proto < 3)
    ERR("We're not using link protocol >= 3");
  if (conn->handshake_state->received_certs_cell)
    ERR("We already got one");
  if (conn->handshake_state->authenticated) {
    /* Should be unreachable, but let's make sure. */
    ERR("We're already authenticated!");
  }
  if (cell->payload_len < 1)
    ERR("It had no body");
  if (cell->circ_id)
    ERR("It had a nonzero circuit ID");

  n_certs = cell->payload[0];
  ptr = cell->payload + 1;
  for (i = 0; i < n_certs; ++i) {
    uint8_t cert_type;
    uint16_t cert_len;
    if (ptr + 3 > cell->payload + cell->payload_len) {
      goto truncated;
    }
    cert_type = *ptr;
    cert_len = ntohs(get_uint16(ptr+1));
    if (ptr + 3 + cert_len > cell->payload + cell->payload_len) {
      goto truncated;
    }
    if (cert_type == OR_CERT_TYPE_TLS_LINK ||
        cert_type == OR_CERT_TYPE_ID_1024 ||
        cert_type == OR_CERT_TYPE_AUTH_1024) {
      tor_cert_t *cert = tor_cert_decode(ptr + 3, cert_len);
      if (!cert) {
        log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
               "Received undecodable certificate in CERTS cell from %s:%d",
               safe_str(conn->_base.address), conn->_base.port);
      } else {
        if (cert_type == OR_CERT_TYPE_TLS_LINK) {
          if (link_cert) {
            tor_cert_free(cert);
            ERR("Too many TLS_LINK certificates");
          }
          link_cert = cert;
        } else if (cert_type == OR_CERT_TYPE_ID_1024) {
          if (id_cert) {
            tor_cert_free(cert);
            ERR("Too many ID_1024 certificates");
          }
          id_cert = cert;
        } else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
          if (auth_cert) {
            tor_cert_free(cert);
            ERR("Too many AUTH_1024 certificates");
          }
          auth_cert = cert;
        } else {
          tor_cert_free(cert);
        }
      }
    }
    ptr += 3 + cert_len;
    continue;

  truncated:
    ERR("It ends in the middle of a certificate");
  }

  if (conn->handshake_state->started_here) {
    int severity;
    if (! (id_cert && link_cert))
      ERR("The certs we wanted were missing");
    /* Okay. We should be able to check the certificates now. */
    if (! tor_tls_cert_matches_key(conn->tls, link_cert)) {
      ERR("The link certificate didn't match the TLS public key");
    }
    /* Note that this warns more loudly about time and validity if we were
    * _trying_ to connect to an authority, not necessarily if we _did_ connect
    * to one. */
    if (router_digest_is_trusted_dir(conn->identity_digest))
      severity = LOG_WARN;
    else
      severity = LOG_PROTOCOL_WARN;

    if (! tor_tls_cert_is_valid(severity, link_cert, id_cert, 0))
      ERR("The link certificate was not valid");
    if (! tor_tls_cert_is_valid(severity, id_cert, id_cert, 1))
      ERR("The ID certificate was not valid");

    conn->handshake_state->authenticated = 1;
    {
      const digests_t *id_digests = tor_cert_get_id_digests(id_cert);
      crypto_pk_t *identity_rcvd;
      if (!id_digests)
        ERR("Couldn't compute digests for key in ID cert");

      identity_rcvd = tor_tls_cert_get_key(id_cert);
      if (!identity_rcvd)
        ERR("Internal error: Couldn't get RSA key from ID cert.");
      memcpy(conn->handshake_state->authenticated_peer_id,
             id_digests->d[DIGEST_SHA1], DIGEST_LEN);
      connection_or_set_circid_type(conn, identity_rcvd);
      crypto_pk_free(identity_rcvd);
    }

    if (connection_or_client_learned_peer_id(conn,
                      conn->handshake_state->authenticated_peer_id) < 0)
      ERR("Problem setting or checking peer id");

    log_info(LD_OR, "Got some good certificates from %s:%d: Authenticated it.",
             safe_str(conn->_base.address), conn->_base.port);

    conn->handshake_state->id_cert = id_cert;
    id_cert = NULL;
  } else {
    if (! (id_cert && auth_cert))
      ERR("The certs we wanted were missing");

    /* Remember these certificates so we can check an AUTHENTICATE cell */
    if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, auth_cert, id_cert, 1))
      ERR("The authentication certificate was not valid");
    if (! tor_tls_cert_is_valid(LOG_PROTOCOL_WARN, id_cert, id_cert, 1))
      ERR("The ID certificate was not valid");

    log_info(LD_OR, "Got some good certificates from %s:%d: "
             "Waiting for AUTHENTICATE.",
             safe_str(conn->_base.address), conn->_base.port);
    /* XXXX check more stuff? */

    conn->handshake_state->id_cert = id_cert;
    conn->handshake_state->auth_cert = auth_cert;
    id_cert = auth_cert = NULL;
  }

  conn->handshake_state->received_certs_cell = 1;
 err:
  tor_cert_free(id_cert);
  tor_cert_free(link_cert);
  tor_cert_free(auth_cert);
#undef ERR
}
Example #6
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;
}
Example #7
0
/**
 * Read an ed25519 key and associated certificates from files beginning with
 * <b>fname</b>, with certificate type <b>cert_type</b>.  On failure, return
 * NULL; on success return the keypair.
 *
 * If INIT_ED_KEY_CREATE is set in <b>flags</b>, then create the key (and
 * certificate if requested) if it doesn't exist, and save it to disk.
 *
 * If INIT_ED_KEY_NEEDCERT is set in <b>flags</b>, load/create a certificate
 * too and store it in *<b>cert_out</b>.  Fail if the cert can't be
 * found/created.  To create a certificate, <b>signing_key</b> must be set to
 * the key that should sign it; <b>now</b> to the current time, and
 * <b>lifetime</b> to the lifetime of the key.
 *
 * If INIT_ED_KEY_REPLACE is set in <b>flags</b>, then create and save new key
 * whether we can read the old one or not.
 *
 * If INIT_ED_KEY_EXTRA_STRONG is set in <b>flags</b>, set the extra_strong
 * flag when creating the secret key.
 *
 * If INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT is set in <b>flags</b>, and
 * we create a new certificate, create it with the signing key embedded.
 *
 * If INIT_ED_KEY_SPLIT is set in <b>flags</b>, and we create a new key,
 * store the public key in a separate file from the secret key.
 *
 * If INIT_ED_KEY_MISSING_SECRET_OK is set in <b>flags</b>, and we find a
 * public key file but no secret key file, return successfully anyway.
 *
 * If INIT_ED_KEY_OMIT_SECRET is set in <b>flags</b>, do not try to load a
 * secret key unless no public key is found.  Do not return a secret key. (but
 * create and save one if needed).
 *
 * If INIT_ED_KEY_NO_LOAD_SECRET is set in <b>flags</b>, don't try to load
 * a secret key, no matter what.
 *
 * If INIT_ED_KEY_TRY_ENCRYPTED is set, we look for an encrypted secret key
 * 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_ (full or partial), we do not try to
 * replace them.
 *
 * If INIT_ED_KEY_SUGGEST_KEYGEN is set, have log messages about failures
 * refer to the --keygen option.
 *
 * If INIT_ED_KEY_EXPLICIT_FNAME is set, use the provided file name for the
 * secret key file, encrypted or not.
 */
ed25519_keypair_t *
ed_key_init_from_file(const char *fname, uint32_t flags,
                      int severity,
                      const ed25519_keypair_t *signing_key,
                      time_t now,
                      time_t lifetime,
                      uint8_t cert_type,
                      struct tor_cert_st **cert_out)
{
  char *secret_fname = NULL;
  char *encrypted_secret_fname = NULL;
  char *public_fname = NULL;
  char *cert_fname = NULL;
  const char *loaded_secret_fname = NULL;
  int created_pk = 0, created_sk = 0, created_cert = 0;
  const int try_to_load = ! (flags & INIT_ED_KEY_REPLACE);
  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);
  const int offline_secret = !! (flags & INIT_ED_KEY_OFFLINE_SECRET);
  const int explicit_fname = !! (flags & INIT_ED_KEY_EXPLICIT_FNAME);

  /* we don't support setting both of these flags at once. */
  tor_assert((flags & (INIT_ED_KEY_NO_REPAIR|INIT_ED_KEY_NEEDCERT)) !=
                      (INIT_ED_KEY_NO_REPAIR|INIT_ED_KEY_NEEDCERT));

  char tag[8];
  tor_snprintf(tag, sizeof(tag), "type%d", (int)cert_type);

  tor_cert_t *cert = NULL;
  char *got_tag = NULL;
  ed25519_keypair_t *keypair = tor_malloc_zero(sizeof(ed25519_keypair_t));

  if (explicit_fname) {
    secret_fname = tor_strdup(fname);
    encrypted_secret_fname = tor_strdup(fname);
  } else {
    tor_asprintf(&secret_fname, "%s_secret_key", fname);
    tor_asprintf(&encrypted_secret_fname, "%s_secret_key_encrypted", fname);
  }
  tor_asprintf(&public_fname, "%s_public_key", fname);
  tor_asprintf(&cert_fname, "%s_cert", fname);

  /* Try to read the secret key. */
  int have_secret = 0;
  int load_secret = try_to_load &&
    !offline_secret &&
    (!omit_secret || file_status(public_fname)==FN_NOENT);
  if (load_secret) {
    int rv = ed25519_seckey_read_from_file(&keypair->seckey,
                                           &got_tag, secret_fname);
    if (rv == 0) {
      have_secret = 1;
      loaded_secret_fname = secret_fname;
      tor_assert(got_tag);
    } else {
      if (errno != ENOENT && norepair) {
        tor_log(severity, LD_OR, "Unable to read %s: %s", secret_fname,
                strerror(errno));
        goto err;
      }
    }
  }

  /* 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;
      tor_free(got_tag); /* convince coverity we aren't leaking */
      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));
      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) {
    if (strcmp(got_tag, tag)) {
      tor_log(severity, LD_OR, "%s has wrong tag", loaded_secret_fname);
      goto err;
    }
    /* Derive the public key */
    if (ed25519_public_key_generate(&keypair->pubkey, &keypair->seckey)<0) {
      tor_log(severity, LD_OR, "%s can't produce a public key",
              loaded_secret_fname);
      goto err;
    }
  }

  /* If we do split keys here, try to read the pubkey. */
  int found_public = 0;
  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,
                                                 &got_tag, public_fname) == 0;
    if (!found_public && errno != ENOENT && norepair) {
      tor_log(severity, LD_OR, "Unable to read %s: %s", public_fname,
              strerror(errno));
      goto err;
    }
    if (found_public && strcmp(got_tag, tag)) {
      tor_log(severity, LD_OR, "%s has wrong tag", public_fname);
      goto err;
    }
    if (found_public) {
      if (have_secret) {
        /* If we have a secret key and we're reloading the public key,
         * the key must match! */
        if (! ed25519_pubkey_eq(&keypair->pubkey, &pubkey_tmp)) {
          tor_log(severity, LD_OR, "%s does not match %s!  If you are trying "
                  "to restore from backup, make sure you didn't mix up the "
                  "key files. If you are absolutely sure that %s is the right "
                  "key for this relay, delete %s or move it out of the way.",
                  public_fname, loaded_secret_fname,
                  loaded_secret_fname, public_fname);
          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(LOG_NOTICE, LD_OR,
                  "Found secret key but not %s. Regenerating.",
                  public_fname);
        }
      }
    }
  }

  /* If the secret key is absent and it's not allowed to be, fail. */
  if (!have_secret && found_public &&
      !(flags & INIT_ED_KEY_MISSING_SECRET_OK)) {
    if (have_encrypted_secret_file) {
      tor_log(severity, LD_OR, "We needed to load a secret key from %s, "
              "but it was encrypted. Try 'tor --keygen' instead, so you "
              "can enter the passphrase.",
              secret_fname);
    } else {
      tor_log(severity, LD_OR, "We needed to load a secret key from %s, "
              "but couldn't find it. %s", secret_fname,
              (flags & INIT_ED_KEY_SUGGEST_KEYGEN) ?
              "If you're keeping your master secret key offline, you will "
              "need to run 'tor --keygen' to generate new signing keys." :
              "Did you forget to copy it over when you copied the rest of the "
              "signing key material?");
    }
    goto err;
  }

  /* If it's absent, and we're not supposed to make a new keypair, fail. */
  if (!have_secret && !found_public && !(flags & INIT_ED_KEY_CREATE)) {
    if (split) {
      tor_log(severity, LD_OR, "No key found in %s or %s.",
              secret_fname, public_fname);
    } else {
      tor_log(severity, LD_OR, "No key found in %s.", secret_fname);
    }
    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... */
  if (!have_secret && !found_public) {
    tor_free(keypair);
    keypair = ed_key_new(signing_key, flags, now, lifetime,
                         cert_type, &cert);
    if (!keypair) {
      tor_log(severity, LD_OR, "Couldn't create keypair");
      goto err;
    }
    created_pk = created_sk = created_cert = 1;
  }

  /* Write it to disk if we're supposed to do with a new passphrase, or if
   * we just created it. */
  if (created_sk || (have_secret && get_options()->change_key_passphrase)) {
    if (write_secret_key(&keypair->seckey,
                         encrypt_key,
                         secret_fname, tag, encrypted_secret_fname) < 0
        ||
        (split &&
         ed25519_pubkey_write_to_file(&keypair->pubkey, public_fname, tag) < 0)
        ||
        (cert &&
         crypto_write_tagged_contents_to_file(cert_fname, "ed25519v1-cert",
                                 tag, cert->encoded, cert->encoded_len) < 0)) {
      tor_log(severity, LD_OR, "Couldn't write keys or cert to file.");
      goto err;
    }
    goto done;
  }

  /* If we're not supposed to get a cert, we're done. */
  if (! (flags & INIT_ED_KEY_NEEDCERT))
    goto done;

  /* Read a cert. */
  tor_free(got_tag);
  uint8_t certbuf[256];
  ssize_t cert_body_len = crypto_read_tagged_contents_from_file(
                 cert_fname, "ed25519v1-cert",
                 &got_tag, certbuf, sizeof(certbuf));
  if (cert_body_len >= 0 && !strcmp(got_tag, tag))
    cert = tor_cert_parse(certbuf, cert_body_len);

  /* If we got it, check it to the extent we can. */
  int bad_cert = 0;

  if (! cert) {
    tor_log(severity, LD_OR, "Cert was unparseable");
    bad_cert = 1;
  } else if (!tor_memeq(cert->signed_key.pubkey, keypair->pubkey.pubkey,
                        ED25519_PUBKEY_LEN)) {
    tor_log(severity, LD_OR, "Cert was for wrong key");
    bad_cert = 1;
  } else if (signing_key &&
             tor_cert_checksig(cert, &signing_key->pubkey, now) < 0) {
    tor_log(severity, LD_OR, "Can't check certificate");
    bad_cert = 1;
  } else if (cert->cert_expired) {
    tor_log(severity, LD_OR, "Certificate is expired");
    bad_cert = 1;
  } else if (signing_key && cert->signing_key_included &&
             ! ed25519_pubkey_eq(&signing_key->pubkey, &cert->signing_key)) {
    tor_log(severity, LD_OR, "Certificate signed by unexpectd key!");
    bad_cert = 1;
  }

  if (bad_cert) {
    tor_cert_free(cert);
    cert = NULL;
  }

  /* If we got a cert, we're done. */
  if (cert)
    goto done;

  /* If we didn't get a cert, and we're not supposed to make one, fail. */
  if (!signing_key || !(flags & INIT_ED_KEY_CREATE)) {
    tor_log(severity, LD_OR, "Without signing key, can't create certificate");
    goto err;
  }

  /* We have keys but not a certificate, so make one. */
  uint32_t cert_flags = 0;
  if (flags & INIT_ED_KEY_INCLUDE_SIGNING_KEY_IN_CERT)
    cert_flags |= CERT_FLAG_INCLUDE_SIGNING_KEY;
  cert = tor_cert_create(signing_key, cert_type,
                         &keypair->pubkey,
                         now, lifetime,
                         cert_flags);

  if (! cert) {
    tor_log(severity, LD_OR, "Couldn't create certificate");
    goto err;
  }

  /* Write it to disk. */
  created_cert = 1;
  if (crypto_write_tagged_contents_to_file(cert_fname, "ed25519v1-cert",
                             tag, cert->encoded, cert->encoded_len) < 0) {
    tor_log(severity, LD_OR, "Couldn't write cert to disk.");
    goto err;
  }

 done:
  if (cert_out)
    *cert_out = cert;
  else
    tor_cert_free(cert);

  goto cleanup;

 err:
  if (keypair)
    memwipe(keypair, 0, sizeof(*keypair));
  tor_free(keypair);
  tor_cert_free(cert);
  if (cert_out)
    *cert_out = NULL;
  if (created_sk)
    unlink(secret_fname);
  if (created_pk)
    unlink(public_fname);
  if (created_cert)
    unlink(cert_fname);

 cleanup:
  tor_free(encrypted_secret_fname);
  tor_free(secret_fname);
  tor_free(public_fname);
  tor_free(cert_fname);
  tor_free(got_tag);

  return keypair;
}
Example #8
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;
}
Example #9
0
/** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519
 * key.
 */
static tor_cert_t *
tor_cert_sign_impl(const ed25519_keypair_t *signing_key,
                      uint8_t cert_type,
                      uint8_t signed_key_type,
                      const uint8_t signed_key_info[32],
                      time_t now, time_t lifetime,
                      uint32_t flags)
{
  tor_cert_t *torcert = NULL;

  ed25519_cert_t *cert = ed25519_cert_new();
  cert->cert_type = cert_type;
  cert->exp_field = (uint32_t) CEIL_DIV(now + lifetime, 3600);
  cert->cert_key_type = signed_key_type;
  memcpy(cert->certified_key, signed_key_info, 32);

  if (flags & CERT_FLAG_INCLUDE_SIGNING_KEY) {
    ed25519_cert_extension_t *ext = ed25519_cert_extension_new();
    ext->ext_type = CERTEXT_SIGNED_WITH_KEY;
    memcpy(ext->un_signing_key, signing_key->pubkey.pubkey, 32);
    ed25519_cert_add_ext(cert, ext);
    ++cert->n_extensions;
  }

  const ssize_t alloc_len = ed25519_cert_encoded_len(cert);
  tor_assert(alloc_len > 0);
  uint8_t *encoded = tor_malloc(alloc_len);
  const ssize_t real_len = ed25519_cert_encode(encoded, alloc_len, cert);
  if (real_len < 0)
    goto err;
  tor_assert(real_len == alloc_len);
  tor_assert(real_len > ED25519_SIG_LEN);
  uint8_t *sig = encoded + (real_len - ED25519_SIG_LEN);
  tor_assert(tor_mem_is_zero((char*)sig, ED25519_SIG_LEN));

  ed25519_signature_t signature;
  if (ed25519_sign(&signature, encoded,
                   real_len-ED25519_SIG_LEN, signing_key)<0) {
    log_warn(LD_BUG, "Can't sign certificate");
    goto err;
  }
  memcpy(sig, signature.sig, ED25519_SIG_LEN);

  torcert = tor_cert_parse(encoded, real_len);
  if (! torcert) {
    log_warn(LD_BUG, "Generated a certificate we cannot parse");
    goto err;
  }

  if (tor_cert_checksig(torcert, &signing_key->pubkey, now) < 0) {
    log_warn(LD_BUG, "Generated a certificate whose signature we can't check");
    goto err;
  }

  tor_free(encoded);

  goto done;

 err:
  tor_cert_free(torcert);
  torcert = NULL;
 done:
  ed25519_cert_free(cert);
  tor_free(encoded);
  return torcert;
}
Example #10
0
static void
test_routerkeys_ed_certs(void *args)
{
  (void)args;
  ed25519_keypair_t kp1, kp2;
  tor_cert_t *cert[2] = {NULL, NULL}, *nocert = NULL;
  tor_cert_t *parsed_cert[2] = {NULL, NULL};
  time_t now = 1412094534;
  uint8_t *junk = NULL;
  char *base64 = NULL;

  tt_int_op(0,OP_EQ,ed25519_keypair_generate(&kp1, 0));
  tt_int_op(0,OP_EQ,ed25519_keypair_generate(&kp2, 0));

  for (int i = 0; i <= 1; ++i) {
    uint32_t flags = i ? CERT_FLAG_INCLUDE_SIGNING_KEY : 0;

    cert[i] = tor_cert_create(&kp1, 5, &kp2.pubkey, now, 10000, flags);
    tt_assert(cert[i]);

    tt_uint_op(cert[i]->sig_bad, OP_EQ, 0);
    tt_uint_op(cert[i]->sig_ok, OP_EQ, 1);
    tt_uint_op(cert[i]->cert_expired, OP_EQ, 0);
    tt_uint_op(cert[i]->cert_valid, OP_EQ, 1);
    tt_int_op(cert[i]->cert_type, OP_EQ, 5);
    tt_mem_op(cert[i]->signed_key.pubkey, OP_EQ, &kp2.pubkey.pubkey, 32);
    tt_mem_op(cert[i]->signing_key.pubkey, OP_EQ, &kp1.pubkey.pubkey, 32);
    tt_int_op(cert[i]->signing_key_included, OP_EQ, i);

    tt_assert(cert[i]->encoded);
    tt_int_op(cert[i]->encoded_len, OP_EQ, 104 + 36 * i);
    tt_int_op(cert[i]->encoded[0], OP_EQ, 1);
    tt_int_op(cert[i]->encoded[1], OP_EQ, 5);

    parsed_cert[i] = tor_cert_parse(cert[i]->encoded, cert[i]->encoded_len);
    tt_assert(parsed_cert[i]);
    tt_int_op(cert[i]->encoded_len, OP_EQ, parsed_cert[i]->encoded_len);
    tt_mem_op(cert[i]->encoded, OP_EQ, parsed_cert[i]->encoded,
              cert[i]->encoded_len);
    tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0);
    tt_uint_op(parsed_cert[i]->sig_ok, OP_EQ, 0);
    tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 0);
    tt_uint_op(parsed_cert[i]->cert_valid, OP_EQ, 0);

    /* Expired */
    tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now + 30000),
              OP_LT, 0);
    tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 1);
    parsed_cert[i]->cert_expired = 0;

    /* Wrong key */
    tt_int_op(tor_cert_checksig(parsed_cert[i], &kp2.pubkey, now), OP_LT, 0);
    tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 1);
    parsed_cert[i]->sig_bad = 0;

    /* Missing key */
    int ok = tor_cert_checksig(parsed_cert[i], NULL, now);
    tt_int_op(ok < 0, OP_EQ, i == 0);
    tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0);
    tt_assert(parsed_cert[i]->sig_ok == (i != 0));
    tt_assert(parsed_cert[i]->cert_valid == (i != 0));
    parsed_cert[i]->sig_bad = 0;
    parsed_cert[i]->sig_ok = 0;
    parsed_cert[i]->cert_valid = 0;

    /* Right key */
    tt_int_op(tor_cert_checksig(parsed_cert[i], &kp1.pubkey, now), OP_EQ, 0);
    tt_uint_op(parsed_cert[i]->sig_bad, OP_EQ, 0);
    tt_uint_op(parsed_cert[i]->sig_ok, OP_EQ, 1);
    tt_uint_op(parsed_cert[i]->cert_expired, OP_EQ, 0);
    tt_uint_op(parsed_cert[i]->cert_valid, OP_EQ, 1);
  }

  /* Now try some junky certs. */
  /* - Truncated */
  nocert = tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len-1);
  tt_ptr_op(NULL, OP_EQ, nocert);

  /* - First byte modified */
  cert[0]->encoded[0] = 99;
  nocert = tor_cert_parse(cert[0]->encoded, cert[0]->encoded_len);
  tt_ptr_op(NULL, OP_EQ, nocert);
  cert[0]->encoded[0] = 1;

  /* - Extra byte at the end*/
  junk = tor_malloc_zero(cert[0]->encoded_len + 1);
  memcpy(junk, cert[0]->encoded, cert[0]->encoded_len);
  nocert = tor_cert_parse(junk, cert[0]->encoded_len+1);
  tt_ptr_op(NULL, OP_EQ, nocert);

  /* - Multiple signing key instances */
  tor_free(junk);
  junk = tor_malloc_zero(104 + 36 * 2);
  junk[0] = 1; /* version */
  junk[1] = 5; /* cert type */
  junk[6] = 1; /* key type */
  junk[39] = 2; /* n_extensions */
  junk[41] = 32; /* extlen */
  junk[42] = 4; /* exttype */
  junk[77] = 32; /* extlen */
  junk[78] = 4; /* exttype */
  nocert = tor_cert_parse(junk, 104 + 36 * 2);
  tt_ptr_op(NULL, OP_EQ, nocert);

 done:
  tor_cert_free(cert[0]);
  tor_cert_free(cert[1]);
  tor_cert_free(parsed_cert[0]);
  tor_cert_free(parsed_cert[1]);
  tor_cert_free(nocert);
  tor_free(junk);
  tor_free(base64);
}
Example #11
0
static void
test_routerkeys_ed_keys_init_all(void *arg)
{
  (void)arg;
  char *dir = tor_strdup(get_fname("test_ed_keys_init_all"));
  char *keydir = tor_strdup(get_fname("test_ed_keys_init_all/KEYS"));
  or_options_t *options = tor_malloc_zero(sizeof(or_options_t));
  time_t now = time(NULL);
  ed25519_public_key_t id;
  ed25519_keypair_t sign, auth;
  tor_cert_t *link_cert = NULL;

  get_options_mutable()->ORPort_set = 1;

  crypto_pk_t *rsa = pk_generate(0);

  set_server_identity_key(rsa);
  set_client_identity_key(rsa);

  router_initialize_tls_context();

  options->SigningKeyLifetime = 30*86400;
  options->TestingAuthKeyLifetime = 2*86400;
  options->TestingLinkCertLifetime = 2*86400;
  options->TestingSigningKeySlop = 2*86400;
  options->TestingAuthKeySlop = 2*3600;
  options->TestingLinkKeySlop = 2*3600;

#ifdef _WIN32
  mkdir(dir);
  mkdir(keydir);
#else
  mkdir(dir, 0700);
  mkdir(keydir, 0700);
#endif /* defined(_WIN32) */

  options->DataDirectory = dir;
  options->KeyDirectory = keydir;

  tt_int_op(1, OP_EQ, load_ed_keys(options, now));
  tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
  tt_assert(get_master_identity_key());
  tt_assert(get_master_identity_key());
  tt_assert(get_master_signing_keypair());
  tt_assert(get_current_auth_keypair());
  tt_assert(get_master_signing_key_cert());
  tt_assert(get_current_link_cert_cert());
  tt_assert(get_current_auth_key_cert());
  memcpy(&id, get_master_identity_key(), sizeof(id));
  memcpy(&sign, get_master_signing_keypair(), sizeof(sign));
  memcpy(&auth, get_current_auth_keypair(), sizeof(auth));
  link_cert = tor_cert_dup(get_current_link_cert_cert());

  /* Call load_ed_keys again, but nothing has changed. */
  tt_int_op(0, OP_EQ, load_ed_keys(options, now));
  tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
  tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
  tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
  tt_mem_op(&auth, OP_EQ, get_current_auth_keypair(), sizeof(auth));
  tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));

  /* Force a reload: we make new link/auth keys. */
  routerkeys_free_all();
  tt_int_op(1, OP_EQ, load_ed_keys(options, now));
  tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
  tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
  tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
  tt_assert(tor_cert_eq(link_cert, get_current_link_cert_cert()));
  tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
  tt_assert(get_master_signing_key_cert());
  tt_assert(get_current_link_cert_cert());
  tt_assert(get_current_auth_key_cert());
  tor_cert_free(link_cert);
  link_cert = tor_cert_dup(get_current_link_cert_cert());
  memcpy(&auth, get_current_auth_keypair(), sizeof(auth));

  /* Force a link/auth-key regeneration by advancing time. */
  tt_int_op(0, OP_EQ, load_ed_keys(options, now+3*86400));
  tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now+3*86400, 0));
  tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
  tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
  tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
  tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
  tt_assert(get_master_signing_key_cert());
  tt_assert(get_current_link_cert_cert());
  tt_assert(get_current_auth_key_cert());
  tor_cert_free(link_cert);
  link_cert = tor_cert_dup(get_current_link_cert_cert());
  memcpy(&auth, get_current_auth_keypair(), sizeof(auth));

  /* Force a signing-key regeneration by advancing time. */
  tt_int_op(1, OP_EQ, load_ed_keys(options, now+100*86400));
  tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now+100*86400, 0));
  tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
  tt_mem_op(&sign, OP_NE, get_master_signing_keypair(), sizeof(sign));
  tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
  tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
  tt_assert(get_master_signing_key_cert());
  tt_assert(get_current_link_cert_cert());
  tt_assert(get_current_auth_key_cert());
  memcpy(&sign, get_master_signing_keypair(), sizeof(sign));
  tor_cert_free(link_cert);
  link_cert = tor_cert_dup(get_current_link_cert_cert());
  memcpy(&auth, get_current_auth_keypair(), sizeof(auth));

  /* Demonstrate that we can start up with no secret identity key */
  routerkeys_free_all();
  unlink(get_fname("test_ed_keys_init_all/KEYS/"
                   "ed25519_master_id_secret_key"));
  tt_int_op(1, OP_EQ, load_ed_keys(options, now));
  tt_int_op(0, OP_EQ, generate_ed_link_cert(options, now, 0));
  tt_mem_op(&id, OP_EQ, get_master_identity_key(), sizeof(id));
  tt_mem_op(&sign, OP_EQ, get_master_signing_keypair(), sizeof(sign));
  tt_assert(! tor_cert_eq(link_cert, get_current_link_cert_cert()));
  tt_mem_op(&auth, OP_NE, get_current_auth_keypair(), sizeof(auth));
  tt_assert(get_master_signing_key_cert());
  tt_assert(get_current_link_cert_cert());
  tt_assert(get_current_auth_key_cert());

  /* But we're in trouble if we have no id key and our signing key has
     expired. */
  log_global_min_severity_ = LOG_ERR; /* Suppress warnings.
                                       * XXX (better way to do this)? */
  routerkeys_free_all();
  tt_int_op(-1, OP_EQ, load_ed_keys(options, now+200*86400));

 done:
  tor_free(dir);
  tor_free(keydir);
  tor_free(options);
  tor_cert_free(link_cert);
  routerkeys_free_all();
}
Example #12
0
static void
test_routerkeys_ed_key_init_split(void *arg)
{
  (void) arg;

  tor_cert_t *cert = NULL;
  ed25519_keypair_t *kp1 = NULL, *kp2 = NULL;
  time_t now = time(NULL);
  char *fname1 = tor_strdup(get_fname("test_ed_key_3"));
  char *fname2 = tor_strdup(get_fname("test_ed_key_4"));
  struct stat st;
  const uint32_t flags = INIT_ED_KEY_SPLIT|INIT_ED_KEY_MISSING_SECRET_OK;

  unlink(fname1);
  unlink(fname2);

  /* Can't load key that isn't there. */
  kp1 = ed_key_init_from_file(fname1, flags, LOG_INFO, NULL, now, 0, 7, &cert);
  tt_assert(kp1 == NULL);
  tt_assert(cert == NULL);

  /* Create a split key */
  kp1 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
                              LOG_INFO, NULL, now, 0, 7, &cert);
  tt_assert(kp1 != NULL);
  tt_assert(cert == NULL);
  tt_int_op(stat(get_fname("test_ed_key_3_cert"), &st), OP_LT, 0);
  tt_int_op(stat(get_fname("test_ed_key_3_secret_key"), &st), OP_EQ, 0);
  tt_int_op(stat(get_fname("test_ed_key_3_public_key"), &st), OP_EQ, 0);

  /* Load it. */
  kp2 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
                              LOG_INFO, NULL, now, 0, 7, &cert);
  tt_assert(kp2 != NULL);
  tt_assert(cert == NULL);
  tt_mem_op(kp1, OP_EQ, kp2, sizeof(*kp2));
  ed25519_keypair_free(kp2); kp2 = NULL;

  /* Okay, try killing the secret key and loading it. */
  unlink(get_fname("test_ed_key_3_secret_key"));
  kp2 = ed_key_init_from_file(fname1, flags,
                              LOG_INFO, NULL, now, 0, 7, &cert);
  tt_assert(kp2 != NULL);
  tt_assert(cert == NULL);
  tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey));
  tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
                            sizeof(kp2->seckey.seckey)));
  ed25519_keypair_free(kp2); kp2 = NULL;

  /* Even when we're told to "create", don't create if there's a public key */
  kp2 = ed_key_init_from_file(fname1, flags|INIT_ED_KEY_CREATE,
                              LOG_INFO, NULL, now, 0, 7, &cert);
  tt_assert(kp2 != NULL);
  tt_assert(cert == NULL);
  tt_mem_op(&kp1->pubkey, OP_EQ, &kp2->pubkey, sizeof(kp2->pubkey));
  tt_assert(tor_mem_is_zero((char*)kp2->seckey.seckey,
                            sizeof(kp2->seckey.seckey)));
  ed25519_keypair_free(kp2); kp2 = NULL;

  /* Make sure we fail on a tag mismatch, though */
  kp2 = ed_key_init_from_file(fname1, flags,
                              LOG_INFO, NULL, now, 0, 99, &cert);
  tt_assert(kp2 == NULL);

 done:
  ed25519_keypair_free(kp1);
  ed25519_keypair_free(kp2);
  tor_cert_free(cert);
  tor_free(fname1);
  tor_free(fname2);
}
Example #13
0
static void
test_routerkeys_ed_key_init_basic(void *arg)
{
  (void) arg;

  tor_cert_t *cert = NULL, *cert2 = NULL;
  ed25519_keypair_t *kp1 = NULL, *kp2 = NULL, *kp3 = NULL;
  time_t now = time(NULL);
  char *fname1 = tor_strdup(get_fname("test_ed_key_1"));
  char *fname2 = tor_strdup(get_fname("test_ed_key_2"));
  struct stat st;

  unlink(fname1);
  unlink(fname2);

  /* Fail to load a key that isn't there. */
  kp1 = ed_key_init_from_file(fname1, 0, LOG_INFO, NULL, now, 0, 7, &cert);
  tt_assert(kp1 == NULL);
  tt_assert(cert == NULL);

  /* Create the key if requested to do so. */
  kp1 = ed_key_init_from_file(fname1, INIT_ED_KEY_CREATE, LOG_INFO,
                              NULL, now, 0, 7, &cert);
  tt_assert(kp1 != NULL);
  tt_assert(cert == NULL);
  tt_int_op(stat(get_fname("test_ed_key_1_cert"), &st), OP_LT, 0);
  tt_int_op(stat(get_fname("test_ed_key_1_secret_key"), &st), OP_EQ, 0);

  /* Fail to load if we say we need a cert */
  kp2 = ed_key_init_from_file(fname1, INIT_ED_KEY_NEEDCERT, LOG_INFO,
                              NULL, now, 0, 7, &cert);
  tt_assert(kp2 == NULL);

  /* Fail to load if we say the wrong key type */
  kp2 = ed_key_init_from_file(fname1, 0, LOG_INFO,
                              NULL, now, 0, 6, &cert);
  tt_assert(kp2 == NULL);

  /* Load successfully if we're not picky, whether we say "create" or not. */
  kp2 = ed_key_init_from_file(fname1, INIT_ED_KEY_CREATE, LOG_INFO,
                              NULL, now, 0, 7, &cert);
  tt_assert(kp2 != NULL);
  tt_assert(cert == NULL);
  tt_mem_op(kp1, OP_EQ, kp2, sizeof(*kp1));
  ed25519_keypair_free(kp2); kp2 = NULL;

  kp2 = ed_key_init_from_file(fname1, 0, LOG_INFO,
                              NULL, now, 0, 7, &cert);
  tt_assert(kp2 != NULL);
  tt_assert(cert == NULL);
  tt_mem_op(kp1, OP_EQ, kp2, sizeof(*kp1));
  ed25519_keypair_free(kp2); kp2 = NULL;

  /* Now create a key with a cert. */
  kp2 = ed_key_init_from_file(fname2, (INIT_ED_KEY_CREATE|
                                       INIT_ED_KEY_NEEDCERT),
                              LOG_INFO, kp1, now, 7200, 7, &cert);
  tt_assert(kp2 != NULL);
  tt_assert(cert != NULL);
  tt_mem_op(kp1, OP_NE, kp2, sizeof(*kp1));
  tt_int_op(stat(get_fname("test_ed_key_2_cert"), &st), OP_EQ, 0);
  tt_int_op(stat(get_fname("test_ed_key_2_secret_key"), &st), OP_EQ, 0);

  tt_assert(cert->cert_valid == 1);
  tt_mem_op(&cert->signed_key, OP_EQ, &kp2->pubkey, 32);

  /* Now verify we can load the cert... */
  kp3 = ed_key_init_from_file(fname2, (INIT_ED_KEY_CREATE|
                                       INIT_ED_KEY_NEEDCERT),
                              LOG_INFO, kp1, now, 7200, 7, &cert2);
  tt_mem_op(kp2, OP_EQ, kp3, sizeof(*kp2));
  tt_mem_op(cert2->encoded, OP_EQ, cert->encoded, cert->encoded_len);
  ed25519_keypair_free(kp3); kp3 = NULL;
  tor_cert_free(cert2); cert2 = NULL;

  /* ... even without create... */
  kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
                              LOG_INFO, kp1, now, 7200, 7, &cert2);
  tt_mem_op(kp2, OP_EQ, kp3, sizeof(*kp2));
  tt_mem_op(cert2->encoded, OP_EQ, cert->encoded, cert->encoded_len);
  ed25519_keypair_free(kp3); kp3 = NULL;
  tor_cert_free(cert2); cert2 = NULL;

  /* ... but that we don't crash or anything if we say we don't want it. */
  kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
                              LOG_INFO, kp1, now, 7200, 7, NULL);
  tt_mem_op(kp2, OP_EQ, kp3, sizeof(*kp2));
  ed25519_keypair_free(kp3); kp3 = NULL;

  /* Fail if we're told the wrong signing key */
  kp3 = ed_key_init_from_file(fname2, INIT_ED_KEY_NEEDCERT,
                              LOG_INFO, kp2, now, 7200, 7, &cert2);
  tt_assert(kp3 == NULL);
  tt_assert(cert2 == NULL);

 done:
  ed25519_keypair_free(kp1);
  ed25519_keypair_free(kp2);
  ed25519_keypair_free(kp3);
  tor_cert_free(cert);
  tor_cert_free(cert2);
  tor_free(fname1);
  tor_free(fname2);
}