[or-cvs] infrastructure for integrity-checks in relay cells

Roger Dingledine arma at seul.org
Tue Dec 16 22:56:52 UTC 2003


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/home2/arma/work/onion/cvs/src/or

Modified Files:
	circuit.c connection.c connection_edge.c or.h 
Log Message:
infrastructure for integrity-checks in relay cells
make circuit_consider_sending_sendme use connection_edge_send_command
fix endian bug in relay length handling (maybe)


Index: circuit.c
===================================================================
RCS file: /home/or/cvsroot/src/or/circuit.c,v
retrieving revision 1.120
retrieving revision 1.121
diff -u -d -r1.120 -r1.121
--- circuit.c	16 Dec 2003 20:45:10 -0000	1.120
+++ circuit.c	16 Dec 2003 22:56:49 -0000	1.121
@@ -194,7 +194,7 @@
 }
 
 /* Find the newest circ that conn can use, preferably one which is
- * dirty and not too old.
+ * dirty. Circ must not be too old.
  * If !conn, return newest.
  *
  * If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN.
@@ -303,6 +303,35 @@
   return 0;
 }
 
+/* update digest from the payload of cell. assign integrity part to cell. */
+void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell) {
+  uint32_t integrity;
+
+  crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE);
+  crypto_digest_get_digest(digest, (char *)&integrity, 4);
+  SET_CELL_RELAY_INTEGRITY(*cell, integrity);
+}
+
+/* update digest from the payload of cell (with the integrity part set
+ * to 0). If the integrity part is valid return 0, else return -1.
+ */
+int relay_check_digest(crypto_digest_env_t *digest, cell_t *cell) {
+  uint32_t received_integrity, calculated_integrity;
+
+  received_integrity = CELL_RELAY_INTEGRITY(*cell);
+  SET_CELL_RELAY_INTEGRITY(*cell, 0);
+
+  crypto_digest_add_bytes(digest, cell->payload, CELL_PAYLOAD_SIZE);
+  crypto_digest_get_digest(digest, (char *)&calculated_integrity, 4);
+
+  if(received_integrity != calculated_integrity) {
+    log_fn(LOG_WARN,"Integrity check on cell payload failed. Bug or attack. (%d vs %d).",
+           received_integrity, calculated_integrity);
+    return -1;
+  }
+  return 0;
+}
+
 int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
                                int cell_direction, crypt_path_t *layer_hint) {
   connection_t *conn=NULL;
@@ -321,12 +350,10 @@
 
   if(recognized) {
     if(cell_direction == CELL_DIRECTION_OUT) {
-#if 0
-       if(relay_update_digest(circ->n_digest, cell) < 0) {
+       if(relay_check_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) {
@@ -335,12 +362,10 @@
       }
     }
     if(cell_direction == CELL_DIRECTION_IN) {
-#if 0
-      if(relay_update_digest(layer_hint->p_digest, cell) < 0) {
+      if(relay_check_digest(layer_hint->b_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) {
@@ -545,39 +570,20 @@
   return 1;
 }
 
-int circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
-  cell_t cell;
-
-  assert(circ);
-
-  memset(&cell, 0, sizeof(cell_t));
-  cell.command = CELL_RELAY;
-  SET_CELL_RELAY_COMMAND(cell, RELAY_COMMAND_SENDME);
-  SET_CELL_STREAM_ID(cell, ZERO_STREAM);
-  SET_CELL_RELAY_LENGTH(cell, 0);
-
-  if(edge_type == EDGE_AP) { /* i'm the AP */
-    cell.circ_id = circ->n_circ_id;
-    while(layer_hint->deliver_window < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
-      log_fn(LOG_DEBUG,"deliver_window %d, Queueing sendme forward.", layer_hint->deliver_window);
+void circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint) {
+  while((edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window) <
+         CIRCWINDOW_START - CIRCWINDOW_INCREMENT) {
+    log_fn(LOG_DEBUG,"Queueing circuit sendme.");
+    if(edge_type == EDGE_AP)
       layer_hint->deliver_window += CIRCWINDOW_INCREMENT;
-      if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_OUT, layer_hint) < 0) {
-        log_fn(LOG_WARN,"At AP: circuit_deliver_relay_cell failed.");
-        return -1;
-      }
-    }
-  } else if(edge_type == EDGE_EXIT) { /* i'm the exit */
-    cell.circ_id = circ->p_circ_id;
-    while(circ->deliver_window < CIRCWINDOW_START-CIRCWINDOW_INCREMENT) {
-      log_fn(LOG_DEBUG,"deliver_window %d, Queueing sendme back.", circ->deliver_window);
+    else
       circ->deliver_window += CIRCWINDOW_INCREMENT;
-      if(circuit_deliver_relay_cell(&cell, circ, CELL_DIRECTION_IN, layer_hint) < 0) {
-        log_fn(LOG_WARN,"At exit: circuit_deliver_relay_cell failed.");
-        return -1;
-      }
+    if(connection_edge_send_command(NULL, circ, RELAY_COMMAND_SENDME,
+                                    NULL, 0, layer_hint) < 0) {
+      log_fn(LOG_WARN,"connection_edge_send_command failed. Returning.");
+      return; /* the circuit's closed, don't continue */
     }
   }
-  return 0;
 }
 
 void circuit_close(circuit_t *circ) {
@@ -602,6 +608,8 @@
   if (circ->state == CIRCUIT_STATE_BUILDING ||
       circ->state == CIRCUIT_STATE_OR_WAIT) {
     /* If we never built the circuit, note it as a failure. */
+    /* Note that we can't just check circ->cpath here, because if
+     * circuit-building failed immediately, it won't be set yet. */
     circuit_increment_failure_count();
   }
   circuit_free(circ);

Index: connection.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection.c,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -d -r1.140 -r1.141
--- connection.c	14 Dec 2003 08:32:13 -0000	1.140
+++ connection.c	16 Dec 2003 22:56:50 -0000	1.141
@@ -371,7 +371,7 @@
     if(connection_speaks_cells(conn)) {
       at_most = 30*(CELL_NETWORK_SIZE);
     } else {
-      at_most = 30*(CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE);
+      at_most = 30*(RELAY_PAYLOAD_SIZE);
     }
 
     if(at_most > global_read_bucket)

Index: connection_edge.c
===================================================================
RCS file: /home/or/cvsroot/src/or/connection_edge.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- connection_edge.c	16 Dec 2003 09:48:17 -0000	1.78
+++ connection_edge.c	16 Dec 2003 22:56:50 -0000	1.79
@@ -132,18 +132,18 @@
 
   if(!circ) {
     log_fn(LOG_WARN,"no circ. Closing.");
-    return 0;
+    return -1;
   }
 
   if(!fromconn || relay_command == RELAY_COMMAND_BEGIN) /* XXX more */
     is_control_cell = 1;
 
   memset(&cell, 0, sizeof(cell_t));
-  if(fromconn && fromconn->type == CONN_TYPE_AP) {
+//  if(fromconn && fromconn->type == CONN_TYPE_AP) {
+  if(cpath_layer) {
     cell.circ_id = circ->n_circ_id;
     cell_direction = CELL_DIRECTION_OUT;
   } else {
-    /* NOTE: if !fromconn, we assume that it's heading towards the OP */
     cell.circ_id = circ->p_circ_id;
     cell_direction = CELL_DIRECTION_IN;
   }
@@ -159,6 +159,12 @@
   if(payload_len) {
     memcpy(cell.payload+RELAY_HEADER_SIZE,payload,payload_len);
   }
+
+  if(cell_direction == CELL_DIRECTION_OUT) /* AP */
+    relay_set_digest(cpath_layer->f_digest, &cell);
+  else /* exit */
+    relay_set_digest(circ->p_digest, &cell);
+
   log_fn(LOG_DEBUG,"delivering %d cell %s.", relay_command,
          cell_direction == CELL_DIRECTION_OUT ? "forward" : "backward");
 
@@ -231,11 +237,7 @@
       }
       log_fn(LOG_DEBUG,"circ deliver_window now %d.", edge_type == EDGE_AP ? layer_hint->deliver_window : circ->deliver_window);
 
-      if(circuit_consider_sending_sendme(circ, edge_type, layer_hint) < 0) {
-        log_fn(LOG_WARN,"circuit_consider_sending_sendme() failed.");
-        conn->has_sent_end = 1; /* we failed because conn is broken. can't send end. */
-        return -1;
-      }
+      circuit_consider_sending_sendme(circ, edge_type, layer_hint);
 
       if(!conn) {
         log_fn(LOG_INFO,"relay cell dropped, unknown stream %d.",*(int*)conn->stream_id);
@@ -247,7 +249,6 @@
         return -1; /* somebody's breaking protocol. kill the whole circuit. */
       }
 
-//      printf("New text for buf (%d bytes): '%s'", cell->length - RELAY_HEADER_SIZE, cell->payload + RELAY_HEADER_SIZE);
       stats_n_data_bytes_received += CELL_RELAY_LENGTH(*cell);
       connection_write_to_buf(cell->payload + RELAY_HEADER_SIZE,
                               CELL_RELAY_LENGTH(*cell), conn);
@@ -416,7 +417,7 @@
       /* deliver a 'connected' relay cell back through the circuit. */
       *(uint32_t*)connected_payload = htonl(conn->addr);
       if(connection_edge_send_command(conn, circuit_get_by_conn(conn),
-         RELAY_COMMAND_CONNECTED, NULL, 0, conn->cpath_layer) < 0)
+         RELAY_COMMAND_CONNECTED, NULL, 0, NULL) < 0)
         return 0; /* circuit is closed, don't continue */
       assert(conn->package_window > 0);
       return connection_edge_process_inbuf(conn); /* in case the server has written anything */
@@ -541,10 +542,10 @@
 
 static void connection_edge_consider_sending_sendme(connection_t *conn) {
   circuit_t *circ;
- 
+
   if(connection_outbuf_too_full(conn))
     return;
- 
+
   circ = circuit_get_by_conn(conn);
   if(!circ) {
     /* this can legitimately happen if the destroy has already
@@ -552,7 +553,7 @@
     log_fn(LOG_INFO,"No circuit associated with conn. Skipping.");
     return;
   }
- 
+
   while(conn->deliver_window < STREAMWINDOW_START - STREAMWINDOW_INCREMENT) {
     log_fn(LOG_DEBUG,"Outbuf %d, Queueing stream sendme.", conn->outbuf_flushlen);
     conn->deliver_window += STREAMWINDOW_INCREMENT;
@@ -828,7 +829,7 @@
   /* also, deliver a 'connected' cell back through the circuit. */
   *((uint32_t*) connected_payload) = htonl(conn->addr);
   connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_CONNECTED,
-                               connected_payload, 4, conn->cpath_layer);
+                               connected_payload, 4, NULL);
 }
 
 int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit)

Index: or.h
===================================================================
RCS file: /home/or/cvsroot/src/or/or.h,v
retrieving revision 1.208
retrieving revision 1.209
diff -u -d -r1.208 -r1.209
--- or.h	16 Dec 2003 09:48:17 -0000	1.208
+++ or.h	16 Dec 2003 22:56:50 -0000	1.209
@@ -250,9 +250,17 @@
 
 #define CELL_RELAY_COMMAND_END_REASON(c) (*(uint8_t)((c).payload+1))
 
+/* integrity is the first 32 bits (in network order) of a sha-1 of all
+ * cell payloads that are relay cells that have been sent / delivered
+ * to the hop on the * circuit (the integrity is zeroed while doing
+ * each calculation)
+ */
+#define CELL_RELAY_INTEGRITY(c)       (ntohl(*(uint32_t*)((c).payload+1+STREAM_ID_SIZE)))
+#define SET_CELL_RELAY_INTEGRITY(c,i) (*(uint32_t*)((c).payload+1+STREAM_ID_SIZE) = htonl(i))
+
 /* relay length is how many bytes are used in the cell payload past relay_header_size */
-#define CELL_RELAY_LENGTH(c)         (*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4))
-#define SET_CELL_RELAY_LENGTH(c,len) (*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4) = (len))
+#define CELL_RELAY_LENGTH(c)         (ntohs(*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4)))
+#define SET_CELL_RELAY_LENGTH(c,len) (*(uint16_t*)((c).payload+1+STREAM_ID_SIZE+4) = htons(len))
 
 #define CELL_PAYLOAD_SIZE 509
 #define CELL_NETWORK_SIZE 512
@@ -544,6 +552,8 @@
 int circuit_count_building(void);
 int circuit_stream_is_being_handled(connection_t *conn);
 
+void relay_set_digest(crypto_digest_env_t *digest, cell_t *cell);
+int relay_check_digest(crypto_digest_env_t *digest, cell_t *cell);
 int circuit_deliver_relay_cell(cell_t *cell, circuit_t *circ,
                                int cell_direction, crypt_path_t *layer_hint);
 int relay_crypt(circuit_t *circ, char *in, int inlen, char cell_direction,
@@ -552,7 +562,7 @@
 
 void circuit_resume_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
 int circuit_consider_stop_edge_reading(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
-int circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
+void circuit_consider_sending_sendme(circuit_t *circ, int edge_type, crypt_path_t *layer_hint);
 
 void circuit_close(circuit_t *circ);
 void circuit_about_to_close_connection(connection_t *conn);



More information about the tor-commits mailing list