Browse Source

Merge remote-tracking branch 'tor-github/pr/1039' into maint-0.4.0

Nick Mathewson 4 years ago
parent
commit
2300a619a5

+ 10 - 0
changes/ticket30454

@@ -0,0 +1,10 @@
+  o Major bugfixes (hidden service v3):
+    - An intro point could try to send an INTRODUCE_ACK with a status code
+      that it wasn't able to encode leading to a hard assert() of the relay.
+      Fortunately, that specific code path can not be reached thus this issue
+      can't be triggered. We've consolidated the ABI values into trunnel now.
+      Fixes bug 30454; bugfix on 0.3.0.1-alpha.
+    - HSv3 client will now be able to properly handle unknown status code from
+      a INTRODUCE_ACK cell (nack) even if they do not know it. The NACK
+      behavior will stay the same. This will allow us to extend status code if
+      we want in the future without breaking the normal client behavior.

+ 9 - 7
src/feature/hs/hs_cell.c

@@ -161,11 +161,12 @@ parse_introduce2_encrypted(const uint8_t *decrypted_data,
   }
 
   if (trn_cell_introduce_encrypted_get_onion_key_type(enc_cell) !=
-      HS_CELL_ONION_KEY_TYPE_NTOR) {
+      TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR) {
     log_info(LD_REND, "INTRODUCE2 onion key type is invalid. Got %u but "
                       "expected %u on circuit %u for service %s",
              trn_cell_introduce_encrypted_get_onion_key_type(enc_cell),
-             HS_CELL_ONION_KEY_TYPE_NTOR, TO_CIRCUIT(circ)->n_circ_id,
+             TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR,
+             TO_CIRCUIT(circ)->n_circ_id,
              safe_str_client(service->onion_address));
     goto err;
   }
@@ -258,7 +259,7 @@ introduce1_set_encrypted_onion_key(trn_cell_introduce_encrypted_t *cell,
   tor_assert(onion_pk);
   /* There is only one possible key type for a non legacy cell. */
   trn_cell_introduce_encrypted_set_onion_key_type(cell,
-                                                  HS_CELL_ONION_KEY_TYPE_NTOR);
+                                   TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR);
   trn_cell_introduce_encrypted_set_onion_key_len(cell, CURVE25519_PUBKEY_LEN);
   trn_cell_introduce_encrypted_setlen_onion_key(cell, CURVE25519_PUBKEY_LEN);
   memcpy(trn_cell_introduce_encrypted_getarray_onion_key(cell), onion_pk,
@@ -442,7 +443,8 @@ introduce1_set_auth_key(trn_cell_introduce1_t *cell,
   tor_assert(cell);
   tor_assert(data);
   /* There is only one possible type for a non legacy cell. */
-  trn_cell_introduce1_set_auth_key_type(cell, HS_INTRO_AUTH_KEY_TYPE_ED25519);
+  trn_cell_introduce1_set_auth_key_type(cell,
+                                   TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
   trn_cell_introduce1_set_auth_key_len(cell, ED25519_PUBKEY_LEN);
   trn_cell_introduce1_setlen_auth_key(cell, ED25519_PUBKEY_LEN);
   memcpy(trn_cell_introduce1_getarray_auth_key(cell),
@@ -515,7 +517,7 @@ hs_cell_build_establish_intro(const char *circ_nonce,
 
   /* Set AUTH_KEY_TYPE: 2 means ed25519 */
   trn_cell_establish_intro_set_auth_key_type(cell,
-                                             HS_INTRO_AUTH_KEY_TYPE_ED25519);
+                                    TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
 
   /* Set AUTH_KEY and AUTH_KEY_LEN field. Must also set byte-length of
    * AUTH_KEY to match */
@@ -882,9 +884,9 @@ hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len)
    * do a special case. */
   if (payload_len <= 1) {
     if (payload_len == 0) {
-      ret = HS_CELL_INTRO_ACK_SUCCESS;
+      ret = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
     } else {
-      ret = HS_CELL_INTRO_ACK_FAILURE;
+      ret = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
     }
     goto end;
   }

+ 0 - 13
src/feature/hs/hs_cell.h

@@ -16,19 +16,6 @@
  * 3.2.2 of the specification). Below this value, the cell must be padded. */
 #define HS_CELL_INTRODUCE1_MIN_SIZE 246
 
-/* Status code of an INTRODUCE_ACK cell. */
-typedef enum {
-  HS_CELL_INTRO_ACK_SUCCESS = 0x0000, /* Cell relayed to service. */
-  HS_CELL_INTRO_ACK_FAILURE = 0x0001, /* Service ID not recognized */
-  HS_CELL_INTRO_ACK_BADFMT  = 0x0002, /* Bad message format */
-  HS_CELL_INTRO_ACK_NORELAY = 0x0003, /* Can't relay cell to service */
-} hs_cell_introd_ack_status_t;
-
-/* Onion key type found in the INTRODUCE1 cell. */
-typedef enum {
-  HS_CELL_ONION_KEY_TYPE_NTOR = 1,
-} hs_cell_onion_key_type_t;
-
 /* This data structure contains data that we need to build an INTRODUCE1 cell
  * used by the INTRODUCE1 build function. */
 typedef struct hs_cell_introduce1_data_t {

+ 9 - 9
src/feature/hs/hs_client.c

@@ -47,6 +47,8 @@
  * public key to hs_client_service_authorization_t *. */
 static digest256map_t *client_auths = NULL;
 
+#include "trunnel/hs/cell_introduce1.h"
+
 /* Return a human-readable string for the client fetch status code. */
 static const char *
 fetch_status_to_string(hs_client_fetch_status_t status)
@@ -1067,23 +1069,21 @@ handle_introduce_ack(origin_circuit_t *circ, const uint8_t *payload,
 
   status = hs_cell_parse_introduce_ack(payload, payload_len);
   switch (status) {
-  case HS_CELL_INTRO_ACK_SUCCESS:
+  case TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS:
     ret = 0;
     handle_introduce_ack_success(circ);
     goto end;
-  case HS_CELL_INTRO_ACK_FAILURE:
-  case HS_CELL_INTRO_ACK_BADFMT:
-  case HS_CELL_INTRO_ACK_NORELAY:
+  case TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID:
+  case TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT:
+  /* It is possible that the intro point can send us an unknown status code
+   * for the NACK that we do not know about like a new code for instance.
+   * Just fallthrough so we can note down the NACK and re-extend. */
+  default:
     handle_introduce_ack_bad(circ, status);
     /* We are going to see if we have to close the circuits (IP and RP) or we
      * can re-extend to a new intro point. */
     ret = close_or_reextend_intro_circ(circ);
     break;
-  default:
-    log_info(LD_PROTOCOL, "Unknown INTRODUCE_ACK status code %u from %s",
-        status,
-        safe_str_client(extend_info_describe(circ->build_state->chosen_exit)));
-    break;
   }
 
  end:

+ 14 - 13
src/feature/hs/hs_intropoint.c

@@ -78,7 +78,7 @@ verify_establish_intro_cell(const trn_cell_establish_intro_t *cell,
   /* We only reach this function if the first byte of the cell is 0x02 which
    * means that auth_key_type is of ed25519 type, hence this check should
    * always pass. See hs_intro_received_establish_intro().  */
-  if (BUG(cell->auth_key_type != HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
+  if (BUG(cell->auth_key_type != TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519)) {
     return -1;
   }
 
@@ -318,10 +318,10 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
    * ESTABLISH_INTRO and pass it to the appropriate cell handler */
   const uint8_t first_byte = request[0];
   switch (first_byte) {
-    case HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
-    case HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
+    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0:
+    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1:
       return rend_mid_establish_intro_legacy(circ, request, request_len);
-    case HS_INTRO_AUTH_KEY_TYPE_ED25519:
+    case TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519:
       return handle_establish_intro(circ, request, request_len);
     default:
       log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -339,7 +339,7 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request,
  * Return 0 on success else a negative value on error which will close the
  * circuit. */
 static int
-send_introduce_ack_cell(or_circuit_t *circ, hs_intro_ack_status_t status)
+send_introduce_ack_cell(or_circuit_t *circ, uint16_t status)
 {
   int ret = -1;
   uint8_t *encoded_cell = NULL;
@@ -399,7 +399,7 @@ validate_introduce1_parsed_cell(const trn_cell_introduce1_t *cell)
   /* The auth key of an INTRODUCE1 should be of type ed25519 thus leading to a
    * known fixed length as well. */
   if (trn_cell_introduce1_get_auth_key_type(cell) !=
-      HS_INTRO_AUTH_KEY_TYPE_ED25519) {
+      TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519) {
     log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
            "Rejecting invalid INTRODUCE1 cell auth key type. "
            "Responding with NACK.");
@@ -436,7 +436,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
   int ret = -1;
   or_circuit_t *service_circ;
   trn_cell_introduce1_t *parsed_cell;
-  hs_intro_ack_status_t status = HS_INTRO_ACK_STATUS_SUCCESS;
+  uint16_t status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
 
   tor_assert(client_circ);
   tor_assert(request);
@@ -451,14 +451,14 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
            "Rejecting %s INTRODUCE1 cell. Responding with NACK.",
            cell_size == -1 ? "invalid" : "truncated");
     /* Inform client that the INTRODUCE1 has a bad format. */
-    status = HS_INTRO_ACK_STATUS_BAD_FORMAT;
+    status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
     goto send_ack;
   }
 
   /* Once parsed validate the cell format. */
   if (validate_introduce1_parsed_cell(parsed_cell) < 0) {
     /* Inform client that the INTRODUCE1 has bad format. */
-    status = HS_INTRO_ACK_STATUS_BAD_FORMAT;
+    status = TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT;
     goto send_ack;
   }
 
@@ -475,7 +475,7 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
                         "Responding with NACK.",
                safe_str(b64_key), client_circ->p_circ_id);
       /* Inform the client that we don't know the requested service ID. */
-      status = HS_INTRO_ACK_STATUS_UNKNOWN_ID;
+      status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
       goto send_ack;
     }
   }
@@ -486,13 +486,14 @@ handle_introduce1(or_circuit_t *client_circ, const uint8_t *request,
                                    RELAY_COMMAND_INTRODUCE2,
                                    (char *) request, request_len, NULL)) {
     log_warn(LD_PROTOCOL, "Unable to send INTRODUCE2 cell to the service.");
-    /* Inform the client that we can't relay the cell. */
-    status = HS_INTRO_ACK_STATUS_CANT_RELAY;
+    /* Inform the client that we can't relay the cell. Use the unknown ID
+     * status code since it means that we do not know the service. */
+    status = TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID;
     goto send_ack;
   }
 
   /* Success! Send an INTRODUCE_ACK success status onto the client circuit. */
-  status = HS_INTRO_ACK_STATUS_SUCCESS;
+  status = TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS;
   ret = 0;
 
  send_ack:

+ 0 - 15
src/feature/hs/hs_intropoint.h

@@ -12,21 +12,6 @@
 #include "lib/crypt_ops/crypto_curve25519.h"
 #include "feature/nodelist/torcert.h"
 
-/* Authentication key type in an ESTABLISH_INTRO cell. */
-typedef enum {
-  HS_INTRO_AUTH_KEY_TYPE_LEGACY0 = 0x00,
-  HS_INTRO_AUTH_KEY_TYPE_LEGACY1 = 0x01,
-  HS_INTRO_AUTH_KEY_TYPE_ED25519 = 0x02,
-} hs_intro_auth_key_type_t;
-
-/* INTRODUCE_ACK status code. */
-typedef enum {
-  HS_INTRO_ACK_STATUS_SUCCESS    = 0x0000,
-  HS_INTRO_ACK_STATUS_UNKNOWN_ID = 0x0001,
-  HS_INTRO_ACK_STATUS_BAD_FORMAT = 0x0002,
-  HS_INTRO_ACK_STATUS_CANT_RELAY = 0x0003,
-} hs_intro_ack_status_t;
-
 /* Object containing introduction point common data between the service and
  * the client side. */
 typedef struct hs_intropoint_t {

+ 1 - 1
src/test/test_hs_cell.c

@@ -50,7 +50,7 @@ test_gen_establish_intro_cell(void *arg)
   /* Check the contents of the cell */
   {
     /* First byte is the auth key type: make sure its correct */
-    tt_int_op(buf[0], OP_EQ, HS_INTRO_AUTH_KEY_TYPE_ED25519);
+    tt_int_op(buf[0], OP_EQ, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
     /* Next two bytes is auth key len */
     tt_int_op(ntohs(get_uint16(buf+1)), OP_EQ, ED25519_PUBKEY_LEN);
     /* Skip to the number of extensions: no extensions */

+ 2 - 2
src/test/test_hs_intropoint.c

@@ -140,7 +140,7 @@ helper_create_introduce1_cell(void)
   {
     size_t auth_key_len = sizeof(auth_key_kp.pubkey);
     trn_cell_introduce1_set_auth_key_type(cell,
-                                         HS_INTRO_AUTH_KEY_TYPE_ED25519);
+                                     TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
     trn_cell_introduce1_set_auth_key_len(cell, auth_key_len);
     trn_cell_introduce1_setlen_auth_key(cell, auth_key_len);
     uint8_t *auth_key_ptr = trn_cell_introduce1_getarray_auth_key(cell);
@@ -751,7 +751,7 @@ test_introduce1_validation(void *arg)
   ret = validate_introduce1_parsed_cell(cell);
   tt_int_op(ret, OP_EQ, -1);
   /* Reset is to correct value and make sure it's correct. */
-  cell->auth_key_type = HS_INTRO_AUTH_KEY_TYPE_ED25519;
+  cell->auth_key_type = TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519;
   ret = validate_introduce1_parsed_cell(cell);
   tt_int_op(ret, OP_EQ, 0);
 

+ 17 - 27
src/trunnel/hs/cell_introduce1.c

@@ -50,6 +50,7 @@ trn_cell_introduce1_new(void)
   trn_cell_introduce1_t *val = trunnel_calloc(1, sizeof(trn_cell_introduce1_t));
   if (NULL == val)
     return NULL;
+  val->auth_key_type = TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519;
   return val;
 }
 
@@ -121,7 +122,7 @@ trn_cell_introduce1_get_auth_key_type(const trn_cell_introduce1_t *inp)
 int
 trn_cell_introduce1_set_auth_key_type(trn_cell_introduce1_t *inp, uint8_t val)
 {
-  if (! ((val == 0 || val == 1 || val == 2))) {
+  if (! ((val == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519 || val == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0 || val == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1))) {
      TRUNNEL_SET_ERROR_CODE(inp);
      return -1;
   }
@@ -295,7 +296,7 @@ trn_cell_introduce1_check(const trn_cell_introduce1_t *obj)
     return "Object was NULL";
   if (obj->trunnel_error_code_)
     return "A set function failed on this object";
-  if (! (obj->auth_key_type == 0 || obj->auth_key_type == 1 || obj->auth_key_type == 2))
+  if (! (obj->auth_key_type == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519 || obj->auth_key_type == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0 || obj->auth_key_type == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1))
     return "Integer out of bounds";
   if (TRUNNEL_DYNARRAY_LEN(&obj->auth_key) != obj->auth_key_len)
     return "Length mismatch for auth_key";
@@ -319,7 +320,7 @@ trn_cell_introduce1_encoded_len(const trn_cell_introduce1_t *obj)
   /* Length of u8 legacy_key_id[TRUNNEL_SHA1_LEN] */
   result += TRUNNEL_SHA1_LEN;
 
-  /* Length of u8 auth_key_type IN [0, 1, 2] */
+  /* Length of u8 auth_key_type IN [TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1] */
   result += 1;
 
   /* Length of u16 auth_key_len */
@@ -367,7 +368,7 @@ trn_cell_introduce1_encode(uint8_t *output, const size_t avail, const trn_cell_i
   memcpy(ptr, obj->legacy_key_id, TRUNNEL_SHA1_LEN);
   written += TRUNNEL_SHA1_LEN; ptr += TRUNNEL_SHA1_LEN;
 
-  /* Encode u8 auth_key_type IN [0, 1, 2] */
+  /* Encode u8 auth_key_type IN [TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1] */
   trunnel_assert(written <= avail);
   if (avail - written < 1)
     goto truncated;
@@ -451,11 +452,11 @@ trn_cell_introduce1_parse_into(trn_cell_introduce1_t *obj, const uint8_t *input,
   memcpy(obj->legacy_key_id, ptr, TRUNNEL_SHA1_LEN);
   remaining -= TRUNNEL_SHA1_LEN; ptr += TRUNNEL_SHA1_LEN;
 
-  /* Parse u8 auth_key_type IN [0, 1, 2] */
+  /* Parse u8 auth_key_type IN [TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0, TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1] */
   CHECK_REMAINING(1, truncated);
   obj->auth_key_type = (trunnel_get_uint8(ptr));
   remaining -= 1; ptr += 1;
-  if (! (obj->auth_key_type == 0 || obj->auth_key_type == 1 || obj->auth_key_type == 2))
+  if (! (obj->auth_key_type == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519 || obj->auth_key_type == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0 || obj->auth_key_type == TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1))
     goto fail;
 
   /* Parse u16 auth_key_len */
@@ -550,10 +551,6 @@ trn_cell_introduce_ack_get_status(const trn_cell_introduce_ack_t *inp)
 int
 trn_cell_introduce_ack_set_status(trn_cell_introduce_ack_t *inp, uint16_t val)
 {
-  if (! ((val == 0 || val == 1 || val == 2))) {
-     TRUNNEL_SET_ERROR_CODE(inp);
-     return -1;
-  }
   inp->status = val;
   return 0;
 }
@@ -587,8 +584,6 @@ trn_cell_introduce_ack_check(const trn_cell_introduce_ack_t *obj)
     return "Object was NULL";
   if (obj->trunnel_error_code_)
     return "A set function failed on this object";
-  if (! (obj->status == 0 || obj->status == 1 || obj->status == 2))
-    return "Integer out of bounds";
   {
     const char *msg;
     if (NULL != (msg = trn_cell_extension_check(obj->extensions)))
@@ -606,7 +601,7 @@ trn_cell_introduce_ack_encoded_len(const trn_cell_introduce_ack_t *obj)
      return -1;
 
 
-  /* Length of u16 status IN [0, 1, 2] */
+  /* Length of u16 status */
   result += 2;
 
   /* Length of struct trn_cell_extension extensions */
@@ -638,7 +633,7 @@ trn_cell_introduce_ack_encode(uint8_t *output, const size_t avail, const trn_cel
   trunnel_assert(encoded_len >= 0);
 #endif
 
-  /* Encode u16 status IN [0, 1, 2] */
+  /* Encode u16 status */
   trunnel_assert(written <= avail);
   if (avail - written < 2)
     goto truncated;
@@ -687,12 +682,10 @@ trn_cell_introduce_ack_parse_into(trn_cell_introduce_ack_t *obj, const uint8_t *
   ssize_t result = 0;
   (void)result;
 
-  /* Parse u16 status IN [0, 1, 2] */
+  /* Parse u16 status */
   CHECK_REMAINING(2, truncated);
   obj->status = trunnel_ntohs(trunnel_get_uint16(ptr));
   remaining -= 2; ptr += 2;
-  if (! (obj->status == 0 || obj->status == 1 || obj->status == 2))
-    goto fail;
 
   /* Parse struct trn_cell_extension extensions */
   result = trn_cell_extension_parse(&obj->extensions, ptr, remaining);
@@ -708,9 +701,6 @@ trn_cell_introduce_ack_parse_into(trn_cell_introduce_ack_t *obj, const uint8_t *
  relay_fail:
   trunnel_assert(result < 0);
   return result;
- fail:
-  result = -1;
-  return result;
 }
 
 ssize_t
@@ -733,7 +723,7 @@ trn_cell_introduce_encrypted_new(void)
   trn_cell_introduce_encrypted_t *val = trunnel_calloc(1, sizeof(trn_cell_introduce_encrypted_t));
   if (NULL == val)
     return NULL;
-  val->onion_key_type = 1;
+  val->onion_key_type = TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR;
   return val;
 }
 
@@ -837,7 +827,7 @@ trn_cell_introduce_encrypted_get_onion_key_type(const trn_cell_introduce_encrypt
 int
 trn_cell_introduce_encrypted_set_onion_key_type(trn_cell_introduce_encrypted_t *inp, uint8_t val)
 {
-  if (! ((val == 1))) {
+  if (! ((val == TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR))) {
      TRUNNEL_SET_ERROR_CODE(inp);
      return -1;
   }
@@ -1079,7 +1069,7 @@ trn_cell_introduce_encrypted_check(const trn_cell_introduce_encrypted_t *obj)
     if (NULL != (msg = trn_cell_extension_check(obj->extensions)))
       return msg;
   }
-  if (! (obj->onion_key_type == 1))
+  if (! (obj->onion_key_type == TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR))
     return "Integer out of bounds";
   if (TRUNNEL_DYNARRAY_LEN(&obj->onion_key) != obj->onion_key_len)
     return "Length mismatch for onion_key";
@@ -1112,7 +1102,7 @@ trn_cell_introduce_encrypted_encoded_len(const trn_cell_introduce_encrypted_t *o
   /* Length of struct trn_cell_extension extensions */
   result += trn_cell_extension_encoded_len(obj->extensions);
 
-  /* Length of u8 onion_key_type IN [1] */
+  /* Length of u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR] */
   result += 1;
 
   /* Length of u16 onion_key_len */
@@ -1176,7 +1166,7 @@ trn_cell_introduce_encrypted_encode(uint8_t *output, const size_t avail, const t
     goto fail; /* XXXXXXX !*/
   written += result; ptr += result;
 
-  /* Encode u8 onion_key_type IN [1] */
+  /* Encode u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR] */
   trunnel_assert(written <= avail);
   if (avail - written < 1)
     goto truncated;
@@ -1280,11 +1270,11 @@ trn_cell_introduce_encrypted_parse_into(trn_cell_introduce_encrypted_t *obj, con
   trunnel_assert((size_t)result <= remaining);
   remaining -= result; ptr += result;
 
-  /* Parse u8 onion_key_type IN [1] */
+  /* Parse u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR] */
   CHECK_REMAINING(1, truncated);
   obj->onion_key_type = (trunnel_get_uint8(ptr));
   remaining -= 1; ptr += 1;
-  if (! (obj->onion_key_type == 1))
+  if (! (obj->onion_key_type == TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR))
     goto fail;
 
   /* Parse u16 onion_key_len */

+ 7 - 0
src/trunnel/hs/cell_introduce1.h

@@ -12,6 +12,13 @@ struct trn_cell_extension_st;
 struct link_specifier_st;
 #define TRUNNEL_SHA1_LEN 20
 #define TRUNNEL_REND_COOKIE_LEN 20
+#define TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS 0
+#define TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID 1
+#define TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT 2
+#define TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0 0
+#define TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1 1
+#define TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519 2
+#define TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR 1
 #if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_TRN_CELL_INTRODUCE1)
 struct trn_cell_introduce1_st {
   uint8_t legacy_key_id[TRUNNEL_SHA1_LEN];

+ 18 - 3
src/trunnel/hs/cell_introduce1.trunnel

@@ -12,13 +12,28 @@ extern struct link_specifier;
 const TRUNNEL_SHA1_LEN = 20;
 const TRUNNEL_REND_COOKIE_LEN = 20;
 
+/* Introduce ACK status code. */
+const TRUNNEL_HS_INTRO_ACK_STATUS_SUCCESS    = 0x0000;
+const TRUNNEL_HS_INTRO_ACK_STATUS_UNKNOWN_ID = 0x0001;
+const TRUNNEL_HS_INTRO_ACK_STATUS_BAD_FORMAT = 0x0002;
+
+/* Authentication key type. */
+const TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0 = 0x00;
+const TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1 = 0x01;
+const TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519 = 0x02;
+
+/* Onion key type. */
+const TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR = 0x01;
+
 /* INTRODUCE1 payload. See details in section 3.2.1. */
 struct trn_cell_introduce1 {
   /* Always zeroed. MUST be checked explicitly by the caller. */
   u8 legacy_key_id[TRUNNEL_SHA1_LEN];
 
   /* Authentication key material. */
-  u8 auth_key_type IN [0x00, 0x01, 0x02];
+  u8 auth_key_type IN [TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY0,
+                       TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_LEGACY1,
+                       TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519];
   u16 auth_key_len;
   u8 auth_key[auth_key_len];
 
@@ -32,7 +47,7 @@ struct trn_cell_introduce1 {
 /* INTRODUCE_ACK payload. See details in section 3.2.2. */
 struct trn_cell_introduce_ack {
   /* Status of introduction. */
-  u16 status IN [0x0000, 0x0001, 0x0002];
+  u16 status;
 
   /* Extension(s). Reserved fields. */
   struct trn_cell_extension extensions;
@@ -47,7 +62,7 @@ struct trn_cell_introduce_encrypted {
   struct trn_cell_extension extensions;
 
   /* Onion key material. */
-  u8 onion_key_type IN [0x01];
+  u8 onion_key_type IN [TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR];
   u16 onion_key_len;
   u8 onion_key[onion_key_len];