wren-linux / extras / tails-usb.sh
#!/bin/bash
# Tails on a USB stick. Tails is a whole operating system that runs from a USB
# stick, sends everything through Tor and forgets everything when you shut it
# down. This sets up a command, tails-usb, that:
# - finds the newest Tails in Tails' own release file, and downloads the USB
# image through Tor when Tor runs here (apt over Tor, remote access, the
# onion site), so your network can't see you fetch it; otherwise it asks
# before downloading directly;
# - uses the image only if its signature is the Tails signing key's (pinned
# in pins.sh, TAILS_FPR) and it is exactly the image the release file names
# for the newest version (so an older, signed Tails isn't slipped in);
# - keeps that verified copy in offline/tails (the newest only), checked again
# before every use, so the next stick needs no download;
# - lists only USB sticks, never the disk this system runs from, asks you to
# type the stick's name, writes Tails onto it, and reads it back to check;
# - says how to start and use it (docs/extras/tails-usb.md has more).
# Writing a stick erases everything on it, Persistent Storage included.
# Usage: bash tails-usb.sh set up tails-usb, and say how to use it
# bash tails-usb.sh --make make a stick (what tails-usb runs)
# bash tails-usb.sh --remove
# bash tails-usb.sh --manual the steps to make a stick by hand
# summary: Tails on a USB stick, downloaded and checked
# security: most
# category: systems
# status: bin:tails-usb
. "$(dirname -- "${BASH_SOURCE[0]}")/../lib.sh"
. "$WREN_DIR/lib/appimage.sh"
. "$WREN_DIR/lib/tails.sh"
. "$WREN_DIR/lib/usb-stick.sh"
if [ "${1:-}" = --manual ]; then print_manual; exit; fi
need_user
MIN_STICK=$((7500 * 1000 * 1000)) # Tails asks for 8 GB; sticks sold as 8 GB hold a little less
if [ "${1:-}" = --remove ]; then
remove_bin tails-usb
apt_purge torsocks
if [ -d "$TAILS_OFFLINE" ] && ask "Also delete the saved Tails image in $TAILS_OFFLINE?" n; then
rm -rf "$TAILS_OFFLINE"
note "Deleted."
fi
note "Sticks you made keep working; Tails updates itself."
exit
fi
setup() {
say "Installing what tails-usb needs"
# torsocks: the download through Tor; python3: reading Tails' release file
apt_install wget gpg python3 torsocks util-linux
install_bin tails-usb
}
# fetch URL FILE: through Tor when this computer runs it, else as decided below
VIA_TOR=false
fetch() {
if $VIA_TOR; then torsocks wget -q --show-progress -c -O "$2" "$1"; else wget -q --show-progress -c -O "$2" "$1"; fi
}
make_stick() {
local tmp line v url sha size img sig key i
tmp=$(mktemp -d)
# (its name now: tmp is this function's, gone by the time the script exits)
# shellcheck disable=SC2064
trap "rm -rf '$tmp'" EXIT
mkdir -p "$TAILS_OFFLINE"
say "How to download"
if systemctl is-active --quiet tor@default.service && command -v torsocks >/dev/null; then
VIA_TOR=true
note "Through Tor (the system tor service runs here): your network won't see you fetch Tails."
else
note "Tor doesn't run here, so your network would see you download Tails from tails.net"
note "(not what you do with it later). Set up apt over Tor first (wrenctl install apt-tor)"
note "to download through Tor instead."
ask "Download directly?" y || die "Nothing was downloaded."
fi
say "The newest Tails"
if fetch "$TAILS_LATEST_URL" "$tmp/latest.json" 2>/dev/null && line=$(tails_latest "$tmp/latest.json"); then
read -r v url sha size <<<"$line"
note "Tails $v ($((size / 1000000)) MB)"
echo "$line" >"$tmp/release"
else
# Offline: the saved copy, with the release details saved next to it
line=$(cat "$TAILS_OFFLINE"/tails-amd64-*.release 2>/dev/null | sort -V | tail -1)
[ -n "$line" ] || die "Couldn't read Tails' release file from tails.net, and no saved copy is here."
read -r v url sha size <<<"$line"
warn "Couldn't reach tails.net: using the saved Tails $v, which may not be the newest."
fi
img=$TAILS_OFFLINE/tails-amd64-$v.img
sig=$img.sig
key=$TAILS_OFFLINE/tails-signing.key
if [ -f "$img" ] && [ -f "$sig" ] && [ -f "$key" ] && tails_image_ok "$img" "$sig" "$key" "$sha" "$size" 2>/dev/null; then
note "Using the saved copy, checked again: $img"
else
say "Downloading Tails $v"
fetch "$TAILS_KEY_URL" "$key.part" && mv "$key.part" "$key" || die "Couldn't download the Tails signing key."
fetch "$TAILS_SIG_BASE/tails-amd64-$v.img.sig" "$sig" || die "Couldn't download the signature."
fetch "$url" "$img.part" || die "The download didn't finish; run tails-usb again to go on where it stopped."
say "Checking it"
if ! tails_image_ok "$img.part" "$sig" "$key" "$sha" "$size"; then
rm -f "$img.part" "$sig"
die "The download didn't pass the checks, so it was deleted."
fi
mv "$img.part" "$img"
[ ! -f "$tmp/release" ] || cp "$tmp/release" "$TAILS_OFFLINE/tails-amd64-$v.release"
# Keep only the newest
for i in "$TAILS_OFFLINE"/tails-amd64-*.img; do
[ "$i" = "$img" ] || rm -f "$i" "$i.sig" "${i%.img}.release"
done
note "Signed by the Tails signing key, and the image Tails' release file names: $img"
fi
stick_write "$img" "$MIN_STICK" "Tails $v"
note "Written and read back: the stick holds exactly the checked image."
cat <<EOF
Your Tails stick is ready. To use it:
1. Shut this computer down (or use another one), plug the stick in and
start it. Open the boot menu with the key your computer shows at start
(often F12, F9, F10, F11 or Esc; on a Mac hold Option) and pick the
USB stick. Tails starts with Secure Boot on most computers.
2. The Welcome Screen: pick your language and keyboard. You don't need
anything else to begin; an administration password is only for
installing extra software for that session.
3. Connect to Tor in the "Tor Connection" window. If your network blocks
Tor, or must not see that you use it, choose a bridge there.
4. Everything you do is forgotten when you shut down. To keep files, a
browser bookmark or Wi-Fi passwords, create the encrypted Persistent
Storage (Applications > Persistent Storage) with a long passphrase,
and keep in it only what you need.
5. When you're done, shut Tails down from the menu: it wipes the memory.
Tails updates itself when it is connected. If an update can't be done,
or the stick fails, run tails-usb again to make a fresh one (that erases
the stick, Persistent Storage included: back that up first).
Tails' own guide: https://tails.net/doc/
More: docs/extras/tails-usb.md in the Wren Linux folder.
EOF
}
case ${1:-} in
--make)
for c in wget gpg python3 lsblk; do command -v "$c" >/dev/null || die "$c is missing. Run: bash $WREN_DIR/extras/tails-usb.sh"; done
make_stick ;;
"")
setup
cat <<'EOF'
tails-usb is set up. To make a Tails stick:
1. Have a USB stick of 8 GB or more. Everything on it is erased.
2. Run in a terminal: tails-usb (or Super+d, then tails-usb)
3. It downloads the newest Tails (through Tor if Tor runs here, else it
asks first), checks its signature, and keeps the checked copy for the
next stick.
4. Plug the stick in when it asks, pick it from the list, and type its
name to confirm. It writes Tails and reads it back to check.
5. When it is done it says how to start the computer from the stick.
More: docs/extras/tails-usb.md in the Wren Linux folder.
EOF
pause_if_asked ;;
*) die "Usage: bash extras/tails-usb.sh [--make | --remove]" ;;
esac