Skip to content

Commit

Permalink
Merge pull request #2173 from sicpa-dlab/connection_invitation_suppor…
Browse files Browse the repository at this point in the history
…t_jwk

Add support for JsonWebKey2020 for the connection invitations
  • Loading branch information
swcurran authored Apr 26, 2023
2 parents 4ac664e + 5afb041 commit d82e450
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 11 deletions.
34 changes: 24 additions & 10 deletions aries_cloudagent/connections/base_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
VerificationMethod,
)
import pydid
from pydid.verification_method import Ed25519VerificationKey2018
from pydid.verification_method import Ed25519VerificationKey2018, JsonWebKey2020

from ..core.error import BaseError
from ..core.profile import Profile
Expand All @@ -37,6 +37,7 @@
from .models.conn_record import ConnRecord
from .models.connection_target import ConnectionTarget
from .models.diddoc import DIDDoc, PublicKey, PublicKeyType, Service
from ..wallet.util import bytes_to_b58, b64_to_bytes


class BaseConnectionManagerError(BaseError):
Expand All @@ -48,7 +49,6 @@ class BaseConnectionManager:

RECORD_TYPE_DID_DOC = "did_doc"
RECORD_TYPE_DID_KEY = "did_key"
SUPPORTED_KEY_TYPES = (Ed25519VerificationKey2018,)

def __init__(self, profile: Profile):
"""
Expand Down Expand Up @@ -277,18 +277,32 @@ async def resolve_invitation(
for url in first_didcomm_service.routing_keys
]

for key in [*recipient_keys, *routing_keys]:
if not isinstance(key, self.SUPPORTED_KEY_TYPES):
raise BaseConnectionManagerError(
f"Key type {type(key).__name__} is not supported"
)

return (
endpoint,
[key.material for key in recipient_keys],
[key.material for key in routing_keys],
[
self._extract_key_material_in_base58_format(key)
for key in recipient_keys
],
[self._extract_key_material_in_base58_format(key) for key in routing_keys],
)

@staticmethod
def _extract_key_material_in_base58_format(method: VerificationMethod) -> str:
if isinstance(method, Ed25519VerificationKey2018):
return method.material
elif isinstance(method, JsonWebKey2020):
if method.public_key_jwk.get("kty") == "OKP":
return bytes_to_b58(b64_to_bytes(method.public_key_jwk.get("x"), True))
else:
raise BaseConnectionManagerError(
f"Key type {type(method).__name__}"
f"with kty {method.public_key_jwk.get('kty')} is not supported"
)
else:
raise BaseConnectionManagerError(
f"Key type {type(method).__name__} is not supported"
)

async def fetch_connection_targets(
self, connection: ConnRecord
) -> Sequence[ConnectionTarget]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from ..messages.connection_request import ConnectionRequest
from ..messages.connection_response import ConnectionResponse
from ..models.connection_detail import ConnectionDetail
from .....wallet.util import bytes_to_b64, b58_to_bytes


class TestConnectionManager(AsyncTestCase):
Expand Down Expand Up @@ -2322,13 +2323,81 @@ async def test_fetch_connection_targets_conn_invitation_no_didcomm_services(self
with self.assertRaises(BaseConnectionManagerError):
await self.manager.fetch_connection_targets(mock_conn)

async def test_fetch_connection_targets_conn_invitation_supported_JsonWebKey2020_key_type(
self,
):
async with self.profile.session() as session:
builder = DIDDocumentBuilder("did:btcr:x705-jznz-q3nl-srs")
vmethod = builder.verification_method.add(
JsonWebKey2020,
ident="1",
public_key_jwk={
"kty": "OKP",
"crv": "Ed25519",
"x": bytes_to_b64(b58_to_bytes(self.test_target_verkey), True),
},
)
builder.service.add_didcomm(
type_="IndyAgent",
service_endpoint=self.test_endpoint,
recipient_keys=[vmethod],
)
did_doc = builder.build()
self.resolver = async_mock.MagicMock()
self.resolver.get_endpoint_for_did = async_mock.CoroutineMock(
return_value=self.test_endpoint
)
self.resolver.resolve = async_mock.CoroutineMock(return_value=did_doc)
self.resolver.dereference = async_mock.CoroutineMock(
return_value=did_doc.verification_method[0]
)
self.context.injector.bind_instance(DIDResolver, self.resolver)
local_did = await session.wallet.create_local_did(
method=SOV,
key_type=ED25519,
seed=self.test_seed,
did=did_doc.id,
metadata=None,
)

conn_invite = ConnectionInvitation(
did=did_doc.id,
endpoint=self.test_endpoint,
recipient_keys=[vmethod.public_key_jwk],
routing_keys=[self.test_verkey],
label="label",
)
mock_conn = async_mock.MagicMock(
my_did=did_doc.id,
their_did=self.test_target_did,
connection_id="dummy",
their_role=ConnRecord.Role.RESPONDER.rfc23,
state=ConnRecord.State.INVITATION.rfc23,
retrieve_invitation=async_mock.CoroutineMock(return_value=conn_invite),
)

targets = await self.manager.fetch_connection_targets(mock_conn)
assert len(targets) == 1
target = targets[0]
assert target.did == mock_conn.their_did
assert target.endpoint == self.test_endpoint
assert target.label == conn_invite.label
assert target.recipient_keys == [self.test_target_verkey]
assert target.routing_keys == []
assert target.sender_key == local_did.verkey

async def test_fetch_connection_targets_conn_invitation_unsupported_key_type(self):
async with self.profile.session() as session:
builder = DIDDocumentBuilder("did:btcr:x705-jznz-q3nl-srs")
vmethod = builder.verification_method.add(
JsonWebKey2020,
ident="1",
public_key_jwk={"jwk": "stuff"},
public_key_jwk={
"kty": "EC",
"crv": "P-256",
"x": "2syLh57B-dGpa0F8p1JrO6JU7UUSF6j7qL-vfk1eOoY",
"y": "BgsGtI7UPsObMRjdElxLOrgAO9JggNMjOcfzEPox18w",
},
)
builder.service.add_didcomm(
type_="IndyAgent",
Expand Down

0 comments on commit d82e450

Please sign in to comment.