Repository: hyperledger/aries-cloudagent-python

Issue:
ACA-Py - AFJ: ACA-Py fails on DID Exchange Request
ACA-Py fails on a DID Exchange request from AFJ.

```mermaid
sequenceDiagram
participant acapy as ACA-Py
participant afj as AFJ

acapy ->> acapy: Create OOB invitation
acapy -->> afj: Deliver invitation
afj -x acapy: https://didcomm.org/didexchange/1.0/request
```

OOB Invitaiton received by AFJ:
```json
{
  "@type": "https://didcomm.org/out-of-band/1.1/invitation",
  "@id": "f459945c-39f1-4052-819f-6ef862eb4201",
  "label": "Alice",
  "handshake_protocols": [
    "https://didcomm.org/didexchange/1.0"
  ],
  "services": [
    {
      "id": "#inline",
      "serviceEndpoint": "http://acapy:3000",
      "type": "did-communication",
      "recipientKeys": [
        "did:key:z6MkrwQaATaVCja2XSPwfq1t3ABLvcYW8y58ammmZnYftDEu#z6MkrwQaATaVCja2XSPwfq1t3ABLvcYW8y58ammmZnYftDEu"
      ]
    }
  ]
}
```

Request prepared by AFJ:
```json
{
  "@type": "https://didcomm.org/didexchange/1.0/request",
  "@id": "2e082ac5-c0d2-4fab-b369-27338d51c238",
  "label": "test-agent",
  "did": "did:peer:1zQmd5sQ7mhYcbwtr5L6fQ1KfwFYtEGU3mCpedeBtgmycXC5",
  "~thread": {
    "pthid": "f459945c-39f1-4052-819f-6ef862eb4201"
  },
  "did_doc~attach": {
    "@id": "33718c9b-3f48-4576-8fd3-516fad2409f8",
    "mime-type": "application/json",
    "data": {
      "base64": "eyJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL2RpZC92MSJdLCJpZCI6ImRpZDpwZWVyOjF6UW1kNXNRN21oWWNid3RyNUw2ZlExS2Z3Rll0RUdVM21DcGVkZUJ0Z215Y1hDNSIsInNlcnZpY2UiOlt7ImlkIjoiI2lubGluZS0wIiwic2VydmljZUVuZHBvaW50IjoiZGlkY29tbTp0cmFuc3BvcnQvcXVldWUiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJwcmlvcml0eSI6MCwicmVjaXBpZW50S2V5cyI6WyIjNzNkMDZhM2ItNzRkNS00ZjlhLWI4YzctZTA3NWNiNzY2NGRkIl0sInJvdXRpbmdLZXlzIjpbXX1dLCJhdXRoZW50aWNhdGlvbiI6W3siaWQiOiIjNzNkMDZhM2ItNzRkNS00ZjlhLWI4YzctZTA3NWNiNzY2NGRkIiwidHlwZSI6IkVkMjU1MTlWZXJpZmljYXRpb25LZXkyMDE4IiwiY29udHJvbGxlciI6IiNpZCIsInB1YmxpY0tleUJhc2U1OCI6IkV6VnZHSm1mWTZXaUdlYWZmbzJMWlBLVmpvcEFrMlBzNXFncVJhQ1Vyd2gxIn1dLCJrZXlBZ3JlZW1lbnQiOlt7ImlkIjoiIzUwNDQxZWM0LTcyZWItNDIzOC05ODM1LTEzZjg0NTI5M2M2NSIsInR5cGUiOiJYMjU1MTlLZXlBZ3JlZW1lbnRLZXkyMDE5IiwiY29udHJvbGxlciI6IiNpZCIsInB1YmxpY0tleUJhc2U1OCI6IjlBM3BhdlZETkFoN0NwajJuYUdBVmY1eGlNazV2WUxwUVZuRkZqRnBZYjJDIn1dfQ==",
      "jws": {
        "protected": "eyJhbGciOiJFZERTQSIsImp3ayI6eyJrdHkiOiJPS1AiLCJjcnYiOiJFZDI1NTE5IiwieCI6InotSzc5czVQZVlOd3ZzODE2VzU4VjRyc1NpWi1XU0tYdmNnX1ozNlM3eUEifX0",
        "signature": "N-_ig4v3S-4Jt8iKy6eWkg-wocqjY5FC91WtgunFzoO8ZVjmxkYBGu9tr9hk4-lYao0I_2OfxvLnWk50zEfhCQ",
        "header": {
          "kid": "did:key:z6MktSkxrZ26se1BP9RNMMzBQUsVZP629ueDmrbmFrAVnAUP"
        }
      }
    }
  }
}
```

Decoded attachment:
```json
{
  "@context": [
    "https://w3id.org/did/v1"
  ],
  "id": "did:peer:1zQmd5sQ7mhYcbwtr5L6fQ1KfwFYtEGU3mCpedeBtgmycXC5",
  "service": [
    {
      "id": "#inline-0",
      "serviceEndpoint": "didcomm:transport/queue",
      "type": "did-communication",
      "priority": 0,
      "recipientKeys": [
        "#73d06a3b-74d5-4f9a-b8c7-e075cb7664dd"
      ],
      "routingKeys": []
    }
  ],
  "authentication": [
    {
      "id": "#73d06a3b-74d5-4f9a-b8c7-e075cb7664dd",
      "type": "Ed25519VerificationKey2018",
      "controller": "#id",
      "publicKeyBase58": "EzVvGJmfY6WiGeaffo2LZPKVjopAk2Ps5qgqRaCUrwh1"
    }
  ],
  "keyAgreement": [
    {
      "id": "#50441ec4-72eb-4238-9835-13f845293c65",
      "type": "X25519KeyAgreementKey2019",
      "controller": "#id",
      "publicKeyBase58": "9A3pavVDNAh7Cpj2naGAVf5xiMk5vYLpQVnFFjFpYb2C"
    }
  ]
}
```

Decoded protected headers:
```json
{
  "alg": "EdDSA",
  "jwk": {
    "kty": "OKP",
    "crv": "Ed25519",
    "x": "z-K79s5PeYNwvs816W58V4rsSiZ-WSKXvcg_Z36S7yA"
  }
}
```

Error on ACA-Py:
```python
2023-11-17 02:07:55,576 aries_cloudagent.core.dispatcher ERROR Handler error: Dispatcher.handle_message
Traceback (most recent call last):
  File "/usr/local/lib/python3.9/asyncio/tasks.py", line 256, in __step
    result = coro.send(None)
  File "/aries_cloudagent/core/dispatcher.py", line 253, in handle_message
    await handler(context, responder)
  File "/aries_cloudagent/protocols/didexchange/v1_0/handlers/request_handler.py", line 39, in handle
    conn_rec = await mgr.receive_request(
  File "/aries_cloudagent/protocols/didexchange/v1_0/manager.py", line 486, in receive_request
    conn_did_doc = await self.verify_diddoc(wallet, request.did_doc_attach)
  File "/aries_cloudagent/protocols/didexchange/v1_0/manager.py", line 940, in verify_diddoc
    if not await attached.data.verify(wallet, invi_key):
  File "/aries_cloudagent/messaging/decorators/attach_decorator.py", line 452, in verify
    encoded_pk = DIDKey.from_did(protected["jwk"]["kid"]).public_key_b58
KeyError: 'kid'
```


Discussion:
Versions:
- ACA-Py: latest main
- AFJ: 0.4.2
What ACA-Py is used to seeing (pulled from an exchange between two ACA-Py agents):
```json
{
  "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/didexchange/1.0/request",
  "@id": "fc190b98-6d32-43b0-8f39-f235d7b7014d",
  "~thread": {
    "thid": "fc190b98-6d32-43b0-8f39-f235d7b7014d",
    "pthid": "386901f3-96cd-4c3a-b9cf-9d383b9e3bf3"
  },
  "label": "Bob",
  "did": "9aBi8zsthDuvLkhSaQWMU",
  "did_doc~attach": {
    "@id": "6f04c85f-a54d-4c4a-9523-c76b8b92f2a2",
    "mime-type": "application/json",
    "data": {
      "base64": "eyJAY29udGV4dCI6ICJodHRwczovL3czaWQub3JnL2RpZC92MSIsICJpZCI6ICJkaWQ6c292OjlhQmk4enN0aER1dkxraFNhUVdNVSIsICJwdWJsaWNLZXkiOiBbeyJpZCI6ICJkaWQ6c292OjlhQmk4enN0aER1dkxraFNhUVdNVSMxIiwgInR5cGUiOiAiRWQyNTUxOVZlcmlmaWNhdGlvbktleTIwMTgiLCAiY29udHJvbGxlciI6ICJkaWQ6c292OjlhQmk4enN0aER1dkxraFNhUVdNVSIsICJwdWJsaWNLZXlCYXNlNTgiOiAiNWZ5ekVGWEJma0tBUEtvalVOMkR0ZW9Dam1OdFc2ZTJpWXJta0U5ajZRciJ9XSwgImF1dGhlbnRpY2F0aW9uIjogW3sidHlwZSI6ICJFZDI1NTE5U2lnbmF0dXJlQXV0aGVudGljYXRpb24yMDE4IiwgInB1YmxpY0tleSI6ICJkaWQ6c292OjlhQmk4enN0aER1dkxraFNhUVdNVSMxIn1dLCAic2VydmljZSI6IFt7ImlkIjogImRpZDpzb3Y6OWFCaTh6c3RoRHV2TGtoU2FRV01VO2luZHkiLCAidHlwZSI6ICJJbmR5QWdlbnQiLCAicHJpb3JpdHkiOiAwLCAicmVjaXBpZW50S2V5cyI6IFsiNWZ5ekVGWEJma0tBUEtvalVOMkR0ZW9Dam1OdFc2ZTJpWXJta0U5ajZRciJdLCAic2VydmljZUVuZHBvaW50IjogImh0dHA6Ly9ib2I6MzAwMCJ9XX0=",
      "jws": {
        "header": {
          "kid": "did:key:z6MkeXw2aUVxXDEnGtAWR3Ks4zCo2K3EJPLzijTnc2CAeKCE"
        },
        "protected": "eyJhbGciOiAiRWREU0EiLCAia2lkIjogImRpZDprZXk6ejZNa2VYdzJhVVZ4WERFbkd0QVdSM0tzNHpDbzJLM0VKUEx6aWpUbmMyQ0FlS0NFIiwgImp3ayI6IHsia3R5IjogIk9LUCIsICJjcnYiOiAiRWQyNTUxOSIsICJ4IjogIkFUSm1vdDRqdVczQnQ2UWhCN0xwZnhDRUZYMlRySUk0X0M3c3h5U2xZUXMiLCAia2lkIjogImRpZDprZXk6ejZNa2VYdzJhVVZ4WERFbkd0QVdSM0tzNHpDbzJLM0VKUEx6aWpUbmMyQ0FlS0NFIn19",
        "signature": "E8wV3G57bLU8myguhuPr42aMrtgnq7mf9uWirUOCjajfhXnsgmD_W64W_UvlAwC1pn5AhfX5vR6YtR7HLuQ-CA"
      }
    }
  }
}
```

Decoded attachment data:
```json
{
  "@context": "https://w3id.org/did/v1",
  "id": "did:sov:9aBi8zsthDuvLkhSaQWMU",
  "publicKey": [
    {
      "id": "did:sov:9aBi8zsthDuvLkhSaQWMU#1",
      "type": "Ed25519VerificationKey2018",
      "controller": "did:sov:9aBi8zsthDuvLkhSaQWMU",
      "publicKeyBase58": "5fyzEFXBfkKAPKojUN2DteoCjmNtW6e2iYrmkE9j6Qr"
    }
  ],
  "authentication": [
    {
      "type": "Ed25519SignatureAuthentication2018",
      "publicKey": "did:sov:9aBi8zsthDuvLkhSaQWMU#1"
    }
  ],
  "service": [
    {
      "id": "did:sov:9aBi8zsthDuvLkhSaQWMU;indy",
      "type": "IndyAgent",
      "priority": 0,
      "recipientKeys": [
        "5fyzEFXBfkKAPKojUN2DteoCjmNtW6e2iYrmkE9j6Qr"
      ],
      "serviceEndpoint": "http://bob:3000"
    }
  ]
}
```

Decoded protected headers:
```json
{
  "alg": "EdDSA",
  "kid": "did:key:z6MkeXw2aUVxXDEnGtAWR3Ks4zCo2K3EJPLzijTnc2CAeKCE",
  "jwk": {
    "kty": "OKP",
    "crv": "Ed25519",
    "x": "ATJmot4juW3Bt6QhB7LpfxCEFX2TrII4_C7sxySlYQs",
    "kid": "did:key:z6MkeXw2aUVxXDEnGtAWR3Ks4zCo2K3EJPLzijTnc2CAeKCE"
  }
}
```


Resolving patch:
diff --git a/aries_cloudagent/messaging/decorators/attach_decorator.py b/aries_cloudagent/messaging/decorators/attach_decorator.py
--- a/aries_cloudagent/messaging/decorators/attach_decorator.py
+++ b/aries_cloudagent/messaging/decorators/attach_decorator.py
@@ -448,13 +448,19 @@ async def verify(self, wallet: BaseWallet, signer_verkey: str = None) -> bool:
 
             sign_input = (b64_protected + "." + b64_payload).encode("ascii")
             b_sig = b64_to_bytes(b64_sig, urlsafe=True)
-            verkey = bytes_to_b58(b64_to_bytes(protected["jwk"]["x"], urlsafe=True))
-            encoded_pk = DIDKey.from_did(protected["jwk"]["kid"]).public_key_b58
-            verkey_to_check.append(encoded_pk)
+            jwk = protected["jwk"]
+            verkey = bytes_to_b58(b64_to_bytes(jwk["x"], urlsafe=True))
             if not await wallet.verify_message(sign_input, b_sig, verkey, ED25519):
                 return False
-            if not await wallet.verify_message(sign_input, b_sig, encoded_pk, ED25519):
-                return False
+
+            if "kid" in jwk:
+                encoded_pk = DIDKey.from_did(protected["jwk"]["kid"]).public_key_b58
+                verkey_to_check.append(encoded_pk)
+                if not await wallet.verify_message(
+                    sign_input, b_sig, encoded_pk, ED25519
+                ):
+                    return False
+
         if signer_verkey and signer_verkey not in verkey_to_check:
             return False
         return True


Test patch: