return;
}
-/* go through ol_list, find the element which points to circ, remove and
- * free that element. leave circ itself alone.
+/* go through ol_list, find the onion_queue_t element which points to
+ * circ, remove and free that element. leave circ itself alone.
*/
void onion_pending_remove(circuit_t *circ) {
struct onion_queue_t *tmpo, *victim;
log(LOG_DEBUG,"onion_deliver_to_conn(): Setting onion length to %u.",onionlen);
*(uint32_t*)buf = htonl(onionlen);
- memcpy((void *)(buf+4),(void *)onion,onionlen);
+ memcpy((buf+4),onion,onionlen);
dataleft = buflen;
while(dataleft > 0) {
if(learn_my_address(&me) < 0)
return -1;
- if(!decrypt_onion((onion_layer_t *)circ->onion,circ->onionlen,getprivatekey())) {
+ /* decrypt it in-place */
+ if(decrypt_onion(circ->onion,circ->onionlen,getprivatekey()) < 0) {
log(LOG_DEBUG,"command_process_create_cell(): decrypt_onion() failed, closing circuit.");
return -1;
}
log(LOG_DEBUG,"command_process_create_cell(): Onion decrypted.");
/* check freshness */
- if (((onion_layer_t *)circ->onion)->expire < time(NULL)) /* expired onion */
+ if (ntohl(*(uint32_t *)(circ->onion+8)) < (uint32_t)time(NULL)) /* expired onion */
{
log(LOG_NOTICE,"I have just received an expired onion. This could be a replay attack.");
return -1;
}
aci_type = decide_aci_type(ntohl(me.sin_addr.s_addr), ntohs(me.sin_port),
- ((onion_layer_t *)circ->onion)->addr,((onion_layer_t *)circ->onion)->port);
+ ntohl(*(uint32_t *)(circ->onion+4)),ntohs(*(uint16_t *)(circ->onion+2)));
if(circuit_init(circ, aci_type) < 0) {
log(LOG_ERR,"process_onion(): init_circuit() failed.");
}
/* check for replay */
- if(id_tracked_onion(circ->onion, circ->onionlen, tracked_onions)) {
+ if(find_tracked_onion(circ->onion, circ->onionlen, tracked_onions)) {
log(LOG_NOTICE,"process_onion(): I have just received a replayed onion. This could be a replay attack.");
return -1;
}
/* track the new onion */
- if(!new_tracked_onion(circ->onion,circ->onionlen, &tracked_onions, &last_tracked_onion)) {
+ if(add_tracked_onion(circ->onion,circ->onionlen, &tracked_onions, &last_tracked_onion) < 0) {
log(LOG_DEBUG,"process_onion(): Onion tracking failed. Will ignore.");
}
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, sizeof(onion_layer_t));
+ 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((void *)circ->onion);
+ 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.");
cipher_type = CRYPTO_CIPHER_DES;
break;
case ONION_CIPHER_RC4 :
- cipher_type = ONION_CIPHER_RC4;
+ cipher_type = CRYPTO_CIPHER_RC4;
break;
case ONION_CIPHER_IDENTITY :
cipher_type = CRYPTO_CIPHER_IDENTITY;
unsigned char *create_onion(routerinfo_t **rarray, int rarray_len, unsigned int *route, int routelen, int *len, crypt_path_t **cpath)
{
int i,j;
- onion_layer_t *layer = NULL;
+ char *layer;
crypt_path_t *hop = NULL;
unsigned char *buf;
routerinfo_t *router;
assert(rarray && route && len && routelen);
/* calculate the size of the onion */
- *len = routelen * 28 + 100; /* 28 bytes per layer + 100 bytes padding for the innermost layer */
+ *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);
/* allocate memory for the onion */
- buf = (unsigned char *)malloc(*len);
- if (!buf) {
+ buf = malloc(*len);
+ if(!buf) {
log(LOG_ERR,"Error allocating memory.");
return NULL;
}
log(LOG_DEBUG,"create_onion() : Allocated memory for the onion.");
- for (i=0; i<routelen;i++) {
+ 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,
crypto_pk_keysize((rarray[route[i]])->pkey));
}
- layer = (onion_layer_t *)(buf + *len - 128); /* pointer to innermost layer */
+ layer = buf + *len - ONION_LAYER_SIZE - ONION_PADDING_SIZE; /* pointer to innermost layer */
/* create the onion layer by layer, starting with the innermost */
for (i=0;i<routelen;i++) {
router = rarray[route[i]];
// log(LOG_DEBUG,"create_onion() : Key pointer = %u.",router->pkey);
// log(LOG_DEBUG,"create_onion() : Key size = %u.",crypto_pk_keysize(router->pkey));
- /* 0 bit */
- layer->zero = 0;
- /* version */
- layer->version = OR_VERSION;
+ *layer = OR_VERSION;
/* Back F + Forw F both use DES OFB*/
- layer->backf = ONION_DEFAULT_CIPHER;
- layer->forwf = ONION_DEFAULT_CIPHER;
+ *(layer+1) = (ONION_DEFAULT_CIPHER << 4) /* for backf */ +
+ ONION_DEFAULT_CIPHER; /* for forwf */
+
/* Dest Port */
if (i) /* not last hop */
- layer->port = rarray[route[i-1]]->or_port;
+ *(uint16_t *)(layer+2) = htons(rarray[route[i-1]]->or_port);
else
- layer->port = 0;
+ *(uint16_t *)(layer+2) = htons(0);
+
/* Dest Addr */
if (i) /* not last hop */
- layer->addr = rarray[route[i-1]]->addr;
+ *(uint32_t *)(layer+4) = htonl(rarray[route[i-1]]->addr);
else
- layer->addr = 0;
+ *(uint32_t *)(layer+4) = htonl(0);
+
/* Expiration Time */
- layer->expire = time(NULL) + 86400; /* NOW + 1 day */
+ *(uint32_t *)(layer+8) = htonl((uint32_t)(time(NULL) + 86400)); /* NOW + 1 day */
+
/* Key Seed Material */
- if(crypto_rand(16, layer->keyseed)) { /* error */
+ if(crypto_rand(16, layer+12)) { /* error */
log(LOG_ERR,"Error generating random data.");
goto error;
}
log(LOG_DEBUG,"create_onion() : Building hop %u of crypt path.",i+1);
hop = cpath[i];
/* set crypto functions */
- hop->backf = layer->backf;
- hop->forwf = layer->forwf;
+ hop->backf = *(layer+1) >> 4;
+ hop->forwf = *(layer+1) & 0x0f;
/* calculate keys */
- crypto_SHA_digest(layer->keyseed,16,hop->digest3);
+ crypto_SHA_digest(layer+12,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.");
/* padding if this is the innermost layer */
if (!i) {
- if (crypto_pseudo_rand(100, (unsigned char *)layer + 28)) { /* error */
+ if (crypto_pseudo_rand(ONION_PADDING_SIZE, layer + ONION_LAYER_SIZE)) { /* error */
log(LOG_ERR,"Error generating pseudo-random data.");
goto error;
}
/* encrypt */
- if(! encrypt_onion(layer,128+(i*28),router->pkey)) {
+ if(encrypt_onion(layer,ONION_PADDING_SIZE+(i+1)*ONION_LAYER_SIZE,router->pkey) < 0) {
log(LOG_ERR,"Error encrypting onion layer.");
goto error;
}
log(LOG_DEBUG,"create_onion() : Encrypted layer.");
/* calculate pointer to next layer */
- layer = (onion_layer_t *)(buf + (routelen-i-2)*sizeof(onion_layer_t));
+ layer = buf + (routelen-i-2)*ONION_LAYER_SIZE;
}
return buf;
+
error:
if (buf)
- free((void *)buf);
+ free(buf);
if (cpath) {
for (j=0;j<i;j++) {
if(cpath[i]->f_crypto)
/* 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 */
-unsigned char *encrypt_onion(onion_layer_t *onion, uint32_t onionlen, crypto_pk_env_t *pkey)
-{
+int encrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *pkey) {
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((void *)iv,0,8);
+ 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);
+// 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) {
+ if(!tmpbuf) {
log(LOG_ERR,"Could not allocate memory.");
- return NULL;
+ 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(((onion_layer_t *)onion)->keyseed,16,digest)) {
+ if (crypto_SHA_digest(onion+12,16,digest)) {
log(LOG_ERR,"Error computing SHA1 digest.");
goto error;
}
log(LOG_DEBUG,"encrypt_onion() : Trying to RSA encrypt.");
/* encrypt 128 bytes with RSA *pkey */
- if (crypto_pk_public_encrypt(pkey, (unsigned char *)onion, 128, tmpbuf, RSA_NO_PADDING) == -1) {
+ 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;
}
goto error;
}
- if (crypto_cipher_encrypt(crypt_env,(unsigned char *)onion+128, onionlen-128, (unsigned char *)tmpbuf+128)) { /* 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() : DES OFB encrypted the rest of the onion.");
/* now copy tmpbuf to onion */
- memcpy((void *)onion,(void *)tmpbuf,onionlen);
+ memcpy(onion,tmpbuf,onionlen);
log(LOG_DEBUG,"encrypt_onion() : Copied cipher to original onion buffer.");
- free((void *)tmpbuf);
+ free(tmpbuf);
crypto_free_cipher_env(crypt_env);
- return (unsigned char *)onion;
+ return 0;
error:
if (tmpbuf)
- free((void *)tmpbuf);
+ free(tmpbuf);
if (crypt_env)
crypto_free_cipher_env(crypt_env);
- return NULL;
+ return -1;
}
/* decrypts the first 128 bytes using RSA and prkey, decrypts the rest with DES OFB with key1 */
-unsigned char *decrypt_onion(onion_layer_t *onion, uint32_t onionlen, crypto_pk_env_t *prkey)
-{
+int decrypt_onion(unsigned char *onion, uint32_t onionlen, crypto_pk_env_t *prkey) {
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 */
- if ( (onion) && (prkey) ) { /* valid parameters */
- memset((void *)iv,0,8);
+ assert(onion && prkey);
+
+ memset(iv,0,8);
- /* allocate space for tmpbuf */
- tmpbuf = malloc(onionlen);
- if (!tmpbuf) {
- log(LOG_ERR,"Could not allocate memory.");
- return NULL;
- }
- log(LOG_DEBUG,"decrypt_onion() : Allocated memory for the temporary buffer.");
+ /* 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, (unsigned char*)onion, 128, (unsigned char *)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.");
+ /* 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.");
- /* get key1 = SHA1(KeySeed) */
- if (crypto_SHA_digest(((onion_layer_t *)tmpbuf)->keyseed,16,digest))
- {
- log(LOG_ERR,"Error computing SHA1 digest.");
- goto error;
- }
- log(LOG_DEBUG,"decrypt_onion() : Computed DES key.");
+ /* get key1 = SHA1(KeySeed) */
+ if (crypto_SHA_digest(tmpbuf+12,16,digest)) {
+ log(LOG_ERR,"Error computing SHA1 digest.");
+ goto error;
+ }
+ log(LOG_DEBUG,"decrypt_onion() : Computed DES key.");
- /* now decrypt the rest with DES OFB */
- crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_DES, digest, iv, 0);
- if (!crypt_env) {
- log(LOG_ERR,"Error creating crypto environment");
- goto error;
- }
+ /* now decrypt the rest with DES OFB */
+ crypt_env = crypto_create_init_cipher(CRYPTO_CIPHER_DES, digest, iv, 0);
+ if (!crypt_env) {
+ log(LOG_ERR,"Error creating crypto environment");
+ goto error;
+ }
- if (crypto_cipher_decrypt(crypt_env,(unsigned char *)onion+128, onionlen-128,(unsigned char *)tmpbuf+128)) {
- log(LOG_ERR,"Error performing DES decryption:%s",crypto_perror());
- 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.");
+ log(LOG_DEBUG,"decrypt_onion() : DES decryption complete.");
- /* now copy tmpbuf to onion */
- memcpy((void *)onion,(void *)tmpbuf,onionlen);
- free((void *)tmpbuf);
- crypto_free_cipher_env(crypt_env);
- return (unsigned char *)onion;
- } /* valid parameters */
- else
- return NULL;
+ /* now copy tmpbuf to onion */
+ memcpy(onion,tmpbuf,onionlen);
+ free(tmpbuf);
+ crypto_free_cipher_env(crypt_env);
+ return 0;
error:
if (tmpbuf)
- free((void *)tmpbuf);
+ free(tmpbuf);
if (crypt_env)
crypto_free_cipher_env(crypt_env);
- return NULL;
+ 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)
{
- if (onion) /* valid parameter */
- {
- memmove((void *)onion,(void *)(onion+n),onionlen-n);
- crypto_pseudo_rand(n, onion+onionlen-n);
- }
+ assert(onion);
+
+ memmove(onion,onion+n,onionlen-n);
+ crypto_pseudo_rand(n, onion+onionlen-n);
}
/* create a new tracked_onion entry */
-tracked_onion_t *new_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t **tracked_onions, tracked_onion_t **last_tracked_onion)
+int add_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t **tracked_onions, tracked_onion_t **last_tracked_onion)
{
tracked_onion_t *to = NULL;
- if (!onion || !tracked_onions || !last_tracked_onion) /* invalid parameters */
- return NULL;
+ assert(onion && tracked_onions && last_tracked_onion);
to = (tracked_onion_t *)malloc(sizeof(tracked_onion_t));
if (!to)
- return NULL;
+ return -1;
- to->expire = ((onion_layer_t *)onion)->expire; /* set the expiration date */
+ to->expire = ntohl(*(uint32_t *)(onion+8)); /* set the expiration date */
/* compute the SHA digest */
- if (crypto_SHA_digest(onion, onionlen, to->digest))
- {
- log(LOG_DEBUG,"new_tracked_onion() : Failed to compute a SHA1 digest of the onion.");
- free((void *)to);
- return NULL;
+ if (crypto_SHA_digest(onion, onionlen, to->digest)) {
+ log(LOG_DEBUG,"new_tracked_onion(): Failed to compute a SHA1 digest of the onion.");
+ free(to);
+ return -1;
}
to->next = NULL;
- if (!*tracked_onions)
- {
+ if (!*tracked_onions) {
to->prev = NULL;
*tracked_onions = to;
- }
- else
- {
- to->prev = (void *)*last_tracked_onion;
- (*last_tracked_onion)->next = (void *)to;
+ } else {
+ to->prev = *last_tracked_onion;
+ (*last_tracked_onion)->next = to;
}
*last_tracked_onion = to;
- return to;
+ return 0;
}
/* delete a tracked onion entry */
void remove_tracked_onion(tracked_onion_t *to, tracked_onion_t **tracked_onions, tracked_onion_t **last_tracked_onion)
{
- if (!*tracked_onions || !*last_tracked_onion || !to)
- return;
+ assert(*tracked_onions && *last_tracked_onion && to);
if (to->prev)
((tracked_onion_t *)to->prev)->next = to->next;
if (to == *last_tracked_onion)
*last_tracked_onion = (tracked_onion_t *)to->prev;
- free((void *)to);
+ free(to);
return;
}
/* find a tracked onion in the linked list of tracked onions */
-tracked_onion_t *id_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t *tracked_onions)
+tracked_onion_t *find_tracked_onion(unsigned char *onion, uint32_t onionlen, tracked_onion_t *tracked_onions)
{
tracked_onion_t *to = tracked_onions;
unsigned char digest[20];
/* compute the SHA digest of the onion */
crypto_SHA_digest(onion,onionlen, digest);
- while(to)
- {
- if (!memcmp((void *)digest, (void *)to->digest, 20))
+ while(to) {
+ if(!memcmp(digest, to->digest, 20))
return to;
to = (tracked_onion_t *)to->next;
}
return NULL;
}
+