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

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package jose
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/elliptic"
    12  	"encoding/base64"
    13  	"encoding/json"
    14  	"fmt"
    15  	"testing"
    16  
    17  	"github.com/google/tink/go/aead"
    18  	"github.com/google/tink/go/keyset"
    19  	"github.com/stretchr/testify/require"
    20  
    21  	cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto"
    22  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto"
    23  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/ecdh"
    24  	"github.com/hyperledger/aries-framework-go/pkg/crypto/tinkcrypto/primitive/composite/keyio"
    25  )
    26  
    27  func TestFailConvertRecKeyToMarshalledJWK(t *testing.T) {
    28  	t.Run("test convertRecEPKToMarshalledJWK using EPK with bad curve", func(t *testing.T) {
    29  		recKey := &cryptoapi.RecipientWrappedKey{
    30  			EPK: cryptoapi.PublicKey{
    31  				Curve: "badCurveName",
    32  				Type:  "EC",
    33  			},
    34  		}
    35  
    36  		_, err := convertRecEPKToMarshalledJWK(&recKey.EPK)
    37  		require.EqualError(t, err, "unsupported curve")
    38  	})
    39  
    40  	t.Run("test convertRecEPKToMarshalledJWK and buildRecipientHeaders using EPK with bad key type", func(t *testing.T) {
    41  		recKey := &cryptoapi.RecipientWrappedKey{
    42  			EPK: cryptoapi.PublicKey{
    43  				Curve: "P-256",
    44  			},
    45  		}
    46  
    47  		_, err := convertRecEPKToMarshalledJWK(&recKey.EPK)
    48  		require.EqualError(t, err, "invalid key type")
    49  
    50  		_, err = buildRecipientHeaders(recKey, false)
    51  		require.EqualError(t, err, "failed to convert recipient key to marshalled JWK: invalid key type")
    52  	})
    53  }
    54  
    55  func TestBuildRecsWithEPKMissingKeyTypeFailure(t *testing.T) {
    56  	recKey := &cryptoapi.RecipientWrappedKey{
    57  		EPK: cryptoapi.PublicKey{
    58  			Curve: "P-256",
    59  		},
    60  	}
    61  
    62  	c, err := tinkcrypto.New()
    63  	require.NoError(t, err)
    64  
    65  	recipients, recsKH := createRecipients(t, 2)
    66  
    67  	enc, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType,
    68  		"0", recsKH["0"], recipients, c)
    69  	require.NoError(t, err)
    70  
    71  	_, _, err = enc.buildRecs([]*cryptoapi.RecipientWrappedKey{recKey}, true)
    72  	require.EqualError(t, err, "failed to convert recipient key to marshalled JWK: invalid key type")
    73  }
    74  
    75  func TestBadSenderKeyType(t *testing.T) {
    76  	c, err := tinkcrypto.New()
    77  	require.NoError(t, err)
    78  
    79  	// create a keyset.Handle that fails JWE/ECDH primitive execution (must come from an ECDH key template).
    80  	aeadKT := aead.AES256GCMKeyTemplate()
    81  	aeadKH, err := keyset.NewHandle(aeadKT)
    82  	require.NoError(t, err)
    83  
    84  	recipients, _ := createRecipients(t, 2)
    85  
    86  	// create jweEncrypter manually with a bad sender type
    87  	jweEncrypter := JWEEncrypt{
    88  		skid:           "123",
    89  		senderKH:       aeadKH,
    90  		recipientsKeys: recipients,
    91  		crypto:         c,
    92  		encAlg:         A256GCM,
    93  	}
    94  
    95  	_, err = jweEncrypter.Encrypt([]byte{})
    96  	require.EqualError(t, err, "jweencryptWithSender: failed to wrap cek: wrapCEKForRecipientsWithTagAndEPK: "+
    97  		"wrapKey: 1 failed: wrapKey: deriveKEKAndWrap: error ECDH-1PU kek derivation: derive1PUKEK: EC key derivation "+
    98  		"error derive1PUWithECKey: failed to retrieve sender key: ksToPrivateECDSAKey: failed to extract sender key: "+
    99  		"extractPrivKey: can't extract unsupported private key 'type.googleapis.com/google.crypto.tink.AesGcmKey'")
   100  }
   101  
   102  func TestMergeSingleRecipientsHeadersFailureWithUnsetCurve(t *testing.T) {
   103  	aad := map[string]string{"enc": "test"}
   104  
   105  	mAAD, err := json.Marshal(aad)
   106  	require.NoError(t, err)
   107  
   108  	wk := &cryptoapi.RecipientWrappedKey{
   109  		EPK: cryptoapi.PublicKey{Type: "EC"},
   110  	}
   111  
   112  	// fail with aad not base64URL encoded
   113  	_, err = mergeSingleRecipientHeaders(wk, []byte("aad not base64URL encoded"), json.Marshal)
   114  	require.EqualError(t, err, "illegal base64 data at input byte 3")
   115  
   116  	badAAD := base64.RawURLEncoding.EncodeToString([]byte("aad not a json format"))
   117  
   118  	// fail with aad not being a marshalled json
   119  	_, err = mergeSingleRecipientHeaders(wk, []byte(badAAD), json.Marshal)
   120  	require.EqualError(t, err, "invalid character 'a' looking for beginning of value")
   121  
   122  	// fail with epk curve not set
   123  	_, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), json.Marshal)
   124  	require.EqualError(t, err, "unsupported curve")
   125  
   126  	// set epk curve for subsequent tests
   127  	wk.EPK.Curve = elliptic.P256().Params().Name
   128  
   129  	fm := &failingMarshaller{
   130  		numTimesMarshalCalledBeforeReturnErr: 0,
   131  	}
   132  
   133  	// fail KID marshalling
   134  	_, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), fm.failingMarshal)
   135  	require.EqualError(t, err, errFailingMarshal.Error())
   136  
   137  	fm = &failingMarshaller{
   138  		numTimesMarshalCalledBeforeReturnErr: 1,
   139  	}
   140  
   141  	// fail Alg marshalling
   142  	_, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), fm.failingMarshal)
   143  	require.EqualError(t, err, errFailingMarshal.Error())
   144  
   145  	fm = &failingMarshaller{
   146  		numTimesMarshalCalledBeforeReturnErr: 1,
   147  	}
   148  
   149  	// fail EPK marshalling
   150  	_, err = mergeSingleRecipientHeaders(wk, []byte(base64.RawURLEncoding.EncodeToString(mAAD)), fm.failingMarshal)
   151  	require.EqualError(t, err, errFailingMarshal.Error())
   152  }
   153  
   154  func TestEmptyComputeAuthData(t *testing.T) {
   155  	protecteHeaders := new(map[string]interface{})
   156  	aad := []byte("")
   157  	_, err := computeAuthData(*protecteHeaders, "", aad)
   158  	require.NoError(t, err, "computeAuthData with empty protectedHeaders and empty aad should not fail")
   159  }
   160  
   161  // createRecipients and return their public key and keyset.Handle.
   162  func createRecipients(t *testing.T, numberOfEntities int) ([]*cryptoapi.PublicKey, map[string]*keyset.Handle) {
   163  	t.Helper()
   164  
   165  	r := make([]*cryptoapi.PublicKey, 0)
   166  	rKH := make(map[string]*keyset.Handle)
   167  
   168  	for i := 0; i < numberOfEntities; i++ {
   169  		mrKey, kh := createAndMarshalEntityKey(t)
   170  		ecPubKey := new(cryptoapi.PublicKey)
   171  		err := json.Unmarshal(mrKey, ecPubKey)
   172  		require.NoError(t, err)
   173  
   174  		ecPubKey.KID = fmt.Sprint(i)
   175  
   176  		r = append(r, ecPubKey)
   177  		rKH[fmt.Sprint(i)] = kh
   178  	}
   179  
   180  	return r, rKH
   181  }
   182  
   183  // createAndMarshalEntityKey creates a new recipient keyset.Handle, extracts public key, marshals it and returns
   184  // both marshalled public key and original recipient keyset.Handle.
   185  func createAndMarshalEntityKey(t *testing.T) ([]byte, *keyset.Handle) {
   186  	t.Helper()
   187  
   188  	tmpl := ecdh.NISTP256ECDHKWKeyTemplate()
   189  
   190  	kh, err := keyset.NewHandle(tmpl)
   191  	require.NoError(t, err)
   192  
   193  	pubKH, err := kh.Public()
   194  	require.NoError(t, err)
   195  
   196  	buf := new(bytes.Buffer)
   197  	pubKeyWriter := keyio.NewWriter(buf)
   198  	require.NotEmpty(t, pubKeyWriter)
   199  
   200  	err = pubKH.WriteWithNoSecrets(pubKeyWriter)
   201  	require.NoError(t, err)
   202  
   203  	return buf.Bytes(), kh
   204  }
   205  
   206  const (
   207  	testEncType     = "application/test-encrypted+json"
   208  	testPayloadType = "application/test-content+json"
   209  )
   210  
   211  func TestFailJWEEncrypt(t *testing.T) {
   212  	c, err := tinkcrypto.New()
   213  	require.NoError(t, err)
   214  
   215  	recipients, recsKH := createRecipients(t, 2)
   216  
   217  	enc, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType,
   218  		"0", recsKH["0"], recipients, c)
   219  	require.NoError(t, err)
   220  
   221  	enc.encAlg = "Undefined"
   222  
   223  	_, err = enc.Encrypt([]byte("test"))
   224  	require.EqualError(t, err, "jweencrypt: failed to get encryption primitive: getECDHEncPrimitive: encAlg"+
   225  		" not supported: 'Undefined'")
   226  }
   227  
   228  func TestFailJWEDecrypt(t *testing.T) {
   229  	c, err := tinkcrypto.New()
   230  	require.NoError(t, err)
   231  
   232  	recipients, _ := createRecipients(t, 2)
   233  
   234  	// encrypt using local jose package
   235  	jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType,
   236  		"", nil, recipients, c)
   237  	require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys")
   238  
   239  	pt := []byte("some msg")
   240  	jwe, err := jweEncrypter.Encrypt(pt)
   241  	require.NoError(t, err)
   242  	require.Equal(t, len(recipients), len(jwe.Recipients))
   243  
   244  	dec := NewJWEDecrypt(nil, c, nil)
   245  	require.NotEmpty(t, dec)
   246  
   247  	jwe.ProtectedHeaders[HeaderEncryption] = "Undefined"
   248  
   249  	_, err = dec.decryptJWE(jwe, []byte(""))
   250  	require.EqualError(t, err, "jwedecrypt: failed to get decryption primitive: invalid content encAlg: 'Undefined'")
   251  
   252  	delete(jwe.ProtectedHeaders, HeaderEncryption)
   253  
   254  	_, err = dec.decryptJWE(jwe, []byte(""))
   255  	require.EqualError(t, err, "jwedecrypt: JWE 'enc' protected header is missing")
   256  }
   257  
   258  func TestBuildAPUAPVFailures(t *testing.T) {
   259  	c, err := tinkcrypto.New()
   260  	require.NoError(t, err)
   261  
   262  	recipients, _ := createRecipients(t, 3)
   263  
   264  	// encrypt using local jose package
   265  	jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType,
   266  		"", nil, recipients, c)
   267  	require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys")
   268  
   269  	t.Run("call encryptWithSender and  buildAPUAPV with JWEEncrypter having empty skid", func(t *testing.T) {
   270  		_, err = jweEncrypter.encryptWithSender(nil, nil, nil, nil, nil)
   271  		require.EqualError(t, err, "jweencryptWithSender: cannot create APU/APV with empty sender skid")
   272  
   273  		_, _, err = jweEncrypter.buildAPUAPV()
   274  		require.EqualError(t, err, "cannot create APU/APV with empty sender skid")
   275  	})
   276  
   277  	t.Run("call buildAPUAPV with JWEEncrypter having empty recipients", func(t *testing.T) {
   278  		jweEncrypter.skid = "skid"
   279  		jweEncrypter.recipientsKeys = nil
   280  
   281  		_, _, err = jweEncrypter.buildAPUAPV()
   282  		require.EqualError(t, err, "cannot create APU/APV with empty recipient keys")
   283  	})
   284  }
   285  
   286  func TestGenerateEPKAndUpdateAuthDataFor1PUFailure(t *testing.T) {
   287  	c, err := tinkcrypto.New()
   288  	require.NoError(t, err)
   289  
   290  	recipients, _ := createRecipients(t, 5)
   291  
   292  	recipients[0].Type = "invalidType"
   293  
   294  	// encrypt using local jose package
   295  	jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType,
   296  		"", nil, recipients, c)
   297  	require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys")
   298  
   299  	epk, authData, authJSON, err := jweEncrypter.generateEPKAndUpdateAuthDataFor1PU(nil, nil, nil, nil)
   300  	require.EqualError(t, err, "generateEPKAndUpdateAuthDataFor1PU: newEPK: invalid key type 'invalidType'")
   301  	require.Empty(t, epk)
   302  	require.Empty(t, authData)
   303  	require.Empty(t, authJSON)
   304  
   305  	recipients[0].Type = "EC"
   306  	recipients[0].Curve = "invalid"
   307  
   308  	_, _, err = jweEncrypter.newEPK([]byte(""))
   309  	require.EqualError(t, err, "newEPK: ecEPKAndAlg: getCurve: unsupported curve")
   310  }
   311  
   312  func TestBuildCommonAuthDataFailure(t *testing.T) {
   313  	c, err := tinkcrypto.New()
   314  	require.NoError(t, err)
   315  
   316  	recipients, _ := createRecipients(t, 5)
   317  
   318  	recipients[0].Type = "invalid"
   319  
   320  	// encrypt using local jose package
   321  	jweEncrypter, err := NewJWEEncrypt(A256GCM, testEncType, testPayloadType,
   322  		"", nil, recipients, c)
   323  	require.NoError(t, err, "NewJWEEncrypt should not fail with non empty recipientPubKeys")
   324  
   325  	t.Run("buildCommonAuthData with authData having invalid b64 format", func(t *testing.T) {
   326  		epk, authData, authJSON, err := jweEncrypter.buildCommonAuthData(0, "", "==Badb64Str$$#^",
   327  			nil, nil, nil, nil)
   328  		require.EqualError(t, err, "buildCommonAuthData: authdata decode: illegal base64 data at input byte 0")
   329  		require.Empty(t, epk)
   330  		require.Empty(t, authData)
   331  		require.Empty(t, authJSON)
   332  	})
   333  
   334  	t.Run("buildCommonAuthData with authData having invalid json format", func(t *testing.T) {
   335  		epk, authData, authJSON, err := jweEncrypter.buildCommonAuthData(0, "", "badjsonunmarshal",
   336  			nil, nil, nil, nil)
   337  		require.EqualError(t, err, "buildCommonAuthData: authData unmarshall: invalid character 'm' looking "+
   338  			"for beginning of value")
   339  		require.Empty(t, epk)
   340  		require.Empty(t, authData)
   341  		require.Empty(t, authJSON)
   342  	})
   343  
   344  	t.Run("buildCommonAuthData with epk having invalid public key type", func(t *testing.T) {
   345  		epk, authData, authJSON, err := jweEncrypter.buildCommonAuthData(0, "", "eyJ0ZXN0IjoidGVzdCJ9",
   346  			nil, nil, nil, &cryptoapi.PrivateKey{
   347  				PublicKey: cryptoapi.PublicKey{Type: "invalid"},
   348  				D:         nil,
   349  			})
   350  		require.EqualError(t, err, "buildCommonAuthData: epk marshall: invalid key type")
   351  		require.Empty(t, epk)
   352  		require.Empty(t, authData)
   353  		require.Empty(t, authJSON)
   354  	})
   355  }
   356  
   357  func TestDecodeAPUAPVFailure(t *testing.T) {
   358  	t.Run("decodeAPUAPV with recipient APU header as invalid b64 []byte", func(t *testing.T) {
   359  		_, _, err := decodeAPUAPV(&RecipientHeaders{APU: "=Badb64Str$$#^"})
   360  		require.EqualError(t, err, "illegal base64 data at input byte 0")
   361  	})
   362  
   363  	t.Run("decodeAPUAPV with recipient APV header as invalid b64 []byte", func(t *testing.T) {
   364  		_, _, err := decodeAPUAPV(&RecipientHeaders{APV: "=Badb64Str$$#^"})
   365  		require.EqualError(t, err, "illegal base64 data at input byte 0")
   366  	})
   367  }
   368  
   369  func TestJWKMarshalEPKFailure(t *testing.T) {
   370  	t.Run("jwkMarshalEPK with protectedHeadersJSON having 'epk' with invalid json format", func(t *testing.T) {
   371  		err := jwkMarshalEPK(map[string]json.RawMessage{HeaderEPK: []byte("badjsonunmarshal")})
   372  		require.EqualError(t, err, "unable to read JWK: invalid character 'b' looking for beginning of value")
   373  	})
   374  }