#!/bin/bash ## Copyright (C) 2019 - 2023 ENCRYPTED SUPPORT LP ## See the file COPYING for copying conditions. ## usage: ## sudo virtport=80 hsport=80 hsname=hidden_service client=1 anon-auth-autogen #set -x set -e error_handler() { local exit_code="$?" echo "ERROR: exit_code: $exit_code | BASH_COMMAND: $BASH_COMMAND" exit 1 } trap error_handler ERR SCRIPTNAME="$(basename "$BASH_SOURCE")" if [ "$(id -u)" != "0" ]; then echo "ERROR: This must be run as root (sudo)!" echo "INFO: You can start $SCRIPTNAME by entering..." echo " sudo $SCRIPTNAME" exit 1 fi [ -n "$hsname" ] || hsname="hidden_service" [ -n "$hsport" ] || hsport=80 [ -n "$virtport" ] || virtport=80 [ -n "$hsversion" ] || hsversion=3 [ -n "$tor_autogen_root_folder" ] || tor_autogen_root_folder="/var/lib/tor_autogen" [ -n "$tor_autogen_hs_folder" ] || tor_autogen_hs_folder="/var/lib/tor_autogen/${hsname}" [ -n "$hsdir" ] || hsdir="/var/lib/tor/${hsname}" [ -n "$onion_url_file" ] || onion_url_file="${hsdir}/hostname" [ -n "$authorized_clients_folder" ] || authorized_clients_folder="${hsdir}/authorized_clients" [ -n "$torconfdir" ] || torconfdir="/usr/local/etc/torrc.d" [ -n "$torconffile" ] || torconffile="${torconfdir}/43_${hsname}_hs_autogen.conf" [ -n "$torunit" ] || torunit="tor@default" [ -n "$unitaction" ] || unitaction="reload" [ -n "$unitruntest" ] || unitruntest="is-active" [ -n "$unittool" ] || unittool="systemctl" [ -n "$unitcmd" ] || unitcmd="$unittool $unitaction $torunit" [ -n "$sleep_seconds_after_reload" ] || sleep_seconds_after_reload="5" [ -n "$unitruntestcmd" ] || unitruntestcmd="$unittool $unitruntest $torunit" [ -n "$tor_user" ] || tor_user="debian-tor" [ -n "$tor_group" ] || tor_group="debian-tor" [ -n "$client" ] || client="1" [ -n "$private_key_file" ] || private_key_file="${tor_autogen_hs_folder}/${client}_private_key.pem" [ -n "$public_key_file" ] || public_key_file="${tor_autogen_hs_folder}/${client}_public_key.pem" [ -n "$home_folder_auth_private_file" ] || home_folder_auth_private_file="/home/user/${client}.auth_private" [ -n "$auth_private_file" ] || auth_private_file="${tor_autogen_hs_folder}/${client}.auth_private" [ -n "$base_32_private" ] || base_32_private="${tor_autogen_hs_folder}/${client}_private_key.base32" [ -n "$base_32_public" ] || base_32_public="${tor_autogen_hs_folder}/${client}_public_key.base32" [ -n "$client_authorization_file_name" ] || client_authorization_file_name="${client}.auth" [ -n "$client_authorization_full_path" ] || client_authorization_full_path="${tor_autogen_hs_folder}/${client_authorization_file_name}" [ -n "$tor_user_sudo" ] || tor_user_sudo="sudo --non-interactive -u $tor_user" if [ "$ip" = "" ]; then if command -v qubesdb-read &>/dev/null ; then ip="$(qubesdb-read /qubes-ip)" else ip=10.152.152.11 fi fi which basez tail tr cat grep tee openssl mkdir chown cp sudo id groups "$unittool" sleep >/dev/null id "$tor_user" >/dev/null groups "$tor_group" >/dev/null if ! $unitruntestcmd &>/dev/null ; then echo "ERROR: Tor is not running. Start Tor first." exit 1 fi test -d "$torconfdir" rm -f "$torconffile" touch "$torconffile" echo "\ # This file is generated by: $0 # User configuration should go to /usr/local/etc/torrc.d/50_user.conf, not here. # However, deleting this file will be fine since a new plain file will be generated the next time you run $SCRIPTNAME HiddenServiceDir $hsdir HiddenServicePort ${virtport} ${ip}:${hsport} HiddenServiceVersion ${hsversion} " | tee "$torconffile" >/dev/null echo "INFO: Created torconffile '$torconffile'." echo "INFO: Reloading Tor." ## Reload Tor to so Tor will create onion_url_file. ## by default: ## systemctl reload tor@default $unitcmd echo "INFO: Giving Tor $sleep_seconds_after_reload seconds to create hidden service file." sleep "$sleep_seconds_after_reload" onion_url="$(cat "$onion_url_file")" onionname="$(echo "$onion_url" | LANG=C str_replace ".onion" "")" mkdir -p "$tor_autogen_root_folder" chown "${tor_user}:${tor_group}" "$tor_autogen_root_folder" $tor_user_sudo mkdir -p "$tor_autogen_hs_folder" pushd "$tor_autogen_hs_folder" >/dev/null ## Based on: ## https://tor.stackexchange.com/questions/19221/how-to-setup-client-authorization-for-v3-onion-services ## Using OpenSSL 1.1 or later, generate a new X25519 private key. ## This will produce a PEM-encoded private key file, private-key.pem $tor_user_sudo openssl genpkey -algorithm x25519 -out "$private_key_file" ## Using the newly generated private key file, generate a corresponding public key file, public-key.pem: $tor_user_sudo openssl pkey -in "$private_key_file" -pubout -outform PEM -out "$public_key_file" ## Now that you have both the private and public parts of your keypair, ## first convert the private part from its PEM-encoded format into a Base32 ## encoded string for use in your Tor client's .auth_private file: cat "$private_key_file" | \ grep -v " PRIVATE KEY" | \ basez --base64pem --decode | \ tail --bytes 32 | \ basez --base32 | \ tr -d '=' | \ $tor_user_sudo tee "$base_32_private" >/dev/null ## Visitors need to be provided with. echo -n "$onionname:descriptor:x25519:" | \ cat - "$base_32_private" | \ $tor_user_sudo tee "$auth_private_file" >/dev/null cat "$public_key_file" | \ grep -v " PUBLIC KEY" | \ basez --base64pem --decode | \ tail --bytes 32 | \ basez --base32 | \ tr -d '=' | \ $tor_user_sudo tee "$base_32_public" >/dev/null echo -n "descriptor:x25519:" | \ cat - "$base_32_public" | \ $tor_user_sudo tee "$client_authorization_full_path" >/dev/null $tor_user_sudo mkdir -p "$authorized_clients_folder" $tor_user_sudo cp "$client_authorization_full_path" "${authorized_clients_folder}/" echo "INFO: Installed \".auth\" file (public key) '$client_authorization_full_path' to '$client_authorization_full_path' to allow client '$client' to access hsname '$hsname' onion_url '$onion_url'." echo "INFO: Reloading Tor again to activate \".auth\" (public key) file for client '$client'." ## Reload Tor to so Tor will load client_authorization_full_path. ## by default: ## systemctl reload tor@default $unitcmd echo "INFO: You need to provide client '$client' with \".auth_private\" file (private key) '$auth_private_file'." echo "INFO: Visitors that use Whonix could store '$auth_private_file' in '$home_folder_auth_private_file' and then run 'sudo sourcefile=$home_folder_auth_private_file anon-server-to-client-install'."