v3でクライアント認証を使う

Onion Services v3でクライアント認証を使う必要があったので、その時の色々をまとめたメモ。
前よりも面倒くさくなっていたので手順とか。

クライアント認証の導入について

Torでクライアント認証をしたい。
前はtorrcに設定を記入したら勝手によしなにしてくれた(ような記憶がある)が、v3はキーの生成を手動で行わなければならなそう。

とりあえずhttps://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txtを読みながらやってみる。 サーバサイドでの設定とクライアントサイドでの設定に別れていたので別個で。

サーバサイド

A hidden service that wants to enable client authorization, needs topopulate the "authorized_clients/" directory of its HiddenServiceDirdirectory with the ".auth" files of its authorized clients.

hidden_service/authorized_clients/.authファイルを置く必要がありそう。

When Tor starts up with a configured onion service, Tor checks its/authorized_clients/ directory for ".auth" files, and ifany recognized and parseable such files are found, then clientauthorization becomes activated for that service.

.authファイルが存在したら自動的にクライアント認証が有効になるらしい。

For the "descriptor" authentication type, the ".auth" file MUST containthe x25519 public key of that client. Here is a suggested file format:
<auth-type>:<key-type>:<base32-encoded-public-key>

.authは以下のような形式で書かれている必要がある。

 descriptor:x25519:<base32-encoded-public-key>

Tor SHOULD ignore lines it does not recognize.
Tor SHOULD ignore files that don't use the ".auth" suffix.

.authでないファイルや、パースできないファイルは無視される。(should)

クライアントサイド

A client who wants to register client authorization data for onion services needs to add the following line to their torrc to indicate the directory which hosts ".auth_private" files containing client-side credentials for onion services:
ClientOnionAuthDir

サーバ側に置く.authと対になる.auth_privateを<DIR>に置き、その<DIR>の場所を以下のような感じでtorrcに書く必要がある。

ClientOnionAuthDir <DIR>

The <DIR> contains a file with the suffix ".auth_private" for each onion service the client is authorized with. Tor should scan the directory for ".auth_private" files to find which onion services require client authorization from this client. For the "descriptor" auth-type, a ".auth_private" file contains the private x25519 key:
<onion-address>:descriptor:x25519:<base32-encoded-privkey>

.auth_privateはx25519の秘密鍵を含んだ以下のようなフォーマット。

<onion-address>:descriptor:x25519:<base32-encoded-privkey>

The keypair used for client authorization is created by a third party tool for which the public key needs to be transferred to the service operator in a secure out-of-band way. The third party tool SHOULD add appropriate headers to the private key file to ensure that users won't accidentally give out their private key.

サードパーティのツールでキーペアを作成する。それをセキュアなoobで渡す。

やる

やるべきことがわかったので、やる。

手順としては、

  1. クライアント側でx25519のキーペアを作成する
  2. キーをいい感じに整形する
  3. toorrcに鍵の場所を知らせる(クライアント)
  4. セキュアなoobでpubキーをサーバに渡す
  5. キーを/var/lib/tor/hidden_service/authorized_clientsに置く

でできそう。

キーペアの作成

まずはx25519のキーペアを作成する。

openssl genpkey -algorithm x25519 -out private.pem
openssl pkey -in private-key.pem -pubout -outform PEM -out public.pem

pemはbase64でデコードされてしまっているので、base32にするために一度デコードする。

cat private.pem | grep -v " PRIVATE KEY" | base64 -d | tail --bytes 32 >> raw.auth_private

rawな鍵をbase32でエンコードする。

cat raw.auth_private | base32 | sed -e "s/=//g" > base32ed.auth_private

接続先のホスト名/auth-type/key-typeを結合する。

echo -n "{{HOSTNAME}}:descriptor:x25519:" | cat - base32ed.auth_private > somebody_hs1.auth_private

pubキーも同様に作成する。

cat public.pem | \
    grep -v " PUBLIC KEY" | \
    base64 -d | \
    tail --bytes 32 > raw.auth
    cat raw.auth | \
    base32 | \
    sed -e "s/=//g" > base32ed.auth

auth-typeとkey-typeを結合する。

echo -n "descriptor:x25519:" | cat - base32ed.auth > somebody.auth

※tailで下32バイトを取り出してるのはx25519の仕様のため。https://tools.ietf.org/html/rfc7748

クライアント側での処理

先程生成した.auth_privateファイルを`/var/lib/tor/cliet_keys'あたりに置く(任意の場所で大丈夫なはず)。
そして、torrcに以下の行を追加する。

ClientOnionAuthDir /var/lib/tor/client_keys

一応念の為に書いておくと、tor browserを使用する場合は、TorBrowser/Data/Tor/torrcが使われるので、そこに追加。 変更後サービスの再起動。

sudo systemctl restart tor

サーバ側での処理

サーバ側に公開鍵を渡す。
渡された公開鍵は/var/lib/tor/hidden_service/authorrized_clientsに置く。
その後、Torの再起動。

sudo systemctl restart tor

おわり

Webサーバを使用している場合、認証されているクライアントからアクセスするとアクセスできるが、認証されていないクライアントからアクセスするとアクセスできないようになっているはず。

他の機能やネットワークフォレンジックっぽいことも書こうとしていたが、圧倒的怠惰によりこれだけの内容になってしまった。次書く機会があったら多分それをやる。 あと、間違えて一度ifdownしてしまってからなぜかAppArmorに引っかかるようになってしまったのが謎。すぐに解決しなかったから一時的に無効化してしまった(駄目)。