diff options
Diffstat (limited to 'src/or/hs_descriptor.c')
-rw-r--r-- | src/or/hs_descriptor.c | 109 |
1 files changed, 91 insertions, 18 deletions
diff --git a/src/or/hs_descriptor.c b/src/or/hs_descriptor.c index cb3e934614..3b9ee8aa2d 100644 --- a/src/or/hs_descriptor.c +++ b/src/or/hs_descriptor.c @@ -4,6 +4,52 @@ /** * \file hs_descriptor.c * \brief Handle hidden service descriptor encoding/decoding. + * + * \details + * Here is a graphical depiction of an HS descriptor and its layers: + * + * +------------------------------------------------------+ + * |DESCRIPTOR HEADER: | + * | hs-descriptor 3 | + * | descriptor-lifetime 180 | + * | ... | + * | superencrypted | + * |+---------------------------------------------------+ | + * ||SUPERENCRYPTED LAYER (aka OUTER ENCRYPTED LAYER): | | + * || desc-auth-type x25519 | | + * || desc-auth-ephemeral-key | | + * || auth-client | | + * || auth-client | | + * || ... | | + * || encrypted | | + * ||+-------------------------------------------------+| | + * |||ENCRYPTED LAYER (aka INNER ENCRYPTED LAYER): || | + * ||| create2-formats || | + * ||| intro-auth-required || | + * ||| introduction-point || | + * ||| introduction-point || | + * ||| ... || | + * ||+-------------------------------------------------+| | + * |+---------------------------------------------------+ | + * +------------------------------------------------------+ + * + * The DESCRIPTOR HEADER section is completely unencrypted and contains generic + * descriptor metadata. + * + * The SUPERENCRYPTED LAYER section is the first layer of encryption, and it's + * encrypted using the blinded public key of the hidden service to protect + * against entities who don't know its onion address. The clients of the hidden + * service know its onion address and blinded public key, whereas third-parties + * (like HSDirs) don't know it (except if it's a public hidden service). + * + * The ENCRYPTED LAYER section is the second layer of encryption, and it's + * encrypted using the client authorization key material (if those exist). When + * client authorization is enabled, this second layer of encryption protects + * the descriptor content from unauthorized entities. If client authorization + * is disabled, this second layer of encryption does not provide any extra + * security but is still present. The plaintext of this layer contains all the + * information required to connect to the hidden service like its list of + * introduction points. **/ /* For unit tests.*/ @@ -23,6 +69,7 @@ #define str_desc_cert "descriptor-signing-key-cert" #define str_rev_counter "revision-counter" #define str_superencrypted "superencrypted" +#define str_encrypted "encrypted" #define str_signature "signature" #define str_lifetime "descriptor-lifetime" /* Constant string value for the encrypted part of the descriptor. */ @@ -36,9 +83,14 @@ #define str_intro_point_start "\n" str_intro_point " " /* Constant string value for the construction to encrypt the encrypted data * section. */ -#define str_enc_hsdir_data "hsdir-superencrypted-data" +#define str_enc_const_superencryption "hsdir-superencrypted-data" +#define str_enc_const_encryption "hsdir-encrypted-data" /* Prefix required to compute/verify HS desc signatures */ #define str_desc_sig_prefix "Tor onion service descriptor sig v3" +#define str_desc_auth_type "desc-auth-type" +#define str_desc_auth_key "desc-auth-ephemeral-key" +#define str_desc_auth_client "auth-client" +#define str_encrypted "encrypted" /* Authentication supported types. */ static const struct { @@ -393,7 +445,8 @@ build_secret_input(const hs_descriptor_t *desc, uint8_t *dst, size_t dstlen) static void build_kdf_key(const hs_descriptor_t *desc, const uint8_t *salt, size_t salt_len, - uint8_t *key_out, size_t key_out_len) + uint8_t *key_out, size_t key_out_len, + int is_superencrypted_layer) { uint8_t secret_input[HS_DESC_ENCRYPTED_SECRET_INPUT_LEN]; crypto_xof_t *xof; @@ -409,8 +462,16 @@ build_kdf_key(const hs_descriptor_t *desc, /* Feed our KDF. [SHAKE it like a polaroid picture --Yawning]. */ crypto_xof_add_bytes(xof, secret_input, sizeof(secret_input)); crypto_xof_add_bytes(xof, salt, salt_len); - crypto_xof_add_bytes(xof, (const uint8_t *) str_enc_hsdir_data, - strlen(str_enc_hsdir_data)); + + /* Feed in the right string constant based on the desc layer */ + if (is_superencrypted_layer) { + crypto_xof_add_bytes(xof, (const uint8_t *) str_enc_const_superencryption, + strlen(str_enc_const_superencryption)); + } else { + crypto_xof_add_bytes(xof, (const uint8_t *) str_enc_const_encryption, + strlen(str_enc_const_encryption)); + } + /* Eat from our KDF. */ crypto_xof_squeeze_bytes(xof, key_out, key_out_len); crypto_xof_free(xof); @@ -425,7 +486,8 @@ build_secret_key_iv_mac(const hs_descriptor_t *desc, const uint8_t *salt, size_t salt_len, uint8_t *key_out, size_t key_len, uint8_t *iv_out, size_t iv_len, - uint8_t *mac_out, size_t mac_len) + uint8_t *mac_out, size_t mac_len, + int is_superencrypted_layer) { size_t offset = 0; uint8_t kdf_key[HS_DESC_ENCRYPTED_KDF_OUTPUT_LEN]; @@ -436,7 +498,8 @@ build_secret_key_iv_mac(const hs_descriptor_t *desc, tor_assert(iv_out); tor_assert(mac_out); - build_kdf_key(desc, salt, salt_len, kdf_key, sizeof(kdf_key)); + build_kdf_key(desc, salt, salt_len, kdf_key, sizeof(kdf_key), + is_superencrypted_layer); /* Copy the bytes we need for both the secret key and IV. */ memcpy(key_out, kdf_key, key_len); offset += key_len; @@ -529,7 +592,8 @@ build_plaintext_padding(const char *plaintext, size_t plaintext_len, * data. Return size of the encrypted data buffer. */ static size_t build_encrypted(const uint8_t *key, const uint8_t *iv, const char *plaintext, - size_t plaintext_len, uint8_t **encrypted_out) + size_t plaintext_len, uint8_t **encrypted_out, + int is_superencrypted_layer) { size_t encrypted_len; uint8_t *padded_plaintext, *encrypted; @@ -540,15 +604,21 @@ build_encrypted(const uint8_t *key, const uint8_t *iv, const char *plaintext, tor_assert(plaintext); tor_assert(encrypted_out); + /* If we are encrypting the middle layer of the descriptor, we need to first + pad the plaintext */ + if (is_superencrypted_layer) { + encrypted_len = build_plaintext_padding(plaintext, plaintext_len, + &padded_plaintext); + /* Extra precautions that we have a valid padding length. */ + tor_assert(!(encrypted_len % HS_DESC_PLAINTEXT_PADDING_MULTIPLE)); + } else { /* No padding required for inner layers */ + padded_plaintext = tor_memdup(plaintext, plaintext_len); + encrypted_len = plaintext_len; + } + /* This creates a cipher for AES. It can't fail. */ cipher = crypto_cipher_new_with_iv_and_bits(key, iv, HS_DESC_ENCRYPTED_BIT_SIZE); - /* This can't fail. */ - encrypted_len = build_plaintext_padding(plaintext, plaintext_len, - &padded_plaintext); - /* Extra precautions that we have a valie padding length. */ - tor_assert(encrypted_len <= HS_DESC_PADDED_PLAINTEXT_MAX_LEN); - tor_assert(!(encrypted_len % HS_DESC_PLAINTEXT_PADDING_MULTIPLE)); /* We use a stream cipher so the encrypted length will be the same as the * plaintext padded length. */ encrypted = tor_malloc_zero(encrypted_len); @@ -562,12 +632,13 @@ build_encrypted(const uint8_t *key, const uint8_t *iv, const char *plaintext, return encrypted_len; } -/* Encrypt the given plaintext buffer and using the descriptor to get the +/* Encrypt the given <b>plaintext</b> buffer using <b>desc</b> to get the * keys. Set encrypted_out with the encrypted data and return the length of - * it. */ + * it. <b>is_superencrypted_layer</b> is set if this is the outer encrypted + * layer of the descriptor. */ static size_t encrypt_descriptor_data(const hs_descriptor_t *desc, const char *plaintext, - char **encrypted_out) + char **encrypted_out, int is_superencrypted_layer) { char *final_blob; size_t encrypted_len, final_blob_len, offset = 0; @@ -588,11 +659,13 @@ encrypt_descriptor_data(const hs_descriptor_t *desc, const char *plaintext, build_secret_key_iv_mac(desc, salt, sizeof(salt), secret_key, sizeof(secret_key), secret_iv, sizeof(secret_iv), - mac_key, sizeof(mac_key)); + mac_key, sizeof(mac_key), + is_superencrypted_layer); /* Build the encrypted part that is do the actual encryption. */ encrypted_len = build_encrypted(secret_key, secret_iv, plaintext, - strlen(plaintext), &encrypted); + strlen(plaintext), &encrypted, + is_superencrypted_layer); memwipe(secret_key, 0, sizeof(secret_key)); memwipe(secret_iv, 0, sizeof(secret_iv)); /* This construction is specified in section 2.5 of proposal 224. */ |