Tor 0.4.9.0-alpha-dev
onion_ntor.c
Go to the documentation of this file.
1/* Copyright (c) 2012-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file onion_ntor.c
6 *
7 * \brief Implementation for the ntor handshake.
8 *
9 * The ntor circuit-extension handshake was developed as a replacement
10 * for the old TAP handshake. It uses Elliptic-curve Diffie-Hellman and
11 * a hash function in order to perform a one-way authenticated key
12 * exchange. The ntor handshake is meant to replace the old "TAP"
13 * handshake.
14 *
15 * We instantiate ntor with curve25519, HMAC-SHA256, and HKDF.
16 *
17 * This handshake, like the other circuit-extension handshakes, is
18 * invoked from onion.c.
19 */
20
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"
33
34#include <string.h>
35
36/** Free storage held in an ntor handshake state. */
37void
39{
40 if (!state)
41 return;
42 memwipe(state, 0, sizeof(*state));
43 tor_free(state);
44}
45
46/** Convenience function to represent HMAC_SHA256 as our instantiation of
47 * ntor's "tweaked hash'. Hash the <b>inp_len</b> bytes at <b>inp</b> into
48 * a DIGEST256_LEN-byte digest at <b>out</b>, with the hash changing
49 * depending on the value of <b>tweak</b>. */
50static void
51h_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
59/** Wrapper around a set of tweak-values for use with the ntor handshake. */
60typedef struct tweakset_t {
61 const char *t_mac;
62 const char *t_key;
63 const char *t_verify;
64 const char *m_expand;
66
67/** The tweaks to be used with our handshake. */
68static 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
77/** Convenience macro: copy <b>len</b> bytes from <b>inp</b> to <b>ptr</b>,
78 * and advance <b>ptr</b> by the number of bytes copied. */
79#define APPEND(ptr, inp, len) \
80 STMT_BEGIN { \
81 memcpy(ptr, (inp), (len)); \
82 ptr += len; \
83 } STMT_END
84
85/**
86 * Compute the first client-side step of the ntor handshake for communicating
87 * with a server whose DIGEST_LEN-byte server identity is <b>router_id</b>,
88 * and whose onion key is <b>router_key</b>. Store the NTOR_ONIONSKIN_LEN-byte
89 * message in <b>onion_skin_out</b>, and store the handshake state in
90 * *<b>handshake_state_out</b>. Return 0 on success, -1 on failure.
91 */
92int
93onion_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{
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" */
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
137/**
138 * Perform the server side of an ntor handshake. Given an
139 * NTOR_ONIONSKIN_LEN-byte message in <b>onion_skin</b>, our own identity
140 * fingerprint as <b>my_node_id</b>, and an associative array mapping public
141 * onion keys to curve25519_keypair_t in <b>private_keys</b>, attempt to
142 * perform the handshake. Use <b>junk_keys</b> if present if the handshake
143 * indicates an unrecognized public key. Write an NTOR_REPLY_LEN-byte
144 * message to send back to the client into <b>handshake_reply_out</b>, and
145 * generate <b>key_out_len</b> bytes of key material in <b>key_out</b>. Return
146 * 0 on success, -1 on failure.
147 */
148int
149onion_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];
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);
204 curve25519_handshake(si, &keypair_bB->seckey, &s.pubkey_X);
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
247/**
248 * Perform the final client side of the ntor handshake, using the state in
249 * <b>handshake_state</b> and the server's NTOR_REPLY_LEN-byte reply in
250 * <b>handshake_reply</b>. Generate <b>key_out_len</b> bytes of key material
251 * in <b>key_out</b>. Return 0 on success, -1 on failure.
252 */
253int
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 {
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);
287 curve25519_handshake(si, &handshake_state->seckey_x,
288 &handshake_state->pubkey_B);
289 bad |= (safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN) << 1);
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}
Headers for crypto_cipher.c.
void curve25519_handshake(uint8_t *output, const curve25519_secret_key_t *skey, const curve25519_public_key_t *pkey)
int curve25519_secret_key_generate(curve25519_secret_key_t *key_out, int extra_strong)
void curve25519_public_key_generate(curve25519_public_key_t *key_out, const curve25519_secret_key_t *seckey)
Headers for crypto_digest.c.
void crypto_hmac_sha256(char *hmac_out, const char *key, size_t key_len, const char *msg, size_t msg_len)
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
Headers for crypto_hkdf.h.
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:55
Common functions for cryptographic routines.
int safe_mem_is_zero(const void *mem, size_t sz)
Definition: di_ops.c:224
void * dimap_search(const di_digest256_map_t *map, const uint8_t *key, void *dflt_val)
Definition: di_ops.c:200
Headers for di_ops.c.
#define tor_memneq(a, b, sz)
Definition: di_ops.h:21
#define DIGEST_LEN
Definition: digest_sizes.h:20
#define DIGEST256_LEN
Definition: digest_sizes.h:23
Headers for log.c.
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_PROTOCOL
Definition: log.h:72
#define LOG_WARN
Definition: log.h:53
#define LOG_INFO
Definition: log.h:45
#define tor_free(p)
Definition: malloc.h:56
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
static void h_tweak(uint8_t *out, const uint8_t *inp, size_t inp_len, const char *tweak)
Definition: onion_ntor.c:51
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 APPEND(ptr, inp, len)
Definition: onion_ntor.c:79
static const tweakset_t proto1_tweaks
Definition: onion_ntor.c:68
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
void ntor_handshake_state_free_(ntor_handshake_state_t *state)
Definition: onion_ntor.c:38
Header for onion_ntor.c.
struct ntor_handshake_state_t ntor_handshake_state_t
Definition: onion_ntor.h:20
#define NTOR_ONIONSKIN_LEN
Definition: onion_ntor.h:23
#define T(s, t, a, o)
Definition: parsecommon.h:247
Macros to manage assertions, fatal and non-fatal.
#define tor_assert_nonfatal_unreached()
Definition: util_bug.h:177
#define tor_assert(expr)
Definition: util_bug.h:103
#define CURVE25519_OUTPUT_LEN
Definition: x25519_sizes.h:24
#define CURVE25519_PUBKEY_LEN
Definition: x25519_sizes.h:20