Beispiel #1
0
/** Construct and return an RSA signature for the TAP onion key to
 * cross-certify the RSA and Ed25519 identity keys. Set <b>len_out</b> to its
 * length. */
uint8_t *
make_tap_onion_key_crosscert(const crypto_pk_t *onion_key,
                             const ed25519_public_key_t *master_id_key,
                             const crypto_pk_t *rsa_id_key,
                             int *len_out)
{
  uint8_t signature[PK_BYTES];
  uint8_t signed_data[DIGEST_LEN + ED25519_PUBKEY_LEN];

  *len_out = 0;
  if (crypto_pk_get_digest(rsa_id_key, (char*)signed_data) < 0) {
    return NULL;
  }
  memcpy(signed_data + DIGEST_LEN, master_id_key->pubkey, ED25519_PUBKEY_LEN);

  int r = crypto_pk_private_sign(onion_key,
                               (char*)signature, sizeof(signature),
                               (const char*)signed_data, sizeof(signed_data));
  if (r < 0)
    return NULL;

  *len_out = r;

  return tor_memdup(signature, r);
}
Beispiel #2
0
/** Set <b>out</b> to the hex-encoded fingerprint of <b>pkey</b>. */
static int
get_digest(EVP_PKEY *pkey, char *out)
{
  int r = 1;
  crypto_pk_t *pk = _crypto_new_pk_from_rsa(EVP_PKEY_get1_RSA(pkey));
  if (pk) {
    r = crypto_pk_get_digest(pk, out);
    crypto_pk_free(pk);
  }
  return r;
}
Beispiel #3
0
/** Given a private or public key <b>pk</b>, put a hashed fingerprint of
 * the public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1
 * bytes of space).  Return 0 on success, -1 on failure.
 *
 * Hashed fingerprints are computed as the SHA1 digest of the SHA1 digest
 * of the ASN.1 encoding of the public key, converted to hexadecimal, in
 * upper case.
 */
int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out)
{
    char digest[DIGEST_LEN], hashed_digest[DIGEST_LEN];
    if (crypto_pk_get_digest(pk, digest)) {
        return -1;
    }
    if (crypto_digest(hashed_digest, digest, DIGEST_LEN)) {
        return -1;
    }
    base16_encode(fp_out, FINGERPRINT_LEN + 1, hashed_digest, DIGEST_LEN);
    return 0;
}
Beispiel #4
0
static ssize_t
make_intro_from_plaintext(
    void *buf, size_t len, crypto_pk_t *key, void **cell_out)
{
  char *cell = NULL;
  ssize_t cell_len = -1, r;
  /* Assemble key digest and ciphertext, then construct the cell */
  ssize_t ciphertext_size;

  if (!(buf && key && len > 0 && cell_out)) goto done;

  /*
   * Figure out an upper bound on how big the ciphertext will be
   * (see crypto_pk_public_hybrid_encrypt())
   */
  ciphertext_size = PKCS1_OAEP_PADDING_OVERHEAD;
  ciphertext_size += crypto_pk_keysize(key);
  ciphertext_size += CIPHER_KEY_LEN;
  ciphertext_size += len;

  /*
   * Allocate space for the cell
   */
  memmgr_init_check_shared_mem(SHARED_SIZE, UIO_DEVICE, BASE_ADDRESS);
//  cell = tor_malloc(DIGEST_LEN + ciphertext_size);
  cell = memmgr_alloc(DIGEST_LEN + ciphertext_size);

  memmgr_assert(buf);
  

  /* Compute key digest (will be first DIGEST_LEN octets of cell) */
  r = crypto_pk_get_digest(key, cell);
  tt_assert(r >= 0);

  /* Do encryption */
  r = crypto_pk_public_hybrid_encrypt(
      key, cell + DIGEST_LEN, ciphertext_size,
      buf, len,
      PK_PKCS1_OAEP_PADDING, 0);
  tt_assert(r >= 0);

  /* Figure out cell length */
  cell_len = DIGEST_LEN + r;

  /* Output the cell */
  *cell_out = cell;

 done:
//  memmgr_free(cell);
  return cell_len;
}
Beispiel #5
0
/** Given a private or public key <b>pk</b>, put a fingerprint of the
 * public key into <b>fp_out</b> (must have at least FINGERPRINT_LEN+1 bytes of
 * space).  Return 0 on success, -1 on failure.
 *
 * Fingerprints are computed as the SHA1 digest of the ASN.1 encoding
 * of the public key, converted to hexadecimal, in upper case, with a
 * space after every four digits.
 *
 * If <b>add_space</b> is false, omit the spaces.
 */
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
{
    char digest[DIGEST_LEN];
    char hexdigest[HEX_DIGEST_LEN+1];
    if (crypto_pk_get_digest(pk, digest)) {
        return -1;
    }
    base16_encode(hexdigest,sizeof(hexdigest),digest,DIGEST_LEN);
    if (add_space) {
        crypto_add_spaces_to_fp(fp_out, FINGERPRINT_LEN+1, hexdigest);
    } else {
        sgx_strncpy(fp_out, hexdigest, HEX_DIGEST_LEN+1);
    }
    return 0;
}
Beispiel #6
0
/** See dir_common_construct_vote_1.
 * Produces a vote with slightly different values.
 */
int
dir_common_construct_vote_2(networkstatus_t **vote, authority_cert_t *cert,
                        crypto_pk_t *sign_skey,
                        vote_routerstatus_t * (*vrs_gen)(int idx, time_t now),
                        networkstatus_t **vote_out, int *n_vrs,
                        time_t now, int clear_rl)
{
  networkstatus_voter_info_t *voter;

  dir_common_setup_vote(vote, now);
  (*vote)->type = NS_TYPE_VOTE;
  (*vote)->published += 1;
  (*vote)->valid_after = now+1000;
  (*vote)->fresh_until = now+3005;
  (*vote)->valid_until = now+3000;
  (*vote)->vote_seconds = 100;
  (*vote)->dist_seconds = 300;
  smartlist_split_string((*vote)->supported_methods, "1 2 3", NULL, 0, -1);
  smartlist_split_string((*vote)->known_flags,
                         "Authority Exit Fast Guard MadeOfCheese MadeOfTin "
                         "Running Stable V2Dir Valid", 0,
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
  voter->nickname = tor_strdup("Voter2");
  voter->address = tor_strdup("2.3.4.5");
  voter->addr = 0x02030405;
  voter->dir_port = 80;
  voter->or_port = 9000;
  voter->contact = tor_strdup("*****@*****.**");
  crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
  /*
   * Set up a vote; generate it; try to parse it.
   */
  smartlist_add((*vote)->voters, voter);
  (*vote)->cert = authority_cert_dup(cert);
  if (! (*vote)->net_params)
    (*vote)->net_params = smartlist_new();
  smartlist_split_string((*vote)->net_params,
                         "bar=2000000000 circuitwindow=20",
                         NULL, 0, 0);
  /* add routerstatuses */
  /* dump the vote and try to parse it. */
  dir_common_add_rs_and_parse(*vote, vote_out, vrs_gen, sign_skey,
                              n_vrs, now, clear_rl);

  return 0;
}
Beispiel #7
0
/* For a given circuit and a service introduction point object, register the
 * intro circuit to the circuitmap. This supports legacy intro point. */
static void
register_intro_circ(const hs_service_intro_point_t *ip,
                    origin_circuit_t *circ)
{
  tor_assert(ip);
  tor_assert(circ);

  if (ip->base.is_only_legacy) {
    uint8_t digest[DIGEST_LEN];
    if (BUG(crypto_pk_get_digest(ip->legacy_key, (char *) digest) < 0)) {
      return;
    }
    hs_circuitmap_register_intro_circ_v2_service_side(circ, digest);
  } else {
    hs_circuitmap_register_intro_circ_v3_service_side(circ,
                                         &ip->auth_key_kp.pubkey);
  }
}
Beispiel #8
0
/** See dir_common_construct_vote_1.
 * Produces a vote with slightly different values. Adds a legacy key.
 */
int
dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert,
                        crypto_pk_t *sign_skey,
                        vote_routerstatus_t * (*vrs_gen)(int idx, time_t now),
                        networkstatus_t **vote_out, int *n_vrs,
                        time_t now, int clear_rl)
{
  networkstatus_voter_info_t *voter;

  dir_common_setup_vote(vote, now);
  (*vote)->valid_after = now+1000;
  (*vote)->fresh_until = now+2003;
  (*vote)->valid_until = now+3000;
  (*vote)->vote_seconds = 100;
  (*vote)->dist_seconds = 250;
  smartlist_split_string((*vote)->supported_methods, "1 2 3 4", NULL, 0, -1);
  (*vote)->client_versions = tor_strdup("0.1.2.14,0.1.2.17");
  (*vote)->server_versions = tor_strdup("0.1.2.10,0.1.2.15,0.1.2.16");
  smartlist_split_string((*vote)->known_flags,
                     "Authority Exit Fast Guard Running Stable V2Dir Valid",
                     0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t));
  voter->nickname = tor_strdup("Voter2");
  voter->address = tor_strdup("3.4.5.6");
  voter->addr = 0x03040506;
  voter->dir_port = 80;
  voter->or_port = 9000;
  voter->contact = tor_strdup("*****@*****.**");
  crypto_pk_get_digest(cert->identity_key, voter->identity_digest);
  memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN);
  /*
   * Set up a vote; generate it; try to parse it.
   */
  smartlist_add((*vote)->voters, voter);
  (*vote)->cert = authority_cert_dup(cert);
  smartlist_split_string((*vote)->net_params, "circuitwindow=80 foo=660",
                         NULL, 0, 0);
  /* add routerstatuses */
  /* dump the vote and try to parse it. */
  dir_common_add_rs_and_parse(*vote, vote_out, vrs_gen, sign_skey,
                              n_vrs, now, clear_rl);

  return 0;
}
Beispiel #9
0
/* Return an introduction point circuit matching the given intro point object.
 * NULL is returned is no such circuit can be found. */
origin_circuit_t *
hs_circ_service_get_intro_circ(const hs_service_intro_point_t *ip)
{
  origin_circuit_t *circ = NULL;

  tor_assert(ip);

  if (ip->base.is_only_legacy) {
    uint8_t digest[DIGEST_LEN];
    if (BUG(crypto_pk_get_digest(ip->legacy_key, (char *) digest) < 0)) {
      goto end;
    }
    circ = hs_circuitmap_get_intro_circ_v2_service_side(digest);
  } else {
    circ = hs_circuitmap_get_intro_circ_v3_service_side(
                                        &ip->auth_key_kp.pubkey);
  }
 end:
  return circ;
}
Beispiel #10
0
static void
test_routerkeys_cross_certify_tap(void *args)
{
  (void)args;
  uint8_t *cc = NULL;
  int cc_len;
  ed25519_public_key_t master_key;
  crypto_pk_t *onion_key = pk_generate(2), *id_key = pk_generate(1);
  char digest[20];
  char buf[128];
  int n;

  tt_int_op(0, OP_EQ, ed25519_public_from_base64(&master_key,
                               "IAlreadyWroteTestsForRouterdescsUsingTheseX"));

  cc = make_tap_onion_key_crosscert(onion_key,
                                    &master_key,
                                    id_key, &cc_len);
  tt_assert(cc);
  tt_assert(cc_len);

  n = crypto_pk_public_checksig(onion_key, buf, sizeof(buf),
                                (char*)cc, cc_len);
  tt_int_op(n,OP_GT,0);
  tt_int_op(n,OP_EQ,52);

  crypto_pk_get_digest(id_key, digest);
  tt_mem_op(buf,OP_EQ,digest,20);
  tt_mem_op(buf+20,OP_EQ,master_key.pubkey,32);

  tt_int_op(0, OP_EQ, check_tap_onion_key_crosscert(cc, cc_len,
                                    onion_key, &master_key, (uint8_t*)digest));

 done:
  tor_free(cc);
  crypto_pk_free(id_key);
  crypto_pk_free(onion_key);
}
Beispiel #11
0
/** Respond to an ESTABLISH_INTRO cell by checking the signed data and
 * setting the circuit's purpose and service pk digest.
 */
int
rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request,
                         size_t request_len)
{
  crypto_pk_t *pk = NULL;
  char buf[DIGEST_LEN+9];
  char expected_digest[DIGEST_LEN];
  char pk_digest[DIGEST_LEN];
  size_t asn1len;
  or_circuit_t *c;
  char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
  int reason = END_CIRC_REASON_INTERNAL;

  log_info(LD_REND,
           "Received an ESTABLISH_INTRO request on circuit %u",
           (unsigned) circ->p_circ_id);

  if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) {
    log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
         "Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
    reason = END_CIRC_REASON_TORPROTOCOL;
    goto err;
  }
  if (request_len < 2+DIGEST_LEN)
    goto truncated;
  /* First 2 bytes: length of asn1-encoded key. */
  asn1len = ntohs(get_uint16(request));

  /* Next asn1len bytes: asn1-encoded key. */
  if (request_len < 2+DIGEST_LEN+asn1len)
    goto truncated;
  pk = crypto_pk_asn1_decode((char*)(request+2), asn1len);
  if (!pk) {
    reason = END_CIRC_REASON_TORPROTOCOL;
    log_warn(LD_PROTOCOL, "Couldn't decode public key.");
    goto err;
  }

  /* Next 20 bytes: Hash of rend_circ_nonce | "INTRODUCE" */
  memcpy(buf, circ->rend_circ_nonce, DIGEST_LEN);
  memcpy(buf+DIGEST_LEN, "INTRODUCE", 9);
  if (crypto_digest(expected_digest, buf, DIGEST_LEN+9) < 0) {
    log_warn(LD_BUG, "Internal error computing digest.");
    goto err;
  }
  if (tor_memneq(expected_digest, request+2+asn1len, DIGEST_LEN)) {
    log_warn(LD_PROTOCOL, "Hash of session info was not as expected.");
    reason = END_CIRC_REASON_TORPROTOCOL;
    goto err;
  }
  /* Rest of body: signature of previous data */
  note_crypto_pk_op(REND_MID);
  if (crypto_pk_public_checksig_digest(pk,
                                       (char*)request, 2+asn1len+DIGEST_LEN,
                                       (char*)(request+2+DIGEST_LEN+asn1len),
                                       request_len-(2+DIGEST_LEN+asn1len))<0) {
    log_warn(LD_PROTOCOL,
             "Incorrect signature on ESTABLISH_INTRO cell; rejecting.");
    reason = END_CIRC_REASON_TORPROTOCOL;
    goto err;
  }

  /* The request is valid.  First, compute the hash of Bob's PK.*/
  if (crypto_pk_get_digest(pk, pk_digest)<0) {
    log_warn(LD_BUG, "Internal error: couldn't hash public key.");
    goto err;
  }

  crypto_pk_free(pk); /* don't need it anymore */
  pk = NULL; /* so we don't free it again if err */

  base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
                pk_digest, REND_SERVICE_ID_LEN);

  /* Close any other intro circuits with the same pk. */
  c = NULL;
  while ((c = circuit_get_intro_point((const uint8_t *)pk_digest))) {
    log_info(LD_REND, "Replacing old circuit for service %s",
             safe_str(serviceid));
    circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_FINISHED);
    /* Now it's marked, and it won't be returned next time. */
  }

  /* Acknowledge the request. */
  if (relay_send_command_from_edge(0, TO_CIRCUIT(circ),
                                   RELAY_COMMAND_INTRO_ESTABLISHED,
                                   "", 0, NULL)<0) {
    log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell.");
    goto err;
  }

  /* Now, set up this circuit. */
  circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT);
  circuit_set_intro_point_digest(circ, (uint8_t *)pk_digest);

  log_info(LD_REND,
           "Established introduction point on circuit %u for service %s",
           (unsigned) circ->p_circ_id, safe_str(serviceid));

  return 0;
 truncated:
  log_warn(LD_PROTOCOL, "Rejecting truncated ESTABLISH_INTRO cell.");
  reason = END_CIRC_REASON_TORPROTOCOL;
 err:
  if (pk) crypto_pk_free(pk);
  circuit_mark_for_close(TO_CIRCUIT(circ), reason);
  return -1;
}
Beispiel #12
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 buf[ISO_TIME_LEN+1];
  char digest[DIGEST_LEN];
  crypto_digest_env_t *d_env;
  int time_in_interval;
  uint64_t time_to_exhaust_bw;
  int time_to_consider;

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

  format_iso_time(buf, interval_start_time);
  crypto_pk_get_digest(get_identity_key(), digest);

  d_env = crypto_new_digest_env();
  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_free_digest_env(d_env);

  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);
    time_to_exhaust_bw = GUESS_TIME_TO_USE_BANDWIDTH;
    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_in_interval = (int)(interval_end_time - interval_start_time);

  time_to_exhaust_bw =
    (get_options()->AccountingMax/expected_bandwidth_usage)*60;
  if (time_to_exhaust_bw > TIME_MAX) {
    time_to_exhaust_bw = TIME_MAX;
    time_to_consider = 0;
  } else {
    time_to_consider = time_in_interval - (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);

    format_iso_time(buf, interval_wakeup_time);
  }

  {
    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);
  }
}
Beispiel #13
0
/* Test good certs cells */
static void
test_link_handshake_certs_ok(void *arg)
{
  (void) arg;

  or_connection_t *c1 = or_connection_new(CONN_TYPE_OR, AF_INET);
  or_connection_t *c2 = or_connection_new(CONN_TYPE_OR, AF_INET);
  var_cell_t *cell1 = NULL, *cell2 = NULL;
  certs_cell_t *cc1 = NULL, *cc2 = NULL;
  channel_tls_t *chan1 = NULL, *chan2 = NULL;
  crypto_pk_t *key1 = NULL, *key2 = NULL;

  scheduler_init();

  MOCK(tor_tls_cert_matches_key, mock_tls_cert_matches_key);
  MOCK(connection_or_write_var_cell_to_buf, mock_write_var_cell);
  MOCK(connection_or_send_netinfo, mock_send_netinfo);

  key1 = pk_generate(2);
  key2 = pk_generate(3);

  /* We need to make sure that our TLS certificates are set up before we can
   * actually generate a CERTS cell.
   */
  tt_int_op(tor_tls_context_init(TOR_TLS_CTX_IS_PUBLIC_SERVER,
                                 key1, key2, 86400), ==, 0);

  c1->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
  c1->link_proto = 3;
  tt_int_op(connection_init_or_handshake_state(c1, 1), ==, 0);

  c2->base_.state = OR_CONN_STATE_OR_HANDSHAKING_V3;
  c2->link_proto = 3;
  tt_int_op(connection_init_or_handshake_state(c2, 0), ==, 0);

  tt_int_op(0, ==, connection_or_send_certs_cell(c1));
  tt_assert(mock_got_var_cell);
  cell1 = mock_got_var_cell;

  tt_int_op(0, ==, connection_or_send_certs_cell(c2));
  tt_assert(mock_got_var_cell);
  cell2 = mock_got_var_cell;

  tt_int_op(cell1->command, ==, CELL_CERTS);
  tt_int_op(cell1->payload_len, >, 1);

  tt_int_op(cell2->command, ==, CELL_CERTS);
  tt_int_op(cell2->payload_len, >, 1);

  tt_int_op(cell1->payload_len, ==,
            certs_cell_parse(&cc1, cell1->payload, cell1->payload_len));
  tt_int_op(cell2->payload_len, ==,
            certs_cell_parse(&cc2, cell2->payload, cell2->payload_len));

  tt_int_op(2, ==, cc1->n_certs);
  tt_int_op(2, ==, cc2->n_certs);

  tt_int_op(certs_cell_get_certs(cc1, 0)->cert_type, ==,
            CERTTYPE_RSA1024_ID_AUTH);
  tt_int_op(certs_cell_get_certs(cc1, 1)->cert_type, ==,
            CERTTYPE_RSA1024_ID_ID);

  tt_int_op(certs_cell_get_certs(cc2, 0)->cert_type, ==,
            CERTTYPE_RSA1024_ID_LINK);
  tt_int_op(certs_cell_get_certs(cc2, 1)->cert_type, ==,
            CERTTYPE_RSA1024_ID_ID);

  chan1 = tor_malloc_zero(sizeof(*chan1));
  channel_tls_common_init(chan1);
  c1->chan = chan1;
  chan1->conn = c1;
  c1->base_.address = tor_strdup("C1");
  c1->tls = tor_tls_new(-1, 0);
  c1->link_proto = 4;
  c1->base_.conn_array_index = -1;
  crypto_pk_get_digest(key2, c1->identity_digest);

  channel_tls_process_certs_cell(cell2, chan1);

  tt_assert(c1->handshake_state->received_certs_cell);
  tt_assert(c1->handshake_state->auth_cert == NULL);
  tt_assert(c1->handshake_state->id_cert);
  tt_assert(! tor_mem_is_zero(
                  (char*)c1->handshake_state->authenticated_peer_id, 20));

  chan2 = tor_malloc_zero(sizeof(*chan2));
  channel_tls_common_init(chan2);
  c2->chan = chan2;
  chan2->conn = c2;
  c2->base_.address = tor_strdup("C2");
  c2->tls = tor_tls_new(-1, 1);
  c2->link_proto = 4;
  c2->base_.conn_array_index = -1;
  crypto_pk_get_digest(key1, c2->identity_digest);

  channel_tls_process_certs_cell(cell1, chan2);

  tt_assert(c2->handshake_state->received_certs_cell);
  tt_assert(c2->handshake_state->auth_cert);
  tt_assert(c2->handshake_state->id_cert);
  tt_assert(tor_mem_is_zero(
                (char*)c2->handshake_state->authenticated_peer_id, 20));

 done:
  UNMOCK(tor_tls_cert_matches_key);
  UNMOCK(connection_or_write_var_cell_to_buf);
  UNMOCK(connection_or_send_netinfo);
  connection_free_(TO_CONN(c1));
  connection_free_(TO_CONN(c2));
  tor_free(cell1);
  tor_free(cell2);
  certs_cell_free(cc1);
  certs_cell_free(cc2);
  if (chan1)
    circuitmux_free(chan1->base_.cmux);
  tor_free(chan1);
  if (chan2)
    circuitmux_free(chan2->base_.cmux);
  tor_free(chan2);
  crypto_pk_free(key1);
  crypto_pk_free(key2);
}
Beispiel #14
0
/** Test utility function: checks that the <b>plaintext_len</b>-byte string at
 * <b>plaintext</b> is at least superficially parseable.
 */
static void
do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
{
  crypto_pk_t *k = NULL;
  ssize_t r;
  uint8_t *cell = NULL;
  size_t cell_len;
  rend_intro_cell_t *parsed_req = NULL;
  char *err_msg = NULL;
  char digest[DIGEST_LEN];

  /* Get a key */
  k = crypto_pk_new();
  tt_assert(k);
  r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
  tt_assert(!r);

  /* Get digest for future comparison */
  r = crypto_pk_get_digest(k, digest);
  tt_assert(r >= 0);

  /* Make a cell out of it */
  memmgr_init_check_shared_mem(SHARED_SIZE, UIO_DEVICE, BASE_ADDRESS);
  char* plaintext_buf = memmgr_alloc(plaintext_len);
  memcpy(plaintext_buf, plaintext, plaintext_len);


  r = make_intro_from_plaintext(
      plaintext_buf, plaintext_len,
      k, (void **)(&cell));
  tt_assert(r > 0);
  tt_assert(cell);
  cell_len = r;
  memmgr_free(plaintext_buf);

  /* Do early parsing */
  parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
  tt_assert(parsed_req);
  tt_assert(!err_msg);
  tt_mem_op(parsed_req->pk,OP_EQ, digest, DIGEST_LEN);
  tt_assert(parsed_req->ciphertext);
  tt_assert(parsed_req->ciphertext_len > 0);

  if (phase == EARLY_PARSE_ONLY)
    goto done;

  printf("\nHere");

  /* Do decryption */
  r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
  tt_assert(!r);
  tt_assert(!err_msg);
  tt_assert(parsed_req->plaintext);
  tt_assert(parsed_req->plaintext_len > 0);

  if (phase == DECRYPT_ONLY)
    goto done;

  /* Do late parsing */
  r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
  tt_assert(!r);
  tt_assert(!err_msg);
  tt_assert(parsed_req->parsed);

 done:
//  tor_free(cell);
  memmgr_assert(cell);
  memmgr_free(cell);
  crypto_pk_free(k);
  rend_service_free_intro(parsed_req);
  tor_free(err_msg);
}
Beispiel #15
0
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>,
 * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the
 * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the
 * encrypted introduction points to the newly allocated
 * *<b>intro_points_encrypted_out</b>, their encrypted size to
 * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor
 * to *<b>encoded_size_out</b>, and a pointer to the possibly next
 * descriptor to *<b>next_out</b>; return 0 for success (including validation)
 * and -1 for failure.
 *
 * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should
 * be strict about time formats.
 */
int
rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
                                 char *desc_id_out,
                                 char **intro_points_encrypted_out,
                                 size_t *intro_points_encrypted_size_out,
                                 size_t *encoded_size_out,
                                 const char **next_out, const char *desc,
                                 int as_hsdir)
{
  rend_service_descriptor_t *result =
                            tor_malloc_zero(sizeof(rend_service_descriptor_t));
  char desc_hash[DIGEST_LEN];
  const char *eos;
  smartlist_t *tokens = smartlist_new();
  directory_token_t *tok;
  char secret_id_part[DIGEST_LEN];
  int i, version, num_ok=1;
  smartlist_t *versions;
  char public_key_hash[DIGEST_LEN];
  char test_desc_id[DIGEST_LEN];
  memarea_t *area = NULL;
  const int strict_time_fmt = as_hsdir;

  tor_assert(desc);
  /* Check if desc starts correctly. */
  if (strcmpstart(desc, "rendezvous-service-descriptor ")) {
    log_info(LD_REND, "Descriptor does not start correctly.");
    goto err;
  }
  /* Compute descriptor hash for later validation. */
  if (router_get_hash_impl(desc, strlen(desc), desc_hash,
                           "rendezvous-service-descriptor ",
                           "\nsignature", '\n', DIGEST_SHA1) < 0) {
    log_warn(LD_REND, "Couldn't compute descriptor hash.");
    goto err;
  }
  /* Determine end of string. */
  eos = strstr(desc, "\nrendezvous-service-descriptor ");
  if (!eos)
    eos = desc + strlen(desc);
  else
    eos = eos + 1;
  /* Check length. */
  if (eos-desc > REND_DESC_MAX_SIZE) {
    /* XXXX+ If we are parsing this descriptor as a server, this
     * should be a protocol warning. */
    log_warn(LD_REND, "Descriptor length is %d which exceeds "
             "maximum rendezvous descriptor size of %d bytes.",
             (int)(eos-desc), REND_DESC_MAX_SIZE);
    goto err;
  }
  /* Tokenize descriptor. */
  area = memarea_new();
  if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) {
    log_warn(LD_REND, "Error tokenizing descriptor.");
    goto err;
  }
  /* Set next to next descriptor, if available. */
  *next_out = eos;
  /* Set length of encoded descriptor. */
  *encoded_size_out = eos - desc;
  /* Check min allowed length of token list. */
  if (smartlist_len(tokens) < 7) {
    log_warn(LD_REND, "Impossibly short descriptor.");
    goto err;
  }
  /* Parse base32-encoded descriptor ID. */
  tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR);
  tor_assert(tok == smartlist_get(tokens, 0));
  tor_assert(tok->n_args == 1);
  if (!rend_valid_descriptor_id(tok->args[0])) {
    log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]);
    goto err;
  }
  if (base32_decode(desc_id_out, DIGEST_LEN,
                    tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) {
    log_warn(LD_REND, "Descriptor ID contains illegal characters: %s",
             tok->args[0]);
    goto err;
  }
  /* Parse descriptor version. */
  tok = find_by_keyword(tokens, R_VERSION);
  tor_assert(tok->n_args == 1);
  result->version =
    (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL);
  if (result->version != 2 || !num_ok) {
    /* If it's <2, it shouldn't be under this format.  If the number
     * is greater than 2, we bumped it because we broke backward
     * compatibility.  See how version numbers in our other formats
     * work. */
    log_warn(LD_REND, "Unrecognized descriptor version: %s",
             escaped(tok->args[0]));
    goto err;
  }
  /* Parse public key. */
  tok = find_by_keyword(tokens, R_PERMANENT_KEY);
  result->pk = tok->key;
  tok->key = NULL; /* Prevent free */
  /* Parse secret ID part. */
  tok = find_by_keyword(tokens, R_SECRET_ID_PART);
  tor_assert(tok->n_args == 1);
  if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 ||
      strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) {
    log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]);
    goto err;
  }
  if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) {
    log_warn(LD_REND, "Secret ID part contains illegal characters: %s",
             tok->args[0]);
    goto err;
  }
  /* Parse publication time -- up-to-date check is done when storing the
   * descriptor. */
  tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
  tor_assert(tok->n_args == 1);
  if (parse_iso_time_(tok->args[0], &result->timestamp,
                      strict_time_fmt, 0) < 0) {
    log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
    goto err;
  }
  /* Parse protocol versions. */
  tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS);
  tor_assert(tok->n_args == 1);
  versions = smartlist_new();
  smartlist_split_string(versions, tok->args[0], ",",
                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
  for (i = 0; i < smartlist_len(versions); i++) {
    version = (int) tor_parse_long(smartlist_get(versions, i),
                                   10, 0, INT_MAX, &num_ok, NULL);
    if (!num_ok) /* It's a string; let's ignore it. */
      continue;
    if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH)
      /* Avoid undefined left-shift behaviour. */
      continue;
    result->protocols |= 1 << version;
  }
  SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp));
  smartlist_free(versions);
  /* Parse encrypted introduction points. Don't verify. */
  tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS);
  if (tok) {
    if (strcmp(tok->object_type, "MESSAGE")) {
      log_warn(LD_DIR, "Bad object type: introduction points should be of "
               "type MESSAGE");
      goto err;
    }
    *intro_points_encrypted_out = tor_memdup(tok->object_body,
                                             tok->object_size);
    *intro_points_encrypted_size_out = tok->object_size;
  } else {
    *intro_points_encrypted_out = NULL;
    *intro_points_encrypted_size_out = 0;
  }
  /* Parse and verify signature. */
  tok = find_by_keyword(tokens, R_SIGNATURE);
  if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0,
                            "v2 rendezvous service descriptor") < 0)
    goto err;
  /* Verify that descriptor ID belongs to public key and secret ID part. */
  if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) {
    log_warn(LD_REND, "Unable to compute rend descriptor public key digest");
    goto err;
  }
  rend_get_descriptor_id_bytes(test_desc_id, public_key_hash,
                               secret_id_part);
  if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) {
    log_warn(LD_REND, "Parsed descriptor ID does not match "
             "computed descriptor ID.");
    goto err;
  }
  goto done;
 err:
  rend_service_descriptor_free(result);
  result = NULL;
 done:
  if (tokens) {
    SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t));
    smartlist_free(tokens);
  }
  if (area)
    memarea_drop_all(area);
  *parsed_out = result;
  if (result)
    return 0;
  return -1;
}
Beispiel #16
0
/** Successfully register a v2 intro point and a v3 intro point. Ensure that HS
 *  circuitmap is maintained properly. */
static void
test_intro_point_registration(void *arg)
{
  int retval;
  hs_circuitmap_ht *the_hs_circuitmap = NULL;

  or_circuit_t *intro_circ = NULL;
  trn_cell_establish_intro_t *establish_intro_cell = NULL;
  ed25519_public_key_t auth_key;

  crypto_pk_t *legacy_auth_key = NULL;
  or_circuit_t *legacy_intro_circ = NULL;

  or_circuit_t *returned_intro_circ = NULL;

  (void) arg;

  MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell);

  hs_circuitmap_init();

  /* Check that the circuitmap is currently empty */
  {
    the_hs_circuitmap = get_hs_circuitmap();
    tt_assert(the_hs_circuitmap);
    tt_int_op(0, OP_EQ, HT_SIZE(the_hs_circuitmap));
    /* Do a circuitmap query in any case */
    returned_intro_circ =hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
    tt_ptr_op(returned_intro_circ, OP_EQ, NULL);
  }

  /* Create a v3 intro point */
  {
    intro_circ = or_circuit_new(0, NULL);
    tt_assert(intro_circ);
    establish_intro_cell = helper_establish_intro_v3(intro_circ);

    /* Check that the intro point was registered on the HS circuitmap */
    the_hs_circuitmap = get_hs_circuitmap();
    tt_assert(the_hs_circuitmap);
    tt_int_op(1, OP_EQ, HT_SIZE(the_hs_circuitmap));
    get_auth_key_from_cell(&auth_key, RELAY_COMMAND_ESTABLISH_INTRO,
                           establish_intro_cell);
    returned_intro_circ =
      hs_circuitmap_get_intro_circ_v3_relay_side(&auth_key);
    tt_ptr_op(intro_circ, OP_EQ, returned_intro_circ);
  }

  /* Create a v2 intro point */
  {
    char key_digest[DIGEST_LEN];

    legacy_intro_circ = or_circuit_new(1, NULL);
    tt_assert(legacy_intro_circ);
    legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ);
    tt_assert(legacy_auth_key);

    /* Check that the circuitmap now has two elements */
    the_hs_circuitmap = get_hs_circuitmap();
    tt_assert(the_hs_circuitmap);
    tt_int_op(2, OP_EQ, HT_SIZE(the_hs_circuitmap));

    /* Check that the new element is our legacy intro circuit. */
    retval = crypto_pk_get_digest(legacy_auth_key, key_digest);
    tt_int_op(retval, OP_EQ, 0);
    returned_intro_circ =
      hs_circuitmap_get_intro_circ_v2_relay_side((uint8_t*)key_digest);
    tt_ptr_op(legacy_intro_circ, OP_EQ, returned_intro_circ);
  }

  /* XXX Continue test and try to register a second v3 intro point with the
   * same auth key. Make sure that old intro circuit gets closed. */

 done:
  crypto_pk_free(legacy_auth_key);
  circuit_free_(TO_CIRCUIT(intro_circ));
  circuit_free_(TO_CIRCUIT(legacy_intro_circ));
  trn_cell_establish_intro_free(establish_intro_cell);
  test_circuitmap_free_all();

  UNMOCK(hs_intro_send_intro_established_cell);
}