[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r16330: Add replay protection for v3 INTRODUCE2 cells using timestam (in tor/branches/121-hs-authorization: doc/spec src/or)
Author: kloesing
Date: 2008-08-01 11:43:35 -0400 (Fri, 01 Aug 2008)
New Revision: 16330
Modified:
tor/branches/121-hs-authorization/doc/spec/rend-spec.txt
tor/branches/121-hs-authorization/src/or/or.h
tor/branches/121-hs-authorization/src/or/rendclient.c
tor/branches/121-hs-authorization/src/or/rendservice.c
Log:
Add replay protection for v3 INTRODUCE2 cells using timestamp and first part of DH handshake.
Modified: tor/branches/121-hs-authorization/doc/spec/rend-spec.txt
===================================================================
--- tor/branches/121-hs-authorization/doc/spec/rend-spec.txt 2008-08-01 14:14:00 UTC (rev 16329)
+++ tor/branches/121-hs-authorization/doc/spec/rend-spec.txt 2008-08-01 15:43:35 UTC (rev 16330)
@@ -608,6 +608,7 @@
AUTHT The auth type that is supported [1 octet]
AUTHL Length of auth data [2 octets]
AUTHD Auth data [variable]
+ TS Timestamp (sec. since 1-1-1970) [4 octets]
IP Rendezvous point's address [4 octets]
PORT Rendezvous point's OR port [2 octets]
ID Rendezvous point identity ID [20 octets]
Modified: tor/branches/121-hs-authorization/src/or/or.h
===================================================================
--- tor/branches/121-hs-authorization/src/or/or.h 2008-08-01 14:14:00 UTC (rev 16329)
+++ tor/branches/121-hs-authorization/src/or/or.h 2008-08-01 15:43:35 UTC (rev 16330)
@@ -3807,7 +3807,6 @@
char *client_name;
char descriptor_cookie[REND_DESC_COOKIE_LEN];
crypto_pk_env_t *client_key;
- smartlist_t *access_history;
} rend_authorized_client_t;
/** Client-side configuration of authorization for a hidden service. */
Modified: tor/branches/121-hs-authorization/src/or/rendclient.c
===================================================================
--- tor/branches/121-hs-authorization/src/or/rendclient.c 2008-08-01 14:14:00 UTC (rev 16329)
+++ tor/branches/121-hs-authorization/src/or/rendclient.c 2008-08-01 15:43:35 UTC (rev 16330)
@@ -117,7 +117,7 @@
}
}
- /* if version is 3, possibly write authentication data */
+ /* if version is 3, write authentication data and timestamp. */
if (entry->parsed->protocols & (1<<3)) {
tmp[0] = 3; /* version 3 of the cell format */
auth_shift = 1;
@@ -126,7 +126,11 @@
set_uint16(tmp+2, htons(REND_DESC_COOKIE_LEN));
memcpy(tmp+4, introcirc->rend_desc_cookie, REND_DESC_COOKIE_LEN);
auth_shift += 2+REND_DESC_COOKIE_LEN;
+ } else {
+ tmp[1] = 0;
}
+ set_uint32(tmp+auth_shift+1, htonl(time(NULL)));
+ auth_shift += 4;
} /* if version 2 only write version number */
else if (entry->parsed->protocols & (1<<2)) {
tmp[0] = 2; /* version 2 of the cell format */
Modified: tor/branches/121-hs-authorization/src/or/rendservice.c
===================================================================
--- tor/branches/121-hs-authorization/src/or/rendservice.c 2008-08-01 14:14:00 UTC (rev 16329)
+++ tor/branches/121-hs-authorization/src/or/rendservice.c 2008-08-01 15:43:35 UTC (rev 16330)
@@ -68,12 +68,14 @@
* published. */
smartlist_t *clients; /**< List of rend_authorized_client_t's for
* clients that may access our service. */
+ smartlist_t *accepted_intros; /**< List of client_access_event_t's for
+ * accepted and answered INTRODUCE2 cells. */
} rend_service_t;
/** The event of a client accessing our hidden service. */
typedef struct client_access_event_t {
time_t access_time;
- char rendezvous_cookie[DIGEST_LEN];
+ char diffie_hellman_hash[DIGEST_LEN];
} client_access_event_t;
/** A list of rend_service_t's for services run on this OP.
@@ -95,11 +97,6 @@
{
rend_authorized_client_t *client = authorized_client;
if (!authorized_client) return;
- if (client->access_history) {
- SMARTLIST_FOREACH(client->access_history,
- client_access_event_t *, ev, tor_free(ev););
- smartlist_free(client->access_history);
- }
if (client->client_key)
crypto_free_pk_env(client->client_key);
tor_free(client->client_name);
@@ -672,21 +669,14 @@
}
/** Check client authorization of a given <b>descriptor_cookie</b> for
- * <b>service</b>, use <b>rendezvous_cookie</b> to detect replays or
- * denial of service attacks, and add this request to the access history.
- * Return 1 for success and 0 for failure. */
+ * <b>service</b>. Return 1 for success and 0 for failure. */
static int
rend_check_authorization(rend_service_t *service,
- const char *descriptor_cookie,
- const char *rendezvous_cookie)
+ const char *descriptor_cookie)
{
rend_authorized_client_t *auth_client = NULL;
- client_access_event_t *event;
- time_t now = time(NULL);
- int num_same_rend_cookie = -1;
tor_assert(service);
tor_assert(descriptor_cookie);
- tor_assert(rendezvous_cookie);
if (!service->clients) {
log_warn(LD_BUG, "Can't check authorization for a service that is not "
"configured to perform such.");
@@ -713,49 +703,8 @@
return 0;
}
- /* Add request to access history, including time and rendezvous cookie. */
- event = tor_malloc_zero(sizeof(client_access_event_t));
- event->access_time = now;
- memcpy(event->rendezvous_cookie, rendezvous_cookie, DIGEST_LEN);
- if (!auth_client->access_history)
- auth_client->access_history = smartlist_create();
- smartlist_add(auth_client->access_history, event);
-
- /* Iterate over past requests, remove those which are older than one
- * hour, and count the number of requests with same rendezvous cookie. */
- SMARTLIST_FOREACH(auth_client->access_history, client_access_event_t *,
- access, {
- if (access->access_time + 60 * 60 < now) {
- tor_free(access);
- SMARTLIST_DEL_CURRENT(auth_client->access_history, access);
- } else if (!memcmp(access->rendezvous_cookie, rendezvous_cookie,
- DIGEST_LEN)) {
- num_same_rend_cookie++;
- }
- });
-
- /* If the total number of requests (including this request) within the
- * last hour exceeds 10, drop this request. */
- if (smartlist_len(auth_client->access_history) > 10) {
- log_warn(LD_REND, "Client '%s' has exceeded the maximum number of %d "
- "requests per hour for service '%s'. Is this an attack? "
- "Access denied!",
- auth_client->client_name, 10, service->service_id);
- return 0;
- }
-
- /* If the number of requests with the same rendezvous cookie (including
- * this request) exceeds 3 , drop this request. */
- if (num_same_rend_cookie >= 3) {
- log_warn(LD_REND, "Client '%s' has exceeded the maximum number of %d "
- "requests using the same rendezvous cookie for service '%s'. "
- "Is this an attack? Access denied!",
- auth_client->client_name, 3, service->service_id);
- return 0;
- }
-
/* Allow the request. */
- log_warn(LD_REND, "Client %s could be identified for service %s.",
+ log_info(LD_REND, "Client %s could be identified for service %s.",
auth_client->client_name, service->service_id);
return 1;
}
@@ -776,7 +725,7 @@
char buf[RELAY_PAYLOAD_SIZE];
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; /* Holds KH, Df, Db, Kf, Kb */
rend_service_t *service;
- int r, i, auth_shift = 0;
+ int r, i, auth_shift = 0, ts_shift = 0;
size_t len, keylen;
crypto_dh_env_t *dh = NULL;
origin_circuit_t *launched = NULL;
@@ -790,6 +739,10 @@
int auth_type;
size_t auth_len;
char *auth_data = NULL;
+ crypto_digest_env_t *digest = NULL;
+ time_t now = time(NULL);
+ char diffie_hellman_hash[DIGEST_LEN];
+ client_access_event_t *event = NULL;
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
circuit->rend_pk_digest, REND_SERVICE_ID_LEN);
@@ -855,6 +808,7 @@
len = r;
if (*buf == 3) {
/* Version 3 INTRODUCE2 cell. */
+ time_t ts = 0, now = time(NULL);
auth_shift = 1;
auth_type = buf[1];
if (auth_type == 1) {
@@ -866,29 +820,41 @@
}
auth_data = tor_malloc_zero(REND_DESC_COOKIE_LEN);
memcpy(auth_data, buf+4, REND_DESC_COOKIE_LEN);
- auth_shift += 18;
+ auth_shift += 2+REND_DESC_COOKIE_LEN;
}
+
+ /* Check timestamp. */
+ memcpy((char*)&ts, buf+1+auth_shift, sizeof(uint32_t));
+ ts_shift = 4;
+ ts = ntohl(ts);
+ if ((now - ts) < -30 * 60 || (now - ts) > 30 * 60) {
+ log_warn(LD_REND, "INTRODUCE2 cell is too %s. Discarding.",
+ (now - ts) < 0 ? "old" : "new");
+ return -1;
+ }
}
if (*buf == 2 || *buf == 3) {
/* Version 2 INTRODUCE2 cell. */
int klen;
extend_info = tor_malloc_zero(sizeof(extend_info_t));
- extend_info->addr = ntohl(get_uint32(buf+auth_shift+1));
- extend_info->port = ntohs(get_uint16(buf+auth_shift+5));
- memcpy(extend_info->identity_digest, buf+auth_shift+7, DIGEST_LEN);
+ extend_info->addr = ntohl(get_uint32(buf+auth_shift+ts_shift+1));
+ extend_info->port = ntohs(get_uint16(buf+auth_shift+ts_shift+5));
+ memcpy(extend_info->identity_digest, buf+auth_shift+ts_shift+7,
+ DIGEST_LEN);
extend_info->nickname[0] = '$';
base16_encode(extend_info->nickname+1, sizeof(extend_info->nickname)-1,
extend_info->identity_digest, DIGEST_LEN);
- klen = ntohs(get_uint16(buf+auth_shift+7+DIGEST_LEN));
- if ((int)len != auth_shift+7+DIGEST_LEN+2+klen+20+128) {
+ klen = ntohs(get_uint16(buf+auth_shift+ts_shift+7+DIGEST_LEN));
+ if ((int)len != auth_shift+ts_shift+7+DIGEST_LEN+2+klen+20+128) {
log_warn(LD_PROTOCOL, "Bad length %u for version %d INTRODUCE2 cell.",
(int)len, *buf);
reason = END_CIRC_REASON_TORPROTOCOL;
goto err;
}
extend_info->onion_key =
- crypto_pk_asn1_decode(buf+auth_shift+7+DIGEST_LEN+2, klen);
+ crypto_pk_asn1_decode(buf+auth_shift+ts_shift+7+DIGEST_LEN+2,
+ klen);
if (!extend_info->onion_key) {
log_warn(LD_PROTOCOL,
"Error decoding onion key in version %d INTRODUCE2 cell.",
@@ -896,8 +862,8 @@
reason = END_CIRC_REASON_TORPROTOCOL;
goto err;
}
- ptr = buf+auth_shift+7+DIGEST_LEN+2+klen;
- len -= auth_shift+7+DIGEST_LEN+2+klen;
+ ptr = buf+auth_shift+ts_shift+7+DIGEST_LEN+2+klen;
+ len -= auth_shift+ts_shift+7+DIGEST_LEN+2+klen;
} else {
char *rp_nickname;
size_t nickname_field_len;
@@ -949,16 +915,56 @@
r_cookie = ptr;
base16_encode(hexcookie,9,r_cookie,4);
- /* If the cell contains authentication data, check authorization. */
- if (auth_data) {
- if (service->clients) {
- if (!rend_check_authorization(service, auth_data, r_cookie)) {
+ /* Determine hash of Diffie-Hellman, part 1 to detect replays. */
+ digest = crypto_new_digest_env();
+ crypto_digest_add_bytes(digest, ptr+REND_COOKIE_LEN, DH_KEY_LEN);
+ crypto_digest_get_digest(digest, diffie_hellman_hash, DIGEST_LEN);
+ crypto_free_digest_env(digest);
+
+ /* Iterate over past requests, remove those which are older than one
+ * hour, and check check whether there is one with same Diffie-Hellman,
+ * part 1. */
+ if (!service->accepted_intros)
+ service->accepted_intros = smartlist_create();
+ SMARTLIST_FOREACH(service->accepted_intros, client_access_event_t *,
+ access, {
+ if (access->access_time + 60 * 60 < now) {
+ tor_free(access);
+ SMARTLIST_DEL_CURRENT(service->accepted_intros, access);
+ } else if (!memcmp(access->diffie_hellman_hash, diffie_hellman_hash,
+ DIGEST_LEN)) {
+ log_warn(LD_REND, "Possible replay detected! We received an "
+ "INTRODUCE2 cell with same first part of Diffie-Hellman "
+ "handshake %d seconds ago. Dropping cell.",
+ (uint32_t) (now - access->access_time));
+ return 0;
+ }
+ });
+
+ /* Add request to access history, including time and hash of
+ * Diffie-Hellman, part 1. */
+ event = tor_malloc_zero(sizeof(client_access_event_t));
+ event->access_time = now;
+ memcpy(event->diffie_hellman_hash, diffie_hellman_hash, DIGEST_LEN);
+ smartlist_add(service->accepted_intros, event);
+
+ /* If the service performs client authorization, check included auth data. */
+ if (service->clients) {
+ if (auth_data) {
+ if (rend_check_authorization(service, auth_data)) {
+ log_info(LD_REND, "Authorization data in INTRODUCE2 cell are valid.");
+ } else {
+ log_info(LD_REND, "The authorization data that are contained in "
+ "the INTRODUCE2 cell are invalid. Dropping cell.");
reason = END_CIRC_REASON_CONNECTFAILED;
goto err;
}
- } else
- log_info(LD_PROTOCOL, "INTRODUCE2 cell contains authentication data, "
- "but we don't perform access control. Ignoring.");
+ } else {
+ log_info(LD_REND, "INTRODUCE2 cell does not contain authentication "
+ "data, but we require client authorization. Dropping cell.");
+ reason = END_CIRC_REASON_CONNECTFAILED;
+ goto err;
+ }
}
/* Try DH handshake... */