tor  0.4.2.0-alpha-dev
onion_ntor.c
Go to the documentation of this file.
1 /* Copyright (c) 2012-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
21 #include "orconfig.h"
22 
23 #define ONION_NTOR_PRIVATE
24 
29 #include "lib/ctime/di_ops.h"
30 #include "lib/log/log.h"
31 #include "lib/log/util_bug.h"
32 #include "core/crypto/onion_ntor.h"
33 
34 #include <string.h>
35 
37 void
38 ntor_handshake_state_free_(ntor_handshake_state_t *state)
39 {
40  if (!state)
41  return;
42  memwipe(state, 0, sizeof(*state));
43  tor_free(state);
44 }
45 
50 static void
51 h_tweak(uint8_t *out,
52  const uint8_t *inp, size_t inp_len,
53  const char *tweak)
54 {
55  size_t tweak_len = strlen(tweak);
56  crypto_hmac_sha256((char*)out, tweak, tweak_len, (const char*)inp, inp_len);
57 }
58 
60 typedef struct tweakset_t {
61  const char *t_mac;
62  const char *t_key;
63  const char *t_verify;
64  const char *m_expand;
65 } tweakset_t;
66 
68 static const tweakset_t proto1_tweaks = {
69 #define PROTOID "ntor-curve25519-sha256-1"
70 #define PROTOID_LEN 24
71  PROTOID ":mac",
72  PROTOID ":key_extract",
73  PROTOID ":verify",
74  PROTOID ":key_expand"
75 };
76 
79 #define APPEND(ptr, inp, len) \
80  STMT_BEGIN { \
81  memcpy(ptr, (inp), (len)); \
82  ptr += len; \
83  } STMT_END
84 
92 int
93 onion_skin_ntor_create(const uint8_t *router_id,
94  const curve25519_public_key_t *router_key,
95  ntor_handshake_state_t **handshake_state_out,
96  uint8_t *onion_skin_out)
97 {
98  ntor_handshake_state_t *state;
99  uint8_t *op;
100 
101  state = tor_malloc_zero(sizeof(ntor_handshake_state_t));
102 
103  memcpy(state->router_id, router_id, DIGEST_LEN);
104  memcpy(&state->pubkey_B, router_key, sizeof(curve25519_public_key_t));
105  if (curve25519_secret_key_generate(&state->seckey_x, 0) < 0) {
106  /* LCOV_EXCL_START
107  * Secret key generation should be unable to fail when the key isn't
108  * marked as "extra-strong" */
109  tor_assert_nonfatal_unreached();
110  tor_free(state);
111  return -1;
112  /* LCOV_EXCL_STOP */
113  }
114  curve25519_public_key_generate(&state->pubkey_X, &state->seckey_x);
115 
116  op = onion_skin_out;
117  APPEND(op, router_id, DIGEST_LEN);
118  APPEND(op, router_key->public_key, CURVE25519_PUBKEY_LEN);
119  APPEND(op, state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
120  tor_assert(op == onion_skin_out + NTOR_ONIONSKIN_LEN);
121 
122  *handshake_state_out = state;
123 
124  return 0;
125 }
126 
127 #define SERVER_STR "Server"
128 #define SERVER_STR_LEN 6
129 
130 #define SECRET_INPUT_LEN (CURVE25519_PUBKEY_LEN * 3 + \
131  CURVE25519_OUTPUT_LEN * 2 + \
132  DIGEST_LEN + PROTOID_LEN)
133 #define AUTH_INPUT_LEN (DIGEST256_LEN + DIGEST_LEN + \
134  CURVE25519_PUBKEY_LEN*3 + \
135  PROTOID_LEN + SERVER_STR_LEN)
136 
148 int
149 onion_skin_ntor_server_handshake(const uint8_t *onion_skin,
150  const di_digest256_map_t *private_keys,
151  const curve25519_keypair_t *junk_keys,
152  const uint8_t *my_node_id,
153  uint8_t *handshake_reply_out,
154  uint8_t *key_out,
155  size_t key_out_len)
156 {
157  const tweakset_t *T = &proto1_tweaks;
158  /* Sensitive stack-allocated material. Kept in an anonymous struct to make
159  * it easy to wipe. */
160  struct {
161  uint8_t secret_input[SECRET_INPUT_LEN];
162  uint8_t auth_input[AUTH_INPUT_LEN];
163  curve25519_public_key_t pubkey_X;
164  curve25519_secret_key_t seckey_y;
165  curve25519_public_key_t pubkey_Y;
166  uint8_t verify[DIGEST256_LEN];
167  } s;
168  uint8_t *si = s.secret_input, *ai = s.auth_input;
169  const curve25519_keypair_t *keypair_bB;
170  int bad;
171 
172  /* Decode the onion skin */
173  /* XXXX Does this possible early-return business threaten our security? */
174  if (tor_memneq(onion_skin, my_node_id, DIGEST_LEN))
175  return -1;
176  /* Note that on key-not-found, we go through with this operation anyway,
177  * using "junk_keys". This will result in failed authentication, but won't
178  * leak whether we recognized the key. */
179  keypair_bB = dimap_search(private_keys, onion_skin + DIGEST_LEN,
180  (void*)junk_keys);
181  if (!keypair_bB)
182  return -1;
183 
184  memcpy(s.pubkey_X.public_key, onion_skin+DIGEST_LEN+DIGEST256_LEN,
186 
187  /* Make y, Y */
188  curve25519_secret_key_generate(&s.seckey_y, 0);
189  curve25519_public_key_generate(&s.pubkey_Y, &s.seckey_y);
190 
191  /* NOTE: If we ever use a group other than curve25519, or a different
192  * representation for its points, we may need to perform different or
193  * additional checks on X here and on Y in the client handshake, or lose our
194  * security properties. What checks we need would depend on the properties
195  * of the group and its representation.
196  *
197  * In short: if you use anything other than curve25519, this aspect of the
198  * code will need to be reconsidered carefully. */
199 
200  /* build secret_input */
201  curve25519_handshake(si, &s.seckey_y, &s.pubkey_X);
203  si += CURVE25519_OUTPUT_LEN;
204  curve25519_handshake(si, &keypair_bB->seckey, &s.pubkey_X);
206  si += CURVE25519_OUTPUT_LEN;
207 
208  APPEND(si, my_node_id, DIGEST_LEN);
209  APPEND(si, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
210  APPEND(si, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
211  APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
212  APPEND(si, PROTOID, PROTOID_LEN);
213  tor_assert(si == s.secret_input + sizeof(s.secret_input));
214 
215  /* Compute hashes of secret_input */
216  h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);
217 
218  /* Compute auth_input */
219  APPEND(ai, s.verify, DIGEST256_LEN);
220  APPEND(ai, my_node_id, DIGEST_LEN);
221  APPEND(ai, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
222  APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
223  APPEND(ai, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
224  APPEND(ai, PROTOID, PROTOID_LEN);
225  APPEND(ai, SERVER_STR, SERVER_STR_LEN);
226  tor_assert(ai == s.auth_input + sizeof(s.auth_input));
227 
228  /* Build the reply */
229  memcpy(handshake_reply_out, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
230  h_tweak(handshake_reply_out+CURVE25519_PUBKEY_LEN,
231  s.auth_input, sizeof(s.auth_input),
232  T->t_mac);
233 
234  /* Generate the key material */
236  s.secret_input, sizeof(s.secret_input),
237  (const uint8_t*)T->t_key, strlen(T->t_key),
238  (const uint8_t*)T->m_expand, strlen(T->m_expand),
239  key_out, key_out_len);
240 
241  /* Wipe all of our local state */
242  memwipe(&s, 0, sizeof(s));
243 
244  return bad ? -1 : 0;
245 }
246 
253 int
255  const ntor_handshake_state_t *handshake_state,
256  const uint8_t *handshake_reply,
257  uint8_t *key_out,
258  size_t key_out_len,
259  const char **msg_out)
260 {
261  const tweakset_t *T = &proto1_tweaks;
262  /* Sensitive stack-allocated material. Kept in an anonymous struct to make
263  * it easy to wipe. */
264  struct {
265  curve25519_public_key_t pubkey_Y;
266  uint8_t secret_input[SECRET_INPUT_LEN];
267  uint8_t verify[DIGEST256_LEN];
268  uint8_t auth_input[AUTH_INPUT_LEN];
269  uint8_t auth[DIGEST256_LEN];
270  } s;
271  uint8_t *ai = s.auth_input, *si = s.secret_input;
272  const uint8_t *auth_candidate;
273  int bad;
274 
275  /* Decode input */
276  memcpy(s.pubkey_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN);
277  auth_candidate = handshake_reply + CURVE25519_PUBKEY_LEN;
278 
279  /* See note in server_handshake above about checking points. The
280  * circumstances under which we'd need to check Y for membership are
281  * different than those under which we'd be checking X. */
282 
283  /* Compute secret_input */
284  curve25519_handshake(si, &handshake_state->seckey_x, &s.pubkey_Y);
286  si += CURVE25519_OUTPUT_LEN;
287  curve25519_handshake(si, &handshake_state->seckey_x,
288  &handshake_state->pubkey_B);
289  bad |= (safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN) << 1);
290  si += CURVE25519_OUTPUT_LEN;
291  APPEND(si, handshake_state->router_id, DIGEST_LEN);
292  APPEND(si, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
293  APPEND(si, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
294  APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
295  APPEND(si, PROTOID, PROTOID_LEN);
296  tor_assert(si == s.secret_input + sizeof(s.secret_input));
297 
298  /* Compute verify from secret_input */
299  h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);
300 
301  /* Compute auth_input */
302  APPEND(ai, s.verify, DIGEST256_LEN);
303  APPEND(ai, handshake_state->router_id, DIGEST_LEN);
304  APPEND(ai, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
305  APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
306  APPEND(ai, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
307  APPEND(ai, PROTOID, PROTOID_LEN);
308  APPEND(ai, SERVER_STR, SERVER_STR_LEN);
309  tor_assert(ai == s.auth_input + sizeof(s.auth_input));
310 
311  /* Compute auth */
312  h_tweak(s.auth, s.auth_input, sizeof(s.auth_input), T->t_mac);
313 
314  bad |= (tor_memneq(s.auth, auth_candidate, DIGEST256_LEN) << 2);
315 
317  s.secret_input, sizeof(s.secret_input),
318  (const uint8_t*)T->t_key, strlen(T->t_key),
319  (const uint8_t*)T->m_expand, strlen(T->m_expand),
320  key_out, key_out_len);
321 
322  memwipe(&s, 0, sizeof(s));
323 
324  if (bad) {
325  if (bad & 4) {
326  if (msg_out)
327  *msg_out = NULL; /* Don't report this one; we probably just had the
328  * wrong onion key.*/
330  "Invalid result from curve25519 handshake: %d", bad);
331  }
332  if (bad & 3) {
333  if (msg_out)
334  *msg_out = "Zero output from curve25519 handshake";
336  "Invalid result from curve25519 handshake: %d", bad);
337  }
338  }
339 
340  return bad ? -1 : 0;
341 }
#define APPEND(ptr, inp, len)
Definition: onion_ntor.c:79
Headers for di_ops.c.
void * dimap_search(const di_digest256_map_t *map, const uint8_t *key, void *dflt_val)
Definition: di_ops.c:197
void ntor_handshake_state_free_(ntor_handshake_state_t *state)
Definition: onion_ntor.c:38
Headers for crypto_cipher.c.
#define LOG_INFO
Definition: log.h:43
int onion_skin_ntor_create(const uint8_t *router_id, const curve25519_public_key_t *router_key, ntor_handshake_state_t **handshake_state_out, uint8_t *onion_skin_out)
Definition: onion_ntor.c:93
int onion_skin_ntor_client_handshake(const ntor_handshake_state_t *handshake_state, const uint8_t *handshake_reply, uint8_t *key_out, size_t key_out_len, const char **msg_out)
Definition: onion_ntor.c:254
#define tor_free(p)
Definition: malloc.h:52
struct tweakset_t tweakset_t
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:57
void curve25519_handshake(uint8_t *output, const curve25519_secret_key_t *skey, const curve25519_public_key_t *pkey)
#define DIGEST256_LEN
Definition: digest_sizes.h:23
Headers for crypto_hkdf.h.
int curve25519_secret_key_generate(curve25519_secret_key_t *key_out, int extra_strong)
int crypto_expand_key_material_rfc5869_sha256(const uint8_t *key_in, size_t key_in_len, const uint8_t *salt_in, size_t salt_in_len, const uint8_t *info_in, size_t info_in_len, uint8_t *key_out, size_t key_out_len)
Definition: crypto_hkdf.c:179
Common functions for cryptographic routines.
tor_assert(buffer)
static const tweakset_t proto1_tweaks
Definition: onion_ntor.c:68
#define DIGEST_LEN
Definition: digest_sizes.h:20
void curve25519_public_key_generate(curve25519_public_key_t *key_out, const curve25519_secret_key_t *seckey)
void crypto_hmac_sha256(char *hmac_out, const char *key, size_t key_len, const char *msg, size_t msg_len)
#define LOG_WARN
Definition: log.h:51
Headers for crypto_digest.c.
#define CURVE25519_OUTPUT_LEN
Definition: x25519_sizes.h:24
#define log_fn(severity, domain, args,...)
Definition: log.h:273
static void h_tweak(uint8_t *out, const uint8_t *inp, size_t inp_len, const char *tweak)
Definition: onion_ntor.c:51
int safe_mem_is_zero(const void *mem, size_t sz)
Definition: di_ops.c:221
Headers for log.c.
Macros to manage assertions, fatal and non-fatal.
#define LD_PROTOCOL
Definition: log.h:70
int onion_skin_ntor_server_handshake(const uint8_t *onion_skin, const di_digest256_map_t *private_keys, const curve25519_keypair_t *junk_keys, const uint8_t *my_node_id, uint8_t *handshake_reply_out, uint8_t *key_out, size_t key_out_len)
Definition: onion_ntor.c:149
#define CURVE25519_PUBKEY_LEN
Definition: x25519_sizes.h:20
#define T(s, t, a, o)
Definition: parsecommon.h:246