From 961ecf7abfc80571ab858099d1d4f6362b791ea0 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Tue, 16 Dec 2003 08:21:58 +0000 Subject: add H(K|1) to the onionskin reply verify it at the client end abstract the onionskin handshake lengths breaks backward compatibility (again) svn:r941 --- src/or/circuit.c | 28 +++++++++--- src/or/command.c | 6 +-- src/or/cpuworker.c | 18 ++++---- src/or/onion.c | 127 +++++++++++++++++++++++++++++++++-------------------- src/or/or.h | 19 +++++--- src/or/test.c | 8 ++-- 6 files changed, 132 insertions(+), 74 deletions(-) (limited to 'src') diff --git a/src/or/circuit.c b/src/or/circuit.c index 0d908bf20..fa5883ec1 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -114,6 +114,10 @@ static void circuit_free_cpath_node(crypt_path_t *victim) { crypto_free_cipher_env(victim->f_crypto); if(victim->b_crypto) crypto_free_cipher_env(victim->b_crypto); + if(victim->f_digest) + crypto_free_digest_env(victim->f_digest); + if(victim->b_digest) + crypto_free_digest_env(victim->b_digest); if(victim->handshake_state) crypto_dh_free(victim->handshake_state); free(victim); @@ -319,6 +323,12 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, if(recognized) { if(cell_direction == CELL_DIRECTION_OUT) { +#if 0 + if(relay_update_digest(circ->n_digest, cell) < 0) { + log_fn(LOG_WARN,"outgoing cell failed integrity check. Closing circ."); + return -1; + } +#endif ++stats_n_relay_cells_delivered; log_fn(LOG_DEBUG,"Sending to exit."); if (connection_edge_process_relay_cell(cell, circ, conn, EDGE_EXIT, NULL) < 0) { @@ -327,6 +337,12 @@ int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ, } } if(cell_direction == CELL_DIRECTION_IN) { +#if 0 + if(relay_update_digest(layer_hint->p_digest, cell) < 0) { + log_fn(LOG_WARN,"outgoing cell failed integrity check. Closing circ."); + return -1; + } +#endif ++stats_n_relay_cells_delivered; log_fn(LOG_DEBUG,"Sending to AP."); if (connection_edge_process_relay_cell(cell, circ, conn, EDGE_AP, layer_hint) < 0) { @@ -365,7 +381,8 @@ int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction, assert(inlen < 256); if(cell_direction == CELL_DIRECTION_IN) { - if(circ->cpath) { /* we're at the beginning of the circuit. We'll want to do layered crypts. */ + if(circ->cpath) { /* we're at the beginning of the circuit. + We'll want to do layered crypts. */ thishop = circ->cpath; if(thishop->state != CPATH_STATE_OPEN) { log_fn(LOG_WARN,"Relay cell before first created cell?"); @@ -845,7 +862,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) { memset(&cell, 0, sizeof(cell_t)); cell.command = CELL_CREATE; cell.circ_id = circ->n_circ_id; - cell.length = DH_ONIONSKIN_LEN; + cell.length = ONIONSKIN_CHALLENGE_LEN; if(onion_skin_create(circ->n_conn->onion_pkey, &(circ->cpath->handshake_state), cell.payload) < 0) { log_fn(LOG_WARN,"onion_skin_create (first hop) failed."); @@ -883,7 +900,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) { SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_EXTEND); SET_CELL_STREAM_ID(cell, ZERO_STREAM); - cell.length = RELAY_HEADER_SIZE + 6 + DH_ONIONSKIN_LEN; + cell.length = RELAY_HEADER_SIZE + 6 + ONIONSKIN_CHALLENGE_LEN; *(uint32_t*)(cell.payload+RELAY_HEADER_SIZE) = htonl(hop->addr); *(uint16_t*)(cell.payload+RELAY_HEADER_SIZE+4) = htons(hop->port); if(onion_skin_create(router->onion_pkey, &(hop->handshake_state), cell.payload+RELAY_HEADER_SIZE+6) < 0) { @@ -954,9 +971,10 @@ int circuit_extend(cell_t *cell, circuit_t *circ) { memset(&newcell, 0, sizeof(cell_t)); newcell.command = CELL_CREATE; newcell.circ_id = circ->n_circ_id; - newcell.length = DH_ONIONSKIN_LEN; + newcell.length = ONIONSKIN_CHALLENGE_LEN; - memcpy(newcell.payload, cell->payload+RELAY_HEADER_SIZE+6, DH_ONIONSKIN_LEN); + memcpy(newcell.payload, cell->payload+RELAY_HEADER_SIZE+6, + ONIONSKIN_CHALLENGE_LEN); connection_or_write_cell_to_buf(&newcell, circ->n_conn); return 0; diff --git a/src/or/command.c b/src/or/command.c index fa83d23c8..ed0a8d04d 100644 --- a/src/or/command.c +++ b/src/or/command.c @@ -103,7 +103,7 @@ static void command_process_create_cell(cell_t *cell, connection_t *conn) { circ = circuit_new(cell->circ_id, conn); circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING; - if(cell->length != DH_ONIONSKIN_LEN) { + if(cell->length != ONIONSKIN_CHALLENGE_LEN) { log_fn(LOG_WARN,"Bad cell length %d. Dropping.", cell->length); circuit_close(circ); return; @@ -135,7 +135,7 @@ static void command_process_created_cell(cell_t *cell, connection_t *conn) { circuit_close(circ); return; } - assert(cell->length == DH_KEY_LEN); + assert(cell->length == ONIONSKIN_REPLY_LEN); if(circ->cpath) { /* we're the OP. Handshake this. */ log_fn(LOG_DEBUG,"at OP. Finishing handshake."); @@ -153,7 +153,7 @@ static void command_process_created_cell(cell_t *cell, connection_t *conn) { } else { /* pack it into an extended relay cell, and send it. */ log_fn(LOG_INFO,"Converting created cell to extended relay cell, sending."); connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTENDED, - cell->payload, DH_KEY_LEN, NULL); + cell->payload, cell->length, NULL); } } diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c index c964115f9..fee8eebb4 100644 --- a/src/or/cpuworker.c +++ b/src/or/cpuworker.c @@ -9,8 +9,8 @@ extern or_options_t options; /* command-line and config-file options */ #define MIN_CPUWORKERS 1 #define TAG_LEN 8 -#define LEN_ONION_QUESTION (1+TAG_LEN+DH_ONIONSKIN_LEN) -#define LEN_ONION_RESPONSE (1+TAG_LEN+DH_KEY_LEN+32) +#define LEN_ONION_QUESTION (1+TAG_LEN+ONIONSKIN_CHALLENGE_LEN) +#define LEN_ONION_RESPONSE (1+TAG_LEN+ONIONSKIN_REPLY_LEN+32) int num_cpuworkers=0; int num_cpuworkers_busy=0; @@ -95,7 +95,7 @@ int connection_cpu_process_inbuf(connection_t *conn) { circuit_close(circ); goto done_processing; } - if(onionskin_answer(circ, buf+1+TAG_LEN, buf+1+TAG_LEN+DH_KEY_LEN) < 0) { + if(onionskin_answer(circ, buf+1+TAG_LEN, buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) { log_fn(LOG_WARN,"onionskin_answer failed. Closing."); circuit_close(circ); goto done_processing; @@ -113,14 +113,14 @@ done_processing: } int cpuworker_main(void *data) { - unsigned char question[DH_ONIONSKIN_LEN]; + unsigned char question[ONIONSKIN_CHALLENGE_LEN]; unsigned char question_type; int *fdarray = data; int fd; /* variables for onion processing */ unsigned char keys[32]; - unsigned char reply_to_proxy[DH_KEY_LEN]; + unsigned char reply_to_proxy[ONIONSKIN_REPLY_LEN]; unsigned char buf[LEN_ONION_RESPONSE]; char tag[TAG_LEN]; @@ -140,7 +140,7 @@ int cpuworker_main(void *data) { spawn_exit(); } - if(read_all(fd, question, DH_ONIONSKIN_LEN) != DH_ONIONSKIN_LEN) { + if(read_all(fd, question, ONIONSKIN_CHALLENGE_LEN) != ONIONSKIN_CHALLENGE_LEN) { log_fn(LOG_ERR,"read question failed. Exiting."); spawn_exit(); } @@ -156,8 +156,8 @@ int cpuworker_main(void *data) { log_fn(LOG_INFO,"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,DH_KEY_LEN); - memcpy(buf+1+TAG_LEN+DH_KEY_LEN,keys,32); + memcpy(buf+1+TAG_LEN,reply_to_proxy,ONIONSKIN_REPLY_LEN); + memcpy(buf+1+TAG_LEN+ONIONSKIN_REPLY_LEN,keys,32); } if(write_all(fd, buf, LEN_ONION_RESPONSE) != LEN_ONION_RESPONSE) { log_fn(LOG_ERR,"writing response buf failed. Exiting."); @@ -272,7 +272,7 @@ int assign_to_cpuworker(connection_t *cpuworker, unsigned char question_type, connection_write_to_buf(&question_type, 1, cpuworker); connection_write_to_buf(tag, sizeof(tag), cpuworker); - connection_write_to_buf(circ->onionskin, DH_ONIONSKIN_LEN, cpuworker); + connection_write_to_buf(circ->onionskin, ONIONSKIN_CHALLENGE_LEN, cpuworker); } return 0; } diff --git a/src/or/onion.c b/src/or/onion.c index 5578fb793..0923741d9 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -124,13 +124,13 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key memset(&cell, 0, sizeof(cell_t)); cell.command = CELL_CREATED; cell.circ_id = circ->p_circ_id; - cell.length = DH_KEY_LEN; + cell.length = ONIONSKIN_REPLY_LEN; circ->state = CIRCUIT_STATE_OPEN; log_fn(LOG_DEBUG,"Entering."); - memcpy(cell.payload, payload, DH_KEY_LEN); + memcpy(cell.payload, payload, ONIONSKIN_REPLY_LEN); log_fn(LOG_DEBUG,"init cipher forward %d, backward %d.", *(int*)keys, *(int*)(keys+16)); @@ -548,52 +548,56 @@ int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state, rout /*----------------------------------------------------------------------*/ -/* Given a router's public key, generates a 144-byte encrypted DH pubkey, - * and stores it into onion_skin out. Stores the DH private key into - * handshake_state_out for later completion of the handshake. +/* Given a router's 128 byte public key, + stores the following in onion_skin_out: +[16 bytes] Symmetric key for encrypting blob past RSA +[112 bytes] g^x part 1 (inside the RSA) +[16 bytes] g^x part 2 (symmetrically encrypted) +[ 6 bytes] Meeting point (IP/port) +[ 8 bytes] Meeting cookie +[16 bytes] End-to-end authentication [optional] + + * Stores the DH private key into handshake_state_out for later completion + * of the handshake. * - * The encrypted pubkey is formed as follows: - * 16 bytes of symmetric key - * 128 bytes of g^x for DH. - * The first 128 bytes are RSA-encrypted with the server's public key, - * and the last 16 are encrypted with the symmetric key. + * The meeting point/cookies and auth are zeroed out for now. */ int onion_skin_create(crypto_pk_env_t *dest_router_key, crypto_dh_env_t **handshake_state_out, - char *onion_skin_out) /* Must be DH_ONIONSKIN_LEN bytes long */ + char *onion_skin_out) /* Must be ONIONSKIN_CHALLENGE_LEN bytes */ { char iv[16]; - char *pubkey = NULL; + char *challenge = NULL; crypto_dh_env_t *dh = NULL; crypto_cipher_env_t *cipher = NULL; int dhbytes, pkbytes; *handshake_state_out = NULL; - memset(onion_skin_out, 0, DH_ONIONSKIN_LEN); + memset(onion_skin_out, 0, ONIONSKIN_CHALLENGE_LEN); memset(iv, 0, 16); if (!(dh = crypto_dh_new())) goto err; - + dhbytes = crypto_dh_get_bytes(dh); pkbytes = crypto_pk_keysize(dest_router_key); - assert(dhbytes+16 == DH_ONIONSKIN_LEN); - pubkey = (char *)tor_malloc(dhbytes+16); + assert(dhbytes == 128); + assert(pkbytes == 128); + challenge = (char *)tor_malloc_zero(ONIONSKIN_CHALLENGE_LEN); - if (crypto_rand(16, pubkey)) + if (crypto_rand(16, challenge)) goto err; /* You can't just run around RSA-encrypting any bitstream: if it's * greater than the RSA key, then OpenSSL will happily encrypt, * and later decrypt to the wrong value. So we set the first bit - * of 'pubkey' to 0. This means that our symmetric key is really only - * 127 bits long, but since it shouldn't be necessary to encrypt - * DH public keys values in the first place, we should be fine. + * of 'challenge' to 0. This means that our symmetric key is really + * only 127 bits. */ - pubkey[0] &= 0x7f; + challenge[0] &= 0x7f; - if (crypto_dh_get_public(dh, pubkey+16, dhbytes)) + if (crypto_dh_get_public(dh, challenge+16, dhbytes)) goto err; #ifdef DEBUG_ONION_SKINS @@ -601,65 +605,69 @@ onion_skin_create(crypto_pk_env_t *dest_router_key, { int _i; for (_i = 0; _i