本稿ではRADIUS protocolのAuthenticator header、Message-Authenticator attribute、それぞれの役割、計算方法、弊社ISE(Identity Services Engine)との関連を紹介します。
Authenticator headerはRequestor(Access-Requestの場合NAD)がResponder(Access-Challenge等の場合AAA server)からのpacketを特定のRequestに対してのものと確認するために使われます。
どのRADIUS packetにも含まれ16bytes長になります。
計算式は
Responder側のAuthenticator = MD5(Code + Id + Length + Authenticator + Attributes + Secret)
です(右辺のAuthenticatorはRequestorからのもので、それ以外はResponderからのもの)。IdはPacket Identifier headerのことです。
以下、実際のpacket例(Wiresharkで表示)で説明します。

これはEAP-TLSのやりとりを含む例です。No.44がAccess-Request, No.45が対となるAccess-challengeです。この「対となる」ことを確認します。No.44の中は

となっています。Access-RequestのAuthenticatorはRequestor側でRequest毎にrandom値を決定します。No.45の中は

となっています。WiresharkでRadius Protocolで
することでRadius protocolのbinaryデータをファイル化できます。上記の式はRadius protocolのbinaryデータに対して
- AuthenticatorをRequestor側(No.44)のAuthenticatorで置換
- binaryデータの末尾にSecret(NAD-AAA server間のShared Secret)を追加
したデータのMD5 hashを求めるという意味になります。No.45のRadius protocolをエクスポートしたファイルをrp.bin、No.44のAuthenticatorをエクスポートしたフィルをra.binとすると、一般的なlinux上で
cat ra.bin | dd of=rp.bin bs=1 seek=4 conv=notrunc
(置換)
echo -n "cisco" | dd of=rp.bin bs=1 oflag=append conv=notrunc
(追加)
ができます。(Code,Idは1byte, Lengthは2bytesなため、rp.binの先頭から5byte目から16bytes分をra.binで上書きしています。この環境のshared secretはciscoです。)
これらの処理がされたrp.binを cat rp.bin | openssl md5
した値がResponder側のAuthenticator値になります。
Responder側はこの値を実際にpacketに入れてRequestor側へのresponse(No.45)とし、Requestor側はこのpacket並びに(お互い知っている)Shared Secretと自分で作成したAuthenticator値から同じ演算が可能なため期待されたAuthenticator値とResponderからのAuthenticator値が一致していた場合、適切なresponseと判断できます。
実際に上記の通り計算をすると、
[ubuntu] tmp$ cat ra.bin | dd of=rp.bin bs=1 seek=4 conv=notrunc
16+0 records in
16+0 records out
16 bytes copied, 0.003778 s, 4.2 kB/s
[ubuntu] tmp$ echo -n "cisco" | dd of=rp.bin bs=1 oflag=append conv=notrunc
5+0 records in
5+0 records out
5 bytes copied, 0.0013068 s, 3.8 kB/s
[ubuntu] tmp$ cat rp.bin | openssl md5
(stdin)= ea12c8618f06561e01a385f70e3bdfb0
[ubuntu] tmp$
とNo.45のAuthenticator値と同じ値となっていることを確認できます。
(ddコマンドの代わりにbinary editorで代用も可)
上記はAccess-Request(/Challenge/Accept/Reject)に関しての役割・計算方法となりAccounting-Request(/Response)では計算式が一部変わります。
Authenticator = MD5(Code + Id + Length + 16 octetsのzero + Attributes + Secret)
違いはRequestor側でrandomに決めていたAuthenticator値はなく、双方のAuthenticator値がこの式で求まります(random値の代わりに16bytesの0と考えることもできます)。そのため、Requestor側/Responder側双方が相手からのAuthenticator値を予測でき有効なRADIUS packetが届いているかcheckできます(Access-Requestに関してはあくまでRequestorがResponderのpacketをcheckするのみです)。計算はAccess-Requestの例でのra.binの中が全て0のものとなります。
Message-Authenticator attributeは受信側が送信側からのRADIUS packetが改ざんされていないことを確認するために使われます(NADもAAA serverも相手からのpacketの改ざん検知に使えます)。EAP-Message attributeが含まれるRADIUS packetでは必須となります(逆にEAP-Message attributeが無いpacketでも存在する場合があります)。これも16bytes長です。AuthenticatorはRADIUSのprotocol headerでしたが、Message-AuthenticatorはAVpairs(Attribute Value Pairs)の一部になります。
計算式は
Message-Authenticator = HMAC-MD5 (Code, Id, Length, Authenticator,
Attributes)
です。Access-Request内のMessage-AuthenticatorはRADIUS protocolをエクスポートしたrp.binのMessage-Authenticatorの部分をall 0で上書きし計算します。Access-Request以外のMessage-Authenticatorはこの処理の他にAuthenticator headerを元のAccess-RequestのAuthenticatorで上書きして計算します。以下の例ではAuthenticator headerの計算で使用したpacket captureを再度使いAccess-Requestでの計算を説明します。
No.44のAttribute Value Pairsを開くと

のようになっているので、RADIUS protocolをエクスポートしrp.binとし、Message-Authenticatorの値を0で上書きします。このpacketの場合はrp.binの最後の16 bytesをbinary editor等で0に変更した上で(80,18はそれぞれ16進で0x50,0x12となることに注意)
cat rp.bin | openssl dgst -md5 -hmac 'shared secret'
を実行すると('shared secret'はcisco)、
[ubuntu] tmp$ cat rp.bin | openssl dgst -md5 -hmac cisco
(stdin)= 19f629f1377a702e82e807c4cc173d93
[ubuntu] tmp$
となり、No.44のMessage-Authenticator attributeの値と等しくなることが確認できます。
受信側では受信packetから同じ計算をしpacketに含まれるMessage-Authenticator attributeの値と比較して一致していれば改ざん無と判断できます。
本稿で使用したNo.44とNo.45のpacketのファイルを添付します。Wiresharkで開けますので実際に計算してみていただければと思います。
ISEではAuthenticator header/Message-Authenticator attributeに関して以下のようなMessageがあります(以下はISE 2.7での画面キャプチャ)。遭遇した際には本稿の内容を活用いただければと思います。
