Merge remote-tracking branch 'asn/bug21334_v3'

This commit is contained in:
Nick Mathewson 2017-03-13 16:18:55 -04:00
commit 43dd9bf0fc
5 changed files with 814 additions and 300 deletions

File diff suppressed because it is too large Load diff

View file

@ -41,24 +41,11 @@
* the secret IV and MAC key length which is the length of H() output. */ * the secret IV and MAC key length which is the length of H() output. */
#define HS_DESC_ENCRYPTED_KDF_OUTPUT_LEN \ #define HS_DESC_ENCRYPTED_KDF_OUTPUT_LEN \
CIPHER256_KEY_LEN + CIPHER_IV_LEN + DIGEST256_LEN CIPHER256_KEY_LEN + CIPHER_IV_LEN + DIGEST256_LEN
/* We need to pad the plaintext version of the encrypted data section before /* Pad plaintext of superencrypted data section before encryption so that its
* encryption and it has to be a multiple of this value. */ * length is a multiple of this value. */
#define HS_DESC_PLAINTEXT_PADDING_MULTIPLE 128 #define HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE 10000
/* 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
/* Maximum length in bytes of a full hidden service descriptor. */ /* Maximum length in bytes of a full hidden service descriptor. */
#define HS_DESC_MAX_LEN 50000 /* 50kb max size */ #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 /* Key length for the descriptor symmetric encryption. As specified in the
* protocol, we use AES-256 for the encrypted section of the descriptor. The * protocol, we use AES-256 for the encrypted section of the descriptor. The
@ -68,8 +55,7 @@
/* Type of authentication in the descriptor. */ /* Type of authentication in the descriptor. */
typedef enum { typedef enum {
HS_DESC_AUTH_PASSWORD = 1, HS_DESC_AUTH_ED25519 = 1
HS_DESC_AUTH_ED25519 = 2,
} hs_desc_auth_type_t; } hs_desc_auth_type_t;
/* Type of encryption key in the descriptor. */ /* 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 /* A list of authentication types that a client must at least support one
* in order to contact the service. Contains NULL terminated strings. */ * 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? */ /* Is this descriptor a single onion service? */
unsigned int single_onion_service : 1; 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. */ * has changed. Spec specifies this as a 8 bytes positive integer. */
uint64_t revision_counter; uint64_t revision_counter;
/* Decoding only: The base64-decoded encrypted blob from the descriptor */ /* Decoding only: The b64-decoded superencrypted blob from the descriptor */
uint8_t *encrypted_blob; uint8_t *superencrypted_blob;
/* Decoding only: Size of the encrypted_blob */ /* Decoding only: Size of the superencrypted_blob */
size_t encrypted_blob_size; size_t superencrypted_blob_size;
} hs_desc_plaintext_data_t; } hs_desc_plaintext_data_t;
/* Service descriptor in its decoded form. */ /* 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 ed25519_public_key_t *signing_pubkey,
const char *encoded_desc, size_t encoded_len); const char *encoded_desc, size_t encoded_len);
STATIC void desc_intro_point_free(hs_desc_intro_point_t *ip); 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 /* HS_DESCRIPTOR_PRIVATE */
#endif /* TOR_HS_DESCRIPTOR_H */ #endif /* TOR_HS_DESCRIPTOR_H */

View file

@ -157,12 +157,16 @@ typedef enum {
R3_SUPERENCRYPTED, R3_SUPERENCRYPTED,
R3_SIGNATURE, R3_SIGNATURE,
R3_CREATE2_FORMATS, R3_CREATE2_FORMATS,
R3_AUTHENTICATION_REQUIRED, R3_INTRO_AUTH_REQUIRED,
R3_SINGLE_ONION_SERVICE, R3_SINGLE_ONION_SERVICE,
R3_INTRODUCTION_POINT, R3_INTRODUCTION_POINT,
R3_INTRO_AUTH_KEY, R3_INTRO_AUTH_KEY,
R3_INTRO_ENC_KEY, R3_INTRO_ENC_KEY,
R3_INTRO_ENC_KEY_CERTIFICATION, R3_INTRO_ENC_KEY_CERTIFICATION,
R3_DESC_AUTH_TYPE,
R3_DESC_AUTH_KEY,
R3_DESC_AUTH_CLIENT,
R3_ENCRYPTED,
R_IPO_IDENTIFIER, R_IPO_IDENTIFIER,
R_IPO_IP_ADDRESS, R_IPO_IP_ADDRESS,

View file

@ -93,8 +93,8 @@ helper_build_hs_desc(uint64_t revision_counter, uint32_t lifetime,
/* Setup encrypted data section. */ /* Setup encrypted data section. */
desc->encrypted_data.create2_ntor = 1; desc->encrypted_data.create2_ntor = 1;
desc->encrypted_data.auth_types = smartlist_new(); desc->encrypted_data.intro_auth_types = smartlist_new();
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(); desc->encrypted_data.intro_points = smartlist_new();
/* Add an intro point. */ /* Add an intro point. */
smartlist_add(desc->encrypted_data.intro_points, 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; size_t body_used = 0;
fetch_from_buf_http(TO_CONN(conn)->outbuf, &headers, MAX_HEADERS_SIZE, 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); tor_free(headers);
} }

View file

@ -15,6 +15,9 @@
#include "test.h" #include "test.h"
#include "torcert.h" #include "torcert.h"
#include "test_helpers.h"
#include "log_test_helpers.h"
static hs_desc_intro_point_t * static hs_desc_intro_point_t *
helper_build_intro_point(const ed25519_keypair_t *blinded_kp, time_t now, helper_build_intro_point(const ed25519_keypair_t *blinded_kp, time_t now,
const char *addr, int legacy) 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. */ /* Setup encrypted data section. */
desc->encrypted_data.create2_ntor = 1; 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; 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(); desc->encrypted_data.intro_points = smartlist_new();
if (!no_ip) { if (!no_ip) {
/* Add four intro points. */ /* Add four intro points. */
@ -157,14 +160,17 @@ helper_compare_hs_desc(const hs_descriptor_t *desc1,
desc2->encrypted_data.create2_ntor); desc2->encrypted_data.create2_ntor);
/* Authentication type. */ /* Authentication type. */
tt_int_op(!!desc1->encrypted_data.auth_types, ==, tt_int_op(!!desc1->encrypted_data.intro_auth_types, ==,
!!desc2->encrypted_data.auth_types); !!desc2->encrypted_data.intro_auth_types);
if (desc1->encrypted_data.auth_types && desc2->encrypted_data.auth_types) { if (desc1->encrypted_data.intro_auth_types &&
tt_int_op(smartlist_len(desc1->encrypted_data.auth_types), ==, desc2->encrypted_data.intro_auth_types) {
smartlist_len(desc2->encrypted_data.auth_types)); tt_int_op(smartlist_len(desc1->encrypted_data.intro_auth_types), ==,
for (int i = 0; i < smartlist_len(desc1->encrypted_data.auth_types); i++) { smartlist_len(desc2->encrypted_data.intro_auth_types));
tt_str_op(smartlist_get(desc1->encrypted_data.auth_types, i), OP_EQ, for (int i = 0;
smartlist_get(desc2->encrypted_data.auth_types, i)); 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 /* 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. */ * to give 256. With l = 127, ceiled division gives 1 then times 128. */
#define PADDING_EXPECTED_LEN(l) \ #define PADDING_EXPECTED_LEN(l) \
CEIL_DIV(l, HS_DESC_PLAINTEXT_PADDING_MULTIPLE) * \ CEIL_DIV(l, HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE) * \
HS_DESC_PLAINTEXT_PADDING_MULTIPLE HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE
(void) arg; (void) arg;
{ /* test #1: no padding */ { /* test #1: no padding */
plaintext_len = HS_DESC_PLAINTEXT_PADDING_MULTIPLE; plaintext_len = HS_DESC_SUPERENC_PLAINTEXT_PAD_MULTIPLE;
plaintext = tor_malloc(plaintext_len); plaintext = tor_malloc(plaintext_len);
padded_len = build_plaintext_padding(plaintext, plaintext_len, padded_len = build_plaintext_padding(plaintext, plaintext_len,
&padded_plaintext); &padded_plaintext);
@ -333,7 +339,7 @@ test_descriptor_padding(void *arg)
} }
{ /* test #2: one byte padding? */ { /* 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); plaintext = tor_malloc(plaintext_len);
padded_plaintext = NULL; padded_plaintext = NULL;
padded_len = build_plaintext_padding(plaintext, plaintext_len, padded_len = build_plaintext_padding(plaintext, plaintext_len,
@ -350,7 +356,7 @@ test_descriptor_padding(void *arg)
} }
{ /* test #3: Lots more bytes of padding? */ { /* 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); plaintext = tor_malloc(plaintext_len);
padded_plaintext = NULL; padded_plaintext = NULL;
padded_len = build_plaintext_padding(plaintext, plaintext_len, padded_len = build_plaintext_padding(plaintext, plaintext_len,
@ -587,19 +593,11 @@ test_encrypted_data_len(void *arg)
/* No length, error. */ /* No length, error. */
ret = encrypted_data_length_is_valid(0); ret = encrypted_data_length_is_valid(0);
tt_int_op(ret, OP_EQ, 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. */ /* Valid value. */
value = HS_DESC_PADDED_PLAINTEXT_MAX_LEN + HS_DESC_ENCRYPTED_SALT_LEN + value = HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN + 1;
DIGEST256_LEN;
ret = encrypted_data_length_is_valid(value); ret = encrypted_data_length_is_valid(value);
tt_int_op(ret, OP_EQ, 1); tt_int_op(ret, OP_EQ, 1);
/* XXX: Test maximum possible size. */
done: done:
; ;
} }
@ -1006,6 +1004,103 @@ test_desc_signature(void *arg)
tor_free(data); 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[] = { struct testcase_t hs_descriptor[] = {
/* Encoding tests. */ /* Encoding tests. */
{ "cert_encoding", test_cert_encoding, TT_FORK, { "cert_encoding", test_cert_encoding, TT_FORK,
@ -1035,6 +1130,9 @@ struct testcase_t hs_descriptor[] = {
{ "desc_signature", test_desc_signature, TT_FORK, { "desc_signature", test_desc_signature, TT_FORK,
NULL, NULL }, NULL, NULL },
{ "parse_hs_desc_superencrypted", test_parse_hs_desc_superencrypted,
TT_FORK, NULL, NULL },
END_OF_TESTCASES END_OF_TESTCASES
}; };