Skip to content

Commit

Permalink
feat: implementation of DID authentication (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xHansLee committed Mar 8, 2023
1 parent e5c210b commit 255994f
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 1 deletion.
22 changes: 22 additions & 0 deletions pkg/vc/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,27 @@ func (f *Framework) SignPresentation(presentation []byte, privKey []byte, opts *
return pres.MarshalJSON()
}

// AuthenticateDID creates a verifiable presentation for DID authentication
// https://w3c-ccg.github.io/vp-request-spec/#did-authentication
func (f *Framework) AuthenticateDID(privKey []byte, opts *ProofOptions) ([]byte, error) {
presentation, err := verifiable.NewPresentation()
if err != nil {
return nil, fmt.Errorf("failed to create new presentation for DID authentication: %w", err)
}

if len(opts.Controller) == 0 {
return nil, fmt.Errorf("controller cannot be empty")
}

presentation.Holder = opts.Controller

if err := f.addProof(presentation, privKey, opts); err != nil {
return nil, fmt.Errorf("failed to add proof to DID authentication: %w", err)
}

return presentation.MarshalJSON()
}

// VerifyPresentation verifies a proof in the verifiable presentation.
// If there is a presentation definition provided, also verifies that the presentation meets the requirements.
func (f *Framework) VerifyPresentation(vp []byte, opts ...VerificationOption) (*verifiable.Presentation, error) {
Expand Down Expand Up @@ -204,6 +225,7 @@ type provable interface {

// ProofOptions is model to allow the dynamic proofing options by the user.
type ProofOptions struct {
Controller string `json:"controller,omitempty"`
VerificationMethod string `json:"verificationMethod,omitempty"`
SignatureType string `json:"signatureType,omitempty"`
ProofPurpose string `json:"proofPurpose,omitempty"`
Expand Down
31 changes: 30 additions & 1 deletion pkg/vc/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,44 @@ import (
"crypto/sha256"
"encoding/base64"
"fmt"
"testing"

"github.com/hyperledger/aries-framework-go/pkg/doc/did"
"github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
"testing"
didtypes "github.com/medibloc/panacea-core/v2/x/did/types"

"github.com/btcsuite/btcd/btcec"
"github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub"
"github.com/stretchr/testify/require"
)

func TestDIDAuthentication_Success(t *testing.T) {
holderPrivKey, err := btcec.NewPrivateKey(btcec.S256())
require.NoError(t, err)

mockVDR := NewMockVDR(holderPrivKey.PubKey().SerializeUncompressed(), "EcdsaSecp256k1VerificationKey2019")
f, err := NewFramework(mockVDR)
require.NoError(t, err)

holderDID := didtypes.NewDID(holderPrivKey.PubKey().SerializeCompressed())

proofOpts := &ProofOptions{
Controller: holderDID,
VerificationMethod: fmt.Sprintf("%s#key1", holderDID),
SignatureType: "EcdsaSecp256k1Signature2019",
Domain: "https://my-domain.com",
Challenge: "this is a challenge",
Created: "2017-06-18T21:19:10Z",
ProofPurpose: "authentication",
}

didAuth, err := f.AuthenticateDID(holderPrivKey.Serialize(), proofOpts)
require.NoError(t, err)

_, err = f.VerifyPresentation(didAuth)
require.NoError(t, err)
}

func TestFullScenarioWithSecp256k1(t *testing.T) {
cred := `{"@context": ["https://www.w3.org/2018/credentials/v1","https://www.w3.org/2018/credentials/examples/v1"],
"issuer": "did:panacea:BFbUAkxqj3cXXYdNK9FAF9UuEmm7jCT5T77rXhBCvy2K",
Expand Down
155 changes: 155 additions & 0 deletions pkg/vdr/did_auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package vdr

import (
"fmt"
"testing"

didtypes "github.com/medibloc/panacea-core/v2/x/did/types"
"github.com/medibloc/vc-sdk/pkg/vc"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/crypto/secp256k1"
)

type panaceaDIDAuthTestSuite struct {
suite.Suite

holderPrivKey secp256k1.PrivKey
attackerPrivKey secp256k1.PrivKey

holderDID string
attackerDID string

challenge string
domain string

VDR *mockDIDClient
}

func TestPanaceaDIDAuthTestSuite(t *testing.T) {
suite.Run(t, &panaceaDIDAuthTestSuite{})
}

func (suite *panaceaDIDAuthTestSuite) BeforeTest(_, _ string) {
holderMnemonic, _ := newMnemonic()
attackerMnemonic, _ := newMnemonic()

suite.holderPrivKey, _ = generatePrivateKeyFromMnemonic(holderMnemonic)
suite.attackerPrivKey, _ = generatePrivateKeyFromMnemonic(attackerMnemonic)

suite.holderDID = didtypes.NewDID(suite.holderPrivKey.PubKey().Bytes())
suite.attackerDID = didtypes.NewDID(suite.attackerPrivKey.PubKey().Bytes())

holderPubKeyBase58 := base58.Encode(suite.holderPrivKey.PubKey().Bytes())
attackerPubKeyBase58 := base58.Encode(suite.attackerPrivKey.PubKey().Bytes())

holderDIDDoc := createDIDDoc(suite.holderDID, holderPubKeyBase58)
attackerDIDDoc := createDIDDoc(suite.attackerDID, attackerPubKeyBase58)

suite.VDR = newMockDIDClient(holderDIDDoc, attackerDIDDoc)

suite.challenge = "this is a challenge"
suite.domain = "https://my-domain.com"
}

func (suite *panaceaDIDAuthTestSuite) TestDIDAuthentication_Success() {
panaceaVDR := NewPanaceaVDR(suite.VDR)
f, err := vc.NewFramework(panaceaVDR)
suite.NoError(err)

proofOpts := &vc.ProofOptions{
Controller: suite.holderDID,
VerificationMethod: fmt.Sprintf("%s#key1", suite.holderDID),
SignatureType: ecdsaSigType,
Domain: suite.domain,
Challenge: suite.challenge,
Created: "2017-06-18T21:19:10Z",
ProofPurpose: "authentication",
}

didAuth, err := f.AuthenticateDID(suite.holderPrivKey.Bytes(), proofOpts)
suite.NoError(err)

_, err = f.VerifyPresentation(didAuth)
suite.NoError(err)
}

func (suite *panaceaDIDAuthTestSuite) TestDIDAuthentication_FailNotHolder() {
panaceaVDR := NewPanaceaVDR(suite.VDR)
f, err := vc.NewFramework(panaceaVDR)
suite.NoError(err)

proofOpts := &vc.ProofOptions{
Controller: suite.holderDID,
VerificationMethod: fmt.Sprintf("%s#key1", suite.holderDID),
SignatureType: ecdsaSigType,
Domain: suite.domain,
Challenge: suite.challenge,
Created: "2017-06-18T21:19:10Z",
ProofPurpose: "authentication",
}

didAuth, err := f.AuthenticateDID(suite.attackerPrivKey.Bytes(), proofOpts)
suite.NoError(err)

_, err = f.VerifyPresentation(didAuth)
suite.ErrorContains(err, "ecdsa: invalid signature")
}

func (suite *panaceaDIDAuthTestSuite) TestDIDAuthentication_DifferentChallengeAndDomain() {
panaceaVDR := NewPanaceaVDR(suite.VDR)
f, err := vc.NewFramework(panaceaVDR)
suite.NoError(err)

proofOpts := &vc.ProofOptions{
Controller: suite.holderDID,
VerificationMethod: fmt.Sprintf("%s#key1", suite.holderDID),
SignatureType: ecdsaSigType,
Domain: suite.domain,
Challenge: suite.challenge,
Created: "2017-06-18T21:19:10Z",
ProofPurpose: "authentication",
}

didAuth, err := f.AuthenticateDID(suite.holderPrivKey.Bytes(), proofOpts)
suite.NoError(err)

pres, err := f.VerifyPresentation(didAuth)
suite.NoError(err)

tamperedChallengeProofOpts := &vc.ProofOptions{
Controller: suite.holderDID,
VerificationMethod: fmt.Sprintf("%s#key1", suite.holderDID),
SignatureType: ecdsaSigType,
Domain: suite.domain,
Challenge: "tampered challenge",
Created: "2017-06-18T21:19:10Z",
ProofPurpose: "authentication",
}

didAuthWrongChallenge, err := f.AuthenticateDID(suite.holderPrivKey.Bytes(), tamperedChallengeProofOpts)
suite.NoError(err)

presWrongChallenge, err := f.VerifyPresentation(didAuthWrongChallenge)
suite.NoError(err)

tamperedDomainProofOpts := &vc.ProofOptions{
Controller: suite.holderDID,
VerificationMethod: fmt.Sprintf("%s#key1", suite.holderDID),
SignatureType: ecdsaSigType,
Domain: "tampered domain",
Challenge: suite.challenge,
Created: "2017-06-18T21:19:10Z",
ProofPurpose: "authentication",
}

didAuthWrongDomain, err := f.AuthenticateDID(suite.holderPrivKey.Bytes(), tamperedDomainProofOpts)
suite.NoError(err)

presWrongDomain, err := f.VerifyPresentation(didAuthWrongDomain)
suite.NoError(err)

// compare proofs
suite.NotEqual(pres.Proofs, presWrongChallenge.Proofs)
suite.NotEqual(pres.Proofs, presWrongDomain.Proofs)
}

0 comments on commit 255994f

Please sign in to comment.