1 /* Copyright (c) 2012-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
4 /**
5  * \file ext_orport.c
6  * \brief Code implementing the Extended ORPort.
7  *
8  * The Extended ORPort interface is used by pluggable transports to
9  * communicate additional information to a Tor bridge, including
10  * address information. For more information on this interface,
11  * see pt-spec.txt in torspec.git.
12  *
13  * There is no separate structure for extended ORPort connections; they use
14  * or_connection_t objects, and share most of their implementation with
15  * connection_or.c.  Once the handshake is done, an extended ORPort connection
16  * turns into a regular OR connection, using connection_ext_or_transition().
17  */
18 
19 #define EXT_ORPORT_PRIVATE
20 #include "core/or/or.h"
21 #include "core/mainloop/connection.h"
22 #include "core/or/connection_or.h"
23 #include "feature/control/control_events.h"
24 #include "app/config/config.h"
25 #include "lib/crypt_ops/crypto_rand.h"
26 #include "lib/crypt_ops/crypto_util.h"
27 #include "feature/relay/ext_orport.h"
28 #include "core/mainloop/mainloop.h"
29 #include "core/proto/proto_ext_or.h"
30 
31 #include "core/or/or_connection_st.h"
32 
33 /** Allocate and return a structure capable of holding an Extended
34  *  ORPort message of body length <b>len</b>. */
35 ext_or_cmd_t *
ext_or_cmd_new(uint16_t len)36 ext_or_cmd_new(uint16_t len)
37 {
38   size_t size = offsetof(ext_or_cmd_t, body) + len;
39   ext_or_cmd_t *cmd = tor_malloc(size);
40   cmd->len = len;
41   return cmd;
42 }
43 
44 /** Deallocate the Extended ORPort message in <b>cmd</b>. */
45 void
ext_or_cmd_free_(ext_or_cmd_t * cmd)46 ext_or_cmd_free_(ext_or_cmd_t *cmd)
47 {
48   tor_free(cmd);
49 }
50 
51 /** Get an Extended ORPort message from <b>conn</b>, and place it in
52  *  <b>out</b>. Return -1 on fail, 0 if we need more data, and 1 if we
53  *  successfully extracted an Extended ORPort command from the
54  *  buffer.  */
55 static int
connection_fetch_ext_or_cmd_from_buf(connection_t * conn,ext_or_cmd_t ** out)56 connection_fetch_ext_or_cmd_from_buf(connection_t *conn, ext_or_cmd_t **out)
57 {
58   return fetch_ext_or_command_from_buf(conn->inbuf, out);
59 }
60 
61 /** Write an Extended ORPort message to <b>conn</b>. Use
62  *  <b>command</b> as the command type, <b>bodylen</b> as the body
63  *  length, and <b>body</b>, if it's present, as the body of the
64  *  message. */
65 STATIC int
connection_write_ext_or_command(connection_t * conn,uint16_t command,const char * body,size_t bodylen)66 connection_write_ext_or_command(connection_t *conn,
67                                 uint16_t command,
68                                 const char *body,
69                                 size_t bodylen)
70 {
71   char header[4];
72   if (bodylen > UINT16_MAX)
73     return -1;
74   set_uint16(header, htons(command));
75   set_uint16(header+2, htons(bodylen));
76   connection_buf_add(header, 4, conn);
77   if (bodylen) {
78     tor_assert(body);
79     connection_buf_add(body, bodylen, conn);
80   }
81   return 0;
82 }
83 
84 /** Transition from an Extended ORPort which accepts Extended ORPort
85  *  messages, to an Extended ORport which accepts OR traffic. */
86 static void
connection_ext_or_transition(or_connection_t * conn)87 connection_ext_or_transition(or_connection_t *conn)
88 {
89   tor_assert(conn->base_.type == CONN_TYPE_EXT_OR);
90 
91   conn->base_.type = CONN_TYPE_OR;
92   TO_CONN(conn)->state = 0; // set the state to a neutral value
93   connection_or_event_status(conn, OR_CONN_EVENT_NEW, 0);
94   connection_tls_start_handshake(conn, 1);
95 }
96 
97 /** Length of authentication cookie. */
98 #define EXT_OR_PORT_AUTH_COOKIE_LEN 32
99 /** Length of the header of the cookie file. */
100 #define EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN 32
101 /** Static cookie file header. */
102 #define EXT_OR_PORT_AUTH_COOKIE_HEADER "! Extended ORPort Auth Cookie !\x0a"
103 /** Length of safe-cookie protocol hashes. */
104 #define EXT_OR_PORT_AUTH_HASH_LEN DIGEST256_LEN
105 /** Length of safe-cookie protocol nonces. */
106 #define EXT_OR_PORT_AUTH_NONCE_LEN 32
107 /** Safe-cookie protocol constants. */
108 #define EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST \
109   "ExtORPort authentication server-to-client hash"
110 #define EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST \
111   "ExtORPort authentication client-to-server hash"
112 
113 /* Code to indicate cookie authentication */
114 #define EXT_OR_AUTHTYPE_SAFECOOKIE 0x01
115 
116 /** If true, we've set ext_or_auth_cookie to a secret code and stored
117  * it to disk. */
118 STATIC int ext_or_auth_cookie_is_set = 0;
119 /** If ext_or_auth_cookie_is_set, a secret cookie that we've stored to disk
120  * and which we're using to authenticate controllers.  (If the controller can
121  * read it off disk, it has permission to connect.) */
122 STATIC uint8_t *ext_or_auth_cookie = NULL;
123 
124 /** Helper: Return a newly allocated string containing a path to the
125  * file where we store our authentication cookie. */
126 char *
get_ext_or_auth_cookie_file_name(void)127 get_ext_or_auth_cookie_file_name(void)
128 {
129   const or_options_t *options = get_options();
130   if (options->ExtORPortCookieAuthFile &&
131       strlen(options->ExtORPortCookieAuthFile)) {
132     return tor_strdup(options->ExtORPortCookieAuthFile);
133   } else {
134     return get_datadir_fname("extended_orport_auth_cookie");
135   }
136 }
137 
138 /* Initialize the cookie-based authentication system of the
139  * Extended ORPort. If <b>is_enabled</b> is 0, then disable the cookie
140  * authentication system. */
141 int
init_ext_or_cookie_authentication(int is_enabled)142 init_ext_or_cookie_authentication(int is_enabled)
143 {
144   char *fname = NULL;
145   int retval;
146 
147   if (!is_enabled) {
148     ext_or_auth_cookie_is_set = 0;
149     return 0;
150   }
151 
152   fname = get_ext_or_auth_cookie_file_name();
153   retval = init_cookie_authentication(fname, EXT_OR_PORT_AUTH_COOKIE_HEADER,
154                                       EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN,
155                            get_options()->ExtORPortCookieAuthFileGroupReadable,
156                                       &ext_or_auth_cookie,
157                                       &ext_or_auth_cookie_is_set);
158   tor_free(fname);
159   return retval;
160 }
161 
162 /** Read data from <b>conn</b> and see if the client sent us the
163  *  authentication type that they prefer to use in this session.
164  *
165  *  Return -1 if we received corrupted data or if we don't support the
166  *  authentication type. Return 0 if we need more data in
167  *  <b>conn</b>. Return 1 if the authentication type negotiation was
168  *  successful. */
169 static int
connection_ext_or_auth_neg_auth_type(connection_t * conn)170 connection_ext_or_auth_neg_auth_type(connection_t *conn)
171 {
172   char authtype[1] = {0};
173 
174   if (connection_get_inbuf_len(conn) < 1)
175     return 0;
176 
177   if (connection_buf_get_bytes(authtype, 1, conn) < 0)
178     return -1;
179 
180   log_debug(LD_GENERAL, "Client wants us to use %d auth type", authtype[0]);
181   if (authtype[0] != EXT_OR_AUTHTYPE_SAFECOOKIE) {
182     /* '1' is the only auth type supported atm */
183     return -1;
184   }
185 
186   conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE;
187   return 1;
188 }
189 
190 /* DOCDOC */
191 STATIC int
handle_client_auth_nonce(const char * client_nonce,size_t client_nonce_len,char ** client_hash_out,char ** reply_out,size_t * reply_len_out)192 handle_client_auth_nonce(const char *client_nonce, size_t client_nonce_len,
193                          char **client_hash_out,
194                          char **reply_out, size_t *reply_len_out)
195 {
196   char server_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0};
197   char server_nonce[EXT_OR_PORT_AUTH_NONCE_LEN] = {0};
198   char *reply;
199   size_t reply_len;
200 
201   if (client_nonce_len != EXT_OR_PORT_AUTH_NONCE_LEN)
202     return -1;
203 
204   /* Get our nonce */
205   crypto_rand(server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
206 
207   { /* set up macs */
208     size_t hmac_s_msg_len = strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) +
209       2*EXT_OR_PORT_AUTH_NONCE_LEN;
210     size_t hmac_c_msg_len = strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) +
211       2*EXT_OR_PORT_AUTH_NONCE_LEN;
212 
213     char *hmac_s_msg = tor_malloc_zero(hmac_s_msg_len);
214     char *hmac_c_msg = tor_malloc_zero(hmac_c_msg_len);
215     char *correct_client_hash = tor_malloc_zero(EXT_OR_PORT_AUTH_HASH_LEN);
216 
217     memcpy(hmac_s_msg,
218            EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST,
219            strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST));
220     memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST),
221            client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
222     memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) +
223            EXT_OR_PORT_AUTH_NONCE_LEN,
224            server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
225 
226     memcpy(hmac_c_msg,
227            EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST,
228            strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST));
229     memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST),
230            client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
231     memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) +
232            EXT_OR_PORT_AUTH_NONCE_LEN,
233            server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
234 
235     crypto_hmac_sha256(server_hash,
236                        (char*)ext_or_auth_cookie,
237                        EXT_OR_PORT_AUTH_COOKIE_LEN,
238                        hmac_s_msg,
239                        hmac_s_msg_len);
240 
241     crypto_hmac_sha256(correct_client_hash,
242                        (char*)ext_or_auth_cookie,
243                        EXT_OR_PORT_AUTH_COOKIE_LEN,
244                        hmac_c_msg,
245                        hmac_c_msg_len);
246 
247     /* Store the client hash we generated. We will need to compare it
248        with the hash sent by the client. */
249     *client_hash_out = correct_client_hash;
250 
251     memwipe(hmac_s_msg, 0, hmac_s_msg_len);
252     memwipe(hmac_c_msg, 0, hmac_c_msg_len);
253 
254     tor_free(hmac_s_msg);
255     tor_free(hmac_c_msg);
256   }
257 
258   { /* debug logging */ /* XXX disable this codepath if not logging on debug?*/
259     char server_hash_encoded[(2*EXT_OR_PORT_AUTH_HASH_LEN) + 1];
260     char server_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1];
261     char client_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1];
262 
263     base16_encode(server_hash_encoded, sizeof(server_hash_encoded),
264                   server_hash, sizeof(server_hash));
265     base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded),
266                   server_nonce, sizeof(server_nonce));
267     base16_encode(client_nonce_encoded, sizeof(client_nonce_encoded),
268                   client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
269 
270     log_debug(LD_GENERAL,
271               "server_hash: '%s'\nserver_nonce: '%s'\nclient_nonce: '%s'",
272               server_hash_encoded, server_nonce_encoded, client_nonce_encoded);
273 
274     memwipe(server_hash_encoded, 0, sizeof(server_hash_encoded));
275     memwipe(server_nonce_encoded, 0, sizeof(server_nonce_encoded));
276     memwipe(client_nonce_encoded, 0, sizeof(client_nonce_encoded));
277   }
278 
279   { /* write reply: (server_hash, server_nonce) */
280 
281     reply_len = EXT_OR_PORT_AUTH_COOKIE_LEN+EXT_OR_PORT_AUTH_NONCE_LEN;
282     reply = tor_malloc_zero(reply_len);
283     memcpy(reply, server_hash, EXT_OR_PORT_AUTH_HASH_LEN);
284     memcpy(reply + EXT_OR_PORT_AUTH_HASH_LEN, server_nonce,
285            EXT_OR_PORT_AUTH_NONCE_LEN);
286   }
287 
288   *reply_out = reply;
289   *reply_len_out = reply_len;
290 
291   return 0;
292 }
293 
294 /** Read the client's nonce out of <b>conn</b>, setup the safe-cookie
295  *  crypto, and then send our own hash and nonce to the client
296  *
297  *  Return -1 if there was an error; return 0 if we need more data in
298  *  <b>conn</b>, and return 1 if we successfully retrieved the
299  *  client's nonce and sent our own. */
300 static int
connection_ext_or_auth_handle_client_nonce(connection_t * conn)301 connection_ext_or_auth_handle_client_nonce(connection_t *conn)
302 {
303   char client_nonce[EXT_OR_PORT_AUTH_NONCE_LEN];
304   char *reply=NULL;
305   size_t reply_len=0;
306 
307   if (!ext_or_auth_cookie_is_set) { /* this should not happen */
308     log_warn(LD_BUG, "Extended ORPort authentication cookie was not set. "
309              "That's weird since we should have done that on startup. "
310              "This might be a Tor bug, please file a bug report. ");
311     return -1;
312   }
313 
314   if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_NONCE_LEN)
315     return 0;
316 
317   if (connection_buf_get_bytes(client_nonce,
318                                 EXT_OR_PORT_AUTH_NONCE_LEN, conn) < 0)
319     return -1;
320 
321   /* We extract the ClientNonce from the received data, and use it to
322      calculate ServerHash and ServerNonce according to proposal 217.
323 
324      We also calculate our own ClientHash value and save it in the
325      connection state. We validate it later against the ClientHash
326      sent by the client.  */
327   if (handle_client_auth_nonce(client_nonce, sizeof(client_nonce),
328                             &TO_OR_CONN(conn)->ext_or_auth_correct_client_hash,
329                             &reply, &reply_len) < 0)
330     return -1;
331 
332   connection_buf_add(reply, reply_len, conn);
333 
334   memwipe(reply, 0, reply_len);
335   tor_free(reply);
336 
337   log_debug(LD_GENERAL, "Got client nonce, and sent our own nonce and hash.");
338 
339   conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH;
340   return 1;
341 }
342 
343 #define connection_ext_or_auth_send_result_success(c)  \
344   connection_ext_or_auth_send_result(c, 1)
345 #define connection_ext_or_auth_send_result_fail(c)  \
346   connection_ext_or_auth_send_result(c, 0)
347 
348 /** Send authentication results to <b>conn</b>. Successful results if
349  *  <b>success</b> is set; failure results otherwise. */
350 static void
connection_ext_or_auth_send_result(connection_t * conn,int success)351 connection_ext_or_auth_send_result(connection_t *conn, int success)
352 {
353   if (success)
354     connection_buf_add("\x01", 1, conn);
355   else
356     connection_buf_add("\x00", 1, conn);
357 }
358 
359 /** Receive the client's hash from <b>conn</b>, validate that it's
360  *  correct, and then send the authentication results to the client.
361  *
362  *  Return -1 if there was an error during validation; return 0 if we
363  *  need more data in <b>conn</b>, and return 1 if we successfully
364  *  validated the client's hash and sent a happy authentication
365  *  result. */
366 static int
connection_ext_or_auth_handle_client_hash(connection_t * conn)367 connection_ext_or_auth_handle_client_hash(connection_t *conn)
368 {
369   char provided_client_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0};
370 
371   if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_HASH_LEN)
372     return 0;
373 
374   if (connection_buf_get_bytes(provided_client_hash,
375                                 EXT_OR_PORT_AUTH_HASH_LEN, conn) < 0)
376     return -1;
377 
378   if (tor_memneq(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash,
379                  provided_client_hash, EXT_OR_PORT_AUTH_HASH_LEN)) {
380     log_warn(LD_GENERAL, "Incorrect client hash. Authentication failed.");
381     connection_ext_or_auth_send_result_fail(conn);
382     return -1;
383   }
384 
385   log_debug(LD_GENERAL, "Got client's hash and it was legit.");
386 
387   /* send positive auth result */
388   connection_ext_or_auth_send_result_success(conn);
389   conn->state = EXT_OR_CONN_STATE_OPEN;
390   return 1;
391 }
392 
393 /** Handle data from <b>or_conn</b> received on Extended ORPort.
394  *  Return -1 on error. 0 on insufficient data. 1 on correct. */
395 static int
connection_ext_or_auth_process_inbuf(or_connection_t * or_conn)396 connection_ext_or_auth_process_inbuf(or_connection_t *or_conn)
397 {
398   connection_t *conn = TO_CONN(or_conn);
399 
400   /* State transitions of the Extended ORPort authentication protocol:
401 
402      EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE (start state) ->
403      EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE ->
404      EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH ->
405      EXT_OR_CONN_STATE_OPEN
406 
407      During EXT_OR_CONN_STATE_OPEN, data is handled by
408      connection_ext_or_process_inbuf().
409   */
410 
411   switch (conn->state) { /* Functionify */
412   case EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE:
413     return connection_ext_or_auth_neg_auth_type(conn);
414 
415   case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE:
416     return connection_ext_or_auth_handle_client_nonce(conn);
417 
418   case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH:
419     return connection_ext_or_auth_handle_client_hash(conn);
420 
421   default:
422     log_warn(LD_BUG, "Encountered unexpected connection state %d while trying "
423              "to process Extended ORPort authentication data.", conn->state);
424     return -1;
425   }
426 }
427 
428 /** Extended ORPort commands (Transport-to-Bridge) */
429 #define EXT_OR_CMD_TB_DONE 0x0000
430 #define EXT_OR_CMD_TB_USERADDR 0x0001
431 #define EXT_OR_CMD_TB_TRANSPORT 0x0002
432 
433 /** Extended ORPort commands (Bridge-to-Transport) */
434 #define EXT_OR_CMD_BT_OKAY 0x1000
435 #define EXT_OR_CMD_BT_DENY 0x1001
436 #define EXT_OR_CMD_BT_CONTROL 0x1002
437 
438 /** Process a USERADDR command from the Extended
439  *  ORPort. <b>payload</b> is a payload of size <b>len</b>.
440  *
441  *  If the USERADDR command was well formed, change the address of
442  *  <b>conn</b> to the address on the USERADDR command.
443  *
444  *  Return 0 on success and -1 on error. */
445 static int
connection_ext_or_handle_cmd_useraddr(connection_t * conn,const char * payload,uint16_t len)446 connection_ext_or_handle_cmd_useraddr(connection_t *conn,
447                                       const char *payload, uint16_t len)
448 {
449   /* Copy address string. */
450   tor_addr_t addr;
451   uint16_t port;
452   char *addr_str;
453   char *address_part=NULL;
454   int res;
455   if (memchr(payload, '\0', len)) {
456     log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort UserAddr");
457     return -1;
458   }
459 
460   addr_str = tor_memdup_nulterm(payload, len);
461 
462   res = tor_addr_port_split(LOG_INFO, addr_str, &address_part, &port);
463   tor_free(addr_str);
464   if (res<0)
465     return -1;
466   if (port == 0) {
467     log_warn(LD_GENERAL, "Server transport proxy gave us an empty port "
468              "in ExtORPort UserAddr command.");
469     // return -1; // enable this if nothing breaks after a while.
470   }
471 
472   res = tor_addr_parse(&addr, address_part);
473   tor_free(address_part);
474   if (res<0)
475     return -1;
476 
477   { /* do some logging */
478     char *old_address = tor_addr_to_str_dup(&conn->addr);
479     char *new_address = tor_addr_to_str_dup(&addr);
480 
481     log_debug(LD_NET, "Received USERADDR."
482              "We rewrite our address from '%s:%u' to '%s:%u'.",
483              safe_str(old_address), conn->port, safe_str(new_address), port);
484 
485     tor_free(old_address);
486     tor_free(new_address);
487   }
488 
489   /* record the address */
490   tor_addr_copy(&conn->addr, &addr);
491   conn->port = port;
492   if (conn->address) {
493     tor_free(conn->address);
494   }
495   conn->address = tor_addr_to_str_dup(&addr);
496 
497   /* Now that we know the address, we don't have to manually override rate
498    * limiting. */
499   conn->always_rate_limit_as_remote = 0;
500 
501   return 0;
502 }
503 
504 /** Process a TRANSPORT command from the Extended
505  *  ORPort. <b>payload</b> is a payload of size <b>len</b>.
506  *
507  *  If the TRANSPORT command was well formed, register the name of the
508  *  transport on <b>conn</b>.
509  *
510  *  Return 0 on success and -1 on error. */
511 static int
connection_ext_or_handle_cmd_transport(or_connection_t * conn,const char * payload,uint16_t len)512 connection_ext_or_handle_cmd_transport(or_connection_t *conn,
513                                        const char *payload, uint16_t len)
514 {
515   char *transport_str;
516   if (memchr(payload, '\0', len)) {
517     log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort Transport");
518     return -1;
519   }
520 
521   transport_str = tor_memdup_nulterm(payload, len);
522 
523   /* Transport names MUST be C-identifiers. */
524   if (!string_is_C_identifier(transport_str)) {
525     tor_free(transport_str);
526     return -1;
527   }
528 
529   /* If ext_or_transport is already occupied (because the PT sent two
530    *  TRANSPORT commands), deallocate the old name and keep the new
531    *  one */
532   if (conn->ext_or_transport)
533     tor_free(conn->ext_or_transport);
534 
535   conn->ext_or_transport = transport_str;
536   return 0;
537 }
538 
539 #define EXT_OR_CONN_STATE_IS_AUTHENTICATING(st) \
540   ((st) <= EXT_OR_CONN_STATE_AUTH_MAX)
541 
542 /** Process Extended ORPort messages from <b>or_conn</b>. */
543 int
connection_ext_or_process_inbuf(or_connection_t * or_conn)544 connection_ext_or_process_inbuf(or_connection_t *or_conn)
545 {
546   connection_t *conn = TO_CONN(or_conn);
547   ext_or_cmd_t *command;
548   int r;
549 
550   /* DOCDOC Document the state machine and transitions in this function */
551 
552   /* If we are still in the authentication stage, process traffic as
553      authentication data: */
554   while (EXT_OR_CONN_STATE_IS_AUTHENTICATING(conn->state)) {
555     log_debug(LD_GENERAL, "Got Extended ORPort authentication data (%u).",
556               (unsigned int) connection_get_inbuf_len(conn));
557     r = connection_ext_or_auth_process_inbuf(or_conn);
558     if (r < 0) {
559       connection_mark_for_close(conn);
560       return -1;
561     } else if (r == 0) {
562       return 0;
563     }
564     /* if r > 0, loop and process more data (if any). */
565   }
566 
567   while (1) {
568     log_debug(LD_GENERAL, "Got Extended ORPort data.");
569     command = NULL;
570     r = connection_fetch_ext_or_cmd_from_buf(conn, &command);
571     if (r < 0)
572       goto err;
573     else if (r == 0)
574       return 0; /* need to wait for more data */
575 
576     /* Got a command! */
577     tor_assert(command);
578 
579     if (command->cmd == EXT_OR_CMD_TB_DONE) {
580       if (connection_get_inbuf_len(conn)) {
581         /* The inbuf isn't empty; the client is misbehaving. */
582         goto err;
583       }
584 
585       log_debug(LD_NET, "Received DONE.");
586 
587       /* If the transport proxy did not use the TRANSPORT command to
588        * specify the transport name, mark this as unknown transport. */
589       if (!or_conn->ext_or_transport) {
590         /* We write this string this way to avoid ??>, which is a C
591          * trigraph. */
592         or_conn->ext_or_transport = tor_strdup("<?" "?>");
593       }
594 
595       connection_write_ext_or_command(conn, EXT_OR_CMD_BT_OKAY, NULL, 0);
596 
597       /* can't transition immediately; need to flush first. */
598       conn->state = EXT_OR_CONN_STATE_FLUSHING;
599       connection_stop_reading(conn);
600     } else if (command->cmd == EXT_OR_CMD_TB_USERADDR) {
601       if (connection_ext_or_handle_cmd_useraddr(conn,
602                                             command->body, command->len) < 0)
603         goto err;
604     } else if (command->cmd == EXT_OR_CMD_TB_TRANSPORT) {
605       if (connection_ext_or_handle_cmd_transport(or_conn,
606                                              command->body, command->len) < 0)
607         goto err;
608     } else {
609       log_notice(LD_NET,"Got Extended ORPort command we don't recognize (%u).",
610                  command->cmd);
611     }
612 
613     ext_or_cmd_free(command);
614   }
615 
616   return 0;
617 
618  err:
619   ext_or_cmd_free(command);
620   connection_mark_for_close(conn);
621   return -1;
622 }
623 
624 /** <b>conn</b> finished flushing Extended ORPort messages to the
625  *  network, and is now ready to accept OR traffic. This function
626  *  does the transition. */
627 int
connection_ext_or_finished_flushing(or_connection_t * conn)628 connection_ext_or_finished_flushing(or_connection_t *conn)
629 {
630   if (conn->base_.state == EXT_OR_CONN_STATE_FLUSHING) {
631     connection_start_reading(TO_CONN(conn));
632     connection_ext_or_transition(conn);
633   }
634   return 0;
635 }
636 
637 /** Initiate Extended ORPort authentication, by sending the list of
638  *  supported authentication types to the client. */
639 int
connection_ext_or_start_auth(or_connection_t * or_conn)640 connection_ext_or_start_auth(or_connection_t *or_conn)
641 {
642   connection_t *conn = TO_CONN(or_conn);
643   const uint8_t authtypes[] = {
644     /* We only support authtype '1' for now. */
645     EXT_OR_AUTHTYPE_SAFECOOKIE,
646     /* Marks the end of the list. */
647     0
648   };
649 
650   log_debug(LD_GENERAL,
651            "ExtORPort authentication: Sending supported authentication types");
652 
653   connection_buf_add((const char *)authtypes, sizeof(authtypes), conn);
654   conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE;
655 
656   return 0;
657 }
658 
659 /** Creates an Extended ORPort identifier for <b>conn</b> and deposits
660  *  it into the global list of identifiers. */
661 void
connection_or_set_ext_or_identifier(or_connection_t * conn)662 connection_or_set_ext_or_identifier(or_connection_t *conn)
663 {
664   char random_id[EXT_OR_CONN_ID_LEN];
665 
666   if (!conn->ext_or_conn_id)
667     conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN);
668 
669   memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN);
670 }
671 
672 /** Free any leftover allocated memory of the ext_orport.c subsystem. */
673 void
ext_orport_free_all(void)674 ext_orport_free_all(void)
675 {
676   if (ext_or_auth_cookie) /* Free the auth cookie */
677     tor_free(ext_or_auth_cookie);
678 }
679