|
@@ -6,11 +6,8 @@
|
|
|
|
|
|
extern or_options_t options; /* command-line and config-file options */
|
|
|
|
|
|
-static int onion_process(circuit_t *circ);
|
|
|
-static int onion_deliver_to_conn(aci_t aci, unsigned char *onion, uint32_t onionlen, connection_t *conn);
|
|
|
static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len);
|
|
|
-static int find_tracked_onion(unsigned char *onion, uint32_t onionlen,
|
|
|
- int expire);
|
|
|
+static int onionskin_process(circuit_t *circ);
|
|
|
|
|
|
int decide_aci_type(uint32_t local_addr, uint16_t local_port,
|
|
|
uint32_t remote_addr, uint16_t remote_port) {
|
|
@@ -76,17 +73,19 @@ void onion_pending_process_one(void) {
|
|
|
if(!ol_list)
|
|
|
return; /* no onions pending, we're done */
|
|
|
|
|
|
- assert(ol_list->circ && ol_list->circ->p_conn);
|
|
|
+ assert(ol_list->circ);
|
|
|
+ assert(ol_list->circ->p_conn);
|
|
|
assert(ol_length > 0);
|
|
|
circ = ol_list->circ;
|
|
|
|
|
|
- if(onion_process(circ) < 0) {
|
|
|
+ if(onionskin_process(circ) < 0) {
|
|
|
log(LOG_DEBUG,"onion_pending_process_one(): Failed. Closing.");
|
|
|
onion_pending_remove(circ);
|
|
|
circuit_close(circ);
|
|
|
} else {
|
|
|
log(LOG_DEBUG,"onion_pending_process_one(): Succeeded. Delivering queued relay cells.");
|
|
|
for(tmpd = ol_list->relay_cells; tmpd; tmpd=tmpd->next) {
|
|
|
+ log(LOG_DEBUG,"onion_pending_process_one(): Delivering relay cell...");
|
|
|
command_process_relay_cell(tmpd->cell, circ->p_conn);
|
|
|
}
|
|
|
onion_pending_remove(circ);
|
|
@@ -174,136 +173,48 @@ void onion_pending_relay_add(circuit_t *circ, cell_t *cell) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* helper function for onion_process */
|
|
|
-static int onion_deliver_to_conn(aci_t aci, unsigned char *onion, uint32_t onionlen, connection_t *conn) {
|
|
|
- char *buf;
|
|
|
- int buflen, dataleft;
|
|
|
+/* learn keys, initialize, then send a created cell back */
|
|
|
+static int onionskin_process(circuit_t *circ) {
|
|
|
+ unsigned char iv[16];
|
|
|
+ unsigned char keys[32];
|
|
|
cell_t cell;
|
|
|
-
|
|
|
- assert(aci && onion && onionlen);
|
|
|
-
|
|
|
- buflen = onionlen+4;
|
|
|
- buf = malloc(buflen);
|
|
|
- if(!buf)
|
|
|
- return -1;
|
|
|
-
|
|
|
- log(LOG_DEBUG,"onion_deliver_to_conn(): Setting onion length to %u.",onionlen);
|
|
|
- *(uint32_t*)buf = htonl(onionlen);
|
|
|
- memcpy((buf+4),onion,onionlen);
|
|
|
-
|
|
|
- dataleft = buflen;
|
|
|
- while(dataleft > 0) {
|
|
|
- memset(&cell,0,sizeof(cell_t));
|
|
|
- cell.command = CELL_CREATE;
|
|
|
- cell.aci = aci;
|
|
|
- if(dataleft >= CELL_PAYLOAD_SIZE)
|
|
|
- cell.length = CELL_PAYLOAD_SIZE;
|
|
|
- else
|
|
|
- cell.length = dataleft;
|
|
|
- memcpy(cell.payload, buf+buflen-dataleft, cell.length);
|
|
|
- dataleft -= cell.length;
|
|
|
-
|
|
|
- log(LOG_DEBUG,"onion_deliver_to_conn(): Delivering create cell, payload %d bytes.",cell.length);
|
|
|
- if(connection_write_cell_to_buf(&cell, conn) < 0) {
|
|
|
- log(LOG_DEBUG,"onion_deliver_to_conn(): Could not buffer new create cells. Closing.");
|
|
|
- free(buf);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
- free(buf);
|
|
|
- return 0;
|
|
|
-}
|
|
|
|
|
|
-static int onion_process(circuit_t *circ) {
|
|
|
- connection_t *n_conn;
|
|
|
- int retval;
|
|
|
- aci_t aci_type;
|
|
|
- struct sockaddr_in me; /* my router identity */
|
|
|
- onion_layer_t layer;
|
|
|
+ memset(iv, 0, 16);
|
|
|
|
|
|
- if(learn_my_address(&me) < 0)
|
|
|
- return -1;
|
|
|
+ memset(&cell, 0, sizeof(cell_t));
|
|
|
+ cell.command = CELL_CREATED;
|
|
|
+ cell.aci = circ->p_aci;
|
|
|
+ cell.length = 192;
|
|
|
|
|
|
- /* decrypt it in-place */
|
|
|
- if(decrypt_onion(circ->onion,circ->onionlen,getprivatekey(),&layer) < 0) {
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): decrypt_onion() failed, closing circuit.");
|
|
|
+ circ->state = CIRCUIT_STATE_OPEN;
|
|
|
+
|
|
|
+ log(LOG_DEBUG,"onionskin_process(): Entering.");
|
|
|
+
|
|
|
+ if(onion_skin_server_handshake(circ->onionskin, getprivatekey(),
|
|
|
+ cell.payload, keys, 32) < 0) {
|
|
|
+ log(LOG_ERR,"onionskin_process(): onion_skin_server_handshake failed.");
|
|
|
return -1;
|
|
|
}
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): Onion decrypted.");
|
|
|
|
|
|
- /* check freshness */
|
|
|
- if (layer.expire < (uint32_t)time(NULL)) /* expired onion */ /*XXXX*/
|
|
|
- {
|
|
|
- log(LOG_NOTICE,"I have just received an expired onion. This could be a replay attack.");
|
|
|
+ log(LOG_DEBUG,"onionskin_process: init cipher forward %d, backward %d.", *(int*)keys, *(int*)(keys+16));
|
|
|
+
|
|
|
+ if (!(circ->n_crypto =
|
|
|
+ crypto_create_init_cipher(DEFAULT_CIPHER,keys,iv,0))) {
|
|
|
+ log(LOG_ERR,"Cipher initialization failed.");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- aci_type = decide_aci_type(ntohl(me.sin_addr.s_addr), ntohs(me.sin_port),
|
|
|
- layer.addr, layer.port);
|
|
|
-
|
|
|
- if(circuit_init(circ, aci_type, &layer) < 0) {
|
|
|
- log(LOG_ERR,"process_onion(): init_circuit() failed.");
|
|
|
+ if (!(circ->p_crypto =
|
|
|
+ crypto_create_init_cipher(DEFAULT_CIPHER,keys+16,iv,1))) {
|
|
|
+ log(LOG_ERR,"Cipher initialization failed.");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- /* check for replay. at the same time, add it to the pile of tracked onions. */
|
|
|
- if(find_tracked_onion(circ->onion, circ->onionlen, layer.expire)) {
|
|
|
- log(LOG_NOTICE,"process_onion(): I have just received a replayed onion. This could be a replay attack.");
|
|
|
+ if(connection_write_cell_to_buf(&cell, circ->p_conn) < 0) {
|
|
|
return -1;
|
|
|
}
|
|
|
+ log(LOG_DEBUG,"onionskin_process(): Finished sending 'created' cell.");
|
|
|
|
|
|
- /* now we must send create cells to the next router */
|
|
|
- if(circ->n_addr && circ->n_port) {
|
|
|
- n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
|
|
|
- if(!n_conn || n_conn->type != CONN_TYPE_OR) {
|
|
|
- /* i've disabled making connections through OPs, but it's definitely
|
|
|
- * possible here. I'm not sure if it would be a bug or a feature. -RD
|
|
|
- */
|
|
|
- /* note also that this will close circuits where the onion has the same
|
|
|
- * router twice in a row in the path. i think that's ok. -RD
|
|
|
- */
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): Next router not connected. Closing.");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- circ->n_addr = n_conn->addr; /* these are different if we found a twin instead */
|
|
|
- circ->n_port = n_conn->port;
|
|
|
-
|
|
|
- circ->n_conn = n_conn;
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): n_conn is %s:%u",n_conn->address,n_conn->port);
|
|
|
-
|
|
|
- /* send the CREATE cells on to the next hop */
|
|
|
- pad_onion(circ->onion, circ->onionlen, ONION_LAYER_SIZE);
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): Padded the onion with random data.");
|
|
|
-
|
|
|
- retval = onion_deliver_to_conn(circ->n_aci, circ->onion, circ->onionlen, n_conn);
|
|
|
- free(circ->onion);
|
|
|
- circ->onion = NULL;
|
|
|
- if (retval == -1) {
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): Could not deliver the onion to next conn. Closing.");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- } else { /* this is destined for an exit */
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): create cell reached exit. Circuit established.");
|
|
|
-#if 0
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): Creating new exit connection.");
|
|
|
- n_conn = connection_new(CONN_TYPE_EXIT);
|
|
|
- if(!n_conn) {
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): connection_new failed. Closing.");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- n_conn->state = EXIT_CONN_STATE_CONNECTING_WAIT;
|
|
|
- n_conn->receiver_bucket = -1; /* edge connections don't do receiver buckets */
|
|
|
- n_conn->bandwidth = -1;
|
|
|
- n_conn->s = -1; /* not yet valid */
|
|
|
- if(connection_add(n_conn) < 0) { /* no space, forget it */
|
|
|
- log(LOG_DEBUG,"command_process_create_cell(): connection_add failed. Closing.");
|
|
|
- connection_free(n_conn);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- circ->n_conn = n_conn;
|
|
|
-#endif
|
|
|
- }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -432,402 +343,82 @@ static int count_acceptable_routers(routerinfo_t **rarray, int rarray_len) {
|
|
|
return num;
|
|
|
}
|
|
|
|
|
|
-/* creates a new onion from route, stores it and its length into buf and len respectively */
|
|
|
-unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int *route, int routelen, int *len, crypt_path_t **cpath)
|
|
|
-{
|
|
|
+crypt_path_t *onion_generate_cpath(routerinfo_t **firsthop) {
|
|
|
+ int routelen; /* length of the route */
|
|
|
+ unsigned int *route; /* hops in the route as an array of indexes into rarray */
|
|
|
+ crypt_path_t *cpath=NULL;
|
|
|
+ routerinfo_t **rarray;
|
|
|
+ int rarray_len;
|
|
|
int i;
|
|
|
- char *layerp;
|
|
|
crypt_path_t *hop;
|
|
|
- unsigned char *buf;
|
|
|
routerinfo_t *router;
|
|
|
- unsigned char iv[16];
|
|
|
struct in_addr netaddr;
|
|
|
- onion_layer_t layer;
|
|
|
-
|
|
|
- assert(rarray && route && len && routelen && cpath);
|
|
|
-
|
|
|
- *cpath = NULL;
|
|
|
|
|
|
- /* calculate the size of the onion */
|
|
|
- *len = routelen * ONION_LAYER_SIZE + ONION_PADDING_SIZE;
|
|
|
- /* 28 bytes per layer + 100 bytes padding for the innermost layer */
|
|
|
- log(LOG_DEBUG,"create_onion() : Size of the onion is %u.",*len);
|
|
|
+ router_get_rarray(&rarray, &rarray_len);
|
|
|
|
|
|
- /* allocate memory for the onion */
|
|
|
- buf = malloc(*len);
|
|
|
- if(!buf) {
|
|
|
- log(LOG_ERR,"Error allocating memory.");
|
|
|
+ /* choose a route */
|
|
|
+ route = new_route(options.CoinWeight, rarray, rarray_len, &routelen);
|
|
|
+ if (!route) {
|
|
|
+ log(LOG_ERR,"onion_generate_cpath(): Error choosing a route through the OR network.");
|
|
|
return NULL;
|
|
|
}
|
|
|
- log(LOG_DEBUG,"create_onion() : Allocated memory for the onion.");
|
|
|
+ log(LOG_DEBUG,"onion_generate_cpath(): Chosen a route of length %u: ",routelen);
|
|
|
+
|
|
|
+ *firsthop = rarray[route[routelen-1]];
|
|
|
+ assert(*firsthop); /* should always be defined */
|
|
|
|
|
|
for(i=0; i<routelen; i++) {
|
|
|
netaddr.s_addr = htonl((rarray[route[i]])->addr);
|
|
|
|
|
|
- log(LOG_DEBUG,"create_onion(): %u : %s:%u, %u/%u",routelen-i,
|
|
|
+ log(LOG_DEBUG,"onion_generate_cpath(): %u : %s:%u, %u/%u",routelen-i,
|
|
|
inet_ntoa(netaddr),
|
|
|
(rarray[route[i]])->or_port,
|
|
|
(rarray[route[i]])->pkey,
|
|
|
crypto_pk_keysize((rarray[route[i]])->pkey));
|
|
|
}
|
|
|
|
|
|
- layerp = buf + *len - ONION_LAYER_SIZE - ONION_PADDING_SIZE; /* pointer to innermost layer */
|
|
|
- /* create the onion layer by layer, starting with the innermost */
|
|
|
+ /* create the cpath layer by layer, starting at the last hop */
|
|
|
for (i=0;i<routelen;i++) {
|
|
|
router = rarray[route[i]];
|
|
|
|
|
|
- layer.version = OR_VERSION;
|
|
|
- if (i) { /* not last hop */
|
|
|
- layer.port = rarray[route[i-1]]->or_port;
|
|
|
- layer.addr = rarray[route[i-1]]->addr;
|
|
|
- } else {
|
|
|
- layer.port = 0;
|
|
|
- layer.addr = 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* Expiration Time */
|
|
|
- layer.expire = (uint32_t)(time(NULL) + 86400); /* NOW + 1 day */
|
|
|
-
|
|
|
- /* Key Seed Material */
|
|
|
- if(crypto_rand(ONION_KEYSEED_LEN, layer.keyseed)) { /* error */
|
|
|
- log(LOG_ERR,"Error generating random data.");
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- onion_pack(layerp, &layer);
|
|
|
-
|
|
|
-// log(LOG_DEBUG,"create_onion() : Onion layer %u built : %u, %u, %u, %s, %u.",i+1,layer->zero,layer->backf,layer->forwf,inet_ntoa(*((struct in_addr *)&layer->addr)),layer->port);
|
|
|
-
|
|
|
/* build up the crypt_path */
|
|
|
hop = (crypt_path_t *)malloc(sizeof(crypt_path_t));
|
|
|
if(!hop) {
|
|
|
- log(LOG_ERR,"Error allocating memory.");
|
|
|
- goto error;
|
|
|
+ log(LOG_ERR,"Error allocating crypt path hop memory.");
|
|
|
+ circuit_free_cpath(cpath);
|
|
|
+ free(route);
|
|
|
+ return NULL;
|
|
|
}
|
|
|
+ memset(hop, 0, sizeof(crypt_path_t));
|
|
|
|
|
|
/* link hop into the cpath, at the front */
|
|
|
- hop->next = *cpath;
|
|
|
+ hop->next = cpath;
|
|
|
hop->prev = NULL;
|
|
|
- hop->state = CPATH_STATE_OPEN; /* change when we move to incremental paths */
|
|
|
- if(*cpath) {
|
|
|
- (*cpath)->prev = hop;
|
|
|
- }
|
|
|
- *cpath = hop;
|
|
|
-
|
|
|
- log(LOG_DEBUG,"create_onion() : Building hop %u of crypt path.",i+1);
|
|
|
-
|
|
|
- /* calculate keys */
|
|
|
- crypto_SHA_digest(layer.keyseed,16,hop->digest3);
|
|
|
- log(LOG_DEBUG,"create_onion() : First SHA pass performed.");
|
|
|
- crypto_SHA_digest(hop->digest3,20,hop->digest2);
|
|
|
- log(LOG_DEBUG,"create_onion() : Second SHA pass performed.");
|
|
|
- crypto_SHA_digest(hop->digest2,20,hop->digest3);
|
|
|
- log(LOG_DEBUG,"create_onion() : Third SHA pass performed.");
|
|
|
- log(LOG_DEBUG,"create_onion() : Keys generated.");
|
|
|
- /* set IV to zero */
|
|
|
- memset((void *)iv,0,16);
|
|
|
-
|
|
|
- /* initialize cipher engines */
|
|
|
- if (! (hop->f_crypto =
|
|
|
- crypto_create_init_cipher(DEFAULT_CIPHER, hop->digest3, iv, 1))) {
|
|
|
- /* cipher initialization failed */
|
|
|
- log(LOG_ERR,"Could not create a crypto environment.");
|
|
|
- goto error;
|
|
|
+ hop->state = CPATH_STATE_CLOSED;
|
|
|
+ if(cpath) {
|
|
|
+ cpath->prev = hop;
|
|
|
}
|
|
|
+ cpath = hop;
|
|
|
|
|
|
- if (! (hop->b_crypto =
|
|
|
- crypto_create_init_cipher(DEFAULT_CIPHER, hop->digest2, iv, 0))) {
|
|
|
- /* cipher initialization failed */
|
|
|
- log(LOG_ERR,"Could not create a crypto environment.");
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- log(LOG_DEBUG,"create_onion() : Built corresponding crypt path hop.");
|
|
|
-
|
|
|
- /* padding if this is the innermost layer */
|
|
|
- if (!i) {
|
|
|
- if (crypto_pseudo_rand(ONION_PADDING_SIZE, layerp + ONION_LAYER_SIZE)) { /* error */
|
|
|
- log(LOG_ERR,"Error generating pseudo-random data.");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- log(LOG_DEBUG,"create_onion() : This is the innermost layer. Adding 100 bytes of padding.");
|
|
|
- }
|
|
|
-
|
|
|
- /* encrypt */
|
|
|
-
|
|
|
- if(encrypt_onion(layerp,ONION_PADDING_SIZE+(i+1)*ONION_LAYER_SIZE,router->pkey,layer.keyseed) < 0) {
|
|
|
- log(LOG_ERR,"Error encrypting onion layer.");
|
|
|
- goto error;
|
|
|
+#if 0
|
|
|
+ if (i) { /* not last hop. (last hop has 0's for these.) */
|
|
|
+ hop->port = rarray[route[i-1]]->or_port;
|
|
|
+ hop->addr = rarray[route[i-1]]->addr;
|
|
|
}
|
|
|
- log(LOG_DEBUG,"create_onion() : Encrypted layer.");
|
|
|
+#endif
|
|
|
+ hop->port = rarray[route[i]]->or_port;
|
|
|
+ hop->addr = rarray[route[i]]->addr;
|
|
|
|
|
|
- /* calculate pointer to next layer */
|
|
|
- layerp = buf + (routelen-i-2)*ONION_LAYER_SIZE;
|
|
|
+ log(LOG_DEBUG,"onion_generate_cpath() : Building hop %u of crypt path.",i+1);
|
|
|
}
|
|
|
|
|
|
/* now link cpath->prev to the end of cpath */
|
|
|
- for(hop=*cpath; hop->next; hop=hop->next) ;
|
|
|
- hop->next = *cpath;
|
|
|
- (*cpath)->prev = hop;
|
|
|
-
|
|
|
- return buf;
|
|
|
-
|
|
|
- error:
|
|
|
- if(buf)
|
|
|
- free(buf);
|
|
|
- circuit_free_cpath(*cpath);
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/* encrypts 128 bytes of the onion with the specified public key, the rest with
|
|
|
- * DES OFB with the key as defined in the outter layer */
|
|
|
-int encrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *pkey, char* keyseed) {
|
|
|
- unsigned char *tmpbuf = NULL; /* temporary buffer for crypto operations */
|
|
|
- unsigned char digest[20]; /* stores SHA1 output - 160 bits */
|
|
|
- unsigned char iv[8];
|
|
|
-
|
|
|
- crypto_cipher_env_t *crypt_env = NULL; /* crypto environment */
|
|
|
-
|
|
|
- assert(onion && pkey);
|
|
|
- assert(onionlen >= 128);
|
|
|
-
|
|
|
- memset(iv,0,8);
|
|
|
-
|
|
|
-// log(LOG_DEBUG,"Onion layer : %u, %u, %u, %s, %u.",onion->zero,onion->backf,onion->forwf,inet_ntoa(*((struct in_addr *)&onion->addr)),onion->port);
|
|
|
- /* allocate space for tmpbuf */
|
|
|
- tmpbuf = (unsigned char *)malloc(onionlen);
|
|
|
- if(!tmpbuf) {
|
|
|
- log(LOG_ERR,"Could not allocate memory.");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- log(LOG_DEBUG,"encrypt_onion() : allocated %u bytes of memory for the encrypted onion (at %u).",onionlen,tmpbuf);
|
|
|
-
|
|
|
- /* get key1 = SHA1(KeySeed) */
|
|
|
- if (crypto_SHA_digest(keyseed,16,digest)) {
|
|
|
- log(LOG_ERR,"Error computing SHA1 digest.");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- log(LOG_DEBUG,"encrypt_onion() : Computed DES key.");
|
|
|
-
|
|
|
- log(LOG_DEBUG,"encrypt_onion() : Trying to RSA encrypt.");
|
|
|
- /* encrypt 128 bytes with RSA *pkey */
|
|
|
- if (crypto_pk_public_encrypt(pkey, onion, 128, tmpbuf, RSA_NO_PADDING) == -1) {
|
|
|
- log(LOG_ERR,"Error RSA-encrypting data :%s",crypto_perror());
|
|
|
- goto error;
|
|
|
- }
|
|
|
+ for(hop=cpath; hop->next; hop=hop->next) ;
|
|
|
+ hop->next = cpath;
|
|
|
+ cpath->prev = hop;
|
|
|
|
|
|
- log(LOG_DEBUG,"encrypt_onion() : RSA encrypted first 128 bytes of the onion.");
|
|
|
-
|
|
|
- /* now encrypt the rest with 3DES OFB */
|
|
|
- crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, digest, iv, 1);
|
|
|
- if (!crypt_env) {
|
|
|
- log(LOG_ERR,"Error creating the crypto environment.");
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- if (crypto_cipher_encrypt(crypt_env,onion+128, onionlen-128, (unsigned char *)tmpbuf+128)) { /* error */
|
|
|
- log(LOG_ERR,"Error performing DES encryption:%s",crypto_perror());
|
|
|
- goto error;
|
|
|
- }
|
|
|
- log(LOG_DEBUG,"encrypt_onion() : 3DES OFB encrypted the rest of the onion.");
|
|
|
-
|
|
|
- /* now copy tmpbuf to onion */
|
|
|
- memcpy(onion,tmpbuf,onionlen);
|
|
|
- log(LOG_DEBUG,"encrypt_onion() : Copied cipher to original onion buffer.");
|
|
|
- free(tmpbuf);
|
|
|
- crypto_free_cipher_env(crypt_env);
|
|
|
- return 0;
|
|
|
-
|
|
|
- error:
|
|
|
- if (tmpbuf)
|
|
|
- free(tmpbuf);
|
|
|
- if (crypt_env)
|
|
|
- crypto_free_cipher_env(crypt_env);
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-/* decrypts the first 128 bytes using RSA and prkey, decrypts the rest with DES OFB with key1 */
|
|
|
-int decrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *prkey, onion_layer_t *layer) {
|
|
|
- void *tmpbuf = NULL; /* temporary buffer for crypto operations */
|
|
|
- unsigned char digest[20]; /* stores SHA1 output - 160 bits */
|
|
|
- unsigned char iv[8];
|
|
|
-
|
|
|
- crypto_cipher_env_t *crypt_env =NULL; /* crypto environment */
|
|
|
-
|
|
|
- assert(onion && prkey);
|
|
|
-
|
|
|
- memset(iv,0,8);
|
|
|
-
|
|
|
- /* allocate space for tmpbuf */
|
|
|
- tmpbuf = malloc(onionlen);
|
|
|
- if (!tmpbuf) {
|
|
|
- log(LOG_ERR,"Could not allocate memory.");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- log(LOG_DEBUG,"decrypt_onion() : Allocated memory for the temporary buffer.");
|
|
|
-
|
|
|
- /* decrypt 128 bytes with RSA *prkey */
|
|
|
- if (crypto_pk_private_decrypt(prkey, onion, 128, tmpbuf, RSA_NO_PADDING) == -1)
|
|
|
- {
|
|
|
- log(LOG_ERR,"Error RSA-decrypting data :%s",crypto_perror());
|
|
|
- goto error;
|
|
|
- }
|
|
|
- log(LOG_DEBUG,"decrypt_onion() : RSA decryption complete.");
|
|
|
-
|
|
|
- onion_unpack(layer, tmpbuf);
|
|
|
-
|
|
|
- /* get key1 = SHA1(KeySeed) */
|
|
|
- if (crypto_SHA_digest(layer->keyseed,16,digest)) {
|
|
|
- log(LOG_ERR,"Error computing SHA1 digest.");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- log(LOG_DEBUG,"decrypt_onion() : Computed DES key.");
|
|
|
-
|
|
|
- /* now decrypt the rest with 3DES OFB */
|
|
|
- crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_3DES, digest, iv, 0);
|
|
|
- if (!crypt_env) {
|
|
|
- log(LOG_ERR,"Error creating crypto environment");
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- if (crypto_cipher_decrypt(crypt_env,onion+128, onionlen-128,tmpbuf+128)) {
|
|
|
- log(LOG_ERR,"Error performing DES decryption:%s",crypto_perror());
|
|
|
- goto error;
|
|
|
- }
|
|
|
-
|
|
|
- log(LOG_DEBUG,"decrypt_onion() : DES decryption complete.");
|
|
|
-
|
|
|
- /* now copy tmpbuf to onion */
|
|
|
- memcpy(onion,tmpbuf,onionlen);
|
|
|
- free(tmpbuf);
|
|
|
- crypto_free_cipher_env(crypt_env);
|
|
|
- return 0;
|
|
|
-
|
|
|
- error:
|
|
|
- if (tmpbuf)
|
|
|
- free(tmpbuf);
|
|
|
- if (crypt_env)
|
|
|
- crypto_free_cipher_env(crypt_env);
|
|
|
- return -1;
|
|
|
-}
|
|
|
-
|
|
|
-/* delete first n bytes of the onion and pads the end with n bytes of random data */
|
|
|
-void pad_onion(unsigned char *onion, uint32_t onionlen, int n)
|
|
|
-{
|
|
|
- assert(onion);
|
|
|
-
|
|
|
- memmove(onion,onion+n,onionlen-n);
|
|
|
- crypto_pseudo_rand(n, onion+onionlen-n);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-/* red black tree using Niels' tree.h. I used
|
|
|
-http://www.openbsd.org/cgi-bin/cvsweb/src/regress/sys/sys/tree/rb/
|
|
|
-as my guide */
|
|
|
-
|
|
|
-#include "tree.h"
|
|
|
-
|
|
|
-struct tracked_onion {
|
|
|
- RB_ENTRY(tracked_onion) node;
|
|
|
- uint32_t expire;
|
|
|
- char digest[20]; /* SHA digest of the onion */
|
|
|
- struct tracked_onion *next;
|
|
|
-};
|
|
|
-
|
|
|
-RB_HEAD(tracked_tree, tracked_onion) tracked_root;
|
|
|
-
|
|
|
-int compare_tracked_onions(struct tracked_onion *a, struct tracked_onion *b) {
|
|
|
- return memcmp(a->digest, b->digest, 20);
|
|
|
-}
|
|
|
-
|
|
|
-RB_PROTOTYPE(tracked_tree, tracked_onion, node, compare_tracked_onions)
|
|
|
-RB_GENERATE(tracked_tree, tracked_onion, node, compare_tracked_onions)
|
|
|
-
|
|
|
-void init_tracked_tree(void) {
|
|
|
- RB_INIT(&tracked_root);
|
|
|
-}
|
|
|
-
|
|
|
-/* see if this onion has been seen before. if so, return 1, else
|
|
|
- * return 0 and add the sha1 of this onion to the tree.
|
|
|
- */
|
|
|
-static int find_tracked_onion(unsigned char *onion, uint32_t onionlen,
|
|
|
- int expire) {
|
|
|
- static struct tracked_onion *head_tracked_onions = NULL; /* linked list of tracked onions */
|
|
|
- static struct tracked_onion *tail_tracked_onions = NULL;
|
|
|
-
|
|
|
- uint32_t now = time(NULL);
|
|
|
- struct tracked_onion *to;
|
|
|
-
|
|
|
- /* first take this opportunity to see if there are any expired
|
|
|
- * onions in the tree. we know this is fast because the linked list
|
|
|
- * 'tracked_onions' is ordered by when they were seen.
|
|
|
- */
|
|
|
- while(head_tracked_onions && (head_tracked_onions->expire < now)) {
|
|
|
- to = head_tracked_onions;
|
|
|
- log(LOG_DEBUG,"find_tracked_onion(): Forgetting old onion (expires %d)", to->expire);
|
|
|
- head_tracked_onions = to->next;
|
|
|
- if(!head_tracked_onions) /* if there are no more, */
|
|
|
- tail_tracked_onions = NULL; /* then make sure the list's tail knows that too */
|
|
|
- RB_REMOVE(tracked_tree, &tracked_root, to);
|
|
|
- free(to);
|
|
|
- }
|
|
|
-
|
|
|
- to = malloc(sizeof(struct tracked_onion));
|
|
|
-
|
|
|
- /* compute the SHA digest of the onion */
|
|
|
- crypto_SHA_digest(onion, onionlen, to->digest);
|
|
|
-
|
|
|
- /* try adding it to the tree. if it's already there it will return it. */
|
|
|
- if(RB_INSERT(tracked_tree, &tracked_root, to)) {
|
|
|
- /* yes, it's already there: this is a replay. */
|
|
|
- free(to);
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- /* this is a new onion. add it to the list. */
|
|
|
-
|
|
|
- to->expire = expire; /* set the expiration date */
|
|
|
- to->next = NULL;
|
|
|
-
|
|
|
- if (!head_tracked_onions) {
|
|
|
- head_tracked_onions = to;
|
|
|
- } else {
|
|
|
- tail_tracked_onions->next = to;
|
|
|
- }
|
|
|
- tail_tracked_onions = to;
|
|
|
-
|
|
|
- log(LOG_DEBUG,"find_tracked_onion(): Remembered new onion (expires %d)", to->expire);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-onion_pack(char *dest, onion_layer_t *src)
|
|
|
-{
|
|
|
- assert((src->version & 0x80) == 0);
|
|
|
-
|
|
|
- *(uint8_t*)(dest) = src->version;
|
|
|
- *(uint16_t*)(dest+1) = htons(src->port);
|
|
|
- *(uint32_t*)(dest+3) = htonl(src->addr);
|
|
|
- *(uint32_t*)(dest+7) = htonl(src->expire);
|
|
|
- memcpy(dest+11, src->keyseed, ONION_KEYSEED_LEN);
|
|
|
- log(LOG_DEBUG,"onion_pack(): version %d, port %d, addr %s, expire %u", src->version, src->port,
|
|
|
- inet_ntoa(*((struct in_addr *)(dest+3))), src->expire);
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-onion_unpack(onion_layer_t *dest, char *src)
|
|
|
-{
|
|
|
- dest->version = *(uint8_t*)src;
|
|
|
- dest->port = ntohs(*(uint16_t*)(src+1));
|
|
|
- dest->addr = ntohl(*(uint32_t*)(src+3));
|
|
|
- dest->expire = ntohl(*(uint32_t*)(src+7));
|
|
|
- memcpy(dest->keyseed, src+11, ONION_KEYSEED_LEN);
|
|
|
-
|
|
|
- log(LOG_DEBUG,"onion_unpack(): version %d, port %d, addr %s, expire %u", dest->version, dest->port,
|
|
|
- inet_ntoa(*((struct in_addr *)(src+3))), dest->expire);
|
|
|
+ free(route);
|
|
|
+ return cpath;
|
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
@@ -843,7 +434,7 @@ onion_unpack(onion_layer_t *dest, char *src)
|
|
|
* and the last 80 are encrypted with the symmetric key.
|
|
|
*/
|
|
|
int
|
|
|
-onion_skin_create(crypto_pk_env_t *router_key,
|
|
|
+onion_skin_create(crypto_pk_env_t *dest_router_key,
|
|
|
crypto_dh_env_t **handshake_state_out,
|
|
|
char *onion_skin_out) /* Must be 208 bytes long */
|
|
|
{
|
|
@@ -861,7 +452,7 @@ onion_skin_create(crypto_pk_env_t *router_key,
|
|
|
goto err;
|
|
|
|
|
|
dhbytes = crypto_dh_get_bytes(dh);
|
|
|
- pkbytes = crypto_pk_keysize(router_key);
|
|
|
+ pkbytes = crypto_pk_keysize(dest_router_key);
|
|
|
assert(dhbytes+16 == 208);
|
|
|
if (!(pubkey = malloc(dhbytes+16)))
|
|
|
goto err;
|
|
@@ -896,7 +487,7 @@ onion_skin_create(crypto_pk_env_t *router_key,
|
|
|
if (!cipher)
|
|
|
goto err;
|
|
|
|
|
|
- if (crypto_pk_public_encrypt(router_key, pubkey, pkbytes,
|
|
|
+ if (crypto_pk_public_encrypt(dest_router_key, pubkey, pkbytes,
|
|
|
onion_skin_out, RSA_NO_PADDING)==-1)
|
|
|
goto err;
|
|
|
|