HAIP 準拠 VC 発行

はじめに

本記事では OpenID4VC High Assurance Interoperability Profile 1.0 (以降 HAIP (ハイプ) ) に準拠する Verifiable Credential (以降 VC) 発行手順について解説します。


仕様の要点

VC 発行手順に関しては、HAIP は概ね OpenID for Verifiable Credential Issuance 1.0 (以降 OID4VCI) と FAPI 2.0 Security Profile (以降 FAPI2SP) を組み合わせたものだと言えます。 ただし、留意すべき差分があるので、主要なものについて紹介します。


送信者限定アクセストークン

FAPI2SP では、送信者限定アクセストークンを実現する方法として次のものが利用可能です。

一方、HAIP で許可されるのは DPoP のみです。


クライアント認証

FAPI2SP では、クライアント認証方式として次のものが利用可能です。

HAIP では、これらに加えて OAuth 2.0 Attestation-Based Client Authentication (以降 ABCA) も利用可能です。

  • attest_jwt_client_auth (ABCA)

なお、HAIP の文脈で ABCA を利用する場合、クライアント・アテステーションx5c ヘッダパラメーターを含まなければなりません。 また、署名検証用公開鍵を含む X.509 証明書 (証明書チェーンの先頭の証明書) は、自己署名証明書であってはなりません。


キー・アテステーション

OID4VCI は、クレデンシャルリクエストに含める鍵証明のフォーマットを幾つか定義しています。 これらのうち、jwt Proof Type (OID4VCI Appendix F.1) では、key_attestation ヘッダパラメーターにキー・アテステーション (OID4VCI Appendix D) を指定することができます。 また、attestation Proof Type (OID4VCI Appendix F.3) では、キー・アテステーションそのものを鍵証明として指定します。

HAIP の文脈でキー・アテステーションを用いる場合、それらは x5c ヘッダパラメーターを含まなければなりません。 また、署名検証用公開鍵を含む X.509 証明書 (証明書チェーンの先頭の証明書) は、自己署名証明書であってはなりません。


スコープ

一般的に、アクセストークンは一つ以上のスコープと紐付いています。 HAIP の文脈では、それらのスコープの中に、特定のクレデンシャル設定を指すものが含まれていなければなりません。

具体的には、クレデンシャル・イシュア・メタデータの credential_configurations_supported に列挙されているクレデンシャル設定群の、どれか一つ以上のクレデンシャル設定の scope プロパティーの値が、アクセストークンに紐付いている必要があります。


手順の概要

認可コードフローによる VC 発行手順の概要は下記の通りです。

  1. PAR リクエスト
  2. 認可リクエスト
  3. トークンリクエスト
  4. クレデンシャルリクエスト

しかし、それぞれのリクエストが様々なトークン群を要求するため、実際の手順はより複雑になります。 下記は、トークン群の生成も含めた手順の概要を示しています。

  1. PAR リクエスト
    • PKCE トークン (コード・ベリファイアとコード・チャレンジ) 生成 (PKCE)
    • クライアント・アテステーション生成 (ABCA)
    • アテステーション・チャレンジ取得 (ABCA)
    • クライアント・アテステーション・PoP 生成 (ABCA)
    • DPoP Proof JWT 生成 (DPoP)
    • PAR リクエスト送信 (PAR)
  2. 認可リクエスト
    • 認可リクエスト送信
  3. トークンリクエスト
    • クライアント・アテステーション生成 (ABCA) (再利用可)
    • アテステーション・チャレンジ取得 (ABCA) (再利用可)
    • クライアント・アテステーション・PoP 生成 (ABCA) (再利用可)
    • DPoP Proof JWT 生成 (DPoP)
    • トークンリクエスト送信
  4. クレデンシャルリクエスト
    • ノンス取得 (OID4VCI)
    • キー・アテステーション生成 (OID4VCI)
    • 鍵証明生成 (OID4VCI)
    • DPoP Proof JWT 生成 (DPoP)
    • クレデンシャルリクエスト送信 (OID4VCI)

実際の手順

このセクションでは、実際の手順をみていきます。

なお、トークン群の生成に用いるスクリプト群や秘密鍵・公開鍵・証明書については、authlete/oid4vci-demo で公開しているものを利用します。


PAR リクエスト

HAIP は FAPI2SP をベースとしており、FAPI2SP が PAR を必須としているため、HAIP 準拠の認可リクエストでも PAR の利用が必須となります。 ここでは、PAR エンドポイントで認可リクエストを登録し、リクエスト URI を取得します。


PKCE トークン生成

HAIP は FAPI2SP をベースとしており、FAPI2SP が PKCE を必須としているため、HAIP 準拠の認可リクエストにはコード・チャレンジ、トークンリクエストにコード・ベリファイアを含めなければなりません。 そのため、pkce スクリプトを用いてそれらを用意します。

./pkce

実行結果:

CODE_VERIFIER=3HlzvGOxhJz3jK2fwstAM8aV2GvqzWFpvfnyOGm53kk
CODE_CHALLENGE=elpP-j7DRK-dvxy4GBOzSr4EjnWzwRBquR-mY-ijtT8

シェル組込コマンド eval を次のように用いると、pkce スクリプトの出力結果をそのままシェル変数に代入することができます。

eval "$(./pkce)"

クライアント・アテステーション生成

クライアント・アテステーションは generate-client-attestation スクリプトを用いて生成することができます。 なお、HAIP では x5c ヘッダパラメーターが必須なので、--x5c オプションを用いて x5c ヘッダパラメーターに列挙する X.509 証明書を指定する必要があるので注意してください。 --x5c オプションは複数回指定可能で、指定された順番で X.509 証明書を x5c ヘッダパラメーターに追加していきます。

CLIENT_ATTESTATION=`./generate-client-attestation \
  --attester-key=keys/client-attester-private.jwk \
  --client-id=${CLIENT_ID} \
  --client-key=client.jwk \
  --x5c=keys/client-attester-certificate.pem`

下記は、生成されるクライアント・アテステーションのヘッダとペイロードの例です。

{
  "typ": "oauth-client-attestation+jwt",
  "alg": "ES256",
  "x5c": [
    "MIIBnTCCAUOgAwIBAgIUZr+BYJKFUDY6CIbWubXMjo1cEH8wCgYIKoZIzj0EAwIw
     HzEdMBsGA1UEAwwUQ2xpZW50IEF0dGVzdGVyIFJvb3QwIBcNMjYwNDE0MTc1OTQy
     WhgPNDc2NDAzMTExNzU5NDJaMBoxGDAWBgNVBAMMD0NsaWVudCBBdHRlc3RlcjBZ
     MBMGByqGSM49AgEGCCqGSM49AwEHA0IABI7riGciOegPsU1MJrSF5CnwImt7Cjzx
     YIgSpcLa4woMIxPaeKzhgHf+mi3qSset92VCeQIo0YljKsn6GS057bWjYDBeMAwG
     A1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBRwEoaaN/q/s+jX
     HSE2bybFF82G3zAfBgNVHSMEGDAWgBQ5hrFgDwFhQ8FuCJQETUlyd2pj0jAKBggq
     hkjOPQQDAgNIADBFAiEA2YOKXOd7UgtSMbVs0mMlss3RNXnMMK2RF2JlkrHQemIC
     IAY6Qx5VxmHwovlc0PJgrCDOQZZRUOKBoedy6AoXLSYh"
  ],
  "kid": "I6NQ3o1a3D2LW4pExAS620B3Amw4pkbNoAcxzkygYhM"
}
{
  "sub": "trial_client",
  "iat": 1776702629,
  "exp": 1776789029,
  "cnf": {
    "jwk": {
      "crv": "P-256",
      "kty": "EC",
      "x": "1AmVr4GoHdPgk48LWdS3T9m6m1mP4VTcj9usoSBnCQk",
      "y": "te-WIuUIq2w8tXmXydlEX4pe9lNe-PBcozA8n7y8XTE"
    }
  }
}

次の点に注目してください。

  • typ ヘッダパラメーターの値が oauth-client-attestation+jwt である。
  • x5c ヘッダパラメーターに署名検証用公開鍵の X.509 証明書 (--x5c オプションで指定したもの) が含まれている。
  • sub クレームにクライアント識別子 (--client-id オプションで指定したもの) が設定されている。
  • cnf.jwk クレームにクライアントの鍵 (--client-key オプションで指定したもの) が設定されている。

アテステーション・チャレンジ取得

ABCA 仕様によれば、認可サーバーがチャレンジエンドポイントを提供している場合、そのエンドポイントから発行されるアテステーション・チャレンジをクライアント・アテステーション・PoP に埋め込む必要があります。 認可サーバーがチャレンジエンドポイントを提供しているかどうかは、サーバーメタデータに challenge_endpoint パラメーターが含まれているかどうかで判定することができます。

チャレンジエンドポイントは、HTTP POST リクエストを受け、attestation_challenge プロパティを含む JSON を返します。 下記は ABCA 仕様から抜粋したリクエストとレスポンスの例です。

アテステーション・チャレンジ・リクエストの例

POST /as/challenge HTTP/1.1
Host: as.example.com
Accept: application/json

アテステーション・チャレンジ・レスポンスの例

HTTP/1.1 200 OK
Host: as.example.com
Content-Type: application/json
Cache-Control: no-store

{
  "attestation_challenge": "AYjcyMzY3ZDhiNmJkNTZ"
}

CHALLENGE_ENDPOINT というシェル変数にチャレンジエンドポイントの URL が入っている場合、次のコマンドを実行することでアテステーション・チャレンジの値を CHALLENGE というシェル変数に代入することができます。

CHALLENGE=`curl ${CHALLENGE_ENDPOINT} \
  -X POST | \
  jq -r .attestation_challenge`

クライアント・アテステーション・PoP 生成

クライアント・アテステーション・PoP は generate-client-attestation-pop スクリプトを用いて生成することができます。 challenge クレームを含める場合は --challenge オプションを指定してください。

CLIENT_ATTESTATION_POP=`./generate-client-attestation-pop \
  --as-id=${AUTHORIZATION_SERVER} \
  --client-key=client.jwk \
  --challenge=${CHALLENGE}`

下記は、生成されるクライアント・アテステーション・PoP のヘッダとペイロードの例です。

{
  "typ": "oauth-client-attestation-pop+jwt",
  "alg": "ES256",
  "kid": "7yNhIHVeaPFIB_0k-YpiFATomCLpxIv-e2AAFmCRBLE"
}
{
  "aud": "https://trial.authlete.net",
  "jti": "tiZaOFhUK0au8RA0",
  "iat": 1776704669,
  "exp": 1776791069,
  "challenge": "HECMLA_LpoE9hSDlVP4yptT2i1zOnOdkIPnVa39rInA"
}

次の点に注目してください。

  • typ ヘッダパラメーターの値が oauth-client-attestation-pop+jwt である。
  • aud クレームに認可サーバー識別子 (--as-id オプションで指定したもの) が設定されている。
  • challenge クレームにアテステーション・チャレンジ (--challenge オプションで指定したもの) が設定されている。

DPoP Proof JWT 生成

FAPI2SP に次のように書かれているため、認可コードも DPoP-bound にする必要があります。

if using DPoP, shall support “Authorization Code Binding to DPoP Key” (as required by Section 10.1 of RFC9449);

これを実現する方法は、PAR エンドポイントで登録するリクエストに dpop_jkt リクエストパラメーターを加えるか、もしくは DPoP Proof JWT を加えるか、のどちらかになります。

仕様書にも書かれているように DPoP Proof JWT のほうが実装が単純になるので (リクエストの種類に関わらずクライアントは認可サーバーに送るリクエストに常に DPoP Proof JWT を含めるという実装にすればよいので)、ここでは DPoP Proof JWT を生成することにします。

generate-dpop-proof スクリプトに、PAR リクエストの HTTP メソッド (POST 固定) を指定する -m POST オプションと、PAR エンドポイントの URL を表す -u $PAR_ENDPOINT オプション、クライアントの鍵を表す -k client.jwk オプションを渡して DPoP Proof JWT を生成します。

DPOP_PROOF=`./generate-dpop-proof \
  -m POST \
  -u ${PAR_ENDPOINT} \
  -k client.jwk`

下記は、生成される DPoP Proof JWT のヘッダとペイロードの例です。

{
  "typ": "dpop+jwt",
  "alg": "ES256",
  "jwk": {
    "kty": "EC",
    "alg": "ES256",
    "crv": "P-256",
    "x": "1AmVr4GoHdPgk48LWdS3T9m6m1mP4VTcj9usoSBnCQk",
    "y": "te-WIuUIq2w8tXmXydlEX4pe9lNe-PBcozA8n7y8XTE"
  }
}
{
  "jti": "zrZOAIoZJvCbEQrM",
  "htm": "POST",
  "htu": "https://trial.authlete.net/api/par",
  "iat": 1776708531
}

次の点に注目してください。

  • typ ヘッダパラメーターの値が dpop+jwt である。
  • jwk ヘッダパラメーターにクライアントの鍵 (-k オプションで指定したもの) が設定されている。
  • htm クレームに PAR リクエストの HTTP メソッド (-m オプションで指定したもの) が設定されている。
  • htu クレームに PAR エンドポイントの URL (-u オプションで指定したもの) が設定されている。

PAR リクエスト送信

トークン群の用意ができたので、PAR リクエストを送信します。

curl ${PAR_ENDPOINT} \
  -H "OAuth-Client-Attestation: ${CLIENT_ATTESTATION}" \
  -H "OAuth-Client-Attestation-PoP: ${CLIENT_ATTESTATION_POP}" \
  -H "DPoP: ${DPOP_PROOF}" \
  -d client_id=${CLIENT_ID} \
  -d response_type=code \
  -d scope=digital_credential+haip \
  -d redirect_uri=${REDIRECT_URI} \
  -d code_challenge=${CODE_CHALLENGE} \
  -d code_challenge_method=S256

このリクエストの要点は次の通りです。

項目 説明
クライアント認証 ABCA を用いる場合、OAuth-Client-Attestation HTTP ヘッダと OAuth-Client-Attestation-PoP HTTP ヘッダに、ぞれぞれクライアント・アテステーション、クライアント・アテステーション・PoP を設定します。
送信者限定 DPoP HTTP ヘッダに DPoP Proof JWT を設定します。
client_id 認可リクエストでは client_id リクエストパラメーターは必須です。
response_type FAPI2SP では response_type リクエストパラメーターの値は code でなければなりません。(code 以外を含めることはできません)
scope HAIP 仕様に準拠するため、何かしらのクレデンシャル設定に対応するスコープを scope リクエストパラメーターに含めなければなりません。 この例では、digital_credential という文字列が何かしらのクレデンシャル設定の scope プロパティーに設定されているものと想定しています。 また、この例では追加で haip というスコープも含めています。
redirect_uri FAPI2SP では redirect_uri リクエストパラメーターは必須です。
code_challenge FAPI2SP では PKCE 対応が必須のため、code_challenge リクエストパラメーターを含めます。
code_challenge_method FAPI2SP ではコードチャレンジメソッドとして S256 を使うことが必須のため、明示的に code_challenge_method=S256 を含めます。

PAR リクエストが成功すると、PAR エンドポイントからは request_uri プロパティーを含む JSON が返されます。 下記は PAR 仕様から抜粋した PAR レスポンスの例です。

HTTP/1.1 201 Created
Cache-Control: no-cache, no-store
Content-Type: application/json

{
  "request_uri": "urn:example:bwc4JK-ESC0w8acc191e-Y1LTC2",
  "expires_in": 90
}

request_uri プロパティーの値は、発行されたリクエスト URI です。 このリクエスト URI は、後ほど認可リクエストの request_uri リクエストパラメーターの値として用います。


認可リクエスト

ブラウザ経由で、認可サーバーの認可エンドポイントに認可リクエストを投げます。 その際、PAR エンドポイントから発行されたリクエスト URI を request_uri リクエストパラメーターの値として用います。

${AUTHORIZATION_ENDPOINT}?client_id=${CLIENT_ID}&request_uri=${REQUEST_URI}

認可エンドポイントから返される認可ページでユーザー認証と権限付与同意をおこなうと、認可コードが発行されます。 この認可コードは、後ほどトークンリクエストの code リクエストパラメーターの値として用います。


トークンリクエスト

トークン群生成

トークンリクエストにおいても、クライアント・アテステーションとクライアント・アテステーション・PoP が必要となりますが、PAR リクエスト用に作成したものがまだ有効期限切れしていなければ、再利用可能です。

一方、DPoP Proof JWT は、htu クレームにエンドポイントの URL を設定する必要があるため、PAR リクエスト用に作成したものを再利用することはできません。 -u オプションにトークンエンドポイントの URL を指定して generate-dpop-proof スクリプトを再実行し、DPoP Proof JWT を再生成してください。

DPOP_PROOF=`./generate-dpop-proof \
  -m POST \
  -u ${TOKEN_ENDPOINT} \
  -k client.jwk`

トークンリクエスト送信

トークン群を用意後、トークンリクエストを送信します。

curl ${TOKEN_ENDPOINT} \
  -H "OAuth-Client-Attestation: ${CLIENT_ATTESTATION}" \
  -H "OAuth-Client-Attestation-PoP: ${CLIENT_ATTESTATION_POP}" \
  -H "DPoP: ${DPOP_PROOF}" \
  -d grant_type=authorization_code \
  -d code=${AUTHORIZATION_CODE} \
  -d redirect_uri=${REDIRECT_URI} \
  -d code_verifier=${CODE_VERIFIER}

このリクエストの要点は次の通りです。

項目 説明
クライアント認証 ABCA を用いる場合、OAuth-Client-Attestation HTTP ヘッダと OAuth-Client-Attestation-PoP HTTP ヘッダに、ぞれぞれクライアント・アテステーション、クライアント・アテステーション・PoP を設定します。
送信者限定 DPoP HTTP ヘッダに DPoP Proof JWT を設定します。
grant_type 認可コードフローであることを示すため、authorization_code という値を設定します。
code 認可リクエストの結果発行された認可コードを指定します。
redirect_uri PAR リクエストに含めたのと同一のリダイレクト URI を指定します。
code_verifier PAR リクエストに含めたコード・チャレンジに対応するコード・ベリファイアを指定します。

トークンリクエストが成功すると、トークンエンドポイントからは access_token プロパティーを含む JSON が返されます。

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "zdRKYNzJ0hR99ztiBgd8TTXzQhbattjhtSd-NDykt1A",
  "token_type": "DPoP",
  "expires_in": 86400,
  "scope": "digital_credential haip",
  "refresh_token": "EiHKJFol1UOm7sa9CaKvlnmDH0TP4_takv1I7iWnHI8"
}

access_token プロパティーの値は、発行されたアクセストークンです。 このアクセストークンは、後ほどクレデンシャルリクエストの Authorization HTTP ヘッダに設定します。


クレデンシャルリクエスト

HAIP 仕様を字句通りに解釈すると、必ずしもクレデンシャルリクエストに鍵証明を含める必要はありません。 しかし、現実のユースケースにおいてキー・バインディングを行わないとは考えにくいので、ここで示すクレデンシャルリクエストの例には鍵証明を含めます。


ノンス取得

クレデンシャル・イシュアがノンスエンドポイントを提供している場合、鍵証明やキー・アテステーションにはそのノンスエンドポイントが発行するノンスを含めなければなりません。 クレデンシャル・イシュアがノンスエンドポイントを提供しているかどうかは、クレデンシャル・イシュアのメタデータに nonce_endpoint パラメーターが含まれているかどうかで判定することができます。

ノンスエンドポイントは、HTTP POST リクエストを受け、c_nonce プロパティを含む JSON を返します。下記は OID4VCI 仕様から抜粋したリクエストとレスポンスの例です。

ノンスリクエストの例

POST /nonce HTTP/1.1
Host: credential-issuer.example.com
Content-Length: 0

ノンスレスポンスの例

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
DPoP-Nonce: eyJ7S_zG.eyJH0-Z.HX4w-7v

{
  "c_nonce": "wKI4LT17ac15ES9bw8ac4"
}

NONCE_ENDPOINT というシェル変数にノンスエンドポイントの URL が入っている場合、次のコマンドを実行することでノンスの値を NONCE というシェル変数に代入することができます。

NONCE=`curl ${NONCE_ENDPOINT} \
  -X POST | \
  jq -r .c_nonce`

キー・アテステーション生成

キー・アテステーションは generate-key-attestation スクリプトで生成することができます。 なお、HAIP では x5c ヘッダパラメーターが必須なので、--x5c オプションを用いて x5c ヘッダパラメーターに列挙する X.509 証明書を指定する必要があるので注意してください。 --x5c オプションは複数回指定可能で、指定された順番で X.509 証明書を x5c ヘッダパラメーターに追加していきます。

KEY_ATTESTATION=`./generate-key-attestation \
  --attester-key=keys/key-attester-private.jwk \
  --attested-key=client.jwk \
  --nonce=${NONCE} \
  --x5c=keys/key-attester-certificate.pem`

下記は、生成されるキー・アテステーションのヘッダとペイロードの例です。

{
  "typ": "key-attestation+jwt",
  "alg": "ES256",
  "x5c": [
    "MIIBmDCCAT2gAwIBAgIUTD2qHZdvCkld8qneVGlwL4l+rWAwCgYIKoZIzj0EAwIw
     HDEaMBgGA1UEAwwRS2V5IEF0dGVzdGVyIFJvb3QwIBcNMjYwNDE0MTkwODQ1WhgP
     NDc2NDAzMTExOTA4NDVaMBcxFTATBgNVBAMMDEtleSBBdHRlc3RlcjBZMBMGByqG
     SM49AgEGCCqGSM49AwEHA0IABEj5wOUzDlQKX800+V7kanDu8wASHTw6ivrO2HOW
     keWGUNXaToM14Z4EtyM/szOZYv0UOvsdXNLI1cnZAOgPp3+jYDBeMAwGA1UdEwEB
     /wQCMAAwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBTCXpsU7JVvhynt3n5r5baJ
     xPy21jAfBgNVHSMEGDAWgBRCjxuwwwG/DC9yI5yJ07oD04YvKzAKBggqhkjOPQQD
     AgNJADBGAiEAv3aywa9hsZM5d9zV70GHVP9qmbFleq4SZbmQzIBDNHMCIQDqBvWI
     G9avgr0k6TpwmzhomOTY1H0JigyGaZzuzBe9yQ=="
  ],
  "kid": "qLgVYBf9lZ63QsEz04r9zb4NN3iZnf2-dnoc2k1GWbA"
}
{
  "iat": 1776719761,
  "exp": 1776806161,
  "attested_keys": [
    {
      "crv": "P-256",
      "kty": "EC",
      "x": "1AmVr4GoHdPgk48LWdS3T9m6m1mP4VTcj9usoSBnCQk",
      "y": "te-WIuUIq2w8tXmXydlEX4pe9lNe-PBcozA8n7y8XTE"
    }
  ],
  "nonce": "8aREnUPLVHJT0gswV8dD91YeTBWEKa4YCAd2HpXcOYw"
}

次の点に注目してください。

  • typ ヘッダパラメーターの値が key-attestation+jwt である。
  • x5c ヘッダパラメーターに署名検証用公開鍵の X.509 証明書 (--x5c オプションで指定したもの) が含まれている。
  • attested_keys クレームにアテストされる鍵 (--attested-key オプションで指定したもの) が含まれている。
  • nonce クレームにノンス (--nonce オプションで指定したもの) が設定されている。

鍵証明生成

jwt Proof Type の鍵証明は generate-key-proof スクリプトで生成することができます。

JWT_KEY_PROOF=`./generate-key-proof \
  --client-id=${CLIENT_ID} \
  --issuer=${CREDENTIAL_ISSUER} \
  --key=client.jwk \
  --nonce=${NONCE} \
  --key-attestation=${KEY_ATTESTATION}`

下記は、生成される鍵証明のヘッダとペイロードの例です。

{
  "typ": "openid4vci-proof+jwt",
  "alg": "ES256",
  "jwk": {
    "crv": "P-256",
    "kty": "EC",
    "x": "1AmVr4GoHdPgk48LWdS3T9m6m1mP4VTcj9usoSBnCQk",
    "y": "te-WIuUIq2w8tXmXydlEX4pe9lNe-PBcozA8n7y8XTE"
  },
  "key_attestation":
    "eyJ0eXAiOiJrZXktYXR0ZXN0YXRpb24rand0IiwiYWxnIjoiRVMyNTYiLCJ4NWMi
     OlsiTUlJQm1EQ0NBVDJnQXdJQkFnSVVURDJxSFpkdkNrbGQ4cW5lVkdsd0w0bCty
     V0F3Q2dZSUtvWkl6ajBFQXdJd0hERWFNQmdHQTFVRUF3d1JTMlY1SUVGMGRHVnpk
     R1Z5SUZKdmIzUXdJQmNOTWpZd05ERTBNVGt3T0RRMVdoZ1BORGMyTkRBek1URXhP
     VEE0TkRWYU1CY3hGVEFUQmdOVkJBTU1ERXRsZVNCQmRIUmxjM1JsY2pCWk1CTUdC
     eXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkVqNXdPVXpEbFFLWDgwMCtWN2th
     bkR1OHdBU0hUdzZpdnJPMkhPV2tlV0dVTlhhVG9NMTRaNEV0eU0vc3pPWll2MFVP
     dnNkWE5MSTFjblpBT2dQcDMrallEQmVNQXdHQTFVZEV3RUIvd1FDTUFBd0RnWURW
     UjBQQVFIL0JBUURBZ2VBTUIwR0ExVWREZ1FXQkJUQ1hwc1U3SlZ2aHludDNuNXI1
     YmFKeFB5MjFqQWZCZ05WSFNNRUdEQVdnQlJDanh1d3d3Ry9EQzl5STV5SjA3b0Qw
     NFl2S3pBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQXYzYXl3YTloc1pNNWQ5elY3
     MEdIVlA5cW1iRmxlcTRTWmJtUXpJQkROSE1DSVFEcUJ2V0lHOWF2Z3IwazZUcHdt
     emhvbU9UWTFIMEppZ3lHYVp6dXpCZTl5UT09Il0sImtpZCI6InFMZ1ZZQmY5bFo2
     M1FzRXowNHI5emI0Tk4zaVpuZjItZG5vYzJrMUdXYkEifQ.eyJpYXQiOjE3NzY3M
     Tk3NjEsImV4cCI6MTc3NjgwNjE2MSwiYXR0ZXN0ZWRfa2V5cyI6W3siY3J2IjoiU
     C0yNTYiLCJrdHkiOiJFQyIsIngiOiIxQW1WcjRHb0hkUGdrNDhMV2RTM1Q5bTZtM
     W1QNFZUY2o5dXNvU0JuQ1FrIiwieSI6InRlLVdJdVVJcTJ3OHRYbVh5ZGxFWDRwZ
     TlsTmUtUEJjb3pBOG43eThYVEUifV0sIm5vbmNlIjoiOGFSRW5VUExWSEpUMGdzd
     1Y4ZEQ5MVllVEJXRUthNFlDQWQySHBYY09ZdyJ9.CeDXPV9gfr2x92IHSZ5BcyFf
     RuTK2M5Y4JeHFgijfZeNBytz1QICaxnLOVTZjXYu-JlL21_xkPoODrWTSiDPLg"
}
{
  "iss": "trial_client",
  "aud": "https://trial.authlete.net",
  "iat": 1776720642,
  "nonce": "8aREnUPLVHJT0gswV8dD91YeTBWEKa4YCAd2HpXcOYw"
}

次の点に注目してください。

  • typ ヘッダパラメーターの値が openid4vci-proof+jwt である。
  • jwk ヘッダパラメーターにクライアントの鍵 (--key オプションで指定したもの) が設定されている。
  • key_attestation ヘッダパラメーターにキー・アテステーション (–key-attestation オプションで指定したもの) が設定されている。
  • iss クレームにクライアント識別子 (--client-id オプションで指定したもの) が設定されている。
  • aud クレームにクレデンシャル・イシュア識別子 (--issuer オプションで指定したもの) が設定されている。
  • nonce クレームにノンス (--nonce オプションで指定したもの) が設定されている。

DPoP Proof JWT 生成

-u オプションにクレデンシャルエンドポイントの URL を指定して generate-dpop-proof スクリプトを再実行し、DPoP Proof JWT を再生成します。

なお、クレデンシャルリクエストでは DPoP Proof JWT とアクセストークンを一緒に送信することになるので、DPoP Proof JWT には ath クレームを含めなければなりません。 このため、generate-dpop-proof スクリプトを実行する際、-a オプションを追加してください。

DPOP_PROOF=`./generate-dpop-proof \
  -m POST \
  -u ${CREDENTIAL_ENDPOINT} \
  -k client.jwk \
  -a ${ACCESS_TOKEN}`

クレデンシャルリクエスト送信

鍵証明が用意できたので、クレデンシャルリクエストを送信します。 ここでは、digital_credential スコープが指すクレデンシャル設定の識別子が DigitalCredential であると想定しています。

curl ${CREDENTIAL_ENDPOINT} \
  -H "Authorization: DPoP ${ACCESS_TOKEN}" \
  -H "DPoP: ${DPOP_PROOF}" \
  --json '{
  "credential_configuration_id": "DigitalCredential",
  "proofs": {
    "jwt": ["'${JWT_KEY_PROOF}'"]
  }
}'

このリクエストの要点は次の通りです。

項目 説明
アクセストークン トークンエンドポイントから発行されたアクセストークンを Authorization HTTP ヘッダに設定します。 DPoP-bound なので、スキーム部には DPoP と書きます。
送信者限定 DPoP HTTP ヘッダに DPoP Proof JWT を設定します。
credential_configuration_id クレデンシャルリクエストには credential_configuration_id または credential_identifier のどちらかが必須です。
proofs 鍵証明を指定します。

上記のリクエストでは jwt Proof Type の鍵証明を用いたため、キー・アテステーションを別の JWT に埋め込みました。 一方で、attestation Proof Type の鍵証明であれば、次のようにキー・アテステーションを直接鍵証明として用いることができます。

curl ${CREDENTIAL_ENDPOINT} \
  -H "Authorization: DPoP ${ACCESS_TOKEN}" \
  -H "DPoP: ${DPOP_PROOF}" \
  --json '{
  "credential_configuration_id": "DigitalCredential",
  "proofs": {
    "attestation": ["'${KEY_ATTESTATION}'"]
  }
}'

下記はクレデンシャルレスポンスの例です。

{
  "credentials": [
    {
      "credential":
        "eyJ4NWMiOlsiTUlJQ1NEQ0NBZTZnQXdJQkFnSVVLSlM1R21Ram5mY0JrM1piL2VX
         K0loblFrOHN3Q2dZSUtvWkl6ajBFQXdJd1pURUxNQWtHQTFVRUJoTUNTbEF4RGpB
         TUJnTlZCQWdNQlZSdmEzbHZNUkF3RGdZRFZRUUhEQWREYUdsNWIyUmhNUmN3RlFZ
         RFZRUUtEQTVCZFhSb2JHVjBaU3dnU1c1akxqRWJNQmtHQTFVRUF3d1NkSEpwWVd3
         dVlYVjBhR3hsZEdVdWJtVjBNQ0FYRFRJMU1ESXlOVEExTXpJME9Wb1lEekl5T1Rn
         eE1qRXhNRFV6TWpRNVdqQmxNUXN3Q1FZRFZRUUdFd0pLVURFT01Bd0dBMVVFQ0F3
         RlZHOXJlVzh4RURBT0JnTlZCQWNNQjBOb2FYbHZaR0V4RnpBVkJnTlZCQW9NRGtG
         MWRHaHNaWFJsTENCSmJtTXVNUnN3R1FZRFZRUUREQkowY21saGJDNWhkWFJvYkdW
         MFpTNXVaWFF3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFPZDZU
         Q3ducG5tWHFwczhSUUhxK0s5Tm9vRmJyamIxeXlGeEpsSGs3V2ZUVk9yWkR1OU5x
         K0lPYzl5cm83eStHOXJUZjB6dDhPV0o1aS9XaWpqSUxUbzNvd2VEQWRCZ05WSFE0
         RUZnUVVQTVlhNmZRSlA2TTZ4NHRZTTFmYmYzL0UweE13SHdZRFZSMGpCQmd3Rm9B
         VVBNWWE2ZlFKUDZNNng0dFlNMWZiZjMvRTB4TXdEd1lEVlIwVEFRSC9CQVV3QXdF
         Qi96QWxCZ05WSFJFRUhqQWNoaHBvZEhSd2N6b3ZMM1J5YVdGc0xtRjFkR2hzWlhS
         bExtNWxkREFLQmdncWhrak9QUVFEQWdOSUFEQkZBaUVBeW8zQS9vUVgvTWU4bXlN
         V0wwMjVjVEJ3L2tlY2VIRUxmU1FIbWxlNVFBRUNJQzVnL3luT210L251a3NmSEFl
         TUFCZjd0bzUyelRSa1JkdXFRQ1pITzNlWSJdLCJraWQiOiJaWUdJT0hZdUE5SXBV
         aWpWd1FOdWwzbkU1MzZ4MUpTV0hpT2ZkUzdzYWRnIiwidHlwIjoiZGMrc2Qtand0
         IiwiYWxnIjoiRVMyNTYifQ.eyJfc2QiOlsiM005WU43VXk0RHI0OFdCNEFhNmFEQ
         2NudUhxdi1lRUw2RVFITjBMb3ExbyIsIks2UVZHUmVyOVFId2tDYkpoNW1PVUNLO
         UwtX0luM0pPX2o2eUlQNzVJaGMiLCJQQ1M5dFBvMXlrb2NmV09iYzd0LUVObXU1M
         HdzekY3UTNxZ0MyTFN3dmhRIiwiUS1tdllZWFpfVk9SZlc2ekhXSnhaeC1fNUxwM
         EtNbG1lbGJPSUQ5Z3NyNCIsIlFfTjRKOHJnTnV5QS1Oa2RTVmdNR3pvN0RVM3lrW
         Dk5dk1zVEJzcklLN28iLCJYcjF6RnFETU5kdXp2UDFBZFZqWFV4WlQ5T1RJRW9kd
         TlSRmZ1c2FFYUJJIiwiWVNrSUNPRXI1dzZCY3lEQmVwck5sLXhGMmdheExtOGRaZ
         lp1NVRUcFpiUSIsIll4LXFYdi10a3Babnd6MkJkN1pyOXhlaDBGOE05bnJzdUkxT
         DdvaGlTNEkiLCJkS1pEUDhwYzdLbXlXNkVwSER2TVIxRnd0aDNKN0xoeldNRWgyW
         kh3UXRRIiwiZUFPQ1l0VmN0bVllNnF6eEJvOUh4TE9panZaSlRKSjBBR2pHblJrW
         WdsTSJdLCJ2Y3QiOiJodHRwczovL2NyZWRlbnRpYWxzLmV4YW1wbGUuY29tL2RpZ
         2l0YWxfY3JlZGVudGlhbCIsIl9zZF9hbGciOiJzaGEtMjU2IiwiaXNzIjoiaHR0c
         HM6Ly90cmlhbC5hdXRobGV0ZS5uZXQiLCJjbmYiOnsiandrIjp7Imt0eSI6IkVDI
         iwiY3J2IjoiUC0yNTYiLCJraWQiOiJPUmduOXZ5S2ZKZnI2SmljN1dtaVRFV0pCb
         FRZa1QwZS1JSU9NU3l2SXRvIiwieCI6IjFBbVZyNEdvSGRQZ2s0OExXZFMzVDltN
         m0xbVA0VlRjajl1c29TQm5DUWsiLCJ5IjoidGUtV0l1VUlxMnc4dFhtWHlkbEVYN
         HBlOWxOZS1QQmNvekE4bjd5OFhURSJ9fSwiZXhwIjoxNzc5MzEzOTg5LCJpYXQiO
         jE3NzY3MjE5ODl9.k_BY_BMZVLgNRqutBakVGgpcfq5DbbQdgGsGnTvDWRqZX4KN
         wbzEJd6bHZhIC7Di5_3QS_sUvByHnDpa95NJTw~WyIwbHlrWHpiLTNZR0kwZndVa
         ktMZk5BIiwic3ViIiwiMTAwNCJd~WyJ3Vi04VWk0MUp3eEpmYzN3WnQyaFRRIiwi
         Z2l2ZW5fbmFtZSIsIkluZ2EiXQ~WyJFWlZRUGI0ZFJzY01xa1dheEJmel9nIiwiZ
         mFtaWx5X25hbWUiLCJTaWx2ZXJzdG9uZSJd~WyJrT0ZrLVRFMzVlRlpRVzBrQnpR
         V3FnIiwiYmlydGhkYXRlIiwiMTk5MS0xMS0wNiJd~"
    }
  ]
}

credentials 配列の各要素は JSON オブジェクトであり、それらの credential プロパティの値が発行された VC を表しています。 この例では発行された VC は一つのみで、そのフォーマットは SD-JWT VC となっています。


SD-JWT VC

発行された SD-JWT VC の Issuer-signed JWT 部のヘッダとペイロードをデコードすると次のようになります。

{
  "x5c": [
    "MIICSDCCAe6gAwIBAgIUKJS5GmQjnfcBk3Zb/eW+IhnQk8swCgYIKoZIzj0EAwIw
     ZTELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRva3lvMRAwDgYDVQQHDAdDaGl5b2Rh
     MRcwFQYDVQQKDA5BdXRobGV0ZSwgSW5jLjEbMBkGA1UEAwwSdHJpYWwuYXV0aGxl
     dGUubmV0MCAXDTI1MDIyNTA1MzI0OVoYDzIyOTgxMjExMDUzMjQ5WjBlMQswCQYD
     VQQGEwJKUDEOMAwGA1UECAwFVG9reW8xEDAOBgNVBAcMB0NoaXlvZGExFzAVBgNV
     BAoMDkF1dGhsZXRlLCBJbmMuMRswGQYDVQQDDBJ0cmlhbC5hdXRobGV0ZS5uZXQw
     WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQOd6TCwnpnmXqps8RQHq+K9NooFbrj
     b1yyFxJlHk7WfTVOrZDu9Nq+IOc9yro7y+G9rTf0zt8OWJ5i/WijjILTo3oweDAd
     BgNVHQ4EFgQUPMYa6fQJP6M6x4tYM1fbf3/E0xMwHwYDVR0jBBgwFoAUPMYa6fQJ
     P6M6x4tYM1fbf3/E0xMwDwYDVR0TAQH/BAUwAwEB/zAlBgNVHREEHjAchhpodHRw
     czovL3RyaWFsLmF1dGhsZXRlLm5ldDAKBggqhkjOPQQDAgNIADBFAiEAyo3A/oQX
     /Me8myMWL025cTBw/keceHELfSQHmle5QAECIC5g/ynOmt/nuksfHAeMABf7to52
     zTRkRduqQCZHO3eY"
  ],
  "kid": "ZYGIOHYuA9IpUijVwQNul3nE536x1JSWHiOfdS7sadg",
  "typ": "dc+sd-jwt",
  "alg": "ES256"
}
{
  "_sd": [
    "3M9YN7Uy4Dr48WB4Aa6aDCcnuHqv-eEL6EQHN0Loq1o",
    "K6QVGRer9QHwkCbJh5mOUCK9L-_In3JO_j6yIP75Ihc",
    "PCS9tPo1ykocfWObc7t-ENmu50wszF7Q3qgC2LSwvhQ",
    "Q-mvYYXZ_VORfW6zHWJxZx-_5Lp0KMlmelbOID9gsr4",
    "Q_N4J8rgNuyA-NkdSVgMGzo7DU3ykX99vMsTBsrIK7o",
    "Xr1zFqDMNduzvP1AdVjXUxZT9OTIEodu9RFfusaEaBI",
    "YSkICOEr5w6BcyDBeprNl-xF2gaxLm8dZfZu5TTpZbQ",
    "Yx-qXv-tkpZnwz2Bd7Zr9xeh0F8M9nrsuI1L7ohiS4I",
    "dKZDP8pc7KmyW6EpHDvMR1Fwth3J7LhzWMEh2ZHwQtQ",
    "eAOCYtVctmYe6qzxBo9HxLOijvZJTJJ0AGjGnRkYglM"
  ],
  "vct": "https://credentials.example.com/digital_credential",
  "_sd_alg": "sha-256",
  "iss": "https://trial.authlete.net",
  "cnf": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "kid": "ORgn9vyKfJfr6Jic7WmiTEWJBlTYkT0e-IIOMSyvIto",
      "x": "1AmVr4GoHdPgk48LWdS3T9m6m1mP4VTcj9usoSBnCQk",
      "y": "te-WIuUIq2w8tXmXydlEX4pe9lNe-PBcozA8n7y8XTE"
    }
  },
  "exp": 1779313989,
  "iat": 1776721989
}

次の点に注目してください。

  • typ ヘッダパラメーターの値が dc+sd-jwt である。
  • _sd クレームにディスクロージャ群の SHA-256 ダイジェスト値が列挙されている (ただし偽のダイジェスト値も含む)。
  • _sd_alg クレームがディスクロージャ群のダイジェスト値の計算に用いたハッシュアルゴリズムを示している。
  • SD-JWT VC では必須の vct クレームが含まれている。
  • cnf.jwk クレームに、鍵証明で指定されたクライアント鍵が設定されている。

下記はディスクロージャ群の情報です。

ディスクロージャ WyIwbHlrWHpiLTNZR0kwZndVaktMZk5BIiwic3ViIiwiMTAwNCJd
ダイジェスト eAOCYtVctmYe6qzxBo9HxLOijvZJTJJ0AGjGnRkYglM
ソルト "0lykXzb-3YGI0fwUjKLfNA"
クレーム名 "sub"
クレーム値 "1004"
ディスクロージャ WyJ3Vi04VWk0MUp3eEpmYzN3WnQyaFRRIiwiZ2l2ZW5fbmFtZSIsIkluZ2EiXQ
ダイジェスト 3M9YN7Uy4Dr48WB4Aa6aDCcnuHqv-eEL6EQHN0Loq1o
ソルト "wV-8Ui41JwxJfc3wZt2hTQ"
クレーム名 "given_name"
クレーム値 "Inga"
ディスクロージャ WyJFWlZRUGI0ZFJzY01xa1dheEJmel9nIiwiZmFtaWx5X25hbWUiLCJTaWx2ZXJzdG9uZSJd
ダイジェスト Q-mvYYXZ_VORfW6zHWJxZx-_5Lp0KMlmelbOID9gsr4
ソルト "EZVQPb4dRscMqkWaxBfz_g"
クレーム名 "family_name"
クレーム値 "Silverstone"
ディスクロージャ WyJrT0ZrLVRFMzVlRlpRVzBrQnpRV3FnIiwiYmlydGhkYXRlIiwiMTk5MS0xMS0wNiJd
ダイジェスト Yx-qXv-tkpZnwz2Bd7Zr9xeh0F8M9nrsuI1L7ohiS4I
ソルト "kOFk-TE35eFZQW0kBzQWqg"
クレーム名 "birthdate"
クレーム値 "1991-11-06"

証明書チェーン検証

HAIP では、クライアント・アテステーションとキー・アテステーションは x5c ヘッダパラメーターを含んでいなければなりません。 そのようなアテステーションを受け取った認可サーバーやクレデンシャル・イシュアは、x5c ヘッダパラメーターで指定される証明書チェーンが信頼するルート証明書群のいずれかに繋がることを確認します。 ただし、この確認作業の際に用いるルート証明書群については、HAIP には指定がありません。

とはいえ、HAIP の策定作業が EUDI Wallet を想定して進められていることを鑑みると、HAIP 運用では EU の規制当局が指定するルート証明書を用いることを要求されるだろうことは容易に想像がつきます。 このような状況下では、汎用的な HAIP 実装は、検証に用いるルート証明書群を設定する機能を用意しておくのがよいでしょう。

そういうわけで、Authlete も次のようなプロパティ群をサービスに新設しました。

プロパティ名 説明
clientAttesterRoots OAuth 2.0 Attestation-Based Client Authentication で定義されているクライアント・アテステーションが x5c ヘッダパラメーターを含んでいる場合、Authlete は指定された証明書チェーンを検証します。その検証の際、このプロパティ (clientAttesterRoots) で指定された X.509 証明書群を信頼済みのルート証明書群として利用します。ただし、これらの証明書群を利用すると明示的に設定されている場合に限ります。具体的には、clientAttesterRootsEnabled プロパティの値が true と設定されている場合に限ります。

指定されたルート証明書群で検証をパスできなかった場合、システムにインストール済みのルート証明書群を用いて検証がおこなわれます。ただし、システムのルート証明書群を参照しないように設定されている場合、具体的には clientAttesterRootsOnly プロパティの値が true と設定されている場合、システムのルート証明書群は参照されません。

このプロパティで設定する証明書のフォーマットは PEM としてください。ただし、PEM マーカー (—–BEGIN CERTIFICATE—–—–END CERTIFICATE—–) は省略可能です。なお、Authlete API がこのプロパティの値を返す際は、たとえ設定時に PEM マーカーが省略されていたとしても、PEM マーカーが含まれます。

OAuth 2.0 Attestation-Based Client Authentication はクライアント・アテステーションが x5c ヘッダパラメーターを含むことを要求しません。しかし、OpenID4VC High Assurance Interoperability Profile 1.0 では必須とされているので注意してください。サービスの haipVersion プロパティやクライアントの haipVersion プロパティに値が設定されていたり、haip 属性を持つスコープをリクエストに含めると、HAIP が有効になり、結果としてクライアント・アテステーションの x5c ヘッダパラメーターが必須となります。
clientAttesterRootsEnabled クライアント・アテステーション証明書チェーンの検証用ルート証明書群、具体的には clientAttesterRoots プロパティに設定された X.509 証明書群を、クライアント・アテステーションの x5c ヘッダパラメーターに指定された証明書チェーンを検証する際に利用するかどうかを設定します。このプロパティ (clientAttesterRootsEnabled) を明示的に有効化しないと (true を設定しないと)、たとえ clientAttesterRoots プロパティを設定しても、それらのルート証明書群は利用されません。
clientAttesterRootsOnly クライアント・アテステーションの x5c ヘッダパラメーターに指定された証明書チェーンを検証する際に、それ専用に設定されたルート証明書群、具体的には clientAttesterRoots プロパティに設定された証明書群のみを用いて検証をおこなうかどうかを設定します。このプロパティ (clientAttesterRootsOnly) が有効になっていると (true が設定されていると)、システムにインストールされているルート証明書群は検証に利用されません。
keyAttesterRoots OpenID for Verifiable Credential Issuance 1.0, Appendix D. Key Attestations で定義されているキー・アテステーションが x5c ヘッダパラメーターを含んでいる場合、Authlete は指定された証明書チェーンを検証します。その検証の際、このプロパティ (keyAttesterRoots) で指定された X.509 証明書群を信頼済みのルート証明書群として利用します。ただし、これらの証明書群を利用すると明示的に設定されている場合に限ります。具体的には、keyAttesterRootsEnabled プロパティの値が true と設定されている場合に限ります。

指定されたルート証明書群で検証をパスできなかった場合、システムにインストール済みのルート証明書群を用いて検証がおこなわれます。ただし、システムのルート証明書群を参照しないように設定されている場合、具体的には keyAttesterRootsOnly プロパティの値が true と設定されている場合、システムのルート証明書群は参照されません。

このプロパティで設定する証明書のフォーマットは PEM としてください。ただし、PEM マーカー (—–BEGIN CERTIFICATE—–—–END CERTIFICATE—–) は省略可能です。なお、Authlete API がこのプロパティの値を返す際は、たとえ設定時に PEM マーカーが省略されていたとしても、PEM マーカーが含まれます。

OpenID for Verifiable Credential Issuance 1.0 はキー・アテステーションが x5c ヘッダパラメーターを含むことを要求しません。しかし、OpenID4VC High Assurance Interoperability Profile 1.0 では必須とされているので注意してください。サービスの haipVersion プロパティやクライアントの haipVersion プロパティに値が設定されていたり、haip 属性を持つスコープをリクエストに含めると、HAIP が有効になり、結果としてキー・アテステーションの x5c ヘッダパラメーターが必須となります。
keyAttesterRootsEnabled キー・アテステーション証明書チェーンの検証用ルート証明書群、具体的には keyAttesterRoots プロパティに設定された X.509 証明書群を、キー・アテステーションの x5c ヘッダパラメーターに指定された証明書チェーンを検証する際に利用するかどうかを設定します。このプロパティ (keyAttesterRootsEnabled) を明示的に有効化しないと (true を設定しないと)、たとえ keyAttesterRoots プロパティを設定しても、それらのルート証明書群は利用されません。
keyAttesterRootsOnly キー・アテステーションの x5c ヘッダパラメーターに指定された証明書チェーンを検証する際に、それ専用に設定されたルート証明書群、具体的には keyAttesterRoots プロパティに設定された証明書群のみを用いて検証をおこなうかどうかを設定します。このプロパティ (keyAttesterRootsOnly) が有効になっていると (true が設定されていると)、システムにインストールされているルート証明書群は検証に利用されません。

下記は、クライアント・アテステーションとキー・アテステーションの証明書チェーンの検証に用いるルート証明書群の設定例です。

{
  "clientAttesterRoots": [
    "-----BEGIN CERTIFICATE-----\n
     MIIBpTCCAUugAwIBAgIUUTw+Ep5ZOdplQAjzE/68Z9IUzzgwCgYIKoZIzj0EAwIw\n
     HzEdMBsGA1UEAwwUQ2xpZW50IEF0dGVzdGVyIFJvb3QwIBcNMjYwNDE0MTU0MzQ1\n
     WhgPNDc2NDAzMTExNTQzNDVaMB8xHTAbBgNVBAMMFENsaWVudCBBdHRlc3RlciBS\n
     b290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyRlNlUPzTt6jF5s0ltIjoGHx\n
     SFQu6GE+gZOMm5sOrNGmAaI6i48CSI6yrXpr/F0KV6t4IH9FcKsZWrpIA7evz6Nj\n
     MGEwHQYDVR0OBBYEFDmGsWAPAWFDwW4IlARNSXJ3amPSMB8GA1UdIwQYMBaAFDmG\n
     sWAPAWFDwW4IlARNSXJ3amPSMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\n
     AgEGMAoGCCqGSM49BAMCA0gAMEUCIQCXxFHg356YWT2gEIdU0Vdm2znUMRwm7Wgb\n
     Jf9GbLDvggIgK98PHmvP8WRqPfQr1cNpSSBoogDhZhLcelvm/L0coLA=\n
     -----END CERTIFICATE-----"
  ],
  "clientAttesterRootsEnabled": true,
  "clientAttesterRootsOnly": false,
  "keyAttesterRoots": [
    "-----BEGIN CERTIFICATE-----\n
     MIIBoDCCAUWgAwIBAgIUWRZNOcKwPKKFYiMHguS6ZS81IPUwCgYIKoZIzj0EAwIw\n
     HDEaMBgGA1UEAwwRS2V5IEF0dGVzdGVyIFJvb3QwIBcNMjYwNDE0MTkwNzUxWhgP\n
     NDc2NDAzMTExOTA3NTFaMBwxGjAYBgNVBAMMEUtleSBBdHRlc3RlciBSb290MFkw\n
     EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7RNVRube8DDaZ1zYjBe3vPQFB8WVVqJ/\n
     AAIxUd2HdgLd+7x6EU1T7aHQ5r/ARQpLeYsqiou02jwQoDW+rtNozaNjMGEwHQYD\n
     VR0OBBYEFEKPG7DDAb8ML3IjnInTugPThi8rMB8GA1UdIwQYMBaAFEKPG7DDAb8M\n
     L3IjnInTugPThi8rMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoG\n
     CCqGSM49BAMCA0kAMEYCIQCtbIlRnFUs7QSuQZkv6NCxiK0Ui8V/P+gcq/70nWBk\n
     yQIhAOowEiHzVvY1iTGYJ2at2Z1UigC3rq2q/E2A70AS8gc5\n
     -----END CERTIFICATE-----"
  ],
  "keyAttesterRootsEnabled": true,
  "keyAttesterRootsOnly": false
}

HAIP 有効化

認可サーバーやクレデンシャル・イシュアへのリクエストに対して HAIP バリデーションを実行するかどうかを決める方法は、実装依存です。 Authlete は次の三つの方法を提供しています。

有効化方法 説明
サービスの haipVersion プロパティー サービスの haipVersion プロパティーに値が設定されている場合、そのサービスへのリクエストに対して常に HAIP バリデーションが実行されます。
クライアントの haipVersion プロパティー クライアントの haipVersion プロパティーに値が設定されている場合、そのクライアントからのリクエストに対して常に HAIP バリデーションが実行されます。
スコープの haip 属性 リクエストが、haip 属性に有効な値が設定されているスコープを含んでいる場合、そのリクエストに対して HAIP バリデーションが実行されます。

haipVersion プロパティーや haip 属性に設定することが可能な値は、現時点 (2026 年 4 月) の Authlete の実装では 1.0 (文字列) のみです。


おわりに

HAIP は VC 関連仕様の相互運用性とセキュリティを高めるためのプロファイルです。 この文書で紹介した HAIP 関連の機能は、Authlete バージョン 3.0.31 以降で利用可能です。 詳細についてはコンタクトフォームからお問い合わせください。