Skip to content

Commit

Permalink
Resolving did:key DIDs
Browse files Browse the repository at this point in the history
  • Loading branch information
reinkrul committed Oct 2, 2023
1 parent d8ecf92 commit a09bf2c
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mr-tron/base58 v1.1.3 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect
github.com/multiformats/go-multihash v0.0.11 // indirect
github.com/nats-io/jwt/v2 v2.5.2 // indirect
github.com/nats-io/nkeys v0.4.5 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg=
github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
github.com/multiformats/go-multihash v0.0.11 h1:yEyBxwoR/7vBM5NfLVXRnpQNVLrMhpS6MRb7Z/1pnzc=
github.com/multiformats/go-multihash v0.0.11/go.mod h1:LXRDJcYYY+9BjlsFe6i5LV7uekf0OoEJdnRmitUshxk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
Expand Down
109 changes: 109 additions & 0 deletions vdr/didkey/resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package didkey

import (
"bytes"
"crypto"
"crypto/ed25519"
"crypto/x509"
"encoding/binary"
"errors"
"fmt"
"github.com/lestrrat-go/jwx/x25519"
"github.com/multiformats/go-multicodec"
ssi "github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"github.com/shengdoushi/base58"
)

// MethodName is the name of this DID method.
const MethodName = "key"

var _ resolver.DIDResolver = &Resolver{}

var errInvalidPublicKeyLength = errors.New("invalid did:key: invalid public key length")

type Resolver struct {
}

func (r Resolver) Resolve(id did.DID, metadata *resolver.ResolveMetadata) (*did.Document, *resolver.DocumentMetadata, error) {
if id.Method != MethodName {
return nil, nil, fmt.Errorf("unsupported DID method: %s", id.Method)
}
encodedKey := id.ID
if len(encodedKey) == 0 || encodedKey[0] != 'z' {
return nil, nil, errors.New("did:key does not start with 'z'")
}
mcBytes, err := base58.Decode(encodedKey[1:], base58.BitcoinAlphabet)
if err != nil {
return nil, nil, fmt.Errorf("did:key: invalid base58btc: %w", err)
}
reader := bytes.NewReader(mcBytes)
keyType, err := binary.ReadUvarint(reader)
if err != nil {
return nil, nil, fmt.Errorf("did:key: invalid base58btc: %w", err)
}
// See https://w3c-ccg.github.io/did-method-key/#signature-method-creation-algorithm
var key crypto.PublicKey
keyLength := reader.Len()
switch multicodec.Code(keyType) {
case multicodec.Secp256k1Pub:
if keyLength != 33 {
return nil, nil, errInvalidPublicKeyLength
}
return nil, nil, errors.New("TODO: support secp256k1 public key")
case multicodec.X25519Pub:
if keyLength != 32 {
return nil, nil, errInvalidPublicKeyLength
}
key = x25519.PublicKey(mcBytes[1:])
case multicodec.Ed25519Pub:
if keyLength != 32 {
return nil, nil, errInvalidPublicKeyLength
}
key = ed25519.PublicKey(mcBytes[1:])
case multicodec.P256Pub:
if keyLength != 33 {
return nil, nil, errInvalidPublicKeyLength
}
return nil, nil, errors.New("TODO: find out P256 pub key encoding")
case multicodec.P384Pub:
if keyLength != 49 {
return nil, nil, errInvalidPublicKeyLength
}
return nil, nil, errors.New("TODO: find out P384 pub key encoding")
case multicodec.P521Pub:
return nil, nil, errors.New("TODO: find out P521 pub key encoding")
case multicodec.RsaPub:
key, err = x509.ParsePKCS1PublicKey(mcBytes[1:])
if err != nil {
return nil, nil, fmt.Errorf("did:key: invalid PKCS#1 encoded RSA public key: %w", err)
}
default:
return nil, nil, fmt.Errorf("did:key: unsupported public key type: %d", keyType)
}

document := did.Document{
Context: nil,
ID: id,
AlsoKnownAs: nil,
Authentication: nil,
AssertionMethod: nil,
KeyAgreement: nil,
CapabilityInvocation: nil,
CapabilityDelegation: nil,
Service: nil,
}
keyID := id
keyID.Fragment = id.ID
vm, err := did.NewVerificationMethod(keyID, ssi.JsonWebKey2020, id, key)
if err != nil {
return nil, nil, err
}
document.AddAssertionMethod(vm)
document.AddAuthenticationMethod(vm)
document.AddKeyAgreement(vm)
document.AddCapabilityDelegation(vm)
document.AddCapabilityInvocation(vm)
return nil, nil, nil
}
35 changes: 35 additions & 0 deletions vdr/didkey/resolver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package didkey

import (
"github.com/nuts-foundation/go-did/did"
"github.com/stretchr/testify/require"
"testing"
)

func TestResolver_Resolve(t *testing.T) {
tests := []struct {
name string
id string
err error
}{
{
name: "Ed25519",
id: "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := Resolver{}
got, got1, err := r.Resolve(did.MustParseDID(tt.id), nil)
if tt.err != nil {
require.Error(t, err)
require.Nil(t, got)
require.Nil(t, got1)
return
}
require.NoError(t, err)
require.NotNil(t, got)
require.NotNil(t, got1)
})
}
}

0 comments on commit a09bf2c

Please sign in to comment.