github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/packer/anoncrypt/pack_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package anoncrypt
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/ecdsa"
    12  	"crypto/ed25519"
    13  	"crypto/elliptic"
    14  	"encoding/json"
    15  	"errors"
    16  	"fmt"
    17  	"io"
    18  	"strings"
    19  	"testing"
    20  
    21  	"github.com/go-jose/go-jose/v3"
    22  	"github.com/golang/protobuf/proto"
    23  	hybrid "github.com/google/tink/go/hybrid/subtle"
    24  	"github.com/google/tink/go/keyset"
    25  	commonpb "github.com/google/tink/go/proto/common_go_proto"
    26  	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
    27  	"github.com/stretchr/testify/require"
    28  
    29  	ecdhpb "github.com/hyperledger/aries-framework-go/component/kmscrypto/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto"
    30  
    31  	"github.com/hyperledger/aries-framework-go/pkg/common/log"
    32  	cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto"
    33  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto"
    34  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/keyio"
    35  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
    36  	afgjose "github.com/hyperledger/aries-framework-go/pkg/doc/jose"
    37  	"github.com/hyperledger/aries-framework-go/pkg/doc/util/kmsdidkey"
    38  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    39  	"github.com/hyperledger/aries-framework-go/pkg/kms/localkms"
    40  	mockkms "github.com/hyperledger/aries-framework-go/pkg/mock/kms"
    41  	mockprovider "github.com/hyperledger/aries-framework-go/pkg/mock/provider"
    42  	mockstorage "github.com/hyperledger/aries-framework-go/pkg/mock/storage"
    43  	mockvdr "github.com/hyperledger/aries-framework-go/pkg/mock/vdr"
    44  	"github.com/hyperledger/aries-framework-go/pkg/secretlock/noop"
    45  	spilog "github.com/hyperledger/aries-framework-go/spi/log"
    46  )
    47  
    48  func TestAnoncryptPackerSuccess(t *testing.T) {
    49  	k := createKMS(t)
    50  
    51  	tests := []struct {
    52  		name    string
    53  		keyType kms.KeyType
    54  		encAlg  afgjose.EncAlg
    55  		cty     string
    56  	}{
    57  		{
    58  			name:    "anoncrypt using NISTP256ECDHKW and AES256-GCM",
    59  			keyType: kms.NISTP256ECDHKWType,
    60  			encAlg:  afgjose.A256GCM,
    61  			cty:     transport.MediaTypeV1PlaintextPayload,
    62  		},
    63  		{
    64  			name:    "anoncrypt using NISTP384ECDHKW and AES256-GCM",
    65  			keyType: kms.NISTP384ECDHKWType,
    66  			encAlg:  afgjose.A256GCM,
    67  			cty:     transport.MediaTypeV1PlaintextPayload,
    68  		},
    69  		{
    70  			name:    "anoncrypt using NISTP521ECDHKW and AES256-GCM",
    71  			keyType: kms.NISTP521ECDHKWType,
    72  			encAlg:  afgjose.A256GCM,
    73  			cty:     transport.MediaTypeV1PlaintextPayload,
    74  		},
    75  		{
    76  			name:    "anoncrypt using X25519ECDHKWType and AES256-GCM",
    77  			keyType: kms.X25519ECDHKWType,
    78  			encAlg:  afgjose.A256GCM,
    79  			cty:     transport.MediaTypeV1PlaintextPayload,
    80  		},
    81  		{
    82  			name:    "anoncrypt using NISTP256ECDHKW and XChacha20Poly1305",
    83  			keyType: kms.NISTP256ECDHKW,
    84  			encAlg:  afgjose.XC20P,
    85  			cty:     transport.MediaTypeV1PlaintextPayload,
    86  		},
    87  		{
    88  			name:    "anoncrypt using NISTP384ECDHKW and XChacha20Poly1305",
    89  			keyType: kms.NISTP384ECDHKW,
    90  			encAlg:  afgjose.XC20P,
    91  			cty:     transport.MediaTypeV1PlaintextPayload,
    92  		},
    93  		{
    94  			name:    "anoncrypt using NISTP521ECDHKW and XChacha20Poly1305",
    95  			keyType: kms.NISTP521ECDHKW,
    96  			encAlg:  afgjose.XC20P,
    97  			cty:     transport.MediaTypeV1PlaintextPayload,
    98  		},
    99  		{
   100  			name:    "anoncrypt using X25519ECDHKW and XChacha20Poly1305",
   101  			keyType: kms.X25519ECDHKWType,
   102  			encAlg:  afgjose.XC20P,
   103  			cty:     transport.MediaTypeV1PlaintextPayload,
   104  		},
   105  		{
   106  			name:    "anoncrypt using NISTP256ECDHKW and AES256-GCM without cty",
   107  			keyType: kms.NISTP256ECDHKWType,
   108  			encAlg:  afgjose.A256GCM,
   109  			cty:     transport.MediaTypeV1PlaintextPayload,
   110  		},
   111  		{
   112  			name:    "anoncrypt using X25519ECDHKW and XChacha20Poly1305 without cty",
   113  			keyType: kms.X25519ECDHKWType,
   114  			encAlg:  afgjose.XC20P,
   115  			cty:     transport.MediaTypeV1PlaintextPayload,
   116  		},
   117  		{
   118  			name:    "anoncrypt using NISTP256ECDHKW and XChacha20Poly1305 without cty",
   119  			keyType: kms.NISTP256ECDHKWType,
   120  			encAlg:  afgjose.XC20P,
   121  			cty:     transport.MediaTypeV1PlaintextPayload,
   122  		},
   123  		{
   124  			name:    "anoncrypt using X25519ECDHKW and AES256-GCM without cty",
   125  			keyType: kms.X25519ECDHKWType,
   126  			encAlg:  afgjose.A256GCM,
   127  			cty:     transport.MediaTypeV1PlaintextPayload,
   128  		},
   129  	}
   130  
   131  	t.Parallel()
   132  
   133  	for _, tt := range tests {
   134  		tc := tt
   135  		t.Run(fmt.Sprintf("running %s", tc.name), func(t *testing.T) {
   136  			t.Logf("anoncrypt packing - creating recipient %s keys...", tc.keyType)
   137  			_, recDIDKeys, recipientsKeys, keyHandles := createRecipientsByKeyType(t, k, 3, tc.keyType)
   138  
   139  			log.SetLevel("aries-framework/pkg/didcomm/packer/anoncrypt", spilog.DEBUG)
   140  
   141  			cryptoSvc, err := tinkcrypto.New()
   142  			require.NoError(t, err)
   143  
   144  			anonPacker, err := New(newMockProvider(k, cryptoSvc), tc.encAlg)
   145  			require.NoError(t, err)
   146  
   147  			origMsg := []byte("secret message")
   148  			ct, err := anonPacker.Pack(tc.cty, origMsg, nil, recipientsKeys)
   149  			require.NoError(t, err)
   150  
   151  			jweStr, err := prettyPrint(ct)
   152  			require.NoError(t, err)
   153  			t.Logf("* anoncrypt JWE: %s", jweStr)
   154  
   155  			msg, err := anonPacker.Unpack(ct)
   156  			require.NoError(t, err)
   157  
   158  			recKey, err := exportPubKeyBytes(keyHandles[0], recDIDKeys[0])
   159  			require.NoError(t, err)
   160  
   161  			require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)
   162  
   163  			jweJSON, err := afgjose.Deserialize(string(ct))
   164  			require.NoError(t, err)
   165  
   166  			verifyJWETypes(t, tc.cty, jweJSON.ProtectedHeaders)
   167  
   168  			// try with only 1 recipient
   169  			ct, err = anonPacker.Pack(tc.cty, origMsg, nil, [][]byte{recipientsKeys[0]})
   170  			require.NoError(t, err)
   171  
   172  			t.Logf("* anoncrypt JWE Compact serialization (using first recipient only): %s", ct)
   173  
   174  			jweJSON, err = afgjose.Deserialize(string(ct))
   175  			require.NoError(t, err)
   176  
   177  			jweStr, err = jweJSON.FullSerialize(json.Marshal)
   178  			require.NoError(t, err)
   179  			t.Logf("* anoncrypt Flattened JWE JSON serialization (using first recipient only): %s", jweStr)
   180  
   181  			msg, err = anonPacker.Unpack(ct)
   182  			require.NoError(t, err)
   183  
   184  			require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)
   185  
   186  			verifyJWETypes(t, tc.cty, jweJSON.ProtectedHeaders)
   187  		})
   188  	}
   189  }
   190  
   191  func verifyJWETypes(t *testing.T, cty string, jweHeader afgjose.Headers) {
   192  	encodingType, ok := jweHeader.Type()
   193  	require.True(t, ok)
   194  
   195  	require.Equal(t, transport.MediaTypeV2EncryptedEnvelope, encodingType)
   196  
   197  	contentType, ok := jweHeader.ContentType()
   198  	require.True(t, contentType == "" || contentType != "" && ok)
   199  
   200  	require.Equal(t, cty, contentType)
   201  }
   202  
   203  func TestAnoncryptPackerSuccessWithDifferentCurvesSuccess(t *testing.T) {
   204  	log.SetLevel("aries-framework/pkg/didcomm/packer/anoncrypt", spilog.DEBUG)
   205  
   206  	k := createKMS(t)
   207  	_, recDIDKeys, recipientsKey1, keyHandles1 := createRecipients(t, k, 1)
   208  	_, _, recipientsKey2, _ := createRecipientsByKeyType(t, k, 1, kms.NISTP384ECDHKW) //nolint:dogsled
   209  	_, _, recipientsKey3, _ := createRecipientsByKeyType(t, k, 1, kms.NISTP521ECDHKW) //nolint:dogsled
   210  	_, _, recipientsKey4, _ := createRecipientsByKeyType(t, k, 1, kms.X25519ECDHKW)   //nolint:dogsled
   211  
   212  	recipientsKeys := make([][]byte, 4)
   213  	recipientsKeys[0] = make([]byte, len(recipientsKey1[0]))
   214  	recipientsKeys[1] = make([]byte, len(recipientsKey2[0]))
   215  	recipientsKeys[2] = make([]byte, len(recipientsKey3[0]))
   216  	recipientsKeys[3] = make([]byte, len(recipientsKey4[0]))
   217  
   218  	copy(recipientsKeys[0], recipientsKey1[0])
   219  	copy(recipientsKeys[1], recipientsKey2[0])
   220  	copy(recipientsKeys[2], recipientsKey3[0])
   221  	copy(recipientsKeys[3], recipientsKey4[0])
   222  
   223  	cty := transport.MediaTypeV1PlaintextPayload
   224  
   225  	cryptoSvc, err := tinkcrypto.New()
   226  	require.NoError(t, err)
   227  
   228  	anonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM)
   229  	require.NoError(t, err)
   230  
   231  	origMsg := []byte("secret message")
   232  	ct, err := anonPacker.Pack(cty, origMsg, nil, recipientsKeys)
   233  	require.NoError(t, err)
   234  
   235  	ctStr, err := prettyPrint(ct)
   236  	require.NoError(t, err)
   237  
   238  	t.Logf("anoncrypt JWE: %s", ctStr)
   239  
   240  	msg, err := anonPacker.Unpack(ct)
   241  	require.NoError(t, err)
   242  
   243  	recKey, err := exportPubKeyBytes(keyHandles1[0], recDIDKeys[0])
   244  	require.NoError(t, err)
   245  
   246  	require.EqualValues(t, &transport.Envelope{
   247  		Message: origMsg,
   248  		ToKey:   recKey,
   249  	}, msg)
   250  
   251  	// try with only 1 recipient
   252  	ct, err = anonPacker.Pack(cty, origMsg, nil, [][]byte{recipientsKeys[0]})
   253  	require.NoError(t, err)
   254  
   255  	msg, err = anonPacker.Unpack(ct)
   256  	require.NoError(t, err)
   257  
   258  	require.EqualValues(t, &transport.Envelope{
   259  		Message: origMsg,
   260  		ToKey:   recKey,
   261  	}, msg)
   262  }
   263  
   264  func TestAnoncryptPackerFail(t *testing.T) {
   265  	cty := transport.MediaTypeV1PlaintextPayload
   266  
   267  	t.Run("new Pack fail with nil crypto service", func(t *testing.T) {
   268  		k := createKMS(t)
   269  
   270  		_, err := New(newMockProvider(k, nil), afgjose.A128CBCHS256)
   271  		require.EqualError(t, err, "anoncrypt: failed to create packer because crypto service is empty")
   272  	})
   273  
   274  	cryptoSvc, err := tinkcrypto.New()
   275  	require.NoError(t, err)
   276  
   277  	t.Run("new Pack fail with nil kms", func(t *testing.T) {
   278  		_, err = New(newMockProvider(nil, cryptoSvc), afgjose.A256GCM)
   279  		require.EqualError(t, err, "anoncrypt: failed to create packer because KMS is empty")
   280  	})
   281  
   282  	t.Run("new Pack fail with nil vdr", func(t *testing.T) {
   283  		k := createKMS(t)
   284  		c, e := tinkcrypto.New()
   285  		require.NoError(t, e)
   286  
   287  		p := newMockProvider(k, c)
   288  		p.VDRegistryValue = nil
   289  
   290  		_, err = New(p, afgjose.A192CBCHS384)
   291  		require.EqualError(t, err, "anoncrypt: failed to create packer because vdr registry is empty")
   292  	})
   293  
   294  	k := createKMS(t)
   295  	_, _, recipientsKeys, _ := createRecipients(t, k, 10) //nolint:dogsled
   296  	origMsg := []byte("secret message")
   297  	anonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM)
   298  	require.NoError(t, err)
   299  
   300  	t.Run("pack fail with empty recipients keys", func(t *testing.T) {
   301  		_, err = anonPacker.Pack(cty, origMsg, nil, nil)
   302  		require.EqualError(t, err, "anoncrypt Pack: empty recipientsPubKeys")
   303  	})
   304  
   305  	t.Run("unpack fail with bad recipient key", func(t *testing.T) {
   306  		_, _, keys, _ := createRecipients(t, k, 1)
   307  		keys[0] = []byte(strings.Replace(string(keys[0]), "did:key:", "invalid", 1))
   308  		var ct []byte
   309  		ct, err = anonPacker.Pack(cty, origMsg, nil, keys)
   310  		require.NoError(t, err)
   311  		_, err = anonPacker.Unpack(ct)
   312  		require.Contains(t, err.Error(), "invalid kid format, must be a did:key")
   313  	})
   314  
   315  	t.Run("pack fail with invalid recipients keys", func(t *testing.T) {
   316  		_, err = anonPacker.Pack(cty, origMsg, nil, [][]byte{[]byte("invalid")})
   317  		require.EqualError(t, err, "anoncrypt Pack: failed to convert recipient keys: invalid character 'i' "+
   318  			"looking for beginning of value")
   319  	})
   320  
   321  	t.Run("pack fail with invalid encAlg", func(t *testing.T) {
   322  		invalidAlg := "invalidAlg"
   323  		invalidAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.EncAlg(invalidAlg))
   324  		require.NoError(t, err)
   325  
   326  		_, err = invalidAnonPacker.Pack(cty, origMsg, nil, recipientsKeys)
   327  		require.EqualError(t, err, fmt.Sprintf("anoncrypt Pack: failed to new JWEEncrypt instance: encryption"+
   328  			" algorithm '%s' not supported", invalidAlg))
   329  	})
   330  
   331  	t.Run("pack success but unpack fails with invalid payload", func(t *testing.T) {
   332  		validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM)
   333  		require.NoError(t, err)
   334  
   335  		_, err = validAnonPacker.Pack(cty, origMsg, nil, recipientsKeys)
   336  		require.NoError(t, err)
   337  
   338  		_, err = validAnonPacker.Unpack([]byte("invalid jwe envelope"))
   339  		require.Error(t, err)
   340  		require.Contains(t, err.Error(), "anoncrypt Unpack: failed to deserialize JWE message: invalid compact "+
   341  			"JWE: it must have five parts")
   342  	})
   343  
   344  	t.Run("pack success but unpack fails with invalid payload auth (iv) data", func(t *testing.T) {
   345  		validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A192CBCHS384)
   346  		require.NoError(t, err)
   347  
   348  		var s []byte
   349  
   350  		s, err = validAnonPacker.Pack(cty, origMsg, nil, recipientsKeys)
   351  		require.NoError(t, err)
   352  
   353  		ivStartIndex := bytes.Index(s, []byte("\"iv\""))
   354  		ivEndIndex := ivStartIndex + 6 + bytes.Index(s[ivStartIndex+6:], []byte("\""))
   355  		sTrail := make([]byte, len(s[ivEndIndex:]))
   356  		copy(sTrail, s[ivEndIndex:])
   357  		s = append(s[:ivStartIndex+6], []byte("K3ORqVx392nLcdJveUl_Jg")...) // invalid base64 iv causes decryption error
   358  		s = append(s, sTrail...)
   359  
   360  		_, err = validAnonPacker.Unpack(s)
   361  		require.Error(t, err)
   362  		require.Contains(t, err.Error(), "anoncrypt Unpack: failed to decrypt JWE envelope: ecdh_factory: "+
   363  			"decryption failed")
   364  	})
   365  
   366  	t.Run("pack success but unpack fails with missing keyID in protectedHeader", func(t *testing.T) {
   367  		validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM)
   368  		require.NoError(t, err)
   369  
   370  		ct, err := validAnonPacker.Pack(cty, origMsg, nil, [][]byte{recipientsKeys[0]})
   371  		require.NoError(t, err)
   372  
   373  		jwe, err := afgjose.Deserialize(string(ct))
   374  		require.NoError(t, err)
   375  
   376  		delete(jwe.ProtectedHeaders, afgjose.HeaderKeyID)
   377  
   378  		newCT, err := jwe.CompactSerialize(json.Marshal)
   379  		require.NoError(t, err)
   380  
   381  		_, err = validAnonPacker.Unpack([]byte(newCT))
   382  		require.EqualError(t, err, "anoncrypt Unpack: single recipient missing 'KID' in jwe.ProtectHeaders")
   383  	})
   384  
   385  	t.Run("pack success but unpack fails with missing kid in kms", func(t *testing.T) {
   386  		kids, _, newRecKeys, _ := createRecipients(t, k, 2)
   387  		validAnonPacker, err := New(newMockProvider(k, cryptoSvc), afgjose.A256GCM)
   388  		require.NoError(t, err)
   389  
   390  		ct, err := validAnonPacker.Pack(cty, origMsg, nil, newRecKeys)
   391  		require.NoError(t, err)
   392  
   393  		// rotate keys to update keyID and force a failure
   394  		_, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[0])
   395  		require.NoError(t, err)
   396  
   397  		_, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[1])
   398  		require.NoError(t, err)
   399  
   400  		_, err = validAnonPacker.Unpack(ct)
   401  		require.EqualError(t, err, "anoncrypt Unpack: no matching recipient in envelope")
   402  	})
   403  }
   404  
   405  func exportPubKeyBytes(keyHandle *keyset.Handle, kid string) ([]byte, error) {
   406  	pubKH, err := keyHandle.Public()
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  
   411  	buf := new(bytes.Buffer)
   412  	pubKeyWriter := keyio.NewWriter(buf)
   413  
   414  	err = pubKH.WriteWithNoSecrets(pubKeyWriter)
   415  	if err != nil {
   416  		return nil, err
   417  	}
   418  
   419  	pubKey := &cryptoapi.PublicKey{}
   420  
   421  	err = json.Unmarshal(buf.Bytes(), pubKey)
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  
   426  	pubKey.KID = kid
   427  
   428  	return json.Marshal(pubKey)
   429  }
   430  
   431  // createRecipients and return their public key and keyset.Handle.
   432  func createRecipients(t *testing.T, k *localkms.LocalKMS,
   433  	recipientsCount int) ([]string, []string, [][]byte, []*keyset.Handle) {
   434  	return createRecipientsByKeyType(t, k, recipientsCount, kms.NISTP256ECDHKW)
   435  }
   436  
   437  func createRecipientsByKeyType(t *testing.T, k *localkms.LocalKMS, recipientsCount int,
   438  	kt kms.KeyType) ([]string, []string, [][]byte, []*keyset.Handle) {
   439  	t.Helper()
   440  
   441  	var (
   442  		r       [][]byte
   443  		rKH     []*keyset.Handle
   444  		kids    []string
   445  		didKeys []string
   446  	)
   447  
   448  	for i := 0; i < recipientsCount; i++ {
   449  		kid, didKey, marshalledPubKey, kh := createAndMarshalKeyByKeyType(t, k, kt)
   450  
   451  		r = append(r, marshalledPubKey)
   452  		rKH = append(rKH, kh)
   453  		kids = append(kids, kid)
   454  		didKeys = append(didKeys, didKey)
   455  	}
   456  
   457  	return kids, didKeys, r, rKH
   458  }
   459  
   460  // createAndMarshalKeyByKeyType creates a new recipient keyset.Handle, extracts public key, marshals it and returns
   461  // both marshalled public key, jwk kid, didKey and original recipient keyset.Handle.
   462  func createAndMarshalKeyByKeyType(t *testing.T, k *localkms.LocalKMS,
   463  	kt kms.KeyType) (string, string, []byte, *keyset.Handle) {
   464  	t.Helper()
   465  
   466  	kid, keyHandle, err := k.Create(kt)
   467  	require.NoError(t, err)
   468  
   469  	kh, ok := keyHandle.(*keyset.Handle)
   470  	require.True(t, ok)
   471  
   472  	pubKeyBytes, err := exportPubKeyBytes(kh, kid)
   473  	require.NoError(t, err)
   474  
   475  	key := &cryptoapi.PublicKey{}
   476  	err = json.Unmarshal(pubKeyBytes, key)
   477  	require.NoError(t, err)
   478  
   479  	didKey, err := kmsdidkey.BuildDIDKeyByKeyType(pubKeyBytes, kt)
   480  	require.NoError(t, err)
   481  
   482  	key.KID = didKey
   483  	mKey, err := json.Marshal(key)
   484  	require.NoError(t, err)
   485  
   486  	printKey(t, mKey, kh, kid, didKey)
   487  
   488  	return kid, didKey, mKey, kh
   489  }
   490  
   491  func printKey(t *testing.T, mPubKey []byte, kh *keyset.Handle, kid, didKey string) {
   492  	t.Helper()
   493  
   494  	extractKey, err := extractPrivKey(kh)
   495  	require.NoError(t, err)
   496  
   497  	switch keyType := extractKey.(type) {
   498  	case *hybrid.ECPrivateKey:
   499  		t.Logf("** EC key: %s, \n\t kms kid: %s, \n\t jwe kid (did:key):%s", getPrintedECPrivKey(t, keyType), kid,
   500  			didKey)
   501  	case []byte:
   502  		pubKey := new(cryptoapi.PublicKey)
   503  		err := json.Unmarshal(mPubKey, pubKey)
   504  		require.NoError(t, err)
   505  
   506  		fullKey := append(keyType, pubKey.X...)
   507  		t.Logf("** X25519 key: %s, \n\t kms kid: %s, \n\t jwe kid (did:key):%s", getPrintedX25519PrivKey(t, fullKey), kid,
   508  			didKey)
   509  	default:
   510  		t.Errorf("not supported key type: %s", keyType)
   511  	}
   512  }
   513  
   514  func prettyPrint(msg []byte) (string, error) {
   515  	var prettyJSON bytes.Buffer
   516  
   517  	err := json.Indent(&prettyJSON, msg, "", "\t")
   518  	if err != nil {
   519  		return "", err
   520  	}
   521  
   522  	return prettyJSON.String(), nil
   523  }
   524  
   525  func getPrintedECPrivKey(t *testing.T, privKeyType *hybrid.ECPrivateKey) string {
   526  	jwk := jose.JSONWebKey{
   527  		Key: &ecdsa.PrivateKey{
   528  			PublicKey: ecdsa.PublicKey{
   529  				Curve: privKeyType.PublicKey.Curve,
   530  				X:     privKeyType.PublicKey.Point.X,
   531  				Y:     privKeyType.PublicKey.Point.Y,
   532  			},
   533  			D: privKeyType.D,
   534  		},
   535  	}
   536  
   537  	jwkByte, err := jwk.MarshalJSON()
   538  	require.NoError(t, err)
   539  
   540  	jwkStr, err := prettyPrint(jwkByte)
   541  	require.NoError(t, err)
   542  
   543  	return jwkStr
   544  }
   545  
   546  func getPrintedX25519PrivKey(t *testing.T, privKeyType ed25519.PrivateKey) string {
   547  	jwk := jose.JSONWebKey{
   548  		Key: privKeyType,
   549  	}
   550  
   551  	jwkByte, err := jwk.MarshalJSON()
   552  	require.NoError(t, err)
   553  
   554  	jwkStr, err := prettyPrint(jwkByte)
   555  	require.NoError(t, err)
   556  
   557  	return strings.Replace(jwkStr, "Ed25519", "X25519", 1)
   558  }
   559  
   560  func extractPrivKey(kh *keyset.Handle) (interface{}, error) {
   561  	nistPECDHKWPrivateKeyTypeURL := "type.hyperledger.org/hyperledger.aries.crypto.tink.NistPEcdhKwPrivateKey"
   562  	x25519ECDHKWPrivateKeyTypeURL := "type.hyperledger.org/hyperledger.aries.crypto.tink.X25519EcdhKwPrivateKey"
   563  	buf := new(bytes.Buffer)
   564  	w := &privKeyWriter{w: buf}
   565  	nAEAD := &noopAEAD{}
   566  
   567  	if kh == nil {
   568  		return nil, fmt.Errorf("extractPrivKey: kh is nil")
   569  	}
   570  
   571  	err := kh.Write(w, nAEAD)
   572  	if err != nil {
   573  		return nil, fmt.Errorf("extractPrivKey: retrieving private key failed: %w", err)
   574  	}
   575  
   576  	ks := new(tinkpb.Keyset)
   577  
   578  	err = proto.Unmarshal(buf.Bytes(), ks)
   579  	if err != nil {
   580  		return nil, errors.New("extractPrivKey: invalid private key")
   581  	}
   582  
   583  	primaryKey := ks.Key[0]
   584  
   585  	switch primaryKey.KeyData.TypeUrl {
   586  	case nistPECDHKWPrivateKeyTypeURL:
   587  		pbKey := new(ecdhpb.EcdhAeadPrivateKey)
   588  
   589  		err = proto.Unmarshal(primaryKey.KeyData.Value, pbKey)
   590  		if err != nil {
   591  			return nil, errors.New("extractPrivKey: invalid key in keyset")
   592  		}
   593  
   594  		var c elliptic.Curve
   595  
   596  		c, err = hybrid.GetCurve(pbKey.PublicKey.Params.KwParams.CurveType.String())
   597  		if err != nil {
   598  			return nil, fmt.Errorf("extractPrivKey: invalid key: %w", err)
   599  		}
   600  
   601  		return hybrid.GetECPrivateKey(c, pbKey.KeyValue), nil
   602  	case x25519ECDHKWPrivateKeyTypeURL:
   603  		pbKey := new(ecdhpb.EcdhAeadPrivateKey)
   604  
   605  		err = proto.Unmarshal(primaryKey.KeyData.Value, pbKey)
   606  		if err != nil {
   607  			return nil, errors.New("extractPrivKey: invalid key in keyset")
   608  		}
   609  
   610  		if pbKey.PublicKey.Params.KwParams.CurveType.String() != commonpb.EllipticCurveType_CURVE25519.String() {
   611  			return nil, errors.New("extractPrivKey: invalid key curve")
   612  		}
   613  
   614  		return pbKey.KeyValue, nil
   615  	}
   616  
   617  	return nil, fmt.Errorf("extractPrivKey: can't extract unsupported private key '%s'", primaryKey.KeyData.TypeUrl)
   618  }
   619  
   620  type noopAEAD struct{}
   621  
   622  func (n noopAEAD) Encrypt(plaintext, _ []byte) ([]byte, error) {
   623  	return plaintext, nil
   624  }
   625  
   626  func (n noopAEAD) Decrypt(ciphertext, _ []byte) ([]byte, error) {
   627  	return ciphertext, nil
   628  }
   629  
   630  type privKeyWriter struct {
   631  	w io.Writer
   632  }
   633  
   634  // Write writes the public keyset to the underlying w.Writer. It's not used in this implementation.
   635  func (p *privKeyWriter) Write(_ *tinkpb.Keyset) error {
   636  	return fmt.Errorf("privKeyWriter: write function not supported")
   637  }
   638  
   639  // WriteEncrypted writes the encrypted keyset to the underlying w.Writer.
   640  func (p *privKeyWriter) WriteEncrypted(ks *tinkpb.EncryptedKeyset) error {
   641  	return write(p.w, ks)
   642  }
   643  
   644  func write(w io.Writer, ks *tinkpb.EncryptedKeyset) error {
   645  	// we write EncryptedKeyset directly without decryption since noopAEAD was used to write *keyset.Handle
   646  	_, e := w.Write(ks.EncryptedKeyset)
   647  	return e
   648  }
   649  
   650  func createKMS(t *testing.T) *localkms.LocalKMS {
   651  	t.Helper()
   652  
   653  	p, err := mockkms.NewProviderForKMS(mockstorage.NewMockStoreProvider(), &noop.NoLock{})
   654  	require.NoError(t, err)
   655  
   656  	k, err := localkms.New("local-lock://test/key/uri", p)
   657  	require.NoError(t, err)
   658  
   659  	return k
   660  }
   661  
   662  func newMockProvider(customKMS kms.KeyManager, customCrypto cryptoapi.Crypto) *mockprovider.Provider {
   663  	return &mockprovider.Provider{
   664  		KMSValue:        customKMS,
   665  		CryptoValue:     customCrypto,
   666  		VDRegistryValue: &mockvdr.MockVDRegistry{},
   667  	}
   668  }