Exemple #1
0
/** Helper function: Compute the last part of the HS ntor handshake which
 *  derives key material necessary to create and handle RENDEZVOUS1
 *  cells. Function used by both client and service. The actual calculations is
 *  as follows:
 *
 *    NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
 *    verify = MAC(rend_secret_hs_input, t_hsverify)
 *    auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
 *    auth_input_mac = MAC(auth_input, t_hsmac)
 *
 *  where in the above, AUTH_KEY is <b>intro_auth_pubkey</b>, B is
 *  <b>intro_enc_pubkey</b>, Y is <b>service_ephemeral_rend_pubkey</b>, and X
 *  is <b>client_ephemeral_enc_pubkey</b>. The provided
 *  <b>rend_secret_hs_input</b> is of size REND_SECRET_HS_INPUT_LEN.
 *
 *  The final results of NTOR_KEY_SEED and auth_input_mac are placed in
 *  <b>hs_ntor_rend_cell_keys_out</b>. Return 0 if everything went fine. */
static int
get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input,
                  const ed25519_public_key_t *intro_auth_pubkey,
                  const curve25519_public_key_t *intro_enc_pubkey,
                  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
                  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
                  hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
{
  int bad = 0;
  uint8_t ntor_key_seed[DIGEST256_LEN];
  uint8_t ntor_verify[DIGEST256_LEN];
  uint8_t rend_auth_input[REND_AUTH_INPUT_LEN];
  uint8_t rend_cell_auth[DIGEST256_LEN];
  uint8_t *ptr;

  /* Let's build NTOR_KEY_SEED */
  crypto_mac_sha3_256(ntor_key_seed, sizeof(ntor_key_seed),
                      rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
                      (const uint8_t *)T_HSENC, strlen(T_HSENC));
  bad |= safe_mem_is_zero(ntor_key_seed, DIGEST256_LEN);

  /* Let's build ntor_verify */
  crypto_mac_sha3_256(ntor_verify, sizeof(ntor_verify),
                      rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
                      (const uint8_t *)T_HSVERIFY, strlen(T_HSVERIFY));
  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);

  /* Let's build auth_input: */
  ptr = rend_auth_input;
  /* Append ntor_verify */
  APPEND(ptr, ntor_verify, sizeof(ntor_verify));
  /* Append AUTH_KEY */
  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
  /* Append B */
  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
  /* Append Y */
  APPEND(ptr,
         service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN);
  /* Append X */
  APPEND(ptr,
         client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
  /* Append PROTOID */
  APPEND(ptr, PROTOID, strlen(PROTOID));
  /* Append "Server" */
  APPEND(ptr, SERVER_STR, strlen(SERVER_STR));
  tor_assert(ptr == rend_auth_input + sizeof(rend_auth_input));

  /* Let's build auth_input_mac that goes in RENDEZVOUS1 cell */
  crypto_mac_sha3_256(rend_cell_auth, sizeof(rend_cell_auth),
                      rend_auth_input, sizeof(rend_auth_input),
                      (const uint8_t *)T_HSMAC, strlen(T_HSMAC));
  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);

  { /* Get the computed RENDEZVOUS1 material! */
    memcpy(&hs_ntor_rend_cell_keys_out->rend_cell_auth_mac,
           rend_cell_auth, DIGEST256_LEN);
    memcpy(&hs_ntor_rend_cell_keys_out->ntor_key_seed,
           ntor_key_seed, DIGEST256_LEN);
  }

  memwipe(rend_cell_auth, 0, sizeof(rend_cell_auth));
  memwipe(rend_auth_input, 0, sizeof(rend_auth_input));
  memwipe(ntor_key_seed, 0, sizeof(ntor_key_seed));

  return bad;
}
Exemple #2
0
/** We received an ESTABLISH_INTRO <b>cell</b>. Verify its signature and MAC,
 *  given <b>circuit_key_material</b>. Return 0 on success else -1 on error. */
STATIC int
verify_establish_intro_cell(const trn_cell_establish_intro_t *cell,
                            const uint8_t *circuit_key_material,
                            size_t circuit_key_material_len)
{
  /* We only reach this function if the first byte of the cell is 0x02 which
   * means that auth_key_type is of ed25519 type, hence this check should
   * always pass. See hs_intro_received_establish_intro().  */
  if (BUG(cell->auth_key_type != HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
    return -1;
  }

  /* Make sure the auth key length is of the right size for this type. For
   * EXTRA safety, we check both the size of the array and the length which
   * must be the same. Safety first!*/
  if (trn_cell_establish_intro_getlen_auth_key(cell) != ED25519_PUBKEY_LEN ||
      trn_cell_establish_intro_get_auth_key_len(cell) != ED25519_PUBKEY_LEN) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
           "ESTABLISH_INTRO auth key length is invalid");
    return -1;
  }

  const uint8_t *msg = cell->start_cell;

  /* Verify the sig */
  {
    ed25519_signature_t sig_struct;
    const uint8_t *sig_array =
      trn_cell_establish_intro_getconstarray_sig(cell);

    /* Make sure the signature length is of the right size. For EXTRA safety,
     * we check both the size of the array and the length which must be the
     * same. Safety first!*/
    if (trn_cell_establish_intro_getlen_sig(cell) != sizeof(sig_struct.sig) ||
        trn_cell_establish_intro_get_sig_len(cell) != sizeof(sig_struct.sig)) {
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "ESTABLISH_INTRO sig len is invalid");
      return -1;
    }
    /* We are now sure that sig_len is of the right size. */
    memcpy(sig_struct.sig, sig_array, cell->sig_len);

    ed25519_public_key_t auth_key;
    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO, cell);

    const size_t sig_msg_len = cell->end_sig_fields - msg;
    int sig_mismatch = ed25519_checksig_prefixed(&sig_struct,
                                                 msg, sig_msg_len,
                                                 ESTABLISH_INTRO_SIG_PREFIX,
                                                 &auth_key);
    if (sig_mismatch) {
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "ESTABLISH_INTRO signature not as expected");
      return -1;
    }
  }

  /* Verify the MAC */
  {
    const size_t auth_msg_len = cell->end_mac_fields - msg;
    uint8_t mac[DIGEST256_LEN];
    crypto_mac_sha3_256(mac, sizeof(mac),
                        circuit_key_material, circuit_key_material_len,
                        msg, auth_msg_len);
    if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) {
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "ESTABLISH_INTRO handshake_auth not as expected");
      return -1;
    }
  }

  return 0;
}