Stop trying to generate test scripts via autoconf substitution.
[tor.git] / src / or / onion_ntor.c
blob539f06f61fad0244250d301583a6836458fa8ac6
1 /* Copyright (c) 2012-2015, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include "orconfig.h"
6 #define ONION_NTOR_PRIVATE
7 #include "crypto.h"
8 #include "onion_ntor.h"
9 #include "torlog.h"
10 #include "util.h"
12 /** Free storage held in an ntor handshake state. */
13 void
14 ntor_handshake_state_free(ntor_handshake_state_t *state)
16 if (!state)
17 return;
18 memwipe(state, 0, sizeof(*state));
19 tor_free(state);
22 /** Convenience function to represent HMAC_SHA256 as our instantiation of
23 * ntor's "tweaked hash'. Hash the <b>inp_len</b> bytes at <b>inp</b> into
24 * a DIGEST256_LEN-byte digest at <b>out</b>, with the hash changing
25 * depending on the value of <b>tweak</b>. */
26 static void
27 h_tweak(uint8_t *out,
28 const uint8_t *inp, size_t inp_len,
29 const char *tweak)
31 size_t tweak_len = strlen(tweak);
32 crypto_hmac_sha256((char*)out, tweak, tweak_len, (const char*)inp, inp_len);
35 /** Wrapper around a set of tweak-values for use with the ntor handshake. */
36 typedef struct tweakset_t {
37 const char *t_mac;
38 const char *t_key;
39 const char *t_verify;
40 const char *m_expand;
41 } tweakset_t;
43 /** The tweaks to be used with our handshake. */
44 const tweakset_t proto1_tweaks = {
45 #define PROTOID "ntor-curve25519-sha256-1"
46 #define PROTOID_LEN 24
47 PROTOID ":mac",
48 PROTOID ":key_extract",
49 PROTOID ":verify",
50 PROTOID ":key_expand"
53 /** Convenience macro: copy <b>len</b> bytes from <b>inp</b> to <b>ptr</b>,
54 * and advance <b>ptr</b> by the number of bytes copied. */
55 #define APPEND(ptr, inp, len) \
56 STMT_BEGIN { \
57 memcpy(ptr, (inp), (len)); \
58 ptr += len; \
59 } STMT_END
61 /**
62 * Compute the first client-side step of the ntor handshake for communicating
63 * with a server whose DIGEST_LEN-byte server identity is <b>router_id</b>,
64 * and whose onion key is <b>router_key</b>. Store the NTOR_ONIONSKIN_LEN-byte
65 * message in <b>onion_skin_out</b>, and store the handshake state in
66 * *<b>handshake_state_out</b>. Return 0 on success, -1 on failure.
68 int
69 onion_skin_ntor_create(const uint8_t *router_id,
70 const curve25519_public_key_t *router_key,
71 ntor_handshake_state_t **handshake_state_out,
72 uint8_t *onion_skin_out)
74 ntor_handshake_state_t *state;
75 uint8_t *op;
77 state = tor_malloc_zero(sizeof(ntor_handshake_state_t));
79 memcpy(state->router_id, router_id, DIGEST_LEN);
80 memcpy(&state->pubkey_B, router_key, sizeof(curve25519_public_key_t));
81 if (curve25519_secret_key_generate(&state->seckey_x, 0) < 0) {
82 tor_free(state);
83 return -1;
85 curve25519_public_key_generate(&state->pubkey_X, &state->seckey_x);
87 op = onion_skin_out;
88 APPEND(op, router_id, DIGEST_LEN);
89 APPEND(op, router_key->public_key, CURVE25519_PUBKEY_LEN);
90 APPEND(op, state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
91 tor_assert(op == onion_skin_out + NTOR_ONIONSKIN_LEN);
93 *handshake_state_out = state;
95 return 0;
98 #define SERVER_STR "Server"
99 #define SERVER_STR_LEN 6
101 #define SECRET_INPUT_LEN (CURVE25519_PUBKEY_LEN * 3 + \
102 CURVE25519_OUTPUT_LEN * 2 + \
103 DIGEST_LEN + PROTOID_LEN)
104 #define AUTH_INPUT_LEN (DIGEST256_LEN + DIGEST_LEN + \
105 CURVE25519_PUBKEY_LEN*3 + \
106 PROTOID_LEN + SERVER_STR_LEN)
109 * Perform the server side of an ntor handshake. Given an
110 * NTOR_ONIONSKIN_LEN-byte message in <b>onion_skin</b>, our own identity
111 * fingerprint as <b>my_node_id</b>, and an associative array mapping public
112 * onion keys to curve25519_keypair_t in <b>private_keys</b>, attempt to
113 * perform the handshake. Use <b>junk_keys</b> if present if the handshake
114 * indicates an unrecognized public key. Write an NTOR_REPLY_LEN-byte
115 * message to send back to the client into <b>handshake_reply_out</b>, and
116 * generate <b>key_out_len</b> bytes of key material in <b>key_out</b>. Return
117 * 0 on success, -1 on failure.
120 onion_skin_ntor_server_handshake(const uint8_t *onion_skin,
121 const di_digest256_map_t *private_keys,
122 const curve25519_keypair_t *junk_keys,
123 const uint8_t *my_node_id,
124 uint8_t *handshake_reply_out,
125 uint8_t *key_out,
126 size_t key_out_len)
128 const tweakset_t *T = &proto1_tweaks;
129 /* Sensitive stack-allocated material. Kept in an anonymous struct to make
130 * it easy to wipe. */
131 struct {
132 uint8_t secret_input[SECRET_INPUT_LEN];
133 uint8_t auth_input[AUTH_INPUT_LEN];
134 curve25519_public_key_t pubkey_X;
135 curve25519_secret_key_t seckey_y;
136 curve25519_public_key_t pubkey_Y;
137 uint8_t verify[DIGEST256_LEN];
138 } s;
139 uint8_t *si = s.secret_input, *ai = s.auth_input;
140 const curve25519_keypair_t *keypair_bB;
141 int bad;
143 /* Decode the onion skin */
144 /* XXXX Does this possible early-return business threaten our security? */
145 if (tor_memneq(onion_skin, my_node_id, DIGEST_LEN))
146 return -1;
147 /* Note that on key-not-found, we go through with this operation anyway,
148 * using "junk_keys". This will result in failed authentication, but won't
149 * leak whether we recognized the key. */
150 keypair_bB = dimap_search(private_keys, onion_skin + DIGEST_LEN,
151 (void*)junk_keys);
152 if (!keypair_bB)
153 return -1;
155 memcpy(s.pubkey_X.public_key, onion_skin+DIGEST_LEN+DIGEST256_LEN,
156 CURVE25519_PUBKEY_LEN);
158 /* Make y, Y */
159 curve25519_secret_key_generate(&s.seckey_y, 0);
160 curve25519_public_key_generate(&s.pubkey_Y, &s.seckey_y);
162 /* NOTE: If we ever use a group other than curve25519, or a different
163 * representation for its points, we may need to perform different or
164 * additional checks on X here and on Y in the client handshake, or lose our
165 * security properties. What checks we need would depend on the properties
166 * of the group and its representation.
168 * In short: if you use anything other than curve25519, this aspect of the
169 * code will need to be reconsidered carefully. */
171 /* build secret_input */
172 curve25519_handshake(si, &s.seckey_y, &s.pubkey_X);
173 bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
174 si += CURVE25519_OUTPUT_LEN;
175 curve25519_handshake(si, &keypair_bB->seckey, &s.pubkey_X);
176 bad |= safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
177 si += CURVE25519_OUTPUT_LEN;
179 APPEND(si, my_node_id, DIGEST_LEN);
180 APPEND(si, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
181 APPEND(si, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
182 APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
183 APPEND(si, PROTOID, PROTOID_LEN);
184 tor_assert(si == s.secret_input + sizeof(s.secret_input));
186 /* Compute hashes of secret_input */
187 h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);
189 /* Compute auth_input */
190 APPEND(ai, s.verify, DIGEST256_LEN);
191 APPEND(ai, my_node_id, DIGEST_LEN);
192 APPEND(ai, keypair_bB->pubkey.public_key, CURVE25519_PUBKEY_LEN);
193 APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
194 APPEND(ai, s.pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
195 APPEND(ai, PROTOID, PROTOID_LEN);
196 APPEND(ai, SERVER_STR, SERVER_STR_LEN);
197 tor_assert(ai == s.auth_input + sizeof(s.auth_input));
199 /* Build the reply */
200 memcpy(handshake_reply_out, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
201 h_tweak(handshake_reply_out+CURVE25519_PUBKEY_LEN,
202 s.auth_input, sizeof(s.auth_input),
203 T->t_mac);
205 /* Generate the key material */
206 crypto_expand_key_material_rfc5869_sha256(
207 s.secret_input, sizeof(s.secret_input),
208 (const uint8_t*)T->t_key, strlen(T->t_key),
209 (const uint8_t*)T->m_expand, strlen(T->m_expand),
210 key_out, key_out_len);
212 /* Wipe all of our local state */
213 memwipe(&s, 0, sizeof(s));
215 return bad ? -1 : 0;
219 * Perform the final client side of the ntor handshake, using the state in
220 * <b>handshake_state</b> and the server's NTOR_REPLY_LEN-byte reply in
221 * <b>handshake_reply</b>. Generate <b>key_out_len</b> bytes of key material
222 * in <b>key_out</b>. Return 0 on success, -1 on failure.
225 onion_skin_ntor_client_handshake(
226 const ntor_handshake_state_t *handshake_state,
227 const uint8_t *handshake_reply,
228 uint8_t *key_out,
229 size_t key_out_len,
230 const char **msg_out)
232 const tweakset_t *T = &proto1_tweaks;
233 /* Sensitive stack-allocated material. Kept in an anonymous struct to make
234 * it easy to wipe. */
235 struct {
236 curve25519_public_key_t pubkey_Y;
237 uint8_t secret_input[SECRET_INPUT_LEN];
238 uint8_t verify[DIGEST256_LEN];
239 uint8_t auth_input[AUTH_INPUT_LEN];
240 uint8_t auth[DIGEST256_LEN];
241 } s;
242 uint8_t *ai = s.auth_input, *si = s.secret_input;
243 const uint8_t *auth_candidate;
244 int bad;
246 /* Decode input */
247 memcpy(s.pubkey_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN);
248 auth_candidate = handshake_reply + CURVE25519_PUBKEY_LEN;
250 /* See note in server_handshake above about checking points. The
251 * circumstances under which we'd need to check Y for membership are
252 * different than those under which we'd be checking X. */
254 /* Compute secret_input */
255 curve25519_handshake(si, &handshake_state->seckey_x, &s.pubkey_Y);
256 bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
257 si += CURVE25519_OUTPUT_LEN;
258 curve25519_handshake(si, &handshake_state->seckey_x,
259 &handshake_state->pubkey_B);
260 bad |= (safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN) << 1);
261 si += CURVE25519_OUTPUT_LEN;
262 APPEND(si, handshake_state->router_id, DIGEST_LEN);
263 APPEND(si, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
264 APPEND(si, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
265 APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
266 APPEND(si, PROTOID, PROTOID_LEN);
267 tor_assert(si == s.secret_input + sizeof(s.secret_input));
269 /* Compute verify from secret_input */
270 h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);
272 /* Compute auth_input */
273 APPEND(ai, s.verify, DIGEST256_LEN);
274 APPEND(ai, handshake_state->router_id, DIGEST_LEN);
275 APPEND(ai, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
276 APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
277 APPEND(ai, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
278 APPEND(ai, PROTOID, PROTOID_LEN);
279 APPEND(ai, SERVER_STR, SERVER_STR_LEN);
280 tor_assert(ai == s.auth_input + sizeof(s.auth_input));
282 /* Compute auth */
283 h_tweak(s.auth, s.auth_input, sizeof(s.auth_input), T->t_mac);
285 bad |= (tor_memneq(s.auth, auth_candidate, DIGEST256_LEN) << 2);
287 crypto_expand_key_material_rfc5869_sha256(
288 s.secret_input, sizeof(s.secret_input),
289 (const uint8_t*)T->t_key, strlen(T->t_key),
290 (const uint8_t*)T->m_expand, strlen(T->m_expand),
291 key_out, key_out_len);
293 memwipe(&s, 0, sizeof(s));
295 if (bad) {
296 if (bad & 4) {
297 if (msg_out)
298 *msg_out = NULL; /* Don't report this one; we probably just had the
299 * wrong onion key.*/
300 log_fn(LOG_INFO, LD_PROTOCOL,
301 "Invalid result from curve25519 handshake: %d", bad);
303 if (bad & 3) {
304 if (msg_out)
305 *msg_out = "Zero output from curve25519 handshake";
306 log_fn(LOG_WARN, LD_PROTOCOL,
307 "Invalid result from curve25519 handshake: %d", bad);
311 return bad ? -1 : 0;