github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/verifiable/presentation_jwt_proof_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/rand"
    11  	"errors"
    12  	"fmt"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/stretchr/testify/require"
    17  
    18  	"github.com/hyperledger/aries-framework-go/pkg/doc/signature/verifier"
    19  	"github.com/hyperledger/aries-framework-go/pkg/doc/util"
    20  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    21  )
    22  
    23  func TestParsePresentationFromJWS(t *testing.T) {
    24  	vpBytes := []byte(validPresentation)
    25  
    26  	holderSigner, err := newCryptoSigner(kms.RSARS256Type)
    27  	require.NoError(t, err)
    28  
    29  	keyFetcher := createPresKeyFetcher(holderSigner.PublicKeyBytes())
    30  
    31  	t.Run("Decoding presentation from JWS", func(t *testing.T) {
    32  		jws := createPresJWS(t, vpBytes, false, holderSigner)
    33  		vpFromJWT, err := newTestPresentation(t, jws, WithPresPublicKeyFetcher(keyFetcher))
    34  		require.NoError(t, err)
    35  
    36  		vp, err := newTestPresentation(t, vpBytes)
    37  		require.NoError(t, err)
    38  
    39  		// Validate the JWT field, then clear it to validate against the original presentation.
    40  		require.Equal(t, string(jws), vpFromJWT.JWT)
    41  		vpFromJWT.JWT = ""
    42  
    43  		require.Equal(t, vp, vpFromJWT)
    44  	})
    45  
    46  	t.Run("Decoding presentation from JWS with minimized fields of \"vp\" claim", func(t *testing.T) {
    47  		jws := createPresJWS(t, vpBytes, true, holderSigner)
    48  		vpFromJWT, err := newTestPresentation(t, jws, WithPresPublicKeyFetcher(keyFetcher))
    49  		require.NoError(t, err)
    50  
    51  		vp, err := newTestPresentation(t, vpBytes)
    52  		require.NoError(t, err)
    53  
    54  		require.Equal(t, string(jws), vpFromJWT.JWT)
    55  		vpFromJWT.JWT = ""
    56  
    57  		require.Equal(t, vp, vpFromJWT)
    58  	})
    59  
    60  	t.Run("Failed JWT signature verification of presentation", func(t *testing.T) {
    61  		jws := createPresJWS(t, vpBytes, true, holderSigner)
    62  		vp, err := newTestPresentation(t,
    63  			jws,
    64  			// passing issuers's key, while expecting holder's one
    65  			WithPresPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) {
    66  				issuerSigner, err := newCryptoSigner(kms.RSARS256Type)
    67  				require.NoError(t, err)
    68  
    69  				return &verifier.PublicKey{
    70  					Type:  kms.RSARS256,
    71  					Value: issuerSigner.PublicKeyBytes(),
    72  				}, nil
    73  			}))
    74  
    75  		require.Error(t, err)
    76  		require.Contains(t, err.Error(), "decoding of Verifiable Presentation from JWS")
    77  		require.Nil(t, vp)
    78  	})
    79  
    80  	t.Run("Failed public key fetching", func(t *testing.T) {
    81  		jws := createPresJWS(t, vpBytes, true, holderSigner)
    82  		vp, err := newTestPresentation(t,
    83  			jws,
    84  			WithPresPublicKeyFetcher(func(issuerID, keyID string) (*verifier.PublicKey, error) {
    85  				return nil, errors.New("test: public key is not found")
    86  			}))
    87  
    88  		require.Error(t, err)
    89  		require.Contains(t, err.Error(), "test: public key is not found")
    90  		require.Nil(t, vp)
    91  	})
    92  
    93  	t.Run("Not defined public key fetcher", func(t *testing.T) {
    94  		vp, err := newTestPresentation(t, createPresJWS(t, vpBytes, true, holderSigner))
    95  
    96  		require.Error(t, err)
    97  		require.Contains(t, err.Error(), "public key fetcher is not defined")
    98  		require.Nil(t, vp)
    99  	})
   100  }
   101  
   102  func TestParsePresentationFromJWS_EdDSA(t *testing.T) {
   103  	vpBytes := []byte(validPresentation)
   104  
   105  	signer, err := newCryptoSigner(kms.ED25519Type)
   106  	require.NoError(t, err)
   107  
   108  	vp, err := newTestPresentation(t, vpBytes)
   109  	require.NoError(t, err)
   110  
   111  	// marshal presentation into JWS using EdDSA (Ed25519 signature algorithm).
   112  	jwtClaims, err := vp.JWTClaims([]string{}, false)
   113  	require.NoError(t, err)
   114  
   115  	vpJWSStr, err := jwtClaims.MarshalJWS(EdDSA, signer, vp.Holder+"#keys-"+keyID)
   116  	require.NoError(t, err)
   117  
   118  	// unmarshal presentation from JWS
   119  	vpFromJWS, err := newTestPresentation(t,
   120  		[]byte(vpJWSStr),
   121  		WithPresPublicKeyFetcher(SingleKey(signer.PublicKeyBytes(), kms.ED25519)))
   122  	require.NoError(t, err)
   123  
   124  	require.Equal(t, vpJWSStr, vpFromJWS.JWT)
   125  	vpFromJWS.JWT = ""
   126  
   127  	// unmarshalled presentation must be the same as original one
   128  	require.Equal(t, vp, vpFromJWS)
   129  }
   130  
   131  func TestParsePresentationFromUnsecuredJWT(t *testing.T) {
   132  	vpBytes := []byte(validPresentation)
   133  
   134  	t.Run("Decoding presentation from unsecured JWT", func(t *testing.T) {
   135  		vpFromJWT, err := newTestPresentation(t, createPresUnsecuredJWT(t, vpBytes, false))
   136  
   137  		require.NoError(t, err)
   138  
   139  		vp, err := newTestPresentation(t, vpBytes)
   140  		require.NoError(t, err)
   141  
   142  		require.Equal(t, vp, vpFromJWT)
   143  	})
   144  
   145  	t.Run("Decoding presentation from unsecured JWT with minimized fields of \"vp\" claim", func(t *testing.T) {
   146  		vpFromJWT, err := newTestPresentation(t, createPresUnsecuredJWT(t, vpBytes, true))
   147  
   148  		require.NoError(t, err)
   149  
   150  		vp, err := newTestPresentation(t, vpBytes)
   151  		require.NoError(t, err)
   152  
   153  		require.Equal(t, vp, vpFromJWT)
   154  	})
   155  }
   156  
   157  func TestParsePresentationWithVCJWT(t *testing.T) {
   158  	r := require.New(t)
   159  
   160  	// Create and encode VP.
   161  	issued := time.Date(2010, time.January, 1, 19, 23, 24, 0, time.UTC)
   162  	expired := time.Date(2020, time.January, 1, 19, 23, 24, 0, time.UTC)
   163  
   164  	vc := &Credential{
   165  		Context: []string{
   166  			"https://www.w3.org/2018/credentials/v1",
   167  			"https://www.w3.org/2018/credentials/examples/v1",
   168  		},
   169  		ID: "http://example.edu/credentials/1872",
   170  		Types: []string{
   171  			"VerifiableCredential",
   172  			"UniversityDegreeCredential",
   173  		},
   174  		Subject: UniversityDegreeSubject{
   175  			ID:     "did:example:ebfeb1f712ebc6f1c276e12ec21",
   176  			Name:   "Jayden Doe",
   177  			Spouse: "did:example:c276e12ec21ebfeb1f712ebc6f1",
   178  			Degree: UniversityDegree{
   179  				Type:       "BachelorDegree",
   180  				University: "MIT",
   181  			},
   182  		},
   183  		Issuer: Issuer{
   184  			ID:           "did:example:76e12ec712ebc6f1c221ebfeb1f",
   185  			CustomFields: CustomFields{"name": "Example University"},
   186  		},
   187  		Issued:  util.NewTime(issued),
   188  		Expired: util.NewTime(expired),
   189  		Schemas: []TypedID{},
   190  	}
   191  
   192  	vcJWTClaims, err := vc.JWTClaims(true)
   193  	r.NoError(err)
   194  
   195  	issuerSigner, err := newCryptoSigner(kms.RSARS256Type)
   196  	r.NoError(err)
   197  
   198  	vcJWS, err := vcJWTClaims.MarshalJWS(RS256, issuerSigner, "did:123#issuer-key")
   199  	r.NoError(err)
   200  	r.NotNil(vcJWS)
   201  
   202  	t.Run("Presentation with VC defined as JWS", func(t *testing.T) {
   203  		// Create and encode VP.
   204  		vp, err := NewPresentation(WithJWTCredentials(vcJWS))
   205  		r.NoError(err)
   206  
   207  		vp.ID = "urn:uuid:2978344f-8596-4c3a-a978-8fcaba3903c"
   208  		vp.Holder = "did:example:fbfeb1f712ebc6f1c276e12ec21"
   209  
   210  		holderSigner, err := newCryptoSigner(kms.ED25519Type)
   211  		r.NoError(err)
   212  
   213  		jwtClaims, err := vp.JWTClaims([]string{}, true)
   214  		require.NoError(t, err)
   215  
   216  		vpJWS, err := jwtClaims.MarshalJWS(EdDSA, holderSigner, "did:123#holder-key")
   217  		r.NoError(err)
   218  
   219  		publicKeyFetcher := func(issuerID, keyID string) (*verifier.PublicKey, error) {
   220  			switch keyID {
   221  			case "holder-key":
   222  				return &verifier.PublicKey{
   223  					Type:  kms.ED25519,
   224  					Value: holderSigner.PublicKeyBytes(),
   225  				}, nil
   226  			case "issuer-key":
   227  				return &verifier.PublicKey{
   228  					Type:  kms.RSARS256,
   229  					Value: issuerSigner.PublicKeyBytes(),
   230  				}, nil
   231  			default:
   232  				return nil, errors.New("unexpected key")
   233  			}
   234  		}
   235  
   236  		// Decode VP
   237  		vpDecoded, err := newTestPresentation(t, []byte(vpJWS), WithPresPublicKeyFetcher(publicKeyFetcher))
   238  		r.NoError(err)
   239  		vpCreds, err := vpDecoded.MarshalledCredentials()
   240  		r.NoError(err)
   241  		r.Len(vpCreds, 1)
   242  
   243  		vcDecoded, err := parseTestCredential(t, vpCreds[0], WithPublicKeyFetcher(publicKeyFetcher))
   244  		r.NoError(err)
   245  
   246  		r.Equal(fmt.Sprintf("%q", vcJWS), vcDecoded.stringJSON(t))
   247  	})
   248  
   249  	t.Run("Presentation with VC defined as VC struct", func(t *testing.T) {
   250  		// Create and encode VP.
   251  		vp, err := NewPresentation(WithCredentials(vc))
   252  		r.NoError(err)
   253  
   254  		vp.ID = "urn:uuid:5978344f-8596-4c3a-a978-8fcaba3903c"
   255  		vp.Holder = "did:example:abfeb1f712ebc6f1c276e12ec21"
   256  
   257  		holderSigner, err := newCryptoSigner(kms.ED25519Type)
   258  		r.NoError(err)
   259  
   260  		jwtClaims, err := vp.JWTClaims([]string{}, true)
   261  		require.NoError(t, err)
   262  
   263  		vpJWS, err := jwtClaims.MarshalJWS(EdDSA, holderSigner, "did:123#holder-key")
   264  		r.NoError(err)
   265  
   266  		// Decode VP
   267  		vpDecoded, err := newTestPresentation(t, []byte(vpJWS), WithPresPublicKeyFetcher(
   268  			SingleKey(holderSigner.PublicKeyBytes(), kms.ED25519)))
   269  		r.NoError(err)
   270  		vpCreds, err := vpDecoded.MarshalledCredentials()
   271  		r.NoError(err)
   272  		r.Len(vpCreds, 1)
   273  
   274  		vcDecoded, err := parseTestCredential(t, vpCreds[0])
   275  		r.NoError(err)
   276  
   277  		r.Equal(vc.stringJSON(t), vcDecoded.stringJSON(t))
   278  	})
   279  
   280  	t.Run("Failed check of VC due to invalid JWS", func(t *testing.T) {
   281  		vp, err := NewPresentation(WithJWTCredentials(vcJWS))
   282  		r.NoError(err)
   283  
   284  		vp.ID = "urn:uuid:0978344f-8596-4c3a-a978-8fcaba3903c"
   285  		vp.Holder = "did:example:ebfeb2f712ebc6f1c276e12ec21"
   286  
   287  		holderSigner, err := newCryptoSigner(kms.ED25519Type)
   288  		r.NoError(err)
   289  
   290  		jwtClaims, err := vp.JWTClaims([]string{}, true)
   291  		require.NoError(t, err)
   292  
   293  		vpJWS, err := jwtClaims.MarshalJWS(EdDSA, holderSigner, "did:123#holder-key")
   294  		r.NoError(err)
   295  
   296  		// Decode VP
   297  		vp, err = newTestPresentation(t, []byte(vpJWS), WithPresPublicKeyFetcher(
   298  			func(issuerID, keyID string) (*verifier.PublicKey, error) {
   299  				switch keyID {
   300  				case "holder-key":
   301  					return &verifier.PublicKey{
   302  						Type:  kms.ED25519,
   303  						Value: holderSigner.PublicKeyBytes(),
   304  					}, nil
   305  				case "issuer-key":
   306  					// here we return invalid public key
   307  					anotherPubKey, _, gerr := ed25519.GenerateKey(rand.Reader)
   308  					r.NoError(gerr)
   309  
   310  					return &verifier.PublicKey{
   311  						Type:  kms.ED25519,
   312  						Value: anotherPubKey,
   313  					}, nil
   314  				default:
   315  					r.NoError(err)
   316  					return nil, errors.New("unexpected key")
   317  				}
   318  			}))
   319  		r.Error(err)
   320  		r.Contains(err.Error(), "decode credentials of presentation")
   321  		r.Contains(err.Error(), "JWS decoding")
   322  		r.Nil(vp)
   323  	})
   324  }
   325  
   326  func createPresJWS(t *testing.T, vpBytes []byte, minimize bool, signer Signer) []byte {
   327  	vp, err := newTestPresentation(t, vpBytes)
   328  	require.NoError(t, err)
   329  
   330  	jwtClaims, err := vp.JWTClaims([]string{}, minimize)
   331  	require.NoError(t, err)
   332  
   333  	vpJWT, err := jwtClaims.MarshalJWS(RS256, signer, vp.Holder+"#keys-"+keyID)
   334  	require.NoError(t, err)
   335  
   336  	return []byte(vpJWT)
   337  }
   338  
   339  func createPresKeyFetcher(pubKeyBytes []byte) func(issuerID string, keyID string) (*verifier.PublicKey, error) {
   340  	return func(issuerID, keyID string) (*verifier.PublicKey, error) {
   341  		return &verifier.PublicKey{
   342  			Type:  kms.RSARS256,
   343  			Value: pubKeyBytes,
   344  		}, nil
   345  	}
   346  }
   347  
   348  func createPresUnsecuredJWT(t *testing.T, cred []byte, minimize bool) []byte {
   349  	vp, err := newTestPresentation(t, cred)
   350  	require.NoError(t, err)
   351  
   352  	jwtClaims, err := vp.JWTClaims([]string{}, minimize)
   353  	require.NoError(t, err)
   354  
   355  	vpJWT, err := jwtClaims.MarshalUnsecuredJWT()
   356  	require.NoError(t, err)
   357  
   358  	return []byte(vpJWT)
   359  }