mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 21:53:48 +01:00
164 lines
5.8 KiB
C
164 lines
5.8 KiB
C
|
/* Copyright (c) 2017, The Tor Project, Inc. */
|
||
|
/* See LICENSE for licensing information */
|
||
|
|
||
|
/**
|
||
|
* \file hs_cell.c
|
||
|
* \brief Hidden service API for cell creation and handling.
|
||
|
**/
|
||
|
|
||
|
#include "or.h"
|
||
|
#include "rendservice.h"
|
||
|
|
||
|
#include "hs_cell.h"
|
||
|
|
||
|
/* Trunnel. */
|
||
|
#include "hs/cell_common.h"
|
||
|
#include "hs/cell_establish_intro.h"
|
||
|
|
||
|
/* Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
|
||
|
* encryption key. The encoded cell is put in cell_out that MUST at least be
|
||
|
* of the size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on
|
||
|
* success else a negative value and cell_out is untouched. */
|
||
|
static ssize_t
|
||
|
build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key,
|
||
|
uint8_t *cell_out)
|
||
|
{
|
||
|
ssize_t cell_len;
|
||
|
char buf[RELAY_PAYLOAD_SIZE] = {0};
|
||
|
|
||
|
tor_assert(circ_nonce);
|
||
|
tor_assert(enc_key);
|
||
|
tor_assert(cell_out);
|
||
|
|
||
|
cell_len = rend_service_encode_establish_intro_cell(buf, sizeof(buf),
|
||
|
enc_key, circ_nonce);
|
||
|
tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
|
||
|
if (cell_len >= 0) {
|
||
|
memcpy(cell_out, buf, cell_len);
|
||
|
}
|
||
|
return cell_len;
|
||
|
}
|
||
|
|
||
|
/* ========== */
|
||
|
/* Public API */
|
||
|
/* ========== */
|
||
|
|
||
|
/* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
|
||
|
* object. The encoded cell is put in cell_out that MUST at least be of the
|
||
|
* size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
|
||
|
* a negative value and cell_out is untouched. This function also supports
|
||
|
* legacy cell creation. */
|
||
|
ssize_t
|
||
|
hs_cell_build_establish_intro(const char *circ_nonce,
|
||
|
const hs_service_intro_point_t *ip,
|
||
|
uint8_t *cell_out)
|
||
|
{
|
||
|
ssize_t cell_len = -1;
|
||
|
uint16_t sig_len = ED25519_SIG_LEN;
|
||
|
trn_cell_extension_t *ext;
|
||
|
trn_cell_establish_intro_t *cell = NULL;
|
||
|
|
||
|
tor_assert(circ_nonce);
|
||
|
tor_assert(ip);
|
||
|
|
||
|
/* Quickly handle the legacy IP. */
|
||
|
if (ip->base.is_only_legacy) {
|
||
|
tor_assert(ip->legacy_key);
|
||
|
cell_len = build_legacy_establish_intro(circ_nonce, ip->legacy_key,
|
||
|
cell_out);
|
||
|
tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
|
||
|
/* Success or not we are done here. */
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
/* Set extension data. None used here. */
|
||
|
ext = trn_cell_extension_new();
|
||
|
trn_cell_extension_set_num(ext, 0);
|
||
|
cell = trn_cell_establish_intro_new();
|
||
|
trn_cell_establish_intro_set_extensions(cell, ext);
|
||
|
/* Set signature size. Array is then allocated in the cell. We need to do
|
||
|
* this early so we can use trunnel API to get the signature length. */
|
||
|
trn_cell_establish_intro_set_sig_len(cell, sig_len);
|
||
|
trn_cell_establish_intro_setlen_sig(cell, sig_len);
|
||
|
|
||
|
/* Set AUTH_KEY_TYPE: 2 means ed25519 */
|
||
|
trn_cell_establish_intro_set_auth_key_type(cell,
|
||
|
HS_INTRO_AUTH_KEY_TYPE_ED25519);
|
||
|
|
||
|
/* Set AUTH_KEY and AUTH_KEY_LEN field. Must also set byte-length of
|
||
|
* AUTH_KEY to match */
|
||
|
{
|
||
|
uint16_t auth_key_len = ED25519_PUBKEY_LEN;
|
||
|
trn_cell_establish_intro_set_auth_key_len(cell, auth_key_len);
|
||
|
trn_cell_establish_intro_setlen_auth_key(cell, auth_key_len);
|
||
|
/* We do this call _after_ setting the length because it's reallocated at
|
||
|
* that point only. */
|
||
|
uint8_t *auth_key_ptr = trn_cell_establish_intro_getarray_auth_key(cell);
|
||
|
memcpy(auth_key_ptr, ip->auth_key_kp.pubkey.pubkey, auth_key_len);
|
||
|
}
|
||
|
|
||
|
/* Calculate HANDSHAKE_AUTH field (MAC). */
|
||
|
{
|
||
|
ssize_t tmp_cell_enc_len = 0;
|
||
|
ssize_t tmp_cell_mac_offset =
|
||
|
sig_len + sizeof(cell->sig_len) +
|
||
|
trn_cell_establish_intro_getlen_handshake_mac(cell);
|
||
|
uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0};
|
||
|
uint8_t mac[TRUNNEL_SHA3_256_LEN], *handshake_ptr;
|
||
|
|
||
|
/* We first encode the current fields we have in the cell so we can
|
||
|
* compute the MAC using the raw bytes. */
|
||
|
tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
|
||
|
sizeof(tmp_cell_enc),
|
||
|
cell);
|
||
|
if (BUG(tmp_cell_enc_len < 0)) {
|
||
|
goto done;
|
||
|
}
|
||
|
/* Sanity check. */
|
||
|
tor_assert(tmp_cell_enc_len > tmp_cell_mac_offset);
|
||
|
|
||
|
/* Circuit nonce is always DIGEST_LEN according to tor-spec.txt. */
|
||
|
crypto_mac_sha3_256(mac, sizeof(mac),
|
||
|
(uint8_t *) circ_nonce, DIGEST_LEN,
|
||
|
tmp_cell_enc, tmp_cell_enc_len - tmp_cell_mac_offset);
|
||
|
handshake_ptr = trn_cell_establish_intro_getarray_handshake_mac(cell);
|
||
|
memcpy(handshake_ptr, mac, sizeof(mac));
|
||
|
}
|
||
|
|
||
|
/* Calculate the cell signature SIG. */
|
||
|
{
|
||
|
ssize_t tmp_cell_enc_len = 0;
|
||
|
ssize_t tmp_cell_sig_offset = (sig_len + sizeof(cell->sig_len));
|
||
|
uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}, *sig_ptr;
|
||
|
ed25519_signature_t sig;
|
||
|
|
||
|
/* We first encode the current fields we have in the cell so we can
|
||
|
* compute the signature from the raw bytes of the cell. */
|
||
|
tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
|
||
|
sizeof(tmp_cell_enc),
|
||
|
cell);
|
||
|
if (BUG(tmp_cell_enc_len < 0)) {
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if (ed25519_sign_prefixed(&sig, tmp_cell_enc,
|
||
|
tmp_cell_enc_len - tmp_cell_sig_offset,
|
||
|
ESTABLISH_INTRO_SIG_PREFIX, &ip->auth_key_kp)) {
|
||
|
log_warn(LD_BUG, "Unable to make signature for ESTABLISH_INTRO cell.");
|
||
|
goto done;
|
||
|
}
|
||
|
/* Copy the signature into the cell. */
|
||
|
sig_ptr = trn_cell_establish_intro_getarray_sig(cell);
|
||
|
memcpy(sig_ptr, sig.sig, sig_len);
|
||
|
}
|
||
|
|
||
|
/* Encode the cell. Can't be bigger than a standard cell. */
|
||
|
cell_len = trn_cell_establish_intro_encode(cell_out, RELAY_PAYLOAD_SIZE,
|
||
|
cell);
|
||
|
|
||
|
done:
|
||
|
trn_cell_establish_intro_free(cell);
|
||
|
return cell_len;
|
||
|
}
|
||
|
|