2010/02/17

Debian lennyでのhostapdとfreeradiusによるEAP-TLS環境の構築

AlixではXG-601を使って無線LAN APを構築していますが、stable系はドライバ未対応が原因で使えないため、開発版のhostapd-0.7.1を使っています。 いままではWPA-PSKを使った共有鍵方式で運用してきましたが、今回はEAP-TLSを試す事にします。

EAP-TLSはユーザ毎に認証用ファイルを配布する事ができるようになります。 誰がネットワークに接続したのか特定する必要がある環境ではとても便利な仕組みです。 共通鍵を使った環境では、鍵情報の流出+MACアドレス詐称が行なわれた場合、どの端末がネットワークに接続しているのか、どの経路で情報が漏洩したのか把握する事ができません。

公開鍵暗号化方式は、概念はとてもシンプルですが、使うまでの手順が面倒そうなので、あまり使われていないのではないでしょうか。 最近は市販されている家庭用無線LANルータにもRADIUS設定ができるものが多いので、ローカルなCA局とfreeradiusの運用から始めても良いかもしれません。

試行錯誤したところhostapd内蔵のRADIUS機能がどうしても使えなかったため、freeradiusを稼働させました。 debパッケージから構成できれば楽だったのですが、freeradiusのdebian lennyのパッケージでは、libsslライブラリとリンクされていないため、パッケージのビルドも行なっています。 詳細な手順はWPA2 + FreeRADIUS + EAP-TLSを確認してください。

参考にした文書、サイト

目次

作業全体の流れ

EAP-TLSを稼働させるまでの流れは、参考にした上記リンク先に従って進めています。 リンク先に書かれている事は省略していますが、気になったところや判りずらいところを補足する形で書きたいと思います。

  • hostapd-0.7.1のコンパイル
  • freeradiusパッケージの作成 & インストール
  • hostapd及びfreeradiusの設定
  • Windows Vistaからの接続確認

hostapd-0.7.1のコンパイル

本家からtarアーカイブを取得して、適当な場所にファイルを展開します。 configureスクリプトは附属していないので、次の手順で.configファイルを準備してコンパイルしましょう。

いまどきconfigureを使わずに.configファイルなんてlinux kernelのコンパイルみたいですね。

$ cd hostapd-0.7.1/hostapd/
$ cp defconfig .config
$ make
.configファイル

現状使っているhostapdをコンパイルした時の設定ファイルから、コメントと空行を除いたものは次のようになります。

.configファイルからコメントと空行を除いた中身

CONFIG_DRIVER_NL80211=y
CONFIG_EAP=y
CONFIG_EAP_TLS=y
CONFIG_IPV6=y

freeradiusパッケージの作成 & インストール

標準的にapt-getで導入できるfreeradiusではEAP-TLSが使えないので、設定を少し変更してパッケージを独自に作成する必要があります。

手順は参考にしたサイトにある通りですが、EAP-TLS以外は必要ないので、"--with-rlm_eap_tls"と"--with-openssl"の2個所だけを変更しました。 debian/ruleファイルの差分は次のようになっています。

debian/ruleファイルの差分

--- debian/rules.old	2010-02-15 20:17:09.000000000 +0900
+++ debian/rules	2010-02-15 20:16:36.000000000 +0900
@@ -80,14 +80,14 @@
 		--with-large-files --with-udpfromto --with-edir \
 		--enable-developer \
 		--config-cache \
-		--without-rlm_eap_tls \
+		--with-rlm_eap_tls \
 		--without-rlm_eap_ttls \
 		--without-rlm_eap_peap \
 		--without-rlm_eap_tnc \
 		--without-rlm_otp \
 		--with-rlm_sql_postgresql_lib_dir=`pg_config --libdir` \
 		--with-rlm_sql_postgresql_include_dir=`pg_config --includedir` \
-		--without-openssl \
+		--with-openssl \
 		--without-rlm_eap_ikev2 \
 		--without-rlm_sql_oracle \
 		--without-rlm_sql_unixodbc \
@@ -176,12 +176,12 @@
 	dh_strip -a --dbg-package=freeradius-dbg
 
 	dh_makeshlibs -a -n
-	for pkg in ${pkgs} ; do \
-	  if dh_shlibdeps -p $$pkg -- -O 2>/dev/null | grep -q libssl; then \
-	    echo "$$pkg links to openssl" ;\
-	    exit 1 ;\
-	  fi ;\
-	done
+#	for pkg in ${pkgs} ; do \
+#	  if dh_shlibdeps -p $$pkg -- -O 2>/dev/null | grep -q libssl; then \
+#	    echo "$$pkg links to openssl" ;\
+#	    exit 1 ;\
+#	  fi ;\
+#	done
 	dh_shlibdeps
 
 binary-common:

あとは一般ユーザでパッケージ作成のコマンドを実行して、待つだけです。

$ dpkg-buildpackage -rfakeroot
freeradiusパッケージの導入

ひとつ上(..)のディレクトリにパッケージが作成されているので、これを導入します。

$ cd ..
$ sudo dpkg -i freeradius_2.0.4+dfsg-6_i386.deb
$ sudo dpkg -i libfreeradius2_2.0.4+dfsg-6_i386.deb
$ sudo dpkg -i freeradius-common_2.0.4+dfsg-6_all.deb

ここで事前にパッケージのfreeradiusを導入していなかったり、状況によっては/etc/freeradiusに正しく設定ファイルが配置されないようです。

dpkgを実行した直後の/etc/freeradiusの様子


acct_users.dpkg-new		    otp.conf.dpkg-new
attrs.access_reject.dpkg-new	    policy.conf.dpkg-new
...

どうも依存関係が十分ではなかったようで、他のパッケージを導入しようとしたタイミングで気がつきました。

他のパッケージを導入する際に表示されたメッセージ

The following packages have unmet dependencies:
  freeradius: Depends: libperl5.10 (>= 5.10.0) but it is not going to be installed
              Depends: libsnmp15 (>= 5.4.1~dfsg) but it is not going to be installed
              Recommends: freeradius-utils but it is not going to be installed
E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).

ここに書かれているようにapt-getを実行すれば、問題は解決します。

$ sudo apt-get -f install

予防策としては事前にopensslに対応していないリポジトリのfreeradiusを導入してから、コンパイルしたfreeradiusを導入するのが良いのかもしれません。

2010/03/06追記:
どうやら設定ファイルが正しく配置されない状況があるようなので、このセクションを追加しました。

dpkg --set-selectionsオプションについて

参考にしたサイトでは、自動的にapt-getでfreeradiusのパッケージが更新されてしまう事のないように各パッケージをholdにする手順が書かれています。

しかしこの中の一部の文字コードがASCIIではないために、コマンドの実行に失敗してしまいます。

エラー時の画面出力

$ echo “freeradius hold” | sudo dpkg --set-selections
dpkg: illegal package name at line 1: must start with an alphanumeric

バイトの並びをみると"0xe2 0x80 0x9c"と"..0x9d"になるので、HTMLでいうところの“(left double quotation mark)と”(right double quotation mark)のようです。

ユーロ圏では母国語用キーボードで、ASCIIではない事を意識せずにleft/right double quotation markを簡単に使えるのかもしれません。 実際のところechoコマンドでのquotationは、複数の空白を含めたい場合を除けば必要ありません。

$ echo freeradius hold | sudo dpkg --set-selections
$ echo libfreeradius2 hold | sudo dpkg --set-selections
$ echo freeradius-common hold | sudo dpkg --set-selections
間違ってmakeコマンドを実行してしまったら…

この手順通りに進めれば問題ないのですが、どこかのタイミングでmakeコマンドを打ってしまうとdpkg-buildpackage -rfakerootを実行してもパッケージが作成できなくなってしまいます。 やり直そうとしてmake distcleanとかは実行してはいけないルールのようです。

設定を少し変更してパッケージの作り直しをする時には、そのまま繰り返しdpkg-buildpackageコマンドを実行すればOKです。 どうしようもなくなったら、apt-get sourceからやり直しましょう。

freeradiusの起動

2010/02/17追記:
たまたまfreeradiusが起動しなかったと思ったら、どうもバグだと気がついたのでセクシュンを追加。

正しく設定ファイルを作成しても、現在のstableパッケージ(freeradius_2.0.4+dfsg-6)に含まれる/etc/init.d/freeradiusスクリプトからはfreeradiusは起動しません。

これはバグで/var/run/freeradiusディレクトリにfreeradユーザで書き込みができないからです。 起動スクリプトはこのディレクトリがない場合には作成して、適切な権限に設定してくれますが、このディレクトリはfreeradiusパッケージの管理下にあるため最初からroot権限で作成されてしまいます。

既にrootでのみ書き込みができるディレクトリが存在するため、ディレクトリの作成が行なわれず、後続の権限修正もまた行なわれないままになるという仕組みです。

このバグはfreeradius (2.1.7+dfsg-1)で修正されている模様です。 将来のstableパッケージでは問題は起きないでしょう。

$ sudo chown freerad:freerad /var/run/freeradius

hostapd及びfreeradiusの設定

今回の設定のポイントはTLS用の鍵ファイルを作成するところで、clientAuthserverAuthを指定します。 参考にしたサイトにはchallengeパスワードを設定するよう書かれていますが、EAPTLS.pdfでは言及されていません。

デフォルトのopenssl.cnfファイルにはreq_attributesセクションが定義されているので、おそらくこれが読み込まれているようにみえます。残念ながらドキュメントを追い掛けても、ここら辺の動きについての資料をみつける事ができませんでした。

作業の概要

今回は前回のApache2のSSL化で作成したCA局の鍵をそのまま使います。

ただ後続の作業で"--extfile"オプションを使うため設定ファイルを準備しました。 これはopenssl.cnfに含める事はできないため、別ファイルである事が必要です。ファイル名や配置場所は任意で構いません。

demoCA/xpextensionsファイル

[xpclient_ext]
extendedKeyUsage=1.3.6.1.5.5.7.3.2

[xpserver_ext]
extendedKeyUsage=1.3.6.1.5.5.7.3.1

今回は同様の内容を持つ、次のファイルを使用しました。

demoCA/xpextensionsファイル ver.2

[xpclient_ext]
extendedKeyUsage=clientAuth

[xpserver_ext]
extendedKeyUsage=serverAuth

どちらのファイルを使っても、問題なく動きました。

server用鍵の生成

このステップは基本的にapache2のSSL化の時と同じですが、前回使用したコマンドラインの後ろにextensions関連のオプションを追加したところエラーになってしまいました。

エラーになる実行例

$ openssl ca -policy policy_anything -out newcert.pem -infiles newreq.pem -extensions xpserver_ext -extfile demoCA/xpextensions

今回は次の手順で鍵ファイルを作成しました。

$ openssl req -new -nodes -keyout newkey.pem -out newreq.pem -days 365
$ openssl ca -policy policy_anything -out newcert.pem -extensions xpserver_ext -extfile demoCA/xpextensions -infiles newreq.pem

Extended Key Usageの追加を確認する

        X509v3 extensions:
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
Certificate is to be certified until Feb 16 23:14:16 2011 GMT (365 days)
Sign the certificate? [y/n]:y
...

これで、サーバ用のnewkey.pem(秘密鍵)とnewcert.pem(公開鍵)のペアが作成できているはずです。 別のディレクトリを作成して鍵ファイルを保存します。

$ mkdir wireless_server_keys
$ mv newcert.pem newkey.pem wireless_server_keys/
$ cp demoCA/cacert.pem wireless_server_keys/

2010/03/06追記:
中間CAを使う時にはfreeradiusに指定するcacert.pemファイルは1つなので、親CAと中間CAのpemファイルを連結します。
$ cat ../demoCA/cacert.pem demoCA/cacert.pem > wireless_server_keys/cacert.pem

CN(CommonName)にはローカルのDNSサーバに登録されているFQDNを指定しました。

ここまでの作業が無事に終ったら、秘密鍵(newkey.pem)に繋がるnewreq.pemファイルは削除しておきます。

$ rm newreq.pem
client用の鍵生成

手順自体は同じですが、Windowsでクライアント用の鍵ファイルを読み込むためにpkcs12形式のファイルも作成しておきます。 参考にした手順では、この時に"-clcerts"オプションを指定してCA局の公開鍵を別経路で取り込むようにしています。

セキュリティ的にはより良い方法ですし、もし社内や閉じられたコミュニティ向けのローカルなCA局を運用するのであれば、別経路でのCA局公開鍵の配布は必須とは重います。 ここではpkcs12にCA局の情報も入れています。

$ openssl req -new -nodes -keyout newkey.pem -out newreq.pem -days 365
$ openssl ca -policy policy_anything -out newcert.pem -extensions xpclient_ext -extfile demoCA/xpextensions -infiles newreq.pem 
$ openssl pkcs12 -in newcert.pem -inkey newkey.pem -certfile ./demoCA/cacert.pem -out newcert.p12 -export -name "My Certificate"

ここでのCNにはメールアドレスを入力しました。 社員番号のようなユニークなキーがあれば、それでも良いと思います。

2番目のコマンドで署名をする時には、次のようなExtended Key Usageが付与されているか確認します。 また最後のコマンドでnewcert.p12ファイルを作成する時には、任意のパスワードを付けます。 CA局のパスワードとは違うものにするのが良いでしょう。

Extended Key Usageの追加を確認する

        X509v3 extensions:
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication
Certificate is to be certified until Feb 16 23:26:17 2011 GMT (365 days)
Sign the certificate? [y/n]:y
...

作成した鍵ファイルを別ディレクトリに保存しておきます。

$ mkdir wireless_client_keys
$ mv newcert.pem newkey.pem newcert.p12 wireless_client_keys/
$ rm newreq.pem

freeradiusサーバへの鍵ファイルの配布

TLS-EAPに対応したfreeradiusが既に導入されている事が必要です。 このfreeradiusが稼働するサーバにscpなどで鍵ファイルのディレクトリ全体をコピーしておきます。

$ scp -r wireless_server_keys 192.168.10.10:

freeradiusが稼働するサーバの/etc/freeradius/certs以下にファイルを保存していきます。

$ sudo cp wireless_server_keys/cacert.pem /etc/freeradius/certs
$ sudo cp wireless_server_keys/newkey.pem /etc/freeradius/certs
$ sudo cp wireless_server_keys/newcert.pem /etc/freeradius/certs

さらに参考にしたサイトの例に従って"dh"ファイルや"random"ファイルを作成します。 dhファイルの作成はalixには重い作業なので、より高速なCPUを積んだマシンで作成するのがよいでしょう。

$ openssl dhparam -5 -out dh1024.pem 1024
$ sudo cp dh1024.pem /etc/freeradius/certs

randomファイルはalix上で作成します。

$ sudo dd if=/dev/urandom of=/etc/freeradius/certs/random count=2

2010/03/06追記:
参考にした手順で作成した"dh"ファイルは512bitだったので、1024bitで作成しました。 2048bitでも良いのですが、ファイル作成に時間がかかるのと、そこまでは またrandomファイルの作成手順についても載せています。
この作業の結果、eap.confの中でのdhファイル名を変更(dh->dh1024.pem)しました。

またeap.confは次のようになりました。

/etc/freeradius/eap.confファイル

eap {
        default_eap_type = tls
        timer_expire     = 60
        ignore_unknown_eap_types = no
        cisco_accounting_username_bug = no         

        tls {
                certdir = ${confdir}/certs
                cadir = ${confdir}/certs
                private_key_password = 
                private_key_file = ${certdir}/newkey.pem
                certificate_file = ${certdir}/newcert.pem
                CA_file = ${cadir}/cacert.pem
                dh_file = ${certdir}/dh1024.pem
                random_file = ${certdir}/random
                fragment_size = 1024
                include_length = yes
                check_cert_cn = %{User-Name}
                cipher_list = "DEFAULT"
        }
}

次にclient.confファイルを編集します。 テストのためにclient localhostの定義がありますが、secretは適当に変更しておきます。 そして最後にhostapdが走るホストのIPアドレスかFQDNを定義します。

client 192.168.1.x {
        secret = 6a_abp1z75_5e318
        shortname = wireless-ap
}

パスワードは次のようなコマンドで適当な文字列を表示させて使っています。 このままだと0-9,a-fの範囲しか使わないので数字の'0'は適当な記号に、'f'はa-fの範囲外の適当なアルファベットに手で置き換えるといったことをしています。

$ dd if=/dev/urandom bs=16 count=1 | od -t x8

2010/03/06追記:
あっちこっち参照するのは面倒なのでclient.confの編集とパスワードの適当な選び方について追加しました。

サーバ用のnewreq.pemファイルを生成する段階で、"-nodes"オプションを指定してパスワードをつけていません。 このためprivate_key_passwordには何も指定していないところが、参考にした手順と違うところです。

hostapdの設定について

hostapd内蔵のradius機能を使わないためにeap_server=0を指定するか、コメントアウトする事が必要だろうと思います。 ただ"WPA/IEEE 802.11i configuration"セクションにあるオプションを有効にしたところ、PTK Rekeyingのタイミングで接続が切れるようになってしまいました。

できるだけデフォルト設定のように使って、wpa_ptk_rekeyなどのオプションは指定しないのが良さそうです。 いまのところhostapd.confは次のようになっています。

コメント、空行を除いたhostapd.conf

interface=wlan0
bridge=br0
driver=nl80211
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=0
dump_file=/tmp/hostapd.dump
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0
ssid=ALIXHOMEAP4TEST
country_code=JP
ieee80211d=1
hw_mode=g
channel=9
beacon_int=100
dtim_period=2
max_num_sta=255
rts_threshold=2347
fragm_threshold=2346
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wmm_enabled=1
wmm_ac_bk_cwmin=4
wmm_ac_bk_cwmax=10
wmm_ac_bk_aifs=7
wmm_ac_bk_txop_limit=0
wmm_ac_bk_acm=0
wmm_ac_be_aifs=3
wmm_ac_be_cwmin=4
wmm_ac_be_cwmax=10
wmm_ac_be_txop_limit=0
wmm_ac_be_acm=0
wmm_ac_vi_aifs=2
wmm_ac_vi_cwmin=3
wmm_ac_vi_cwmax=4
wmm_ac_vi_txop_limit=94
wmm_ac_vi_acm=0
wmm_ac_vo_aifs=2
wmm_ac_vo_cwmin=2
wmm_ac_vo_cwmax=3
wmm_ac_vo_txop_limit=47
wmm_ac_vo_acm=0
ap_max_inactivity=300
max_listen_interval=100
ieee8021x=1
eapol_version=1
eapol_key_index_workaround=1
eap_reauth_period=1800
use_pae_group_addr=0
eap_server=0
own_ip_addr=192.168.10.10
nas_identifier=alix.example.org
auth_server_addr=192.168.10.10
auth_server_port=1812
auth_server_shared_secret=xxxxxxxxxxxxxxxxxx
acct_server_addr=192.168.10.10
acct_server_port=1813
acct_server_shared_secret=xxxxxxxxxxxxxxxxxx
radius_retry_primary_interval=600
radius_acct_interim_interval=1200
dynamic_vlan=0
wpa=1
wpa_key_mgmt=WPA-EAP
wpa_pairwise=TKIP

Windows Vistaからの接続確認

作成したnewcert.p12ファイルをUSBメモリなどでコピーし、このファイルをWindows上でダブルクリックするとインストールが始まります。 気をつけるところはデフォルトではどのCA局も信頼する対象になっていませんから、Access Pointのプロパティから信頼するCA局としてチェックを入れるところでしょうか。

ただ、wpa_ptk_rekeyをコメントアウトして、比較的安定して動いていると思いますが、WPA-PSKの時と比べると、まだ時々切断されている事があります。

さいごに

hostapdでEAP-TLSを実現するための方法をみると、CA局を専用に作らないとなのかなぁ、などいろいろ思いますが、なんとかApache2のSSL化で使ったdemoCA/cacert.pemが使えました。 ただ、ちゃんと動く環境を手に入れるまでは不確定な要素を排除するために、専用のdemoCA/cacert.pemを作る確実な手順を踏襲するのが良いとは思います。

いくつかの手順をみるとそれぞれの工夫がみて取れます。 EAPTLS.pdfではスクリプトが準備されていますが、内部を理解しないとちゃんと動かない、なんてことにもなりそうです。 TLS周りの作業は自分でスクリプト化するのは良い事ですが、人が作成したスクリプトは時間をかけても確実に各ステップを確認して、自分なりのスクリプトに編み直す事が必要そうです。

hostapdの内蔵TLSがうまく動いていないとか、未解決のままにしている事はありますが、ひとまずは目的を達成できたので情報を整理しておこうと思います。

0 件のコメント: