tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

hs_ntor.c (26303B)


      1 /* Copyright (c) 2017-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /** \file hs_ntor.c
      5 *  \brief Implements the ntor variant used in Tor hidden services.
      6 *
      7 *  \details
      8 *  This module handles the variant of the ntor handshake that is documented in
      9 *  section [NTOR-WITH-EXTRA-DATA] of rend-spec-ng.txt .
     10 *
     11 *  The functions in this file provide an API that should be used when sending
     12 *  or receiving INTRODUCE1/RENDEZVOUS1 cells to generate the various key
     13 *  material required to create and handle those cells.
     14 *
     15 *  In the case of INTRODUCE1 it provides encryption and MAC keys to
     16 *  encode/decode the encrypted blob (see hs_ntor_intro_cell_keys_t). The
     17 *  relevant pub functions are hs_ntor_{client,service}_get_introduce1_keys().
     18 *
     19 *  In the case of RENDEZVOUS1 it calculates the MAC required to authenticate
     20 *  the cell, and also provides the key seed that is used to derive the crypto
     21 *  material for rendezvous encryption (see hs_ntor_rend_cell_keys_t). The
     22 *  relevant pub functions are hs_ntor_{client,service}_get_rendezvous1_keys().
     23 *  It also provides a function (hs_ntor_circuit_key_expansion()) that does the
     24 *  rendezvous key expansion to setup end-to-end rend circuit keys.
     25 */
     26 
     27 #include "core/or/or.h"
     28 #include "lib/crypt_ops/crypto_util.h"
     29 #include "lib/crypt_ops/crypto_curve25519.h"
     30 #include "lib/crypt_ops/crypto_ed25519.h"
     31 #include "core/crypto/hs_ntor.h"
     32 
     33 /* String constants used by the ntor HS protocol */
     34 #define PROTOID "tor-hs-ntor-curve25519-sha3-256-1"
     35 #define PROTOID_LEN (sizeof(PROTOID) - 1)
     36 #define SERVER_STR "Server"
     37 #define SERVER_STR_LEN (sizeof(SERVER_STR) - 1)
     38 
     39 /* Protocol-specific tweaks to our crypto inputs */
     40 #define T_HSENC PROTOID ":hs_key_extract"
     41 #define T_HSENC_LEN (sizeof(T_HSENC) - 1)
     42 #define T_HSVERIFY PROTOID ":hs_verify"
     43 #define T_HSMAC PROTOID ":hs_mac"
     44 #define M_HSEXPAND PROTOID ":hs_key_expand"
     45 #define M_HSEXPAND_LEN (sizeof(M_HSEXPAND) - 1)
     46 
     47 /************************* Helper functions: *******************************/
     48 
     49 /** Helper macro: copy <b>len</b> bytes from <b>inp</b> to <b>ptr</b> and
     50 *advance <b>ptr</b> by the number of bytes copied. Stolen from onion_ntor.c */
     51 #define APPEND(ptr, inp, len)                   \
     52  STMT_BEGIN {                                  \
     53    memcpy(ptr, (inp), (len));                  \
     54    ptr += len;                                 \
     55  } STMT_END
     56 
     57 /* Length of EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID */
     58 #define REND_SECRET_HS_INPUT_LEN (CURVE25519_OUTPUT_LEN * 2 + \
     59  ED25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN * 3 + PROTOID_LEN)
     60 /* Length of auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server" */
     61 #define REND_AUTH_INPUT_LEN (DIGEST256_LEN + ED25519_PUBKEY_LEN + \
     62  CURVE25519_PUBKEY_LEN * 3 + PROTOID_LEN + SERVER_STR_LEN)
     63 
     64 /** Helper function: Compute the last part of the HS ntor handshake which
     65 *  derives key material necessary to create and handle RENDEZVOUS1
     66 *  cells. Function used by both client and service. The actual calculations is
     67 *  as follows:
     68 *
     69 *    NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
     70 *    verify = MAC(rend_secret_hs_input, t_hsverify)
     71 *    auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
     72 *    auth_input_mac = MAC(auth_input, t_hsmac)
     73 *
     74 *  where in the above, AUTH_KEY is <b>intro_auth_pubkey</b>, B is
     75 *  <b>intro_enc_pubkey</b>, Y is <b>service_ephemeral_rend_pubkey</b>, and X
     76 *  is <b>client_ephemeral_enc_pubkey</b>. The provided
     77 *  <b>rend_secret_hs_input</b> is of size REND_SECRET_HS_INPUT_LEN.
     78 *
     79 *  The final results of NTOR_KEY_SEED and auth_input_mac are placed in
     80 *  <b>hs_ntor_rend_cell_keys_out</b>. Return 0 if everything went fine. */
     81 static int
     82 get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input,
     83                  const ed25519_public_key_t *intro_auth_pubkey,
     84                  const curve25519_public_key_t *intro_enc_pubkey,
     85                  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
     86                  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
     87                  hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
     88 {
     89  int bad = 0;
     90  uint8_t ntor_key_seed[DIGEST256_LEN];
     91  uint8_t ntor_verify[DIGEST256_LEN];
     92  uint8_t rend_auth_input[REND_AUTH_INPUT_LEN];
     93  uint8_t rend_cell_auth[DIGEST256_LEN];
     94  uint8_t *ptr;
     95 
     96  /* Let's build NTOR_KEY_SEED */
     97  crypto_mac_sha3_256(ntor_key_seed, sizeof(ntor_key_seed),
     98                      rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
     99                      (const uint8_t *)T_HSENC, strlen(T_HSENC));
    100  bad |= safe_mem_is_zero(ntor_key_seed, DIGEST256_LEN);
    101 
    102  /* Let's build ntor_verify */
    103  crypto_mac_sha3_256(ntor_verify, sizeof(ntor_verify),
    104                      rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
    105                      (const uint8_t *)T_HSVERIFY, strlen(T_HSVERIFY));
    106  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);
    107 
    108  /* Let's build auth_input: */
    109  ptr = rend_auth_input;
    110  /* Append ntor_verify */
    111  APPEND(ptr, ntor_verify, sizeof(ntor_verify));
    112  /* Append AUTH_KEY */
    113  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
    114  /* Append B */
    115  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    116  /* Append Y */
    117  APPEND(ptr,
    118         service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    119  /* Append X */
    120  APPEND(ptr,
    121         client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    122  /* Append PROTOID */
    123  APPEND(ptr, PROTOID, strlen(PROTOID));
    124  /* Append "Server" */
    125  APPEND(ptr, SERVER_STR, strlen(SERVER_STR));
    126  tor_assert(ptr == rend_auth_input + sizeof(rend_auth_input));
    127 
    128  /* Let's build auth_input_mac that goes in RENDEZVOUS1 cell */
    129  crypto_mac_sha3_256(rend_cell_auth, sizeof(rend_cell_auth),
    130                      rend_auth_input, sizeof(rend_auth_input),
    131                      (const uint8_t *)T_HSMAC, strlen(T_HSMAC));
    132  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);
    133 
    134  { /* Get the computed RENDEZVOUS1 material! */
    135    memcpy(&hs_ntor_rend_cell_keys_out->rend_cell_auth_mac,
    136           rend_cell_auth, DIGEST256_LEN);
    137    memcpy(&hs_ntor_rend_cell_keys_out->ntor_key_seed,
    138           ntor_key_seed, DIGEST256_LEN);
    139  }
    140 
    141  memwipe(rend_cell_auth, 0, sizeof(rend_cell_auth));
    142  memwipe(rend_auth_input, 0, sizeof(rend_auth_input));
    143  memwipe(ntor_key_seed, 0, sizeof(ntor_key_seed));
    144 
    145  return bad;
    146 }
    147 
    148 /** Length of secret_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID */
    149 #define INTRO_SECRET_HS_INPUT_LEN (CURVE25519_OUTPUT_LEN +ED25519_PUBKEY_LEN +\
    150  CURVE25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN + PROTOID_LEN)
    151 /* Length of info = m_hsexpand | subcredential */
    152 #define INFO_BLOB_LEN (M_HSEXPAND_LEN + DIGEST256_LEN)
    153 /* Length of KDF input = intro_secret_hs_input | t_hsenc | info */
    154 #define KDF_INPUT_LEN (INTRO_SECRET_HS_INPUT_LEN + T_HSENC_LEN + INFO_BLOB_LEN)
    155 
    156 /** Helper function: Compute the part of the HS ntor handshake that generates
    157 *  key material for creating and handling INTRODUCE1 cells. Function used
    158 *  by both client and service. Specifically, calculate the following:
    159 *
    160 *     info = m_hsexpand | subcredential
    161 *     hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN)
    162 *     ENC_KEY = hs_keys[0:S_KEY_LEN]
    163 *     MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN]
    164 *
    165 *  where intro_secret_hs_input is <b>secret_input</b> (of size
    166 *  INTRO_SECRET_HS_INPUT_LEN), and <b>subcredential</b> is of size
    167 *  DIGEST256_LEN.
    168 *
    169 * If everything went well, fill <b>hs_ntor_intro_cell_keys_out</b> with the
    170 * necessary key material, and return 0. */
    171 static void
    172 get_introduce1_key_material(const uint8_t *secret_input,
    173                        const hs_subcredential_t *subcredential,
    174                        hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
    175 {
    176  uint8_t keystream[CIPHER256_KEY_LEN + DIGEST256_LEN];
    177  uint8_t info_blob[INFO_BLOB_LEN];
    178  uint8_t kdf_input[KDF_INPUT_LEN];
    179  uint8_t *ptr;
    180 
    181  /* Let's build info */
    182  ptr = info_blob;
    183  APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND));
    184  APPEND(ptr, subcredential->subcred, SUBCRED_LEN);
    185  tor_assert(ptr == info_blob + sizeof(info_blob));
    186 
    187  /* Let's build the input to the KDF */
    188  ptr = kdf_input;
    189  APPEND(ptr, secret_input, INTRO_SECRET_HS_INPUT_LEN);
    190  APPEND(ptr, T_HSENC, strlen(T_HSENC));
    191  APPEND(ptr, info_blob, sizeof(info_blob));
    192  tor_assert(ptr == kdf_input + sizeof(kdf_input));
    193 
    194  /* Now we need to run kdf_input over SHAKE-256 */
    195  crypto_xof(keystream, sizeof(keystream),
    196             kdf_input, sizeof(kdf_input));
    197 
    198  { /* Get the keys */
    199    memcpy(&hs_ntor_intro_cell_keys_out->enc_key, keystream,CIPHER256_KEY_LEN);
    200    memcpy(&hs_ntor_intro_cell_keys_out->mac_key,
    201           keystream+CIPHER256_KEY_LEN, DIGEST256_LEN);
    202  }
    203 
    204  memwipe(keystream,  0, sizeof(keystream));
    205  memwipe(kdf_input,  0, sizeof(kdf_input));
    206 }
    207 
    208 /** Helper function: Calculate the 'intro_secret_hs_input' element used by the
    209 * HS ntor handshake and place it in <b>secret_input_out</b>. This function is
    210 * used by both client and service code.
    211 *
    212 * For the client-side it looks like this:
    213 *
    214 *         intro_secret_hs_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID
    215 *
    216 * whereas for the service-side it looks like this:
    217 *
    218 *         intro_secret_hs_input = EXP(X,b) | AUTH_KEY | X | B | PROTOID
    219 *
    220 * In this function, <b>dh_result</b> carries the EXP() result (and has size
    221 * CURVE25519_OUTPUT_LEN) <b>intro_auth_pubkey</b> is AUTH_KEY,
    222 * <b>client_ephemeral_enc_pubkey</b> is X, and <b>intro_enc_pubkey</b> is B.
    223 */
    224 static void
    225 get_intro_secret_hs_input(const uint8_t *dh_result,
    226                    const ed25519_public_key_t *intro_auth_pubkey,
    227                    const curve25519_public_key_t *client_ephemeral_enc_pubkey,
    228                    const curve25519_public_key_t *intro_enc_pubkey,
    229                    uint8_t *secret_input_out)
    230 {
    231  uint8_t *ptr;
    232 
    233  /* Append EXP() */
    234  ptr = secret_input_out;
    235  APPEND(ptr, dh_result, CURVE25519_OUTPUT_LEN);
    236  /* Append AUTH_KEY */
    237  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
    238  /* Append X */
    239  APPEND(ptr, client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    240  /* Append B */
    241  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    242  /* Append PROTOID */
    243  APPEND(ptr, PROTOID, strlen(PROTOID));
    244  tor_assert(ptr == secret_input_out + INTRO_SECRET_HS_INPUT_LEN);
    245 }
    246 
    247 /** Calculate the 'rend_secret_hs_input' element used by the HS ntor handshake
    248 *  and place it in <b>rend_secret_hs_input_out</b>. This function is used by
    249 *  both client and service code.
    250 *
    251 * The computation on the client side is:
    252 *  rend_secret_hs_input = EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID
    253 * whereas on the service side it is:
    254 *  rend_secret_hs_input = EXP(Y,x) | EXP(B,x) | AUTH_KEY | B | X | Y | PROTOID
    255 *
    256 * where:
    257 * <b>dh_result1</b> and <b>dh_result2</b> carry the two EXP() results (of size
    258 * CURVE25519_OUTPUT_LEN)
    259 * <b>intro_auth_pubkey</b> is AUTH_KEY,
    260 * <b>intro_enc_pubkey</b> is B,
    261 * <b>client_ephemeral_enc_pubkey</b> is X, and
    262 * <b>service_ephemeral_rend_pubkey</b> is Y.
    263 */
    264 static void
    265 get_rend_secret_hs_input(const uint8_t *dh_result1, const uint8_t *dh_result2,
    266                  const ed25519_public_key_t *intro_auth_pubkey,
    267                  const curve25519_public_key_t *intro_enc_pubkey,
    268                  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
    269                  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
    270                  uint8_t *rend_secret_hs_input_out)
    271 {
    272  uint8_t *ptr;
    273 
    274  ptr = rend_secret_hs_input_out;
    275  /* Append the first EXP() */
    276  APPEND(ptr, dh_result1, CURVE25519_OUTPUT_LEN);
    277  /* Append the other EXP() */
    278  APPEND(ptr, dh_result2, CURVE25519_OUTPUT_LEN);
    279  /* Append AUTH_KEY */
    280  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
    281  /* Append B */
    282  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    283  /* Append X */
    284  APPEND(ptr,
    285         client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    286  /* Append Y */
    287  APPEND(ptr,
    288         service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN);
    289  /* Append PROTOID */
    290  APPEND(ptr, PROTOID, strlen(PROTOID));
    291  tor_assert(ptr == rend_secret_hs_input_out + REND_SECRET_HS_INPUT_LEN);
    292 }
    293 
    294 /************************* Public functions: *******************************/
    295 
    296 /* Public function: Do the appropriate ntor calculations and derive the keys
    297 * needed to encrypt and authenticate INTRODUCE1 cells. Return 0 and place the
    298 * final key material in <b>hs_ntor_intro_cell_keys_out</b> if everything went
    299 * well, otherwise return -1;
    300 *
    301 * The relevant calculations are as follows:
    302 *
    303 *     intro_secret_hs_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID
    304 *     info = m_hsexpand | subcredential
    305 *     hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN)
    306 *     ENC_KEY = hs_keys[0:S_KEY_LEN]
    307 *     MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN]
    308 *
    309 * where:
    310 * <b>intro_auth_pubkey</b> is AUTH_KEY (found in HS descriptor),
    311 * <b>intro_enc_pubkey</b> is B (also found in HS descriptor),
    312 * <b>client_ephemeral_enc_keypair</b> is freshly generated keypair (x,X)
    313 * <b>subcredential</b> is the hidden service subcredential (of size
    314 * DIGEST256_LEN). */
    315 int
    316 hs_ntor_client_get_introduce1_keys(
    317                      const ed25519_public_key_t *intro_auth_pubkey,
    318                      const curve25519_public_key_t *intro_enc_pubkey,
    319                      const curve25519_keypair_t *client_ephemeral_enc_keypair,
    320                      const hs_subcredential_t *subcredential,
    321                      hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
    322 {
    323  int bad = 0;
    324  uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN];
    325  uint8_t dh_result[CURVE25519_OUTPUT_LEN];
    326 
    327  tor_assert(intro_auth_pubkey);
    328  tor_assert(intro_enc_pubkey);
    329  tor_assert(client_ephemeral_enc_keypair);
    330  tor_assert(subcredential);
    331  tor_assert(hs_ntor_intro_cell_keys_out);
    332 
    333  /* Calculate EXP(B,x) */
    334  curve25519_handshake(dh_result,
    335                       &client_ephemeral_enc_keypair->seckey,
    336                       intro_enc_pubkey);
    337  bad |= safe_mem_is_zero(dh_result, CURVE25519_OUTPUT_LEN);
    338 
    339  /* Get intro_secret_hs_input */
    340  get_intro_secret_hs_input(dh_result, intro_auth_pubkey,
    341                            &client_ephemeral_enc_keypair->pubkey,
    342                            intro_enc_pubkey, secret_input);
    343  bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN);
    344 
    345  /* Get ENC_KEY and MAC_KEY! */
    346  get_introduce1_key_material(secret_input, subcredential,
    347                              hs_ntor_intro_cell_keys_out);
    348 
    349  /* Cleanup */
    350  memwipe(secret_input,  0, sizeof(secret_input));
    351  if (bad) {
    352    memwipe(hs_ntor_intro_cell_keys_out, 0, sizeof(hs_ntor_intro_cell_keys_t));
    353  }
    354 
    355  return bad ? -1 : 0;
    356 }
    357 
    358 /* Public function: Do the appropriate ntor calculations and derive the keys
    359 * needed to verify RENDEZVOUS1 cells and encrypt further rendezvous
    360 * traffic. Return 0 and place the final key material in
    361 * <b>hs_ntor_rend_cell_keys_out</b> if everything went well, else return -1.
    362 *
    363 * The relevant calculations are as follows:
    364 *
    365 *  rend_secret_hs_input = EXP(Y,x) | EXP(B,x) | AUTH_KEY | B | X | Y | PROTOID
    366 *  NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
    367 *  verify = MAC(rend_secret_hs_input, t_hsverify)
    368 *  auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
    369 *  auth_input_mac = MAC(auth_input, t_hsmac)
    370 *
    371 * where:
    372 * <b>intro_auth_pubkey</b> is AUTH_KEY (found in HS descriptor),
    373 * <b>client_ephemeral_enc_keypair</b> is freshly generated keypair (x,X)
    374 * <b>intro_enc_pubkey</b> is B (also found in HS descriptor),
    375 * <b>service_ephemeral_rend_pubkey</b> is Y (SERVER_PK in RENDEZVOUS1 cell) */
    376 int
    377 hs_ntor_client_get_rendezvous1_keys(
    378                  const ed25519_public_key_t *intro_auth_pubkey,
    379                  const curve25519_keypair_t *client_ephemeral_enc_keypair,
    380                  const curve25519_public_key_t *intro_enc_pubkey,
    381                  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
    382                  hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
    383 {
    384  int bad = 0;
    385  uint8_t rend_secret_hs_input[REND_SECRET_HS_INPUT_LEN];
    386  uint8_t dh_result1[CURVE25519_OUTPUT_LEN];
    387  uint8_t dh_result2[CURVE25519_OUTPUT_LEN];
    388 
    389  tor_assert(intro_auth_pubkey);
    390  tor_assert(client_ephemeral_enc_keypair);
    391  tor_assert(intro_enc_pubkey);
    392  tor_assert(service_ephemeral_rend_pubkey);
    393  tor_assert(hs_ntor_rend_cell_keys_out);
    394 
    395  /* Compute EXP(Y, x) */
    396  curve25519_handshake(dh_result1,
    397                       &client_ephemeral_enc_keypair->seckey,
    398                       service_ephemeral_rend_pubkey);
    399  bad |= safe_mem_is_zero(dh_result1, CURVE25519_OUTPUT_LEN);
    400 
    401  /* Compute EXP(B, x) */
    402  curve25519_handshake(dh_result2,
    403                       &client_ephemeral_enc_keypair->seckey,
    404                       intro_enc_pubkey);
    405  bad |= safe_mem_is_zero(dh_result2, CURVE25519_OUTPUT_LEN);
    406 
    407  /* Get rend_secret_hs_input */
    408  get_rend_secret_hs_input(dh_result1, dh_result2,
    409                           intro_auth_pubkey, intro_enc_pubkey,
    410                           &client_ephemeral_enc_keypair->pubkey,
    411                           service_ephemeral_rend_pubkey,
    412                           rend_secret_hs_input);
    413 
    414  /* Get NTOR_KEY_SEED and the auth_input MAC */
    415  bad |= get_rendezvous1_key_material(rend_secret_hs_input,
    416                                      intro_auth_pubkey,
    417                                      intro_enc_pubkey,
    418                                      service_ephemeral_rend_pubkey,
    419                                      &client_ephemeral_enc_keypair->pubkey,
    420                                      hs_ntor_rend_cell_keys_out);
    421 
    422  memwipe(rend_secret_hs_input, 0, sizeof(rend_secret_hs_input));
    423  if (bad) {
    424    memwipe(hs_ntor_rend_cell_keys_out, 0, sizeof(hs_ntor_rend_cell_keys_t));
    425  }
    426 
    427  return bad ? -1 : 0;
    428 }
    429 
    430 /* Public function: Do the appropriate ntor calculations and derive the keys
    431 * needed to decrypt and verify INTRODUCE1 cells. Return 0 and place the final
    432 * key material in <b>hs_ntor_intro_cell_keys_out</b> if everything went well,
    433 * otherwise return -1;
    434 *
    435 * The relevant calculations are as follows:
    436 *
    437 *    intro_secret_hs_input = EXP(X,b) | AUTH_KEY | X | B | PROTOID
    438 *    info = m_hsexpand | subcredential
    439 *    hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN)
    440 *    HS_DEC_KEY = hs_keys[0:S_KEY_LEN]
    441 *    HS_MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN]
    442 *
    443 * where:
    444 * <b>intro_auth_pubkey</b> is AUTH_KEY (introduction point auth key),
    445 * <b>intro_enc_keypair</b> is (b,B) (introduction point encryption keypair),
    446 * <b>client_ephemeral_enc_pubkey</b> is X (CLIENT_PK in INTRODUCE2 cell),
    447 * <b>subcredential</b> is the HS subcredential (of size DIGEST256_LEN) */
    448 int
    449 hs_ntor_service_get_introduce1_keys(
    450                    const ed25519_public_key_t *intro_auth_pubkey,
    451                    const curve25519_keypair_t *intro_enc_keypair,
    452                    const curve25519_public_key_t *client_ephemeral_enc_pubkey,
    453                    const hs_subcredential_t *subcredential,
    454                    hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
    455 {
    456  return hs_ntor_service_get_introduce1_keys_multi(
    457                             intro_auth_pubkey,
    458                             intro_enc_keypair,
    459                             client_ephemeral_enc_pubkey,
    460                             1,
    461                             subcredential,
    462                             hs_ntor_intro_cell_keys_out);
    463 }
    464 
    465 /**
    466 * As hs_ntor_service_get_introduce1_keys(), but take multiple subcredentials
    467 * as input, and yield multiple sets of keys as output.
    468 **/
    469 int
    470 hs_ntor_service_get_introduce1_keys_multi(
    471            const struct ed25519_public_key_t *intro_auth_pubkey,
    472            const struct curve25519_keypair_t *intro_enc_keypair,
    473            const struct curve25519_public_key_t *client_ephemeral_enc_pubkey,
    474            size_t n_subcredentials,
    475            const hs_subcredential_t *subcredentials,
    476            hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
    477 {
    478  int bad = 0;
    479  uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN];
    480  uint8_t dh_result[CURVE25519_OUTPUT_LEN];
    481 
    482  tor_assert(intro_auth_pubkey);
    483  tor_assert(intro_enc_keypair);
    484  tor_assert(client_ephemeral_enc_pubkey);
    485  tor_assert(n_subcredentials >= 1);
    486  tor_assert(subcredentials);
    487  tor_assert(hs_ntor_intro_cell_keys_out);
    488 
    489  /* Compute EXP(X, b) */
    490  curve25519_handshake(dh_result,
    491                       &intro_enc_keypair->seckey,
    492                       client_ephemeral_enc_pubkey);
    493  bad |= safe_mem_is_zero(dh_result, CURVE25519_OUTPUT_LEN);
    494 
    495  /* Get intro_secret_hs_input */
    496  get_intro_secret_hs_input(dh_result, intro_auth_pubkey,
    497                            client_ephemeral_enc_pubkey,
    498                            &intro_enc_keypair->pubkey,
    499                            secret_input);
    500  bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN);
    501 
    502  for (unsigned i = 0; i < n_subcredentials; ++i) {
    503    /* Get ENC_KEY and MAC_KEY! */
    504    get_introduce1_key_material(secret_input, &subcredentials[i],
    505                                &hs_ntor_intro_cell_keys_out[i]);
    506  }
    507 
    508  memwipe(secret_input,  0, sizeof(secret_input));
    509  if (bad) {
    510    memwipe(hs_ntor_intro_cell_keys_out, 0,
    511            sizeof(hs_ntor_intro_cell_keys_t) * n_subcredentials);
    512  }
    513 
    514  return bad ? -1 : 0;
    515 }
    516 
    517 /* Public function: Do the appropriate ntor calculations and derive the keys
    518 * needed to create and authenticate RENDEZVOUS1 cells. Return 0 and place the
    519 * final key material in <b>hs_ntor_rend_cell_keys_out</b> if all went fine,
    520 * return -1 if error happened.
    521 *
    522 * The relevant calculations are as follows:
    523 *
    524 *  rend_secret_hs_input = EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID
    525 *  NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
    526 *  verify = MAC(rend_secret_hs_input, t_hsverify)
    527 *  auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
    528 *  auth_input_mac = MAC(auth_input, t_hsmac)
    529 *
    530 * where:
    531 * <b>intro_auth_pubkey</b> is AUTH_KEY (intro point auth key),
    532 * <b>intro_enc_keypair</b> is (b,B) (intro point enc keypair)
    533 * <b>service_ephemeral_rend_keypair</b> is a fresh (y,Y) keypair
    534 * <b>client_ephemeral_enc_pubkey</b> is X (CLIENT_PK in INTRODUCE2 cell) */
    535 int
    536 hs_ntor_service_get_rendezvous1_keys(
    537                    const ed25519_public_key_t *intro_auth_pubkey,
    538                    const curve25519_keypair_t *intro_enc_keypair,
    539                    const curve25519_keypair_t *service_ephemeral_rend_keypair,
    540                    const curve25519_public_key_t *client_ephemeral_enc_pubkey,
    541                    hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
    542 {
    543  int bad = 0;
    544  uint8_t rend_secret_hs_input[REND_SECRET_HS_INPUT_LEN];
    545  uint8_t dh_result1[CURVE25519_OUTPUT_LEN];
    546  uint8_t dh_result2[CURVE25519_OUTPUT_LEN];
    547 
    548  tor_assert(intro_auth_pubkey);
    549  tor_assert(intro_enc_keypair);
    550  tor_assert(service_ephemeral_rend_keypair);
    551  tor_assert(client_ephemeral_enc_pubkey);
    552  tor_assert(hs_ntor_rend_cell_keys_out);
    553 
    554  /* Compute EXP(X, y) */
    555  curve25519_handshake(dh_result1,
    556                       &service_ephemeral_rend_keypair->seckey,
    557                       client_ephemeral_enc_pubkey);
    558  bad |= safe_mem_is_zero(dh_result1, CURVE25519_OUTPUT_LEN);
    559 
    560  /* Compute EXP(X, b) */
    561  curve25519_handshake(dh_result2,
    562                       &intro_enc_keypair->seckey,
    563                       client_ephemeral_enc_pubkey);
    564  bad |= safe_mem_is_zero(dh_result2, CURVE25519_OUTPUT_LEN);
    565 
    566  /* Get rend_secret_hs_input */
    567  get_rend_secret_hs_input(dh_result1, dh_result2,
    568                           intro_auth_pubkey,
    569                           &intro_enc_keypair->pubkey,
    570                           client_ephemeral_enc_pubkey,
    571                           &service_ephemeral_rend_keypair->pubkey,
    572                           rend_secret_hs_input);
    573 
    574  /* Get NTOR_KEY_SEED and AUTH_INPUT_MAC! */
    575  bad |= get_rendezvous1_key_material(rend_secret_hs_input,
    576                                      intro_auth_pubkey,
    577                                      &intro_enc_keypair->pubkey,
    578                                      &service_ephemeral_rend_keypair->pubkey,
    579                                      client_ephemeral_enc_pubkey,
    580                                      hs_ntor_rend_cell_keys_out);
    581 
    582  memwipe(rend_secret_hs_input, 0, sizeof(rend_secret_hs_input));
    583  if (bad) {
    584    memwipe(hs_ntor_rend_cell_keys_out, 0, sizeof(hs_ntor_rend_cell_keys_t));
    585  }
    586 
    587  return bad ? -1 : 0;
    588 }
    589 
    590 /** Given a received RENDEZVOUS2 MAC in <b>mac</b> (of length DIGEST256_LEN),
    591 *  and the RENDEZVOUS1 key material in <b>hs_ntor_rend_cell_keys</b>, return 1
    592 *  if the MAC is good, otherwise return 0. */
    593 int
    594 hs_ntor_client_rendezvous2_mac_is_good(
    595                        const hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys,
    596                        const uint8_t *rcvd_mac)
    597 {
    598  tor_assert(rcvd_mac);
    599  tor_assert(hs_ntor_rend_cell_keys);
    600 
    601  return tor_memeq(hs_ntor_rend_cell_keys->rend_cell_auth_mac,
    602                   rcvd_mac, DIGEST256_LEN);
    603 }
    604 
    605 /* Input length to KDF for key expansion */
    606 #define NTOR_KEY_EXPANSION_KDF_INPUT_LEN (DIGEST256_LEN + M_HSEXPAND_LEN)
    607 
    608 /** Given the rendezvous key seed in <b>ntor_key_seed</b> (of size
    609 *  DIGEST256_LEN), do the circuit key expansion as specified by section
    610 *  '4.2.1. Key expansion' and place the keys in <b>keys_out</b> (which must be
    611 *  of size HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN).
    612 *
    613 * Return 0 if things went well, else return -1. */
    614 int
    615 hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, size_t seed_len,
    616                              uint8_t *keys_out, size_t keys_out_len)
    617 {
    618  uint8_t *ptr;
    619  uint8_t kdf_input[NTOR_KEY_EXPANSION_KDF_INPUT_LEN];
    620 
    621  /* Sanity checks on lengths to make sure we are good */
    622  if (BUG(seed_len != DIGEST256_LEN)) {
    623    return -1;
    624  }
    625  if (BUG(keys_out_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
    626    return -1;
    627  }
    628 
    629  /* Let's build the input to the KDF */
    630  ptr = kdf_input;
    631  APPEND(ptr, ntor_key_seed, DIGEST256_LEN);
    632  APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND));
    633  tor_assert(ptr == kdf_input + sizeof(kdf_input));
    634 
    635  /* Generate the keys */
    636  crypto_xof(keys_out, HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN,
    637             kdf_input, sizeof(kdf_input));
    638 
    639  return 0;
    640 }