hs_cell.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /* Copyright (c) 2017, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file hs_cell.c
  5. * \brief Hidden service API for cell creation and handling.
  6. **/
  7. #include "or.h"
  8. #include "rendservice.h"
  9. #include "hs_cell.h"
  10. /* Trunnel. */
  11. #include "hs/cell_common.h"
  12. #include "hs/cell_establish_intro.h"
  13. /* Build a legacy ESTABLISH_INTRO cell with the given circuit nonce and RSA
  14. * encryption key. The encoded cell is put in cell_out that MUST at least be
  15. * of the size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on
  16. * success else a negative value and cell_out is untouched. */
  17. static ssize_t
  18. build_legacy_establish_intro(const char *circ_nonce, crypto_pk_t *enc_key,
  19. uint8_t *cell_out)
  20. {
  21. ssize_t cell_len;
  22. char buf[RELAY_PAYLOAD_SIZE] = {0};
  23. tor_assert(circ_nonce);
  24. tor_assert(enc_key);
  25. tor_assert(cell_out);
  26. cell_len = rend_service_encode_establish_intro_cell(buf, sizeof(buf),
  27. enc_key, circ_nonce);
  28. tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
  29. if (cell_len >= 0) {
  30. memcpy(cell_out, buf, cell_len);
  31. }
  32. return cell_len;
  33. }
  34. /* ========== */
  35. /* Public API */
  36. /* ========== */
  37. /* Build an ESTABLISH_INTRO cell with the given circuit nonce and intro point
  38. * object. The encoded cell is put in cell_out that MUST at least be of the
  39. * size of RELAY_PAYLOAD_SIZE. Return the encoded cell length on success else
  40. * a negative value and cell_out is untouched. This function also supports
  41. * legacy cell creation. */
  42. ssize_t
  43. hs_cell_build_establish_intro(const char *circ_nonce,
  44. const hs_service_intro_point_t *ip,
  45. uint8_t *cell_out)
  46. {
  47. ssize_t cell_len = -1;
  48. uint16_t sig_len = ED25519_SIG_LEN;
  49. trn_cell_extension_t *ext;
  50. trn_cell_establish_intro_t *cell = NULL;
  51. tor_assert(circ_nonce);
  52. tor_assert(ip);
  53. /* Quickly handle the legacy IP. */
  54. if (ip->base.is_only_legacy) {
  55. tor_assert(ip->legacy_key);
  56. cell_len = build_legacy_establish_intro(circ_nonce, ip->legacy_key,
  57. cell_out);
  58. tor_assert(cell_len <= RELAY_PAYLOAD_SIZE);
  59. /* Success or not we are done here. */
  60. goto done;
  61. }
  62. /* Set extension data. None used here. */
  63. ext = trn_cell_extension_new();
  64. trn_cell_extension_set_num(ext, 0);
  65. cell = trn_cell_establish_intro_new();
  66. trn_cell_establish_intro_set_extensions(cell, ext);
  67. /* Set signature size. Array is then allocated in the cell. We need to do
  68. * this early so we can use trunnel API to get the signature length. */
  69. trn_cell_establish_intro_set_sig_len(cell, sig_len);
  70. trn_cell_establish_intro_setlen_sig(cell, sig_len);
  71. /* Set AUTH_KEY_TYPE: 2 means ed25519 */
  72. trn_cell_establish_intro_set_auth_key_type(cell,
  73. HS_INTRO_AUTH_KEY_TYPE_ED25519);
  74. /* Set AUTH_KEY and AUTH_KEY_LEN field. Must also set byte-length of
  75. * AUTH_KEY to match */
  76. {
  77. uint16_t auth_key_len = ED25519_PUBKEY_LEN;
  78. trn_cell_establish_intro_set_auth_key_len(cell, auth_key_len);
  79. trn_cell_establish_intro_setlen_auth_key(cell, auth_key_len);
  80. /* We do this call _after_ setting the length because it's reallocated at
  81. * that point only. */
  82. uint8_t *auth_key_ptr = trn_cell_establish_intro_getarray_auth_key(cell);
  83. memcpy(auth_key_ptr, ip->auth_key_kp.pubkey.pubkey, auth_key_len);
  84. }
  85. /* Calculate HANDSHAKE_AUTH field (MAC). */
  86. {
  87. ssize_t tmp_cell_enc_len = 0;
  88. ssize_t tmp_cell_mac_offset =
  89. sig_len + sizeof(cell->sig_len) +
  90. trn_cell_establish_intro_getlen_handshake_mac(cell);
  91. uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0};
  92. uint8_t mac[TRUNNEL_SHA3_256_LEN], *handshake_ptr;
  93. /* We first encode the current fields we have in the cell so we can
  94. * compute the MAC using the raw bytes. */
  95. tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
  96. sizeof(tmp_cell_enc),
  97. cell);
  98. if (BUG(tmp_cell_enc_len < 0)) {
  99. goto done;
  100. }
  101. /* Sanity check. */
  102. tor_assert(tmp_cell_enc_len > tmp_cell_mac_offset);
  103. /* Circuit nonce is always DIGEST_LEN according to tor-spec.txt. */
  104. crypto_mac_sha3_256(mac, sizeof(mac),
  105. (uint8_t *) circ_nonce, DIGEST_LEN,
  106. tmp_cell_enc, tmp_cell_enc_len - tmp_cell_mac_offset);
  107. handshake_ptr = trn_cell_establish_intro_getarray_handshake_mac(cell);
  108. memcpy(handshake_ptr, mac, sizeof(mac));
  109. }
  110. /* Calculate the cell signature SIG. */
  111. {
  112. ssize_t tmp_cell_enc_len = 0;
  113. ssize_t tmp_cell_sig_offset = (sig_len + sizeof(cell->sig_len));
  114. uint8_t tmp_cell_enc[RELAY_PAYLOAD_SIZE] = {0}, *sig_ptr;
  115. ed25519_signature_t sig;
  116. /* We first encode the current fields we have in the cell so we can
  117. * compute the signature from the raw bytes of the cell. */
  118. tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
  119. sizeof(tmp_cell_enc),
  120. cell);
  121. if (BUG(tmp_cell_enc_len < 0)) {
  122. goto done;
  123. }
  124. if (ed25519_sign_prefixed(&sig, tmp_cell_enc,
  125. tmp_cell_enc_len - tmp_cell_sig_offset,
  126. ESTABLISH_INTRO_SIG_PREFIX, &ip->auth_key_kp)) {
  127. log_warn(LD_BUG, "Unable to make signature for ESTABLISH_INTRO cell.");
  128. goto done;
  129. }
  130. /* Copy the signature into the cell. */
  131. sig_ptr = trn_cell_establish_intro_getarray_sig(cell);
  132. memcpy(sig_ptr, sig.sig, sig_len);
  133. }
  134. /* Encode the cell. Can't be bigger than a standard cell. */
  135. cell_len = trn_cell_establish_intro_encode(cell_out, RELAY_PAYLOAD_SIZE,
  136. cell);
  137. done:
  138. trn_cell_establish_intro_free(cell);
  139. return cell_len;
  140. }