tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

commit 7ea0e041aec14f6d8c544be1d4d223b7648c5c61
parent 11542a3d04bb746e4d2ba83c3127f2e6b9292afc
Author: Nick Mathewson <nickm@torproject.org>
Date:   Tue,  4 Nov 2025 10:10:54 -0500

HTTP CONNECT: Warn on Proxy-Authorization in legacy format.

To avoid confusing with other apps, we want applications to
deliberately choose a format that indicates that they know they're using Tor
for isolation.  That's "Basic" auth, with username "tor" and
password chosen for isolation.

Diffstat:
Msrc/core/or/connection_edge.c | 35+++++++++++++++++++++++++++++++++++
Msrc/core/or/connection_edge.h | 1+
Msrc/test/test_proto_http.c | 27++++++++++++++++++++++++++-
3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c @@ -3049,6 +3049,37 @@ host_header_is_localhost(const char *host_value) return result; } +/** Return true if the Proxy-Authorization header present in 'auth' + * isn't using the "modern" format introduced by proposal 365, + * with "basic" auth and username "tor". */ +STATIC bool +using_old_proxy_auth(const char *auth) +{ + auth = eat_whitespace(auth); + if (strcasecmpstart(auth, "Basic ")) { + // Not Basic. + return true; + } + auth += strlen("Basic "); + auth = eat_whitespace(auth); + + ssize_t clen = base64_decode_maxsize(strlen(auth)) + 1; + char *credential = tor_malloc_zero(clen); + ssize_t n = base64_decode(credential, clen, auth, strlen(auth)); + if (n < 0 || BUG(n >= clen)) { + // not base64, or somehow too long. + tor_free(credential); + return true; + } + // nul-terminate. + credential[n] = 0; + + bool username_is_modern = ! strcmpstart(credential, "tor:"); + tor_free(credential); + + return ! username_is_modern; +} + /** Called on an HTTP CONNECT entry connection when some bytes have arrived, * but we have not yet received a full HTTP CONNECT request. Try to parse an * HTTP CONNECT request from the connection's inbuf. On success, set up the @@ -3144,6 +3175,10 @@ connection_ap_process_http_connect(entry_connection_t *conn) { char *authorization = http_get_header(headers, "Proxy-Authorization: "); if (authorization) { + if (using_old_proxy_auth(authorization)) { + log_warn(LD_GENERAL, "Proxy-Authorization header in legacy format. " + "With modern Tor, use Basic auth with username=tor."); + } socks->username = authorization; // steal reference socks->usernamelen = strlen(authorization); } diff --git a/src/core/or/connection_edge.h b/src/core/or/connection_edge.h @@ -310,6 +310,7 @@ STATIC void connection_half_edge_add(const edge_connection_t *conn, STATIC struct half_edge_t *connection_half_edge_find_stream_id( const smartlist_t *half_conns, streamid_t stream_id); +STATIC bool using_old_proxy_auth(const char *auth); #endif /* defined(CONNECTION_EDGE_PRIVATE) */ #endif /* !defined(TOR_CONNECTION_EDGE_H) */ diff --git a/src/test/test_proto_http.c b/src/test/test_proto_http.c @@ -6,11 +6,14 @@ * \brief Tests for our HTTP protocol parser code */ +#define CONNECTION_EDGE_PRIVATE + #include "core/or/or.h" #include "test/test.h" #include "lib/buf/buffers.h" #include "core/proto/proto_http.h" #include "test/log_test_helpers.h" +#include "core/or/connection_edge.h" #define S(str) str, sizeof(str)-1 @@ -203,11 +206,33 @@ test_proto_http_invalid(void *arg) teardown_capture_of_logs(); } +static void +test_proto_http_proxy_auth(void *arg) +{ + (void)arg; + + tt_assert(using_old_proxy_auth("")); + tt_assert(using_old_proxy_auth("Foo Bar")); + tt_assert(using_old_proxy_auth("Basicish Bar")); + tt_assert(using_old_proxy_auth("Basic")); + tt_assert(using_old_proxy_auth("Basic x")); + // encodes foo:bar + tt_assert(using_old_proxy_auth("Basic Zm9vOmJhcg==")); + // encodes torx:bar + tt_assert(using_old_proxy_auth("Basic dG9yeDpiYXI=")); + + // encodes tor:random + tt_assert(! using_old_proxy_auth("Basic dG9yOnJhbmRvbQ==")); + + done: + ; +} + struct testcase_t proto_http_tests[] = { { "peek", test_proto_http_peek, 0, NULL, NULL }, { "valid", test_proto_http_valid, 0, NULL, NULL }, { "invalid", test_proto_http_invalid, 0, NULL, NULL }, + { "proxyauth", test_proto_http_proxy_auth, 0, NULL, NULL }, END_OF_TESTCASES }; -