Microsoft Entra Verified ID の動きをみてみた。検証編
Digital Identity技術勉強会 #iddance Advent Calendar 2022 16 日目の記事の続きです。
発行編は以下になります。
Microsoft Entra Verified ID の動きをみてみた。 発行編
https://zenn.dev/nerocrux/articles/ee34b2c18c5752
本記事では前回に続けて、Microsoft Entra Verified ID を利用して発行した VC への Verification (検証)の流れについて説明します。
VC 検証フロー
アクターの紹介は、VC 発行時とほぼ一緒のため、VC 発行編をご覧ください。
一点だけ、VC 発行フローの Web App は Issuer のものとなりますが、検証フローでは Verifier のものになります。
※ MS のチュートリアルは適当に Issuer と Verifier を同じテナント上のアプリを利用していますが、一般的なシナリオでは Issuer と Verifier は別々のテナントになります。現時点では MS Verified ID を使うには Azure AD Premium P2 ライセンスがいらなくなったはずなので、二つのテナントを建てて遊んでみたほうが体験的によいはずです(KeyVault はそれぞれ課金されますが、そんなに高くないはずです)。
VC 検証フローの詳細
それでは、VC 検証フローの各ステップで何が起きているかをみてみましょう。
(1) VC を検証する Web サイトにユーザーがアクセスし、「VC を提示する」みたいなボタンをクリックします。
学位証明書発行の例でいうと、例えば学生 X は大学 A で修士学位を修了して、大学 B の博士課程に進めるとします。
その場合、大学 A は学生に修士修了証明を VC として発行した後に、学生はこの VC をもって大学 B に入学するときに、大学 B が学生の修士修了証明を検証するために、大学 A が発行した VC を検証します。
検証手続きを開始するために、学校 B は Web ページ等で「あなたの修士学位(VC)を検証しますよ」みたいなボタンを用意します。
学生はこのボタンをクリックしたら、VC 検証フローがキックオフされる想定になります。
(2) Web App は MS Verified ID の Presentation API に VC 検証要求を送信します。
MS Verified ID サービスでは、実際の Verifier(上記例の中の "学校 B")の代わりに MS Verified ID サービスが VC を検証しますので、Web App は MS Verified ID に対して、VC 検証要求を送信します。
実際リクエスト送信対象となり API は以下になります。
API Reference
https://learn.microsoft.com/ja-jp/azure/active-directory/verifiable-credentials/presentation-request-api
また、送信するリクエストの一例は以下です。
POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createPresentationRequest
Content-Type: application/json
Authorization: Bearer <token>
{
"includeQRCode": true,
"includeReceipt": true,
"authority": "did:ion:xxxxxxxxxxxxxxxxxxxxxxxxxx:eyJ...xxxxxxxxxxxxx",
"registration": {
"clientName": "Delos"
},
"callback": {
"url": "https://www.contoso.com/api/verifier/presentationCallback",
"state": "92d076dd-450a-4247-aa5b-d2e75a1a5d58",
"headers": {
"api-key": "OPTIONAL API-KEY for CALLBACK EVENTS"
}
},
"requestedCredentials": [
{
"type": "Delos",
"purpose": "Verify if you are an host.",
"acceptedIssuers": [
"did:ion:xxxxxxxxxxxxxxxxxxxxxxxxxx:eyJ...<SNIP>..."
],
"configuration": {
"validation": {
"allowRevoked": false,
"validateLinkedDomain": false
}
}
}
]
}
VC 発行と同様に、Web App は自分の(Verifier の)Azure AD テナント上に登録されている資格情報を利用して、OAuth 2.0 Client Credentials Grant で Access Token を取得します。
リクエストにある authority
は Verifier (学校 B)の DID となり、acceptIssuers
は Verifier 側で受け入れる VC の Issuer (例:学校 A)の DID となります。
余談ですが、最近 Microsoft Entra ポータルが改修されていて、ポータルから検証済みの Issuer を検索して、その Issuer が発行する VC を選択したら、その VC への検証要求を(半自動的に)作成してくれる機能を用意してくれたらしいですね(半年くらい前にはなかった気がする)。
(3) MS Verified ID サービスは Web App に Presentation Request の応答を返します。
応答の一例として、以下の形のレスポンスが Web App に返されます。
{
"requestId": "e4ef27ca-eb8c-4b63-823b-3b95140eac11",
"url": "openid-vc://?request_uri=https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/request/7215574c-5757-4b2a-b779-550da5022793",
"expiry": 1633017751,
"qrCode": "data:image/png;base64,iVBORw0KGgoA<SNIP>"
}
この中に QR Code のデータがすでに qrCode
に含まれており、中身は url
の内容と一致します。
(4) Web App は QR コードを Web ブラウザーに渡します。
(5) Web ブラウザーは QR コードをユーザーに表示します。
(6) Web ブラウザーは Web App に対して Polling を実施します。
(7) ユーザーは Authenticator アプリを使って QR コードをスキャンします。
(4) (5) (6) (7) のやることは Issuance の時と一緒ですので、ユーザー体験についての説明を省略します。
(8) Authenticator は request_uri から Authorization Request をダウンロードします。
VC 発行時と同様に、検証時でも Authenticator は QR コードから request_uri を取得して、その URL から HTTP Get で Authorization Request をダウンロードします。
検証の場合、Authorization Request / Response は OpenID for Verifiable Presentation プロトコル(+ SIOP V2)の定義に従い構成されます。
このプロトコルにも、SIOP V2 に類似する Verifier-initiated Cross-Device Flow というフローが定義されており、Verifier から Wallet に Authorization Request は QR コード方式で伝達します。
実際 Authenticator が取得した Authorization Request の一例は以下になります。
{
"alg": "ES256K",
"kid": "did:ion:EiB-gFzUixxxxxxxxxxxxxxxxzR0wvg:eyJkZWx0YSI6eyxxxxxxxxxxxxxxxxxxxxxx#c94420b0135848918c0b67f706fe4b97vcSigningKey-e3bde",
"typ": "JWT"
}.{
"jti": "98cd5197-f19e-4090-8ce5-805c049f9137",
"iat": 1670919641,
"response_type": "id_token",
"response_mode": "post",
"scope": "openid",
"nonce": "byjDQVz4ZR1jDzLr6VquGQ==",
"client_id": "did:ion:EiB-gFzUi926tGd-gFzUixxxxxxxxxxxxxxxxzR0wvg:eyJkZWx0YSI6eyxxxxxxxxxxxxxxxxxxxxxx",
"redirect_uri": "https://beta.did.msidentity.com/v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/present",
"state": "xxxxxxxxxxxxxxxxxxxxx",
"exp": 1670919941,
"registration": {
"client_name": "Delos",
"subject_syntax_types_supported": [
"did:ion"
],
"vp_formats": {
"jwt_vp": {
"alg": [
"ES256K",
"EdDSA"
]
},
"jwt_vc": {
"alg": [
"ES256K",
"EdDSA"
]
}
}
},
"claims": {
"vp_token": {
"presentation_definition": {
"id": "fcffd6a9-c353-460a-9380-de60b872bc07",
"input_descriptors": [
{
"id": "Delos",
"name": "Delos",
"purpose": "verify vc card issued for Delos",
"schema": [
{
"uri": "Delos"
}
]
}
]
}
}
}
}.[Signature]
こちらのパラメータも発行時と同様に、普通の OpenID Connect Authorization Request っぽいパラメータが確認できます。
また、vp_token
には、Verifiable Presentation 関連のパラメータが含まれています。
presentation_definition について
claims.vp_token.presentation_definition
に、Verifier (Web App)から Holder(Authenticator)に対して、提示してほしい VP の定義が記載されています。
presentation_definition
は Presentation Exchange という仕様で定義されているデータモデルに従い構成されています。
Presentation Exchange の仕様では、提示してほしい VP の要件をいろんなスキーマで定義できますが、MS Verified ID サービスは現状 Presentation Request API の自由度が低く感じていて(requestedCredentials.acceptedIssuers
に定義する「受け入れる Issuer」と requestedCredentials.type
に定義する「VC の種類」くらい)、そのため現状 presentation_definition
の input_descriptors
にも VC の種類を示すパラメータ(schema.uri
)しかないように見えます。
より高度な presentation_definition
の構成方法については把握しておりませんが(API の仕様をみると、ないじゃないかと思いますが)、もし方法があれば教えてください。
(9) Authenticator は Verifier の DID を Resolve します。
こちらも発行時と同様に、Authenticator は Authorization Request の client_id
にある Verifier の DID を Resolve します(MS Verified ID の Discovery エンドポイント利用)。
DID Document 取得後、Autheticator は以下のようなリクエストで Verifier の Well Known DID Configuration (did-configuration.json)を取得しました。
HTTP GET
https://vc.example.com/.well-known/did-configuration.json
{
"@context": "https://identity.foundation/.well-known/contexts/did-configuration-v0.0.jsonld",
"linked_dids": [
"eyJhbGciOiJFUzI1NksiLCJraWxxxxxxxxxxxxxxxxxxxx"]
}
ただ自分の調査では、発行時に Authenticator は Issuer の did-configuration.json を取ってないよう(MS Verified ID が取得していると思いますが)でして、検証時に Verifier の did-configuration.json を取得したのは、検証時では Authenticator 側で Linked Domain を検証している...?と思いますが。ここだけ発行時と検証時の動作に差異があったようです。
(10) MS Verified ID サービスは Web App にコールバックを送信します。
こちらも発行時と同様に、Authenticator が Authorization Request を MS Verified ID からダウンロードした後に、MS Verified ID サービスは「ユーザーが QR コードをスキャンしたよ」の状態変化を Web App に通知します。
Callback 一例
{
"requestId": "e4ef27ca-eb8c-4b63-823b-3b95140eac11",
"requestStatus":"request_retrieved",
"state": "92d076dd-450a-4247-aa5b-d2e75a1a5d58"
}
API Reference
https://learn.microsoft.com/ja-jp/azure/active-directory/verifiable-credentials/presentation-request-api#callback-events
(11) ユーザーが Authenticator 上で Verifier に提示する VC カードを選択します。
Authenticator に複数の VC を保有していて、複数の VC が presentation_definition
を満たしている可能性があるため、Authenticator はどのカードを提示するかをユーザーに選択してもらいます。
その際に、以下のような UI が表示され、ユーザーが MS Verified ID / Verifier に提示する VC を選択して、共有
ボタンを押します。
(12) Authenticator が VC から VP を作成します。
ユーザーが Verfiier に提示する VC を選択しましたら、Authenticator は選択された VC を含む VP(Verifiable Presentation) を作成します。
VP のデータ構造も、Verifiable Credentials Data Model の定義とおりに構成されていると思われます。
VP は JWT 形式のもので、デコード後の一例は以下になります。
{
"typ": "JWT",
"alg": "ES256K",
"kid": "did:ion:EiBtR0YwYDcU1jC5awwLQH89_6Q:eyJkZWx0YSI6eyJwYXRjaGVxxxxxxxxxxxxxxxxxxxxxxxx#sign_G8Bzln9MJP"
}.{
"nonce": "byjDQVz4ZR1jDzLr6VquGQ==",
"iat": 1670919706,
"jti": "E505CEA1-6BCE-4B35-B003-0E03DFFF491A",
"nbf": 1670919706,
"exp": 1670922706,
"aud": "did:ion:EiB-gFzUi92xxxxxxxxxxxxxxxxxxxzR0wvg:eyJkZWx0YSI6eyJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"vp": {
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": [
"VerifiablePresentation"
],
"verifiableCredential": [
"eyJhbGciOiJFUzI1NksiLCJraWQxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
]
},
"iss": "did:ion:EiBtR0YwYDcU1jC5awwLQH89_6Q:eyJkZWx0YSI6eyJwYXRjaGVxxxxxxxxxxxxxxxxxxxxxxxx#sign_G8Bzln9MJP"
}.[Signature]
VP の中に、ユーザーが選択した VC が vp.verifiableCredential
に含まれます。
この VP は、Authenticator の DID の秘密鍵で署名されており、秘密鍵は Authenticator 端末の KeyStore / KeyChain 等に保存されていると思われます。
(13) Authenticator が VP を MS Verified ID サービスに送信します。
VP 作成後、Authenticator は OpenID for Verifiable Presentation の Authorization Response を作成します。
POST /v1.0/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/verifiableCredentials/present
Host: beta.did.msidentity.com
Content-Type: application/x-www-form-urlencoded
id_token=eyJxxxxxxxxxxxxxxxxxxxxx
vp_token=eyJxxxxxxxxxxxxxxxxxxxxx
state=xxxxxxxxxxxxxxxxxxxxxxxxxxx
vp_token
パラメータに、Authenticator が作成した VP が入ります。
そして Authorization Request の response_type
が id_token
になっているため、id_token
というパラメータも送信されます。
id_token
の一例は以下となります(デコード後)。
{
"typ": "JWT",
"alg": "ES256K",
"kid": "did:ion:EiBtR0YwYDcU1jC5awwLQH89_6Q:eyJkZWx0YSI6eyJwYXRjaGVxxxxxxxxxxxxxxxxxxxxxxxx#sign_G8Bzln9MJP#sign_G8Bzln9MJP"
}.{
"iat": 1670919706,
"nonce": "byjDQVz4ZR1jDzLr6VquGQ==",
"sub": "did:ion:EiBtR0YwYDcU1jC5awwLQH89_6Q:eyJkZWx0YSI6eyJwYXRjaGVxxxxxxxxxxxxxxxxxxxxxxxx#sign_G8Bzln9MJP",
"exp": 1670922706,
"aud": "did:ion:EiB-gFzUixxxxxxxxxxxxxxxxzR0wvg:eyJkZWx0YSI6eyxxxxxxxxxxxxxxxxxxxxxx#c94420b0135848918c0b67f706fe4b97vcSigningKey-e3bde",
"_vp_token": {
"presentation_submission": {
"id": "442681DA-4354-455B-AFC9-053B338995CC",
"definition_id": "fcffd6a9-c353-460a-9380-de60b872bc07",
"descriptor_map": [
{
"path": "$",
"id": "Delos",
"format": "jwt_vp",
"path_nested": {
"id": "Delos",
"format": "jwt_vc",
"path": "$.verifiableCredential[0]"
}
}
]
}
},
"iss": "https://self-issued.me/v2/openid-vc"
}.[Signature]
この ID Token は Authenticator が Self-Issued なもので、
-
kid
、iss
は Authenticator の DID となります。 -
iss
にはhttps://self-issued.me/v2/openid-vc
になっています。※ この値(固定値)の出典はわかってないです。
また
-
aud
はこのトークンの利用先である Verifier の DID となります。 -
_vp_token.presentation_submission
には VP トークンとペアとなり(VP トークンに入れてはいけないと定義されている)、presentation_definition
をどのように満たしているかの説明が記載されています。presentation_submission
のスキーマも Presentation Exchange によって定義されています。今回 definition はとてもシンプルな形になってますので、submission もシンプルですね。
このレスポンスを MS Verified ID が正しく受け取った場合、Authenticator にシンプルに 200 OK を返します。state が expire したりすることもあり得ますので、その際に JSON レスポンスでエラー情報を Authenticator に返しています。
(14) MS Verified ID が VP を検証します。
MS Verified ID が VP を受け取ったあとに、(具体的になにをやっているか知りませんが)おそらく以下のような検証を行われると思われます。
- VP 自体は有効であるか(検証要求が満たされているかなど)
- VP / VC の署名は正しいか
- VP の
iss
は VC のsub
と一致するか(Holder の DID であるか) - などなど
なお、VP は Authenticator の DID に署名されていますが、Authenticator (Holder)の DID は現状 ION にコミットされていないはずで、Authenticator の DID は Long Form になっているため、MS Verified ID は DID に含まれている公開鍵を取り出して、署名検証を行っていると思われます。
(15) MS Verified ID が Web App に presentation_verified の通知を送信します。
手順 (10) と同様に、MS Verified ID が提示された VP の有効性を検証した後に、Web App 「VP 検証できたよ」の通知を送ります。
これだけでなく、MS Verified ID が Authenticator から送られてきた VP (receipt.vp_token
) や ID Token (receipt.id_token
) を「レシート」 として、Callback に含めて Web App に送ります。
これは、あくまでも Web App 側でデバッグ用(Authenticator から MS Verified ID に実際何を送ったかの確認用)のものでして、Web App 側で検証したりする必要がありません。
{
"requestId": "e4ef27ca-eb8c-4b63-823b-3b95140eac11",
"requestStatus": "presentation_verified",
"state": "92d076dd-450a-4247-aa5b-d2e75a1a5d58",
"subject": "did:ion:EiAlrenrtD3Lsw0GlbzS1O2YFdy3Xtu8yo35W<SNIP>…",
"verifiedCredentialsData": [
{
"issuer": "did:ion:issuer",
"type": [
"VerifiableCredential",
"VerifiedCredentialExpert"
],
"claims": {
"firstName": "Megan",
"lastName": "Bowen"
},
"credentialState": {
"revocationStatus": "VALID"
},
"domainValidation": {
"url": "https://contoso.com/"
}
}
],
"receipt": {
"id_token": "eyJraWQiOiJkaWQ6aW<SNIP>",
"vp_token": "...",
"state": "..."
}
}
これで Web App が「ユーザー持つ VC は、自分の要求を満たしている」ことが MS Verified ID サービスによって検証されたことを把握できましたので、次の手続きに進めることができます。
(16) Web ブラウザーが Polling で状態変更を取得し、ユーザーに知らせます。
Web ブラウザーとしては Polling で取得する VC 検証の状態も更新されるはずですので、次の手続きに進むか、VC が検証されたことをユーザーに通知します。
終わりに
以上は Microsoft Verified ID サービスを利用した VC(VP)検証フローになります。
これでなんとなる Verifiable Credentials / Microsoft Verified ID を入門したような気持ちになりました。
ただこれは Microsoft が OpenID を利用した VC の一実装例に過ぎないと理解しており、そのほかもいろんな実装例があるはずなので、いろいろ見てみたいと思います。
また、VC の Revoke についても、今後時間がありましたら記事に落としたいと思います。
2023/1/25 追記
取消編 も書きました。
Discussion