【Hyperledger Aries】ACA-Pyと3つのコネクション生成プロトコル

SSI

こんにちは。GMOグローバルサイン・ホールディングスCTO室で分散型IDの研究開発をしている神沼@t_kanumaです。

HyperLedger AriesではAgent同士を接続するために以下の3つのプロトコルが用意されています。

  1. Aries RFC 0160: Connection Protocol
  2. Aries RFC 0023: DID Exchange Protocol 1.0
  3. Aries RFC 0434: Out-of-Band Protocol 1.1

端的にいうと、DID ExchangeはConnection Protocolの後継であり、Agent間でのメッセージ交換において、正規のDID Documentフォーマットを使用するモノです。(Connection ProtocolはW3CのDID Documentのフォーマットに則っていない。)
そして、Out-of-Bandは、他の2つをラップする仕様であり、おそらく一番望ましい形というのはDID Exchange in Out-Of-Bandとして使うということになるのではと考えます。

RFC上3つとも状態がACCEPTEDになっており、ACA-Pyでも既に実装されています。
(ただし備考として、2022/7/1現在、ACA-PyがサポートするRFCの一覧に以下の注釈がある通り、AIP1.0から2.0へのアップデートの最中であり、DID Exchangeにおいては、コネクションで交換するDID DocumentのフォーマットがW3Cの仕様に準拠していなかったり、Aries固有のPairwise DIDはdid:peerとして機能するものの、method specific identifierのみで表現されていたりと、完全に仕様通りの実装ではない模様です。)

Not using DIDDoc conventions yet, still using DID format of 0160-connections (which is incorrect and outdated). Also using incorrect format for did:peer (or not using a did: prefix at all)

この記事ではACA-Pyの起動パラメーター、およびAdmin APIによるリクエスト/レスポンスに焦点を当てて、プロトコルごとにコネクションを生成し、そこからそれぞれの差異を探ってみます。

備考

各プロトコルにおける開始から完了までの詳細なシーケンス、状態遷移、その中でどのようにDIDと、公開鍵とサービスエンドポイントを含むDIDDocを交換するか、そしてそれを安全に交換するために使う暗号方式など詳細な仕組みについては、上記のそれぞれのRFCをご参照ください。

またここについては筆者がDIF Japan Monthly Syncで登壇した際にDIDComm v1、DID Exchange、およびOut-Of-Bandについて述べています。以下、資料です。

Hyperledger Ariesの全体像、現況、アプリ開発手法について(Slide No.37~42)

前提

Hyperledger Indy/Ariesとは何か、またAriesのアーキテクチャなどについては以下の拙著をご参照ください。

また当記事ではローカルに環境を構築します。
以下の拙著の内容を前提にしていますので軽く目を通した上でお進みください。

利用するOSSのバージョンはこの拙著と同様です。

  • ACA-Py: 0.7.3
  • von-network: 1.7.2

Agent間のコネクションについて

現在主流のクライアント(ブラウザ、モバイル)と中央集権的サーバのモデルと比較した時の、SSI/VCモデルにおける大きな特徴、肝の1つは、各Agent(Issuer、Holder、Verifier)がP2Pでやりとりすることです。つまりは、VC発行、Proof検証、およびメッセージ交換においてIssuer、Holder、Verifierは対等の立場でやりとりするわけですが、Hyperledger Indy/Ariesにおいては、そのための最初の一歩がAgent間でのコネクションの生成です。

動作確認

ではここから、ACA-Pyを使ってそれぞれのプロトコルでコネクションを作る手順を追っていきます。

環境

ローカル環境にて以下のようにシンプルに2つのACA-Pyを繋ぎます。
AliceについてはIndy LedgerにPublic DIDを持ちます。

以下、AliceのPublic DIDです。

また、全てのプロトコルが自動的に進むように以下の起動パラメータを付与しています。

  • auto-accept-invites
  • auto-accept-requests
  • auto-ping-connection

1. Connection Protocol

これまでの私のHyperledger Indy/Ariesに関する記事では、Agent間のコネクションの生成にこのプロトコルを利用していました。

ここでは以下の2つのパターンをそれぞれ述べます。

  • AliceとBob両者ともにPairwise DIDを使いコネクションを張る。
  • AliceはPublic DIDをBobはPairwise DIDを使いコネクションを張る。

このプロトコルで重要なポイントは、Invitationの受け渡しをVCモデルの外で行うことです。メールやQRコードなどを用いて信頼できる経路で受け渡す必要があります。

両者ともPairwise DIDのパターン

AliceのAdmin APIにてInvitationを作成します。

# request
curl -X 'POST' \
  'http://localhost:8071/connections/create-invitation' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "my_label": "Alice",
  "service_endpoint": "http://172.19.0.7:8070"
}'

# response
{
  "connection_id": "c1a08ec4-e5e4-437b-bfbf-8d1dd5abbb05",
  "invitation": {
    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
    "@id": "9168506f-9ddf-44cd-a8c2-e6511a1bfdcb",
    "label": "Alice",
    "recipientKeys": [
      "2ny34rVedF4EtYFuhkFvF37MSLzc2k6HrPyrTGiyZHSf"
    ],
    "serviceEndpoint": "http://172.19.0.7:8070"
  },
  "invitation_url": "http://172.19.0.7:8070?c_i=eyJAdHlwZSI6ICJkaWQ6c292OkJ6Q2JzTlloTXJqSGlxWkRUVUFTSGc7c3BlYy9jb25uZWN0aW9ucy8xLjAvaW52aXRhdGlvbiIsICJAaWQiOiAiOTE2ODUwNmYtOWRkZi00NGNkLWE4YzItZTY1MTFhMWJmZGNiIiwgImxhYmVsIjogIkFsaWNlIiwgInJlY2lwaWVudEtleXMiOiBbIjJueTM0clZlZEY0RXRZRnVoa0Z2RjM3TVNMemMyazZIclB5clRHaXlaSFNmIl0sICJzZXJ2aWNlRW5kcG9pbnQiOiAiaHR0cDovLzE3Mi4xOS4wLjc6ODA3MCJ9"
}

invitationオブジェクトを抜き出し、BobのAdmin APIにてそれを受容します。

# request
curl -X 'POST' \
  'http://localhost:8081/connections/receive-invitation' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
    "@id": "9168506f-9ddf-44cd-a8c2-e6511a1bfdcb",
    "label": "Alice",
    "recipientKeys": [
      "2ny34rVedF4EtYFuhkFvF37MSLzc2k6HrPyrTGiyZHSf"
    ],
    "serviceEndpoint": "http://172.19.0.7:8070"
  }'

# response
{
  "updated_at": "2022-06-17T04:52:35.424804Z",
  "their_label": "Alice",
  "my_did": "BzHCmN1fsDWAaefGrp1gjv",
  "routing_state": "none",
  "connection_id": "6c898108-0f0f-4813-9f87-4c2a8b5e6ebb",
  "request_id": "7315b18c-a197-4094-a8bb-df56a570fce7",
  "connection_protocol": "connections/1.0",
  "invitation_msg_id": "9168506f-9ddf-44cd-a8c2-e6511a1bfdcb",
  "accept": "auto",
  "rfc23_state": "request-sent",
  "invitation_key": "2ny34rVedF4EtYFuhkFvF37MSLzc2k6HrPyrTGiyZHSf",
  "created_at": "2022-06-17T04:52:35.408156Z",
  "their_role": "inviter",
  "state": "request",
  "invitation_mode": "once"
}

前述の通り、AliceとBobの両ACA-Pyの起動パラメータで自動的にプロトコルが進められる設定のため、微小な時間経過で状態がActiveになりコネクションの生成が完了します。
Alice側からコネクションの状態を確認します。(Bob側からでも状態の結果は同様です。)

# request
curl -X 'GET' \
  'http://localhost:8071/connections' \
  -H 'accept: application/json'

# response
{
  "results": [
    {
      "state": "active",
      "their_did": "35BBBVrU4tJqz8ukWu5n6t",
      "my_did": "81gxgzXViqbDWKUe2o4bgU",
      "connection_id": "c1a08ec4-e5e4-437b-bfbf-8d1dd5abbb05",
      "connection_protocol": "connections/1.0",
      "created_at": "2022-06-17T04:50:17.333144Z",
      "updated_at": "2022-06-17T04:50:51.111923Z",
      "invitation_mode": "once",
      "their_label": "connection-bob",
      "invitation_key": "2ny34rVedF4EtYFuhkFvF37MSLzc2k6HrPyrTGiyZHSf",
      "their_role": "invitee",
      "rfc23_state": "completed",
      "accept": "auto",
      "routing_state": "none"
    }
  ]
}

AliceのみPublic DIDのパターン

続いて片方のAgentだけPublic DIDにするパターンです。
この場合、ACA-Pyの起動に際し、以下のパラメーターを付与する必要があります。

 --public-invites

Alice側でInvitationを作成します。
“public=true”のクエリパラメーターを付与します。

# request
curl -X 'POST' \
  'http://localhost:8031/connections/create-invitation?public=true' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "my_label": "Alice",
  "service_endpoint": "http://172.19.0.3:8030"
}'

# response
{
  "connection_id": null,
  "invitation": {
    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
    "@id": "81290b11-4831-4aed-aa96-c5de8883aeb2",
    "did": "did:sov:Vtw2qgmuMVy3rk2ipw7Vxt",
    "label": "Alice"
  },
  "invitation_url": "?c_i=eyJAdHlwZSI6ICJkaWQ6c292OkJ6Q2JzTlloTXJqSGlxWkRUVUFTSGc7c3BlYy9jb25uZWN0aW9ucy8xLjAvaW52aXRhdGlvbiIsICJAaWQiOiAiODEyOTBiMTEtNDgzMS00YWVkLWFhOTYtYzVkZTg4ODNhZWIyIiwgImRpZCI6ICJkaWQ6c292OlZ0dzJxZ211TVZ5M3JrMmlwdzdWeHQiLCAibGFiZWwiOiAiQWxpY2UifQ=="
}

レスポンスを覗くと、InvitationのDIDには、Alice起動前にIndy Ledgerに登録したAliceのPublic DIDになっていることがわかります。

Bob側でInvitationを受容します。

# request
curl -X 'POST' \
  'http://localhost:8081/connections/receive-invitation?alias=Bob' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
    "@id": "81290b11-4831-4aed-aa96-c5de8883aeb2",
    "did": "did:sov:Vtw2qgmuMVy3rk2ipw7Vxt",
    "label": "Alice"
  }'

# response
  "updated_at": "2022-06-22T02:01:57.485773Z",
  "their_label": "Alice",
  "my_did": "KTpmWdW9c2goDpZcnd6Gxq",
  "routing_state": "none",
  "connection_id": "d3064ae4-4026-42c2-bcf5-a737c594570d",
  "request_id": "512c0c17-8688-4ca1-bb48-ce3260be375b",
  "alias": "Bob",
  "connection_protocol": "connections/1.0",
  "invitation_msg_id": "81290b11-4831-4aed-aa96-c5de8883aeb2",
  "accept": "auto",
  "rfc23_state": "request-sent",
  "created_at": "2022-06-22T02:01:57.452614Z",
  "their_role": "inviter",
  "state": "request",
  "invitation_mode": "once"
}

Alice側からコネクションの状態を確認します。(Admin APIレスポンスのみ記載)
状態がActiveになっていることがわかります。

   {
      "my_did": "WXRgorX93PiDYrFf3FV5T4",
      "rfc23_state": "completed",
      "connection_id": "2ad280b6-59f7-4c2d-a89e-b422b9f3c5d3",
      "their_label": "connection-bob",
      "state": "active",
      "created_at": "2022-06-22T02:01:57.892412Z",
      "routing_state": "none",
      "accept": "auto",
      "invitation_mode": "once",
      "updated_at": "2022-06-22T02:01:58.392233Z",
      "their_did": "KTpmWdW9c2goDpZcnd6Gxq",
      "their_role": "inviter",
      "connection_protocol": "connections/1.0",
      "invitation_key": "GkSW51oCZKvRK8sHD2om2VBqDzHt41K7v22J9NqtGqaC"
    }

Bob側からも確認です。

    {
      "updated_at": "2022-06-22T02:01:58.492253Z",
      "their_label": "Alice",
      "my_did": "KTpmWdW9c2goDpZcnd6Gxq",
      "routing_state": "none",
      "their_did": "WXRgorX93PiDYrFf3FV5T4",
      "connection_id": "d3064ae4-4026-42c2-bcf5-a737c594570d",
      "request_id": "512c0c17-8688-4ca1-bb48-ce3260be375b",
      "alias": "Bob",
      "connection_protocol": "connections/1.0",
      "invitation_msg_id": "81290b11-4831-4aed-aa96-c5de8883aeb2",
      "accept": "auto",
      "rfc23_state": "completed",
      "created_at": "2022-06-22T02:01:57.452614Z",
      "their_role": "inviter",
      "state": "active",
      "invitation_mode": "once"
    }

my_did(their_did)を確認すると、コネクション生成の起点として、Endpoint情報などの取得のためAliceのPublic DIDに紐づくDID Documentを利用したと思われるものの、実際にコネクションに対応するAliceのDIDは、PublicではなくPairwiseになっていることがわかります。つまりIndy Ledger上のDIDはあくまでVCに署名する目的に存在し、Agent間のP2P通信にはdid:peer相当のPairwise DIDを使うと整理することができます。

以上、Connection Protocolでコネクションを生成することができました。

2. DID Exchange Protocol 1.0

DID Exchangeの場合、後述のOut-Of-Bandと組み合わせることで、前述のConnection Protocol同様に、メールなどのVCモデルの外でInvitationをセキュアに受渡して、コネクションを作ることができるようです。これに加えて、もう1つ手法があり、InviteeがPublic DIDの場合、Inviterは相手のService EndpointをDID Docから知ることができるため、メールなどを介さなくても直接相手のEndpointにConnection要求を送ることができます。ここではこの後者を試します。

DID Exchangeのために以下のEndpointが用意されています。

まずBob側から始めます。Admin API上、Exchange Protocolでは相手側のPublic DIDを指定する必要があるようです。(Out-Of-Bandとの併用ではなく、DID Exchange単体の場合は、Agentの片方または両方がPublic DIDを持つ前提のようです。)

クエリパラメーターにAliceのPublic DID(did:sov:Vtw2qgmuMVy3rk2ipw7Vxt)と、自身のEndpointを指定して、DID Exchangeのリクエストを出します。

# request
curl -X 'POST' \
  'http://localhost:8081/didexchange/create-request?their_public_did=did%3Asov%3AVtw2qgmuMVy3rk2ipw7Vxt&my_endpoint=http%3A%2F%2F172.19.0.8%3A8080&my_label=Bob' \
  -H 'accept: application/json' \
  -d ''

# response
{
  "updated_at": "2022-06-22T02:42:46.946776Z",
  "their_public_did": "did:sov:Vtw2qgmuMVy3rk2ipw7Vxt",
  "my_did": "2vrU8HWcZfT8fk9oHbwHtU",
  "routing_state": "none",
  "their_did": "did:sov:Vtw2qgmuMVy3rk2ipw7Vxt",
  "connection_id": "6ad0658c-3d85-40a0-8831-1be6d1f3e578",
  "request_id": "abaf6d00-b784-4d2d-a4d7-0bfee2b87898",
  "connection_protocol": "didexchange/1.0",
  "accept": "manual",
  "rfc23_state": "request-sent",
  "created_at": "2022-06-22T02:42:46.943030Z",
  "their_role": "inviter",
  "state": "request",
  "invitation_mode": "once"
}

レスポンスを見ると、しっかりとコネクションのプロトコルがDID Exchange 1.0になっていることがわかります。

ここでAlice側からコネクションを確認します。(Admin APIのレスポンスのみ記載)

    {
      "request_id": "abaf6d00-b784-4d2d-a4d7-0bfee2b87898",
      "my_did": "BzoPvN7uoAogbCpUbgwx5t",
      "rfc23_state": "completed",
      "connection_id": "fc271b41-d04a-471b-a405-4855ed32671e",
      "their_label": "Bob",
      "state": "active",
      "created_at": "2022-06-22T02:42:47.354417Z",
      "routing_state": "none",
      "accept": "auto",
      "invitation_mode": "once",
      "updated_at": "2022-06-22T02:42:47.888568Z",
      "their_did": "2vrU8HWcZfT8fk9oHbwHtU",
      "their_role": "invitee",
      "connection_protocol": "didexchange/1.0",
      "invitation_key": "GkSW51oCZKvRK8sHD2om2VBqDzHt41K7v22J9NqtGqaC"
    }

次はBob側です。

    {
      "updated_at": "2022-06-22T02:42:47.679583Z",
      "their_public_did": "did:sov:Vtw2qgmuMVy3rk2ipw7Vxt",
      "my_did": "2vrU8HWcZfT8fk9oHbwHtU",
      "routing_state": "none",
      "their_did": "BzoPvN7uoAogbCpUbgwx5t",
      "connection_id": "6ad0658c-3d85-40a0-8831-1be6d1f3e578",
      "request_id": "abaf6d00-b784-4d2d-a4d7-0bfee2b87898",
      "connection_protocol": "didexchange/1.0",
      "accept": "manual",
      "rfc23_state": "completed",
      "created_at": "2022-06-22T02:42:46.943030Z",
      "their_role": "inviter",
      "state": "active",
      "invitation_mode": "once"
    }

以下、レスポンスから読み取れるポイントです。

  • Bob側でDID Exchangeのリクエストを出しただけでしたが、両側でコネクションの状態がActiveになりコネクションが生成されています。このことから、前述のプロトコルを自動で進めるACA-Pyの起動パラメーターは、DID Exchangeについても効いていると考えます。
  • コネクション生成の起点はPublic DIDにしていますが、Connection Protocol同様、実際のDIDはPairwiseを使っています。
  • Connection Protocolではコネクションを張る相手がPublic DIDを持っていてもInvitaitonをVCモデル外の安全なルートで渡す必要がありましたが、ここではその必要がありません。相手がPublic DIDを持つ際はDID Exchange Protocolを使った方がセキュリティ面で良いと考えます。

以上、DID Exchange Protocolでコネクションを生成することができました。

3. Out-Of-Band Protocol 1.1

このプロトコルのモチベーションはドキュメントにある通り、4つありますが、中でも2番目の”Inviterがオファーするリストから、Inviteeがコネクション生成のためのプロトコル(現時点だとConnection ProtocolもしくはDID Exchange Protocolのどちらか)を選択できる”というのが大きなポイントかと考えます。(前述の通り、Out-Of-BandはConnection/DID Exchange Protocolをラップしている仕様だと理解しています。)

以下、モチベーションの1番目である”一度生成したコネクションを再利用できる”ことを確認します。

例えば、Issuerが提示するQRコードをHolderが読み込み、コネクション生成からVerifiable Credential発行までユーザー視点でバックグラウンドで一気に行うケースを考えます。VCを再発行する目的でQRコードを読み込んだ際、Out-Of-Band Protocolを使えば既存のコネクションを再利用することができ、リソースを無駄なく利用できます。

ここでは上記2つのプロトコルとの差として、コネクションの再利用ができるかどうかを確かめます。

このGitHub Issueによれば、コネクションの再利用には片方がPublic DIDを持つ必要があるようです。前提として先のDID Exchange Protocolにて以下のコネクションを作成してあります。

(ちなみにですが、上記のDID Exchange Protocolを試した際は、Bob側Admin APIのクエリパラメーター”their_public_did”に”did:sov:Vtw2qgmuMVy3rk2ipw7Vxt”とDIDの正規の形式で指定していましたが、この形式だとOut-Of-Band Protocolでコネクションの再利用ができませんでした。今回はスキームとメソッドつまり”did:sov”の部分を消してDID Exchangeによるコネクション生成しています。DID Exchangeとしては”did:sov”の有無は現状、影響しないようです。)

Alice側の既存コネクション情報

    {
      "request_id": "732f73d9-af82-4648-b86a-aeeb80dc6ec4",
      "my_did": "HADN8y4ztbMXsHCFc1fzHa",
      "rfc23_state": "completed",
      "connection_id": "44586e2b-1f5b-4f08-a25a-8196cf56087f",
      "their_label": "connection-bob",
      "state": "active",
      "created_at": "2022-06-22T03:37:23.310383Z",
      "routing_state": "none",
      "accept": "auto",
      "invitation_mode": "once",
      "updated_at": "2022-06-22T03:45:00.102988Z",
      "invitation_msg_id": "f0ee58b4-9e3b-4b6d-aff5-4c0a589467c5",
      "their_did": "DdEHPMZ2wjcRu2cwbFc7Zf",
      "their_role": "invitee",
      "connection_protocol": "didexchange/1.0",
      "invitation_key": "GkSW51oCZKvRK8sHD2om2VBqDzHt41K7v22J9NqtGqaC"
    }

Bob側の既存コネクション情報

    {
      "updated_at": "2022-06-22T03:45:00.159548Z",
      "their_public_did": "Vtw2qgmuMVy3rk2ipw7Vxt",
      "my_did": "DdEHPMZ2wjcRu2cwbFc7Zf",
      "routing_state": "none",
      "their_did": "HADN8y4ztbMXsHCFc1fzHa",
      "connection_id": "e7993980-809e-4075-8580-c248b78597c5",
      "request_id": "732f73d9-af82-4648-b86a-aeeb80dc6ec4",
      "connection_protocol": "didexchange/1.0",
      "invitation_msg_id": "f0ee58b4-9e3b-4b6d-aff5-4c0a589467c5",
      "accept": "manual",
      "rfc23_state": "completed",
      "created_at": "2022-06-22T03:37:22.945397Z",
      "their_role": "inviter",
      "state": "active",
      "invitation_mode": "once"
    }

Out-Of-Bandが構えるEndpointは以下の通りです。
Connection Protocol同様、InvitationをVCモデル外で相手に渡す必要があります。

まずPublic DIDを持つAlice側からOut-Of-BandでInvitationを作成します。
ポイントとしてはボディの中で”use_public_did:true”を指定する必要があります。

# request
curl -X 'POST' \
  'http://localhost:8031/out-of-band/create-invitation' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "handshake_protocols": [
    "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/didexchange/1.0"
  ],
  "my_label": "Alice",
  "use_public_did": true
}'

# response
{
  "invi_msg_id": "f0ee58b4-9e3b-4b6d-aff5-4c0a589467c5",
  "trace": false,
  "invitation": {
    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/out-of-band/1.0/invitation",
    "@id": "f0ee58b4-9e3b-4b6d-aff5-4c0a589467c5",
    "services": [
      "did:sov:Vtw2qgmuMVy3rk2ipw7Vxt"
    ],
    "handshake_protocols": [
      "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/didexchange/1.0"
    ],
    "label": "Alice"
  },
  "state": "initial",
  "invitation_url": "http://172.19.0.3:8030?oob=eyJAdHlwZSI6ICJkaWQ6c292OkJ6Q2JzTlloTXJqSGlxWkRUVUFTSGc7c3BlYy9vdXQtb2YtYmFuZC8xLjAvaW52aXRhdGlvbiIsICJAaWQiOiAiZjBlZTU4YjQtOWUzYi00YjZkLWFmZjUtNGMwYTU4OTQ2N2M1IiwgInNlcnZpY2VzIjogWyJkaWQ6c292OlZ0dzJxZ211TVZ5M3JrMmlwdzdWeHQiXSwgImhhbmRzaGFrZV9wcm90b2NvbHMiOiBbImRpZDpzb3Y6QnpDYnNOWWhNcmpIaXFaRFRVQVNIZztzcGVjL2RpZGV4Y2hhbmdlLzEuMCJdLCAibGFiZWwiOiAiQWxpY2UifQ=="
}

invitationオブジェクトのみを抜き出しBob側で受容します。

# request
curl -X 'POST' \
  'http://localhost:8081/out-of-band/receive-invitation?use_existing_connection=true' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/out-of-band/1.0/invitation",
    "@id": "f0ee58b4-9e3b-4b6d-aff5-4c0a589467c5",
    "services": [
      "did:sov:Vtw2qgmuMVy3rk2ipw7Vxt"
    ],
    "handshake_protocols": [
      "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/didexchange/1.0"
    ],
    "label": "Alice"
  }'

# response
{
  "updated_at": "2022-06-22T03:45:00.159548Z",
  "their_public_did": "Vtw2qgmuMVy3rk2ipw7Vxt",
  "my_did": "DdEHPMZ2wjcRu2cwbFc7Zf",
  "routing_state": "none",
  "their_did": "HADN8y4ztbMXsHCFc1fzHa",
  "connection_id": "e7993980-809e-4075-8580-c248b78597c5",
  "request_id": "732f73d9-af82-4648-b86a-aeeb80dc6ec4",
  "connection_protocol": "didexchange/1.0",
  "invitation_msg_id": "f0ee58b4-9e3b-4b6d-aff5-4c0a589467c5",
  "accept": "manual",
  "rfc23_state": "completed",
  "created_at": "2022-06-22T03:37:22.945397Z",
  "their_role": "inviter",
  "state": "active",
  "invitation_mode": "once"
}

Invitationを受容した時点で状態がActiveになっており、自身と相手のDID(my_did/their_did)、そしてconnection_idが、前述の既存コネクションのそれになっています。また全てのコネクション情報を取得しても新しくは作られていませんでした。

以上のことから、既存のコネクションの再利用を確認できました。

おわりに

簡単ではありますが、Agent間でコネクションを生成するための3つのプロトコルを試してみました。どなたかのお役に立てたならば幸いです。