Skip to content
This repository has been archived by the owner on Mar 27, 2024. It is now read-only.

feat: add KMS key type for X25519 key #2486

Merged
merged 1 commit into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions pkg/didcomm/packager/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func TestBaseKMSInPackager_UnpackMessage(t *testing.T) {
require.NoError(t, err)

// fromKey is stored in the KMS
fromKID, fromKey, err := customKMS.CreateAndExportPubKeyBytes(kms.ECDH256KWAES256GCMType)
fromKID, fromKey, err := customKMS.CreateAndExportPubKeyBytes(kms.NISTP256ECDHKWType)
require.NoError(t, err)

// for authcrypt, sender key should be in third party store, must use base58 wrapped store to match kms store.
Expand All @@ -149,7 +149,7 @@ func TestBaseKMSInPackager_UnpackMessage(t *testing.T) {
require.NoError(t, err)

// toVerKey is stored in the KMS as well
toKID, toKey, err := customKMS.CreateAndExportPubKeyBytes(kms.ECDH256KWAES256GCM)
toKID, toKey, err := customKMS.CreateAndExportPubKeyBytes(kms.NISTP256ECDHKW)
require.NoError(t, err)

// PackMessage should pass with both value from and to keys
Expand Down Expand Up @@ -207,10 +207,10 @@ func TestBaseKMSInPackager_UnpackMessage(t *testing.T) {
require.NoError(t, err)

// use ECDH1PU type as we are using a sender key (ie: packer's FromKey is not empty aka authcrypt)
fromKID, _, err := customKMS.Create(kms.ECDH384KWAES256GCMType)
fromKID, _, err := customKMS.Create(kms.NISTP384ECDHKWType)
require.NoError(t, err)

_, toKey, err := customKMS.CreateAndExportPubKeyBytes(kms.ECDH384KWAES256GCMType)
_, toKey, err := customKMS.CreateAndExportPubKeyBytes(kms.NISTP384ECDHKWType)
require.NoError(t, err)

// try pack with nil envelope - should fail
Expand Down Expand Up @@ -282,10 +282,10 @@ func TestBaseKMSInPackager_UnpackMessage(t *testing.T) {
packager, err := New(mockedProviders)
require.NoError(t, err)

fromKID, fromKey, err := customKMS.CreateAndExportPubKeyBytes(kms.ECDH256KWAES256GCMType)
fromKID, fromKey, err := customKMS.CreateAndExportPubKeyBytes(kms.NISTP256ECDHKWType)
require.NoError(t, err)

_, toKey, err := customKMS.CreateAndExportPubKeyBytes(kms.ECDH256KWAES256GCMType)
_, toKey, err := customKMS.CreateAndExportPubKeyBytes(kms.NISTP256ECDHKWType)
require.NoError(t, err)

// pack an non empty envelope - should pass
Expand Down
85 changes: 60 additions & 25 deletions pkg/didcomm/packer/anoncrypt/pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,43 +28,78 @@ import (

func TestAnoncryptPackerSuccess(t *testing.T) {
k := createKMS(t)
_, recipientsKeys, keyHandles := createRecipients(t, k, 10)

cryptoSvc, err := tinkcrypto.New()
require.NoError(t, err)
tests := []struct {
name string
keyType kms.KeyType
encAlg jose.EncAlg
}{
{
"anoncrypt using NISTP256ECDHKW and AES256-GCM",
kms.NISTP256ECDHKWType,
jose.A256GCM,
},
{
"anoncrypt using X25519ECDHKW and XChacha20Poly1305",
kms.X25519ECDHKWType,
jose.XC20P,
},
{
"anoncrypt using NISTP256ECDHKW and XChacha20Poly1305",
kms.NISTP256ECDHKWType,
jose.XC20P,
},
{
"anoncrypt using X25519ECDHKW and AES256-GCM",
kms.X25519ECDHKWType,
jose.A256GCM,
},
}

anonPacker, err := New(newMockProvider(k, cryptoSvc), jose.A256GCM)
require.NoError(t, err)
t.Parallel()

origMsg := []byte("secret message")
ct, err := anonPacker.Pack(origMsg, nil, recipientsKeys)
require.NoError(t, err)
for _, tt := range tests {
tc := tt
t.Run(fmt.Sprintf("running %s", tc.name), func(t *testing.T) {
_, recipientsKeys, keyHandles := createRecipientsByKeyType(t, k, 3, tc.keyType)

msg, err := anonPacker.Unpack(ct)
require.NoError(t, err)
cryptoSvc, err := tinkcrypto.New()
require.NoError(t, err)

recKey, err := exportPubKeyBytes(keyHandles[0])
require.NoError(t, err)
anonPacker, err := New(newMockProvider(k, cryptoSvc), jose.A256GCM)
require.NoError(t, err)

require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)
origMsg := []byte("secret message")
ct, err := anonPacker.Pack(origMsg, nil, recipientsKeys)
require.NoError(t, err)

// try with only 1 recipient
ct, err = anonPacker.Pack(origMsg, nil, [][]byte{recipientsKeys[0]})
require.NoError(t, err)
msg, err := anonPacker.Unpack(ct)
require.NoError(t, err)

msg, err = anonPacker.Unpack(ct)
require.NoError(t, err)
recKey, err := exportPubKeyBytes(keyHandles[0])
require.NoError(t, err)

require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)
require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)

require.Equal(t, encodingType, anonPacker.EncodingType())
// try with only 1 recipient
ct, err = anonPacker.Pack(origMsg, nil, [][]byte{recipientsKeys[0]})
require.NoError(t, err)

msg, err = anonPacker.Unpack(ct)
require.NoError(t, err)

require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)

require.Equal(t, encodingType, anonPacker.EncodingType())
})
}
}

func TestAnoncryptPackerSuccessWithDifferentCurvesSuccess(t *testing.T) {
k := createKMS(t)
_, recipientsKey1, keyHandles1 := createRecipients(t, k, 1)
_, recipientsKey2, _ := createRecipientsByKeyType(t, k, 1, kms.ECDH384KWAES256GCM)
_, recipientsKey3, _ := createRecipientsByKeyType(t, k, 1, kms.ECDH521KWAES256GCM)
_, recipientsKey2, _ := createRecipientsByKeyType(t, k, 1, kms.NISTP384ECDHKW)
_, recipientsKey3, _ := createRecipientsByKeyType(t, k, 1, kms.NISTP521ECDHKW)

recipientsKeys := make([][]byte, 3)
recipientsKeys[0] = make([]byte, len(recipientsKey1[0]))
Expand Down Expand Up @@ -183,10 +218,10 @@ func TestAnoncryptPackerFail(t *testing.T) {
require.NoError(t, err)

// rotate keys to update keyID and force a failure
_, _, err = k.Rotate(kms.ECDH256KWAES256GCMType, kids[0])
_, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[0])
require.NoError(t, err)

_, _, err = k.Rotate(kms.ECDH256KWAES256GCMType, kids[1])
_, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[1])
require.NoError(t, err)

_, err = validAnonPacker.Unpack(ct)
Expand All @@ -196,7 +231,7 @@ func TestAnoncryptPackerFail(t *testing.T) {

// createRecipients and return their public key and keyset.Handle.
func createRecipients(t *testing.T, k *localkms.LocalKMS, recipientsCount int) ([]string, [][]byte, []*keyset.Handle) {
return createRecipientsByKeyType(t, k, recipientsCount, kms.ECDH256KWAES256GCM)
return createRecipientsByKeyType(t, k, recipientsCount, kms.NISTP256ECDHKW)
}

func createRecipientsByKeyType(t *testing.T, k *localkms.LocalKMS, recipientsCount int,
Expand Down
108 changes: 72 additions & 36 deletions pkg/didcomm/packer/authcrypt/pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,56 +31,92 @@ import (

func TestAuthryptPackerSuccess(t *testing.T) {
k := createKMS(t)
_, recipientsKeys, keyHandles := createRecipients(t, k, 10)

skid, senderKey, _ := createAndMarshalKey(t, k)
tests := []struct {
name string
keyType kms.KeyType
encAlg jose.EncAlg
}{
{
"authpack using NISTP256ECDHKW and AES256-GCM",
kms.NISTP256ECDHKWType,
jose.A256GCM,
},
{
"authpack using X25519ECDHKW and XChacha20Poly1305",
kms.X25519ECDHKWType,
jose.XC20P,
},
{
"authpack using NISTP256ECDHKW and XChacha20Poly1305",
kms.NISTP256ECDHKWType,
jose.XC20P,
},
{
"authpack using X25519ECDHKW and AES256-GCM",
kms.X25519ECDHKWType,
jose.A256GCM,
},
}

thirdPartyKeyStore := make(map[string][]byte)
mockStoreProvider := &mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{
Store: thirdPartyKeyStore,
}}
t.Parallel()

cryptoSvc, err := tinkcrypto.New()
require.NoError(t, err)
for _, tt := range tests {
tc := tt
t.Run(fmt.Sprintf("running %s", tc.name), func(t *testing.T) {
_, recipientsKeys, keyHandles := createRecipientsByKeyType(t, k, 3, tc.keyType)

authPacker, err := New(newMockProvider(mockStoreProvider, k, cryptoSvc), jose.A256GCM)
require.NoError(t, err)
skid, senderKey, _ := createAndMarshalKeyByKeyType(t, k, tc.keyType)

// add sender key in thirdPartyKS (prep step before Authcrypt.Pack()/Unpack())
fromWrappedKID := prefix.StorageKIDPrefix + skid
thirdPartyKeyStore[fromWrappedKID] = senderKey
thirdPartyKeyStore := make(map[string][]byte)
mockStoreProvider := &mockstorage.MockStoreProvider{Store: &mockstorage.MockStore{
Store: thirdPartyKeyStore,
}}

origMsg := []byte("secret message")
ct, err := authPacker.Pack(origMsg, []byte(skid), recipientsKeys)
require.NoError(t, err)
cryptoSvc, err := tinkcrypto.New()
require.NoError(t, err)

msg, err := authPacker.Unpack(ct)
require.NoError(t, err)
authPacker, err := New(newMockProvider(mockStoreProvider, k, cryptoSvc), tc.encAlg)
require.NoError(t, err)

recKey, err := exportPubKeyBytes(keyHandles[0])
require.NoError(t, err)
// add sender key in thirdPartyKS (prep step before Authcrypt.Pack()/Unpack())
fromWrappedKID := prefix.StorageKIDPrefix + skid
thirdPartyKeyStore[fromWrappedKID] = senderKey

require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)
origMsg := []byte("secret message")
ct, err := authPacker.Pack(origMsg, []byte(skid), recipientsKeys)
require.NoError(t, err)

// try with only 1 recipient
ct, err = authPacker.Pack(origMsg, []byte(skid), [][]byte{recipientsKeys[0]})
require.NoError(t, err)
msg, err := authPacker.Unpack(ct)
require.NoError(t, err)

msg, err = authPacker.Unpack(ct)
require.NoError(t, err)
recKey, err := exportPubKeyBytes(keyHandles[0])
require.NoError(t, err)

require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)
require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)

require.Equal(t, encodingType, authPacker.EncodingType())
// try with only 1 recipient to force compact JWE serialization
ct, err = authPacker.Pack(origMsg, []byte(skid), [][]byte{recipientsKeys[0]})
require.NoError(t, err)

msg, err = authPacker.Unpack(ct)
require.NoError(t, err)

require.EqualValues(t, &transport.Envelope{Message: origMsg, ToKey: recKey}, msg)

require.Equal(t, encodingType, authPacker.EncodingType())
})
}
}

func TestAuthryptPackerUsingKeysWithDifferentCurvesSuccess(t *testing.T) {
k := createKMS(t)
_, recipientsKey1, keyHandles1 := createRecipients(t, k, 1)
// since authcrypt does ECDH kw using the sender key, the recipient keys must be on the same curve as the sender's.
// this is why recipient keys with different curves are not supported for authcrypt.
_, recipientsKey2, _ := createRecipients(t, k, 1) // can't create key with kms.ECDH384KWAES256GCM
_, recipientsKey3, _ := createRecipients(t, k, 1) // can't create key with kms.ECDH521KWAES256GCM
// since authcrypt does ECDH kw using the sender key, the recipient keys must be on the same curve (for NIST P keys)
// and the same key type (for NIST P / X25519 keys) as the sender's.
// this is why recipient keys with different curves/type are not supported for authcrypt.
_, recipientsKey2, _ := createRecipients(t, k, 1) // can't create key with kms.NISTP384ECDHKW
_, recipientsKey3, _ := createRecipients(t, k, 1) // can't create key with kms.NISTP521ECDHKW

recipientsKeys := make([][]byte, 3)
recipientsKeys[0] = make([]byte, len(recipientsKey1[0]))
Expand Down Expand Up @@ -251,10 +287,10 @@ func TestAuthcryptPackerFail(t *testing.T) {
require.NoError(t, err)

// rotate keys to update keyID and force a failure
_, _, err = k.Rotate(kms.ECDH256KWAES256GCMType, kids[0])
_, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[0])
require.NoError(t, err)

_, _, err = k.Rotate(kms.ECDH256KWAES256GCMType, kids[1])
_, _, err = k.Rotate(kms.NISTP256ECDHKWType, kids[1])
require.NoError(t, err)

_, err = validAuthPacker.Unpack(ct)
Expand All @@ -264,7 +300,7 @@ func TestAuthcryptPackerFail(t *testing.T) {

// createRecipients and return their public key and keyset.Handle.
func createRecipients(t *testing.T, k *localkms.LocalKMS, recipientsCount int) ([]string, [][]byte, []*keyset.Handle) {
return createRecipientsByKeyType(t, k, recipientsCount, kms.ECDH256KWAES256GCM)
return createRecipientsByKeyType(t, k, recipientsCount, kms.NISTP256ECDHKW)
}

func createRecipientsByKeyType(t *testing.T, k *localkms.LocalKMS, recipientsCount int,
Expand All @@ -291,7 +327,7 @@ func createRecipientsByKeyType(t *testing.T, k *localkms.LocalKMS, recipientsCou
// createAndMarshalKey creates a new recipient keyset.Handle, extracts public key, marshals it and returns
// both marshalled public key and original recipient keyset.Handle.
func createAndMarshalKey(t *testing.T, k *localkms.LocalKMS) (string, []byte, *keyset.Handle) {
return createAndMarshalKeyByKeyType(t, k, kms.ECDH256KWAES256GCMType)
return createAndMarshalKeyByKeyType(t, k, kms.NISTP256ECDHKWType)
}

func createAndMarshalKeyByKeyType(t *testing.T, k *localkms.LocalKMS, kt kms.KeyType) (string, []byte, *keyset.Handle) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/doc/jose/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ const (
// A256GCMALG is the default content encryption algorithm value as per
// the JWA specification: https://tools.ietf.org/html/rfc7518#section-5.1
A256GCMALG = "A256GCM"
// XC20PALG represented XChacha20Poly1305 content encryption algorithm value.
XC20PALG = "XC20P"
// DIDCommEncType representing the JWE 'Typ' protected type header.
DIDCommEncType = "didcomm-envelope-enc"
)
Expand Down
Loading