iPhone(iOS14)でWebAuthn認証を試す

# Safari 14でWebAuthn認証
　ついに2020/09/17にリリースされた Safari 14 でWebAuthn(パスワードレス)認証にTouch IDとFace IDがPlatoform Authenticator(認証デバイス)として利用できるようになりました。これによりiPhoneやiPad単体でOpenAMなどWebAuthnが使えるWebサービスに、生体認証を利用したログインが可能となります。
https://developer.apple.com/documentation/safari-release-notes/safari-14-release-notes#Authentication-and-Passwords
※~~今はbetaのリリースノートだけですが、いずれ~~正式版も公開されるでしょう。

引用
> Added a Web Authentication platform authenticator using Face ID or Touch ID, depending on which capability is present.
> Added support for PIN entry and account selection on external Web Authentication security keys.

引用の妙訳
> [1. WebAuthn の認証デバイスとして　Face ID / Touch ID　を使えます。](#1-webauthn-認証デバイスとしての-face-idtouch-id)
> [2. 外部認証デバイスのPIN入力とアカウント選択をサポートします。](#2-外部認証デバイスのpin入力とアカウント選択)

　遂にappleさんも約束の地へやってきたのです。
　参照→[iPhone(iOS13)でパスワードレス(WebAuthn)を試す](https://qiita.com/tonoki/items/7a2fd83fe6620302a7e8)

## 1. WebAuthn 認証デバイスとしての Face ID/Touch ID
　話を始める前に、Appleらしい[クセ](#touch-idface-id-の-platform-authenticator-の選択肢が出ない)もあるので書いてある通りに動かないからと言って怒らないでください。

　今回試したRPサーバー環境はOpenAM14です。構築方法は以下リンクの通りです。
・[OpenAM 14を最速で構築 10分クッキング](https://qiita.com/tonoki/items/6a59cb9fe0b3062d8e84)
・[OpenAM 14のWebAuthn認証設定 10分クッキング](https://qiita.com/tonoki/items/9cd3b6ff427bf9916ed0)

## 利用可能なブラウザ
　現時点で利用可能なのブラウザはSafari 14のみです。
　正確には2020/09/18時点ではver.14.0です。

## Touch IDを認証デバイスとして登録する
　6月のbetaリリース開始の頃から見た目は変っていませんが、遂に自分のiPhoneでこの画面が拝めるとは感慨深いです。あえてTouch IDを使わずに「セキュリティキーを使用」を選んでYubikeyなど外部認証デバイスを使うこともできます。
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/cdd5b2ec-ffc1-16fc-e639-68c2d0e8b551.png">

Youtube動画リンク
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/wbCY6I4JYfk/0.jpg)](http://www.youtube.com/watch?v=wbCY6I4JYfk)


## Touch IDを認証デバイスとしてログインする
　パスワードレス認証の場合はこのような画面となります。「続ける」からTouch IDをタッチする画面へ遷移します。もちろん外部キーを利用したい場合は「セキュリティキーからアカ・・・」を選んで利用できます。
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/dab293b4-2fe7-62f9-f296-0c4a559091cd.png">

Youtube動画リンク
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/G4fGpTenIHo/0.jpg)](http://www.youtube.com/watch?v=G4fGpTenIHo)

## 鍵の削除方法
　(2021/01/26訂正）ドメイン毎に選択しての削除はできません。「設定」ー「Safari」画面から「履歴とWebサイトデータを消去」を選ぶと全てドメインの鍵を削除できますが、あらゆるサイトの鍵が削除されてしまい危険なのでご注意下さい。
　~~ドメイン毎にiPhone上に登録された鍵情報を削除できます。同じドメインに鍵(アカウント)が複数あってもアカウント指定の削除はできません。~~
　~~設定のSafariを開き、一番下の「詳細」から「Webサイトデータ」を開きます。~~
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/241c4a6e-72cd-8107-a2fe-4655fe77b16b.png">

　~~該当のドメインデータを削除すると鍵が削除されます。~~
　(2021/01/26訂正）申し訳ありません、この手順では削除できません。
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/b61208fa-53f1-5a6f-61ee-591223c06733.png">

## 2. 外部認証デバイスのPIN入力とアカウント選択
　Safari 13ではPINを入力するダイアログが出ずにPIN入力が出来ませんでしたが、Safari 14からは、ダイアログが出るようになりました。※2
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/ce7f1eaf-93f7-9399-b42f-f33f02768011.png">
　※2 Yubikey5 NFCで試した限りはuserVerification=requiredにすると動作しません。userVerification=preferredなら上記動作します。全く謎です。

### アカウント選択
　ResidentKeyの場合は、RPサーバーから認証を開始した時点でユーザーが特定されていません。iPhoneに認証リクエストが到着した時点で手元のアカウント一覧からログインしたいユーザーを選びます。Touch IDでも外部キーでも同様な画面となります。
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/57c7266a-bcc0-6ecb-7d68-976045ce708d.png">

## その他マルチキーの対応
　すでにiOS13の時点でも動作していましたが、一応確認しました。
　1ユーザーで複数の認証デバイスを登録して使うケース、TouchID と Yubikeyなど、その時に利用できるデバイスで動作します。
![debices.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/b0828444-accf-b193-f4e8-f10c1ac4e0de.png)

## 試したWebAuthnのオプション
　iOS13(Safari 13)の時と同じようにWebAuthnのオプションと結果を確認します。

|オプション名|パラメーター|
|---|---|
|[attestation](#オプションその1-attestation)|none/direct/indirect|
|[userVerification](#オプションその2-userverification)|preferred/required/dicouraged|
|[residentkey](#オプションその3-residentkey)|true/false|


### オプションその1 [attestation]
none以外はfmt=appleな[attestation statement](#attestation-statementとは)が戻ります。

| パラメーター　| 結果 |
| --- | --- |
|none|noneとして正常に動作します|
|direct| fmt=apple な attestation[※1](#1-apple-anonymous-attestationについて) |
|indirect|  fmt=apple な attestation[※1](#1-apple-anonymous-attestationについて) |

#### ※1 Apple Anonymous Attestationについて
　生成されるattestation statementのフォーマットがapple独自です。
　今の所は[W3CのWebAuthnのattestation statement fmt一覧](https://www.w3.org/TR/webauthn/#defined-attestation-formats)にはappleは無いです。いずれ追加になるのかもしれないですし、~~永遠にそのままかもしれません。~~
正式勧告のLevel 1の方はまだですが、Level 2 のドラフトには追加されました。(2020/11/18)
https://w3c.github.io/webauthn/#sctn-apple-anonymous-attestation

#### attestation statementとは？
　認証デバイスを登録する時だけ送信するデータで、attestation=direct(indirect)をRPサーバーが指定した場合に生成されます。
　細かく説明すると長くなりすぎるのでザックリ言うと、「登録するために送信された公開鍵は確かにそのデバイスで生成したよ」という公開鍵の身元保証書みたいなものです。
　現時点でattestation=noneと設定すればfmt=appleなattestationは送られて来ないので動作します。しかし、attestation statementを受け取って内容の検証をしたいのなら、apple独自仕様のfmtに合うようにRPサーバーを改修しなければなりません。

### オプションその2 [userVerification]
　Touch ID/Face IDがローカル認証相当なので、どのパラメーターでも戻り値のUVフラグは1となります。

| パラメーター　| 結果 |
| --- | --- |
|preferred| UVフラグ = 1 |
|required| UVフラグ = 1 |
|discouraged| UVフラグ = 1 |

### オプションその3 [residentkey]
　常にtrueを与えた時と同じような動作で、認証時には常にuserHandleにuserIDを応答します。RPサーバーサイドでfalseを指定しても無視されてtrue扱いのようです。デバイス内にNameなどが保存され、ResidentKeyの認証フローで使えます。

| パラメーター　| 結果 |
| --- | --- |
| false | 無視され、true相当として動作しているようです |
| true | 動作します |

## Touch ID/Face ID の platform authenticator の選択肢が出ない
　Touch IDを使いたいのに登録時は「"auth.example.com"にセキュリティキーを使用してサインインできるようにしますか？」、認証時は、「"auth.example.com"にセキュリティキーを使用してサインインしますか？」、というダイアログが出てplatform authetnticatorが使えないケースがあります。
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/72fd644a-6dee-5381-27cc-0f22a7576346.png">

　詳しく原因を追って無いですが、platform authenticatorを動作させるにはappleの安全性判定条件をクリアしている必要があり、その条件をクリアしていないと、外部「セキュリティーキー」の利用しか許可されない状態になってしまうようです。
　この状態でリモートインスペクタを見ると「User gesture is not detected. To use the platform authenticator, call 'navigator.credentials.get' within user activated events.」というメッセージが確認できます。
![スクリーンショット_2020-09-16_14.32.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/5976a91a-1fc1-30e2-35f6-3da83b4c2aaa.png)

　ユーザーの「user activated events」の中で「navigator.credentials.create/get」が呼び出されたとSafariが”認識”できない場合「platform authenticator」が利用できない、ただこのSafariが”認識”するロジックには昔は[問題があった](https://bugs.webkit.org/show_bug.cgi?id=213595)ようです。
　自分が把握している限りは、アクセスしているサイトのパスワードが保存されており、自動入力が行われると、たまにこの症状になります。そのほか「user activated events」がどの条件で満たされるのか、必要があればもっと細かい条件は調べようと思います。
　さしあたっての回避にはSafariのパスワード自動入力ダイアログの右下鍵マークから、保存パスワード管理画面を出し、ドメイン名で記録されてるパスワードを削除して下さい。
<img width="375" alt="PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316098/61e3c42b-fedb-7cce-6aa4-25a295544f0f.png">

それでも駄目な場合は、同じく「設定」ー「Safari」の画面から「履歴とWebサイトデータを消去」するとTouch ID/Face IDが使えるようになるケースもありました。

というわけで、遂にappleさんもWebAuthnの世界に来ました。非常にメデタイです。