Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

Commit

Permalink
fix: fixes for didexchange interop with aca-py
Browse files Browse the repository at this point in the history
accept old and new didex. message formats and mime types:
- application/ssi-agent-wire is accepted as an inbound mime type
- did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/didexchange/1.0 is accepted as
  an inbound PIURI for didexchange messages
- did doc can be parsed from "did_doc~attach" attachment in request
  messages, as per didexchange spec, in addition to being accepted
  inside "connection" field, as per connection-request spec

did doc format:
- Parse legacy peer did docs with publicKey members even if their
  context states they are using a newer format.
- Translate raw ed25519 public key values to did:key when reading
  recipient keys or routing keys

Signed-off-by: Filip Burlacu <filip.burlacu@securekey.com>
  • Loading branch information
Filip Burlacu committed Mar 23, 2021
1 parent e6ebe2c commit 7b3cad0
Show file tree
Hide file tree
Showing 16 changed files with 478 additions and 13 deletions.
4 changes: 2 additions & 2 deletions cmd/aries-agent-rest/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ require (
github.com/gorilla/mux v1.7.3
github.com/hyperledger/aries-framework-go v0.1.6-0.20210304193329-f56b2cebc386
github.com/hyperledger/aries-framework-go/component/storage/leveldb v0.0.0-20210305152013-b276ca413681
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210310001230-bc1bd8ea889c
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210310001230-bc1bd8ea889c
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210320144851-40976de98ccf
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210320144851-40976de98ccf
github.com/rs/cors v1.7.0
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5 // indirect
Expand Down
6 changes: 6 additions & 0 deletions cmd/aries-agent-rest/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-202102242
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210224230531-58e1368e5661/go.mod h1:XaPVDJcbQT8BKmThfQdWPc+hgicHFAQzSOavHw2gn/4=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210310001230-bc1bd8ea889c h1:ELa1dI2zdRegFsaPygDgho+1DKIVUAs0KGnkw7ab304=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210310001230-bc1bd8ea889c/go.mod h1:zOolL2VqWj6+SPe13nrK0oo5QUOfQZQKB0j1iQsje0k=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210320144851-40976de98ccf h1:rh+NCbTrYfJ9ho4NRVdgLuIVF05vuklmnF2JWP1+aFo=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210320144851-40976de98ccf/go.mod h1:HVV8sifdHIyLkrlgmK/6+3YWKnOJPUfoNU+4SwQqMSs=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210205153949-f852f978a0d6/go.mod h1:fDr9wW00GJJl1lR1SFHmJW8utIocdvjO5RNhAYS05EY=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210210184327-0b9d0fd4c34e/go.mod h1:fDr9wW00GJJl1lR1SFHmJW8utIocdvjO5RNhAYS05EY=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210224230531-58e1368e5661/go.mod h1:fDr9wW00GJJl1lR1SFHmJW8utIocdvjO5RNhAYS05EY=
Expand All @@ -221,10 +223,14 @@ github.com/hyperledger/aries-framework-go/spi v0.0.0-20210305152013-b276ca413681
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210305152013-b276ca413681/go.mod h1:fDr9wW00GJJl1lR1SFHmJW8utIocdvjO5RNhAYS05EY=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210310001230-bc1bd8ea889c h1:PzNaY9LS6oP1edqx8CWUf8FifpWb56PGedqf/tAwR3Q=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210310001230-bc1bd8ea889c/go.mod h1:fDr9wW00GJJl1lR1SFHmJW8utIocdvjO5RNhAYS05EY=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210310160016-d5eea2ecdd50/go.mod h1:fDr9wW00GJJl1lR1SFHmJW8utIocdvjO5RNhAYS05EY=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210320144851-40976de98ccf h1:5xKqwVy1gEBENyU7a+KCeDOOtF21wrYtHsEicuXWE/c=
github.com/hyperledger/aries-framework-go/spi v0.0.0-20210320144851-40976de98ccf/go.mod h1:fDr9wW00GJJl1lR1SFHmJW8utIocdvjO5RNhAYS05EY=
github.com/hyperledger/aries-framework-go/test/component v0.0.0-20210219073333-c46e84ce678f/go.mod h1:/ljIFCu5iDIziwuvObF0vEc3fJ5dgDpT8RYAhQdNeHI=
github.com/hyperledger/aries-framework-go/test/component v0.0.0-20210226235232-298aa129d822/go.mod h1:6Za6hvu+eZDPerePXIlMuBWbQZDKqTgOrKV56WZMtcI=
github.com/hyperledger/aries-framework-go/test/component v0.0.0-20210304193329-f56b2cebc386 h1:LLJg+gSy+yPGtdYQopGMI4/C4LA9ZTFkomA4c83q0Ow=
github.com/hyperledger/aries-framework-go/test/component v0.0.0-20210304193329-f56b2cebc386/go.mod h1:6Za6hvu+eZDPerePXIlMuBWbQZDKqTgOrKV56WZMtcI=
github.com/hyperledger/aries-framework-go/test/component v0.0.0-20210310160016-d5eea2ecdd50/go.mod h1:AybsT4/saiuxdVhK5CgOLIkcNMPZtX3GAUMOjHcLLjk=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
Expand Down
2 changes: 1 addition & 1 deletion cmd/aries-js-worker/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ go 1.15

require (
github.com/google/uuid v1.1.2
github.com/hyperledger/aries-framework-go v0.1.7-0.20210310160016-d5eea2ecdd50
github.com/hyperledger/aries-framework-go v0.1.7-0.20210320144851-40976de98ccf
github.com/hyperledger/aries-framework-go/component/storage/indexeddb v0.0.0-00010101000000-000000000000
github.com/mitchellh/mapstructure v1.3.0
github.com/stretchr/testify v1.7.0
Expand Down
2 changes: 2 additions & 0 deletions cmd/aries-js-worker/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210310001230-bc1bd8ea889c h1:ELa1dI2zdRegFsaPygDgho+1DKIVUAs0KGnkw7ab304=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210310001230-bc1bd8ea889c/go.mod h1:zOolL2VqWj6+SPe13nrK0oo5QUOfQZQKB0j1iQsje0k=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210320144851-40976de98ccf h1:rh+NCbTrYfJ9ho4NRVdgLuIVF05vuklmnF2JWP1+aFo=
github.com/hyperledger/aries-framework-go/component/storageutil v0.0.0-20210320144851-40976de98ccf/go.mod h1:HVV8sifdHIyLkrlgmK/6+3YWKnOJPUfoNU+4SwQqMSs=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
Expand Down
66 changes: 65 additions & 1 deletion pkg/didcomm/common/service/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ package service
import (
"fmt"

"github.com/btcsuite/btcutil/base58"

diddoc "github.com/hyperledger/aries-framework-go/pkg/doc/did"
vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
"github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint"
)

// Destination provides the recipientKeys, routingKeys, and serviceEndpoint for an outbound message.
Expand All @@ -23,6 +26,8 @@ type Destination struct {

const (
didCommServiceType = "did-communication"
// legacyDIDCommServiceType is the non-spec service type used by legacy didcomm agent systems.
legacyDIDCommServiceType = "IndyAgent"
)

// GetDestination constructs a Destination struct based on the given DID and parameters
Expand All @@ -41,7 +46,8 @@ func GetDestination(did string, vdr vdrapi.Registry) (*Destination, error) {
func CreateDestination(didDoc *diddoc.Doc) (*Destination, error) {
didCommService, ok := diddoc.LookupService(didDoc, didCommServiceType)
if !ok {
return nil, fmt.Errorf("create destination: missing DID doc service")
// Interop: legacy docs may use the IndyAgent service type for didcomm, with slightly different content format.
return createDestinationFromIndy(didDoc)
}

if didCommService.ServiceEndpoint == "" {
Expand All @@ -61,3 +67,61 @@ func CreateDestination(didDoc *diddoc.Doc) (*Destination, error) {
RoutingKeys: didCommService.RoutingKeys,
}, nil
}

func createDestinationFromIndy(didDoc *diddoc.Doc) (*Destination, error) {
didCommService, ok := diddoc.LookupService(didDoc, legacyDIDCommServiceType)
if !ok {
return nil, fmt.Errorf("create destination: missing DID doc service")
}

if didCommService.ServiceEndpoint == "" {
return nil, fmt.Errorf("create destination: no service endpoint on didcomm service block in diddoc: %+v", didDoc)
}

if len(didCommService.RecipientKeys) == 0 {
return nil, fmt.Errorf("create destination: no recipient keys on didcomm service block in diddoc: %+v", didDoc)
}

// TODO ensure recipient keys are did:key's
// https://github.com/hyperledger/aries-framework-go/issues/1604

// convert plain base58 keys to did:key
recKeys := lookupIndyRecipientKeys(didDoc, didCommService.RecipientKeys)
routeKeys := lookupIndyRecipientKeys(didDoc, didCommService.RoutingKeys)

return &Destination{
RecipientKeys: recKeys,
ServiceEndpoint: didCommService.ServiceEndpoint,
RoutingKeys: routeKeys,
}, nil
}

func lookupIndyRecipientKeys(didDoc *diddoc.Doc, recipientKeys []string) []string {
b58VMkeys := map[string]int{}

for i, vm := range didDoc.VerificationMethod {
b58Key := base58.Encode(vm.Value)
b58VMkeys[b58Key] = i
}

var didKeys []string

for _, key := range recipientKeys {
vmIdx, ok := b58VMkeys[key]
if !ok {
continue
}

vm := didDoc.VerificationMethod[vmIdx]
if vm.Type != "Ed25519VerificationKey2018" {
// TODO: handle further key types
continue
}

didKey, _ := fingerprint.CreateDIDKey(vm.Value)

didKeys = append(didKeys, didKey)
}

return didKeys
}
86 changes: 86 additions & 0 deletions pkg/didcomm/common/service/destination_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/hyperledger/aries-framework-go/pkg/doc/did"
mockdiddoc "github.com/hyperledger/aries-framework-go/pkg/mock/diddoc"
mockvdr "github.com/hyperledger/aries-framework-go/pkg/mock/vdr"
"github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint"
)

func TestGetDestinationFromDID(t *testing.T) {
Expand Down Expand Up @@ -110,6 +111,91 @@ func TestPrepareDestination(t *testing.T) {
})
}

func TestCreateDestinationFromLegacyDoc(t *testing.T) {
t.Run("successfully prepared destination", func(t *testing.T) {
doc := mockdiddoc.GetMockIndyDoc(t)
dest, err := CreateDestination(doc)
require.NoError(t, err)
require.NotNil(t, dest)
require.Equal(t, dest.ServiceEndpoint, "https://localhost:8090")
require.Equal(t, doc.Service[0].RoutingKeys, dest.RoutingKeys)
})

t.Run("error while getting service", func(t *testing.T) {
didDoc := mockdiddoc.GetMockIndyDoc(t)
didDoc.Service = nil

dest, err := createDestinationFromIndy(didDoc)
require.Error(t, err)
require.Contains(t, err.Error(), "missing DID doc service")
require.Nil(t, dest)
})

t.Run("missing service endpoint", func(t *testing.T) {
didDoc := mockdiddoc.GetMockIndyDoc(t)
didDoc.Service = []did.Service{{
Type: legacyDIDCommServiceType,
}}

dest, err := createDestinationFromIndy(didDoc)
require.Error(t, err)
require.Contains(t, err.Error(), "no service endpoint")
require.Nil(t, dest)
})

t.Run("missing recipient keys", func(t *testing.T) {
didDoc := mockdiddoc.GetMockIndyDoc(t)
didDoc.Service = []did.Service{{
Type: legacyDIDCommServiceType,
ServiceEndpoint: "localhost:8080",
}}

dest, err := createDestinationFromIndy(didDoc)
require.Error(t, err)
require.Contains(t, err.Error(), "no recipient keys")
require.Nil(t, dest)
})
}

func TestLookupIndyKeys(t *testing.T) {
t.Run("lookup recipient keys", func(t *testing.T) {
didDoc := mockdiddoc.GetMockIndyDoc(t)

recipientKeys := lookupIndyRecipientKeys(didDoc, didDoc.Service[0].RecipientKeys)
require.NotNil(t, recipientKeys)
require.Len(t, recipientKeys, 1)

pk, err := fingerprint.PubKeyFromDIDKey(recipientKeys[0])
require.NoError(t, err)
require.ElementsMatch(t, didDoc.VerificationMethod[0].Value, pk)
})

t.Run("no keys to lookup", func(t *testing.T) {
didDoc := mockdiddoc.GetMockIndyDoc(t)

recipientKeys := lookupIndyRecipientKeys(didDoc, nil)
require.Nil(t, recipientKeys)
})

t.Run("skip key that isn't found in verificationmethod list", func(t *testing.T) {
didDoc := mockdiddoc.GetMockIndyDoc(t)

didDoc.Service[0].RecipientKeys = []string{"bad key"}

recipientKeys := lookupIndyRecipientKeys(didDoc, didDoc.Service[0].RecipientKeys)
require.Len(t, recipientKeys, 0)
})

t.Run("skip keys that aren't of handled type", func(t *testing.T) {
didDoc := mockdiddoc.GetMockIndyDoc(t)

didDoc.VerificationMethod[0].Type = "bad type"

recipientKeys := lookupIndyRecipientKeys(didDoc, didDoc.Service[0].RecipientKeys)
require.Len(t, recipientKeys, 0)
})
}

func createDIDDoc() *did.Doc {
pubKey, _ := generateKeyPair()
return createDIDDocWithKey(pubKey)
Expand Down
8 changes: 8 additions & 0 deletions pkg/didcomm/common/service/did_comm_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const (
jsonThreadID = "thid"
jsonParentThreadID = "pthid"
jsonMetadata = "_internal_metadata"

oldPIURI = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/"
newPIURI = "https://didcomm.org/"
)

// Metadata may contain additional payload for the protocol. It might be populated by the client/protocol
Expand Down Expand Up @@ -76,6 +79,11 @@ func ParseDIDCommMsgMap(payload []byte) (DIDCommMsgMap, error) {
return nil, fmt.Errorf("invalid payload data format: %w", err)
}

// Interop: accept old PIURI when it's used, as we handle backwards-compatibility at a more fine-grained level.
if typ := msg.Type(); typ != "" {
msg[jsonType] = strings.Replace(typ, oldPIURI, newPIURI, 1)
}

return msg, nil
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/didcomm/protocol/didexchange/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ type Request struct {
Label string `json:"label,omitempty"`
Connection *Connection `json:"connection,omitempty"`
Thread *decorator.Thread `json:"~thread,omitempty"`
// DID the did of the requester. Optional, may be present within `connection` instead.
DID string `json:"did,omitempty"`
// DocAttach an attachment containing the did doc of the requester.
// Optional, may be present within `connection` instead.
DocAttach *decorator.Attachment `json:"did_doc~attach,omitempty"`
}

// Response defines a2a DID exchange response
Expand Down
47 changes: 46 additions & 1 deletion pkg/didcomm/protocol/didexchange/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ SPDX-License-Identifier: Apache-2.0
package didexchange

import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strings"

"github.com/google/uuid"

Expand Down Expand Up @@ -722,6 +724,43 @@ func (s *Service) invitationMsgRecord(msg service.DIDCommMsg) (*connection.Recor
return connRecord, nil
}

// nolint:gomnd
func pad(b64 string) string {
mod := len(b64) % 4
if mod <= 1 {
return b64
}

return b64 + strings.Repeat("=", 4-mod)
}

func getRequestConnection(r *Request) (*Connection, error) {
// Interop: accept the 'connection' attribute of rfc 0160 (connection protocol) if present
if r.Connection != nil {
return r.Connection, nil
}

if r.DocAttach == nil {
return nil, fmt.Errorf("missing did_doc~attach from request")
}

docData, err := base64.StdEncoding.DecodeString(pad(r.DocAttach.Data.Base64))
if err != nil {
return nil, fmt.Errorf("failed to parse base64 attachment data: %w", err)
}

doc, err := did.ParseDocument(docData)
if err != nil {
logger.Errorf("doc bytes: '%s'", string(docData))
return nil, fmt.Errorf("failed to parse did document: %w", err)
}

return &Connection{
DID: r.DID,
DIDDoc: doc,
}, nil
}

func (s *Service) requestMsgRecord(msg service.DIDCommMsg) (*connection.Record, error) {
request := Request{}

Expand All @@ -740,11 +779,17 @@ func (s *Service) requestMsgRecord(msg service.DIDCommMsg) (*connection.Record,
ConnectionID: generateRandomID(),
ThreadID: request.ID,
State: stateNameNull,
TheirDID: request.Connection.DID,
InvitationID: invitationID,
Namespace: theirNSPrefix,
}

// Interop: read their DID from the connection attribute if present
if request.Connection != nil {
connRecord.TheirDID = request.Connection.DID
} else {
connRecord.TheirDID = request.DID
}

if err := s.connectionRecorder.SaveConnectionRecord(connRecord); err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 7b3cad0

Please sign in to comment.