hgot07 Hotspot Blog

主に無線LANや認証連携などの技術についてまとめるブログです。ネコは見る専。

FreeRADIUSで安全・簡単にEAP-TLSを使えるようにするためのメモ

個人利用ばかりではなく、他人にも安全・簡単にEAP-TLSを使ってもらえることを目指します。

つまり、公衆無線LANとか、学校の無線LANとか、そういうものです。

EAP-TLSの何が面倒くさいって、
自分で決めなければならない事項が多い
ことでしょう。設定そのものよりも、自分で考えることの方が、何倍も面倒くさいものです_('、3」∠)_

考えることをなるべく放棄できるように、設定の勘所をメモしていきます。

まずは、お奨め方針をざっくりと一覧にしてみます。その後に詳しい説明を書いていきます。

  • とりあえずFreeRADIUSでEAP-TTLSを動かしてみればよい。あとは、クライアント認証のための証明書チェーンを仕込むだけでEAP-TLSに対応できる。
  • サーバ認証を省略してはいけない。
  • サーバ認証にはパブリックCAから発行されたサーバ証明書を使うのが無難。
  • ルートCA証明書を端末に追加する操作を利用者に行わせるのは避ける。
  • サーバ認証にはLet's Encryptの証明書を使うこともできる (もちろん他のものでもよい)
  • 端末側の設定は、必ずサーバ証明書ドメイン (CNやSAN)をチェックするようにする (やらないと危険)
  • クライアント認証にはプライベートCAを使う。パブリックCAを使うのは危険。
  • CA構築や証明書の発行の仕方が分からないなら、FreeRADIUSの certs/Makefile を参考にすればよい。
  • クライアント証明書はRSAではなくECCを使って小さいものにする (UDP fragmentationの影響を受けにくくなる)
  • Wi-Fiプロファイルを使った自動設定を使うようにして、利用者に細かい設定を手入力させるのを避ける (利便性を高めて、設定ミスを減らせる)

 

FreeRADIUSのEAP-TLSの設定

FreeRADIUSの設定の大部分はEAP-TTLSと一緒なので、とりあえずEAP-TTLSを動かしてみればよいです。例えば、このWikiのような感じ。ただし、サーバ証明書については十分な説明がないので、本記事の方を参考にしてください。

meatwiki.nii.ac.jp

EAP-TLSの設定についても、先人たちが参考になる文書を残してくれているので、参考になるでしょう。ただし、いきなり読んでも分からないところがあると思うので、後の章を読んでから読み直した方がよいと思います

blog.yamano.dev

qiita.com

www.fumibu.com

サーバ認証の設定

設定箇所

EAP-TTLS と共通です。以下、FreeRADIUSの設定ファイルが置かれている場所 (例えば /etc/raddb)を起点として、ファイル名を示していきます。

EAP-TTLSやPEAPEAP-TLSでは、サーバ認証が必須ですEAP-TTLSやPEAPでサーバ認証を省略すると、偽基地局に誘導されてパスワードが解析される危険性があります

※ 最近の端末では、EAP-TTLSでサーバ認証を省略できないようになっています。

mods-enabled/eaptls-config tls-common{ } セクションの中で、次の項目にサーバ証明書を指定します。

  • private_key_password
  • private_key_file
  • certificate_file

private_key_password には、サーバ証明書を取得するときに指定したパスフレーズを設定します。Let's Encryptの証明書を使う場合は空にします。

private_key_file には、サーバ証明書と対になる秘密鍵のファイルを指定します。Let's Encryptの場合は privkey.pem を指定します。

certificate_file には、サーバ証明書のファイルを指定します。中間証明書がある場合は、ルートCA証明書に到達するのに必要なものをすべて、そのファイルに含める必要があります。PEM形式の証明書をcatコマンドで連結すればよいです。

$ cat server.pem ica1.pem ica2.pem > server-chain.pem

ただし、ルートCA証明書は入れないようにします。Let's Encryptの場合は、fullchain.pem を指定することになります。

なぜ certificate_file に中間証明書を含めるかというと、端末は一般にルートCA証明書しか持っていなくて、サーバ証明書だけでは検証できないからです。サーバ証明書に署名した中間証明書は、CAによって時々変更されることがあります。

 

ca_file や ca_path はサーバ証明書のルートCA証明書を指定する項目ではありません!

参考:

hgot07.hatenablog.com

ところで、サーバ証明書はどこから?

 

パブリックCAから取得したサーバ証明書を使うのがお奨め

公衆無線LANや、キャンパス無線LANでは、これがお奨めです。

端末にプリインストールされているCA証明書ストアを使ってサーバ認証ができるようになるので、利用者がCA証明書をインストールする手間が無くなります (重要!)。

ただし、端末側で、ドメイン名 (証明書のCNに対応) のチェックを必ず有効にする必要があります

 

Let's Encryptの証明書でも大丈夫です。有効期限が3か月しかないので、自動更新のスクリプトの中でFreeRADIUSも再起動するように仕込んでおきましょう。

hgot07.hatenablog.com

 

プライベートCAの証明書ではダメなのか

ダメというわけではありませんが、企業や学校などで、MDM (Mobile Device Management) でガチガチに設定できる用途でもなければ、不便な上に、安全性にも懸念があります。

最近のOSは、セキュリティ対策のために、ルートCA証明書のインストールを容易にできないようになってきています。他人に安易にインストール操作をさせない方がよいでしょう。

一応、certs ディレクトリの中で自動的にダミーのサーバ証明書が作られるので、certs/Makefile を参考に certs/ca.cnf と certs/server.cnf を自分用に変更すれば、そのディレクトリがプライベートCAになります。

 

端末側のサーバ認証の設定

サーバ認証を無効にしてはいけません!

パブリックCAの証明書を使う場合は、端末側の「CA証明書」の設定は「システム証明書を使用」にします。

Android 11以降には「証明書のステータスをリクエストする」という項目があって、分かりにくいのですが、サーバ証明書が期限切れや無効化されていないかを確認するための機能です。他のネットワーク接続手段がないとこの検証はできないので、「証明書のステータスをリクエストする」を選んでおくのが無難です。

サーバ認証において、ドメイン名のチェックは必須です。ドメイン名を入力する項目があるので、サーバ証明書の CN や SAN とマッチするものを設定します。

 

クライアント認証の設定

プライベートCAを使う

もしパブリックCAから発行された証明書をクライアント認証に使用すると、同じCAを使う第三者の証明書でも certification path validation が成功する、つまり、認証が通ってしまうことになります。クライアント証明書の中身を検証するロジックを追加することも考えられますが、そもそも、偽造されないようなデータを用意しなければならないので本末転倒感があります。

FreeRADIUSでは、mods-enabled/eaptls-config tls-common{ } セクションの中で、ca_file または ca_path に "クライアント認証用の" ルートCA証明書を含めます

あえて「含める」と書きましたが、複数のルートCA証明書を指定することができるためです。つまり、新しく別のCAを立てても、発行済みのクライアント証明書を殺すことなく、新旧両方のCAの認証を受け入れることができます。

もし中間証明書がある場合は、それらも ca_file または ca_path に含めます。クライアント認証では、端末はクライアント証明書のみを持ち、中間証明書を持つ必要はありません。

 

プライベートCAの立て方

certs/Makefile を見ると、どのようにCAを構築しているのか、openssl のコマンドとともに理解できるでしょう。ここはちょっと面倒ですが、opensslとおともだちになる必要があります。

デフォルトのCA証明書は有効期限が短く、パスフレーズが全世界で共有されています (だめ)。まずは certs/ca.cnf を編集して、自分の環境に合わせる必要があります。冒頭に貼った先人の記事が参考になるでしょう。

デフォルトでは2048 bitのRSAのCA証明書が作成されますが、不安ならビット数を増やせばよいでしょう。例えば4096に。

 

クライアント証明書はECCで小さく作るのがお奨め

RADIUSの通信では、標準でポート 1812/udp (authentication), 1813/udp (accounting) が使われます。ローミング環境で EAP-TLS を使い、素のRADIUSパケットをインターネットに流すと、ローミング先での認証ができない、または、不安定になることがあります。例えば、ある場所では安定して認証が通るのに、別の場所では通らないといった現象に見舞われることがあります。

EAP-TLS でこのような問題が発生する原因の一つとして、UDP fragmentation の影響が知られています。UDP fragmentation の影響を受けにくくするために、RADIUSパケットを小さくするというワークアラウンドがあります。具体的には、小さなクライアント証明書を使えばよいということで、RSAではなくECC (楕円曲線暗号)の証明書を使います。

FreeRADIUSに付属のデモ用CAでは、RSA 2048 bit のクライアント証明書が作成されるようになっています。certs/Makefile を覗くと、このようになっています。

client.csr client.key: client.cnf
        $(OPENSSL) req -new  -out client.csr -keyout client.key -config ./client.cnf
        chmod g+r client.key

この部分を、以下のように書き換えます。

client.csr client.key: client.cnf client-csr.cnf
        $(OPENSSL) ecparam -name secp384r1 -genkey -out client.key
        $(OPENSSL) req -new -out client.csr -key client.key -config ./client-csr.cnf
        chmod g+r client.key

新しく client-csr.cnf というファイルを作ります。中身は以下のようにしますが、自分の環境に合わせて書き換えます。

[ req ]
prompt = no
distinguished_name = client
req_extensions = v3_req
string_mask = utf8only

[ client ]
countryName = FR
stateOrProvinceName = Radius
localityName = Somewhere
organizationName = Example Inc.
commonName = user@example.org

[ v3_req ]
subjectAltName          = @alt_names

[ alt_names ]
email.1 = user@example.org

RSA 2048 bitで作成された client.pem は約1,800バイトですが、ECC の secp384r1 では240バイトほど短くなります。鍵長はずっと短いものになります。

ECCの短い鍵

ECCの短い鍵

 

ちなみに、現在、UDPRADIUSパケットを流すことは望ましくないとされ、RADIUS/TLS (RadSec) などのトランスポートを使うように移行が進められています。UDP fragmentation の影響は回避できるでしょうが、そもそも RSA を使い続ける積極的な理由はないでしょう。

 

端末の設定

全般的な注意点

他人に使わせるなら、手作業での設定が必要な運用は避けましょう。

特に、ルートCA証明書のインストールはセキュリティ面でリスクのある行為なので、極力避けましょう。

最近のOSなら、ウェブサイトからWi-Fiプロファイルをダウンロードして、Wi-Fi設定を容易に行うことのできる仕組みが組み込まれています。このような設定方法は、web-based provisioning と呼ばれています。以下のようなツールでプロファイルを生成するウェブサービスを作ることができます。eduroam用に見えますが、WPA2 Enterpriseの設定全般に使えます。

github.com

PKCS #12形式のファイルの作り方

以下、OSごとのWi-Fiプロファイルの扱いについて説明していくのですが、その前に PKCS #12 形式のファイルの作り方を説明します。

まず、最近ハマった件から
openssl 3系になってから、以前はうまく動いていたPKCS #12形式のファイルがOSで受け付けられなくなる現象が見られました。以下の記事が参考になるでしょう。要するに、-legacy オプションを付ければ解決できます。

mseeeen.msen.jp

certs/Makefile の client.p12: の所を見れば、openssl コマンドの使い方が分かります。パスフレーズ無しにするなら、-passout pass:"" のようにします。

 

Android

Androidでは、PPS MO (Per-Provider Subscription - Mobile Object) を使った web-based provisioning が使えるのですが、これはPasspoint専用なので、Passpointを使わないWPA2 Enterpriseでは利用できません。PPS MOの代わりに、.eap-config 形式のプロファイルと geteduroam というアプリを使うことで、設定を自動化できます。このアプリは、eduroam でなくてもWPA2 Enterprise一般に使うことができます。

クライアント証明書と秘密鍵は、パスフレーズ無しPKCS #12 形式で端末に読み込ませる必要があります。

 

macOS, iOS, iPadOS

Apple Configurator などで使われる .mobileconfig 形式に従ってWi-Fiプロファイルを作ると、これを読み込ませるだけでWi-Fi設定が済みます。

クライアント証明書と秘密鍵は、パスフレーズ付きPKCS #12 形式で端末に読み込ませる必要があります。

 

Windows 10, Windows 11

Windowsでは ms-settings: URI スキームを用いて、ウェブからWi-Fi設定ができるのですが、執筆時点ではこの方法が EAP-TTLS 専用で、EAP-TLS が使えません。

Androidと同じ、.eap-config 形式のプロファイルと geteduroam が使えます。クライアント証明書と秘密鍵は、パスフレーズ無しPKCS #12 形式です。

もし手動設定のためにクライアント証明書をWindowsにロードする場合は、パスフレーズ付きPKCS #12 形式のファイルが必要です。

 

Chrome OS

ONC (Open Network Configuration) 形式のファイルを作ります。クライアント証明書と秘密鍵は、パスフレーズ無しPKCS #12 形式で埋め込んでおきます。ファイルの作り方は、eduroamProvisioningTools のコードが参考になるでしょう。

ChromeブラウザのURL欄に chrome://network と入力すると、"Import ONC File" という設定項目があります (分かりにくい!)。ここで ONC 形式のファイルを読み込ませると、Wi-Fi設定が済みます。

 

 

とりあえず、おしまい。思い出したら逐次追記。