Skip to content

Commit

Permalink
Refactor DID package (#371)
Browse files Browse the repository at this point in the history
* refactor did pkg

* refactor did pkg

* lints

* pr comments

* lint
  • Loading branch information
decentralgabe authored May 8, 2023
1 parent d231d5b commit 989cdd2
Show file tree
Hide file tree
Showing 60 changed files with 1,750 additions and 1,511 deletions.
14 changes: 8 additions & 6 deletions credential/exchange/submission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import (
"context"
"testing"

"github.com/TBD54566975/ssi-sdk/crypto/jwx"
"github.com/TBD54566975/ssi-sdk/did"
"github.com/TBD54566975/ssi-sdk/util"
"github.com/goccy/go-json"
"github.com/oliveagle/jsonpath"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/TBD54566975/ssi-sdk/crypto/jwx"
"github.com/TBD54566975/ssi-sdk/did/key"
"github.com/TBD54566975/ssi-sdk/did/resolution"
"github.com/TBD54566975/ssi-sdk/util"

"github.com/TBD54566975/ssi-sdk/credential"
"github.com/TBD54566975/ssi-sdk/crypto"
"github.com/TBD54566975/ssi-sdk/cryptosuite"
Expand Down Expand Up @@ -55,7 +57,7 @@ func TestBuildPresentationSubmission(t *testing.T) {
assert.NoError(tt, err)
assert.NotEmpty(tt, submissionBytes)

resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)
_, _, _, err = credential.VerifyVerifiablePresentationJWT(context.Background(), *verifier, resolver, string(submissionBytes))
assert.Error(tt, err)
Expand Down Expand Up @@ -99,7 +101,7 @@ func TestBuildPresentationSubmission(t *testing.T) {

println(string(submissionBytes))

resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)
_, _, vp, err := credential.VerifyVerifiablePresentationJWT(context.Background(), *verifier, resolver, string(submissionBytes))
assert.NoError(tt, err)
Expand Down Expand Up @@ -846,7 +848,7 @@ func getGenericTestClaim() map[string]any {
}

func getJWKSignerVerifier(t *testing.T) (*jwx.Signer, *jwx.Verifier) {
privKey, didKey, err := did.GenerateDIDKey(crypto.Ed25519)
privKey, didKey, err := key.GenerateDIDKey(crypto.Ed25519)
require.NoError(t, err)

expanded, err := didKey.Expand()
Expand Down
13 changes: 7 additions & 6 deletions credential/exchange/verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import (
"strings"

"github.com/TBD54566975/ssi-sdk/crypto/jwx"
"github.com/TBD54566975/ssi-sdk/did"
"github.com/TBD54566975/ssi-sdk/did/resolution"
"github.com/TBD54566975/ssi-sdk/schema"

"github.com/TBD54566975/ssi-sdk/credential"
"github.com/TBD54566975/ssi-sdk/util"
"github.com/goccy/go-json"
"github.com/oliveagle/jsonpath"
"github.com/pkg/errors"

"github.com/TBD54566975/ssi-sdk/credential"
"github.com/TBD54566975/ssi-sdk/util"
)

// VerifiedSubmissionData is the result of a successful verification of a presentation submission
Expand All @@ -30,14 +31,14 @@ type VerifiedSubmissionData struct {

// VerifyPresentationSubmission verifies a presentation submission for both signature validity and correctness
// with the specification. It is assumed that the caller knows the submission embed target, and the corresponding
// presentation definition, and has access to the public key of the signer. A DID resolver is required to resolve
// presentation definition, and has access to the public key of the signer. A DID resolution is required to resolve
// the DID and keys of the signer for each credential in the presentation, whose signatures also need to be verified.
// Note: this method does not support LD cryptosuites, and prefers JWT representations. Future refactors
// may include an analog method for LD suites.
// TODO(gabe) remove embed target, have it detected from the submission
func VerifyPresentationSubmission(ctx context.Context, verifier any, resolver did.Resolver, et EmbedTarget, def PresentationDefinition, submission []byte) ([]VerifiedSubmissionData, error) { //revive:disable-line
func VerifyPresentationSubmission(ctx context.Context, verifier any, resolver resolution.Resolver, et EmbedTarget, def PresentationDefinition, submission []byte) ([]VerifiedSubmissionData, error) { //revive:disable-line
if resolver == nil {
return nil, errors.New("resolver cannot be empty")
return nil, errors.New("resolution cannot be empty")
}
if len(submission) == 0 {
return nil, errors.New("submission cannot be empty")
Expand Down
18 changes: 10 additions & 8 deletions credential/exchange/verification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@ import (
"context"
"testing"

"github.com/stretchr/testify/assert"

"github.com/TBD54566975/ssi-sdk/crypto/jwx"
"github.com/TBD54566975/ssi-sdk/did"
"github.com/TBD54566975/ssi-sdk/did/key"
"github.com/TBD54566975/ssi-sdk/did/resolution"
"github.com/TBD54566975/ssi-sdk/util"
"github.com/stretchr/testify/assert"

"github.com/TBD54566975/ssi-sdk/credential"
"github.com/TBD54566975/ssi-sdk/cryptosuite"
)

func TestVerifyPresentationSubmission(t *testing.T) {
t.Run("Empty submission", func(tt *testing.T) {
resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)
verifier := jwx.Verifier{}
_, err = VerifyPresentationSubmission(context.Background(), verifier, resolver, "badEmbedTarget", PresentationDefinition{}, nil)
Expand All @@ -24,7 +26,7 @@ func TestVerifyPresentationSubmission(t *testing.T) {
})

t.Run("Empty presentation definition", func(tt *testing.T) {
resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)
verifier := jwx.Verifier{}
_, err = VerifyPresentationSubmission(context.Background(), verifier, resolver, "badEmbedTarget", PresentationDefinition{}, []byte{0, 1, 2, 3})
Expand All @@ -33,7 +35,7 @@ func TestVerifyPresentationSubmission(t *testing.T) {
})

t.Run("Unsupported embed target", func(tt *testing.T) {
resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)
verifier := jwx.Verifier{}
_, err = VerifyPresentationSubmission(context.Background(), verifier, resolver, "badEmbedTarget", PresentationDefinition{ID: "1"}, []byte{0, 1, 2, 3})
Expand All @@ -60,7 +62,7 @@ func TestVerifyPresentationSubmission(t *testing.T) {
},
}

resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)
_, verifier := getJWKSignerVerifier(tt)
_, err = VerifyPresentationSubmission(context.Background(), *verifier, resolver, JWTVPTarget, def, []byte{0, 1, 2, 3})
Expand Down Expand Up @@ -88,7 +90,7 @@ func TestVerifyPresentationSubmission(t *testing.T) {
}
assert.NoError(tt, def.IsValid())

resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)

signer, verifier := getJWKSignerVerifier(tt)
Expand Down Expand Up @@ -127,7 +129,7 @@ func TestVerifyPresentationSubmission(t *testing.T) {
}
assert.NoError(tt, def.IsValid())

resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
assert.NoError(tt, err)

signer, verifier := getJWKSignerVerifier(tt)
Expand Down
11 changes: 6 additions & 5 deletions credential/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
"time"

"github.com/TBD54566975/ssi-sdk/crypto/jwx"
"github.com/TBD54566975/ssi-sdk/did"
"github.com/TBD54566975/ssi-sdk/did/resolution"

"github.com/goccy/go-json"
"github.com/google/uuid"
"github.com/lestrrat-go/jwx/v2/jwa"
Expand Down Expand Up @@ -269,9 +270,9 @@ func SignVerifiablePresentationJWT(signer jwx.Signer, parameters JWTVVPParameter
// After decoding the signature of each credential in the presentation is verified. If there are any issues during
// decoding or signature validation, an error is returned. As a result, a successfully decoded VerifiablePresentation
// object is returned.
func VerifyVerifiablePresentationJWT(ctx context.Context, verifier jwx.Verifier, resolver did.Resolver, token string) (jws.Headers, jwt.Token, *VerifiablePresentation, error) {
if resolver == nil {
return nil, nil, nil, errors.New("resolver cannot be empty")
func VerifyVerifiablePresentationJWT(ctx context.Context, verifier jwx.Verifier, r resolution.Resolver, token string) (jws.Headers, jwt.Token, *VerifiablePresentation, error) {
if r == nil {
return nil, nil, nil, errors.New("r cannot be empty")
}

// verify outer signature on the token
Expand Down Expand Up @@ -300,7 +301,7 @@ func VerifyVerifiablePresentationJWT(ctx context.Context, verifier jwx.Verifier,
// verify signature for each credential in the vp
for i, cred := range vp.VerifiableCredential {
// verify the signature on the credential
verified, err := VerifyCredentialSignature(ctx, cred, resolver)
verified, err := VerifyCredentialSignature(ctx, cred, r)
if err != nil {
return nil, nil, nil, errors.Wrapf(err, "verifying credential %d", i)
}
Expand Down
16 changes: 8 additions & 8 deletions credential/jwt_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build jwx_es256k

package credential

import (
Expand All @@ -9,7 +7,9 @@ import (

"github.com/TBD54566975/ssi-sdk/crypto"
"github.com/TBD54566975/ssi-sdk/crypto/jwx"
"github.com/TBD54566975/ssi-sdk/did"
"github.com/TBD54566975/ssi-sdk/did/key"
"github.com/TBD54566975/ssi-sdk/did/resolution"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -108,7 +108,7 @@ func TestVerifiablePresentationJWT(t *testing.T) {
err = verifier.Verify(token)
assert.NoError(tt, err)

resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
require.NoError(tt, err)
require.NotEmpty(tt, resolver)

Expand Down Expand Up @@ -142,7 +142,7 @@ func TestVerifiablePresentationJWT(t *testing.T) {
assert.NotEmpty(tt, parsedHeaders)
assert.NotEmpty(tt, parsedPres)

resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
require.NoError(tt, err)
require.NotEmpty(tt, resolver)

Expand All @@ -155,7 +155,7 @@ func TestVerifiablePresentationJWT(t *testing.T) {
})

t.Run("with VC a single valid VC JWT", func(tt *testing.T) {
issuerPrivKey, issuerDID, err := did.GenerateDIDKey(crypto.Ed25519)
issuerPrivKey, issuerDID, err := key.GenerateDIDKey(crypto.Ed25519)
assert.NoError(tt, err)
assert.NotEmpty(tt, issuerPrivKey)
assert.NotEmpty(tt, issuerDID)
Expand All @@ -165,7 +165,7 @@ func TestVerifiablePresentationJWT(t *testing.T) {
issuerKID := expandedIssuerDID.VerificationMethod[0].ID
assert.NotEmpty(tt, issuerKID)

subjectPrivKey, subjectDID, err := did.GenerateDIDKey(crypto.Ed25519)
subjectPrivKey, subjectDID, err := key.GenerateDIDKey(crypto.Ed25519)
assert.NoError(tt, err)
assert.NotEmpty(tt, subjectPrivKey)
assert.NotEmpty(tt, subjectDID)
Expand Down Expand Up @@ -215,7 +215,7 @@ func TestVerifiablePresentationJWT(t *testing.T) {
assert.NotEmpty(tt, parsedPres)

// Verify the VP JWT
resolver, err := did.NewResolver([]did.Resolver{did.KeyResolver{}}...)
resolver, err := resolution.NewResolver([]resolution.Resolver{key.Resolver{}}...)
require.NoError(tt, err)
require.NotEmpty(tt, resolver)

Expand Down
24 changes: 13 additions & 11 deletions credential/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ import (

"github.com/TBD54566975/ssi-sdk/crypto/jwx"
"github.com/TBD54566975/ssi-sdk/did"
"github.com/TBD54566975/ssi-sdk/did/resolution"

"github.com/pkg/errors"
)

// VerifyCredentialSignature verifies the signature of a credential of any type
// TODO(gabe) support other types of credentials https://github.com/TBD54566975/ssi-sdk/issues/352
func VerifyCredentialSignature(ctx context.Context, genericCred any, resolver did.Resolver) (bool, error) {
func VerifyCredentialSignature(ctx context.Context, genericCred any, r resolution.Resolver) (bool, error) {
if genericCred == nil {
return false, errors.New("credential cannot be empty")
}
if resolver == nil {
return false, errors.New("resolver cannot be empty")
if r == nil {
return false, errors.New("resolution cannot be empty")
}
switch genericCred.(type) {
case *VerifiableCredential, VerifiableCredential, map[string]any:
Expand All @@ -38,29 +40,29 @@ func VerifyCredentialSignature(ctx context.Context, genericCred any, resolver di
return false, errors.New("data integrity signature verification not yet implemented")
case []byte:
// turn it into a string and try again
return VerifyCredentialSignature(ctx, string(genericCred.([]byte)), resolver)
return VerifyCredentialSignature(ctx, string(genericCred.([]byte)), r)
case string:
// could be a Data Integrity credential
var cred VerifiableCredential
if err := json.Unmarshal([]byte(genericCred.(string)), &cred); err == nil {
return VerifyCredentialSignature(ctx, cred, resolver)
return VerifyCredentialSignature(ctx, cred, r)
}

// could be a JWT
return VerifyJWTCredential(genericCred.(string), resolver)
return VerifyJWTCredential(genericCred.(string), r)
}
return false, fmt.Errorf("invalid credential type: %s", reflect.TypeOf(genericCred).Kind().String())
}

// VerifyJWTCredential verifies the signature of a JWT credential after parsing it to resolve the issuer DID
// The issuer DID is resolver from the provided resolver, and used to find the issuer's public key matching
// The issuer DID is resolution from the provided resolution, and used to find the issuer's public key matching
// the KID in the JWT header.
func VerifyJWTCredential(cred string, resolver did.Resolver) (bool, error) {
func VerifyJWTCredential(cred string, r resolution.Resolver) (bool, error) {
if cred == "" {
return false, errors.New("credential cannot be empty")
}
if resolver == nil {
return false, errors.New("resolver cannot be empty")
if r == nil {
return false, errors.New("resolution cannot be empty")
}
headers, token, _, err := ParseVerifiableCredentialFromJWT(cred)
if err != nil {
Expand All @@ -72,7 +74,7 @@ func VerifyJWTCredential(cred string, resolver did.Resolver) (bool, error) {
if issuerKID == "" {
return false, errors.Errorf("missing kid in header of credential<%s>", token.JwtID())
}
issuerDID, err := resolver.Resolve(context.Background(), token.Issuer())
issuerDID, err := r.Resolve(context.Background(), token.Issuer())
if err != nil {
return false, errors.Wrapf(err, "error getting issuer DID<%s> to verify credential<%s>", token.Issuer(), token.JwtID())
}
Expand Down
Loading

0 comments on commit 989cdd2

Please sign in to comment.