[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor/master] hs-v3: Generate all descriptor related keys
commit 08bbcffc0ef6e69c02cc746568724df662654d2b
Author: Suphanat Chunhapanya <haxx.pop@xxxxxxxxx>
Date: Mon Apr 9 23:09:41 2018 +0700
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@xxxxxxxxxxxxxx>
---
src/feature/hs/hs_descriptor.c | 107 +++++++++++++++++++++++++++++++++++++++++
src/feature/hs/hs_descriptor.h | 64 ++++++++++++++++++++++++
src/feature/hs/hs_service.c | 104 +++++++++++++++++++++++++++++++++++++--
src/feature/hs/hs_service.h | 7 +++
4 files changed, 278 insertions(+), 4 deletions(-)
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index 392800016..34ff2b0a3 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -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)
diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h
index bfdf7559c..3e7dcc457 100644
--- a/src/feature/hs/hs_descriptor.h
+++ b/src/feature/hs/hs_descriptor.h
@@ -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. */
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index 8d1ee82ab..0ffe0926d 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -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;
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index cab9b41bc..f1b98b805 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -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;
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits