diff options
Diffstat (limited to 'src/feature/hs/hs_descriptor.c')
-rw-r--r-- | src/feature/hs/hs_descriptor.c | 604 |
1 files changed, 245 insertions, 359 deletions
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index f74bb97ee2..6e448b322e 100644 --- a/src/feature/hs/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Tor Project, Inc. */ +/* Copyright (c) 2016-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,7 +55,9 @@ /* For unit tests.*/ #define HS_DESCRIPTOR_PRIVATE +#include <stdbool.h> #include "core/or/or.h" +#include "app/config/config.h" #include "trunnel/ed25519_cert.h" /* Trunnel interface. */ #include "feature/hs/hs_descriptor.h" #include "core/or/circuitbuild.h" @@ -102,7 +104,7 @@ #define str_desc_auth_client "auth-client" #define str_encrypted "encrypted" -/* Authentication supported types. */ +/** Authentication supported types. */ static const struct { hs_desc_auth_type_t type; const char *identifier; @@ -112,7 +114,7 @@ static const struct { { 0, NULL } }; -/* Descriptor ruleset. */ +/** Descriptor ruleset. */ static token_rule_t hs_desc_v3_token_table[] = { T1_START(str_hs_desc, R_HS_DESCRIPTOR, EQ(1), NO_OBJ), T1(str_lifetime, R3_DESC_LIFETIME, EQ(1), NO_OBJ), @@ -123,7 +125,7 @@ static token_rule_t hs_desc_v3_token_table[] = { END_OF_TABLE }; -/* Descriptor ruleset for the superencrypted section. */ +/** Descriptor ruleset for the superencrypted section. */ static token_rule_t hs_desc_superencrypted_v3_token_table[] = { T1_START(str_desc_auth_type, R3_DESC_AUTH_TYPE, GE(1), NO_OBJ), T1(str_desc_auth_key, R3_DESC_AUTH_KEY, GE(1), NO_OBJ), @@ -132,7 +134,7 @@ static token_rule_t hs_desc_superencrypted_v3_token_table[] = { END_OF_TABLE }; -/* Descriptor ruleset for the encrypted section. */ +/** Descriptor ruleset for the encrypted section. */ static token_rule_t hs_desc_encrypted_v3_token_table[] = { T1_START(str_create2_formats, R3_CREATE2_FORMATS, CONCAT_ARGS, NO_OBJ), T01(str_intro_auth_required, R3_INTRO_AUTH_REQUIRED, GE(1), NO_OBJ), @@ -140,7 +142,7 @@ static token_rule_t hs_desc_encrypted_v3_token_table[] = { END_OF_TABLE }; -/* Descriptor ruleset for the introduction points section. */ +/** Descriptor ruleset for the introduction points section. */ static token_rule_t hs_desc_intro_point_v3_token_table[] = { T1_START(str_intro_point, R3_INTRODUCTION_POINT, EQ(1), NO_OBJ), T1N(str_ip_onion_key, R3_INTRO_ONION_KEY, GE(2), OBJ_OK), @@ -152,7 +154,7 @@ static token_rule_t hs_desc_intro_point_v3_token_table[] = { END_OF_TABLE }; -/* Using a key, salt and encrypted payload, build a MAC and put it in mac_out. +/** Using a key, salt and encrypted payload, build a MAC and put it in mac_out. * We use SHA3-256 for the MAC computation. * This function can't fail. */ static void @@ -184,7 +186,7 @@ build_mac(const uint8_t *mac_key, size_t mac_key_len, crypto_digest_free(digest); } -/* Using a secret data and a given decriptor object, build the secret +/** Using a secret data and a given descriptor object, build the secret * input needed for the KDF. * * secret_input = SECRET_DATA | subcredential | INT_8(revision_counter) @@ -211,7 +213,7 @@ build_secret_input(const hs_descriptor_t *desc, memcpy(secret_input, secret_data, secret_data_len); offset += secret_data_len; /* Copy subcredential. */ - memcpy(secret_input + offset, desc->subcredential, DIGEST256_LEN); + memcpy(secret_input + offset, desc->subcredential.subcred, DIGEST256_LEN); offset += DIGEST256_LEN; /* Copy revision counter value. */ set_uint64(secret_input + offset, @@ -224,7 +226,7 @@ build_secret_input(const hs_descriptor_t *desc, return secret_input_len; } -/* Do the KDF construction and put the resulting data in key_out which is of +/** Do the KDF construction and put the resulting data in key_out which is of * key_out_len length. It uses SHAKE-256 as specified in the spec. */ static void build_kdf_key(const hs_descriptor_t *desc, @@ -269,7 +271,7 @@ build_kdf_key(const hs_descriptor_t *desc, tor_free(secret_input); } -/* Using the given descriptor, secret data, and salt, run it through our +/** Using the given descriptor, secret data, and salt, run it through our * KDF function and then extract a secret key in key_out, the IV in iv_out * and MAC in mac_out. This function can't fail. */ static void @@ -308,7 +310,7 @@ build_secret_key_iv_mac(const hs_descriptor_t *desc, /* === ENCODING === */ -/* Encode the given link specifier objects into a newly allocated string. +/** Encode the given link specifier objects into a newly allocated string. * This can't fail so caller can always assume a valid string being * returned. */ STATIC char * @@ -324,12 +326,11 @@ encode_link_specifiers(const smartlist_t *specs) link_specifier_list_set_n_spec(lslist, smartlist_len(specs)); - SMARTLIST_FOREACH_BEGIN(specs, const hs_desc_link_specifier_t *, + SMARTLIST_FOREACH_BEGIN(specs, const link_specifier_t *, spec) { - link_specifier_t *ls = hs_desc_lspec_to_trunnel(spec); - if (ls) { - link_specifier_list_add_spec(lslist, ls); - } + link_specifier_t *ls = link_specifier_dup(spec); + tor_assert(ls); + link_specifier_list_add_spec(lslist, ls); } SMARTLIST_FOREACH_END(spec); { @@ -356,7 +357,7 @@ encode_link_specifiers(const smartlist_t *specs) return encoded_b64; } -/* Encode an introduction point legacy key and certificate. Return a newly +/** Encode an introduction point legacy key and certificate. Return a newly * allocated string with it. On failure, return NULL. */ static char * encode_legacy_key(const hs_desc_intro_point_t *ip) @@ -393,7 +394,7 @@ encode_legacy_key(const hs_desc_intro_point_t *ip) return encoded; } -/* Encode an introduction point encryption key and certificate. Return a newly +/** Encode an introduction point encryption key and certificate. Return a newly * allocated string with it. On failure, return NULL. */ static char * encode_enc_key(const hs_desc_intro_point_t *ip) @@ -404,9 +405,7 @@ encode_enc_key(const hs_desc_intro_point_t *ip) tor_assert(ip); /* Base64 encode the encryption key for the "enc-key" field. */ - if (curve25519_public_to_base64(key_b64, &ip->enc_key) < 0) { - goto done; - } + curve25519_public_to_base64(key_b64, &ip->enc_key, true); if (tor_cert_encode_ed22519(ip->enc_key_cert, &encoded_cert) < 0) { goto done; } @@ -421,8 +420,8 @@ encode_enc_key(const hs_desc_intro_point_t *ip) return encoded; } -/* Encode an introduction point onion key. Return a newly allocated string - * with it. On failure, return NULL. */ +/** Encode an introduction point onion key. Return a newly allocated string + * with it. Can not fail. */ static char * encode_onion_key(const hs_desc_intro_point_t *ip) { @@ -432,16 +431,13 @@ encode_onion_key(const hs_desc_intro_point_t *ip) tor_assert(ip); /* Base64 encode the encryption key for the "onion-key" field. */ - if (curve25519_public_to_base64(key_b64, &ip->onion_key) < 0) { - goto done; - } + curve25519_public_to_base64(key_b64, &ip->onion_key, true); tor_asprintf(&encoded, "%s ntor %s", str_ip_onion_key, key_b64); - done: return encoded; } -/* Encode an introduction point object and return a newly allocated string +/** Encode an introduction point object and return a newly allocated string * with it. On failure, return NULL. */ static char * encode_intro_point(const ed25519_public_key_t *sig_key, @@ -511,7 +507,7 @@ encode_intro_point(const ed25519_public_key_t *sig_key, return encoded_ip; } -/* Given a source length, return the new size including padding for the +/** Given a source length, return the new size including padding for the * plaintext encryption. */ static size_t compute_padded_plaintext_length(size_t plaintext_len) @@ -531,7 +527,7 @@ compute_padded_plaintext_length(size_t plaintext_len) return plaintext_padded_len; } -/* Given a buffer, pad it up to the encrypted section padding requirement. Set +/** Given a buffer, pad it up to the encrypted section padding requirement. Set * the newly allocated string in padded_out and return the length of the * padded buffer. */ STATIC size_t @@ -554,7 +550,7 @@ build_plaintext_padding(const char *plaintext, size_t plaintext_len, return padded_len; } -/* Using a key, IV and plaintext data of length plaintext_len, create the +/** Using a key, IV and plaintext data of length plaintext_len, create the * encrypted section by encrypting it and setting encrypted_out with the * data. Return size of the encrypted data buffer. */ static size_t @@ -599,7 +595,7 @@ build_encrypted(const uint8_t *key, const uint8_t *iv, const char *plaintext, return encrypted_len; } -/* Encrypt the given <b>plaintext</b> buffer using <b>desc</b> and +/** Encrypt the given <b>plaintext</b> buffer using <b>desc</b> and * <b>secret_data</b> to get the keys. Set encrypted_out with the encrypted * data and return the length of it. <b>is_superencrypted_layer</b> is set * if this is the outer encrypted layer of the descriptor. */ @@ -669,7 +665,7 @@ encrypt_descriptor_data(const hs_descriptor_t *desc, return final_blob_len; } -/* Create and return a string containing a client-auth entry. It's the +/** Create and return a string containing a client-auth entry. It's the * responsibility of the caller to free the returned string. This function * will never fail. */ static char * @@ -684,7 +680,7 @@ get_auth_client_str(const hs_desc_authorized_client_t *client) char encrypted_cookie_b64[HS_DESC_ENCRYPED_COOKIE_LEN * 2]; #define ASSERT_AND_BASE64(field) STMT_BEGIN \ - tor_assert(!tor_mem_is_zero((char *) client->field, \ + tor_assert(!fast_mem_is_zero((char *) client->field, \ sizeof(client->field))); \ ret = base64_encode_nopad(field##_b64, sizeof(field##_b64), \ client->field, sizeof(client->field)); \ @@ -739,7 +735,7 @@ get_all_auth_client_lines(const hs_descriptor_t *desc) return auth_client_lines_str; } -/* Create the inner layer of the descriptor (which includes the intro points, +/** Create the inner layer of the descriptor (which includes the intro points, * etc.). Return a newly-allocated string with the layer plaintext, or NULL if * an error occurred. It's the responsibility of the caller to free the * returned string. */ @@ -795,11 +791,11 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc) return encoded_str; } -/* Create the middle layer of the descriptor, which includes the client auth +/** Create the middle layer of the descriptor, which includes the client auth * data and the encrypted inner layer (provided as a base64 string at * <b>layer2_b64_ciphertext</b>). Return a newly-allocated string with the - * layer plaintext, or NULL if an error occurred. It's the responsibility of - * the caller to free the returned string. */ + * layer plaintext. It's the responsibility of the caller to free the returned + * string. Can not fail. */ static char * get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, const char *layer2_b64_ciphertext) @@ -815,13 +811,10 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, const curve25519_public_key_t *ephemeral_pubkey; ephemeral_pubkey = &desc->superencrypted_data.auth_ephemeral_pubkey; - tor_assert(!tor_mem_is_zero((char *) ephemeral_pubkey->public_key, + tor_assert(!fast_mem_is_zero((char *) ephemeral_pubkey->public_key, CURVE25519_PUBKEY_LEN)); - if (curve25519_public_to_base64(ephemeral_key_base64, - ephemeral_pubkey) < 0) { - goto done; - } + curve25519_public_to_base64(ephemeral_key_base64, ephemeral_pubkey, true); smartlist_add_asprintf(lines, "%s %s\n", str_desc_auth_key, ephemeral_key_base64); @@ -846,7 +839,6 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, layer1_str = smartlist_join_strings(lines, "", 0, NULL); - done: /* We need to memwipe all lines because it contains the ephemeral key */ SMARTLIST_FOREACH(lines, char *, a, memwipe(a, 0, strlen(a))); SMARTLIST_FOREACH(lines, char *, a, tor_free(a)); @@ -855,7 +847,7 @@ get_outer_encrypted_layer_plaintext(const hs_descriptor_t *desc, return layer1_str; } -/* Encrypt <b>encoded_str</b> into an encrypted blob and then base64 it before +/** Encrypt <b>encoded_str</b> into an encrypted blob and then base64 it before * returning it. <b>desc</b> is provided to derive the encryption * keys. <b>secret_data</b> is also proved to derive the encryption keys. * <b>is_superencrypted_layer</b> is set if <b>encoded_str</b> is the @@ -888,7 +880,7 @@ encrypt_desc_data_and_base64(const hs_descriptor_t *desc, return enc_b64; } -/* Generate the secret data which is used to encrypt/decrypt the descriptor. +/** Generate the secret data which is used to encrypt/decrypt the descriptor. * * SECRET_DATA = blinded-public-key * SECRET_DATA = blinded-public-key | descriptor_cookie @@ -935,7 +927,7 @@ build_secret_data(const ed25519_public_key_t *blinded_pubkey, return secret_data_len; } -/* Generate and encode the superencrypted portion of <b>desc</b>. This also +/** Generate and encode the superencrypted portion of <b>desc</b>. This also * involves generating the encrypted portion of the descriptor, and performing * the superencryption. A newly allocated NUL-terminated string pointer * containing the encrypted encoded blob is put in encrypted_blob_out. Return 0 @@ -1009,7 +1001,7 @@ encode_superencrypted_data(const hs_descriptor_t *desc, return ret; } -/* Encode a v3 HS descriptor. Return 0 on success and set encoded_out to the +/** Encode a v3 HS descriptor. Return 0 on success and set encoded_out to the * newly allocated string of the encoded descriptor. On error, -1 is returned * and encoded_out is untouched. */ static int @@ -1028,10 +1020,6 @@ desc_encode_v3(const hs_descriptor_t *desc, tor_assert(encoded_out); tor_assert(desc->plaintext_data.version == 3); - if (BUG(desc->subcredential == NULL)) { - goto err; - } - /* Build the non-encrypted values. */ { char *encoded_cert; @@ -1092,11 +1080,7 @@ desc_encode_v3(const hs_descriptor_t *desc, tor_free(encoded_str); goto err; } - if (ed25519_signature_to_base64(ed_sig_b64, &sig) < 0) { - log_warn(LD_BUG, "Can't base64 encode descriptor signature!"); - tor_free(encoded_str); - goto err; - } + ed25519_signature_to_base64(ed_sig_b64, &sig); /* Create the signature line. */ smartlist_add_asprintf(lines, "%s %s", str_signature, ed_sig_b64); } @@ -1125,7 +1109,7 @@ desc_encode_v3(const hs_descriptor_t *desc, /* === DECODING === */ -/* Given the token tok for an auth client, decode it as +/** Given the token tok for an auth client, decode it as * hs_desc_authorized_client_t. tok->args MUST contain at least 3 elements * Return 0 on success else -1 on failure. */ static int @@ -1161,7 +1145,7 @@ decode_auth_client(const directory_token_t *tok, return ret; } -/* Given an encoded string of the link specifiers, return a newly allocated +/** Given an encoded string of the link specifiers, return a newly allocated * list of decoded link specifiers. Return NULL on error. */ STATIC smartlist_t * decode_link_specifiers(const char *encoded) @@ -1190,52 +1174,22 @@ decode_link_specifiers(const char *encoded) results = smartlist_new(); for (i = 0; i < link_specifier_list_getlen_spec(specs); i++) { - hs_desc_link_specifier_t *hs_spec; link_specifier_t *ls = link_specifier_list_get_spec(specs, i); - tor_assert(ls); - - hs_spec = tor_malloc_zero(sizeof(*hs_spec)); - hs_spec->type = link_specifier_get_ls_type(ls); - switch (hs_spec->type) { - case LS_IPV4: - tor_addr_from_ipv4h(&hs_spec->u.ap.addr, - link_specifier_get_un_ipv4_addr(ls)); - hs_spec->u.ap.port = link_specifier_get_un_ipv4_port(ls); - break; - case LS_IPV6: - tor_addr_from_ipv6_bytes(&hs_spec->u.ap.addr, (const char *) - link_specifier_getarray_un_ipv6_addr(ls)); - hs_spec->u.ap.port = link_specifier_get_un_ipv6_port(ls); - break; - case LS_LEGACY_ID: - /* Both are known at compile time so let's make sure they are the same - * else we can copy memory out of bound. */ - tor_assert(link_specifier_getlen_un_legacy_id(ls) == - sizeof(hs_spec->u.legacy_id)); - memcpy(hs_spec->u.legacy_id, link_specifier_getarray_un_legacy_id(ls), - sizeof(hs_spec->u.legacy_id)); - break; - case LS_ED25519_ID: - /* Both are known at compile time so let's make sure they are the same - * else we can copy memory out of bound. */ - tor_assert(link_specifier_getlen_un_ed25519_id(ls) == - sizeof(hs_spec->u.ed25519_id)); - memcpy(hs_spec->u.ed25519_id, - link_specifier_getconstarray_un_ed25519_id(ls), - sizeof(hs_spec->u.ed25519_id)); - break; - default: - tor_free(hs_spec); + if (BUG(!ls)) { goto err; } - - smartlist_add(results, hs_spec); + link_specifier_t *ls_dup = link_specifier_dup(ls); + if (BUG(!ls_dup)) { + goto err; + } + smartlist_add(results, ls_dup); } goto done; err: if (results) { - SMARTLIST_FOREACH(results, hs_desc_link_specifier_t *, s, tor_free(s)); + SMARTLIST_FOREACH(results, link_specifier_t *, s, + link_specifier_free(s)); smartlist_free(results); results = NULL; } @@ -1245,7 +1199,7 @@ decode_link_specifiers(const char *encoded) return results; } -/* Given a list of authentication types, decode it and put it in the encrypted +/** Given a list of authentication types, decode it and put it in the encrypted * data section. Return 1 if we at least know one of the type or 0 if we know * none of them. */ static int @@ -1273,7 +1227,7 @@ decode_auth_type(hs_desc_encrypted_data_t *desc, const char *list) return match; } -/* Parse a space-delimited list of integers representing CREATE2 formats into +/** Parse a space-delimited list of integers representing CREATE2 formats into * the bitfield in hs_desc_encrypted_data_t. Ignore unrecognized values. */ static void decode_create2_list(hs_desc_encrypted_data_t *desc, const char *list) @@ -1307,7 +1261,7 @@ decode_create2_list(hs_desc_encrypted_data_t *desc, const char *list) smartlist_free(tokens); } -/* Given a certificate, validate the certificate for certain conditions which +/** Given a certificate, validate the certificate for certain conditions which * are if the given type matches the cert's one, if the signing key is * included and if the that key was actually used to sign the certificate. * @@ -1331,11 +1285,20 @@ cert_is_valid(tor_cert_t *cert, uint8_t type, const char *log_obj_type) log_warn(LD_REND, "Signing key is NOT included for %s.", log_obj_type); goto err; } + /* The following will not only check if the signature matches but also the * expiration date and overall validity. */ if (tor_cert_checksig(cert, &cert->signing_key, approx_time()) < 0) { - log_warn(LD_REND, "Invalid signature for %s: %s", log_obj_type, - tor_cert_describe_signature_status(cert)); + if (cert->cert_expired) { + char expiration_str[ISO_TIME_LEN+1]; + format_iso_time(expiration_str, cert->valid_until); + log_fn(LOG_PROTOCOL_WARN, LD_REND, "Invalid signature for %s: %s (%s)", + log_obj_type, tor_cert_describe_signature_status(cert), + expiration_str); + } else { + log_warn(LD_REND, "Invalid signature for %s: %s", + log_obj_type, tor_cert_describe_signature_status(cert)); + } goto err; } @@ -1344,7 +1307,7 @@ cert_is_valid(tor_cert_t *cert, uint8_t type, const char *log_obj_type) return 0; } -/* Given some binary data, try to parse it to get a certificate object. If we +/** Given some binary data, try to parse it to get a certificate object. If we * have a valid cert, validate it using the given wanted type. On error, print * a log using the err_msg has the certificate identifier adding semantic to * the log and cert_out is set to NULL. On success, 0 is returned and cert_out @@ -1381,7 +1344,7 @@ cert_parse_and_validate(tor_cert_t **cert_out, const char *data, return -1; } -/* Return true iff the given length of the encrypted data of a descriptor +/** Return true iff the given length of the encrypted data of a descriptor * passes validation. */ STATIC int encrypted_data_length_is_valid(size_t len) @@ -1400,8 +1363,51 @@ encrypted_data_length_is_valid(size_t len) return 0; } -/* Decrypt the descriptor cookie given the descriptor, the auth client, - * and the client secret key. On sucess, return 0 and a newly allocated +/** Build the KEYS component for the authorized client computation. The format + * of the construction is: + * + * SECRET_SEED = x25519(sk, pk) + * KEYS = KDF(subcredential | SECRET_SEED, 40) + * + * Set the <b>keys_out</b> argument to point to the buffer containing the KEYS, + * and return the buffer's length. The caller should wipe and free its content + * once done with it. This function can't fail. */ +static size_t +build_descriptor_cookie_keys(const hs_subcredential_t *subcredential, + const curve25519_secret_key_t *sk, + const curve25519_public_key_t *pk, + uint8_t **keys_out) +{ + uint8_t secret_seed[CURVE25519_OUTPUT_LEN]; + uint8_t *keystream; + size_t keystream_len = HS_DESC_CLIENT_ID_LEN + HS_DESC_COOKIE_KEY_LEN; + crypto_xof_t *xof; + + tor_assert(subcredential); + tor_assert(sk); + tor_assert(pk); + tor_assert(keys_out); + + keystream = tor_malloc_zero(keystream_len); + + /* Calculate x25519(sk, pk) to get the secret seed. */ + curve25519_handshake(secret_seed, sk, pk); + + /* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */ + xof = crypto_xof_new(); + crypto_xof_add_bytes(xof, subcredential->subcred, SUBCRED_LEN); + crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed)); + crypto_xof_squeeze_bytes(xof, keystream, keystream_len); + crypto_xof_free(xof); + + memwipe(secret_seed, 0, sizeof(secret_seed)); + + *keys_out = keystream; + return keystream_len; +} + +/** Decrypt the descriptor cookie given the descriptor, the auth client, + * and the client secret key. On success, return 0 and a newly allocated * descriptor cookie descriptor_cookie_out. On error or if the client id * is invalid, return -1 and descriptor_cookie_out is set to * NULL. */ @@ -1412,36 +1418,37 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, uint8_t **descriptor_cookie_out) { int ret = -1; - uint8_t secret_seed[CURVE25519_OUTPUT_LEN]; - uint8_t keystream[HS_DESC_CLIENT_ID_LEN + HS_DESC_COOKIE_KEY_LEN]; - uint8_t *cookie_key = NULL; + uint8_t *keystream = NULL; + size_t keystream_length = 0; uint8_t *descriptor_cookie = NULL; + const uint8_t *cookie_key = NULL; crypto_cipher_t *cipher = NULL; - crypto_xof_t *xof = NULL; tor_assert(desc); tor_assert(client); tor_assert(client_auth_sk); - tor_assert(!tor_mem_is_zero( + tor_assert(!fast_mem_is_zero( (char *) &desc->superencrypted_data.auth_ephemeral_pubkey, sizeof(desc->superencrypted_data.auth_ephemeral_pubkey))); - tor_assert(!tor_mem_is_zero((char *) client_auth_sk, - sizeof(*client_auth_sk))); - tor_assert(!tor_mem_is_zero((char *) desc->subcredential, DIGEST256_LEN)); + tor_assert(!fast_mem_is_zero((char *) desc->subcredential.subcred, + DIGEST256_LEN)); - /* Calculate x25519(client_x, hs_Y) */ - curve25519_handshake(secret_seed, client_auth_sk, - &desc->superencrypted_data.auth_ephemeral_pubkey); + /* Catch potential code-flow cases of an uninitialized private key sneaking + * into this function. */ + if (BUG(fast_mem_is_zero((char *)client_auth_sk, sizeof(*client_auth_sk)))) { + goto done; + } - /* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, desc->subcredential, DIGEST256_LEN); - crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed)); - crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream)); - crypto_xof_free(xof); + /* Get the KEYS component to derive the CLIENT-ID and COOKIE-KEY. */ + keystream_length = + build_descriptor_cookie_keys(&desc->subcredential, + client_auth_sk, + &desc->superencrypted_data.auth_ephemeral_pubkey, + &keystream); + tor_assert(keystream_length > 0); /* If the client id of auth client is not the same as the calculcated - * client id, it means that this auth client is invaild according to the + * client id, it means that this auth client is invalid according to the * client secret key client_auth_sk. */ if (tor_memneq(client->client_id, keystream, HS_DESC_CLIENT_ID_LEN)) { goto done; @@ -1464,8 +1471,8 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, if (cipher) { crypto_cipher_free(cipher); } - memwipe(secret_seed, 0, sizeof(secret_seed)); - memwipe(keystream, 0, sizeof(keystream)); + memwipe(keystream, 0, keystream_length); + tor_free(keystream); return ret; } @@ -1474,17 +1481,15 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc, * the descriptor object <b>desc</b> and <b>descriptor_cookie</b> * to generate the right decryption keys; set <b>decrypted_out</b> to * the plaintext. If <b>is_superencrypted_layer</b> is set, this is - * the outter encrypted layer of the descriptor. + * the outer encrypted layer of the descriptor. * * On any error case, including an empty output, return 0 and set * *<b>decrypted_out</b> to NULL. */ MOCK_IMPL(STATIC size_t, decrypt_desc_layer,(const hs_descriptor_t *desc, - const uint8_t *encrypted_blob, - size_t encrypted_blob_size, const uint8_t *descriptor_cookie, - int is_superencrypted_layer, + bool is_superencrypted_layer, char **decrypted_out)) { uint8_t *decrypted = NULL; @@ -1494,6 +1499,12 @@ decrypt_desc_layer,(const hs_descriptor_t *desc, uint8_t mac_key[DIGEST256_LEN], our_mac[DIGEST256_LEN]; const uint8_t *salt, *encrypted, *desc_mac; size_t encrypted_len, result_len = 0; + const uint8_t *encrypted_blob = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob + : desc->superencrypted_data.encrypted_blob; + size_t encrypted_blob_size = (is_superencrypted_layer) + ? desc->plaintext_data.superencrypted_blob_size + : desc->superencrypted_data.encrypted_blob_size; tor_assert(decrypted_out); tor_assert(desc); @@ -1592,7 +1603,7 @@ decrypt_desc_layer,(const hs_descriptor_t *desc, return result_len; } -/* Decrypt the superencrypted section of the descriptor using the given +/** Decrypt the superencrypted section of the descriptor using the given * descriptor object <b>desc</b>. A newly allocated NUL terminated string is * put in decrypted_out which contains the superencrypted layer of the * descriptor. Return the length of decrypted_out on success else 0 is @@ -1607,9 +1618,8 @@ desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out) tor_assert(decrypted_out); superencrypted_len = decrypt_desc_layer(desc, - desc->plaintext_data.superencrypted_blob, - desc->plaintext_data.superencrypted_blob_size, - NULL, 1, &superencrypted_plaintext); + NULL, + true, &superencrypted_plaintext); if (!superencrypted_len) { log_warn(LD_REND, "Decrypting superencrypted desc failed."); @@ -1625,7 +1635,7 @@ desc_decrypt_superencrypted(const hs_descriptor_t *desc, char **decrypted_out) return superencrypted_len; } -/* Decrypt the encrypted section of the descriptor using the given descriptor +/** Decrypt the encrypted section of the descriptor using the given descriptor * object <b>desc</b>. A newly allocated NUL terminated string is put in * decrypted_out which contains the encrypted layer of the descriptor. * Return the length of decrypted_out on success else 0 is returned and @@ -1658,9 +1668,9 @@ desc_decrypt_encrypted(const hs_descriptor_t *desc, } encrypted_len = decrypt_desc_layer(desc, - desc->superencrypted_data.encrypted_blob, - desc->superencrypted_data.encrypted_blob_size, - descriptor_cookie, 0, &encrypted_plaintext); + descriptor_cookie, + false, &encrypted_plaintext); + if (!encrypted_len) { goto err; } @@ -1678,7 +1688,7 @@ desc_decrypt_encrypted(const hs_descriptor_t *desc, return encrypted_len; } -/* Given the token tok for an intro point legacy key, the list of tokens, the +/** Given the token tok for an intro point legacy key, the list of tokens, the * introduction point ip being decoded and the descriptor desc from which it * comes from, decode the legacy key and set the intro point object. Return 0 * on success else -1 on failure. */ @@ -1736,7 +1746,7 @@ decode_intro_legacy_key(const directory_token_t *tok, return -1; } -/* Dig into the descriptor <b>tokens</b> to find the onion key we should use +/** Dig into the descriptor <b>tokens</b> to find the onion key we should use * for this intro point, and set it into <b>onion_key_out</b>. Return 0 if it * was found and well-formed, otherwise return -1 in case of errors. */ static int @@ -1780,7 +1790,7 @@ set_intro_point_onion_key(curve25519_public_key_t *onion_key_out, return retval; } -/* Given the start of a section and the end of it, decode a single +/** Given the start of a section and the end of it, decode a single * introduction point from that section. Return a newly allocated introduction * point object containing the decoded data. Return NULL if the section can't * be decoded. */ @@ -1909,7 +1919,7 @@ decode_introduction_point(const hs_descriptor_t *desc, const char *start) return ip; } -/* Given a descriptor string at <b>data</b>, decode all possible introduction +/** Given a descriptor string at <b>data</b>, decode all possible introduction * points that we can find. Add the introduction point object to desc_enc as we * find them. This function can't fail and it is possible that zero * introduction points can be decoded. */ @@ -1972,7 +1982,8 @@ decode_intro_points(const hs_descriptor_t *desc, SMARTLIST_FOREACH(intro_points, char *, a, tor_free(a)); smartlist_free(intro_points); } -/* Return 1 iff the given base64 encoded signature in b64_sig from the encoded + +/** Return 1 iff the given base64 encoded signature in b64_sig from the encoded * descriptor in encoded_desc validates the descriptor content. */ STATIC int desc_sig_is_valid(const char *b64_sig, @@ -1992,7 +2003,7 @@ desc_sig_is_valid(const char *b64_sig, /* Signature length check. */ if (strlen(b64_sig) != ED25519_SIG_BASE64_LEN) { log_warn(LD_REND, "Service descriptor has an invalid signature length." - "Exptected %d but got %lu", + "Expected %d but got %lu", ED25519_SIG_BASE64_LEN, (unsigned long) strlen(b64_sig)); goto err; } @@ -2031,14 +2042,14 @@ desc_sig_is_valid(const char *b64_sig, return ret; } -/* Decode descriptor plaintext data for version 3. Given a list of tokens, an +/** Decode descriptor plaintext data for version 3. Given a list of tokens, an * allocated plaintext object that will be populated and the encoded * descriptor with its length. The last one is needed for signature * verification. Unknown tokens are simply ignored so this won't error on * unknowns but requires that all v3 token be present and valid. * * Return 0 on success else a negative value. */ -static int +static hs_desc_decode_status_t desc_decode_plaintext_v3(smartlist_t *tokens, hs_desc_plaintext_data_t *desc, const char *encoded_desc, size_t encoded_len) @@ -2128,21 +2139,19 @@ desc_decode_plaintext_v3(smartlist_t *tokens, goto err; } - return 0; - + return HS_DESC_DECODE_OK; err: - return -1; + return HS_DESC_DECODE_PLAINTEXT_ERROR; } -/* Decode the version 3 superencrypted section of the given descriptor desc. - * The desc_superencrypted_out will be populated with the decoded data. - * Return 0 on success else -1. */ -static int +/** Decode the version 3 superencrypted section of the given descriptor desc. + * The desc_superencrypted_out will be populated with the decoded data. */ +static hs_desc_decode_status_t desc_decode_superencrypted_v3(const hs_descriptor_t *desc, hs_desc_superencrypted_data_t * desc_superencrypted_out) { - int ret = -1; + int ret = HS_DESC_DECODE_SUPERENC_ERROR; char *message = NULL; size_t message_len; memarea_t *area = NULL; @@ -2228,11 +2237,11 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc, tok->object_size); superencrypted->encrypted_blob_size = tok->object_size; - ret = 0; + ret = HS_DESC_DECODE_OK; goto done; err: - tor_assert(ret < 0); + tor_assert(ret < HS_DESC_DECODE_OK); hs_desc_superencrypted_data_free_contents(desc_superencrypted_out); done: @@ -2249,15 +2258,14 @@ desc_decode_superencrypted_v3(const hs_descriptor_t *desc, return ret; } -/* Decode the version 3 encrypted section of the given descriptor desc. The - * desc_encrypted_out will be populated with the decoded data. Return 0 on - * success else -1. */ -static int +/** Decode the version 3 encrypted section of the given descriptor desc. The + * desc_encrypted_out will be populated with the decoded data. */ +static hs_desc_decode_status_t desc_decode_encrypted_v3(const hs_descriptor_t *desc, const curve25519_secret_key_t *client_auth_sk, hs_desc_encrypted_data_t *desc_encrypted_out) { - int ret = -1; + int ret = HS_DESC_DECODE_ENCRYPTED_ERROR; char *message = NULL; size_t message_len; memarea_t *area = NULL; @@ -2280,12 +2288,14 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, * authorization is failing. */ log_warn(LD_REND, "Client authorization for requested onion address " "is invalid. Can't decrypt the descriptor."); + ret = HS_DESC_DECODE_BAD_CLIENT_AUTH; } else { /* Inform at notice level that the onion address requested can't be * reached without client authorization most likely. */ log_notice(LD_REND, "Fail to decrypt descriptor for requested onion " "address. It is likely requiring client " "authorization."); + ret = HS_DESC_DECODE_NEED_CLIENT_AUTH; } goto err; } @@ -2344,11 +2354,11 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, /* NOTE: Unknown fields are allowed because this function could be used to * decode other descriptor version. */ - ret = 0; + ret = HS_DESC_DECODE_OK; goto done; err: - tor_assert(ret < 0); + tor_assert(ret < HS_DESC_DECODE_OK); hs_desc_encrypted_data_free_contents(desc_encrypted_out); done: @@ -2365,9 +2375,9 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, return ret; } -/* Table of encrypted decode function version specific. The function are +/** Table of encrypted decode function version specific. The function are * indexed by the version number so v3 callback is at index 3 in the array. */ -static int +static hs_desc_decode_status_t (*decode_encrypted_handlers[])( const hs_descriptor_t *desc, const curve25519_secret_key_t *client_auth_sk, @@ -2377,15 +2387,15 @@ static int desc_decode_encrypted_v3, }; -/* Decode the encrypted data section of the given descriptor and store the +/** Decode the encrypted data section of the given descriptor and store the * data in the given encrypted data object. Return 0 on success else a * negative value on error. */ -int +hs_desc_decode_status_t hs_desc_decode_encrypted(const hs_descriptor_t *desc, const curve25519_secret_key_t *client_auth_sk, hs_desc_encrypted_data_t *desc_encrypted) { - int ret; + int ret = HS_DESC_DECODE_ENCRYPTED_ERROR; uint32_t version; tor_assert(desc); @@ -2399,7 +2409,6 @@ hs_desc_decode_encrypted(const hs_descriptor_t *desc, /* Let's make sure we have a supported version as well. By correctly parsing * the plaintext, this should not fail. */ if (BUG(!hs_desc_is_supported_version(version))) { - ret = -1; goto err; } /* Extra precaution. Having no handler for the supported version should @@ -2418,9 +2427,9 @@ hs_desc_decode_encrypted(const hs_descriptor_t *desc, return ret; } -/* Table of superencrypted decode function version specific. The function are +/** Table of superencrypted decode function version specific. The function are * indexed by the version number so v3 callback is at index 3 in the array. */ -static int +static hs_desc_decode_status_t (*decode_superencrypted_handlers[])( const hs_descriptor_t *desc, hs_desc_superencrypted_data_t *desc_superencrypted) = @@ -2429,15 +2438,14 @@ static int desc_decode_superencrypted_v3, }; -/* Decode the superencrypted data section of the given descriptor and store the - * data in the given superencrypted data object. Return 0 on success else a - * negative value on error. */ -int +/** Decode the superencrypted data section of the given descriptor and store + * the data in the given superencrypted data object. */ +hs_desc_decode_status_t hs_desc_decode_superencrypted(const hs_descriptor_t *desc, hs_desc_superencrypted_data_t * desc_superencrypted) { - int ret; + int ret = HS_DESC_DECODE_SUPERENC_ERROR; uint32_t version; tor_assert(desc); @@ -2451,7 +2459,6 @@ hs_desc_decode_superencrypted(const hs_descriptor_t *desc, /* Let's make sure we have a supported version as well. By correctly parsing * the plaintext, this should not fail. */ if (BUG(!hs_desc_is_supported_version(version))) { - ret = -1; goto err; } /* Extra precaution. Having no handler for the supported version should @@ -2469,9 +2476,9 @@ hs_desc_decode_superencrypted(const hs_descriptor_t *desc, return ret; } -/* Table of plaintext decode function version specific. The function are +/** Table of plaintext decode function version specific. The function are * indexed by the version number so v3 callback is at index 3 in the array. */ -static int +static hs_desc_decode_status_t (*decode_plaintext_handlers[])( smartlist_t *tokens, hs_desc_plaintext_data_t *desc, @@ -2482,13 +2489,13 @@ static int desc_decode_plaintext_v3, }; -/* Fully decode the given descriptor plaintext and store the data in the - * plaintext data object. Returns 0 on success else a negative value. */ -int +/** Fully decode the given descriptor plaintext and store the data in the + * plaintext data object. */ +hs_desc_decode_status_t hs_desc_decode_plaintext(const char *encoded, hs_desc_plaintext_data_t *plaintext) { - int ok = 0, ret = -1; + int ok = 0, ret = HS_DESC_DECODE_PLAINTEXT_ERROR; memarea_t *area = NULL; smartlist_t *tokens = NULL; size_t encoded_len; @@ -2538,11 +2545,11 @@ hs_desc_decode_plaintext(const char *encoded, /* Run the version specific plaintext decoder. */ ret = decode_plaintext_handlers[plaintext->version](tokens, plaintext, encoded, encoded_len); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } /* Success. Descriptor has been populated with the data. */ - ret = 0; + ret = HS_DESC_DECODE_OK; err: if (tokens) { @@ -2555,19 +2562,19 @@ hs_desc_decode_plaintext(const char *encoded, return ret; } -/* Fully decode an encoded descriptor and set a newly allocated descriptor +/** Fully decode an encoded descriptor and set a newly allocated descriptor * object in desc_out. Client secret key is used to decrypt the "encrypted" * section if not NULL else it's ignored. * * Return 0 on success. A negative value is returned on error and desc_out is * set to NULL. */ -int +hs_desc_decode_status_t hs_desc_decode_descriptor(const char *encoded, - const uint8_t *subcredential, + const hs_subcredential_t *subcredential, const curve25519_secret_key_t *client_auth_sk, hs_descriptor_t **desc_out) { - int ret = -1; + hs_desc_decode_status_t ret = HS_DESC_DECODE_GENERIC_ERROR; hs_descriptor_t *desc; tor_assert(encoded); @@ -2576,25 +2583,25 @@ hs_desc_decode_descriptor(const char *encoded, /* Subcredentials are not optional. */ if (BUG(!subcredential || - tor_mem_is_zero((char*)subcredential, DIGEST256_LEN))) { + fast_mem_is_zero((char*)subcredential, DIGEST256_LEN))) { log_warn(LD_GENERAL, "Tried to decrypt without subcred. Impossible!"); goto err; } - memcpy(desc->subcredential, subcredential, sizeof(desc->subcredential)); + memcpy(&desc->subcredential, subcredential, sizeof(desc->subcredential)); ret = hs_desc_decode_plaintext(encoded, &desc->plaintext_data); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } ret = hs_desc_decode_superencrypted(desc, &desc->superencrypted_data); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } ret = hs_desc_decode_encrypted(desc, client_auth_sk, &desc->encrypted_data); - if (ret < 0) { + if (ret != HS_DESC_DECODE_OK) { goto err; } @@ -2615,7 +2622,7 @@ hs_desc_decode_descriptor(const char *encoded, return ret; } -/* Table of encode function version specific. The functions are indexed by the +/** Table of encode function version specific. The functions are indexed by the * version number so v3 callback is at index 3 in the array. */ static int (*encode_handlers[])( @@ -2628,7 +2635,7 @@ static int desc_encode_v3, }; -/* Encode the given descriptor desc including signing with the given key pair +/** Encode the given descriptor desc including signing with the given key pair * signing_kp and encrypting with the given descriptor cookie. * * If the client authorization is enabled, descriptor_cookie must be the same @@ -2671,9 +2678,10 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc, * symmetric only if the client auth is disabled. That is, the descriptor * cookie will be NULL. */ if (!descriptor_cookie) { - ret = hs_desc_decode_descriptor(*encoded_out, desc->subcredential, + ret = hs_desc_decode_descriptor(*encoded_out, &desc->subcredential, NULL, NULL); - if (BUG(ret < 0)) { + if (BUG(ret != HS_DESC_DECODE_OK)) { + ret = -1; goto err; } } @@ -2685,7 +2693,7 @@ hs_desc_encode_descriptor,(const hs_descriptor_t *desc, return ret; } -/* Free the content of the plaintext section of a descriptor. */ +/** Free the content of the plaintext section of a descriptor. */ void hs_desc_plaintext_data_free_contents(hs_desc_plaintext_data_t *desc) { @@ -2701,7 +2709,7 @@ hs_desc_plaintext_data_free_contents(hs_desc_plaintext_data_t *desc) memwipe(desc, 0, sizeof(*desc)); } -/* Free the content of the superencrypted section of a descriptor. */ +/** Free the content of the superencrypted section of a descriptor. */ void hs_desc_superencrypted_data_free_contents(hs_desc_superencrypted_data_t *desc) { @@ -2721,7 +2729,7 @@ hs_desc_superencrypted_data_free_contents(hs_desc_superencrypted_data_t *desc) memwipe(desc, 0, sizeof(*desc)); } -/* Free the content of the encrypted section of a descriptor. */ +/** Free the content of the encrypted section of a descriptor. */ void hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc) { @@ -2741,7 +2749,7 @@ hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc) memwipe(desc, 0, sizeof(*desc)); } -/* Free the descriptor plaintext data object. */ +/** Free the descriptor plaintext data object. */ void hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc) { @@ -2749,7 +2757,7 @@ hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc) tor_free(desc); } -/* Free the descriptor plaintext data object. */ +/** Free the descriptor plaintext data object. */ void hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc) { @@ -2757,7 +2765,7 @@ hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc) tor_free(desc); } -/* Free the descriptor encrypted data object. */ +/** Free the descriptor encrypted data object. */ void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc) { @@ -2765,7 +2773,7 @@ hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc) tor_free(desc); } -/* Free the given descriptor object. */ +/** Free the given descriptor object. */ void hs_descriptor_free_(hs_descriptor_t *desc) { @@ -2779,7 +2787,7 @@ hs_descriptor_free_(hs_descriptor_t *desc) tor_free(desc); } -/* Return the size in bytes of the given plaintext data object. A sizeof() is +/** Return the size in bytes of the given plaintext data object. A sizeof() is * not enough because the object contains pointers and the encrypted blob. * This is particularly useful for our OOM subsystem that tracks the HSDir * cache size for instance. */ @@ -2791,7 +2799,7 @@ hs_desc_plaintext_obj_size(const hs_desc_plaintext_data_t *data) data->superencrypted_blob_size); } -/* Return the size in bytes of the given encrypted data object. Used by OOM +/** Return the size in bytes of the given encrypted data object. Used by OOM * subsystem. */ static size_t hs_desc_encrypted_obj_size(const hs_desc_encrypted_data_t *data) @@ -2811,18 +2819,20 @@ hs_desc_encrypted_obj_size(const hs_desc_encrypted_data_t *data) return sizeof(*data) + intro_size; } -/* Return the size in bytes of the given descriptor object. Used by OOM +/** Return the size in bytes of the given descriptor object. Used by OOM * subsystem. */ size_t hs_desc_obj_size(const hs_descriptor_t *data) { - tor_assert(data); + if (data == NULL) { + return 0; + } return (hs_desc_plaintext_obj_size(&data->plaintext_data) + hs_desc_encrypted_obj_size(&data->encrypted_data) + sizeof(data->subcredential)); } -/* Return a newly allocated descriptor intro point. */ +/** Return a newly allocated descriptor intro point. */ hs_desc_intro_point_t * hs_desc_intro_point_new(void) { @@ -2831,7 +2841,7 @@ hs_desc_intro_point_new(void) return ip; } -/* Free a descriptor intro point object. */ +/** Free a descriptor intro point object. */ void hs_desc_intro_point_free_(hs_desc_intro_point_t *ip) { @@ -2839,8 +2849,8 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *ip) return; } if (ip->link_specifiers) { - SMARTLIST_FOREACH(ip->link_specifiers, hs_desc_link_specifier_t *, - ls, hs_desc_link_specifier_free(ls)); + SMARTLIST_FOREACH(ip->link_specifiers, link_specifier_t *, + ls, link_specifier_free(ls)); smartlist_free(ip->link_specifiers); } tor_cert_free(ip->auth_key_cert); @@ -2850,7 +2860,7 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *ip) tor_free(ip); } -/* Allocate and build a new fake client info for the descriptor. Return a +/** Allocate and build a new fake client info for the descriptor. Return a * newly allocated object. This can't fail. */ hs_desc_authorized_client_t * hs_desc_build_fake_authorized_client(void) @@ -2868,49 +2878,44 @@ hs_desc_build_fake_authorized_client(void) return client_auth; } -/* Using the service's subcredential, client public key, auth ephemeral secret +/** Using the service's subcredential, client public key, auth ephemeral secret * key, and descriptor cookie, build the auth client so we can then encode the * descriptor for publication. client_out must be already allocated. */ void -hs_desc_build_authorized_client(const uint8_t *subcredential, +hs_desc_build_authorized_client(const hs_subcredential_t *subcredential, const curve25519_public_key_t *client_auth_pk, const curve25519_secret_key_t * auth_ephemeral_sk, const uint8_t *descriptor_cookie, hs_desc_authorized_client_t *client_out) { - uint8_t secret_seed[CURVE25519_OUTPUT_LEN]; - uint8_t keystream[HS_DESC_CLIENT_ID_LEN + HS_DESC_COOKIE_KEY_LEN]; - uint8_t *cookie_key; + uint8_t *keystream = NULL; + size_t keystream_length = 0; + const uint8_t *cookie_key; crypto_cipher_t *cipher; - crypto_xof_t *xof; tor_assert(client_auth_pk); tor_assert(auth_ephemeral_sk); tor_assert(descriptor_cookie); tor_assert(client_out); tor_assert(subcredential); - tor_assert(!tor_mem_is_zero((char *) auth_ephemeral_sk, + tor_assert(!fast_mem_is_zero((char *) auth_ephemeral_sk, sizeof(*auth_ephemeral_sk))); - tor_assert(!tor_mem_is_zero((char *) client_auth_pk, + tor_assert(!fast_mem_is_zero((char *) client_auth_pk, sizeof(*client_auth_pk))); - tor_assert(!tor_mem_is_zero((char *) descriptor_cookie, + tor_assert(!fast_mem_is_zero((char *) descriptor_cookie, HS_DESC_DESCRIPTOR_COOKIE_LEN)); - tor_assert(!tor_mem_is_zero((char *) subcredential, + tor_assert(!fast_mem_is_zero((char *) subcredential, DIGEST256_LEN)); - /* Calculate x25519(hs_y, client_X) */ - curve25519_handshake(secret_seed, - auth_ephemeral_sk, - client_auth_pk); - - /* Calculate KEYS = KDF(subcredential | SECRET_SEED, 40) */ - xof = crypto_xof_new(); - crypto_xof_add_bytes(xof, subcredential, DIGEST256_LEN); - crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed)); - crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream)); - crypto_xof_free(xof); + /* Get the KEYS part so we can derive the CLIENT-ID and COOKIE-KEY. */ + keystream_length = + build_descriptor_cookie_keys(subcredential, + auth_ephemeral_sk, client_auth_pk, + &keystream); + tor_assert(keystream_length > 0); + /* Extract the CLIENT-ID and COOKIE-KEY from the KEYS. */ memcpy(client_out->client_id, keystream, HS_DESC_CLIENT_ID_LEN); cookie_key = keystream + HS_DESC_CLIENT_ID_LEN; @@ -2925,83 +2930,20 @@ hs_desc_build_authorized_client(const uint8_t *subcredential, (const char *) descriptor_cookie, HS_DESC_DESCRIPTOR_COOKIE_LEN); - memwipe(secret_seed, 0, sizeof(secret_seed)); - memwipe(keystream, 0, sizeof(keystream)); + memwipe(keystream, 0, keystream_length); + tor_free(keystream); crypto_cipher_free(cipher); } -/* Free an authoriezd client object. */ +/** Free an authoriezd client object. */ void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client) { tor_free(client); } -/* Free the given descriptor link specifier. */ -void -hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls) -{ - if (ls == NULL) { - return; - } - tor_free(ls); -} - -/* Return a newly allocated descriptor link specifier using the given extend - * info and requested type. Return NULL on error. */ -hs_desc_link_specifier_t * -hs_desc_link_specifier_new(const extend_info_t *info, uint8_t type) -{ - hs_desc_link_specifier_t *ls = NULL; - - tor_assert(info); - - ls = tor_malloc_zero(sizeof(*ls)); - ls->type = type; - switch (ls->type) { - case LS_IPV4: - if (info->addr.family != AF_INET) { - goto err; - } - tor_addr_copy(&ls->u.ap.addr, &info->addr); - ls->u.ap.port = info->port; - break; - case LS_IPV6: - if (info->addr.family != AF_INET6) { - goto err; - } - tor_addr_copy(&ls->u.ap.addr, &info->addr); - ls->u.ap.port = info->port; - break; - case LS_LEGACY_ID: - /* Bug out if the identity digest is not set */ - if (BUG(tor_mem_is_zero(info->identity_digest, - sizeof(info->identity_digest)))) { - goto err; - } - memcpy(ls->u.legacy_id, info->identity_digest, sizeof(ls->u.legacy_id)); - break; - case LS_ED25519_ID: - /* ed25519 keys are optional for intro points */ - if (ed25519_public_key_is_zero(&info->ed_identity)) { - goto err; - } - memcpy(ls->u.ed25519_id, info->ed_identity.pubkey, - sizeof(ls->u.ed25519_id)); - break; - default: - /* Unknown type is code flow error. */ - tor_assert(0); - } - - return ls; - err: - tor_free(ls); - return NULL; -} - -/* From the given descriptor, remove and free every introduction point. */ +/** From the given descriptor, remove and free every introduction point. */ void hs_descriptor_clear_intro_points(hs_descriptor_t *desc) { @@ -3016,59 +2958,3 @@ hs_descriptor_clear_intro_points(hs_descriptor_t *desc) smartlist_clear(ips); } } - -/* From a descriptor link specifier object spec, returned a newly allocated - * link specifier object that is the encoded representation of spec. Return - * NULL on error. */ -link_specifier_t * -hs_desc_lspec_to_trunnel(const hs_desc_link_specifier_t *spec) -{ - tor_assert(spec); - - link_specifier_t *ls = link_specifier_new(); - link_specifier_set_ls_type(ls, spec->type); - - switch (spec->type) { - case LS_IPV4: - link_specifier_set_un_ipv4_addr(ls, - tor_addr_to_ipv4h(&spec->u.ap.addr)); - link_specifier_set_un_ipv4_port(ls, spec->u.ap.port); - /* Four bytes IPv4 and two bytes port. */ - link_specifier_set_ls_len(ls, sizeof(spec->u.ap.addr.addr.in_addr) + - sizeof(spec->u.ap.port)); - break; - case LS_IPV6: - { - size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls); - const uint8_t *in6_addr = tor_addr_to_in6_addr8(&spec->u.ap.addr); - uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls); - memcpy(ipv6_array, in6_addr, addr_len); - link_specifier_set_un_ipv6_port(ls, spec->u.ap.port); - /* Sixteen bytes IPv6 and two bytes port. */ - link_specifier_set_ls_len(ls, addr_len + sizeof(spec->u.ap.port)); - break; - } - case LS_LEGACY_ID: - { - size_t legacy_id_len = link_specifier_getlen_un_legacy_id(ls); - uint8_t *legacy_id_array = link_specifier_getarray_un_legacy_id(ls); - memcpy(legacy_id_array, spec->u.legacy_id, legacy_id_len); - link_specifier_set_ls_len(ls, legacy_id_len); - break; - } - case LS_ED25519_ID: - { - size_t ed25519_id_len = link_specifier_getlen_un_ed25519_id(ls); - uint8_t *ed25519_id_array = link_specifier_getarray_un_ed25519_id(ls); - memcpy(ed25519_id_array, spec->u.ed25519_id, ed25519_id_len); - link_specifier_set_ls_len(ls, ed25519_id_len); - break; - } - default: - tor_assert_nonfatal_unreached(); - link_specifier_free(ls); - ls = NULL; - } - - return ls; -} |