2.2.7. Client-side validation of onion addresses When a Tor client receives a prop224 onion address from the user, it MUST first validate the onion address before attempting to connect or fetch its descriptor. If the validation fails, the client MUST refuse to connect. As part of the address validation, Tor clients should check that the underlying ed25519 key does not have a torsion component. If Tor accepted ed25519 keys with torsion components, attackers could create multiple equivalent onion addresses for a single ed25519 key, which would map to the same service. We want to avoid that because it could lead to phishing attacks and surprising behaviors (e.g. imagine a browser plugin that blocks onion addresses, but could be bypassed using an equivalent onion address with a torsion component). The right way for clients to detect such fraudulent addresses (which should only occur malevolently and never naturally) is to extract the ed25519 public key from the onion address and multiply it by the ed25519 group order and ensure that the result is the ed25519 identity element. For more details, please see [TORSION-REFS].
Then a basic test consists in bringing the Onion Service online using the candidate keypair and accessing it using Tor, which validates keys according to the spec, on hs_address_is_valid() calling ed25519_validate_pubkey().
Then a basic test consists in bringing the Onion Service online using the candidate keypair and accessing it using Tor
The bin/test-keys script implemented on 67a96f37 does exactly that:
Sets a random nounce.
Launches a Tor process setting up an Onion Server with the desired keypair.
Waits for Tor to bootstrap.
Launches a simple webserver (based on netcat) which just serves the random nounce.
Try to fetch the Onion Service with torify curl.
Check if the Onion Service is available and if the offered nounce matches the expected value.
Usage
$ bin/test-keys usage: test-keys <pool> <candidate> [wait]Test an Onion Service keypair candidate mined in a pool pool: the mining pool to operate on candidate: which candidate in the pool to test wait: how many seconds to wait between service bootstrap and checking, defaults to 60Available pools: example.org$ bin/test-keys example.orgusage: test-keys <pool> <candidate> [wait]Test an Onion Service keypair candidate mined in a pool pool: the mining pool to operate on candidate: which candidate in the pool to test wait: how many seconds to wait between service bootstrap and checking, defaults to 60Available candidates in pool example.org: test35n4rit2dzagyzixi7kfktuzns3q464donfggtn5jhflqvwihrqd.onion testbldudyzs5zc4q35esi3e7rkf56mys6jt3dhbtg7epzcpw35zc4id.onion testk4ae7qr6nhlgahvyicxy7nsrmfmhigtdophufo3vumisvop2gryd.onion
Example invocation
./bin/test-keys example.org test35n4rit2dzagyzixi7kfktuzns3q464donfggtn5jhflqvwihrqd.onionLaunching a minimal web server listening on /srv/shared/pools/example.org/daemon/nc.socket...Launching the Tor daemon with test35n4rit2dzagyzixi7kfktuzns3q464donfggtn5jhflqvwihrqd.onion Onion Service listening on port 24245...Sleeping 60 seconds while the Onion Service is bootstrapped...May 16 16:55:10.864 [notice] Tor 0.4.5.10 running on Linux with Libevent 2.1.12-stable, OpenSSL 1.1.1n, Zlib 1.2.11, Liblzma 5.2.5, Libzstd 1.4.8 and Glibc 2.31 as libc.May 16 16:55:10.864 [notice] Tor can't help you if you use it wrong! Learn how to be safe at https://www.torproject.org/download/download#warningMay 16 16:55:10.864 [notice] Read configuration file "/etc/tor/torrc".May 16 16:55:10.000 [notice] Parsing GEOIP IPv4 file /usr/share/tor/geoip.May 16 16:55:10.000 [notice] Parsing GEOIP IPv6 file /usr/share/tor/geoip6.May 16 16:55:11.000 [notice] Bootstrapped 0% (starting): StartingMay 16 16:55:11.000 [notice] Starting with guard context "default"May 16 16:55:12.000 [notice] Bootstrapped 5% (conn): Connecting to a relayMay 16 16:55:12.000 [notice] Bootstrapped 10% (conn_done): Connected to a relayMay 16 16:55:12.000 [notice] Bootstrapped 14% (handshake): Handshaking with a relayMay 16 16:55:12.000 [notice] Bootstrapped 15% (handshake_done): Handshake with a relay doneMay 16 16:55:12.000 [notice] Bootstrapped 75% (enough_dirinfo): Loaded enough directory info to build circuitsMay 16 16:55:12.000 [notice] Bootstrapped 90% (ap_handshake_done): Handshake finished with a relay to build circuitsMay 16 16:55:12.000 [notice] Bootstrapped 95% (circuit_create): Establishing a Tor circuitMay 16 16:55:14.000 [notice] Bootstrapped 100% (done): DoneTrying to fetch the secret random value 8b498b54fa920ce69b4fb9e691e4654b4b685e29057e170c699d1dc520118ed7e2bc7eee5d1ab97015f948b14d6ce8c0808f5708a5fb1f17949f46bd9ed6273d from the Onion Service...Secret sharing matched, Onion Service candidate test35n4rit2dzagyzixi7kfktuzns3q464donfggtn5jhflqvwihrqd.onion validated!May 16 16:56:15.000 [notice] Catching signal TERM, exiting cleanly.
(Comment edited to reflect recent changes in test-keys usage and behavior)
Ideally, a better script could use the Tor control protocol and wait for the descriptor to be published before trying to access the Onion Service. That would be a requirement for some automated procedure, but here we're looking for simple and manual way to check the keys.
It can also lead to false negatives if running sequentially for the same Onion Service keys, due to the descriptors being published many times, some of those with past introduction points.