1 /* Copyright (c) 2001 Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2013, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
9 * \brief Functions to implement the original Tor circuit extension handshake
12 * We didn't call it "TAP" ourselves -- Ian Goldberg named it in "On the
13 * Security of the Tor Authentication Protocol". (Spoiler: it's secure, but
14 * its security is kind of fragile and implementation dependent. Never modify
15 * this implementation without reading and understanding that paper at least.)
20 #include "onion_tap.h"
23 /*----------------------------------------------------------------------*/
25 /** Given a router's 128 byte public key,
26 * stores the following in onion_skin_out:
27 * - [42 bytes] OAEP padding
28 * - [16 bytes] Symmetric key for encrypting blob past RSA
29 * - [70 bytes] g^x part 1 (inside the RSA)
30 * - [58 bytes] g^x part 2 (symmetrically encrypted)
32 * Stores the DH private key into handshake_state_out for later completion
35 * The meeting point/cookies and auth are zeroed out for now.
38 onion_skin_TAP_create(crypto_pk_t
*dest_router_key
,
39 crypto_dh_t
**handshake_state_out
,
40 char *onion_skin_out
) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
42 char challenge
[DH_KEY_LEN
];
43 crypto_dh_t
*dh
= NULL
;
46 tor_assert(dest_router_key
);
47 tor_assert(handshake_state_out
);
48 tor_assert(onion_skin_out
);
49 *handshake_state_out
= NULL
;
50 memset(onion_skin_out
, 0, TAP_ONIONSKIN_CHALLENGE_LEN
);
52 if (!(dh
= crypto_dh_new(DH_TYPE_CIRCUIT
)))
55 dhbytes
= crypto_dh_get_bytes(dh
);
56 pkbytes
= (int) crypto_pk_keysize(dest_router_key
);
57 tor_assert(dhbytes
== 128);
58 tor_assert(pkbytes
== 128);
60 if (crypto_dh_get_public(dh
, challenge
, dhbytes
))
63 note_crypto_pk_op(ENC_ONIONSKIN
);
65 /* set meeting point, meeting cookie, etc here. Leave zero for now. */
66 if (crypto_pk_public_hybrid_encrypt(dest_router_key
, onion_skin_out
,
67 TAP_ONIONSKIN_CHALLENGE_LEN
,
68 challenge
, DH_KEY_LEN
,
69 PK_PKCS1_OAEP_PADDING
, 1)<0)
72 memwipe(challenge
, 0, sizeof(challenge
));
73 *handshake_state_out
= dh
;
77 memwipe(challenge
, 0, sizeof(challenge
));
78 if (dh
) crypto_dh_free(dh
);
82 /** Given an encrypted DH public key as generated by onion_skin_create,
83 * and the private key for this onion router, generate the reply (128-byte
84 * DH plus the first 20 bytes of shared key material), and store the
85 * next key_out_len bytes of key material in key_out.
88 onion_skin_TAP_server_handshake(
89 /*TAP_ONIONSKIN_CHALLENGE_LEN*/
90 const char *onion_skin
,
91 crypto_pk_t
*private_key
,
92 crypto_pk_t
*prev_private_key
,
93 /*TAP_ONIONSKIN_REPLY_LEN*/
94 char *handshake_reply_out
,
98 char challenge
[TAP_ONIONSKIN_CHALLENGE_LEN
];
99 crypto_dh_t
*dh
= NULL
;
101 char *key_material
=NULL
;
102 size_t key_material_len
=0;
108 k
= i
==0?private_key
:prev_private_key
;
111 note_crypto_pk_op(DEC_ONIONSKIN
);
112 len
= crypto_pk_private_hybrid_decrypt(k
, challenge
,
113 TAP_ONIONSKIN_CHALLENGE_LEN
,
115 TAP_ONIONSKIN_CHALLENGE_LEN
,
116 PK_PKCS1_OAEP_PADDING
,0);
121 log_info(LD_PROTOCOL
,
122 "Couldn't decrypt onionskin: client may be using old onion key");
124 } else if (len
!= DH_KEY_LEN
) {
125 log_fn(LOG_PROTOCOL_WARN
, LD_PROTOCOL
,
126 "Unexpected onionskin length after decryption: %ld",
131 dh
= crypto_dh_new(DH_TYPE_CIRCUIT
);
133 log_warn(LD_BUG
, "Couldn't allocate DH key");
136 if (crypto_dh_get_public(dh
, handshake_reply_out
, DH_KEY_LEN
)) {
137 log_info(LD_GENERAL
, "crypto_dh_get_public failed.");
141 key_material_len
= DIGEST_LEN
+key_out_len
;
142 key_material
= tor_malloc(key_material_len
);
143 len
= crypto_dh_compute_secret(LOG_PROTOCOL_WARN
, dh
, challenge
,
144 DH_KEY_LEN
, key_material
,
147 log_info(LD_GENERAL
, "crypto_dh_compute_secret failed.");
151 /* send back H(K|0) as proof that we learned K. */
152 memcpy(handshake_reply_out
+DH_KEY_LEN
, key_material
, DIGEST_LEN
);
154 /* use the rest of the key material for our shared keys, digests, etc */
155 memcpy(key_out
, key_material
+DIGEST_LEN
, key_out_len
);
157 memwipe(challenge
, 0, sizeof(challenge
));
158 memwipe(key_material
, 0, key_material_len
);
159 tor_free(key_material
);
163 memwipe(challenge
, 0, sizeof(challenge
));
165 memwipe(key_material
, 0, key_material_len
);
166 tor_free(key_material
);
168 if (dh
) crypto_dh_free(dh
);
173 /** Finish the client side of the DH handshake.
174 * Given the 128 byte DH reply + 20 byte hash as generated by
175 * onion_skin_server_handshake and the handshake state generated by
176 * onion_skin_create, verify H(K) with the first 20 bytes of shared
177 * key material, then generate key_out_len more bytes of shared key
178 * material and store them in key_out.
180 * After the invocation, call crypto_dh_free on handshake_state.
183 onion_skin_TAP_client_handshake(crypto_dh_t
*handshake_state
,
184 const char *handshake_reply
, /* TAP_ONIONSKIN_REPLY_LEN bytes */
189 char *key_material
=NULL
;
190 size_t key_material_len
;
191 tor_assert(crypto_dh_get_bytes(handshake_state
) == DH_KEY_LEN
);
193 key_material_len
= DIGEST_LEN
+ key_out_len
;
194 key_material
= tor_malloc(key_material_len
);
195 len
= crypto_dh_compute_secret(LOG_PROTOCOL_WARN
, handshake_state
,
196 handshake_reply
, DH_KEY_LEN
, key_material
,
199 log_warn(LD_PROTOCOL
,"DH computation failed.");
203 if (tor_memneq(key_material
, handshake_reply
+DH_KEY_LEN
, DIGEST_LEN
)) {
204 /* H(K) does *not* match. Something fishy. */
205 log_warn(LD_PROTOCOL
,"Digest DOES NOT MATCH on onion handshake. "
210 /* use the rest of the key material for our shared keys, digests, etc */
211 memcpy(key_out
, key_material
+DIGEST_LEN
, key_out_len
);
213 memwipe(key_material
, 0, key_material_len
);
214 tor_free(key_material
);
217 memwipe(key_material
, 0, key_material_len
);
218 tor_free(key_material
);