From 94e65a46cbd91c7f630f6840b6d9c787286d2fd4 Mon Sep 17 00:00:00 2001
From: Lyuben Penkovski <lyuben.penkovski@vereign.com>
Date: Thu, 4 Aug 2022 13:59:56 +0300
Subject: [PATCH] Enable only strict validation when parsing credentials and
 presentations

It turned out that different validation options are exluding each other
in the Aries framework, and when JSONLD validation is eanbled, the strict
validation is disabled. This commit removes the different validation options
and leaves only the Strict validation.
---
 integration/integration_test.go         |  9 +++--
 internal/service/signer/service.go      | 26 ++++++++++----
 internal/service/signer/service_test.go | 48 +++++++++++++------------
 3 files changed, 51 insertions(+), 32 deletions(-)

diff --git a/integration/integration_test.go b/integration/integration_test.go
index 0708652..211e899 100644
--- a/integration/integration_test.go
+++ b/integration/integration_test.go
@@ -122,6 +122,11 @@ func TestCreateCredentialProof(t *testing.T) {
 			vc:     []byte(credentialWithNumericalSubjectID),
 			errMsg: "verifiable credential subject of unsupported format",
 		},
+		{
+			name:   "presentation is given instead of credential",
+			vc:     []byte(presentationWithSubjectID),
+			errMsg: "verifiable credential is not valid",
+		},
 	}
 
 	for _, test := range tests {
@@ -139,8 +144,6 @@ func TestCreateCredentialProof(t *testing.T) {
 				verifiable.WithJSONLDDocumentLoader(loader),
 				verifiable.WithDisabledProofCheck(),
 				verifiable.WithStrictValidation(),
-				verifiable.WithJSONLDValidation(),
-				verifiable.WithJSONLDOnlyValidRDF(),
 			)
 			require.NoError(t, err)
 			assert.NotNil(t, vc)
@@ -239,7 +242,7 @@ func TestCreatePresentationProof(t *testing.T) {
 		errMsg string
 	}{
 		{
-			name: "presentation with credentia  subject id",
+			name: "presentation with credential subject id",
 			vp:   []byte(presentationWithSubjectID),
 		},
 		{
diff --git a/internal/service/signer/service.go b/internal/service/signer/service.go
index b50a984..b29c42b 100644
--- a/internal/service/signer/service.go
+++ b/internal/service/signer/service.go
@@ -147,6 +147,9 @@ func (s *Service) CredentialProof(ctx context.Context, req *signer.CredentialPro
 	vc, err := s.parseCredential(req.Credential)
 	if err != nil {
 		logger.Error("error parsing verifiable credential", zap.Error(err))
+		if strings.Contains(err.Error(), "JSON-LD doc has different structure after compaction") {
+			return nil, errors.New(errors.BadRequest, "JSON-LD doc has different structure after compaction: some attributes may not be described by schema")
+		}
 		return nil, errors.New(errors.BadRequest, err.Error())
 	}
 
@@ -196,10 +199,10 @@ func (s *Service) PresentationProof(ctx context.Context, req *signer.Presentatio
 	)
 	if err != nil {
 		logger.Error("error parsing verifiable presentation", zap.Error(err))
-		if strings.Contains(err.Error(), "verifiable presentation is not valid") {
-			return nil, errors.New(errors.BadRequest, err.Error())
+		if strings.Contains(err.Error(), "JSON-LD doc has different structure after compaction") {
+			return nil, errors.New(errors.BadRequest, "JSON-LD doc has different structure after compaction: some attributes may not be described by schema")
 		}
-		return nil, err
+		return nil, errors.New(errors.BadRequest, err.Error())
 	}
 
 	if len(vp.Credentials()) == 0 {
@@ -223,6 +226,9 @@ func (s *Service) PresentationProof(ctx context.Context, req *signer.Presentatio
 		_, err = s.parseCredential(credJSON)
 		if err != nil {
 			logger.Error("error validating credential", zap.Error(err))
+			if strings.Contains(err.Error(), "JSON-LD doc has different structure after compaction") {
+				return nil, errors.New(errors.BadRequest, "JSON-LD doc has different structure after compaction: some attributes may not be described by schema")
+			}
 			return nil, errors.New(errors.BadRequest, "error validating credential", err)
 		}
 
@@ -279,6 +285,9 @@ func (s *Service) VerifyCredential(ctx context.Context, req *signer.VerifyCreden
 	vc, err := s.parseCredentialWithProof(req.Credential, fetcher.PublicKeyFetcher())
 	if err != nil {
 		logger.Error("error verifying credential", zap.Error(err))
+		if strings.Contains(err.Error(), "JSON-LD doc has different structure after compaction") {
+			return nil, errors.New(errors.BadRequest, "JSON-LD doc has different structure after compaction: some attributes may not be described by schema")
+		}
 		return nil, errors.New(errors.BadRequest, err.Error())
 	}
 
@@ -315,6 +324,9 @@ func (s *Service) VerifyPresentation(ctx context.Context, req *signer.VerifyPres
 	)
 	if err != nil {
 		logger.Error("error verifying presentation", zap.Error(err))
+		if strings.Contains(err.Error(), "JSON-LD doc has different structure after compaction") {
+			return nil, errors.New(errors.BadRequest, "JSON-LD doc has different structure after compaction: some attributes may not be described by schema")
+		}
 		return nil, errors.New(errors.BadRequest, err.Error())
 	}
 
@@ -345,7 +357,10 @@ func (s *Service) VerifyPresentation(ctx context.Context, req *signer.VerifyPres
 		_, err = s.parseCredential(credJSON)
 		if err != nil {
 			logger.Error("error validating credential", zap.Error(err))
-			return nil, errors.New(errors.BadRequest, "error validating credential", err)
+			if strings.Contains(err.Error(), "JSON-LD doc has different structure after compaction") {
+				return nil, errors.New(errors.BadRequest, "JSON-LD doc has different structure after compaction: some attributes may not be described by schema")
+			}
+			return nil, errors.New(errors.BadRequest, err.Error())
 		}
 
 		if err := validateCredentialSubject(cred["credentialSubject"]); err != nil {
@@ -397,8 +412,6 @@ func (s *Service) parseCredential(vc []byte) (*verifiable.Credential, error) {
 		vc,
 		verifiable.WithJSONLDDocumentLoader(s.docLoader),
 		verifiable.WithStrictValidation(),
-		verifiable.WithJSONLDValidation(),
-		verifiable.WithJSONLDOnlyValidRDF(),
 	)
 }
 
@@ -411,7 +424,6 @@ func (s *Service) parseCredentialWithProof(vc []byte, fetcher verifiable.PublicK
 		),
 		verifiable.WithJSONLDDocumentLoader(s.docLoader),
 		verifiable.WithStrictValidation(),
-		verifiable.WithJSONLDValidation(),
 	)
 	if err != nil {
 		return nil, err
diff --git a/internal/service/signer/service_test.go b/internal/service/signer/service_test.go
index 8298509..bd81d50 100644
--- a/internal/service/signer/service_test.go
+++ b/internal/service/signer/service_test.go
@@ -11,6 +11,7 @@ import (
 	"github.com/hyperledger/aries-framework-go/pkg/doc/verifiable"
 	"github.com/square/go-jose/v3"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"go.uber.org/zap"
 
 	"code.vereign.com/gaiax/tsa/golib/errors"
@@ -421,6 +422,7 @@ func TestService_PresentationProof(t *testing.T) {
 			req: &goasigner.PresentationProofRequest{
 				Presentation: []byte(nonExistingPresentationContexts),
 			},
+			errkind: errors.BadRequest,
 			errtext: "Dereferencing a URL did not result in a valid JSON-LD context",
 		},
 		{
@@ -562,29 +564,28 @@ func TestService_PresentationProof(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			svc := signer.New(test.signer, "issuer", test.defaultKey, test.supportedKeys, http.DefaultClient, zap.NewNop())
 			res, err := svc.PresentationProof(context.Background(), test.req)
-			if err != nil {
+			if test.errtext != "" {
+				require.Error(t, err)
 				assert.Nil(t, res)
-				assert.NotEmpty(t, test.errtext, err.Error())
 				if e, ok := err.(*errors.Error); ok {
 					assert.Equal(t, test.errkind, e.Kind)
 					assert.Contains(t, e.Message, test.errtext)
 				} else {
 					assert.Contains(t, err.Error(), test.errtext)
 				}
-			} else {
-				assert.Empty(t, test.errtext)
-				assert.NotNil(t, res)
+				return
+			}
 
-				vp, ok := res.(*verifiable.Presentation)
-				assert.True(t, ok)
+			assert.NotNil(t, res)
+			vp, ok := res.(*verifiable.Presentation)
+			assert.True(t, ok)
 
-				assert.Equal(t, test.contexts, vp.Context)
-				assert.Equal(t, test.types, vp.Type)
-				assert.Equal(t, test.proofPurpose, vp.Proofs[0]["proofPurpose"])
-				assert.Equal(t, test.proofType, vp.Proofs[0]["type"])
-				assert.Equal(t, test.proofVerificationMethod, vp.Proofs[0]["verificationMethod"])
-				assert.NotEmpty(t, vp.Proofs[0]["jws"])
-			}
+			assert.Equal(t, test.contexts, vp.Context)
+			assert.Equal(t, test.types, vp.Type)
+			assert.Equal(t, test.proofPurpose, vp.Proofs[0]["proofPurpose"])
+			assert.Equal(t, test.proofType, vp.Proofs[0]["type"])
+			assert.Equal(t, test.proofVerificationMethod, vp.Proofs[0]["verificationMethod"])
+			assert.NotEmpty(t, vp.Proofs[0]["jws"])
 		})
 	}
 }
@@ -626,13 +627,16 @@ var invalidCredential = `{"invalid":"credential"}`
 
 //nolint:gosec
 var invalidCredentialContexts = `{
-  "@context": ["https://www.w3.org/2018/credentials/v123"],
-  "credentialSubject": {
-    "hello": "world"
-  },
-  "issuanceDate": "2022-06-02T17:24:05.032533+03:00",
-  "issuer": "https://example.com",
-  "type": "VerifiableCredential"
+	"@context": [
+		"https://www.w3.org/2018/credentials/v1",
+		"https://adsklfhasefugaougyasdkfhaksjdhga.com/v1"
+	],
+	"credentialSubject": {
+		"hello": "world"
+	},
+	"issuanceDate": "2022-06-02T17:24:05.032533+03:00",
+	"issuer": "https://example.com",
+	"type": "VerifiableCredential"
 }`
 
 //nolint:gosec
@@ -733,7 +737,7 @@ var invalidPresentationContexts = `{
 var nonExistingPresentationContexts = `{
   "@context": [
     "https://www.w3.org/2018/credentials/v1",
-    "https://www.nonexistingschema.org"
+    "https://www.akdjsghadkljghadlkgjhadlkgjha.org"
   ],
   "id": "did:123",
   "type": "VerifiablePresentation",
-- 
GitLab