Commit 0bac4247 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

tls infrastructure now in place, give or take


svn:r434
parent 1a9b5f9d
Loading
Loading
Loading
Loading
+108 −56
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ char *conn_state_to_string[][15] = {

/********* END VARIABLES ************/

static int connection_init_accepted_conn(connection_t *conn);

/**************************************************************/

@@ -183,7 +184,7 @@ int connection_create_listener(struct sockaddr_in *bindaddr, int type) {
    return -1;
  }

  log_fn(LOG_DEBUG,"Listening on port %u.",ntohs(bindaddr->sin_port));
  log_fn(LOG_DEBUG,"%s listening on port %u.",conn_type_to_string[type], ntohs(bindaddr->sin_port));

  conn->state = LISTENER_STATE_READY;
  connection_start_reading(conn);
@@ -191,7 +192,7 @@ int connection_create_listener(struct sockaddr_in *bindaddr, int type) {
  return 0;
}

int connection_handle_listener_read(connection_t *conn, int new_type, int new_state) {
int connection_handle_listener_read(connection_t *conn, int new_type) {

  int news; /* the new socket */
  connection_t *newconn;
@@ -237,12 +238,73 @@ int connection_handle_listener_read(connection_t *conn, int new_type, int new_st
    return 0; /* no need to tear down the parent */
  }

  log(LOG_DEBUG,"connection_handle_listener_read(): socket %d entered state %d.",newconn->s, new_state);
  newconn->state = new_state;
  connection_start_reading(newconn);
  if(connection_init_accepted_conn(newconn) < 0) {
    connection_free(newconn);
    return 0;
  }
  return 0;
}

static int connection_init_accepted_conn(connection_t *conn) {

  connection_start_reading(conn);

  switch(conn->type) {
    case CONN_TYPE_OR:
#ifdef USE_TLS
      if(connection_tls_start_handshake(conn) < 0)
        return -1;
#else
      conn->state = OR_CONN_STATE_SERVER_AUTH_WAIT;
#endif
      break;
    case CONN_TYPE_AP:
      conn->state = AP_CONN_STATE_SOCKS_WAIT;
      break;
    case CONN_TYPE_DIR:
      conn->state = DIR_CONN_STATE_COMMAND_WAIT;
      break;
  }
  return 0;
}

#ifdef USE_TLS
int connection_tls_start_handshake(connection_t *conn) {
  conn->state = OR_CONN_STATE_HANDSHAKING;
  conn->tls = tor_tls_new(conn->s, options.OnionRouter);
  if(!conn->tls) {
    log_fn(LOG_ERR,"tor_tls_new failed. Closing.");
    return -1;
  }
  connection_start_reading(conn);
  if(connection_tls_continue_handshake(conn) < 0)
    return -1;
  return 0;
}

int connection_tls_continue_handshake(connection_t *conn) {
  switch(tor_tls_handshake(conn->tls)) {
    case TOR_TLS_ERROR:
    case TOR_TLS_CLOSE:
      log_fn(LOG_DEBUG,"tls error. breaking.");
      return -1;
    case TOR_TLS_DONE:
      conn->state = OR_CONN_STATE_OPEN;
      directory_set_dirty();
      connection_watch_events(conn, POLLIN);
      if(!options.OnionRouter)
        circuit_n_conn_open(conn); /* send the pending create */
      log_fn(LOG_DEBUG,"tls handshake done, now open.");
      return 0;
    case TOR_TLS_WANTWRITE:
      connection_start_writing(conn);
      return 0;
    case TOR_TLS_WANTREAD: /* handshaking conns are *always* reading */
      return 0;
  }
  return 0;
}
#endif

/* start all connections that should be up but aren't */
int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16_t dir_listenport) {
@@ -259,14 +321,14 @@ int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16
  if(or_listenport) {
    bindaddr.sin_port = htons(or_listenport);
    if(!connection_get_by_type(CONN_TYPE_OR_LISTENER)) {
      connection_or_create_listener(&bindaddr);
      connection_create_listener(&bindaddr, CONN_TYPE_OR_LISTENER);
    }
  }

  if(dir_listenport) {
    bindaddr.sin_port = htons(dir_listenport);
    if(!connection_get_by_type(CONN_TYPE_DIR_LISTENER)) {
      connection_dir_create_listener(&bindaddr);
      connection_create_listener(&bindaddr, CONN_TYPE_DIR_LISTENER);
    }
  }
 
@@ -274,7 +336,7 @@ int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16
    bindaddr.sin_port = htons(ap_listenport);
    bindaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* the AP listens only on localhost! */
    if(!connection_get_by_type(CONN_TYPE_AP_LISTENER)) {
      connection_ap_create_listener(&bindaddr);
      connection_create_listener(&bindaddr, CONN_TYPE_AP_LISTENER);
    }
  }

@@ -289,12 +351,12 @@ int connection_handle_read(connection_t *conn) {

  switch(conn->type) {
    case CONN_TYPE_OR_LISTENER:
      return connection_or_handle_listener_read(conn);
      return connection_handle_listener_read(conn, CONN_TYPE_OR);
    case CONN_TYPE_AP_LISTENER:
      return connection_ap_handle_listener_read(conn);
      return connection_handle_listener_read(conn, CONN_TYPE_AP);
    case CONN_TYPE_DIR_LISTENER:
      return connection_dir_handle_listener_read(conn);
    default:
      return connection_handle_listener_read(conn, CONN_TYPE_DIR);
  }

  if(connection_read_to_buf(conn) < 0) {
    if(conn->type == CONN_TYPE_DIR && conn->state == DIR_CONN_STATE_CONNECTING) {
@@ -313,7 +375,6 @@ int connection_handle_read(connection_t *conn) {
    log_fn(LOG_DEBUG,"receiver bucket reached 0 before handshake finished. Closing.");
    return -1;
  }
  } /* end switch */
  return 0;
}

@@ -344,26 +405,22 @@ int connection_read_to_buf(connection_t *conn) {

#ifdef USE_TLS
  if(connection_speaks_cells(conn) && conn->state != OR_CONN_STATE_CONNECTING) {
    if(conn->state == OR_CONN_STATE_HANDSHAKING) {
      result = tor_tls_handshake(conn->tls)
      if(result == TOR_TLS_DONE) {
        conn->state = OR_CONN_STATE_OPEN;
        log_fn(LOG_DEBUG,"tls handshake done, now open.");
      }
    } else { /* open, or closing */
    if(conn->state == OR_CONN_STATE_HANDSHAKING)
      return connection_tls_continue_handshake(conn);

    /* else open, or closing */
    result = read_to_buf_tls(conn->tls, at_most, &conn->inbuf,
                             &conn->inbuflen, &conn->inbuf_datalen);
    }

    switch(result) {
      case TOR_TLS_ERROR:
      case TOR_TLS_CLOSE:
        log_fn(LOG_DEBUG,"tls error. breaking.");
        return -1; /* XXX deal with close better */
      case TOR_TLS_WANT_WRITE:
      case TOR_TLS_WANTWRITE:
        connection_start_writing(conn);
        return 0;
      case TOR_TLS_WANT_READ: /* we're already reading */
      case TOR_TLS_WANTREAD: /* we're already reading */
      case TOR_TLS_DONE: /* no data read, so nothing to process */
        return 0;
    }
@@ -413,7 +470,6 @@ int connection_flush_buf(connection_t *conn) {
/* return -1 if you want to break the conn, else return 0 */
int connection_handle_write(connection_t *conn) {
  struct timeval now;
  int result;

  if(connection_is_listener(conn)) {
    log_fn(LOG_DEBUG,"Got a listener socket. Can't happen!");
@@ -425,26 +481,20 @@ int connection_handle_write(connection_t *conn) {

#ifdef USE_TLS
  if(connection_speaks_cells(conn) && conn->state != OR_CONN_STATE_CONNECTING) {
    if(conn->state == OR_CONN_STATE_HANDSHAKING) {
      result = tor_tls_handshake(conn->tls)
      if(result == TOR_TLS_DONE) {
        conn->state = OR_CONN_STATE_OPEN;
        log_fn(LOG_DEBUG,"tls handshake done, now open.");
      }
    } else { /* open, or closing */
      result = flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen,
                             &conn->outbuf_flushlen, &conn->outbuf_datalen);
    }
    if(conn->state == OR_CONN_STATE_HANDSHAKING)
      return connection_tls_continue_handshake(conn);

    switch(result) {
    /* else open, or closing */
    switch(flush_buf_tls(conn->tls, &conn->outbuf, &conn->outbuflen,
                         &conn->outbuf_flushlen, &conn->outbuf_datalen)) {
      case TOR_TLS_ERROR:
      case TOR_TLS_CLOSE:
        log_fn(LOG_DEBUG,"tls error. breaking.");
        return -1; /* XXX deal with close better */
      case TOR_TLS_WANT_WRITE:
      case TOR_TLS_WANTWRITE:
        /* we're already writing */
        return 0;
      case TOR_TLS_WANT_READ:
      case TOR_TLS_WANTREAD:
        /* Make sure to avoid a loop if the receive buckets are empty. */
        if(!connection_is_reading(conn)) {
          connection_stop_writing(conn);
@@ -766,7 +816,9 @@ int connection_process_cell_from_inbuf(connection_t *conn) {
  /* check if there's a whole cell there.
   * if yes, pull it off, decrypt it if we're not doing TLS, and process it.
   */
#ifndef USE_TLS
  char networkcell[CELL_NETWORK_SIZE];
#endif
  char buf[CELL_NETWORK_SIZE];
//  int x;
  cell_t cell;
+0 −10
Original line number Diff line number Diff line
@@ -159,16 +159,6 @@ int ap_handshake_socks_reply(connection_t *conn, char result) {
  return connection_flush_buf(conn); /* try to flush it, in case we're about to close the conn */
}

int connection_ap_create_listener(struct sockaddr_in *bindaddr) {
  log_fn(LOG_DEBUG,"starting");
  return connection_create_listener(bindaddr, CONN_TYPE_AP_LISTENER);
}

int connection_ap_handle_listener_read(connection_t *conn) {
  log(LOG_NOTICE,"AP: Received a connection request. Waiting for socksinfo.");
  return connection_handle_listener_read(conn, CONN_TYPE_AP, AP_CONN_STATE_SOCKS_WAIT);
} 

/*
  Local Variables:
  mode:c
+15 −16
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@ static int or_handshake_server_process_auth(connection_t *conn);
static int or_handshake_server_process_nonce(connection_t *conn);

static void conn_or_init_crypto(connection_t *conn);
#endif
static void connection_or_set_open(connection_t *conn);
#endif

/*
 *
@@ -85,7 +85,8 @@ int connection_or_finished_flushing(connection_t *conn) {
          conn->address,conn->port);

#ifdef USE_TLS
      call TLS new, and start the TLS handshake
      if(connection_tls_start_handshake(conn) < 0)
        return -1;
#else
      if(options.OnionRouter)
        return or_handshake_client_send_auth(conn);
@@ -182,7 +183,11 @@ connection_t *connection_or_connect(routerinfo_t *router) {
      connection_watch_events(conn, POLLIN | POLLOUT | POLLERR); 
      /* writable indicates finish, readable indicates broken link,
         error indicates broken link on windows */
#ifdef USE_TLS
      conn->state = OR_CONN_STATE_CONNECTING;
#else
      conn->state = OR_CONN_STATE_CLIENT_CONNECTING;
#endif
      return conn;
    }
  }
@@ -198,9 +203,14 @@ connection_t *connection_or_connect(routerinfo_t *router) {
  log(LOG_DEBUG,"connection_or_connect() : Connection to router %s:%u established.",
      router->address, router->or_port);

#ifdef USE_TLS
  if(connection_tls_start_handshake(conn) >= 0)
    return conn;
#else
  if((options.OnionRouter && or_handshake_client_send_auth(conn) >= 0) ||
     (!options.OnionRouter && or_handshake_op_send_keys(conn) >= 0))
    return conn; /* success! */
#endif

  /* failure */
  connection_remove(conn);
@@ -210,17 +220,7 @@ connection_t *connection_or_connect(routerinfo_t *router) {

/* ********************************** */

int connection_or_create_listener(struct sockaddr_in *bindaddr) {
  log(LOG_DEBUG,"connection_create_or_listener starting");
  return connection_create_listener(bindaddr, CONN_TYPE_OR_LISTENER);
}

int connection_or_handle_listener_read(connection_t *conn) {
  log(LOG_NOTICE,"OR: Received a connection request. Attempting to authenticate.");
  return connection_handle_listener_read(conn, CONN_TYPE_OR, OR_CONN_STATE_SERVER_AUTH_WAIT);
}

/* ***************** */
#ifndef USE_TLS
/* Helper functions to implement handshaking */

#define FLAGS_LEN 2
@@ -237,7 +237,7 @@ or_handshake_op_send_keys(connection_t *conn) {

  assert(conn && conn->type == CONN_TYPE_OR);

  conn->bandwidth = DEFAULT_BANDWIDTH_OP;
  conn->bandwidth = DEFAULT_BANDWIDTH_OP; /* XXX USE_TLS */

  /* generate random keys */
  if(crypto_cipher_generate_key(conn->f_crypto) ||
@@ -520,7 +520,7 @@ or_handshake_server_process_auth(connection_t *conn) {
    crypto_cipher_set_key(conn->b_crypto,buf+14);
    crypto_cipher_set_key(conn->f_crypto,buf+30);

    conn->bandwidth = router->bandwidth;
    conn->bandwidth = router->bandwidth; /* XXX USE_TLS and below */

    /* copy all relevant info to conn */
    conn->addr = router->addr, conn->port = router->or_port;
@@ -665,7 +665,6 @@ connection_or_set_open(connection_t *conn) {
  connection_watch_events(conn, POLLIN);
}

#ifndef USE_TLS
static void 
conn_or_init_crypto(connection_t *conn) {
  //int x;
+0 −10
Original line number Diff line number Diff line
@@ -290,16 +290,6 @@ int connection_dir_finished_flushing(connection_t *conn) {
  return 0;
}

int connection_dir_create_listener(struct sockaddr_in *bindaddr) {
  log_fn(LOG_DEBUG,"starting");
  return connection_create_listener(bindaddr, CONN_TYPE_DIR_LISTENER);
}

int connection_dir_handle_listener_read(connection_t *conn) {
  log(LOG_INFO,"Dir: Received a connection request. Waiting for command.");
  return connection_handle_listener_read(conn, CONN_TYPE_DIR, DIR_CONN_STATE_COMMAND_WAIT);
} 

/*
  Local Variables:
  mode:c
+1 −1
Original line number Diff line number Diff line
@@ -462,7 +462,7 @@ static int do_main_loop(void) {
      }
    }

    if(tor_tls_context_new(certfile, get_privatekey(), 1) < 0) {
    if(tor_tls_context_new(options.CertFile, get_privatekey(), 1) < 0) {
      log_fn(LOG_ERR,"Error creating tls context.");
      return -1;
    }
Loading