[tor-commits] [tor/master] Refactor link handshake cell type implementations to use trunnel

nickm at torproject.org nickm at torproject.org
Thu May 28 15:06:55 UTC 2015


commit b29c1530c7864ddfe382b18f4fc6e88eb46c1595
Author: Nick Mathewson <nickm at torproject.org>
Date:   Fri Oct 17 17:06:31 2014 -0400

    Refactor link handshake cell type implementations to use trunnel
    
    Unit tests still pass.
---
 src/or/channeltls.c    |  138 +++++++++++++++++++++--------------------------
 src/or/connection_or.c |  139 ++++++++++++++++++++++++++++++------------------
 2 files changed, 148 insertions(+), 129 deletions(-)

diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index af63444..0376e74 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -24,6 +24,7 @@
 #include "connection.h"
 #include "connection_or.h"
 #include "control.h"
+#include "link_handshake.h"
 #include "relay.h"
 #include "router.h"
 #include "routerlist.h"
@@ -1740,13 +1741,14 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
 STATIC void
 channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
 {
-  tor_x509_cert_t *link_cert = NULL;
-  tor_x509_cert_t *id_cert = NULL;
-  tor_x509_cert_t *auth_cert = NULL;
-  uint8_t *ptr;
+#define MAX_CERT_TYPE_WANTED OR_CERT_TYPE_AUTH_1024
+  tor_x509_cert_t *certs[MAX_CERT_TYPE_WANTED + 1];
   int n_certs, i;
+  certs_cell_t *cc = NULL;
+
   int send_netinfo = 0;
 
+  memset(certs, 0, sizeof(certs));
   tor_assert(cell);
   tor_assert(chan);
   tor_assert(chan->conn);
@@ -1776,63 +1778,41 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
   if (cell->circ_id)
     ERR("It had a nonzero circuit ID");
 
-  n_certs = cell->payload[0];
-  ptr = cell->payload + 1;
+  if (certs_cell_parse(&cc, cell->payload, cell->payload_len) < 0)
+    ERR("It couldn't be parsed.");
+
+  n_certs = cc->n_certs;
+
   for (i = 0; i < n_certs; ++i) {
-    uint8_t cert_type;
-    uint16_t cert_len;
-    if (cell->payload_len < 3)
-      goto truncated;
-    if (ptr > cell->payload + cell->payload_len - 3) {
-      goto truncated;
-    }
-    cert_type = *ptr;
-    cert_len = ntohs(get_uint16(ptr+1));
-    if (cell->payload_len < 3 + cert_len)
-      goto truncated;
-    if (ptr > cell->payload + cell->payload_len - cert_len - 3) {
-      goto truncated;
-    }
-    if (cert_type == OR_CERT_TYPE_TLS_LINK ||
-        cert_type == OR_CERT_TYPE_ID_1024 ||
-        cert_type == OR_CERT_TYPE_AUTH_1024) {
-      tor_x509_cert_t *cert = tor_x509_cert_decode(ptr + 3, cert_len);
-      if (!cert) {
-        log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
-               "Received undecodable certificate in CERTS cell from %s:%d",
-               safe_str(chan->conn->base_.address),
-               chan->conn->base_.port);
+    certs_cell_cert_t *c = certs_cell_get_certs(cc, i);
+
+    uint16_t cert_type = c->cert_type;
+    uint16_t cert_len = c->cert_len;
+    uint8_t *cert_body = certs_cell_cert_getarray_body(c);
+
+    if (cert_type > MAX_CERT_TYPE_WANTED)
+      continue;
+
+    tor_x509_cert_t *cert = tor_x509_cert_decode(cert_body, cert_len);
+    if (!cert) {
+      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+             "Received undecodable certificate in CERTS cell from %s:%d",
+             safe_str(chan->conn->base_.address),
+             chan->conn->base_.port);
+    } else {
+      if (certs[cert_type]) {
+        tor_x509_cert_free(cert);
+        ERR("Duplicate x509 certificate");
       } else {
-        if (cert_type == OR_CERT_TYPE_TLS_LINK) {
-          if (link_cert) {
-            tor_x509_cert_free(cert);
-            ERR("Too many TLS_LINK certificates");
-          }
-          link_cert = cert;
-        } else if (cert_type == OR_CERT_TYPE_ID_1024) {
-          if (id_cert) {
-            tor_x509_cert_free(cert);
-            ERR("Too many ID_1024 certificates");
-          }
-          id_cert = cert;
-        } else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
-          if (auth_cert) {
-            tor_x509_cert_free(cert);
-            ERR("Too many AUTH_1024 certificates");
-          }
-          auth_cert = cert;
-        } else {
-          tor_x509_cert_free(cert);
-        }
+        certs[cert_type] = cert;
       }
     }
-    ptr += 3 + cert_len;
-    continue;
-
-  truncated:
-    ERR("It ends in the middle of a certificate");
   }
 
+  tor_x509_cert_t *id_cert = certs[OR_CERT_TYPE_ID_1024];
+  tor_x509_cert_t *auth_cert = certs[OR_CERT_TYPE_AUTH_1024];
+  tor_x509_cert_t *link_cert = certs[OR_CERT_TYPE_TLS_LINK];
+
   if (chan->conn->handshake_state->started_here) {
     int severity;
     if (! (id_cert && link_cert))
@@ -1881,7 +1861,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
              safe_str(chan->conn->base_.address), chan->conn->base_.port);
 
     chan->conn->handshake_state->id_cert = id_cert;
-    id_cert = NULL;
+    certs[OR_CERT_TYPE_ID_1024] = NULL;
 
     if (!public_server_mode(get_options())) {
       /* If we initiated the connection and we are not a public server, we
@@ -1908,7 +1888,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
 
     chan->conn->handshake_state->id_cert = id_cert;
     chan->conn->handshake_state->auth_cert = auth_cert;
-    id_cert = auth_cert = NULL;
+    certs[OR_CERT_TYPE_ID_1024] = certs[OR_CERT_TYPE_AUTH_1024] = NULL;
   }
 
   chan->conn->handshake_state->received_certs_cell = 1;
@@ -1922,9 +1902,10 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
   }
 
  err:
-  tor_x509_cert_free(id_cert);
-  tor_x509_cert_free(link_cert);
-  tor_x509_cert_free(auth_cert);
+  for (unsigned i = 0; i < ARRAY_LENGTH(certs); ++i) {
+    tor_x509_cert_free(certs[i]);
+  }
+  certs_cell_free(cc);
 #undef ERR
 }
 
@@ -1943,7 +1924,7 @@ STATIC void
 channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
 {
   int n_types, i, use_type = -1;
-  uint8_t *cp;
+  auth_challenge_cell_t *ac = NULL;
 
   tor_assert(cell);
   tor_assert(chan);
@@ -1956,7 +1937,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
            safe_str(chan->conn->base_.address),                 \
            chan->conn->base_.port, (s));                        \
     connection_or_close_for_error(chan->conn, 0);               \
-    return;                                                     \
+    goto done;                                                  \
   } while (0)
 
   if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
@@ -1969,19 +1950,17 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
     ERR("We already received one");
   if (!(chan->conn->handshake_state->received_certs_cell))
     ERR("We haven't gotten a CERTS cell yet");
-  if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
-    ERR("It was too short");
   if (cell->circ_id)
     ERR("It had a nonzero circuit ID");
 
-  n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
-  if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
-    ERR("It looks truncated");
+  if (auth_challenge_cell_parse(&ac, cell->payload, cell->payload_len) < 0)
+    ERR("It was not well-formed.");
+
+  n_types = ac->n_methods;
 
   /* Now see if there is an authentication type we can use */
-  cp = cell->payload+OR_AUTH_CHALLENGE_LEN + 2;
-  for (i = 0; i < n_types; ++i, cp += 2) {
-    uint16_t authtype = ntohs(get_uint16(cp));
+  for (i = 0; i < n_types; ++i) {
+    uint16_t authtype = auth_challenge_cell_get_methods(ac, i);
     if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
       use_type = authtype;
   }
@@ -1992,7 +1971,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
     /* If we're not a public server then we don't want to authenticate on a
        connection we originated, and we already sent a NETINFO cell when we
        got the CERTS cell. We have nothing more to do. */
-    return;
+    goto done;
   }
 
   if (use_type >= 0) {
@@ -2006,7 +1985,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
       log_warn(LD_OR,
                "Couldn't send authenticate cell");
       connection_or_close_for_error(chan->conn, 0);
-      return;
+      goto done;
     }
   } else {
     log_info(LD_OR,
@@ -2019,9 +1998,12 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
   if (connection_or_send_netinfo(chan->conn) < 0) {
     log_warn(LD_OR, "Couldn't send netinfo cell");
     connection_or_close_for_error(chan->conn, 0);
-    return;
+    goto done;
   }
 
+done:
+  auth_challenge_cell_free(ac);
+
 #undef ERR
 }
 
@@ -2038,7 +2020,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
 STATIC void
 channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
 {
-  uint8_t expected[V3_AUTH_FIXED_PART_LEN];
+  uint8_t expected[V3_AUTH_FIXED_PART_LEN+256];
   const uint8_t *auth;
   int authlen;
 
@@ -2094,11 +2076,13 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
   if (authlen < V3_AUTH_BODY_LEN + 1)
     ERR("Authenticator was too short");
 
-  if (connection_or_compute_authenticate_cell_body(
-                        chan->conn, expected, sizeof(expected), NULL, 1) < 0)
+  ssize_t bodylen =
+    connection_or_compute_authenticate_cell_body(
+                        chan->conn, expected, sizeof(expected), NULL, 1);
+  if (bodylen < 0 || bodylen != V3_AUTH_FIXED_PART_LEN)
     ERR("Couldn't compute expected AUTHENTICATE cell body");
 
-  if (tor_memneq(expected, auth, sizeof(expected)))
+  if (tor_memneq(expected, auth, bodylen))
     ERR("Some field in the AUTHENTICATE cell body was not as expected");
 
   {
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 8602bcb..ba30987 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -30,6 +30,7 @@
 #include "entrynodes.h"
 #include "geoip.h"
 #include "main.h"
+#include "link_handshake.h"
 #include "networkstatus.h"
 #include "nodelist.h"
 #include "reasons.h"
@@ -2279,28 +2280,37 @@ connection_or_send_certs_cell(or_connection_t *conn)
 int
 connection_or_send_auth_challenge_cell(or_connection_t *conn)
 {
-  var_cell_t *cell;
-  uint8_t *cp;
-  uint8_t challenge[OR_AUTH_CHALLENGE_LEN];
+  var_cell_t *cell = NULL;
+  int r = -1;
   tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
 
   if (! conn->handshake_state)
     return -1;
 
-  if (crypto_rand((char*)challenge, OR_AUTH_CHALLENGE_LEN) < 0)
-    return -1;
-  cell = var_cell_new(OR_AUTH_CHALLENGE_LEN + 4);
+  auth_challenge_cell_t *ac = auth_challenge_cell_new();
+
+  if (crypto_rand((char*)ac->challenge, sizeof(ac->challenge)) < 0)
+    goto done;
+
+  auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
+  auth_challenge_cell_set_n_methods(ac,
+                                    auth_challenge_cell_getlen_methods(ac));
+
+  cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
+  ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
+                                           ac);
+  if (len != cell->payload_len)
+    goto done;
   cell->command = CELL_AUTH_CHALLENGE;
-  memcpy(cell->payload, challenge, OR_AUTH_CHALLENGE_LEN);
-  cp = cell->payload + OR_AUTH_CHALLENGE_LEN;
-  set_uint16(cp, htons(1)); /* We recognize one authentication type. */
-  set_uint16(cp+2, htons(AUTHTYPE_RSA_SHA256_TLSSECRET));
 
   connection_or_write_var_cell_to_buf(cell, conn);
+  r = 0;
+
+ done:
   var_cell_free(cell);
-  memwipe(challenge, 0, sizeof(challenge));
+  auth_challenge_cell_free(ac);
 
-  return 0;
+  return r;
 }
 
 /** Compute the main body of an AUTHENTICATE cell that a client can use
@@ -2327,19 +2337,18 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
                                              crypto_pk_t *signing_key,
                                              int server)
 {
-  uint8_t *ptr;
+  auth1_t *auth = NULL;
+  auth_ctx_t *ctx = auth_ctx_new();
+  int result;
 
   /* assert state is reasonable XXXX */
 
-  if (outlen < V3_AUTH_FIXED_PART_LEN ||
-      (!server && outlen < V3_AUTH_BODY_LEN))
-    return -1;
+  ctx->is_ed = 0;
 
-  ptr = out;
+  auth = auth1_new();
 
   /* Type: 8 bytes. */
-  memcpy(ptr, "AUTH0001", 8);
-  ptr += 8;
+  memcpy(auth1_getarray_type(auth), "AUTH0001", 8);
 
   {
     const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL;
@@ -2359,12 +2368,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
     server_id = server ? my_id : their_id;
 
     /* Client ID digest: 32 octets. */
-    memcpy(ptr, client_id, 32);
-    ptr += 32;
+    memcpy(auth->cid, client_id, 32);
 
     /* Server ID digest: 32 octets. */
-    memcpy(ptr, server_id, 32);
-    ptr += 32;
+    memcpy(auth->sid, server_id, 32);
   }
 
   {
@@ -2378,12 +2385,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
     }
 
     /* Server log digest : 32 octets */
-    crypto_digest_get_digest(server_d, (char*)ptr, 32);
-    ptr += 32;
+    crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
 
     /* Client log digest : 32 octets */
-    crypto_digest_get_digest(client_d, (char*)ptr, 32);
-    ptr += 32;
+    crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
   }
 
   {
@@ -2396,49 +2401,79 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
       freecert = tor_tls_get_peer_cert(conn->tls);
       cert = freecert;
     }
-    if (!cert)
-      return -1;
-    memcpy(ptr, tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
+    if (!cert) {
+      log_warn(LD_OR, "Unable to find cert when making AUTH1 data.");
+      goto err;
+    }
+
+    memcpy(auth->scert,
+           tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
 
     if (freecert)
       tor_x509_cert_free(freecert);
-    ptr += 32;
   }
 
   /* HMAC of clientrandom and serverrandom using master key : 32 octets */
-  tor_tls_get_tlssecrets(conn->tls, ptr);
-  ptr += 32;
-
-  tor_assert(ptr - out == V3_AUTH_FIXED_PART_LEN);
-
-  if (server)
-    return V3_AUTH_FIXED_PART_LEN; // ptr-out
+  tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
 
   /* 8 octets were reserved for the current time, but we're trying to get out
    * of the habit of sending time around willynilly.  Fortunately, nothing
    * checks it.  That's followed by 16 bytes of nonce. */
-  crypto_rand((char*)ptr, 24);
-  ptr += 24;
+  crypto_rand((char*)auth->rand, 24);
+
+  ssize_t len;
+  if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
+    log_warn(LD_OR, "Unable to encode signed part of AUTH1 data.");
+    goto err;
+  }
 
-  tor_assert(ptr - out == V3_AUTH_BODY_LEN);
+  if (server) {
+    auth1_t *tmp = NULL;
+    ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
+    if (!tmp) {
+      log_warn(LD_OR, "Unable to parse signed part of AUTH1 data.");
+      goto err;
+    }
+    result = (int) (tmp->end_of_fixed_part - out);
+    auth1_free(tmp);
+    if (len2 != len) {
+      log_warn(LD_OR, "Mismatched length when re-parsing AUTH1 data.");
+      goto err;
+    }
+    goto done;
+  }
 
-  if (!signing_key)
-    return V3_AUTH_BODY_LEN; // ptr - out
+  if (signing_key) {
+    auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
 
-  {
-    int siglen;
     char d[32];
-    crypto_digest256(d, (char*)out, ptr-out, DIGEST_SHA256);
-    siglen = crypto_pk_private_sign(signing_key,
-                                    (char*)ptr, outlen - (ptr-out),
+    crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
+    int siglen = crypto_pk_private_sign(signing_key,
+                                    (char*)auth1_getarray_sig(auth),
+                                    auth1_getlen_sig(auth),
                                     d, 32);
-    if (siglen < 0)
+    if (siglen < 0) {
+      log_warn(LD_OR, "Unable to sign AUTH1 data.");
       return -1;
+    }
 
-    ptr += siglen;
-    tor_assert(ptr <= out+outlen);
-    return (int)(ptr - out);
+    auth1_setlen_sig(auth, siglen);
+
+    len = auth1_encode(out, outlen, auth, ctx);
+    if (len < 0) {
+      log_warn(LD_OR, "Unable to encode signed AUTH1 data.");
+      goto err;
+    }
   }
+  result = (int) len;
+  goto done;
+
+ err:
+  result = -1;
+ done:
+  auth1_free(auth);
+  auth_ctx_free(ctx);
+  return result;
 }
 
 /** Send an AUTHENTICATE cell on the connection <b>conn</b>.  Return 0 on





More information about the tor-commits mailing list