Bug 6572: Use timestamp_created for liveness sanity checks.
[tor.git] / src / or / onion_ntor.c
blob9cf7d5dd6eb17b7a98e49b8a1d7a1dbdd73666e4
1 /* Copyright (c) 2012-2013, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include "orconfig.h"
6 #include "crypto.h"
7 #define ONION_NTOR_PRIVATE
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)
231 const tweakset_t *T = &proto1_tweaks;
232 /* Sensitive stack-allocated material. Kept in an anonymous struct to make
233 * it easy to wipe. */
234 struct {
235 curve25519_public_key_t pubkey_Y;
236 uint8_t secret_input[SECRET_INPUT_LEN];
237 uint8_t verify[DIGEST256_LEN];
238 uint8_t auth_input[AUTH_INPUT_LEN];
239 uint8_t auth[DIGEST256_LEN];
240 } s;
241 uint8_t *ai = s.auth_input, *si = s.secret_input;
242 const uint8_t *auth_candidate;
243 int bad;
245 /* Decode input */
246 memcpy(s.pubkey_Y.public_key, handshake_reply, CURVE25519_PUBKEY_LEN);
247 auth_candidate = handshake_reply + CURVE25519_PUBKEY_LEN;
249 /* See note in server_handshake above about checking points. The
250 * circumstances under which we'd need to check Y for membership are
251 * different than those under which we'd be checking X. */
253 /* Compute secret_input */
254 curve25519_handshake(si, &handshake_state->seckey_x, &s.pubkey_Y);
255 bad = safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
256 si += CURVE25519_OUTPUT_LEN;
257 curve25519_handshake(si, &handshake_state->seckey_x,
258 &handshake_state->pubkey_B);
259 bad |= safe_mem_is_zero(si, CURVE25519_OUTPUT_LEN);
260 si += CURVE25519_OUTPUT_LEN;
261 APPEND(si, handshake_state->router_id, DIGEST_LEN);
262 APPEND(si, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
263 APPEND(si, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
264 APPEND(si, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
265 APPEND(si, PROTOID, PROTOID_LEN);
266 tor_assert(si == s.secret_input + sizeof(s.secret_input));
268 /* Compute verify from secret_input */
269 h_tweak(s.verify, s.secret_input, sizeof(s.secret_input), T->t_verify);
271 /* Compute auth_input */
272 APPEND(ai, s.verify, DIGEST256_LEN);
273 APPEND(ai, handshake_state->router_id, DIGEST_LEN);
274 APPEND(ai, handshake_state->pubkey_B.public_key, CURVE25519_PUBKEY_LEN);
275 APPEND(ai, s.pubkey_Y.public_key, CURVE25519_PUBKEY_LEN);
276 APPEND(ai, handshake_state->pubkey_X.public_key, CURVE25519_PUBKEY_LEN);
277 APPEND(ai, PROTOID, PROTOID_LEN);
278 APPEND(ai, SERVER_STR, SERVER_STR_LEN);
279 tor_assert(ai == s.auth_input + sizeof(s.auth_input));
281 /* Compute auth */
282 h_tweak(s.auth, s.auth_input, sizeof(s.auth_input), T->t_mac);
284 bad |= tor_memneq(s.auth, auth_candidate, DIGEST256_LEN);
286 crypto_expand_key_material_rfc5869_sha256(
287 s.secret_input, sizeof(s.secret_input),
288 (const uint8_t*)T->t_key, strlen(T->t_key),
289 (const uint8_t*)T->m_expand, strlen(T->m_expand),
290 key_out, key_out_len);
292 memwipe(&s, 0, sizeof(s));
293 return bad ? -1 : 0;