1 /* Copyright 2004 Roger Dingledine, Nick Mathewson. */
2 /* See LICENSE for licensing information */
4 const char rendcommon_c_id
[] = "$Id$";
8 * \brief Rendezvous implementation: shared code between
9 * introducers, services, clients, and rendezvous points.
14 /** Return 0 if one and two are the same service ids, else -1 or 1 */
15 int rend_cmp_service_ids(const char *one
, const char *two
) {
16 return strcasecmp(one
,two
);
19 /** Free the storage held by the service descriptor <b>desc</b>.
21 void rend_service_descriptor_free(rend_service_descriptor_t
*desc
)
25 crypto_free_pk_env(desc
->pk
);
26 if (desc
->intro_points
) {
27 for (i
=0; i
< desc
->n_intro_points
; ++i
) {
28 tor_free(desc
->intro_points
[i
]);
30 tor_free(desc
->intro_points
);
35 /** Encode a service descriptor for <b>desc</b>, and sign it with
36 * <b>key</b>. Store the descriptor in *<b>str_out</b>, and set
37 * *<b>len_out</b> to its length.
40 rend_encode_service_descriptor(rend_service_descriptor_t
*desc
,
42 char **str_out
, size_t *len_out
)
44 char *buf
, *cp
, *ipoint
;
46 size_t keylen
, asn1len
;
47 keylen
= crypto_pk_keysize(desc
->pk
);
48 buf
= tor_malloc(keylen
*2); /* Too long, but that's okay. */
49 i
= crypto_pk_asn1_encode(desc
->pk
, buf
, keylen
*2);
55 *len_out
= 2 + asn1len
+ 4 + 2 + keylen
;
56 for (i
= 0; i
< desc
->n_intro_points
; ++i
) {
57 *len_out
+= strlen(desc
->intro_points
[i
]) + 1;
59 cp
= *str_out
= tor_malloc(*len_out
);
60 set_uint16(cp
, htons((uint16_t)asn1len
));
62 memcpy(cp
, buf
, asn1len
);
65 set_uint32(cp
, htonl((uint32_t)desc
->timestamp
));
67 set_uint16(cp
, htons((uint16_t)desc
->n_intro_points
));
69 for (i
=0; i
< desc
->n_intro_points
; ++i
) {
70 ipoint
= (char*)desc
->intro_points
[i
];
71 strlcpy(cp
, ipoint
, *len_out
-(cp
-*str_out
));
72 cp
+= strlen(ipoint
)+1;
74 i
= crypto_pk_private_sign_digest(key
, cp
, *str_out
, cp
-*str_out
);
80 tor_assert(*len_out
== (size_t)(cp
-*str_out
));
84 /** Parse a service descriptor at <b>str</b> (<b>len</b> bytes). On
85 * success, return a newly alloced service_descriptor_t. On failure,
88 rend_service_descriptor_t
*rend_parse_service_descriptor(
89 const char *str
, size_t len
)
91 rend_service_descriptor_t
*result
= NULL
;
93 size_t keylen
, asn1len
;
94 const char *end
, *cp
, *eos
;
96 result
= tor_malloc_zero(sizeof(rend_service_descriptor_t
));
99 if (end
-cp
< 2) goto truncated
;
100 asn1len
= ntohs(get_uint16(cp
));
102 if ((size_t)(end
-cp
) < asn1len
) goto truncated
;
103 result
->pk
= crypto_pk_asn1_decode(cp
, asn1len
);
104 if (!result
->pk
) goto truncated
;
106 if (end
-cp
< 4) goto truncated
;
107 result
->timestamp
= (time_t) ntohl(get_uint32(cp
));
109 if (end
-cp
< 2) goto truncated
;
110 result
->n_intro_points
= ntohs(get_uint16(cp
));
111 result
->intro_points
= tor_malloc_zero(sizeof(char*)*result
->n_intro_points
);
113 for (i
=0;i
<result
->n_intro_points
;++i
) {
114 if (end
-cp
< 2) goto truncated
;
115 eos
= (const char *)memchr(cp
,'\0',end
-cp
);
116 if (!eos
) goto truncated
;
117 result
->intro_points
[i
] = tor_strdup(cp
);
120 keylen
= crypto_pk_keysize(result
->pk
);
121 tor_assert(end
-cp
>= 0);
122 if ((size_t)(end
-cp
) < keylen
) goto truncated
;
123 if ((size_t)(end
-cp
) > keylen
) {
124 log_fn(LOG_WARN
, "Signature too long on service descriptor");
127 if (crypto_pk_public_checksig_digest(result
->pk
,
128 (char*)str
,cp
-str
, /* data */
129 (char*)cp
,end
-cp
/* signature*/
131 log_fn(LOG_WARN
, "Bad signature on service descriptor");
137 log_fn(LOG_WARN
, "Truncated service descriptor");
139 rend_service_descriptor_free(result
);
143 /** Sets <b>out</b> to the first 10 bytes of the digest of <b>pk</b>,
144 * base32 encoded. NUL-terminates out. (We use this string to
145 * identify services in directory requests and .onion URLs.)
147 int rend_get_service_id(crypto_pk_env_t
*pk
, char *out
)
149 char buf
[DIGEST_LEN
];
151 if (crypto_pk_get_digest(pk
, buf
) < 0)
153 base32_encode(out
, REND_SERVICE_ID_LEN
+1, buf
, 10);
157 /* ==== Rendezvous service descriptor cache. */
159 #define REND_CACHE_MAX_AGE (24*60*60)
160 #define REND_CACHE_MAX_SKEW (90*60)
162 /** Map from service id (as generated by rend_get_service_id) to
163 * rend_cache_entry_t. */
164 static strmap_t
*rend_cache
= NULL
;
166 /** Initializes the service descriptor cache.
168 void rend_cache_init(void)
170 rend_cache
= strmap_new();
173 /** Removes all old entries from the service descriptor cache.
175 void rend_cache_clean(void)
180 rend_cache_entry_t
*ent
;
182 cutoff
= time(NULL
) - REND_CACHE_MAX_AGE
;
183 for (iter
= strmap_iter_init(rend_cache
); !strmap_iter_done(iter
); ) {
184 strmap_iter_get(iter
, &key
, &val
);
185 ent
= (rend_cache_entry_t
*)val
;
186 if (ent
->parsed
->timestamp
< cutoff
) {
187 iter
= strmap_iter_next_rmv(rend_cache
, iter
);
188 rend_service_descriptor_free(ent
->parsed
);
192 iter
= strmap_iter_next(rend_cache
, iter
);
197 /** Return true iff <b>query</b> is a syntactically valid service ID (as
198 * generated by rend_get_service_id). */
199 int rend_valid_service_id(const char *query
) {
200 if (strlen(query
) != REND_SERVICE_ID_LEN
)
203 if (strspn(query
, BASE32_CHARS
) != REND_SERVICE_ID_LEN
)
209 /** If we have a cached rend_cache_entry_t for the service ID <b>query</b>, set
210 * *<b>e</b> to that entry and return 1. Else return 0.
212 int rend_cache_lookup_entry(const char *query
, rend_cache_entry_t
**e
)
214 tor_assert(rend_cache
);
215 if (!rend_valid_service_id(query
))
217 *e
= strmap_get_lc(rend_cache
, query
);
223 /** <b>query</b> is a base-32'ed service id. If it's malformed, return -1.
225 * - If it is found, point *desc to it, and write its length into
226 * *desc_len, and return 1.
227 * - If it is not found, return 0.
228 * Note: calls to rend_cache_clean or rend_cache_store may invalidate
231 int rend_cache_lookup_desc(const char *query
, const char **desc
, size_t *desc_len
)
233 rend_cache_entry_t
*e
;
235 r
= rend_cache_lookup_entry(query
,&e
);
236 if (r
<= 0) return r
;
242 /** Parse *desc, calculate its service id, and store it in the cache.
243 * If we have a newer descriptor with the same ID, ignore this one.
244 * If we have an older descriptor with the same ID, replace it.
245 * Return -1 if it's malformed or otherwise rejected; return 0 if
246 * it's the same or older than one we've already got; return 1 if
249 int rend_cache_store(const char *desc
, size_t desc_len
)
251 rend_cache_entry_t
*e
;
252 rend_service_descriptor_t
*parsed
;
253 char query
[REND_SERVICE_ID_LEN
+1];
256 tor_assert(rend_cache
);
257 parsed
= rend_parse_service_descriptor(desc
,desc_len
);
259 log_fn(LOG_WARN
,"Couldn't parse service descriptor");
262 if (rend_get_service_id(parsed
->pk
, query
)<0) {
263 log_fn(LOG_WARN
,"Couldn't compute service ID");
264 rend_service_descriptor_free(parsed
);
268 if (parsed
->timestamp
< now
-REND_CACHE_MAX_AGE
) {
269 log_fn(LOG_WARN
,"Service descriptor %s is too old", query
);
270 rend_service_descriptor_free(parsed
);
273 if (parsed
->timestamp
> now
+REND_CACHE_MAX_SKEW
) {
274 log_fn(LOG_WARN
,"Service descriptor %s is too far in the future", query
);
275 rend_service_descriptor_free(parsed
);
278 e
= (rend_cache_entry_t
*) strmap_get_lc(rend_cache
, query
);
279 if (e
&& e
->parsed
->timestamp
> parsed
->timestamp
) {
280 log_fn(LOG_INFO
,"We already have a newer service descriptor %s with the same ID", query
);
281 rend_service_descriptor_free(parsed
);
284 if (e
&& e
->len
== desc_len
&& !memcmp(desc
,e
->desc
,desc_len
)) {
285 log_fn(LOG_INFO
,"We already have this service descriptor %s", query
);
286 e
->received
= time(NULL
);
287 rend_service_descriptor_free(parsed
);
291 e
= tor_malloc_zero(sizeof(rend_cache_entry_t
));
292 strmap_set_lc(rend_cache
, query
, e
);
294 rend_service_descriptor_free(e
->parsed
);
297 e
->received
= time(NULL
);
300 e
->desc
= tor_malloc(desc_len
);
301 memcpy(e
->desc
, desc
, desc_len
);
303 log_fn(LOG_INFO
,"Successfully stored rend desc '%s', len %d", query
, (int)desc_len
);
307 /** Called when we get a rendezvous-related relay cell on circuit
308 * <b>circ</b>. Dispatch on rendezvous relay command. */
309 void rend_process_relay_cell(circuit_t
*circ
, int command
, size_t length
,
314 case RELAY_COMMAND_ESTABLISH_INTRO
:
315 r
= rend_mid_establish_intro(circ
,payload
,length
);
317 case RELAY_COMMAND_ESTABLISH_RENDEZVOUS
:
318 r
= rend_mid_establish_rendezvous(circ
,payload
,length
);
320 case RELAY_COMMAND_INTRODUCE1
:
321 r
= rend_mid_introduce(circ
,payload
,length
);
323 case RELAY_COMMAND_INTRODUCE2
:
324 r
= rend_service_introduce(circ
,payload
,length
);
326 case RELAY_COMMAND_INTRODUCE_ACK
:
327 r
= rend_client_introduction_acked(circ
,payload
,length
);
329 case RELAY_COMMAND_RENDEZVOUS1
:
330 r
= rend_mid_rendezvous(circ
,payload
,length
);
332 case RELAY_COMMAND_RENDEZVOUS2
:
333 r
= rend_client_receive_rendezvous(circ
,payload
,length
);
335 case RELAY_COMMAND_INTRO_ESTABLISHED
:
336 r
= rend_service_intro_established(circ
,payload
,length
);
338 case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED
:
339 r
= rend_client_rendezvous_acked(circ
,payload
,length
);