YubiKeyの U2F 実装の概要
会社のアドベントカレンダーに誘われて、変なこと書けないぞつらーい、と思ったのですが
「最後に、あくまで個人の見解です と書いとけばオールオッケー」
とと言われたので、緩いスタンスで書いていこうと思います。
自己紹介
普段は YubiKey を使ったセキュリティソリューションの開発や、調査、販売サポートなどをおこなったり、 Twitterアカウントを作りなおしたり しているエンジニアです。
YubiKey とは
Yubicoが作っている セキュリティデバイスで、以下のような機能があります。
- FIDO U2F プロトコルによる2要素認証
- PIVの仕様に則ったスマートカード機能
- OpenPGP対応
- 各種標準OTPおよびYubico 独自のカウンタ方式の Yubico OTP
Qiita の記事を見てみるとLinuxのPam認証で使ったり、秘密鍵の管理に使ったりという使い方が多いようですね。
U2Fの仕組み
Qiitaに各記事なので技術的なほうが良いと思ったので、今日は FIDO U2F の Yubico の実装について簡単に説明していきたいと思います。
FIDO U2F とは簡単に言うと電子署名を用いたチャレンジ&レスポンス方式です。
詳しい解説は日本語だと以下のページが非常によくまとまっていますのでご参考に…。
とどのつまり、各RP(サービス)ごとにキーペアを作って、署名検証しましょうということなのですが、 YubiKey の優れているところは各サービスごとの秘密鍵をデバイスに保存しないことです。
YubiKey の U2F 実装
秘密鍵をデバイスに保存しないにもかかわらず、どうして各サービスごとに秘密鍵が作れるのでしょうか。
https://developers.yubico.com/U2F/Protocol_details/key_generation.png //404 not found...
上記の図は register 時の動作です。(画像が消えてます)
まずサービスにキーを登録する際に、 AppID(多くはドメイン)が YubiKey に渡されます。(青のラインです)
YubiKey は内部にある RNG(Random Number Generator)で作成した Nonce と AppID から DeviceSecret※ で HMAC を計算し、それを秘密鍵とします。
※ DeviceSecret : YubiKey製造時に書き込まれるデバイス独自の秘密鍵
つまりはこういうことです。
Secret_{app} = HMAC(Secret_{device}, AppID + Nonce)
さて、作成された秘密鍵から公開鍵を作成すると 公開鍵 、と KeyHandle(NONCE+α 後述) と共にサーバーに送ります。
つまりサーバーは以下の 2 つの情報を得ます。
KeyHandle = Nonce + MAC_{app}\\
Public_{app} = GeneratePublicKey (Secret_{app})
認証時は Signリクエスト(Challenge + KeyHandle + AppID )がサーバーから送られてきます。
この際、KeyHandle には Nonce が含まれているので、 AppID + Nonce + DeviceSecret で先ほど作成したものと同じ秘密鍵を作成できます。
KeyHandle = Nonce + MAC_{app}\\
Secret_{app} = HMAC(Secret_{device}, AppID + Nonce)\\
Signiture = Sign(Secret_{app}, challenge)
それによってサーバーに保存された公開鍵で検証できる署名ができるというわけです。
これらの処理はすべてYubiKeyの内部で行われるため、デバイスの秘密鍵でなく、アプリケーションごとの秘密鍵もデバイスの外にでることはありません。
ちなみに KeyHandle には赤のラインでは作成した HMAC(アプリケーションごとの秘密鍵 + AppID ) も含まれており、これは認証の際に、本当にこのキーで作成された公開鍵かを検証するときに使用されます)
MAC_{app} = HMAC(Secret_{device}, AppID + Secret_{app})
自身のキーで作成された KeyHandle 以外が送られてきても安易に署名が行われないようになっているわけです。
謝罪
とまあ、完全にただ Yubico のページを日本語訳しただけになってしまいましたが、前日に風邪ひいてしまって丸一日寝ていたので皆許してくれるかなあと思います。
※あくまで個人の見解です