/** Run unit tests for the onion handshake code. */ static void test_onion_handshake(void *arg) { /* client-side */ crypto_dh_t *c_dh = NULL; char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; char c_keys[40]; /* server-side */ char s_buf[TAP_ONIONSKIN_REPLY_LEN]; char s_keys[40]; int i; /* shared */ crypto_pk_t *pk = NULL, *pk2 = NULL; (void)arg; pk = pk_generate(0); pk2 = pk_generate(1); /* client handshake 1. */ memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); for (i = 1; i <= 3; ++i) { crypto_pk_t *k1, *k2; if (i==1) { /* server handshake: only one key known. */ k1 = pk; k2 = NULL; } else if (i==2) { /* server handshake: try the right key first. */ k1 = pk; k2 = pk2; } else { /* server handshake: try the right key second. */ k1 = pk2; k2 = pk; } memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN); memset(s_keys, 0, 40); tt_assert(! onion_skin_TAP_server_handshake(c_buf, k1, k2, s_buf, s_keys, 40)); /* client handshake 2 */ memset(c_keys, 0, 40); tt_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, NULL)); tt_mem_op(c_keys,OP_EQ, s_keys, 40); memset(s_buf, 0, 40); tt_mem_op(c_keys,OP_NE, s_buf, 40); } done: crypto_dh_free(c_dh); crypto_pk_free(pk); crypto_pk_free(pk2); }
/** Release all storage held in <b>keys</b>, but do not free <b>keys</b> * itself (as it's likely to be stack-allocated.) */ void release_server_onion_keys(server_onion_keys_t *keys) { if (! keys) return; crypto_pk_free(keys->onion_key); crypto_pk_free(keys->last_onion_key); ntor_key_map_free(keys->curve25519_key_map); tor_free(keys->junk_keypair); memset(keys, 0, sizeof(server_onion_keys_t)); }
static void free_state(void *arg) { state_t *st = arg; crypto_pk_free(st->rsa); tor_free(st); }
static void test_routerkeys_rsa_ed_crosscert(void *arg) { (void)arg; ed25519_public_key_t ed; crypto_pk_t *rsa = pk_generate(2); uint8_t *cc = NULL; ssize_t cc_len; time_t expires_in = 1470846177; tt_int_op(0, OP_EQ, ed25519_public_from_base64(&ed, "ThisStringCanContainAnythingSoNoKeyHereNowX")); cc_len = tor_make_rsa_ed25519_crosscert(&ed, rsa, expires_in, &cc); tt_int_op(cc_len, OP_GT, 0); tt_int_op(cc_len, OP_GT, 37); /* key, expires, siglen */ tt_mem_op(cc, OP_EQ, ed.pubkey, 32); time_t expires_out = 3600 * ntohl(get_uint32(cc+32)); tt_int_op(expires_out, OP_GE, expires_in); tt_int_op(expires_out, OP_LE, expires_in + 3600); tt_int_op(cc_len, OP_EQ, 37 + get_uint8(cc+36)); tt_int_op(0, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed, expires_in - 10)); /* Now try after it has expired */ tt_int_op(-4, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed, expires_out + 1)); /* Truncated object */ tt_int_op(-2, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len - 2, rsa, &ed, expires_in - 10)); /* Key not as expected */ cc[0] ^= 3; tt_int_op(-3, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed, expires_in - 10)); cc[0] ^= 3; /* Bad signature */ cc[40] ^= 3; tt_int_op(-5, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed, expires_in - 10)); cc[40] ^= 3; /* Signature of wrong data */ cc[0] ^= 3; ed.pubkey[0] ^= 3; tt_int_op(-6, OP_EQ, rsa_ed25519_crosscert_check(cc, cc_len, rsa, &ed, expires_in - 10)); cc[0] ^= 3; ed.pubkey[0] ^= 3; done: crypto_pk_free(rsa); tor_free(cc); }
static int workqueue_do_shutdown(void *state, void *work) { (void)state; (void)work; crypto_pk_free(((state_t*)state)->rsa); tor_free(state); return WQ_RPL_SHUTDOWN; }
/** Free the storage held by the service descriptor <b>desc</b>. */ void rend_service_descriptor_free(rend_service_descriptor_t *desc) { if (!desc) return; if (desc->pk) crypto_pk_free(desc->pk); if (desc->intro_nodes) { SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro, rend_intro_point_free(intro););
/** 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; }
/** Set <b>out</b> to the hex-encoded fingerprint of <b>pkey</b>. */ static int get_fingerprint(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_fingerprint(pk, out, 0); crypto_pk_free(pk); } return r; }
static int recv_certs_cleanup(const struct testcase_t *test, void *obj) { (void)test; certs_data_t *d = obj; UNMOCK(tor_tls_cert_matches_key); UNMOCK(connection_or_send_netinfo); UNMOCK(connection_or_close_for_error); if (d) { tor_free(d->cell); certs_cell_free(d->ccell); connection_free_(TO_CONN(d->c)); circuitmux_free(d->chan->base_.cmux); tor_free(d->chan); crypto_pk_free(d->key1); crypto_pk_free(d->key2); tor_free(d); } return 1; }
static RSA * generate_key(int bits) { RSA *rsa = NULL; crypto_pk_t *env = crypto_pk_new(); if (crypto_pk_generate_key_with_bits(env,bits)<0) goto done; rsa = _crypto_pk_get_rsa(env); rsa = RSAPrivateKey_dup(rsa); done: crypto_pk_free(env); return rsa; }
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); }
/* If no distribution option was set, then check_bridge_distribution_setting() * should have set it to "any". */ static void test_router_dump_router_to_string_no_bridge_distribution_method(void *arg) { const char* needle = "bridge-distribution-request any"; or_options_t* options = get_options_mutable(); routerinfo_t* router = NULL; curve25519_keypair_t ntor_keypair; ed25519_keypair_t signing_keypair; char* desc = NULL; char* found = NULL; (void)arg; NS_MOCK(router_get_my_routerinfo); options->ORPort_set = 1; options->BridgeRelay = 1; /* Generate keys which router_dump_router_to_string() expects to exist. */ tt_int_op(0, ==, curve25519_keypair_generate(&ntor_keypair, 0)); tt_int_op(0, ==, ed25519_keypair_generate(&signing_keypair, 0)); /* Set up part of our routerinfo_t so that we don't trigger any other * assertions in router_dump_router_to_string(). */ router = (routerinfo_t*)router_get_my_routerinfo(); tt_ptr_op(router, !=, NULL); /* The real router_get_my_routerinfo() looks up onion_curve25519_pkey using * get_current_curve25519_keypair(), but we don't initialise static data in * this test. */ router->onion_curve25519_pkey = &ntor_keypair.pubkey; /* Generate our server descriptor and ensure that the substring * "bridge-distribution-request any" occurs somewhere within it. */ crypto_pk_t *onion_pkey = router_get_rsa_onion_pkey(router->onion_pkey, router->onion_pkey_len); desc = router_dump_router_to_string(router, router->identity_pkey, onion_pkey, &ntor_keypair, &signing_keypair); crypto_pk_free(onion_pkey); tt_ptr_op(desc, !=, NULL); found = strstr(desc, needle); tt_ptr_op(found, !=, NULL); done: NS_UNMOCK(router_get_my_routerinfo); tor_free(desc); }
static const routerinfo_t* NS(router_get_my_routerinfo)(void) { crypto_pk_t* ident_key; crypto_pk_t* tap_key; time_t now; if (!mock_routerinfo) { /* Mock the published timestamp, otherwise router_dump_router_to_string() * will poop its pants. */ time(&now); /* We'll need keys, or router_dump_router_to_string() would return NULL. */ ident_key = pk_generate(0); tap_key = pk_generate(0); tor_assert(ident_key != NULL); tor_assert(tap_key != NULL); mock_routerinfo = tor_malloc_zero(sizeof(routerinfo_t)); mock_routerinfo->nickname = tor_strdup("ConlonNancarrow"); mock_routerinfo->addr = 123456789; mock_routerinfo->or_port = 443; mock_routerinfo->platform = tor_strdup("unittest"); mock_routerinfo->cache_info.published_on = now; mock_routerinfo->identity_pkey = crypto_pk_dup_key(ident_key); router_set_rsa_onion_pkey(tap_key, &mock_routerinfo->onion_pkey, &mock_routerinfo->onion_pkey_len); mock_routerinfo->bandwidthrate = 9001; mock_routerinfo->bandwidthburst = 9002; crypto_pk_free(ident_key); crypto_pk_free(tap_key); } return mock_routerinfo; }
static void * new_state(void *arg) { state_t *st; (void)arg; st = tor_malloc(sizeof(*st)); /* Every thread gets its own keys. not a problem for benchmarking */ st->rsa = crypto_pk_new(); if (crypto_pk_generate_key_with_bits(st->rsa, 1024) < 0) { crypto_pk_free(st->rsa); tor_free(st); return NULL; } curve25519_secret_key_generate(&st->ecdh, 0); st->magic = 13371337; return st; }
/** Free all resources allocated for <b>tok</b> */ void token_clear(directory_token_t *tok) { if (tok->key) crypto_pk_free(tok->key); }
/** 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; }
static void test_routerkeys_write_fingerprint(void *arg) { crypto_pk_t *key = pk_generate(2); or_options_t *options = get_options_mutable(); const char *ddir = get_fname("write_fingerprint"); char *cp = NULL, *cp2 = NULL; char fp[FINGERPRINT_LEN+1]; (void)arg; tt_assert(key); options->ORPort_set = 1; /* So that we can get the server ID key */ tor_free(options->DataDirectory); options->DataDirectory = tor_strdup(ddir); options->Nickname = tor_strdup("haflinger"); set_server_identity_key(key); set_client_identity_key(crypto_pk_dup_key(key)); tt_int_op(0, OP_EQ, check_private_dir(ddir, CPD_CREATE, NULL)); tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),OP_EQ,0); /* Write fingerprint file */ tt_int_op(0, OP_EQ, router_write_fingerprint(0)); cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"), 0, NULL); crypto_pk_get_fingerprint(key, fp, 0); tor_asprintf(&cp2, "haflinger %s\n", fp); tt_str_op(cp, OP_EQ, cp2); tor_free(cp); tor_free(cp2); /* Write hashed-fingerprint file */ tt_int_op(0, OP_EQ, router_write_fingerprint(1)); cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"), 0, NULL); crypto_pk_get_hashed_fingerprint(key, fp); tor_asprintf(&cp2, "haflinger %s\n", fp); tt_str_op(cp, OP_EQ, cp2); tor_free(cp); tor_free(cp2); /* Replace outdated file */ write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"), "junk goes here", 0); tt_int_op(0, OP_EQ, router_write_fingerprint(1)); cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"), 0, NULL); crypto_pk_get_hashed_fingerprint(key, fp); tor_asprintf(&cp2, "haflinger %s\n", fp); tt_str_op(cp, OP_EQ, cp2); tor_free(cp); tor_free(cp2); done: crypto_pk_free(key); set_client_identity_key(NULL); tor_free(cp); tor_free(cp2); }
/** Run unit tests for our public key crypto functions */ static void test_crypto_pk(void) { crypto_pk_t *pk1 = NULL, *pk2 = NULL; char *encoded = NULL; char data1[1024], data2[1024], data3[1024]; size_t size; int i, j, p, len; /* Public-key ciphers */ pk1 = pk_generate(0); pk2 = crypto_pk_new(); test_assert(pk1 && pk2); test_assert(! crypto_pk_write_public_key_to_string(pk1, &encoded, &size)); test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size)); test_eq(0, crypto_pk_cmp_keys(pk1, pk2)); /* comparison between keys and NULL */ tt_int_op(crypto_pk_cmp_keys(NULL, pk1), <, 0); tt_int_op(crypto_pk_cmp_keys(NULL, NULL), ==, 0); tt_int_op(crypto_pk_cmp_keys(pk1, NULL), >, 0); test_eq(128, crypto_pk_keysize(pk1)); test_eq(1024, crypto_pk_num_bits(pk1)); test_eq(128, crypto_pk_keysize(pk2)); test_eq(1024, crypto_pk_num_bits(pk2)); test_eq(128, crypto_pk_public_encrypt(pk2, data1, sizeof(data1), "Hello whirled.", 15, PK_PKCS1_OAEP_PADDING)); test_eq(128, crypto_pk_public_encrypt(pk1, data2, sizeof(data1), "Hello whirled.", 15, PK_PKCS1_OAEP_PADDING)); /* oaep padding should make encryption not match */ test_memneq(data1, data2, 128); test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data1, 128, PK_PKCS1_OAEP_PADDING,1)); test_streq(data3, "Hello whirled."); memset(data3, 0, 1024); test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128, PK_PKCS1_OAEP_PADDING,1)); test_streq(data3, "Hello whirled."); /* Can't decrypt with public key. */ test_eq(-1, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data2, 128, PK_PKCS1_OAEP_PADDING,1)); /* Try again with bad padding */ memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */ test_eq(-1, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128, PK_PKCS1_OAEP_PADDING,1)); /* File operations: save and load private key */ test_assert(! crypto_pk_write_private_key_to_filename(pk1, get_fname("pkey1"))); /* failing case for read: can't read. */ test_assert(crypto_pk_read_private_key_from_filename(pk2, get_fname("xyzzy")) < 0); write_str_to_file(get_fname("xyzzy"), "foobar", 6); /* Failing case for read: no key. */ test_assert(crypto_pk_read_private_key_from_filename(pk2, get_fname("xyzzy")) < 0); test_assert(! crypto_pk_read_private_key_from_filename(pk2, get_fname("pkey1"))); test_eq(15, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data1, 128, PK_PKCS1_OAEP_PADDING,1)); /* Now try signing. */ strlcpy(data1, "Ossifrage", 1024); test_eq(128, crypto_pk_private_sign(pk1, data2, sizeof(data2), data1, 10)); test_eq(10, crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128)); test_streq(data3, "Ossifrage"); /* Try signing digests. */ test_eq(128, crypto_pk_private_sign_digest(pk1, data2, sizeof(data2), data1, 10)); test_eq(20, crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128)); test_eq(0, crypto_pk_public_checksig_digest(pk1, data1, 10, data2, 128)); test_eq(-1, crypto_pk_public_checksig_digest(pk1, data1, 11, data2, 128)); /*XXXX test failed signing*/ /* Try encoding */ crypto_pk_free(pk2); pk2 = NULL; i = crypto_pk_asn1_encode(pk1, data1, 1024); test_assert(i>0); pk2 = crypto_pk_asn1_decode(data1, i); test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0); /* Try with hybrid encryption wrappers. */ crypto_rand(data1, 1024); for (i = 0; i < 2; ++i) { for (j = 85; j < 140; ++j) { memset(data2,0,1024); memset(data3,0,1024); p = (i==0)?PK_PKCS1_PADDING:PK_PKCS1_OAEP_PADDING; len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2), data1,j,p,0); test_assert(len>=0); len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3), data2,len,p,1); test_eq(len,j); test_memeq(data1,data3,j); } } /* Try copy_full */ crypto_pk_free(pk2); pk2 = crypto_pk_copy_full(pk1); test_assert(pk2 != NULL); test_neq_ptr(pk1, pk2); test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0); done: if (pk1) crypto_pk_free(pk1); if (pk2) crypto_pk_free(pk2); tor_free(encoded); }
/** Deallocate space associated with circ. */ static void circuit_free(circuit_t *circ) { void *mem; size_t memlen; if (!circ) return; if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); mem = ocirc; memlen = sizeof(origin_circuit_t); tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC); if (ocirc->build_state) { extend_info_free(ocirc->build_state->chosen_exit); circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref); } tor_free(ocirc->build_state); circuit_free_cpath(ocirc->cpath); crypto_pk_free(ocirc->intro_key); rend_data_free(ocirc->rend_data); tor_free(ocirc->dest_address); if (ocirc->socks_username) { memwipe(ocirc->socks_username, 0x12, ocirc->socks_username_len); tor_free(ocirc->socks_username); } if (ocirc->socks_password) { memwipe(ocirc->socks_password, 0x06, ocirc->socks_password_len); tor_free(ocirc->socks_password); } } else { or_circuit_t *ocirc = TO_OR_CIRCUIT(circ); /* Remember cell statistics for this circuit before deallocating. */ if (get_options()->CellStatistics) rep_hist_buffer_stats_add_circ(circ, time(NULL)); mem = ocirc; memlen = sizeof(or_circuit_t); tor_assert(circ->magic == OR_CIRCUIT_MAGIC); crypto_cipher_free(ocirc->p_crypto); crypto_digest_free(ocirc->p_digest); crypto_cipher_free(ocirc->n_crypto); crypto_digest_free(ocirc->n_digest); if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC); other->rend_splice = NULL; } /* remove from map. */ circuit_set_p_circid_orconn(ocirc, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(ô->p_conn_cells); } extend_info_free(circ->n_hop); tor_free(circ->n_conn_onionskin); /* Remove from map. */ circuit_set_n_circid_orconn(circ, 0, NULL); /* Clear cell queue _after_ removing it from the map. Otherwise our * "active" checks will be violated. */ cell_queue_clear(&circ->n_conn_cells); memwipe(mem, 0xAA, memlen); /* poison memory */ tor_free(mem); }
/** 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); }
/** Implement a cpuworker. 'data' is an fdarray as returned by socketpair. * Read and writes from fdarray[1]. Reads requests, writes answers. * * Request format: * Task type [1 byte, always CPUWORKER_TASK_ONION] * Opaque tag TAG_LEN * Onionskin challenge ONIONSKIN_CHALLENGE_LEN * Response format: * Success/failure [1 byte, boolean.] * Opaque tag TAG_LEN * Onionskin challenge ONIONSKIN_REPLY_LEN * Negotiated keys KEY_LEN*2+DIGEST_LEN*2 * * (Note: this _should_ be by addr/port, since we're concerned with specific * connections, not with routers (where we'd use identity).) */ static void cpuworker_main(void *data) { char question[ONIONSKIN_CHALLENGE_LEN]; uint8_t question_type; tor_socket_t *fdarray = data; tor_socket_t fd; /* variables for onion processing */ char keys[CPATH_KEY_MATERIAL_LEN]; char reply_to_proxy[ONIONSKIN_REPLY_LEN]; char buf[LEN_ONION_RESPONSE]; char tag[TAG_LEN]; crypto_pk_t *onion_key = NULL, *last_onion_key = NULL; fd = fdarray[1]; /* this side is ours */ #ifndef TOR_IS_MULTITHREADED tor_close_socket(fdarray[0]); /* this is the side of the socketpair the * parent uses */ tor_free_all(1); /* so the child doesn't hold the parent's fd's open */ handle_signals(0); /* ignore interrupts from the keyboard, etc */ #endif tor_free(data); dup_onion_keys(&onion_key, &last_onion_key); for (;;) { ssize_t r; if ((r = recv(fd, (void *)&question_type, 1, 0)) != 1) { // log_fn(LOG_ERR,"read type failed. Exiting."); if (r == 0) { log_info(LD_OR, "CPU worker exiting because Tor process closed connection " "(either rotated keys or died)."); } else { log_info(LD_OR, "CPU worker exiting because of error on connection to Tor " "process."); log_info(LD_OR,"(Error on %d was %s)", fd, tor_socket_strerror(tor_socket_errno(fd))); } goto end; } tor_assert(question_type == CPUWORKER_TASK_ONION); if (read_all(fd, tag, TAG_LEN, 1) != TAG_LEN) { log_err(LD_BUG,"read tag failed. Exiting."); goto end; } if (read_all(fd, question, ONIONSKIN_CHALLENGE_LEN, 1) != ONIONSKIN_CHALLENGE_LEN) { log_err(LD_BUG,"read question failed. Exiting."); goto end; } if (question_type == CPUWORKER_TASK_ONION) { if (onion_skin_server_handshake(question, onion_key, last_onion_key, reply_to_proxy, keys, CPATH_KEY_MATERIAL_LEN) < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); *buf = 0; /* indicate failure in first byte */ memcpy(buf+1,tag,TAG_LEN); /* send all zeros as answer */ memset(buf+1+TAG_LEN, 0, LEN_ONION_RESPONSE-(1+TAG_LEN)); } else { /* success */ log_debug(LD_OR,"onion_skin_server_handshake succeeded."); buf[0] = 1; /* 1 means success */ memcpy(buf+1,tag,TAG_LEN); memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN); memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,CPATH_KEY_MATERIAL_LEN); } if (write_all(fd, buf, LEN_ONION_RESPONSE, 1) != LEN_ONION_RESPONSE) { log_err(LD_BUG,"writing response buf failed. Exiting."); goto end; } log_debug(LD_OR,"finished writing response."); } } end: if (onion_key) crypto_pk_free(onion_key); if (last_onion_key) crypto_pk_free(last_onion_key); tor_close_socket(fd); crypto_thread_cleanup(); spawn_exit(); }
/* 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); }
void construct_consensus(char **consensus_text_md) { networkstatus_t *vote = NULL; networkstatus_t *v1 = NULL, *v2 = NULL, *v3 = NULL; networkstatus_voter_info_t *voter = NULL; authority_cert_t *cert1=NULL, *cert2=NULL, *cert3=NULL; crypto_pk_t *sign_skey_1=NULL, *sign_skey_2=NULL, *sign_skey_3=NULL; crypto_pk_t *sign_skey_leg=NULL; time_t now = time(NULL); smartlist_t *votes = NULL; int n_vrs; tt_assert(!dir_common_authority_pk_init(&cert1, &cert2, &cert3, &sign_skey_1, &sign_skey_2, &sign_skey_3)); sign_skey_leg = pk_generate(4); dir_common_construct_vote_1(&vote, cert1, sign_skey_1, &dir_common_gen_routerstatus_for_v3ns, &v1, &n_vrs, now, 1); networkstatus_vote_free(vote); tt_assert(v1); tt_int_op(n_vrs, ==, 4); tt_int_op(smartlist_len(v1->routerstatus_list), ==, 4); dir_common_construct_vote_2(&vote, cert2, sign_skey_2, &dir_common_gen_routerstatus_for_v3ns, &v2, &n_vrs, now, 1); networkstatus_vote_free(vote); tt_assert(v2); tt_int_op(n_vrs, ==, 4); tt_int_op(smartlist_len(v2->routerstatus_list), ==, 4); dir_common_construct_vote_3(&vote, cert3, sign_skey_3, &dir_common_gen_routerstatus_for_v3ns, &v3, &n_vrs, now, 1); tt_assert(v3); tt_int_op(n_vrs, ==, 4); tt_int_op(smartlist_len(v3->routerstatus_list), ==, 4); networkstatus_vote_free(vote); votes = smartlist_new(); smartlist_add(votes, v1); smartlist_add(votes, v2); smartlist_add(votes, v3); *consensus_text_md = networkstatus_compute_consensus(votes, 3, cert1->identity_key, sign_skey_1, "AAAAAAAAAAAAAAAAAAAA", sign_skey_leg, FLAV_MICRODESC); tt_assert(*consensus_text_md); done: tor_free(voter); networkstatus_vote_free(v1); networkstatus_vote_free(v2); networkstatus_vote_free(v3); smartlist_free(votes); authority_cert_free(cert1); authority_cert_free(cert2); authority_cert_free(cert3); crypto_pk_free(sign_skey_1); crypto_pk_free(sign_skey_2); crypto_pk_free(sign_skey_3); crypto_pk_free(sign_skey_leg); }
static void bench_onion_TAP(void) { const int iters = 1<<9; int i; crypto_pk_t *key, *key2; uint64_t start, end; char os[TAP_ONIONSKIN_CHALLENGE_LEN]; char or[TAP_ONIONSKIN_REPLY_LEN]; crypto_dh_t *dh_out; key = crypto_pk_new(); key2 = crypto_pk_new(); if (crypto_pk_generate_key_with_bits(key, 1024) < 0) goto done; if (crypto_pk_generate_key_with_bits(key2, 1024) < 0) goto done; reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { onion_skin_TAP_create(key, &dh_out, os); crypto_dh_free(dh_out); } end = perftime(); printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); onion_skin_TAP_create(key, &dh_out, os); start = perftime(); for (i = 0; i < iters; ++i) { char key_out[CPATH_KEY_MATERIAL_LEN]; onion_skin_TAP_server_handshake(os, key, NULL, or, key_out, sizeof(key_out)); } end = perftime(); printf("Server-side, key guessed right: %f usec\n", NANOCOUNT(start, end, iters)/1e3); start = perftime(); for (i = 0; i < iters; ++i) { char key_out[CPATH_KEY_MATERIAL_LEN]; onion_skin_TAP_server_handshake(os, key2, key, or, key_out, sizeof(key_out)); } end = perftime(); printf("Server-side, key guessed wrong: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); start = perftime(); for (i = 0; i < iters; ++i) { crypto_dh_t *dh; char key_out[CPATH_KEY_MATERIAL_LEN]; int s; dh = crypto_dh_dup(dh_out); s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out), NULL); crypto_dh_free(dh); tor_assert(s == 0); } end = perftime(); printf("Client-side, part 2: %f usec.\n", NANOCOUNT(start, end, iters)/1e3); done: crypto_pk_free(key); crypto_pk_free(key2); }
static void test_add_onion_helper_keyarg(void *arg) { crypto_pk_t *pk = NULL; crypto_pk_t *pk2 = NULL; const char *key_new_alg = NULL; char *key_new_blob = NULL; char *err_msg = NULL; char *encoded = NULL; char *arg_str = NULL; (void) arg; /* Test explicit RSA1024 key generation. */ pk = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob, &err_msg); tt_assert(pk); tt_str_op(key_new_alg, OP_EQ, "RSA1024"); tt_assert(key_new_blob); tt_assert(!err_msg); /* Test "BEST" key generation (Assumes BEST = RSA1024). */ crypto_pk_free(pk); tor_free(key_new_blob); pk = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob, &err_msg); tt_assert(pk); tt_str_op(key_new_alg, OP_EQ, "RSA1024"); tt_assert(key_new_blob); tt_assert(!err_msg); /* Test discarding the private key. */ crypto_pk_free(pk); tor_free(key_new_blob); pk = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob, &err_msg); tt_assert(pk); tt_assert(!key_new_alg); tt_assert(!key_new_blob); tt_assert(!err_msg); /* Test generating a invalid key type. */ crypto_pk_free(pk); pk = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob, &err_msg); tt_assert(!pk); tt_assert(!key_new_alg); tt_assert(!key_new_blob); tt_assert(err_msg); /* Test loading a RSA1024 key. */ tor_free(err_msg); pk = pk_generate(0); tt_int_op(0, OP_EQ, crypto_pk_base64_encode(pk, &encoded)); tor_asprintf(&arg_str, "RSA1024:%s", encoded); pk2 = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, &err_msg); tt_assert(pk2); tt_assert(!key_new_alg); tt_assert(!key_new_blob); tt_assert(!err_msg); tt_assert(crypto_pk_cmp_keys(pk, pk2) == 0); /* Test loading a invalid key type. */ tor_free(arg_str); crypto_pk_free(pk); pk = NULL; tor_asprintf(&arg_str, "RSA512:%s", encoded); pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, &err_msg); tt_assert(!pk); tt_assert(!key_new_alg); tt_assert(!key_new_blob); tt_assert(err_msg); /* Test loading a invalid key. */ tor_free(arg_str); crypto_pk_free(pk); pk = NULL; tor_free(err_msg); encoded[strlen(encoded)/2] = '\0'; tor_asprintf(&arg_str, "RSA1024:%s", encoded); pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob, &err_msg); tt_assert(!pk); tt_assert(!key_new_alg); tt_assert(!key_new_blob); tt_assert(err_msg); done: crypto_pk_free(pk); crypto_pk_free(pk2); tor_free(key_new_blob); tor_free(err_msg); tor_free(encoded); tor_free(arg_str); }
void scalliontor_readCPUWorkerCallback(int sockd, short ev_types, void * arg) { /* adapted from cpuworker_main. * * these are blocking calls in Tor. we need to cope, so the approach we * take is that if the first read would block, its ok. after that, we * continue through the state machine until we are able to read and write * everything we need to, then reset and start with the next question. * * this is completely nonblocking with the state machine. */ vtor_cpuworker_tp cpuw = arg; g_assert(cpuw); if(cpuw->state == CPUW_NONE) { cpuw->state = CPUW_READTYPE; } int ioResult = 0; int action = 0; enter: switch(cpuw->state) { case CPUW_READTYPE: { ioResult = 0; /* get the type of question */ ioResult = recv(cpuw->fd, &(cpuw->question_type), 1, 0); action = scalliontor_checkIOResult(cpuw, ioResult); if(action == -1) goto kill; else if(action == 0) goto exit; /* we got our initial question type */ tor_assert(cpuw->question_type == CPUWORKER_TASK_ONION); cpuw->state = CPUW_READTAG; goto enter; } case CPUW_READTAG: { ioResult = 0; action = 1; int bytesNeeded = TAG_LEN; while(action > 0 && cpuw->offset < bytesNeeded) { ioResult = recv(cpuw->fd, cpuw->tag+cpuw->offset, bytesNeeded-cpuw->offset, 0); action = scalliontor_checkIOResult(cpuw, ioResult); if(action == -1) goto kill; else if(action == 0) goto exit; /* read some bytes */ cpuw->offset += action; } /* we got what we needed, assert this */ if (cpuw->offset != TAG_LEN) { log_err(LD_BUG,"read tag failed. Exiting."); goto kill; } cpuw->state = CPUW_READCHALLENGE; cpuw->offset = 0; goto enter; } case CPUW_READCHALLENGE: { ioResult = 0; action = 1; int bytesNeeded = ONIONSKIN_CHALLENGE_LEN; while(action > 0 && cpuw->offset < bytesNeeded) { ioResult = recv(cpuw->fd, cpuw->question+cpuw->offset, bytesNeeded-cpuw->offset, 0); action = scalliontor_checkIOResult(cpuw, ioResult); if(action == -1) goto kill; else if(action == 0) goto exit; /* read some bytes */ cpuw->offset += action; } /* we got what we needed, assert this */ if (cpuw->offset != ONIONSKIN_CHALLENGE_LEN) { log_err(LD_BUG,"read question failed. got %i bytes, expecting %i bytes. Exiting.", cpuw->offset, ONIONSKIN_CHALLENGE_LEN); goto kill; } cpuw->state = CPUW_PROCESS; cpuw->offset = 0; goto enter; } case CPUW_PROCESS: { if (cpuw->question_type != CPUWORKER_TASK_ONION) { log_debug(LD_OR,"unknown CPU worker question type. ignoring..."); cpuw->state = CPUW_READTYPE; cpuw->offset = 0; goto exit; } int r = onion_skin_server_handshake(cpuw->question, cpuw->onion_key, cpuw->last_onion_key, cpuw->reply_to_proxy, cpuw->keys, CPATH_KEY_MATERIAL_LEN); if (r < 0) { /* failure */ log_debug(LD_OR,"onion_skin_server_handshake failed."); *(cpuw->buf) = 0; /* indicate failure in first byte */ memcpy(cpuw->buf+1,cpuw->tag,TAG_LEN); /* send all zeros as answer */ memset(cpuw->buf+1+TAG_LEN, 0, LEN_ONION_RESPONSE-(1+TAG_LEN)); } else { /* success */ log_debug(LD_OR,"onion_skin_server_handshake succeeded."); cpuw->buf[0] = 1; /* 1 means success */ memcpy(cpuw->buf+1,cpuw->tag,TAG_LEN); memcpy(cpuw->buf+1+TAG_LEN,cpuw->reply_to_proxy,ONIONSKIN_REPLY_LEN); memcpy(cpuw->buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,cpuw->keys,CPATH_KEY_MATERIAL_LEN); } cpuw->state = CPUW_WRITERESPONSE; cpuw->offset = 0; goto enter; } case CPUW_WRITERESPONSE: { ioResult = 0; action = 1; int bytesNeeded = LEN_ONION_RESPONSE; while(action > 0 && cpuw->offset < bytesNeeded) { ioResult = send(cpuw->fd, cpuw->buf+cpuw->offset, bytesNeeded-cpuw->offset, 0); action = scalliontor_checkIOResult(cpuw, ioResult); if(action == -1) goto kill; else if(action == 0) goto exit; /* wrote some bytes */ cpuw->offset += action; } /* we wrote what we needed, assert this */ if (cpuw->offset != LEN_ONION_RESPONSE) { log_err(LD_BUG,"writing response buf failed. Exiting."); goto kill; } log_debug(LD_OR,"finished writing response."); cpuw->state = CPUW_READTYPE; cpuw->offset = 0; goto enter; } default: { log_err(LD_BUG,"unknown CPU worker state. Exiting."); goto kill; } } exit: return; kill: if(cpuw != NULL) { if (cpuw->onion_key) crypto_pk_free(cpuw->onion_key); if (cpuw->last_onion_key) crypto_pk_free(cpuw->last_onion_key); tor_close_socket(cpuw->fd); event_del(&(cpuw->read_event)); free(cpuw); } }
/** Process an AUTHENTICATE cell from an OR connection. * * If it's ill-formed or we weren't supposed to get one or we're not doing a * v3 handshake, then mark the connection. If it does not authenticate the * other side of the connection successfully (because it isn't signed right, * we didn't get a CERTS cell, etc) mark the connection. Otherwise, accept * the identity of the router on the other side of the connection. */ static void command_process_authenticate_cell(var_cell_t *cell, or_connection_t *conn) { uint8_t expected[V3_AUTH_FIXED_PART_LEN]; const uint8_t *auth; int authlen; #define ERR(s) \ do { \ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, \ "Received a bad AUTHENTICATE cell from %s:%d: %s", \ safe_str(conn->_base.address), conn->_base.port, (s)); \ connection_mark_for_close(TO_CONN(conn)); \ return; \ } while (0) 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->started_here) ERR("We originated this connection"); if (conn->handshake_state->received_authenticate) ERR("We already got one!"); if (conn->handshake_state->authenticated) { /* Should be impossible given other checks */ ERR("The peer is already authenticated"); } if (! conn->handshake_state->received_certs_cell) ERR("We never got a certs cell"); if (conn->handshake_state->auth_cert == NULL) ERR("We never got an authentication certificate"); if (conn->handshake_state->id_cert == NULL) ERR("We never got an identity certificate"); if (cell->payload_len < 4) ERR("Cell was way too short"); auth = cell->payload; { uint16_t type = ntohs(get_uint16(auth)); uint16_t len = ntohs(get_uint16(auth+2)); if (4 + len > cell->payload_len) ERR("Authenticator was truncated"); if (type != AUTHTYPE_RSA_SHA256_TLSSECRET) ERR("Authenticator type was not recognized"); auth += 4; authlen = len; } if (authlen < V3_AUTH_BODY_LEN + 1) ERR("Authenticator was too short"); if (connection_or_compute_authenticate_cell_body( conn, expected, sizeof(expected), NULL, 1) < 0) ERR("Couldn't compute expected AUTHENTICATE cell body"); if (tor_memneq(expected, auth, sizeof(expected))) ERR("Some field in the AUTHENTICATE cell body was not as expected"); { crypto_pk_t *pk = tor_tls_cert_get_key( conn->handshake_state->auth_cert); char d[DIGEST256_LEN]; char *signed_data; size_t keysize; int signed_len; if (!pk) ERR("Internal error: couldn't get RSA key from AUTH cert."); crypto_digest256(d, (char*)auth, V3_AUTH_BODY_LEN, DIGEST_SHA256); keysize = crypto_pk_keysize(pk); signed_data = tor_malloc(keysize); signed_len = crypto_pk_public_checksig(pk, signed_data, keysize, (char*)auth + V3_AUTH_BODY_LEN, authlen - V3_AUTH_BODY_LEN); crypto_pk_free(pk); if (signed_len < 0) { tor_free(signed_data); ERR("Signature wasn't valid"); } if (signed_len < DIGEST256_LEN) { tor_free(signed_data); ERR("Not enough data was signed"); } /* Note that we deliberately allow *more* than DIGEST256_LEN bytes here, * in case they're later used to hold a SHA3 digest or something. */ if (tor_memneq(signed_data, d, DIGEST256_LEN)) { tor_free(signed_data); ERR("Signature did not match data to be signed."); } tor_free(signed_data); } /* Okay, we are authenticated. */ conn->handshake_state->received_authenticate = 1; conn->handshake_state->authenticated = 1; conn->handshake_state->digest_received_data = 0; { crypto_pk_t *identity_rcvd = tor_tls_cert_get_key(conn->handshake_state->id_cert); const digests_t *id_digests = tor_cert_get_id_digests(conn->handshake_state->id_cert); /* This must exist; we checked key type when reading the cert. */ tor_assert(id_digests); 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); connection_or_init_conn_from_address(conn, &conn->_base.addr, conn->_base.port, (const char*)conn->handshake_state->authenticated_peer_id, 0); log_info(LD_OR, "Got an AUTHENTICATE cell from %s:%d: Looks good.", safe_str(conn->_base.address), conn->_base.port); } #undef ERR }
static void test_bad_onion_handshake(void *arg) { char junk_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; char junk_buf2[TAP_ONIONSKIN_CHALLENGE_LEN]; /* client-side */ crypto_dh_t *c_dh = NULL; char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN]; char c_keys[40]; /* server-side */ char s_buf[TAP_ONIONSKIN_REPLY_LEN]; char s_keys[40]; /* shared */ crypto_pk_t *pk = NULL, *pk2 = NULL; (void)arg; pk = pk_generate(0); pk2 = pk_generate(1); /* Server: Case 1: the encrypted data is degenerate. */ memset(junk_buf, 0, sizeof(junk_buf)); crypto_pk_obsolete_public_hybrid_encrypt(pk, junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN, junk_buf, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1); tt_int_op(-1, OP_EQ, onion_skin_TAP_server_handshake(junk_buf2, pk, NULL, s_buf, s_keys, 40)); /* Server: Case 2: the encrypted data is not long enough. */ memset(junk_buf, 0, sizeof(junk_buf)); memset(junk_buf2, 0, sizeof(junk_buf2)); crypto_pk_public_encrypt(pk, junk_buf2, sizeof(junk_buf2), junk_buf, 48, PK_PKCS1_OAEP_PADDING); tt_int_op(-1, OP_EQ, onion_skin_TAP_server_handshake(junk_buf2, pk, NULL, s_buf, s_keys, 40)); /* client handshake 1: do it straight. */ memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN); tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf)); /* Server: Case 3: we just don't have the right key. */ tt_int_op(-1, OP_EQ, onion_skin_TAP_server_handshake(c_buf, pk2, NULL, s_buf, s_keys, 40)); /* Server: Case 4: The RSA-encrypted portion is corrupt. */ c_buf[64] ^= 33; tt_int_op(-1, OP_EQ, onion_skin_TAP_server_handshake(c_buf, pk, NULL, s_buf, s_keys, 40)); c_buf[64] ^= 33; /* (Let the server procede) */ tt_int_op(0, OP_EQ, onion_skin_TAP_server_handshake(c_buf, pk, NULL, s_buf, s_keys, 40)); /* Client: Case 1: The server sent back junk. */ const char *msg = NULL; s_buf[64] ^= 33; tt_int_op(-1, OP_EQ, onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg)); s_buf[64] ^= 33; tt_str_op(msg, OP_EQ, "Digest DOES NOT MATCH on onion handshake. " "Bug or attack."); /* Let the client finish; make sure it can. */ msg = NULL; tt_int_op(0, OP_EQ, onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg)); tt_mem_op(s_keys,OP_EQ, c_keys, 40); tt_ptr_op(msg, OP_EQ, NULL); /* Client: Case 2: The server sent back a degenerate DH. */ memset(s_buf, 0, sizeof(s_buf)); tt_int_op(-1, OP_EQ, onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, &msg)); tt_str_op(msg, OP_EQ, "DH computation failed."); done: crypto_dh_free(c_dh); crypto_pk_free(pk); crypto_pk_free(pk2); }
/** 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 }
/** 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); }