hs-v3: Generate all descriptor related keys

We need to generate all the related keys when building the descriptor, so that
we can encrypt the descriptor.

Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
Suphanat Chunhapanya 2018-04-09 23:09:41 +07:00 committed by David Goulet
parent 15af47ede0
commit 08bbcffc0e
4 changed files with 278 additions and 4 deletions

View File

@ -168,6 +168,26 @@ desc_plaintext_data_free_contents(hs_desc_plaintext_data_t *desc)
memwipe(desc, 0, sizeof(*desc)); memwipe(desc, 0, sizeof(*desc));
} }
/* Free the content of the superencrypted section of a descriptor. */
static void
desc_superencrypted_data_free_contents(hs_desc_superencrypted_data_t *desc)
{
if (!desc) {
return;
}
if (desc->encrypted_blob) {
tor_free(desc->encrypted_blob);
}
if (desc->clients) {
SMARTLIST_FOREACH(desc->clients, hs_desc_authorized_client_t *, client,
hs_desc_authorized_client_free(client));
smartlist_free(desc->clients);
}
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. */
static void static void
desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc) desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc)
@ -2383,6 +2403,14 @@ hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc)
tor_free(desc); tor_free(desc);
} }
/* Free the descriptor plaintext data object. */
void
hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc)
{
desc_superencrypted_data_free_contents(desc);
tor_free(desc);
}
/* Free the descriptor encrypted data object. */ /* Free the descriptor encrypted data object. */
void void
hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc) hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc)
@ -2400,6 +2428,7 @@ hs_descriptor_free_(hs_descriptor_t *desc)
} }
desc_plaintext_data_free_contents(&desc->plaintext_data); desc_plaintext_data_free_contents(&desc->plaintext_data);
desc_superencrypted_data_free_contents(&desc->superencrypted_data);
desc_encrypted_data_free_contents(&desc->encrypted_data); desc_encrypted_data_free_contents(&desc->encrypted_data);
tor_free(desc); tor_free(desc);
} }
@ -2475,6 +2504,84 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *ip)
tor_free(ip); tor_free(ip);
} }
/* Build a fake client info for the descriptor */
void
hs_desc_build_fake_authorized_client(hs_desc_authorized_client_t *client_out)
{
tor_assert(client_out);
crypto_rand((char *) client_out->client_id,
sizeof(client_out->client_id));
crypto_rand((char *) client_out->iv,
sizeof(client_out->iv));
crypto_rand((char *) client_out->encrypted_cookie,
sizeof(client_out->encrypted_cookie));
}
/* Using the 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 curve25519_public_key_t *client_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;
crypto_cipher_t *cipher;
crypto_xof_t *xof;
tor_assert(client_pk);
tor_assert(auth_ephemeral_sk);
tor_assert(descriptor_cookie);
tor_assert(client_out);
tor_assert(!tor_mem_is_zero((char *) auth_ephemeral_sk,
sizeof(*auth_ephemeral_sk)));
tor_assert(!tor_mem_is_zero((char *) client_pk, sizeof(*client_pk)));
tor_assert(!tor_mem_is_zero((char *) descriptor_cookie,
HS_DESC_DESCRIPTOR_COOKIE_LEN));
/* Calculate x25519(hs_y, client_X) */
curve25519_handshake(secret_seed,
auth_ephemeral_sk,
client_pk);
/* Calculate KEYS = KDF(SECRET_SEED, 40) */
xof = crypto_xof_new();
crypto_xof_add_bytes(xof, secret_seed, sizeof(secret_seed));
crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream));
crypto_xof_free(xof);
memcpy(client_out->client_id, keystream, HS_DESC_CLIENT_ID_LEN);
cookie_key = keystream + HS_DESC_CLIENT_ID_LEN;
/* Random IV */
crypto_strongest_rand(client_out->iv, sizeof(client_out->iv));
/* This creates a cipher for AES. It can't fail. */
cipher = crypto_cipher_new_with_iv_and_bits(cookie_key, client_out->iv,
HS_DESC_COOKIE_KEY_BIT_SIZE);
/* This can't fail. */
crypto_cipher_encrypt(cipher, (char *) client_out->encrypted_cookie,
(const char *) descriptor_cookie,
HS_DESC_DESCRIPTOR_COOKIE_LEN);
memwipe(secret_seed, 0, sizeof(secret_seed));
memwipe(keystream, 0, sizeof(keystream));
crypto_cipher_free(cipher);
}
/* 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. */ /* Free the given descriptor link specifier. */
void void
hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls) hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls)

View File

@ -59,6 +59,17 @@ struct link_specifier_t;
#define HS_DESC_ENCRYPTED_KEY_LEN CIPHER256_KEY_LEN #define HS_DESC_ENCRYPTED_KEY_LEN CIPHER256_KEY_LEN
#define HS_DESC_ENCRYPTED_BIT_SIZE (HS_DESC_ENCRYPTED_KEY_LEN * 8) #define HS_DESC_ENCRYPTED_BIT_SIZE (HS_DESC_ENCRYPTED_KEY_LEN * 8)
/* Length of each components in the auth client section in the descriptor. */
#define HS_DESC_CLIENT_ID_LEN 8
#define HS_DESC_DESCRIPTOR_COOKIE_LEN 16
#define HS_DESC_COOKIE_KEY_LEN 32
#define HS_DESC_COOKIE_KEY_BIT_SIZE (HS_DESC_COOKIE_KEY_LEN * 8)
#define HS_DESC_ENCRYPED_COOKIE_LEN HS_DESC_DESCRIPTOR_COOKIE_LEN
/* The number of auth client entries in the descriptor must be the multiple
* of this constant. */
#define HS_DESC_AUTH_CLIENT_MULTIPLE 16
/* Type of authentication in the descriptor. */ /* Type of authentication in the descriptor. */
typedef enum { typedef enum {
HS_DESC_AUTH_ED25519 = 1 HS_DESC_AUTH_ED25519 = 1
@ -126,6 +137,20 @@ typedef struct hs_desc_intro_point_t {
unsigned int cross_certified : 1; unsigned int cross_certified : 1;
} hs_desc_intro_point_t; } hs_desc_intro_point_t;
/* Authorized client information located in a descriptor. */
typedef struct hs_desc_authorized_client_t {
/* An identifier that the client will use to identify which auth client
* entry it needs to use. */
uint8_t client_id[HS_DESC_CLIENT_ID_LEN];
/* An IV that is used to decrypt the encrypted descriptor cookie. */
uint8_t iv[CIPHER_IV_LEN];
/* An encrypted descriptor cookie that the client needs to decrypt to use
* it to decrypt the descriptor. */
uint8_t encrypted_cookie[HS_DESC_ENCRYPED_COOKIE_LEN];
} hs_desc_authorized_client_t;
/* The encrypted data section of a descriptor. Obviously the data in this is /* The encrypted data section of a descriptor. Obviously the data in this is
* in plaintext but encrypted once encoded. */ * in plaintext but encrypted once encoded. */
typedef struct hs_desc_encrypted_data_t { typedef struct hs_desc_encrypted_data_t {
@ -144,6 +169,24 @@ typedef struct hs_desc_encrypted_data_t {
smartlist_t *intro_points; smartlist_t *intro_points;
} hs_desc_encrypted_data_t; } hs_desc_encrypted_data_t;
/* The superencrypted data section of a descriptor. Obviously the data in
* this is in plaintext but encrypted once encoded. */
typedef struct hs_desc_superencrypted_data_t {
/* This field contains ephemeral x25519 public key which is used by
* the encryption scheme in the client authorization. */
curve25519_public_key_t auth_ephemeral_pubkey;
/* A list of authorized clients. Contains hs_desc_authorized_client_t
* objects. */
smartlist_t *clients;
/* Decoding only: The b64-decoded encrypted blob from the descriptor */
uint8_t *encrypted_blob;
/* Decoding only: Size of the encrypted_blob */
size_t encrypted_blob_size;
} hs_desc_superencrypted_data_t;
/* Plaintext data that is unencrypted information of the descriptor. */ /* Plaintext data that is unencrypted information of the descriptor. */
typedef struct hs_desc_plaintext_data_t { typedef struct hs_desc_plaintext_data_t {
/* Version of the descriptor format. Spec specifies this field as a /* Version of the descriptor format. Spec specifies this field as a
@ -182,6 +225,11 @@ typedef struct hs_descriptor_t {
/* Contains the plaintext part of the descriptor. */ /* Contains the plaintext part of the descriptor. */
hs_desc_plaintext_data_t plaintext_data; hs_desc_plaintext_data_t plaintext_data;
/* The following contains what's in the superencrypted part of the
* descriptor. It's only encrypted in the encoded version of the descriptor
* thus the data contained in that object is in plaintext. */
hs_desc_superencrypted_data_t superencrypted_data;
/* The following contains what's in the encrypted part of the descriptor. /* The following contains what's in the encrypted part of the descriptor.
* It's only encrypted in the encoded version of the descriptor thus the * It's only encrypted in the encoded version of the descriptor thus the
* data contained in that object is in plaintext. */ * data contained in that object is in plaintext. */
@ -211,6 +259,10 @@ void hs_descriptor_free_(hs_descriptor_t *desc);
void hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc); void hs_desc_plaintext_data_free_(hs_desc_plaintext_data_t *desc);
#define hs_desc_plaintext_data_free(desc) \ #define hs_desc_plaintext_data_free(desc) \
FREE_AND_NULL(hs_desc_plaintext_data_t, hs_desc_plaintext_data_free_, (desc)) FREE_AND_NULL(hs_desc_plaintext_data_t, hs_desc_plaintext_data_free_, (desc))
void hs_desc_superencrypted_data_free_(hs_desc_superencrypted_data_t *desc);
#define hs_desc_superencrypted_data_free(desc) \
FREE_AND_NULL(hs_desc_superencrypted_data_t, \
hs_desc_superencrypted_data_free_, (desc))
void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc); void hs_desc_encrypted_data_free_(hs_desc_encrypted_data_t *desc);
#define hs_desc_encrypted_data_free(desc) \ #define hs_desc_encrypted_data_free(desc) \
FREE_AND_NULL(hs_desc_encrypted_data_t, hs_desc_encrypted_data_free_, (desc)) FREE_AND_NULL(hs_desc_encrypted_data_t, hs_desc_encrypted_data_free_, (desc))
@ -243,10 +295,22 @@ hs_desc_intro_point_t *hs_desc_intro_point_new(void);
void hs_desc_intro_point_free_(hs_desc_intro_point_t *ip); void hs_desc_intro_point_free_(hs_desc_intro_point_t *ip);
#define hs_desc_intro_point_free(ip) \ #define hs_desc_intro_point_free(ip) \
FREE_AND_NULL(hs_desc_intro_point_t, hs_desc_intro_point_free_, (ip)) FREE_AND_NULL(hs_desc_intro_point_t, hs_desc_intro_point_free_, (ip))
void hs_desc_authorized_client_free_(hs_desc_authorized_client_t *client);
#define hs_desc_authorized_client_free(client) \
FREE_AND_NULL(hs_desc_authorized_client_t, \
hs_desc_authorized_client_free_, (client))
link_specifier_t *hs_desc_lspec_to_trunnel( link_specifier_t *hs_desc_lspec_to_trunnel(
const hs_desc_link_specifier_t *spec); const hs_desc_link_specifier_t *spec);
void
hs_desc_build_fake_authorized_client(hs_desc_authorized_client_t *client_out);
void hs_desc_build_authorized_client(const curve25519_public_key_t *client_pk,
const curve25519_secret_key_t *
auth_ephemeral_sk,
const uint8_t *descriptor_cookie,
hs_desc_authorized_client_t *client_out);
#ifdef HS_DESCRIPTOR_PRIVATE #ifdef HS_DESCRIPTOR_PRIVATE
/* Encoding. */ /* Encoding. */

View File

@ -1559,6 +1559,78 @@ build_service_desc_encrypted(const hs_service_t *service,
return 0; return 0;
} }
/* Populate the descriptor superencrypted section from the given service
* object. This will generate a valid list of hs_desc_authorized_client_t
* of clients that are authorized to use the service. Return 0 on success
* else -1 on error. */
static int
build_service_desc_superencrypted(const hs_service_t *service,
hs_service_descriptor_t *desc)
{
const hs_service_config_t *config;
int i;
hs_desc_superencrypted_data_t *superencrypted;
tor_assert(service);
tor_assert(desc);
superencrypted = &desc->desc->superencrypted_data;
config = &service->config;
/* The ephemeral key pair is already generated, so this should not give
* an error. */
memcpy(&superencrypted->auth_ephemeral_pubkey,
&desc->auth_ephemeral_kp.pubkey,
sizeof(curve25519_public_key_t));
/* Create a smartlist to store clients */
superencrypted->clients = smartlist_new();
/* We do not need to build the desc authorized client if the client
* authorization is disabled */
if (config->is_client_auth_enabled) {
SMARTLIST_FOREACH_BEGIN(config->clients,
hs_service_authorized_client_t *, client) {
hs_desc_authorized_client_t *desc_client;
desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t));
/* Prepare the client for descriptor and then add to the list in the
* superencrypted part of the descriptor */
hs_desc_build_authorized_client(&client->client_pk,
&desc->auth_ephemeral_kp.seckey,
desc->descriptor_cookie, desc_client);
smartlist_add(superencrypted->clients, desc_client);
} SMARTLIST_FOREACH_END(client);
}
/* We cannot let the number of auth-clients to be zero, so we need to
* make it be 16. If it is already a multiple of 16, we do not need to
* do anything. Otherwise, add the additional ones to make it a
* multiple of 16. */
int num_clients = smartlist_len(superencrypted->clients);
int num_clients_to_add;
if (num_clients == 0) {
num_clients_to_add = HS_DESC_AUTH_CLIENT_MULTIPLE;
} else if (num_clients % HS_DESC_AUTH_CLIENT_MULTIPLE == 0) {
num_clients_to_add = 0;
} else {
num_clients_to_add =
HS_DESC_AUTH_CLIENT_MULTIPLE
- (num_clients % HS_DESC_AUTH_CLIENT_MULTIPLE);
}
for (i = 0; i < num_clients_to_add; i++) {
hs_desc_authorized_client_t *desc_client;
desc_client = tor_malloc_zero(sizeof(hs_desc_authorized_client_t));
hs_desc_build_fake_authorized_client(desc_client);
smartlist_add(superencrypted->clients, desc_client);
}
return 0;
}
/* Populate the descriptor plaintext section from the given service object. /* Populate the descriptor plaintext section from the given service object.
* The caller must make sure that the keys in the descriptors are valid that * The caller must make sure that the keys in the descriptors are valid that
* is are non-zero. Return 0 on success else -1 on error. */ * is are non-zero. Return 0 on success else -1 on error. */
@ -1624,13 +1696,14 @@ generate_ope_cipher_for_desc(const hs_service_descriptor_t *hs_desc)
} }
/* For the given service and descriptor object, create the key material which /* For the given service and descriptor object, create the key material which
* is the blinded keypair and the descriptor signing keypair. Return 0 on * is the blinded keypair, the descriptor signing keypair, the ephemeral
* success else -1 on error where the generated keys MUST be ignored. */ * keypair, and the descriptor cookie. Return 0 on success else -1 on error
* where the generated keys MUST be ignored. */
static int static int
build_service_desc_keys(const hs_service_t *service, build_service_desc_keys(const hs_service_t *service,
hs_service_descriptor_t *desc) hs_service_descriptor_t *desc)
{ {
int ret = 0; int ret = -1;
ed25519_keypair_t kp; ed25519_keypair_t kp;
tor_assert(desc); tor_assert(desc);
@ -1661,9 +1734,28 @@ build_service_desc_keys(const hs_service_t *service,
log_warn(LD_REND, "Can't generate descriptor signing keypair for " log_warn(LD_REND, "Can't generate descriptor signing keypair for "
"service %s", "service %s",
safe_str_client(service->onion_address)); safe_str_client(service->onion_address));
ret = -1; goto end;
} }
/* No need for extra strong, this is a temporary key only for this
* descriptor. Nothing long term. */
if (curve25519_keypair_generate(&desc->auth_ephemeral_kp, 0) < 0) {
log_warn(LD_REND, "Can't generate auth ephemeral keypair for "
"service %s",
safe_str_client(service->onion_address));
goto end;
}
/* Random a descriptor cookie to be used as a part of a key to encrypt the
* descriptor, if the client auth is enabled. */
if (service->config.is_client_auth_enabled) {
crypto_strongest_rand(desc->descriptor_cookie,
sizeof(desc->descriptor_cookie));
}
/* Success. */
ret = 0;
end:
return ret; return ret;
} }
@ -1697,6 +1789,10 @@ build_service_descriptor(hs_service_t *service, time_t now,
if (build_service_desc_plaintext(service, desc, now) < 0) { if (build_service_desc_plaintext(service, desc, now) < 0) {
goto err; goto err;
} }
/* Setup superencrypted descriptor content. */
if (build_service_desc_superencrypted(service, desc) < 0) {
goto err;
}
/* Setup encrypted descriptor content. */ /* Setup encrypted descriptor content. */
if (build_service_desc_encrypted(service, desc) < 0) { if (build_service_desc_encrypted(service, desc) < 0) {
goto err; goto err;

View File

@ -105,6 +105,13 @@ typedef struct hs_service_descriptor_t {
* publishes the descriptor. */ * publishes the descriptor. */
hs_descriptor_t *desc; hs_descriptor_t *desc;
/* Client authorization ephemeral keypair. */
curve25519_keypair_t auth_ephemeral_kp;
/* Descriptor cookie used to encrypt the descriptor, when the client
* authorization is enabled */
uint8_t descriptor_cookie[HS_DESC_DESCRIPTOR_COOKIE_LEN];
/* Descriptor signing keypair. */ /* Descriptor signing keypair. */
ed25519_keypair_t signing_kp; ed25519_keypair_t signing_kp;