Loading src/or/hs_descriptor.c +194 −32 Original line number Diff line number Diff line Loading @@ -113,6 +113,15 @@ static token_rule_t hs_desc_v3_token_table[] = { END_OF_TABLE }; /* 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), T1N(str_desc_auth_client, R3_DESC_AUTH_CLIENT, GE(3), NO_OBJ), T1(str_encrypted, R3_ENCRYPTED, NO_ARGS, NEED_OBJ), END_OF_TABLE }; /* 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), Loading Loading @@ -1313,12 +1322,17 @@ encrypted_data_length_is_valid(size_t len) return 0; } /* Decrypt the encrypted section of the descriptor using the given descriptor * object desc. A newly allocated NUL terminated string is put in * decrypted_out. Return the length of decrypted_out on success else 0 is * returned and decrypted_out is set to NULL. */ /** Decrypt an encrypted descriptor layer at <b>encrypted_blob</b> of size * <b>encrypted_blob_size</b>. Use the descriptor object <b>desc</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. */ static size_t desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) decrypt_desc_layer(const hs_descriptor_t *desc, const uint8_t *encrypted_blob, size_t encrypted_blob_size, int is_superencrypted_layer, char **decrypted_out) { uint8_t *decrypted = NULL; uint8_t secret_key[HS_DESC_ENCRYPTED_KEY_LEN], secret_iv[CIPHER_IV_LEN]; Loading @@ -1328,41 +1342,33 @@ desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) tor_assert(decrypted_out); tor_assert(desc); tor_assert(desc->plaintext_data.superencrypted_blob); tor_assert(encrypted_blob); /* Construction is as follow: SALT | ENCRYPTED_DATA | MAC */ if (!encrypted_data_length_is_valid( desc->plaintext_data.superencrypted_blob_size)) { /* Construction is as follow: SALT | ENCRYPTED_DATA | MAC . * Make sure we have enough space for all these things. */ if (!encrypted_data_length_is_valid(encrypted_blob_size)) { goto err; } /* Start of the blob thus the salt. */ salt = desc->plaintext_data.superencrypted_blob; salt = encrypted_blob; /* Next is the encrypted data. */ encrypted = desc->plaintext_data.superencrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN; encrypted_len = desc->plaintext_data.superencrypted_blob_size - encrypted = encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN; encrypted_len = encrypted_blob_size - (HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN); tor_assert(encrypted_len > 0); /* guaranteed by the check above */ /* At the very end is the MAC. Make sure it's of the right size. */ { desc_mac = encrypted + encrypted_len; size_t desc_mac_size = desc->plaintext_data.superencrypted_blob_size - (desc_mac - desc->plaintext_data.superencrypted_blob); if (desc_mac_size != DIGEST256_LEN) { log_warn(LD_REND, "Service descriptor MAC length of encrypted data " "is invalid (%lu, expected %u)", (unsigned long) desc_mac_size, DIGEST256_LEN); goto err; } } /* And last comes the MAC. */ desc_mac = encrypted_blob + encrypted_blob_size - DIGEST256_LEN; /* KDF construction resulting in a key from which the secret key, IV and MAC * key are extracted which is what we need for the decryption. */ build_secret_key_iv_mac(desc, salt, HS_DESC_ENCRYPTED_SALT_LEN, secret_key, sizeof(secret_key), secret_iv, sizeof(secret_iv), mac_key, sizeof(mac_key)); mac_key, sizeof(mac_key), is_superencrypted_layer); /* Build MAC. */ build_mac(mac_key, sizeof(mac_key), salt, HS_DESC_ENCRYPTED_SALT_LEN, Loading Loading @@ -1392,7 +1398,7 @@ desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) } { /* Adjust length to remove NULL padding bytes */ /* Adjust length to remove NUL padding bytes */ uint8_t *end = memchr(decrypted, 0, encrypted_len); result_len = encrypted_len; if (end) { Loading @@ -1418,6 +1424,161 @@ desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) return result_len; } /* Basic validation that the superencrypted client auth portion of the * descriptor is well-formed and recognized. Return True if so, otherwise * return False. */ static int superencrypted_auth_data_is_valid(smartlist_t *tokens) { /* XXX: This is just basic validation for now. When we implement client auth, we can refactor this function so that it actually parses and saves the data. */ { /* verify desc auth type */ const directory_token_t *tok; tok = find_by_keyword(tokens, R3_DESC_AUTH_TYPE); tor_assert(tok->n_args >= 1); if (strcmp(tok->args[0], "x25519")) { return 0; } } { /* verify desc auth key */ const directory_token_t *tok; curve25519_public_key_t k; tok = find_by_keyword(tokens, R3_DESC_AUTH_KEY); tor_assert(tok->n_args >= 1); if (curve25519_public_from_base64(&k, tok->args[0]) < 0) { log_warn(LD_DIR, "Bogus desc auth key in HS desc"); return 0; } } /* verify desc auth client items */ SMARTLIST_FOREACH_BEGIN(tokens, const directory_token_t *, tok) { if (tok->tp == R3_DESC_AUTH_CLIENT) { tor_assert(tok->n_args >= 3); } } SMARTLIST_FOREACH_END(tok); return 1; } /* Parse <b>message</b>, the plaintext of the superencrypted portion of an HS * descriptor. Set <b>encrypted_out</b> to the encrypted blob, and return its * size */ STATIC size_t decode_superencrypted(const char *message, size_t message_len, uint8_t **encrypted_out) { int retval = 0; memarea_t *area = NULL; smartlist_t *tokens = NULL; area = memarea_new(); tokens = smartlist_new(); if (tokenize_string(area, message, message + message_len, tokens, hs_desc_superencrypted_v3_token_table, 0) < 0) { log_warn(LD_REND, "Superencrypted portion is not parseable"); goto err; } /* Do some rudimentary validation of the authentication data */ if (!superencrypted_auth_data_is_valid(tokens)) { goto err; } /* Extract the encrypted data section. */ { const directory_token_t *tok; tok = find_by_keyword(tokens, R3_ENCRYPTED); tor_assert(tok->object_body); if (strcmp(tok->object_type, "MESSAGE") != 0) { log_warn(LD_REND, "Desc superencrypted data section is invalid"); goto err; } /* Make sure the length of the encrypted blob is valid. */ if (!encrypted_data_length_is_valid(tok->object_size)) { goto err; } /* Copy the encrypted blob to the descriptor object so we can handle it * latter if needed. */ *encrypted_out = tor_memdup(tok->object_body, tok->object_size); retval = tok->object_size; } err: SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) { memarea_drop_all(area); } return retval; } /* Decrypt both the superencrypted and 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 inner encrypted * layer of the descriptor. Return the length of decrypted_out on success else * 0 is returned and decrypted_out is set to NULL. */ static size_t desc_decrypt_all(const hs_descriptor_t *desc, char **decrypted_out) { size_t decrypted_len = 0; size_t encrypted_len = 0; size_t superencrypted_len = 0; char *superencrypted_plaintext = NULL; uint8_t *encrypted_blob = NULL; /** Function logic: This function takes us from the descriptor header to the * inner encrypted layer, by decrypting and decoding the middle descriptor * layer. In the end we return the contents of the inner encrypted layer to * our caller. */ /* 1. Decrypt middle layer of descriptor */ superencrypted_len = decrypt_desc_layer(desc, desc->plaintext_data.superencrypted_blob, desc->plaintext_data.superencrypted_blob_size, 1, &superencrypted_plaintext); if (!superencrypted_len) { log_warn(LD_REND, "Decrypting superencrypted desc failed."); goto err; } tor_assert(superencrypted_plaintext); /* 2. Parse "superencrypted" */ encrypted_len = decode_superencrypted(superencrypted_plaintext, superencrypted_len, &encrypted_blob); if (!encrypted_len) { log_warn(LD_REND, "Decrypting encrypted desc failed."); goto err; } tor_assert(encrypted_blob); /* 3. Decrypt "encrypted" and set decrypted_out */ char *decrypted_desc; decrypted_len = decrypt_desc_layer(desc, encrypted_blob, encrypted_len, 0, &decrypted_desc); if (!decrypted_len) { log_warn(LD_REND, "Decrypting encrypted desc failed."); goto err; } tor_assert(decrypted_desc); *decrypted_out = decrypted_desc; err: tor_free(superencrypted_plaintext); tor_free(encrypted_blob); return decrypted_len; } /* 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 Loading Loading @@ -1550,7 +1711,9 @@ decode_introduction_point(const hs_descriptor_t *desc, const char *start) tor_cert_free(cross_cert); SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) { memarea_drop_all(area); } return ip; } Loading Loading @@ -1804,10 +1967,9 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, tor_assert(desc); tor_assert(desc_encrypted_out); /* Decrypt the encrypted data that is located in the plaintext section in * the descriptor as a blob of bytes. The following functions will use the * keys found in the same section. */ message_len = desc_decrypt_data_v3(desc, &message); /* Decrypt the superencrypted data that is located in the plaintext section * in the descriptor as a blob of bytes. */ message_len = desc_decrypt_all(desc, &message); if (!message_len) { log_warn(LD_REND, "Service descriptor decryption failed."); goto err; Loading src/or/hs_descriptor.h +2 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,8 @@ STATIC int desc_sig_is_valid(const char *b64_sig, const ed25519_public_key_t *signing_pubkey, const char *encoded_desc, size_t encoded_len); STATIC void desc_intro_point_free(hs_desc_intro_point_t *ip); STATIC size_t decode_superencrypted(const char *message, size_t message_len, uint8_t **encrypted_out); #endif /* HS_DESCRIPTOR_PRIVATE */ #endif /* TOR_HS_DESCRIPTOR_H */ Loading src/or/parsecommon.h +4 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,10 @@ typedef enum { R3_INTRO_AUTH_KEY, R3_INTRO_ENC_KEY, R3_INTRO_ENC_KEY_CERTIFICATION, R3_DESC_AUTH_TYPE, R3_DESC_AUTH_KEY, R3_DESC_AUTH_CLIENT, R3_ENCRYPTED, R_IPO_IDENTIFIER, R_IPO_IP_ADDRESS, Loading Loading
src/or/hs_descriptor.c +194 −32 Original line number Diff line number Diff line Loading @@ -113,6 +113,15 @@ static token_rule_t hs_desc_v3_token_table[] = { END_OF_TABLE }; /* 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), T1N(str_desc_auth_client, R3_DESC_AUTH_CLIENT, GE(3), NO_OBJ), T1(str_encrypted, R3_ENCRYPTED, NO_ARGS, NEED_OBJ), END_OF_TABLE }; /* 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), Loading Loading @@ -1313,12 +1322,17 @@ encrypted_data_length_is_valid(size_t len) return 0; } /* Decrypt the encrypted section of the descriptor using the given descriptor * object desc. A newly allocated NUL terminated string is put in * decrypted_out. Return the length of decrypted_out on success else 0 is * returned and decrypted_out is set to NULL. */ /** Decrypt an encrypted descriptor layer at <b>encrypted_blob</b> of size * <b>encrypted_blob_size</b>. Use the descriptor object <b>desc</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. */ static size_t desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) decrypt_desc_layer(const hs_descriptor_t *desc, const uint8_t *encrypted_blob, size_t encrypted_blob_size, int is_superencrypted_layer, char **decrypted_out) { uint8_t *decrypted = NULL; uint8_t secret_key[HS_DESC_ENCRYPTED_KEY_LEN], secret_iv[CIPHER_IV_LEN]; Loading @@ -1328,41 +1342,33 @@ desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) tor_assert(decrypted_out); tor_assert(desc); tor_assert(desc->plaintext_data.superencrypted_blob); tor_assert(encrypted_blob); /* Construction is as follow: SALT | ENCRYPTED_DATA | MAC */ if (!encrypted_data_length_is_valid( desc->plaintext_data.superencrypted_blob_size)) { /* Construction is as follow: SALT | ENCRYPTED_DATA | MAC . * Make sure we have enough space for all these things. */ if (!encrypted_data_length_is_valid(encrypted_blob_size)) { goto err; } /* Start of the blob thus the salt. */ salt = desc->plaintext_data.superencrypted_blob; salt = encrypted_blob; /* Next is the encrypted data. */ encrypted = desc->plaintext_data.superencrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN; encrypted_len = desc->plaintext_data.superencrypted_blob_size - encrypted = encrypted_blob + HS_DESC_ENCRYPTED_SALT_LEN; encrypted_len = encrypted_blob_size - (HS_DESC_ENCRYPTED_SALT_LEN + DIGEST256_LEN); tor_assert(encrypted_len > 0); /* guaranteed by the check above */ /* At the very end is the MAC. Make sure it's of the right size. */ { desc_mac = encrypted + encrypted_len; size_t desc_mac_size = desc->plaintext_data.superencrypted_blob_size - (desc_mac - desc->plaintext_data.superencrypted_blob); if (desc_mac_size != DIGEST256_LEN) { log_warn(LD_REND, "Service descriptor MAC length of encrypted data " "is invalid (%lu, expected %u)", (unsigned long) desc_mac_size, DIGEST256_LEN); goto err; } } /* And last comes the MAC. */ desc_mac = encrypted_blob + encrypted_blob_size - DIGEST256_LEN; /* KDF construction resulting in a key from which the secret key, IV and MAC * key are extracted which is what we need for the decryption. */ build_secret_key_iv_mac(desc, salt, HS_DESC_ENCRYPTED_SALT_LEN, secret_key, sizeof(secret_key), secret_iv, sizeof(secret_iv), mac_key, sizeof(mac_key)); mac_key, sizeof(mac_key), is_superencrypted_layer); /* Build MAC. */ build_mac(mac_key, sizeof(mac_key), salt, HS_DESC_ENCRYPTED_SALT_LEN, Loading Loading @@ -1392,7 +1398,7 @@ desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) } { /* Adjust length to remove NULL padding bytes */ /* Adjust length to remove NUL padding bytes */ uint8_t *end = memchr(decrypted, 0, encrypted_len); result_len = encrypted_len; if (end) { Loading @@ -1418,6 +1424,161 @@ desc_decrypt_data_v3(const hs_descriptor_t *desc, char **decrypted_out) return result_len; } /* Basic validation that the superencrypted client auth portion of the * descriptor is well-formed and recognized. Return True if so, otherwise * return False. */ static int superencrypted_auth_data_is_valid(smartlist_t *tokens) { /* XXX: This is just basic validation for now. When we implement client auth, we can refactor this function so that it actually parses and saves the data. */ { /* verify desc auth type */ const directory_token_t *tok; tok = find_by_keyword(tokens, R3_DESC_AUTH_TYPE); tor_assert(tok->n_args >= 1); if (strcmp(tok->args[0], "x25519")) { return 0; } } { /* verify desc auth key */ const directory_token_t *tok; curve25519_public_key_t k; tok = find_by_keyword(tokens, R3_DESC_AUTH_KEY); tor_assert(tok->n_args >= 1); if (curve25519_public_from_base64(&k, tok->args[0]) < 0) { log_warn(LD_DIR, "Bogus desc auth key in HS desc"); return 0; } } /* verify desc auth client items */ SMARTLIST_FOREACH_BEGIN(tokens, const directory_token_t *, tok) { if (tok->tp == R3_DESC_AUTH_CLIENT) { tor_assert(tok->n_args >= 3); } } SMARTLIST_FOREACH_END(tok); return 1; } /* Parse <b>message</b>, the plaintext of the superencrypted portion of an HS * descriptor. Set <b>encrypted_out</b> to the encrypted blob, and return its * size */ STATIC size_t decode_superencrypted(const char *message, size_t message_len, uint8_t **encrypted_out) { int retval = 0; memarea_t *area = NULL; smartlist_t *tokens = NULL; area = memarea_new(); tokens = smartlist_new(); if (tokenize_string(area, message, message + message_len, tokens, hs_desc_superencrypted_v3_token_table, 0) < 0) { log_warn(LD_REND, "Superencrypted portion is not parseable"); goto err; } /* Do some rudimentary validation of the authentication data */ if (!superencrypted_auth_data_is_valid(tokens)) { goto err; } /* Extract the encrypted data section. */ { const directory_token_t *tok; tok = find_by_keyword(tokens, R3_ENCRYPTED); tor_assert(tok->object_body); if (strcmp(tok->object_type, "MESSAGE") != 0) { log_warn(LD_REND, "Desc superencrypted data section is invalid"); goto err; } /* Make sure the length of the encrypted blob is valid. */ if (!encrypted_data_length_is_valid(tok->object_size)) { goto err; } /* Copy the encrypted blob to the descriptor object so we can handle it * latter if needed. */ *encrypted_out = tor_memdup(tok->object_body, tok->object_size); retval = tok->object_size; } err: SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) { memarea_drop_all(area); } return retval; } /* Decrypt both the superencrypted and 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 inner encrypted * layer of the descriptor. Return the length of decrypted_out on success else * 0 is returned and decrypted_out is set to NULL. */ static size_t desc_decrypt_all(const hs_descriptor_t *desc, char **decrypted_out) { size_t decrypted_len = 0; size_t encrypted_len = 0; size_t superencrypted_len = 0; char *superencrypted_plaintext = NULL; uint8_t *encrypted_blob = NULL; /** Function logic: This function takes us from the descriptor header to the * inner encrypted layer, by decrypting and decoding the middle descriptor * layer. In the end we return the contents of the inner encrypted layer to * our caller. */ /* 1. Decrypt middle layer of descriptor */ superencrypted_len = decrypt_desc_layer(desc, desc->plaintext_data.superencrypted_blob, desc->plaintext_data.superencrypted_blob_size, 1, &superencrypted_plaintext); if (!superencrypted_len) { log_warn(LD_REND, "Decrypting superencrypted desc failed."); goto err; } tor_assert(superencrypted_plaintext); /* 2. Parse "superencrypted" */ encrypted_len = decode_superencrypted(superencrypted_plaintext, superencrypted_len, &encrypted_blob); if (!encrypted_len) { log_warn(LD_REND, "Decrypting encrypted desc failed."); goto err; } tor_assert(encrypted_blob); /* 3. Decrypt "encrypted" and set decrypted_out */ char *decrypted_desc; decrypted_len = decrypt_desc_layer(desc, encrypted_blob, encrypted_len, 0, &decrypted_desc); if (!decrypted_len) { log_warn(LD_REND, "Decrypting encrypted desc failed."); goto err; } tor_assert(decrypted_desc); *decrypted_out = decrypted_desc; err: tor_free(superencrypted_plaintext); tor_free(encrypted_blob); return decrypted_len; } /* 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 Loading Loading @@ -1550,7 +1711,9 @@ decode_introduction_point(const hs_descriptor_t *desc, const char *start) tor_cert_free(cross_cert); SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); if (area) { memarea_drop_all(area); } return ip; } Loading Loading @@ -1804,10 +1967,9 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc, tor_assert(desc); tor_assert(desc_encrypted_out); /* Decrypt the encrypted data that is located in the plaintext section in * the descriptor as a blob of bytes. The following functions will use the * keys found in the same section. */ message_len = desc_decrypt_data_v3(desc, &message); /* Decrypt the superencrypted data that is located in the plaintext section * in the descriptor as a blob of bytes. */ message_len = desc_decrypt_all(desc, &message); if (!message_len) { log_warn(LD_REND, "Service descriptor decryption failed."); goto err; Loading
src/or/hs_descriptor.h +2 −0 Original line number Diff line number Diff line Loading @@ -228,6 +228,8 @@ STATIC int desc_sig_is_valid(const char *b64_sig, const ed25519_public_key_t *signing_pubkey, const char *encoded_desc, size_t encoded_len); STATIC void desc_intro_point_free(hs_desc_intro_point_t *ip); STATIC size_t decode_superencrypted(const char *message, size_t message_len, uint8_t **encrypted_out); #endif /* HS_DESCRIPTOR_PRIVATE */ #endif /* TOR_HS_DESCRIPTOR_H */ Loading
src/or/parsecommon.h +4 −0 Original line number Diff line number Diff line Loading @@ -163,6 +163,10 @@ typedef enum { R3_INTRO_AUTH_KEY, R3_INTRO_ENC_KEY, R3_INTRO_ENC_KEY_CERTIFICATION, R3_DESC_AUTH_TYPE, R3_DESC_AUTH_KEY, R3_DESC_AUTH_CLIENT, R3_ENCRYPTED, R_IPO_IDENTIFIER, R_IPO_IP_ADDRESS, Loading