Tor 0.4.9.0-alpha-dev
onion_tap.c
Go to the documentation of this file.
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-2021, The Tor Project, Inc. */
5/* See LICENSE for licensing information */
6
7/**
8 * \file onion_tap.c
9 * \brief Functions to implement the original Tor circuit extension handshake
10 * (a.k.a TAP).
11 *
12 * The "TAP" handshake is the first one that was widely used in Tor: It
13 * combines RSA1024-OAEP and AES128-CTR to perform a hybrid encryption over
14 * the first message DH1024 key exchange. (The RSA-encrypted part of the
15 * encryption is authenticated; the AES-encrypted part isn't. This was
16 * not a smart choice.)
17 *
18 * We didn't call it "TAP" ourselves -- Ian Goldberg named it in "On the
19 * Security of the Tor Authentication Protocol". (Spoiler: it's secure, but
20 * its security is kind of fragile and implementation dependent. Never modify
21 * this implementation without reading and understanding that paper at least.)
22 *
23 * We have deprecated TAP since the ntor handshake came into general use. It
24 * is still used for hidden service IP and RP connections, however.
25 *
26 * This handshake, like the other circuit-extension handshakes, is
27 * invoked from onion.c.
28 **/
29
30#include "core/or/or.h"
31#include "app/config/config.h"
37
38/*----------------------------------------------------------------------*/
39
40/** Given a router's 128 byte public key,
41 * stores the following in onion_skin_out:
42 * - [42 bytes] OAEP padding
43 * - [16 bytes] Symmetric key for encrypting blob past RSA
44 * - [70 bytes] g^x part 1 (inside the RSA)
45 * - [58 bytes] g^x part 2 (symmetrically encrypted)
46 *
47 * Stores the DH private key into handshake_state_out for later completion
48 * of the handshake.
49 *
50 * The meeting point/cookies and auth are zeroed out for now.
51 */
52int
54 crypto_dh_t **handshake_state_out,
55 char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */
56{
57 char challenge[DH1024_KEY_LEN];
58 crypto_dh_t *dh = NULL;
59 int dhbytes, pkbytes;
60
61 tor_assert(dest_router_key);
62 tor_assert(handshake_state_out);
63 tor_assert(onion_skin_out);
64 *handshake_state_out = NULL;
65 memset(onion_skin_out, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
66
67 if (!(dh = crypto_dh_new(DH_TYPE_CIRCUIT)))
68 goto err;
69
70 dhbytes = crypto_dh_get_bytes(dh);
71 pkbytes = (int) crypto_pk_keysize(dest_router_key);
72 tor_assert(dhbytes == 128);
73 tor_assert(pkbytes == 128);
74
75 if (crypto_dh_get_public(dh, challenge, dhbytes))
76 goto err;
77
78 /* set meeting point, meeting cookie, etc here. Leave zero for now. */
79 if (crypto_pk_obsolete_public_hybrid_encrypt(dest_router_key, onion_skin_out,
80 TAP_ONIONSKIN_CHALLENGE_LEN,
81 challenge, DH1024_KEY_LEN,
83 goto err;
84
85 memwipe(challenge, 0, sizeof(challenge));
86 *handshake_state_out = dh;
87
88 return 0;
89 err:
90 /* LCOV_EXCL_START
91 * We only get here if RSA encryption fails or DH keygen fails. Those
92 * shouldn't be possible. */
93 memwipe(challenge, 0, sizeof(challenge));
94 if (dh) crypto_dh_free(dh);
95 return -1;
96 /* LCOV_EXCL_STOP */
97}
98
99/** Given an encrypted DH public key as generated by onion_skin_create,
100 * and the private key for this onion router, generate the reply (128-byte
101 * DH plus the first 20 bytes of shared key material), and store the
102 * next key_out_len bytes of key material in key_out.
103 */
104int
106 /*TAP_ONIONSKIN_CHALLENGE_LEN*/
107 const char *onion_skin,
108 crypto_pk_t *private_key,
109 crypto_pk_t *prev_private_key,
110 /*TAP_ONIONSKIN_REPLY_LEN*/
111 char *handshake_reply_out,
112 char *key_out,
113 size_t key_out_len)
114{
115 char challenge[TAP_ONIONSKIN_CHALLENGE_LEN];
116 crypto_dh_t *dh = NULL;
117 ssize_t len;
118 char *key_material=NULL;
119 size_t key_material_len=0;
120 int i;
121 crypto_pk_t *k;
122
123 len = -1;
124 for (i=0;i<2;++i) {
125 k = i==0?private_key:prev_private_key;
126 if (!k)
127 break;
129 TAP_ONIONSKIN_CHALLENGE_LEN,
130 onion_skin,
131 TAP_ONIONSKIN_CHALLENGE_LEN,
133 if (len>0)
134 break;
135 }
136 if (len<0) {
137 log_info(LD_PROTOCOL,
138 "Couldn't decrypt onionskin: client may be using old onion key");
139 goto err;
140 } else if (len != DH1024_KEY_LEN) {
141 log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
142 "Unexpected onionskin length after decryption: %ld",
143 (long)len);
144 goto err;
145 }
146
147 dh = crypto_dh_new(DH_TYPE_CIRCUIT);
148 if (!dh) {
149 /* LCOV_EXCL_START
150 * Failure to allocate a DH key should be impossible.
151 */
152 log_warn(LD_BUG, "Couldn't allocate DH key");
153 goto err;
154 /* LCOV_EXCL_STOP */
155 }
156 if (crypto_dh_get_public(dh, handshake_reply_out, DH1024_KEY_LEN)) {
157 /* LCOV_EXCL_START
158 * This can only fail if the length of the key we just allocated is too
159 * big. That should be impossible. */
160 log_info(LD_GENERAL, "crypto_dh_get_public failed.");
161 goto err;
162 /* LCOV_EXCL_STOP */
163 }
164
165 key_material_len = DIGEST_LEN+key_out_len;
166 key_material = tor_malloc(key_material_len);
167 len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge,
168 DH1024_KEY_LEN, key_material,
169 key_material_len);
170 if (len < 0) {
171 log_info(LD_GENERAL, "crypto_dh_compute_secret failed.");
172 goto err;
173 }
174
175 /* send back H(K|0) as proof that we learned K. */
176 memcpy(handshake_reply_out+DH1024_KEY_LEN, key_material, DIGEST_LEN);
177
178 /* use the rest of the key material for our shared keys, digests, etc */
179 memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
180
181 memwipe(challenge, 0, sizeof(challenge));
182 memwipe(key_material, 0, key_material_len);
183 tor_free(key_material);
184 crypto_dh_free(dh);
185 return 0;
186 err:
187 memwipe(challenge, 0, sizeof(challenge));
188 if (key_material) {
189 memwipe(key_material, 0, key_material_len);
190 tor_free(key_material);
191 }
192 if (dh) crypto_dh_free(dh);
193
194 return -1;
195}
196
197/** Finish the client side of the DH handshake.
198 * Given the 128 byte DH reply + 20 byte hash as generated by
199 * onion_skin_server_handshake and the handshake state generated by
200 * onion_skin_create, verify H(K) with the first 20 bytes of shared
201 * key material, then generate key_out_len more bytes of shared key
202 * material and store them in key_out.
203 *
204 * After the invocation, call crypto_dh_free on handshake_state.
205 */
206int
208 const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
209 char *key_out,
210 size_t key_out_len,
211 const char **msg_out)
212{
213 ssize_t len;
214 char *key_material=NULL;
215 size_t key_material_len;
216 tor_assert(crypto_dh_get_bytes(handshake_state) == DH1024_KEY_LEN);
217
218 key_material_len = DIGEST_LEN + key_out_len;
219 key_material = tor_malloc(key_material_len);
220 len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state,
221 handshake_reply, DH1024_KEY_LEN, key_material,
222 key_material_len);
223 if (len < 0) {
224 if (msg_out)
225 *msg_out = "DH computation failed.";
226 goto err;
227 }
228
229 if (tor_memneq(key_material, handshake_reply+DH1024_KEY_LEN, DIGEST_LEN)) {
230 /* H(K) does *not* match. Something fishy. */
231 if (msg_out)
232 *msg_out = "Digest DOES NOT MATCH on onion handshake. Bug or attack.";
233 goto err;
234 }
235
236 /* use the rest of the key material for our shared keys, digests, etc */
237 memcpy(key_out, key_material+DIGEST_LEN, key_out_len);
238
239 memwipe(key_material, 0, key_material_len);
240 tor_free(key_material);
241 return 0;
242 err:
243 memwipe(key_material, 0, key_material_len);
244 tor_free(key_material);
245 return -1;
246}
Header file for config.c.
ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, const char *pubkey, size_t pubkey_len, char *secret_out, size_t secret_bytes_out)
Definition: crypto_dh.c:79
Headers for crypto_dh.c.
crypto_dh_t * crypto_dh_new(int dh_type)
Definition: crypto_dh_nss.c:75
int crypto_dh_get_bytes(crypto_dh_t *dh)
Definition: crypto_dh_nss.c:95
int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, size_t pubkey_out_len)
Common functions for using (pseudo-)random number generators.
int crypto_pk_obsolete_public_hybrid_encrypt(crypto_pk_t *env, char *to, size_t tolen, const char *from, size_t fromlen, int padding, int force)
Definition: crypto_rsa.c:94
int crypto_pk_obsolete_private_hybrid_decrypt(crypto_pk_t *env, char *to, size_t tolen, const char *from, size_t fromlen, int padding, int warnOnFailure)
Definition: crypto_rsa.c:163
size_t crypto_pk_keysize(const crypto_pk_t *env)
#define PK_PKCS1_OAEP_PADDING
Definition: crypto_rsa.h:27
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:55
Common functions for cryptographic routines.
#define DH1024_KEY_LEN
Definition: dh_sizes.h:20
#define tor_memneq(a, b, sz)
Definition: di_ops.h:21
#define DIGEST_LEN
Definition: digest_sizes.h:20
#define log_fn(severity, domain, args,...)
Definition: log.h:283
#define LD_PROTOCOL
Definition: log.h:72
#define LD_BUG
Definition: log.h:86
#define LD_GENERAL
Definition: log.h:62
#define tor_free(p)
Definition: malloc.h:56
int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, const char *handshake_reply, char *key_out, size_t key_out_len, const char **msg_out)
Definition: onion_tap.c:207
int onion_skin_TAP_create(crypto_pk_t *dest_router_key, crypto_dh_t **handshake_state_out, char *onion_skin_out)
Definition: onion_tap.c:53
int onion_skin_TAP_server_handshake(const char *onion_skin, crypto_pk_t *private_key, crypto_pk_t *prev_private_key, char *handshake_reply_out, char *key_out, size_t key_out_len)
Definition: onion_tap.c:105
Header file for onion_tap.c.
Master header file for Tor-specific functionality.
Header file for rephist.c.
#define tor_assert(expr)
Definition: util_bug.h:103