github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/credential_ldp_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  SPDX-License-Identifier: Apache-2.0
     4  */
     5  
     6  package verifiable
     7  
     8  import (
     9  	"crypto/ed25519"
    10  	"crypto/sha256"
    11  	"encoding/base64"
    12  	"encoding/json"
    13  	"errors"
    14  	"fmt"
    15  	"strings"
    16  	"testing"
    17  
    18  	"github.com/btcsuite/btcutil/base58"
    19  	"github.com/google/uuid"
    20  	"github.com/stretchr/testify/require"
    21  
    22  	"github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub"
    23  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto"
    24  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk"
    25  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk/jwksupport"
    26  	"github.com/hyperledger/aries-framework-go/pkg/doc/ldcontext"
    27  	jsonldsig "github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld"
    28  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite"
    29  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignature2020"
    30  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/bbsblssignatureproof2020"
    31  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ecdsasecp256k1signature2019"
    32  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ed25519signature2018"
    33  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/ed25519signature2020"
    34  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/suite/jsonwebsignature2020"
    35  	sigverifier "github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier"
    36  	jsonutil "github.com/hyperledger/aries-framework-go/pkg/doc/util/json"
    37  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    38  	"github.com/hyperledger/aries-framework-go/pkg/kms/localkms"
    39  )
    40  
    41  func TestParseCredentialFromLinkedDataProof_Ed25519Signature2018(t *testing.T) {
    42  	r := require.New(t)
    43  
    44  	signer, err := newCryptoSigner(kms.ED25519Type)
    45  	r.NoError(err)
    46  
    47  	sigSuite := ed25519signature2018.New(
    48  		suite.WithSigner(signer),
    49  		suite.WithVerifier(ed25519signature2018.NewPublicKeyVerifier()))
    50  
    51  	ldpContext := &LinkedDataProofContext{
    52  		SignatureType:           "Ed25519Signature2018",
    53  		SignatureRepresentation: SignatureProofValue,
    54  		Suite:                   sigSuite,
    55  		VerificationMethod:      "did:example:123456#key1",
    56  	}
    57  
    58  	vc, err := parseTestCredential(t, []byte(validCredential))
    59  	r.NoError(err)
    60  
    61  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
    62  	r.NoError(err)
    63  
    64  	vcBytes, err := json.Marshal(vc)
    65  	r.NoError(err)
    66  
    67  	vcWithLdp, err := parseTestCredential(t, vcBytes,
    68  		WithEmbeddedSignatureSuites(sigSuite),
    69  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)))
    70  	r.NoError(err)
    71  	r.Equal(vc, vcWithLdp)
    72  }
    73  
    74  func TestParseCredentialFromLinkedDataProof_Ed25519Signature2020(t *testing.T) {
    75  	r := require.New(t)
    76  
    77  	signer, err := newCryptoSigner(kms.ED25519Type)
    78  	r.NoError(err)
    79  
    80  	sigSuite := ed25519signature2020.New(
    81  		suite.WithSigner(signer),
    82  		suite.WithVerifier(ed25519signature2020.NewPublicKeyVerifier()))
    83  
    84  	ldpContext := &LinkedDataProofContext{
    85  		SignatureType:           "Ed25519Signature2020",
    86  		SignatureRepresentation: SignatureProofValue,
    87  		Suite:                   sigSuite,
    88  		VerificationMethod:      "did:example:123456#key1",
    89  	}
    90  
    91  	vc, err := parseTestCredential(t, []byte(validCredential))
    92  	r.NoError(err)
    93  
    94  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
    95  	r.NoError(err)
    96  
    97  	vcBytes, err := json.Marshal(vc)
    98  	r.NoError(err)
    99  
   100  	vcWithLdp, err := parseTestCredential(t, vcBytes,
   101  		WithEmbeddedSignatureSuites(sigSuite),
   102  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)))
   103  	r.NoError(err)
   104  	r.Equal(vc, vcWithLdp)
   105  }
   106  
   107  //nolint:lll
   108  func TestParseCredentialFromLinkedDataProof_JSONLD_Validation(t *testing.T) {
   109  	r := require.New(t)
   110  
   111  	pubKeyBytes := base58.Decode("DqS5F3GVe3rCxucgi4JBNagjv4dKoHc8TDLDw9kR58Pz")
   112  
   113  	localCrypto, err := createLocalCrypto()
   114  	r.NoError(err)
   115  
   116  	sigSuite := ed25519signature2018.New(
   117  		suite.WithVerifier(suite.NewCryptoVerifier(localCrypto)))
   118  
   119  	vcOptions := []CredentialOpt{
   120  		WithEmbeddedSignatureSuites(sigSuite),
   121  		WithPublicKeyFetcher(SingleKey(pubKeyBytes, "Ed25519Signature2018")),
   122  		WithStrictValidation(),
   123  	}
   124  
   125  	t.Run("valid VC", func(t *testing.T) {
   126  		vcJSON := `
   127  {
   128    "@context": [
   129      "https://www.w3.org/2018/credentials/v1",
   130      "https://www.w3.org/2018/credentials/examples/v1"
   131    ],
   132    "type": [
   133      "VerifiableCredential",
   134      "UniversityDegreeCredential"
   135    ],
   136    "id": "http://example.gov/credentials/3732",
   137    "issuanceDate": "2020-03-16T22:37:26.544Z",
   138    "credentialSubject": {
   139      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
   140      "degree": {
   141        "type": "BachelorDegree",
   142        "degree": "MIT"
   143      },
   144      "name": "Jayden Doe",
   145      "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1"
   146    },
   147    "profile": "",
   148    "issuer": "did:web:vc.transmute.world",
   149    "proof": {
   150      "type": "Ed25519Signature2018",
   151      "created": "2019-12-11T03:50:55Z",
   152      "verificationMethod": "did:web:vc.transmute.world#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN",
   153      "proofPurpose": "assertionMethod",
   154      "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MlJy4Sn47kgse7SKc56OKkJUhu-Z3CPiv2_MdjOQXJk8Bpzxa-JuinjJNN3YkYb6tPE6poIhBTlgnc_c5qQsBA"
   155    }
   156  }
   157  `
   158  
   159  		vcWithLdp, err := parseTestCredential(t, []byte(vcJSON), vcOptions...)
   160  		r.NoError(err)
   161  		r.NotNil(t, vcWithLdp)
   162  	})
   163  
   164  	t.Run("VC with unknown field", func(t *testing.T) {
   165  		// "newProp" is a field not defined in any context.
   166  		vcJSON := `
   167  {
   168    "@context": [
   169      "https://www.w3.org/2018/credentials/v1",
   170      "https://www.w3.org/2018/credentials/examples/v1"
   171    ],
   172    "type": [
   173      "VerifiableCredential",
   174      "UniversityDegreeCredential"
   175    ],
   176    "id": "http://example.gov/credentials/3732",
   177    "issuanceDate": "2020-03-16T22:37:26.544Z",
   178    "credentialSubject": {
   179      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
   180      "degree": {
   181        "type": "BachelorDegree",
   182        "degree": "MIT"
   183      },
   184      "name": "Jayden Doe",
   185      "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1"
   186    },
   187    "profile": "",
   188    "issuer": "did:web:vc.transmute.world",
   189    "proof": {
   190      "type": "Ed25519Signature2018",
   191      "created": "2019-12-11T03:50:55Z",
   192      "verificationMethod": "did:web:vc.transmute.world#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN",
   193      "proofPurpose": "assertionMethod",
   194      "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MlJy4Sn47kgse7SKc56OKkJUhu-Z3CPiv2_MdjOQXJk8Bpzxa-JuinjJNN3YkYb6tPE6poIhBTlgnc_c5qQsBA"
   195    },
   196    "newProp": "foo"
   197  }
   198  `
   199  
   200  		vcWithLdp, err := parseTestCredential(t, []byte(vcJSON), vcOptions...)
   201  		r.Error(err)
   202  		r.EqualError(err, "JSON-LD doc has different structure after compaction")
   203  		r.Nil(vcWithLdp)
   204  	})
   205  
   206  	t.Run("VC with unknown proof field", func(t *testing.T) {
   207  		// "newProp" is a field not defined in any context.
   208  		vcJSON := `
   209  {
   210    "@context": [
   211      "https://www.w3.org/2018/credentials/v1",
   212      "https://www.w3.org/2018/credentials/examples/v1"
   213    ],
   214    "type": [
   215      "VerifiableCredential",
   216      "UniversityDegreeCredential"
   217    ],
   218    "id": "http://example.gov/credentials/3732",
   219    "issuanceDate": "2020-03-16T22:37:26.544Z",
   220    "credentialSubject": {
   221      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
   222      "degree": {
   223        "type": "BachelorDegree",
   224        "degree": "MIT"
   225      },
   226      "name": "Jayden Doe",
   227      "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1"
   228    },
   229    "profile": "",
   230    "issuer": "did:web:vc.transmute.world",
   231    "proof": {
   232      "type": "Ed25519Signature2018",
   233      "created": "2019-12-11T03:50:55Z",
   234      "verificationMethod": "did:web:vc.transmute.world#z6MksHh7qHWvybLg5QTPPdG2DgEjjduBDArV9EF9mRiRzMBN",
   235      "proofPurpose": "assertionMethod",
   236      "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MlJy4Sn47kgse7SKc56OKkJUhu-Z3CPiv2_MdjOQXJk8Bpzxa-JuinjJNN3YkYb6tPE6poIhBTlgnc_c5qQsBA",
   237      "newProp": "foo"
   238    }
   239  }
   240  `
   241  
   242  		vcWithLdp, err := parseTestCredential(t, []byte(vcJSON), vcOptions...)
   243  		r.Error(err)
   244  		r.EqualError(err, "JSON-LD doc has different structure after compaction")
   245  		r.Nil(vcWithLdp)
   246  	})
   247  
   248  	t.Run("VC with different mapped field", func(t *testing.T) {
   249  		localJSONLDContext := `
   250  {
   251    "@context":
   252    {
   253        "@version": 1.1,
   254        "xsd": "http://www.w3.org/2001/XMLSchema#",
   255        "schema": "http://schema.org/",
   256        "comments": "schema:text"
   257    }
   258  }
   259  `
   260  
   261  		docLoader := createTestDocumentLoader(t, ldcontext.Document{
   262  			URL:     "http://localhost:9191/example.jsonld",
   263  			Content: []byte(localJSONLDContext),
   264  		})
   265  
   266  		vcJSON := `
   267  {
   268    "@context": [
   269      "https://www.w3.org/2018/credentials/v1",
   270      "http://localhost:9191/example.jsonld"
   271    ],
   272    "id": "http://neo-flow.com/credentials/e94a16cb-35b2-4301-9fb6-7af3d8fe7b81",
   273    "type": ["VerifiableCredential", "BillOfLadingCredential"],
   274    "issuer": "did:example:76e12ec712ebc6f1c221ebfeb1f",
   275    "issuanceDate": "2020-04-09T21:13:13Z",
   276    "credentialSubject": {
   277  	"id": "https://example.edu/status/24",
   278      "comments": ""
   279    },
   280    "proof": {
   281      "type": "Ed25519Signature2018",
   282      "created": "2020-04-26T20:14:44Z",
   283      "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..LFKayh8S3hxHc2hZJP-ARH6qZO06pBUJgPg9osvH2OD-OftB-SvIv3Tni_j0fVwK5iYWfChAs8Cvw-czQ2S1Dw",
   284      "proofPurpose": "assertionMethod",
   285      "verificationMethod": "did:v1:test:nym:z6MkfG5HTrBXzsAP8AbayNpG3ZaoyM4PCqNPrdWQRSpHDV6J#z6MkqfvdBsFw4QdGrZrnx7L1EKfY5zh9tT4gumUGsMMEZHY3"
   286    }
   287  }
   288  `
   289  
   290  		vc, err := parseTestCredential(t, []byte(vcJSON),
   291  			WithDisabledProofCheck(),
   292  			WithStrictValidation(),
   293  			WithJSONLDDocumentLoader(docLoader),
   294  		)
   295  		require.NoError(t, err)
   296  		require.NotNil(t, vc)
   297  	})
   298  }
   299  
   300  //nolint:lll
   301  func TestWithStrictValidationOfJsonWebSignature2020(t *testing.T) {
   302  	vcJSON := `
   303  {
   304    "@context": [
   305      "https://www.w3.org/2018/credentials/v1",
   306      "https://www.w3.org/2018/credentials/examples/v1",
   307      "https://trustbloc.github.io/context/vc/examples-v1.jsonld"
   308    ],
   309    "credentialStatus": {
   310      "id": "http://issuer.vc.rest.example.com:8070/status/1",
   311      "type": "CredentialStatusList2017"
   312    },
   313    "credentialSubject": {
   314      "degree": {
   315        "degree": "MIT",
   316        "type": "BachelorDegree"
   317      },
   318      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
   319      "name": "Jayden Doe",
   320      "spouse": "did:example:c276e12ec21ebfeb1f712ebc6f1"
   321    },
   322    "id": "https://example.com/credentials/720df5b8-d6c9-47e6-a024-0abc1507e549",
   323    "issuanceDate": "2020-03-16T22:37:26.544Z",
   324    "issuer": {
   325      "id": "did:example:76e12ec712ebc6f1c221ebfeb1f",
   326      "name": "Example University"
   327    },
   328    "proof": {
   329      "created": "2021-04-23T20:01:46.987287+03:00",
   330      "jws": "eyJhbGciOiJKc29uV2ViU2lnbmF0dXJlMjAyMCIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..MQIszCkfU3EfFEor_TQ5-BDhQYd9pH6fqY2cHHmaNt5bYkJL15IzA8OZPDOk8YvLLxhQv1ZS1V32JkKdHvePBw",
   331      "proofPurpose": "assertionMethod",
   332      "type": "JsonWebSignature2020",
   333      "verificationMethod": "did:key:z6MknC1wwS6DEYwtGbZZo2QvjQjkh2qSBjb4GYmbye8dv4S5#z6MknC1wwS6DEYwtGbZZo2QvjQjkh2qSBjb4GYmbye8dv4S5"
   334    },
   335    "type": [
   336      "VerifiableCredential",
   337      "UniversityDegreeCredential"
   338    ]
   339  }`
   340  	sigSuite := jsonwebsignature2020.New(
   341  		suite.WithVerifier(jsonwebsignature2020.NewPublicKeyVerifier()))
   342  
   343  	decoded, err := base64.StdEncoding.DecodeString("cvXX3pUdyfEgL2k73NtHOxPX0T4NyABBAfthTYKtFkI=")
   344  	require.NoError(t, err)
   345  
   346  	publicKey := make([]byte, ed25519.PublicKeySize)
   347  	copy(publicKey[0:32], decoded)
   348  	rv := ed25519.PublicKey(publicKey)
   349  
   350  	j, err := jwksupport.JWKFromKey(rv)
   351  	require.NoError(t, err)
   352  
   353  	vcWithLdp, err := parseTestCredential(t, []byte(vcJSON),
   354  		WithEmbeddedSignatureSuites(sigSuite),
   355  		WithPublicKeyFetcher(func(issuerID, keyID string) (*sigverifier.PublicKey, error) {
   356  			return &sigverifier.PublicKey{
   357  				Type: "JsonWebKey2020",
   358  				JWK:  j,
   359  			}, nil
   360  		}),
   361  		WithExternalJSONLDContext("https://w3id.org/security/jws/v1"),
   362  		WithStrictValidation())
   363  
   364  	require.NoError(t, err)
   365  	require.NotNil(t, vcWithLdp)
   366  }
   367  
   368  func TestExtraContextWithLDP(t *testing.T) {
   369  	r := require.New(t)
   370  
   371  	vcJSON := `
   372  {
   373    "@context": [
   374      "https://www.w3.org/2018/credentials/v1",
   375      "https://trustbloc.github.io/context/vc/examples-v1.jsonld"
   376    ],
   377    "id": "http://example.edu/credentials/3732",
   378    "type": ["VerifiableCredential", "SupportingActivity"],
   379    "issuer": "https://example.edu/issuers/14",
   380    "issuanceDate": "2010-01-01T19:23:24Z",
   381    "credentialSubject": {
   382      "id": "did:example:ebfeb1f712ebc6f1c276e12ec21"
   383    },
   384    "credentialStatus": {
   385      "id": "https://example.edu/status/24",
   386      "type": "CredentialStatusList2017"
   387    }
   388  }`
   389  
   390  	signer, err := newCryptoSigner(kms.ED25519Type)
   391  	r.NoError(err)
   392  
   393  	sigSuite := ed25519signature2018.New(
   394  		suite.WithSigner(signer),
   395  		suite.WithVerifier(ed25519signature2018.NewPublicKeyVerifier()))
   396  
   397  	ldpContext := &LinkedDataProofContext{
   398  		SignatureType:           "Ed25519Signature2018",
   399  		SignatureRepresentation: SignatureProofValue,
   400  		Suite:                   sigSuite,
   401  		VerificationMethod:      "did:example:123456#key1",
   402  	}
   403  
   404  	vc, err := parseTestCredential(t, []byte(vcJSON))
   405  	r.NoError(err)
   406  
   407  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
   408  	r.NoError(err)
   409  
   410  	vcBytes, err := json.Marshal(vc)
   411  	r.NoError(err)
   412  
   413  	vcWithLdp, err := parseTestCredential(t, vcBytes,
   414  		WithEmbeddedSignatureSuites(sigSuite),
   415  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)),
   416  		WithStrictValidation())
   417  	r.NoError(err)
   418  	r.Equal(vc, vcWithLdp)
   419  	r.NotNil(vcWithLdp)
   420  
   421  	// Drop https://trustbloc.github.io/context/vc/examples-v1.jsonld context where
   422  	// SupportingActivity and CredentialStatusList2017 are defined.
   423  	vcMap, err := jsonutil.ToMap(vcBytes)
   424  	r.NoError(err)
   425  
   426  	vcMap["@context"] = baseContext
   427  	vcBytes, err = json.Marshal(vcMap)
   428  	r.NoError(err)
   429  
   430  	vcWithLdp, err = parseTestCredential(t, vcBytes,
   431  		WithEmbeddedSignatureSuites(sigSuite),
   432  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)),
   433  		WithStrictValidation())
   434  	r.Error(err)
   435  	r.EqualError(err, "decode new credential: check embedded proof: check linked data proof: invalid JSON-LD context")
   436  	r.Nil(vcWithLdp)
   437  
   438  	// Use extra context.
   439  	vcWithLdp, err = parseTestCredential(t, vcBytes,
   440  		WithEmbeddedSignatureSuites(sigSuite),
   441  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)),
   442  		WithExternalJSONLDContext("https://trustbloc.github.io/context/vc/examples-v1.jsonld"),
   443  		WithStrictValidation())
   444  	r.NoError(err)
   445  	r.NotNil(vcWithLdp)
   446  
   447  	// Use extra context.
   448  	vcWithLdp, err = parseTestCredential(t, vcBytes,
   449  		WithEmbeddedSignatureSuites(sigSuite),
   450  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)),
   451  		WithExternalJSONLDContext("https://trustbloc.github.io/context/vc/examples-v1.jsonld"),
   452  		WithStrictValidation())
   453  	r.NoError(err)
   454  	r.NotNil(vcWithLdp)
   455  
   456  	// Use extra in-memory context.
   457  	dummyContext := `
   458  {
   459      "@context": {
   460        "@version": 1.1,
   461  
   462        "id": "@id",
   463        "type": "@type",
   464  
   465        "ex": "https://example.org/examples#",
   466  
   467        "CredentialStatusList2017": "ex:CredentialStatusList2017",
   468        "DocumentVerification": "ex:DocumentVerification",
   469        "SupportingActivity": "ex:SupportingActivity"
   470      }
   471  }
   472  `
   473  	loader := createTestDocumentLoader(t, ldcontext.Document{
   474  		URL:     "http://localhost:8652/dummy.jsonld",
   475  		Content: []byte(dummyContext),
   476  	})
   477  
   478  	vcWithLdp, err = ParseCredential(vcBytes,
   479  		WithEmbeddedSignatureSuites(sigSuite),
   480  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)),
   481  		WithExternalJSONLDContext("http://localhost:8652/dummy.jsonld"),
   482  		WithJSONLDDocumentLoader(loader),
   483  		WithStrictValidation())
   484  	r.NoError(err)
   485  	r.NotNil(vcWithLdp)
   486  }
   487  
   488  func TestParseCredentialFromLinkedDataProof_BbsBlsSignature2020(t *testing.T) {
   489  	r := require.New(t)
   490  
   491  	pubKey, privKey, err := bbs12381g2pub.GenerateKeyPair(sha256.New, nil)
   492  	r.NoError(err)
   493  
   494  	bbsSigner, err := newBBSSigner(privKey)
   495  	r.NoError(err)
   496  
   497  	sigSuite := bbsblssignature2020.New(
   498  		suite.WithSigner(bbsSigner),
   499  		suite.WithVerifier(bbsblssignature2020.NewG2PublicKeyVerifier()))
   500  
   501  	ldpContext := &LinkedDataProofContext{
   502  		SignatureType:           "BbsBlsSignature2020",
   503  		SignatureRepresentation: SignatureProofValue,
   504  		Suite:                   sigSuite,
   505  		VerificationMethod:      "did:example:123456#key1",
   506  	}
   507  
   508  	vcJSON := `
   509  	{
   510  	 "@context": [
   511  	   "https://www.w3.org/2018/credentials/v1",
   512  	   "https://w3id.org/citizenship/v1",
   513  	   "https://w3id.org/security/bbs/v1"
   514  	 ],
   515  	 "id": "https://issuer.oidp.uscis.gov/credentials/83627465",
   516  	 "type": [
   517  	   "VerifiableCredential",
   518  	   "PermanentResidentCard"
   519  	 ],
   520  	 "issuer": "did:example:489398593",
   521  	 "identifier": "83627465",
   522  	 "name": "Permanent Resident Card",
   523  	 "description": "Government of Example Permanent Resident Card.",
   524  	 "issuanceDate": "2019-12-03T12:19:52Z",
   525  	 "expirationDate": "2029-12-03T12:19:52Z",
   526  	 "credentialSubject": {
   527  	   "id": "did:example:b34ca6cd37bbf23",
   528  	   "type": [
   529  	     "PermanentResident",
   530  	     "Person"
   531  	   ],
   532  	   "givenName": "JOHN",
   533  	   "familyName": "SMITH",
   534  	   "gender": "Male",
   535  	   "image": "data:image/png;base64,iVBORw0KGgokJggg==",
   536  	   "residentSince": "2015-01-01",
   537  	   "lprCategory": "C09",
   538  	   "lprNumber": "999-999-999",
   539  	   "commuterClassification": "C1",
   540  	   "birthCountry": "Bahamas",
   541  	   "birthDate": "1958-07-17"
   542  	 }
   543  	}
   544  	`
   545  
   546  	vc, err := parseTestCredential(t, []byte(vcJSON))
   547  	r.NoError(err)
   548  	r.Len(vc.Proofs, 0)
   549  
   550  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
   551  	r.NoError(err)
   552  	r.Len(vc.Proofs, 1)
   553  	r.Equal("BbsBlsSignature2020", vc.Proofs[0]["type"])
   554  	r.NotEmpty(vc.Proofs[0]["proofValue"])
   555  
   556  	vcBytes, err := json.Marshal(vc)
   557  	r.NoError(err)
   558  	r.NotEmpty(vcBytes)
   559  
   560  	pubKeyBytes, err := pubKey.Marshal()
   561  	r.NoError(err)
   562  
   563  	vcVerified, err := parseTestCredential(t, vcBytes,
   564  		WithEmbeddedSignatureSuites(sigSuite),
   565  		WithPublicKeyFetcher(SingleKey(pubKeyBytes, "Bls12381G2Key2020")),
   566  	)
   567  	r.NoError(err)
   568  	r.NotNil(vcVerified)
   569  	r.Equal(vc, vcVerified)
   570  }
   571  
   572  //nolint:lll
   573  func TestParseCredentialFromLinkedDataProof_BbsBlsSignatureProof2020(t *testing.T) {
   574  	r := require.New(t)
   575  
   576  	// Case 17 (https://github.com/w3c-ccg/vc-http-api/pull/128)
   577  	vcJSON := `{
   578    "@context": [
   579      "https://www.w3.org/2018/credentials/v1",
   580      "https://w3id.org/citizenship/v1",
   581      "https://w3id.org/security/bbs/v1"
   582    ],
   583    "id": "https://issuer.oidp.uscis.gov/credentials/83627465",
   584    "type": [
   585      "PermanentResidentCard",
   586      "VerifiableCredential"
   587    ],
   588    "description": "Government of Example Permanent Resident Card.",
   589    "name": "Permanent Resident Card",
   590    "credentialSubject": {
   591      "id": "did:example:b34ca6cd37bbf23",
   592      "type": [
   593        "Person",
   594        "PermanentResident"
   595      ],
   596      "birthDate": "1958-07-17"
   597    },
   598    "expirationDate": "2029-12-03T12:19:52Z",
   599    "issuanceDate": "2019-12-03T12:19:52Z",
   600    "issuer": "did:key:zUC724vuGvHpnCGFG1qqpXb81SiBLu3KLSqVzenwEZNPoY35i2Bscb8DLaVwHvRFs6F2NkNNXRcPWvqnPDUd9ukdjLkjZd3u9zzL4wDZDUpkPAatLDGLEYVo8kkAzuAKJQMr7N2",
   601    "proof": {
   602      "type": "BbsBlsSignatureProof2020",
   603      "created": "2021-02-23T19:31:12Z",
   604      "nonce": "G/hn9Ca9bIWZpJGlhnr/41r8RB0OO0TLChZASr3QJVztdri/JzS8Zf/xWJT5jW78zlM=",
   605      "proofPurpose": "assertionMethod",
   606      "proofValue": "ABgA/wYfjSxZz8DBQHTIuX+F0MmeskKbywg6NSMGHOqJ9LvYrfaakmMaPh+UsJxIK1z5v3NuiRP4OGhIbYgjo0KovKMZzluSzCGwzAyXui2hnFlrySj3RP+WNmWd+6QZQ6bEm+pyhNC6VrEMVDxJ2TH7DShbx6GFQ6RLvuS0Xf38GuOhX26+5RJ9RBs5Qaj4/UKsTfc9AAAAdKGdxxloz3ZJ2QnoFlqicO6MviT8yzeyf5gILHg8YUjNIAVJJNsh26kBqIdQkaROpQAAAAIVX5Y1Jy9hgEQgqUld/aGN2uxOLZAJsri9BRRHoFNWkkcF73EV4BE9+Hs+8fuvX0SNDAmomTVz6vSrq58bjHZ+tmJ5JddwT1tCunHV330hqleI47eAqwGuY9hdeSixzfL0/CGnZ2XoV2YAybVTcupSAAAACw03E8CoLBvqXeMV7EtRTwMpKQmEUyAM5iwC2ZaAkDLnFOt2iHR4P8VExFmOZCl94gt6bqWuODhJ5mNCJXjEO9wmx3RNM5prB7Au5g59mdcuuY/GCKmKNt087BoHYG//dEFi4Q+bRpVE5MKaGv/JZd/LmPAfKfuj5Tr37m0m3hx6HROmIv0yHcakQlNQqM6QuRQLMr2U+nj4U4OFQZfMg3A+f6fVS6T18WLq4xbHc/2L1bYhIw+SjXwkj20cGhEBsmFOqj4oY5AzjN1t4gfzb5itxQNkZFVE2IdBP9v/Ck8rMQLmxs68PDPcp6CAb9dvMS0fX5CTTbJHqG4XEjYRaBVG0Ji5g3vTpGVAA4jqOzpTbxKQawA4SvddV8NUUm4N/zCeWMermi3yRhZRl1AXa8BqGO+mXNI7yAPjn1YDoGliQkoQc5B4CYY/5ldP19XS2hV5Ak16AJtD4tdeqbaX0bo=",
   607      "verificationMethod": "did:key:zUC724vuGvHpnCGFG1qqpXb81SiBLu3KLSqVzenwEZNPoY35i2Bscb8DLaVwHvRFs6F2NkNNXRcPWvqnPDUd9ukdjLkjZd3u9zzL4wDZDUpkPAatLDGLEYVo8kkAzuAKJQMr7N2#zUC724vuGvHpnCGFG1qqpXb81SiBLu3KLSqVzenwEZNPoY35i2Bscb8DLaVwHvRFs6F2NkNNXRcPWvqnPDUd9ukdjLkjZd3u9zzL4wDZDUpkPAatLDGLEYVo8kkAzuAKJQMr7N2"
   608    }
   609  }`
   610  
   611  	nonceBytes, err := base64.StdEncoding.DecodeString("G/hn9Ca9bIWZpJGlhnr/41r8RB0OO0TLChZASr3QJVztdri/JzS8Zf/xWJT5jW78zlM=")
   612  	require.NoError(t, err)
   613  
   614  	sigSuite := bbsblssignatureproof2020.New(
   615  		suite.WithCompactProof(),
   616  		suite.WithVerifier(bbsblssignatureproof2020.NewG2PublicKeyVerifier(nonceBytes)))
   617  
   618  	// pkBase58 from did:key:zUC724vuGvHpnCGFG1qqpXb81SiBLu3KLSqVzenwEZNPoY35i2Bscb8DLaVwHvRFs6F2NkNNXRcPWvqnPDUd9ukdjLkjZd3u9zzL4wDZDUpkPAatLDGLEYVo8kkAzuAKJQMr7N2
   619  	pkBase58 := "nEP2DEdbRaQ2r5Azeatui9MG6cj7JUHa8GD7khub4egHJREEuvj4Y8YG8w51LnhPEXxVV1ka93HpSLkVzeQuuPE1mH9oCMrqoHXAKGBsuDT1yJvj9cKgxxLCXiRRirCycki"
   620  	pubKeyBytes := base58.Decode(pkBase58)
   621  
   622  	vcVerified, err := parseTestCredential(t, []byte(vcJSON),
   623  		WithEmbeddedSignatureSuites(sigSuite),
   624  		WithPublicKeyFetcher(SingleKey(pubKeyBytes, "Bls12381G2Key2020")),
   625  	)
   626  	r.NoError(err)
   627  	r.NotNil(vcVerified)
   628  }
   629  
   630  func TestParseCredentialFromLinkedDataProof_JsonWebSignature2020_Ed25519(t *testing.T) {
   631  	r := require.New(t)
   632  
   633  	signer, err := newCryptoSigner(kms.ED25519Type)
   634  	r.NoError(err)
   635  
   636  	localCrypto, err := createLocalCrypto()
   637  	r.NoError(err)
   638  
   639  	sigSuite := jsonwebsignature2020.New(
   640  		suite.WithSigner(signer), // TODO replace getEd25519TestSigner with LocalCrypto/KMS
   641  		suite.WithVerifier(suite.NewCryptoVerifier(localCrypto)))
   642  
   643  	ldpContext := &LinkedDataProofContext{
   644  		SignatureType:           "JsonWebSignature2020",
   645  		SignatureRepresentation: SignatureJWS,
   646  		Suite:                   sigSuite,
   647  		VerificationMethod:      "did:example:123456#key1",
   648  	}
   649  
   650  	vc, err := parseTestCredential(t, []byte(validCredential))
   651  	r.NoError(err)
   652  
   653  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
   654  	r.NoError(err)
   655  
   656  	vcBytes, err := json.Marshal(vc)
   657  	r.NoError(err)
   658  
   659  	vcWithLdp, err := parseTestCredential(t, vcBytes,
   660  		WithEmbeddedSignatureSuites(sigSuite),
   661  		WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), "Ed25519Signature2018")))
   662  	r.NoError(err)
   663  	r.Equal(vc, vcWithLdp)
   664  }
   665  
   666  func TestParseCredentialFromLinkedDataProof_JsonWebSignature2020_ecdsaP256(t *testing.T) {
   667  	r := require.New(t)
   668  
   669  	signer, err := newCryptoSigner(kms.ECDSAP256TypeIEEEP1363)
   670  	require.NoError(t, err)
   671  
   672  	localCrypto, err := createLocalCrypto()
   673  	r.NoError(err)
   674  
   675  	sigSuite := jsonwebsignature2020.New(
   676  		suite.WithSigner(signer),
   677  		suite.WithVerifier(suite.NewCryptoVerifier(localCrypto)))
   678  
   679  	ldpContext := &LinkedDataProofContext{
   680  		SignatureType:           "JsonWebSignature2020",
   681  		SignatureRepresentation: SignatureJWS,
   682  		Suite:                   sigSuite,
   683  		VerificationMethod:      "did:example:123456#key1",
   684  	}
   685  
   686  	vc, err := parseTestCredential(t, []byte(validCredential))
   687  	r.NoError(err)
   688  
   689  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
   690  	r.NoError(err)
   691  
   692  	vcBytes, err := json.Marshal(vc)
   693  	r.NoError(err)
   694  
   695  	j, err := jwksupport.JWKFromKey(signer.PublicKey())
   696  	require.NoError(t, err)
   697  
   698  	vcWithLdp, err := parseTestCredential(t, vcBytes,
   699  		WithEmbeddedSignatureSuites(sigSuite),
   700  		WithPublicKeyFetcher(func(issuerID, keyID string) (*sigverifier.PublicKey, error) {
   701  			return &sigverifier.PublicKey{
   702  				Type:  "JwsVerificationKey2020",
   703  				Value: signer.PublicKeyBytes(),
   704  				JWK:   j,
   705  			}, nil
   706  		}))
   707  	r.NoError(err)
   708  	r.Equal(vc, vcWithLdp)
   709  }
   710  
   711  func TestParseCredentialFromLinkedDataProof_EcdsaSecp256k1Signature2019(t *testing.T) {
   712  	r := require.New(t)
   713  
   714  	signer, err := newCryptoSigner(kms.ECDSASecp256k1TypeIEEEP1363)
   715  	require.NoError(t, err)
   716  
   717  	sigSuite := ecdsasecp256k1signature2019.New(
   718  		suite.WithSigner(signer),
   719  		// TODO use suite.NewCryptoVerifier(createLocalCrypto()) verifier as soon as
   720  		//  tinkcrypto will support secp256k1 (https://github.com/hyperledger/aries-framework-go/issues/1285)
   721  		suite.WithVerifier(ecdsasecp256k1signature2019.NewPublicKeyVerifier()))
   722  
   723  	ldpContext := &LinkedDataProofContext{
   724  		SignatureType:           "EcdsaSecp256k1Signature2019",
   725  		SignatureRepresentation: SignatureJWS,
   726  		Suite:                   sigSuite,
   727  		VerificationMethod:      "did:example:123456#key1",
   728  	}
   729  
   730  	vc, err := parseTestCredential(t, []byte(validCredential))
   731  	r.NoError(err)
   732  
   733  	err = vc.AddLinkedDataProof(ldpContext, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
   734  	r.NoError(err)
   735  
   736  	vcBytes, err := json.Marshal(vc)
   737  	r.NoError(err)
   738  
   739  	j, err := jwksupport.JWKFromKey(signer.PublicKey())
   740  	require.NoError(t, err)
   741  
   742  	// JWK encoded public key
   743  	vcWithLdp, err := parseTestCredential(t, vcBytes,
   744  		WithEmbeddedSignatureSuites(sigSuite),
   745  		WithPublicKeyFetcher(func(issuerID, keyID string) (*sigverifier.PublicKey, error) {
   746  			return &sigverifier.PublicKey{
   747  				Type: "EcdsaSecp256k1VerificationKey2019",
   748  				JWK:  j,
   749  			}, nil
   750  		}))
   751  	r.NoError(err)
   752  	r.Equal(vc, vcWithLdp)
   753  
   754  	// Bytes encoded public key (can come in e.g. publicKeyHex field)
   755  	vcWithLdp, err = parseTestCredential(t, vcBytes,
   756  		WithEmbeddedSignatureSuites(sigSuite),
   757  		WithPublicKeyFetcher(func(issuerID, keyID string) (*sigverifier.PublicKey, error) {
   758  			return &sigverifier.PublicKey{
   759  				Type:  "EcdsaSecp256k1VerificationKey2019",
   760  				Value: signer.PublicKeyBytes(),
   761  			}, nil
   762  		}))
   763  	r.NoError(err)
   764  	r.Equal(vc, vcWithLdp)
   765  }
   766  
   767  //nolint:lll
   768  func TestParseCredential_JSONLiteralsNotSupported(t *testing.T) {
   769  	cmtrJSONLD := `
   770  {
   771    "@context": {
   772      "@version": 1.1,
   773      "@protected": true,
   774      "name": "http://schema.org/name",
   775      "description": "http://schema.org/description",
   776      "image": {
   777        "@id": "http://schema.org/image",
   778        "@type": "@id"
   779      },
   780      "hetc": "http://localhost:9393/cmtr#",
   781      "cmtr": {
   782        "@id": "hetc:cmtr",
   783        "@type": "@json"
   784      }
   785    }
   786  }
   787  `
   788  
   789  	docLoader := createTestDocumentLoader(t, ldcontext.Document{
   790  		URL:     "http://127.0.0.1:53401/cmtr.jsonld",
   791  		Content: []byte(cmtrJSONLD),
   792  	})
   793  
   794  	vcJSON := `{
   795    "@context": [
   796      "https://www.w3.org/2018/credentials/v1",
   797      "http://127.0.0.1:53401/cmtr.jsonld"
   798    ],
   799    "id": "http://example.com/credentials/123",
   800    "type": [
   801      "VerifiableCredential",
   802      "CertifiedMillTestReport"
   803    ],
   804    "issuer": "did:elem:ropsten:EiBJJPdo-ONF0jxqt8mZYEj9Z7FbdC87m2xvN0_HAbcoEg",
   805    "issuanceDate": "2020-03-09T18:19:10.033Z",
   806    "name": "Certified Mill Test Report",
   807    "description": "A mill test report (MTR) and often also called a certified mill test report, certified material test report, mill test certificate (MTC), inspection certificate, certificate of test, or a host of other names, is a quality assurance document used in the metals industry that certifies a material's chemical and physical properties and states a product made of metal (steel, aluminum, brass or other alloys) complies with an international standards organization (such as ANSI, ASME, etc.) specific standards.",
   808    "credentialSubject": {
   809      "cmtr": {
   810        "additionalRemarks": "Product is coated for high temperatures. STEEL-IT High Temp coatings are intended for use where surface temperatures reach above 200°F, such as the external surfaces of industrial ovens, certain types of piping used in chemical and other manufacturing, and more. Customers choose which high temp coating is right for them based on whether USDA approval is required; whether the surface will be exposed to corrosive chemicals; or whether the surface will be exposed to sunlight or other sources of ultraviolet radiation.",
   811        "authorizingPartyDate": "February 19, 2020",
   812        "authorizingPartyName": "Stacy Slater",
   813        "authorizingPartyTitle": "Chief Quality Assurance Officer",
   814        "certificateNumber": "CT 001",
   815        "chemicalProperties": {
   816          "columns": [
   817            {
   818              "field": "heatNumber",
   819              "title": "Heat Number"
   820            },
   821            {
   822              "field": "C",
   823              "title": "C"
   824            },
   825            {
   826              "field": "Si",
   827              "title": "Si"
   828            },
   829            {
   830              "field": "P",
   831              "title": "P"
   832            },
   833            {
   834              "field": "S",
   835              "title": "S"
   836            },
   837            {
   838              "field": "V",
   839              "title": "V"
   840            },
   841            {
   842              "field": "Cr",
   843              "title": "Cr"
   844            },
   845            {
   846              "field": "Mn",
   847              "title": "Mn"
   848            },
   849            {
   850              "field": "Ni",
   851              "title": "Ni"
   852            },
   853            {
   854              "field": "Cu",
   855              "title": "Cu"
   856            },
   857            {
   858              "field": "Mo",
   859              "title": "Mo"
   860            },
   861            {
   862              "field": "Sn",
   863              "title": "Sn"
   864            }
   865          ],
   866          "rows": [
   867            {
   868              "C": ".1",
   869              "heatNumber": "404012"
   870            },
   871            {
   872              "C": ".4",
   873              "heatNumber": "387230"
   874            }
   875          ]
   876        },
   877        "companyAddress": "3260 46 Ave SE #30, Calgary, AB T2B 3K7, Canada",
   878        "companyBrandMark": "data:image/png;base64,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",
   879        "companyContactPersonName": "Test Test",
   880        "companyEmail": "stacy@example.com",
   881        "companyName": "Steel Inc.",
   882        "companyPhoneNumber": "555 555 5555",
   883        "companyWebsite": "https://example.com",
   884        "customerLocationAddressCountry": "USA",
   885        "customerLocationAddressLocality": "Jewett",
   886        "customerLocationAddressRegion": "TX",
   887        "customerLocationCompanyName": "Nucor Steel Jewett",
   888        "customerLocationPostalCode": "",
   889        "customerLocationStreetAddress": "U.S. 79",
   890        "invoiceNumber": "IN 456",
   891        "manufacturerLocationAddressCountry": "Canada",
   892        "manufacturerLocationAddressLocality": "Calgary",
   893        "manufacturerLocationAddressRegion": "AB T2B 3K7",
   894        "manufacturerLocationCompanyName": "Steel Inc.",
   895        "manufacturerLocationPostalCode": "",
   896        "manufacturerLocationStreetAddress": "3260 46 Ave SE #30",
   897        "mechanicalProperties": {
   898          "columns": [
   899            {
   900              "field": "heatNumber",
   901              "title": "Heat Number"
   902            },
   903            {
   904              "field": "description",
   905              "title": "Item Description"
   906            },
   907            {
   908              "field": "quantity",
   909              "title": "Quantity"
   910            },
   911            {
   912              "field": "dimension",
   913              "title": "Dimension"
   914            },
   915            {
   916              "field": "weight",
   917              "title": "Net Weight (Kg)"
   918            },
   919            {
   920              "field": "yieldToTensileRatio",
   921              "title": "Yield to Tensile Ratio"
   922            },
   923            {
   924              "field": "yieldStrength",
   925              "title": "Yield Strength (PSI)"
   926            },
   927            {
   928              "field": "tensileStrength",
   929              "title": "Tensile Strength (PSI)"
   930            },
   931            {
   932              "field": "elongation",
   933              "title": "Elongation (%)"
   934            },
   935            {
   936              "field": "charpyImpactTempDegreesC",
   937              "title": "CHARPY IMPACT Temp (C)"
   938            },
   939            {
   940              "field": "charpyImpactEnergyJoules",
   941              "title": "CHARPY IMPACT Energy (J)"
   942            }
   943          ],
   944          "rows": [
   945            {
   946              "description": "Hot Rolled Steel Pipe",
   947              "dimension": "203.2 mm dia. x 5609 + 5663 mm (8\" dia.)",
   948              "elongation": "27",
   949              "heatNumber": "404012",
   950              "quantity": "2",
   951              "tensileStrength": "71000",
   952              "weight": "2900.27",
   953              "yieldStrength": "52000",
   954              "yieldToTensileRatio": "0.73"
   955            },
   956            {
   957              "description": "Cold Rolled Steel Bar",
   958              "dimension": "203.2 mm dia. x 5609 + 5663 mm",
   959              "elongation": "27",
   960              "heatNumber": "387230",
   961              "quantity": "500",
   962              "tensileStrength": "76000",
   963              "weight": "2900.27",
   964              "yieldStrength": "55000",
   965              "yieldToTensileRatio": "0.72"
   966            }
   967          ]
   968        },
   969        "productDescription": "SS490 steel is a structural hot Rolled steel in the form of plates, sheets \u0026 strips for general structural applications. SS490 is a material grade and designation defined in JIS G 3101 standard. JIS G 3101 is a Japanese material standard for hot Rolled steel plates, sheets, strips for general structural usage. The structural quality hot rolled SS490 steel is more reliable in its tensile strength than SS400 steel...",
   970        "proprietaryGrades": [
   971          {
   972            "description": "BF-4122",
   973            "title": "BF-4122"
   974          }
   975        ],
   976        "proprietarySpecifications": [
   977          {
   978            "description": "ASTM-51",
   979            "title": "ASTM-51"
   980          }
   981        ],
   982        "purchaseOrder": "PO 123",
   983        "standardGrades": [
   984          {
   985            "description": "SUS201",
   986            "title": "SUS201"
   987          }
   988        ],
   989        "standardSpecifications": [
   990          {
   991            "description": "Rolled steels for general structure",
   992            "isoCode": "JIS G 3101",
   993            "title": "JIS G 3101"
   994          }
   995        ]
   996      },
   997      "id": "did:key:z6MkjRagNiMu91DduvCvgEsqLZDVzrJzFrwahc4tXLt9DoHd"
   998    },
   999    "proof": {
  1000      "type": "Ed25519Signature2018",
  1001      "created": "2020-05-14T15:22:26.065935+03:00",
  1002      "verificationMethod": "did:example:123456#key1",
  1003      "proofPurpose": "assertionMethod",
  1004      "jws": "eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..dmLYprMM4-E9XnEsd6iQHvmrgeC8pKe2liEKcSAu53A7Ok6LjognKQKLNdJSLsJd8cGh2g15ZTu6BKAnp2v7AQ"
  1005    }
  1006  }`
  1007  
  1008  	publicKeyBytes := base58.Decode("At4yQndGdrJs5AVFjYXqwDRALfm3ghLAmzhLux5eJkhh")
  1009  
  1010  	localCrypto, err := createLocalCrypto()
  1011  	require.NoError(t, err)
  1012  	vc, err := ParseCredential([]byte(vcJSON),
  1013  		WithPublicKeyFetcher(SingleKey(publicKeyBytes, "Ed25519Signature2018")),
  1014  		WithEmbeddedSignatureSuites(ed25519signature2018.New(
  1015  			suite.WithVerifier(suite.NewCryptoVerifier(localCrypto)))),
  1016  		WithJSONLDOnlyValidRDF(),
  1017  		WithStrictValidation(),
  1018  		WithJSONLDDocumentLoader(docLoader))
  1019  
  1020  	require.NoError(t, err)
  1021  	require.NotNil(t, vc)
  1022  }
  1023  
  1024  //nolint:lll
  1025  func TestParseCredential_ProofCreatedWithMillisec(t *testing.T) {
  1026  	vcJSON := `
  1027  	{
  1028  	       "issuanceDate": "2020-03-10T04:24:12.164Z",
  1029  	       "credentialSubject": {
  1030  	         "degree": {
  1031  	           "name": "Bachelor of Science and Arts",
  1032  	           "type": "BachelorDegree"
  1033  	         },
  1034  	         "id": "did:example:ebfeb1f712ebc6f1c276e12ec21"
  1035  	       },
  1036  	       "id": "http://example.gov/credentials/3732",
  1037  	       "type": [
  1038  	         "VerifiableCredential",
  1039  	         "UniversityDegreeCredential"
  1040  	       ],
  1041  	       "@context": [
  1042  	         "https://www.w3.org/2018/credentials/v1",
  1043  	         "https://www.w3.org/2018/credentials/examples/v1"
  1044  	       ],
  1045  	       "issuer": {
  1046  	         "id": "did:key:z6MkrqCMy45WhL3UEa1gGTHUtr17AvU4czfP5fH9KNDoYaYN"
  1047  	       },
  1048  	       "proof": {
  1049  	         "created": "2020-05-04T14:30:37.972Z",
  1050  	         "proofPurpose": "assertionMethod",
  1051  	         "type": "Ed25519Signature2018",
  1052  	         "verificationMethod": "did:key:z6MkrqCMy45WhL3UEa1gGTHUtr17AvU4czfP5fH9KNDoYaYN#z6MkrqCMy45WhL3UEa1gGTHUtr17AvU4czfP5fH9KNDoYaYN",
  1053  	         "jws": "eyJhbGciOiAiRWREU0EiLCAiYjY0IjogZmFsc2UsICJjcml0IjogWyJiNjQiXX0..SVA8JpQQU9-XP9mlEB-V0TVeX0V7d_jDImQyXrV1-SzfOTP7M6CERVmj7ppAAed1CgIQceIoiIZ8sUN3n_0UDg"
  1054  	       }
  1055  	     }
  1056  	`
  1057  
  1058  	publicKeyBytes := base58.Decode("DNwKNoq5MnZ185AyatKe3kT7MMCDD7R2PeNDV6FndMkz")
  1059  
  1060  	localCrypto, err := createLocalCrypto()
  1061  	require.NoError(t, err)
  1062  	vc, err := parseTestCredential(t, []byte(vcJSON),
  1063  		WithPublicKeyFetcher(SingleKey(publicKeyBytes, "Ed25519Signature2018")),
  1064  		WithEmbeddedSignatureSuites(ed25519signature2018.New(
  1065  			suite.WithVerifier(suite.NewCryptoVerifier(localCrypto)))),
  1066  		WithStrictValidation())
  1067  
  1068  	require.NoError(t, err)
  1069  	require.NotNil(t, vc)
  1070  }
  1071  
  1072  func TestParseCredentialWithSeveralLinkedDataProofs(t *testing.T) {
  1073  	r := require.New(t)
  1074  
  1075  	ed25519Signer, err := newCryptoSigner(kms.ED25519Type)
  1076  	r.NoError(err)
  1077  
  1078  	ed25519SigSuite := ed25519signature2018.New(
  1079  		suite.WithSigner(ed25519Signer),
  1080  		suite.WithVerifier(ed25519signature2018.NewPublicKeyVerifier()))
  1081  
  1082  	vc, err := parseTestCredential(t, []byte(validCredential))
  1083  	r.NoError(err)
  1084  
  1085  	err = vc.AddLinkedDataProof(&LinkedDataProofContext{
  1086  		SignatureType:           "Ed25519Signature2018",
  1087  		SignatureRepresentation: SignatureProofValue,
  1088  		Suite:                   ed25519SigSuite,
  1089  		VerificationMethod:      "did:example:123456#key1",
  1090  	}, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
  1091  	r.NoError(err)
  1092  
  1093  	ecdsaSigner, err := newCryptoSigner(kms.ECDSAP256TypeIEEEP1363)
  1094  	require.NoError(t, err)
  1095  
  1096  	ecdsaSigSuite := jsonwebsignature2020.New(
  1097  		suite.WithSigner(ecdsaSigner),
  1098  		suite.WithVerifier(jsonwebsignature2020.NewPublicKeyVerifier()))
  1099  
  1100  	err = vc.AddLinkedDataProof(&LinkedDataProofContext{
  1101  		SignatureType:           "JsonWebSignature2020",
  1102  		SignatureRepresentation: SignatureJWS,
  1103  		Suite:                   ecdsaSigSuite,
  1104  		VerificationMethod:      "did:example:123456#key2",
  1105  	}, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
  1106  	r.NoError(err)
  1107  
  1108  	vcBytes, err := json.Marshal(vc)
  1109  	r.NoError(err)
  1110  	r.NotEmpty(vcBytes)
  1111  
  1112  	j, err := jwksupport.JWKFromKey(ecdsaSigner.PublicKey())
  1113  	require.NoError(t, err)
  1114  
  1115  	vcWithLdp, err := parseTestCredential(t, vcBytes,
  1116  		WithEmbeddedSignatureSuites(ed25519SigSuite, ecdsaSigSuite),
  1117  		WithPublicKeyFetcher(func(issuerID, keyID string) (*sigverifier.PublicKey, error) {
  1118  			switch keyID {
  1119  			case "#key1":
  1120  				return &sigverifier.PublicKey{
  1121  					Type:  "Ed25519Signature2018",
  1122  					Value: ed25519Signer.PublicKeyBytes(),
  1123  				}, nil
  1124  
  1125  			case "#key2":
  1126  				return &sigverifier.PublicKey{
  1127  					Type:  "JsonWebKey2020",
  1128  					Value: ecdsaSigner.PublicKeyBytes(),
  1129  					JWK:   j,
  1130  				}, nil
  1131  			}
  1132  
  1133  			return nil, errors.New("unsupported keyID")
  1134  		}))
  1135  	r.NoError(err)
  1136  	r.Equal(vc, vcWithLdp)
  1137  }
  1138  
  1139  func createLocalCrypto() (*LocalCrypto, error) {
  1140  	lKMS, err := createKMS()
  1141  	if err != nil {
  1142  		return nil, err
  1143  	}
  1144  
  1145  	tinkCrypto, err := tinkcrypto.New()
  1146  	if err != nil {
  1147  		return nil, err
  1148  	}
  1149  
  1150  	return &LocalCrypto{
  1151  		Crypto:   tinkCrypto,
  1152  		localKMS: lKMS,
  1153  	}, nil
  1154  }
  1155  
  1156  // LocalCrypto defines a verifier which is based on Local KMS and Crypto
  1157  // which uses keyset.Handle as input for verification.
  1158  type LocalCrypto struct {
  1159  	*tinkcrypto.Crypto
  1160  	localKMS *localkms.LocalKMS
  1161  }
  1162  
  1163  func (t *LocalCrypto) Verify(sig, msg []byte, kh interface{}) error {
  1164  	pubKey, ok := kh.(*sigverifier.PublicKey)
  1165  	if !ok {
  1166  		return errors.New("bad key handle format")
  1167  	}
  1168  
  1169  	kmsKeyType, err := mapPublicKeyToKMSKeyType(pubKey)
  1170  	if err != nil {
  1171  		return err
  1172  	}
  1173  
  1174  	handle, err := t.localKMS.PubKeyBytesToHandle(pubKey.Value, kmsKeyType)
  1175  	if err != nil {
  1176  		return err
  1177  	}
  1178  
  1179  	return t.Crypto.Verify(sig, msg, handle)
  1180  }
  1181  
  1182  func mapPublicKeyToKMSKeyType(pubKey *sigverifier.PublicKey) (kms.KeyType, error) {
  1183  	switch pubKey.Type {
  1184  	case "Ed25519Signature2018":
  1185  		return kms.ED25519Type, nil
  1186  	case "JwsVerificationKey2020":
  1187  		return mapJWKToKMSKeyType(pubKey.JWK)
  1188  	default:
  1189  		return "", fmt.Errorf("unsupported key type: %s", pubKey.Type)
  1190  	}
  1191  }
  1192  
  1193  func mapJWKToKMSKeyType(j *jwk.JWK) (kms.KeyType, error) {
  1194  	switch j.Kty {
  1195  	case "OKP":
  1196  		return kms.ED25519Type, nil
  1197  	case "EC":
  1198  		switch j.Crv {
  1199  		case "P-256":
  1200  			return kms.ECDSAP256TypeIEEEP1363, nil
  1201  		case "P-384":
  1202  			return kms.ECDSAP384TypeIEEEP1363, nil
  1203  		case "P-521":
  1204  			return kms.ECDSAP521TypeIEEEP1363, nil
  1205  		}
  1206  	}
  1207  
  1208  	return "", fmt.Errorf("unsupported JWK: %v", j)
  1209  }
  1210  
  1211  func TestCredential_AddLinkedDataProof(t *testing.T) {
  1212  	r := require.New(t)
  1213  
  1214  	signer, err := newCryptoSigner(kms.ED25519Type)
  1215  	r.NoError(err)
  1216  
  1217  	t.Run("Add a valid JWS Linked Data proof to VC", func(t *testing.T) {
  1218  		vc, err := parseTestCredential(t, []byte(validCredential))
  1219  		r.NoError(err)
  1220  
  1221  		originalVCMap, err := jsonutil.ToMap(vc)
  1222  		r.NoError(err)
  1223  
  1224  		err = vc.AddLinkedDataProof(&LinkedDataProofContext{
  1225  			SignatureType:           "Ed25519Signature2018",
  1226  			SignatureRepresentation: SignatureJWS,
  1227  			Suite:                   ed25519signature2018.New(suite.WithSigner(signer)),
  1228  			VerificationMethod:      "did:example:xyz#key-1",
  1229  			Challenge:               uuid.New().String(),
  1230  			Domain:                  "issuer.service.com",
  1231  			Purpose:                 "authentication",
  1232  		}, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
  1233  		r.NoError(err)
  1234  
  1235  		vcMap, err := jsonutil.ToMap(vc)
  1236  		r.NoError(err)
  1237  
  1238  		r.Contains(vcMap, "proof")
  1239  		vcProof := vcMap["proof"]
  1240  		vcProofMap, ok := vcProof.(map[string]interface{})
  1241  		r.True(ok)
  1242  		r.Contains(vcProofMap, "created")
  1243  		r.Contains(vcProofMap, "jws")
  1244  		r.Contains(vcProofMap, "challenge")
  1245  		r.Contains(vcProofMap, "domain")
  1246  		r.Contains(vcProofMap, "verificationMethod")
  1247  		r.Contains(vcProofMap, "proofPurpose")
  1248  		r.Equal("Ed25519Signature2018", vcProofMap["type"])
  1249  		r.Equal("authentication", vcProofMap["proofPurpose"])
  1250  
  1251  		// check that only "proof" element was added as a result of AddLinkedDataProof().
  1252  		delete(vcMap, "proof")
  1253  		r.Equal(originalVCMap, vcMap)
  1254  	})
  1255  
  1256  	t.Run("Add invalid Linked Data proof to VC", func(t *testing.T) {
  1257  		vc, err := parseTestCredential(t, []byte(validCredential))
  1258  		require.NoError(t, err)
  1259  
  1260  		vc.CustomFields = map[string]interface{}{
  1261  			"invalidField": make(chan int),
  1262  		}
  1263  
  1264  		err = vc.AddLinkedDataProof(&LinkedDataProofContext{
  1265  			SignatureType:           "Ed25519Signature2018",
  1266  			SignatureRepresentation: SignatureProofValue,
  1267  			Suite:                   ed25519signature2018.New(suite.WithSigner(signer)),
  1268  		})
  1269  		r.Error(err)
  1270  
  1271  		vc.CustomFields = nil
  1272  		ldpContextWithMissingSignatureType := &LinkedDataProofContext{
  1273  			Suite:                   ed25519signature2018.New(suite.WithSigner(signer)),
  1274  			SignatureRepresentation: SignatureProofValue,
  1275  		}
  1276  
  1277  		err = vc.AddLinkedDataProof(ldpContextWithMissingSignatureType)
  1278  		r.Error(err)
  1279  	})
  1280  
  1281  	t.Run("sign and verify proof with capabilityChain", func(t *testing.T) {
  1282  		rootCapability := "https://edv.com/foo/zcap/123"
  1283  		vc, err := parseTestCredential(t, []byte(validCredential))
  1284  		r.NoError(err)
  1285  
  1286  		err = vc.AddLinkedDataProof(&LinkedDataProofContext{
  1287  			SignatureType:           "Ed25519Signature2018",
  1288  			SignatureRepresentation: SignatureJWS,
  1289  			Suite:                   ed25519signature2018.New(suite.WithSigner(signer)),
  1290  			VerificationMethod:      "did:example:xyz#key-1",
  1291  			Challenge:               uuid.New().String(),
  1292  			Domain:                  "issuer.service.com",
  1293  			Purpose:                 "capabilityDelegation",
  1294  			CapabilityChain:         []interface{}{rootCapability},
  1295  		}, jsonldsig.WithDocumentLoader(createTestDocumentLoader(t)))
  1296  		r.NoError(err)
  1297  
  1298  		r.Len(vc.Proofs, 1)
  1299  		proof := vc.Proofs[0]
  1300  		r.Contains(proof, "proofPurpose")
  1301  		r.Equal("capabilityDelegation", proof["proofPurpose"])
  1302  		r.Contains(proof, "capabilityChain")
  1303  		chain, ok := proof["capabilityChain"].([]interface{})
  1304  		r.True(ok)
  1305  		r.Len(chain, 1)
  1306  		r.Equal(rootCapability, chain[0])
  1307  
  1308  		// parse
  1309  		raw, err := json.Marshal(vc)
  1310  		r.NoError(err)
  1311  		result, err := ParseCredential(raw,
  1312  			WithJSONLDDocumentLoader(createTestDocumentLoader(t)),
  1313  			WithPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)),
  1314  		)
  1315  		r.NoError(err)
  1316  		r.Len(result.Proofs, 1)
  1317  		proof = result.Proofs[0]
  1318  		r.Contains(proof, "proofPurpose")
  1319  		r.Equal("capabilityDelegation", proof["proofPurpose"])
  1320  		r.Contains(proof, "capabilityChain")
  1321  		capabilities, ok := proof["capabilityChain"].([]interface{})
  1322  		r.True(ok)
  1323  		r.Len(capabilities, 1)
  1324  		r.Equal(rootCapability, capabilities[0])
  1325  	})
  1326  }
  1327  
  1328  type bbsSigner struct {
  1329  	privKeyBytes []byte
  1330  }
  1331  
  1332  func newBBSSigner(privKey *bbs12381g2pub.PrivateKey) (*bbsSigner, error) {
  1333  	privKeyBytes, err := privKey.Marshal()
  1334  	if err != nil {
  1335  		return nil, err
  1336  	}
  1337  
  1338  	return &bbsSigner{privKeyBytes: privKeyBytes}, nil
  1339  }
  1340  
  1341  func (s *bbsSigner) Sign(data []byte) ([]byte, error) {
  1342  	msgs := s.textToLines(string(data))
  1343  
  1344  	return bbs12381g2pub.New().Sign(msgs, s.privKeyBytes)
  1345  }
  1346  
  1347  func (s *bbsSigner) Alg() string {
  1348  	return ""
  1349  }
  1350  
  1351  func (s *bbsSigner) textToLines(txt string) [][]byte {
  1352  	lines := strings.Split(txt, "\n")
  1353  	linesBytes := make([][]byte, 0, len(lines))
  1354  
  1355  	for i := range lines {
  1356  		if strings.TrimSpace(lines[i]) != "" {
  1357  			linesBytes = append(linesBytes, []byte(lines[i]))
  1358  		}
  1359  	}
  1360  
  1361  	return linesBytes
  1362  }