Self-Issued OpenID Connect Provider DID Profile v0.1 とは

f:id:ritou:20200922040730p:plain

おはようございます。ritouです。

今日はこれを読んでみます。

Self-Issued OpenID Connect Provider DID Profile v0.1

何のための仕様か

This specification defines the "SIOP DID Profile" (SIOP DID) that is a DID AuthN flavor to use OpenID Connect (OIDC) together with the strong decentralization, privacy and security guarantees of Decentralized Identifiers (DID) for everyone who wants to have a generic way to integrate Identity Wallets into their web applications.

  • WebアプリケーションにIdentity Walletを統合するために
  • DIDとOpenID Connectの組み合わせるための
  • SIOP DID Profileじゃ!

と言うことです。

SIOPについてはもう大丈夫でしょうか?七年前の記事で良ければどうぞ。

ritou.hatenablog.com

Qiitaにもいくつか記事があります。

qiita.com

  • OpenID Providerとして特定のWebアプリケーション(Googleとか)ではなく、モバイル端末内で動作するアプリケーションなどを利用する
  • openid:// と言うカスタムURIスキームを用いた認可リクエストにより呼び出され、鍵ペアを生成/管理してIDToken を返す
  • ユーザーの同意のもとで端末単位で保存している情報のやりとりや、使い方次第では端末の識別やリクエストが同端末から送られたことの検証などにも使おうと思えば使える

と言うものであり、仕様としてはモバイルアプリ、ブラウザのプラグイン、デバイスの機能など特定のURI呼び出しを検知して起動できる仕組みで使えるように汎用的に作られています。

この仕様では、特定のサービスではなく端末自体をOPにすると言うSIOPをDID/SSIのIdentity Walletとして使うために必要な差分なりが定義されています。

Protocol Flow

RPはWebアプリ/ブラウザベース(SPAなど)のアプリであり、モバイルもしくはデスクトップブラウザからIdentityWalletアプリを立ち上げて使う想定です。 公式の図を見てみましょう。

https://identity.foundation/did-siop/assets/did_authn_siop_profile_flow.png

流れをざっくりまとめると、

  1. RPは "Sign-in with SSI" ボタンみたいなのを用意し、ユーザーが押すと SIOP Request を生成
  2. openid://?<SIOP Request> として何やかんやで Identity Walletアプリが起動する
  3. Identity Walletアプリは OIDC/DID AuthN に従って SIOP Request を検証する
  4. 必要なら認証をして、その後に SIOP Response を作成する
  5. response_mode の指定にしたがってRPにSIOP Responseが渡される
  6. RPはOIDC/DID AuthN に従って SIOP Response を検証する

となります。

基本的にこのSIOPの流れに、DID用の処理が追加されるイメージです。

  • SIOP Request : RPは自身のDIDを含み、DIDドキュメントから検証可能な秘密鍵で署名を生成
  • SIOP Response : SIOPは自身のDIDを含み、DIDドキュメントから検証可能な秘密鍵で署名を生成

それでは見ていきましょう。

Generate SIOP Request

SIOP Request は次のように定義されています。

  • 互換性のため、response_type, scope, client_id を文字列で指定する
  • それ以外のパラメータは request もしくは request_uri として指定する。RPのDIDもこっちで指定。

例を引用します。

openid://?response_type=id_token
    &client_id=https%3A%2F%2Frp.example.com%2Fcb
    &scope=openid%20did_authn
    &request=<JWT>
openid://?response_type=id_token
    &client_id=https%3A%2F%2Frp.example.com%2Fcb
    &scope=openid%20did_authn
    &request_uri=https%3A%2F%2Frp.example.com%2F90ce0b8a-a910-4dd0

いわゆるリクエストオブジェクトを指定、なんてのはFAPIなどのProfileでも使われているので驚きはないでしょう。

SIOPのフローでは、registration パラメータによってRPのメタデータを登録できます。

  • アルゴリズムRS256 に加えて ES256KEdDSAをサポートしなければならない
  • Request ObjectはDIDドキュメントに記載されている検証方法で直接/間接的に検証可能であり、RPのJWKSにより直接検証可能である必要がある
  • JWKSは jwks_uri もしくは jwks パラメータで指定され、jwks の場合は kid が一致する必要がある。jwks_uriの場合はHTTP(S) DID Resolution Bindingが必要とか...
  • RPはSIOP Responseを暗号化して受信することもできる

リクエストオブジェクトについても細かく書いてありますが、眠いので例示に留めます。

#header
{
    "alg": "ES256K",
    "typ": "JWT",
    "kid": "did:example:0xab#veri-key1"
}

# payload
{
    "iss": "did:example:0xab", # RP's DIID
    "response_type": "id_token",
    "client_id": "https://my.rp.com/cb",
    "scope": "openid did_authn", # did_authn を指定
    "state": "af0ifjsldkj",
    "nonce": "n-0S6_WzA2Mj",
    "response_mode" : "form_post",
    "registration" : {
        "jwks_uri" : "https://uniresolver.io/1.0/identifiers/did:example:0xab;transform-keys=jwks",
        "id_token_signed_response_alg" : "ES256K"
    }
}

SIOP Request Validation

SIOPは scopedid_authn が指定されていたら、OIDCで定義されている検証に加え次のような検証を行います。

  • iss クレームで指定されたRPのDIDからDIDドキュメントを取得
  • jwks_uriが存在する場合、iss とDIDが一致することを検証
  • RPのDIDドキュメントから、kid と一致する検証方法を取得
  • SIOP Requestの検証

Generate SIOP Response

SIOPは以下のような SIOP Response を作成してRPに戻します。

  • sub_jwkkid を含む
    • kid はSIOPのDIDドキュメントの検証方法を参照する DID URL
  • SIOPのDIDを含む : did クレーム
# Header
{
    "alg": "ES256K",
    "typ": "JWT",
    "kid": "did:example:0xab#key-1"
}

# Payload
{
    "iss": "https://self-issued.me",
    "nonce": "n-0S6_WzA2Mj",
    "exp": 1311281970,
    "iat": 1311280970,
    "sub_jwk" : {
        "crv":"secp256k1",
        "kid":"did:example:0xcd#verikey-1",
        "kty":"EC",
        "x":"7KEKZa5xJPh7WVqHJyUpb2MgEe3nA8Rk7eUlXsmBl-M",
        "y":"3zIgl_ml4RhapyEm5J7lvU-4f5jiBvZr4KgxUjEhl9o"
    },
    "sub": "9-aYUQ7mgL2SWQ_LNTeVN2rtw7xFP-3Y2EO9WV22cF0",
    "did": "did:example:0xcd" # SIOPDID
}

(ちょっと追記)通常のSIOPは鍵を生成して端末なりに保存しておくだけのイメージですが、ここではDIDを含みDIDドキュメントから検証できるようにする必要があるわけなのでこれまでのSIOPの感覚で言うと鍵の登録処理も発生しそうです。もう少し細かく追記してもらうのが良いのかなと思ったりします。

SIOP Response Validation

OIDCのSIOP Responseの検証としては

  1. id_token を取得
  2. id_tokensub_jwk の鍵で署名されたことを検証

さらに DID AuthNとして

  1. id_token の SIOP DID(did) から DIDドキュメントを取得
  2. id_tokenのDIDドキュメントから sub_jwkkid と一致する検証方法を取得
  3. その検証方法で id_token を検証

SIOP Discovery

省略します。

UX Considerations

カスタムURLスキームの扱いについて。 モバイルブラウザの場合はアプリ立ち上げるけどAndroid/iOSそれぞれで今までもいろいろ言われてきたよねと。 デスクトップブラウザの場合、もしかしたらブラウザ拡張/プラグインでサポートされるかもしれないけどうまくいかなそうならIdentity Walletのアプリを開かせてQR読み込ませるとかが必要かも。

この辺りが改善されるにはもう少し時間がかかるかもしれませんね。

Security Considerations

まずはSIOP ResponseのIDToken漏れるかも問題

  • Interception of the Redirect URI : SIOP Responseを取られたらIDToken持っていかれるよ -> RP頑張れ(オープンリダイレクト作るな)
  • Identity Token Leak in Browser History : ブラウザの履歴からSIOP ResponseのIDToken漏れるよ -> IDTokenの有効期限短くしたりキャッシュされないようにしたりしよう。完全な対策は難しいかも。
  • Identity Token Leak to Third Party Scripts : SIOP Responseをを受ける時に3rd PartyのJSとかでIDToken持っていかれるよ -> RP頑張れ(信頼できるやつだけ使え)

対策として response_mode=form_post 使えるならう。無理な場合もあるけど。とあります。

次に Session Fixation in Cross-Device Flow として、異なるデバイス間の転送を含む場合の脅威が記載されています。 RPがQRコードからIdentity Walletを呼び出す仕様の場合、攻撃者は自らのセッションに紐付いたQRを読ませることで第3者の認証を攻撃者のセッションでできるかも。 対策としては同一セッションであることの確認、もしくは異なるデバイスでも同一ユーザーであることを別の認証方式などで確認することが必要。

Github

何かあったらここでやってるよと。

github.com

(追記)SIOP側の公開鍵登録についてもう少し説明必要では?みたいなことを書いてみました。

github.com

まとめ

  • SIOPの流れにDIDの検証処理を追加するProfile
  • RPが作るリクエストオブジェクトの部分がモリモリしてるがSIOPのフローは変わらない
  • カスタムURIスキームやQRコード使う部分はもうちょい改善されないとUXキツそう

と言うあたりでしょうか。引き続きウォッチしていきましょう。 ではまた!