Commit 43dd9bf0 authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

Merge remote-tracking branch 'asn/bug21334_v3'

parents 118d7018 61f318b1
Loading
Loading
Loading
Loading
+671 −247

File changed.

Preview size limit exceeded, changes collapsed.

+11 −23
Original line number Diff line number Diff line
@@ -41,24 +41,11 @@
 * the secret IV and MAC key length which is the length of H() output. */
#define HS_DESC_ENCRYPTED_KDF_OUTPUT_LEN \
  CIPHER256_KEY_LEN + CIPHER_IV_LEN + DIGEST256_LEN
/* We need to pad the plaintext version of the encrypted data section before
 * encryption and it has to be a multiple of this value. */
#define HS_DESC_PLAINTEXT_PADDING_MULTIPLE 128
/* XXX: Let's make sure this makes sense as an upper limit for the padded
 * plaintext section. Then we should enforce it as now only an assert will be
 * triggered if we are above it. */
/* Once padded, this is the maximum length in bytes for the plaintext. */
#define HS_DESC_PADDED_PLAINTEXT_MAX_LEN 8192
/* Minimum length in bytes of the encrypted portion of the descriptor. */
#define HS_DESC_ENCRYPTED_MIN_LEN \
  HS_DESC_ENCRYPTED_SALT_LEN + \
  HS_DESC_PLAINTEXT_PADDING_MULTIPLE + DIGEST256_LEN
/* Pad plaintext of superencrypted data section before encryption so that its
 * length is a multiple of this value. */
#define HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE 10000
/* Maximum length in bytes of a full hidden service descriptor. */
#define HS_DESC_MAX_LEN 50000 /* 50kb max size */
/* The minimum amount of fields a descriptor should contain. The parsing of
 * the fields are version specific so the only required field, as a generic
 * view of a descriptor, is 1 that is the version field. */
#define HS_DESC_PLAINTEXT_MIN_FIELDS 1

/* Key length for the descriptor symmetric encryption. As specified in the
 * protocol, we use AES-256 for the encrypted section of the descriptor. The
@@ -68,8 +55,7 @@

/* Type of authentication in the descriptor. */
typedef enum {
  HS_DESC_AUTH_PASSWORD = 1,
  HS_DESC_AUTH_ED25519  = 2,
  HS_DESC_AUTH_ED25519 = 1
} hs_desc_auth_type_t;

/* Type of encryption key in the descriptor. */
@@ -132,7 +118,7 @@ typedef struct hs_desc_encrypted_data_t {

  /* A list of authentication types that a client must at least support one
   * in order to contact the service. Contains NULL terminated strings. */
  smartlist_t *auth_types;
  smartlist_t *intro_auth_types;

  /* Is this descriptor a single onion service? */
  unsigned int single_onion_service : 1;
@@ -167,11 +153,11 @@ typedef struct hs_desc_plaintext_data_t {
   * has changed. Spec specifies this as a 8 bytes positive integer. */
  uint64_t revision_counter;

  /* Decoding only: The base64-decoded encrypted blob from the descriptor */
  uint8_t *encrypted_blob;
  /* Decoding only: The b64-decoded superencrypted blob from the descriptor */
  uint8_t *superencrypted_blob;

  /* Decoding only: Size of the encrypted_blob */
  size_t encrypted_blob_size;
  /* Decoding only: Size of the superencrypted_blob */
  size_t superencrypted_blob_size;
} hs_desc_plaintext_data_t;

/* Service descriptor in its decoded form. */
@@ -242,6 +228,8 @@ STATIC int desc_sig_is_valid(const char *b64_sig,
                             const ed25519_public_key_t *signing_pubkey,
                             const char *encoded_desc, size_t encoded_len);
STATIC void desc_intro_point_free(hs_desc_intro_point_t *ip);
STATIC size_t decode_superencrypted(const char *message, size_t message_len,
                                   uint8_t **encrypted_out);
#endif /* HS_DESCRIPTOR_PRIVATE */

#endif /* TOR_HS_DESCRIPTOR_H */
+5 −1
Original line number Diff line number Diff line
@@ -157,12 +157,16 @@ typedef enum {
  R3_SUPERENCRYPTED,
  R3_SIGNATURE,
  R3_CREATE2_FORMATS,
  R3_AUTHENTICATION_REQUIRED,
  R3_INTRO_AUTH_REQUIRED,
  R3_SINGLE_ONION_SERVICE,
  R3_INTRODUCTION_POINT,
  R3_INTRO_AUTH_KEY,
  R3_INTRO_ENC_KEY,
  R3_INTRO_ENC_KEY_CERTIFICATION,
  R3_DESC_AUTH_TYPE,
  R3_DESC_AUTH_KEY,
  R3_DESC_AUTH_CLIENT,
  R3_ENCRYPTED,

  R_IPO_IDENTIFIER,
  R_IPO_IP_ADDRESS,
+3 −3
Original line number Diff line number Diff line
@@ -93,8 +93,8 @@ helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime,

  /* Setup encrypted data section. */
  desc->encrypted_data.create2_ntor = 1;
  desc->encrypted_data.auth_types = smartlist_new();
  smartlist_add(desc->encrypted_data.auth_types, tor_strdup("ed25519"));
  desc->encrypted_data.intro_auth_types = smartlist_new();
  smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
  desc->encrypted_data.intro_points = smartlist_new();
  /* Add an intro point. */
  smartlist_add(desc->encrypted_data.intro_points,
@@ -333,7 +333,7 @@ helper_fetch_desc_from_hsdir(const ed25519_public_key_t *blinded_key)
    size_t body_used = 0;

    fetch_from_buf_http(TO_CONN(conn)->outbuf, &headers, MAX_HEADERS_SIZE,
                        &received_desc, &body_used, 10000, 0);
                        &received_desc, &body_used, HS_DESC_MAX_LEN, 0);
    tor_free(headers);
  }

+122 −24
Original line number Diff line number Diff line
@@ -15,6 +15,9 @@
#include "test.h"
#include "torcert.h"

#include "test_helpers.h"
#include "log_test_helpers.h"

static hs_desc_intro_point_t *
helper_build_intro_point(const ed25519_keypair_t *blinded_kp, time_t now,
                         const char *addr, int legacy)
@@ -105,9 +108,9 @@ helper_build_hs_desc(unsigned int no_ip, ed25519_public_key_t *signing_pubkey)

  /* Setup encrypted data section. */
  desc->encrypted_data.create2_ntor = 1;
  desc->encrypted_data.auth_types = smartlist_new();
  desc->encrypted_data.intro_auth_types = smartlist_new();
  desc->encrypted_data.single_onion_service = 1;
  smartlist_add(desc->encrypted_data.auth_types, tor_strdup("ed25519"));
  smartlist_add(desc->encrypted_data.intro_auth_types, tor_strdup("ed25519"));
  desc->encrypted_data.intro_points = smartlist_new();
  if (!no_ip) {
    /* Add four intro points. */
@@ -157,14 +160,17 @@ helper_compare_hs_desc(const hs_descriptor_t *desc1,
             desc2->encrypted_data.create2_ntor);

  /* Authentication type. */
  tt_int_op(!!desc1->encrypted_data.auth_types, ==,
            !!desc2->encrypted_data.auth_types);
  if (desc1->encrypted_data.auth_types && desc2->encrypted_data.auth_types) {
    tt_int_op(smartlist_len(desc1->encrypted_data.auth_types), ==,
              smartlist_len(desc2->encrypted_data.auth_types));
    for (int i = 0; i < smartlist_len(desc1->encrypted_data.auth_types); i++) {
      tt_str_op(smartlist_get(desc1->encrypted_data.auth_types, i), OP_EQ,
                smartlist_get(desc2->encrypted_data.auth_types, i));
  tt_int_op(!!desc1->encrypted_data.intro_auth_types, ==,
            !!desc2->encrypted_data.intro_auth_types);
  if (desc1->encrypted_data.intro_auth_types &&
      desc2->encrypted_data.intro_auth_types) {
    tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), ==,
              smartlist_len(desc2->encrypted_data.intro_auth_types));
    for (int i = 0;
         i < smartlist_len(desc1->encrypted_data.intro_auth_types);
         i++) {
      tt_str_op(smartlist_get(desc1->encrypted_data.intro_auth_types, i),OP_EQ,
                smartlist_get(desc2->encrypted_data.intro_auth_types, i));
    }
  }

@@ -311,13 +317,13 @@ test_descriptor_padding(void *arg)
/* Example: if l = 129, the ceiled division gives 2 and then multiplied by 128
 * to give 256. With l = 127, ceiled division gives 1 then times 128. */
#define PADDING_EXPECTED_LEN(l) \
  CEIL_DIV(l, HS_DESC_PLAINTEXT_PADDING_MULTIPLE) * \
  HS_DESC_PLAINTEXT_PADDING_MULTIPLE
  CEIL_DIV(l, HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE) * \
  HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE

  (void) arg;

  { /* test #1: no padding */
    plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE;
    plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE;
    plaintext = tor_malloc(plaintext_len);
    padded_len = build_plaintext_padding(plaintext, plaintext_len,
                                         &padded_plaintext);
@@ -333,7 +339,7 @@ test_descriptor_padding(void *arg)
  }

  { /* test #2: one byte padding? */
    plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE - 1;
    plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE - 1;
    plaintext = tor_malloc(plaintext_len);
    padded_plaintext = NULL;
    padded_len = build_plaintext_padding(plaintext, plaintext_len,
@@ -350,7 +356,7 @@ test_descriptor_padding(void *arg)
  }

  { /* test #3: Lots more bytes of padding? */
    plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE + 1;
    plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE + 1;
    plaintext = tor_malloc(plaintext_len);
    padded_plaintext = NULL;
    padded_len = build_plaintext_padding(plaintext, plaintext_len,
@@ -587,19 +593,11 @@ test_encrypted_data_len(void *arg)
  /* No length, error. */
  ret = encrypted_data_length_is_valid(0);
  tt_int_op(ret, OP_EQ, 0);
  /* Not a multiple of our encryption algorithm (thus no padding). It's
   * suppose to be aligned on HS_DESC_PLAINTEXT_PADDING_MULTIPLE. */
  value = HS_DESC_PLAINTEXT_PADDING_MULTIPLE * 10 - 1;
  ret = encrypted_data_length_is_valid(value);
  tt_int_op(ret, OP_EQ, 0);
  /* Valid value. */
  value = HS_DESC_PADDED_PLAINTEXT_MAX_LEN + HS_DESC_ENCRYPTED_SALT_LEN +
          DIGEST256_LEN;
  value = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN + 1;
  ret = encrypted_data_length_is_valid(value);
  tt_int_op(ret, OP_EQ, 1);

  /* XXX: Test maximum possible size. */

 done:
  ;
}
@@ -1006,6 +1004,103 @@ test_desc_signature(void *arg)
  tor_free(data);
}

/* bad desc auth type */
const char bad_superencrypted_text1[] = "desc-auth-type scoobysnack\n"
  "desc-auth-ephemeral-key A/O8DVtnUheb3r1JqoB8uJB7wxXL1XJX3eny4yB+eFA=\n"
  "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
  "encrypted\n"
  "-----BEGIN MESSAGE-----\n"
  "YmVpbmcgb24gbW91bnRhaW5zLCB0aGlua2luZyBhYm91dCBjb21wdXRlcnMsIGlzIG5vdC"
  "BiYWQgYXQgYWxs\n"
  "-----END MESSAGE-----\n";

/* bad ephemeral key */
const char bad_superencrypted_text2[] = "desc-auth-type x25519\n"
  "desc-auth-ephemeral-key differentalphabet\n"
  "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
  "encrypted\n"
  "-----BEGIN MESSAGE-----\n"
  "YmVpbmcgb24gbW91bnRhaW5zLCB0aGlua2luZyBhYm91dCBjb21wdXRlcnMsIGlzIG5vdC"
  "BiYWQgYXQgYWxs\n"
  "-----END MESSAGE-----\n";

/* bad encrypted msg */
const char bad_superencrypted_text3[] = "desc-auth-type x25519\n"
  "desc-auth-ephemeral-key A/O8DVtnUheb3r1JqoB8uJB7wxXL1XJX3eny4yB+eFA=\n"
  "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
  "encrypted\n"
  "-----BEGIN MESSAGE-----\n"
  "SO SMALL NOT GOOD\n"
  "-----END MESSAGE-----\n";

const char correct_superencrypted_text[] = "desc-auth-type x25519\n"
  "desc-auth-ephemeral-key A/O8DVtnUheb3r1JqoB8uJB7wxXL1XJX3eny4yB+eFA=\n"
  "auth-client oiNrQB8WwKo S5D02W7vKgiWIMygrBl8RQ FB//SfOBmLEx1kViEWWL1g\n"
  "auth-client Od09Qu636Qo /PKLzqewAdS/+0+vZC+MvQ dpw4NFo13zDnuPz45rxrOg\n"
  "auth-client JRr840iGYN0 8s8cxYqF7Lx23+NducC4Qg zAafl4wPLURkuEjJreZq1g\n"
  "encrypted\n"
  "-----BEGIN MESSAGE-----\n"
  "YmVpbmcgb24gbW91bnRhaW5zLCB0aGlua2luZyBhYm91dCBjb21wdXRlcnMsIGlzIG5vdC"
  "BiYWQgYXQgYWxs\n"
  "-----END MESSAGE-----\n";

const char correct_encrypted_plaintext[] = "being on mountains, "
  "thinking about computers, is not bad at all";

static void
test_parse_hs_desc_superencrypted(void *arg)
{
  (void) arg;
  int retval;
  uint8_t *encrypted_out = NULL;

  {
    setup_full_capture_of_logs(LOG_WARN);
    retval = decode_superencrypted(bad_superencrypted_text1,
                                   strlen(bad_superencrypted_text1),
                                   &encrypted_out);
    tt_int_op(retval, ==, 0);
    tt_assert(!encrypted_out);
    expect_log_msg_containing("Unrecognized desc auth type");
    teardown_capture_of_logs();
  }

  {
    setup_full_capture_of_logs(LOG_WARN);
    retval = decode_superencrypted(bad_superencrypted_text2,
                                   strlen(bad_superencrypted_text2),
                                   &encrypted_out);
    tt_int_op(retval, ==, 0);
    tt_assert(!encrypted_out);
    expect_log_msg_containing("Bogus desc auth key in HS desc");
    teardown_capture_of_logs();
  }

  {
    setup_full_capture_of_logs(LOG_WARN);
    retval = decode_superencrypted(bad_superencrypted_text3,
                                   strlen(bad_superencrypted_text3),
                                   &encrypted_out);
    tt_int_op(retval, ==, 0);
    tt_assert(!encrypted_out);
    expect_log_msg_containing("Length of descriptor\'s encrypted data "
                              "is too small.");
    teardown_capture_of_logs();
  }

  /* Now finally the good one */
  retval = decode_superencrypted(correct_superencrypted_text,
                                 strlen(correct_superencrypted_text),
                                 &encrypted_out);

  tt_int_op(retval, ==, strlen(correct_encrypted_plaintext));
  tt_mem_op(encrypted_out, OP_EQ, correct_encrypted_plaintext,
            strlen(correct_encrypted_plaintext));

 done:
  tor_free(encrypted_out);
}

struct testcase_t hs_descriptor[] = {
  /* Encoding tests. */
  { "cert_encoding", test_cert_encoding, TT_FORK,
@@ -1035,6 +1130,9 @@ struct testcase_t hs_descriptor[] = {
  { "desc_signature", test_desc_signature, TT_FORK,
    NULL, NULL },

  { "parse_hs_desc_superencrypted", test_parse_hs_desc_superencrypted,
    TT_FORK, NULL, NULL },

  END_OF_TESTCASES
};