mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
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:
parent
15af47ede0
commit
08bbcffc0e
@ -168,6 +168,26 @@ 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. */
|
||||
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. */
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
void
|
||||
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_superencrypted_data_free_contents(&desc->superencrypted_data);
|
||||
desc_encrypted_data_free_contents(&desc->encrypted_data);
|
||||
tor_free(desc);
|
||||
}
|
||||
@ -2475,6 +2504,84 @@ hs_desc_intro_point_free_(hs_desc_intro_point_t *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. */
|
||||
void
|
||||
hs_desc_link_specifier_free_(hs_desc_link_specifier_t *ls)
|
||||
|
@ -59,6 +59,17 @@ struct link_specifier_t;
|
||||
#define HS_DESC_ENCRYPTED_KEY_LEN CIPHER256_KEY_LEN
|
||||
#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. */
|
||||
typedef enum {
|
||||
HS_DESC_AUTH_ED25519 = 1
|
||||
@ -126,6 +137,20 @@ typedef struct hs_desc_intro_point_t {
|
||||
unsigned int cross_certified : 1;
|
||||
} 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
|
||||
* in plaintext but encrypted once encoded. */
|
||||
typedef struct hs_desc_encrypted_data_t {
|
||||
@ -144,6 +169,24 @@ typedef struct hs_desc_encrypted_data_t {
|
||||
smartlist_t *intro_points;
|
||||
} 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. */
|
||||
typedef struct hs_desc_plaintext_data_t {
|
||||
/* 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. */
|
||||
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.
|
||||
* It's only encrypted in the encoded version of the descriptor thus the
|
||||
* 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);
|
||||
#define 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);
|
||||
#define 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);
|
||||
#define 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(
|
||||
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
|
||||
|
||||
/* Encoding. */
|
||||
|
@ -1559,6 +1559,78 @@ build_service_desc_encrypted(const hs_service_t *service,
|
||||
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.
|
||||
* 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. */
|
||||
@ -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
|
||||
* is the blinded keypair and the descriptor signing keypair. Return 0 on
|
||||
* success else -1 on error where the generated keys MUST be ignored. */
|
||||
* is the blinded keypair, the descriptor signing keypair, the ephemeral
|
||||
* keypair, and the descriptor cookie. Return 0 on success else -1 on error
|
||||
* where the generated keys MUST be ignored. */
|
||||
static int
|
||||
build_service_desc_keys(const hs_service_t *service,
|
||||
hs_service_descriptor_t *desc)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = -1;
|
||||
ed25519_keypair_t kp;
|
||||
|
||||
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 "
|
||||
"service %s",
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1697,6 +1789,10 @@ build_service_descriptor(hs_service_t *service, time_t now,
|
||||
if (build_service_desc_plaintext(service, desc, now) < 0) {
|
||||
goto err;
|
||||
}
|
||||
/* Setup superencrypted descriptor content. */
|
||||
if (build_service_desc_superencrypted(service, desc) < 0) {
|
||||
goto err;
|
||||
}
|
||||
/* Setup encrypted descriptor content. */
|
||||
if (build_service_desc_encrypted(service, desc) < 0) {
|
||||
goto err;
|
||||
|
@ -105,6 +105,13 @@ typedef struct hs_service_descriptor_t {
|
||||
* publishes the descriptor. */
|
||||
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. */
|
||||
ed25519_keypair_t signing_kp;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user