github.com/trustbloc/kms-go@v1.1.2/doc/util/jwkkid/kid_creator_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package jwkkid
     8  
     9  import (
    10  	"crypto/ecdsa"
    11  	"crypto/ed25519"
    12  	"crypto/elliptic"
    13  	"crypto/rand"
    14  	"crypto/sha256"
    15  	"crypto/x509"
    16  	"encoding/base64"
    17  	"encoding/json"
    18  	"fmt"
    19  	"strings"
    20  	"testing"
    21  
    22  	"github.com/btcsuite/btcd/btcec/v2"
    23  	"github.com/stretchr/testify/require"
    24  	"github.com/trustbloc/bbs-signature-go/bbs12381g2pub"
    25  
    26  	ecdhpb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/ecdh_aead_go_proto"
    27  	cryptoapi "github.com/trustbloc/kms-go/spi/crypto"
    28  	"github.com/trustbloc/kms-go/spi/kms"
    29  	"github.com/trustbloc/kms-go/util/cryptoutil"
    30  )
    31  
    32  // TODO: clean up these tests
    33  
    34  func Test_CreateKID(t *testing.T) {
    35  	t.Run("ED25519 KID", func(t *testing.T) {
    36  		pubKey, _, err := ed25519.GenerateKey(rand.Reader)
    37  		require.NoError(t, err)
    38  
    39  		kid, err := CreateKID(pubKey, kms.ED25519Type)
    40  		require.NoError(t, err)
    41  		require.NotEmpty(t, kid)
    42  
    43  		t.Run("KID for invalid keys", func(t *testing.T) {
    44  			_, err = CreateKID(pubKey, "badType")
    45  			require.EqualError(t, err, "createKID: failed to build jwk: buildJWK: key type is not supported: 'badType'")
    46  
    47  			badPubKey := ed25519.PublicKey("badKey")
    48  			_, err = CreateKID(badPubKey, kms.NISTP256ECDHKWType)
    49  			require.EqualError(t, err, "createKID: failed to build jwk: invalid character 'b' looking for "+
    50  				"beginning of value")
    51  		})
    52  	})
    53  
    54  	t.Run("X25519ECDH KID", func(t *testing.T) {
    55  		var kid string
    56  
    57  		randomKey := make([]byte, 32)
    58  		_, err := rand.Read(randomKey)
    59  		require.NoError(t, err)
    60  
    61  		x25519Key := &cryptoapi.PublicKey{
    62  			Curve: "X25519",
    63  			Type:  ecdhpb.KeyType_OKP.String(),
    64  			X:     randomKey,
    65  		}
    66  		mX25519Key, err := json.Marshal(x25519Key)
    67  		require.NoError(t, err)
    68  
    69  		kid, err = CreateKID(mX25519Key, kms.X25519ECDHKWType)
    70  		require.NoError(t, err)
    71  		require.NotEmpty(t, kid)
    72  	})
    73  
    74  	t.Run("ECDSA secp256k1 DER format KID", func(t *testing.T) {
    75  		t.Skip("DER format does not support secp256k1 curve")
    76  		var kid string
    77  
    78  		secp256k1Key, err := ecdsa.GenerateKey(btcec.S256(), rand.Reader)
    79  		require.NoError(t, err)
    80  
    81  		pubECKeyBytes := elliptic.Marshal(secp256k1Key.Curve, secp256k1Key.X, secp256k1Key.Y)
    82  		require.NoError(t, err)
    83  
    84  		kid, err = CreateKID(pubECKeyBytes, kms.ECDSASecp256k1DER)
    85  		require.NoError(t, err)
    86  		require.NotEmpty(t, kid)
    87  	})
    88  
    89  	t.Run("ECDSA secp256k1 IEEE-P1363 format KID", func(t *testing.T) {
    90  		var kid string
    91  
    92  		secp256k1Key, err := ecdsa.GenerateKey(btcec.S256(), rand.Reader)
    93  		require.NoError(t, err)
    94  
    95  		pubECKeyBytes := elliptic.Marshal(secp256k1Key.Curve, secp256k1Key.X, secp256k1Key.Y)
    96  		require.NoError(t, err)
    97  
    98  		kid, err = CreateKID(pubECKeyBytes, kms.ECDSASecp256k1IEEEP1363)
    99  		require.NoError(t, err)
   100  		require.NotEmpty(t, kid)
   101  	})
   102  }
   103  
   104  func TestCreateKID(t *testing.T) {
   105  	pubKey, _, err := ed25519.GenerateKey(rand.Reader)
   106  	require.NoError(t, err)
   107  
   108  	kid, err := CreateKID(pubKey, kms.ED25519Type)
   109  	require.NoError(t, err)
   110  	require.NotEmpty(t, kid)
   111  
   112  	correctEdKID := createED25519KID(t, pubKey)
   113  	require.Equal(t, correctEdKID, kid)
   114  
   115  	_, err = CreateKID(nil, kms.ED25519Type)
   116  	require.EqualError(t, err, "createKID: empty key")
   117  
   118  	_, x, y, err := elliptic.GenerateKey(elliptic.P256(), rand.Reader)
   119  	require.NoError(t, err)
   120  
   121  	ecdhKey := &cryptoapi.PublicKey{
   122  		Curve: elliptic.P256().Params().Name,
   123  		X:     x.Bytes(),
   124  		Y:     y.Bytes(),
   125  	}
   126  
   127  	ecdhKeyMarshalled, err := json.Marshal(ecdhKey)
   128  	require.NoError(t, err)
   129  
   130  	kid, err = CreateKID(ecdhKeyMarshalled, kms.NISTP256ECDHKWType)
   131  	require.NoError(t, err)
   132  	require.NotEmpty(t, kid)
   133  
   134  	_, err = CreateKID(pubKey, "badType")
   135  	require.EqualError(t, err, "createKID: failed to build jwk: buildJWK: key type is not supported: 'badType'")
   136  
   137  	badPubKey := ed25519.PublicKey("badKey")
   138  	_, err = CreateKID(badPubKey, kms.NISTP256ECDHKWType)
   139  	require.EqualError(t, err, "createKID: failed to build jwk: invalid character 'b' looking for "+
   140  		"beginning of value")
   141  
   142  	_, err = CreateKID(badPubKey, kms.ECDSAP256TypeDER)
   143  	require.EqualError(t, err,
   144  		"createKID: failed to build jwk: failed to parse ecdsa key in DER format: asn1: structure error: tags don't "+
   145  			"match (16 vs {class:1 tag:2 length:97 isCompound:true}) {optional:false explicit:false application:false "+
   146  			"private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} publicKeyInfo "+
   147  			"@2")
   148  
   149  	_, err = CreateKID(badPubKey, kms.X25519ECDHKWType)
   150  	require.EqualError(t, err, "createKID: createX25519KID: unmarshalECDHKey: failed to unmarshal ECDH key: "+
   151  		"invalid character 'b' looking for beginning of value")
   152  
   153  	_, err = CreateKID(badPubKey, kms.ECDSAP256TypeIEEEP1363)
   154  	require.EqualError(t, err, "createKID: failed to build jwk: create JWK: go-jose/go-jose: "+
   155  		"invalid EC key (nil, or X/Y missing)")
   156  
   157  	ecKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   158  	require.NoError(t, err)
   159  
   160  	ecKeyBytes := elliptic.Marshal(elliptic.P256(), ecKey.X, ecKey.Y)
   161  	_, err = CreateKID(ecKeyBytes, kms.ECDSAP256TypeIEEEP1363)
   162  	require.NoError(t, err)
   163  
   164  	ecKeyBytes, err = x509.MarshalPKIXPublicKey(&ecKey.PublicKey)
   165  	require.NoError(t, err)
   166  
   167  	_, err = CreateKID(ecKeyBytes, kms.ECDSAP256TypeDER)
   168  	require.NoError(t, err)
   169  
   170  	x25519 := make([]byte, cryptoutil.Curve25519KeySize)
   171  	_, err = rand.Read(x25519)
   172  	require.NoError(t, err)
   173  
   174  	ecdhKey = &cryptoapi.PublicKey{
   175  		Curve: "X25519",
   176  		X:     x25519,
   177  	}
   178  
   179  	ecdhKeyMarshalled, err = json.Marshal(ecdhKey)
   180  	require.NoError(t, err)
   181  
   182  	kid, err = CreateKID(ecdhKeyMarshalled, kms.X25519ECDHKWType)
   183  	require.NoError(t, err)
   184  	require.NotEmpty(t, kid)
   185  }
   186  
   187  func TestCreateKIDFromFixedKey(t *testing.T) {
   188  	// use public key from https://tools.ietf.org/html/rfc8037#appendix-A.2
   189  	refPubKeyB64 := "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
   190  	// JWK Thumbprint base64URL from https://tools.ietf.org/html/rfc8037#appendix-A.3
   191  	refKID := "kPrK_qmxVWaYVA9wwBF6Iuo3vVzz7TxHCTwXBygrS4k"
   192  
   193  	pubKeyBytes, err := base64.RawURLEncoding.DecodeString(refPubKeyB64)
   194  	require.NoError(t, err)
   195  
   196  	aPubKey := ed25519.PublicKey(pubKeyBytes)
   197  
   198  	kid, err := CreateKID(aPubKey, kms.ED25519Type)
   199  	require.NoError(t, err)
   200  	require.EqualValues(t, refKID, kid)
   201  }
   202  
   203  func TestCreateX25519KID_Failure(t *testing.T) {
   204  	key := &cryptoapi.PublicKey{
   205  		Curve: "X25519",
   206  		X:     []byte(strings.Repeat("a", cryptoutil.Curve25519KeySize+1)), // public key > X25519 key size
   207  		Y:     []byte{},
   208  		Type:  ecdhpb.KeyType_OKP.String(),
   209  	}
   210  
   211  	mKey, err := json.Marshal(key)
   212  	require.NoError(t, err)
   213  
   214  	_, err = createX25519KID(mKey)
   215  	require.EqualError(t, err, "createX25519KID: buildX25519JWK: invalid ECDH X25519 key")
   216  }
   217  
   218  func TestBuildJWKX25519(t *testing.T) {
   219  	x25519 := make([]byte, cryptoutil.Curve25519KeySize)
   220  	_, err := rand.Read(x25519)
   221  	require.NoError(t, err)
   222  
   223  	ecdhKey := &cryptoapi.PublicKey{
   224  		Curve: "X25519",
   225  		X:     x25519,
   226  	}
   227  
   228  	ecdhKeyMarshalled, err := json.Marshal(ecdhKey)
   229  	require.NoError(t, err)
   230  
   231  	t.Run("success buildJWK for X25519", func(t *testing.T) {
   232  		_, err = BuildJWK(x25519, kms.X25519ECDHKWType)
   233  		require.NoError(t, err)
   234  	})
   235  
   236  	t.Run("buildJWK for X25519 with invalid marshalled key", func(t *testing.T) {
   237  		_, err = BuildJWK([]byte("invalidKey"), kms.X25519ECDHKWType)
   238  		require.EqualError(t, err, "create JWK: marshalX25519: invalid key")
   239  	})
   240  
   241  	t.Run("buildJWK for X25519 with invalid key size properly marshalled", func(t *testing.T) {
   242  		ecdhKey = &cryptoapi.PublicKey{
   243  			Curve: "X25519",
   244  			X:     []byte("badKeyvalue"), // invalid key size
   245  		}
   246  
   247  		ecdhKeyMarshalled, err = json.Marshal(ecdhKey)
   248  		require.NoError(t, err)
   249  
   250  		_, err = BuildJWK(ecdhKeyMarshalled, kms.X25519ECDHKWType)
   251  		require.EqualError(t, err, "create JWK: marshalX25519: invalid key")
   252  	})
   253  }
   254  
   255  func TestBuildJWK_Ed25519(t *testing.T) {
   256  	t.Run("success", func(t *testing.T) {
   257  		pubKey, _, err := ed25519.GenerateKey(rand.Reader)
   258  		require.NoError(t, err)
   259  
   260  		jwk, err := BuildJWK(pubKey, kms.ED25519Type)
   261  		require.NoError(t, err)
   262  		require.NotNil(t, jwk)
   263  	})
   264  }
   265  
   266  // func TestCreateED25519KID_Failure(t *testing.T) {
   267  //	key := &cryptoapi.PublicKey{
   268  //		Curve: "Ed25519",
   269  //		X:     []byte(strings.Repeat("a", ed25519.PublicKeySize+1)), // public key > Ed25519 key size
   270  //		Y:     []byte{},
   271  //		Type:  ecdhpb.KeyType_OKP.String(),
   272  //	}
   273  //
   274  //	mKey, err := json.Marshal(key)
   275  //	require.NoError(t, err)
   276  //
   277  //	_, err = CreateKID(mKey, kms.ED25519Type)
   278  //	require.EqualError(t, err, "createKID: createED25519KID: invalid Ed25519 key")
   279  // }
   280  
   281  func TestCreateBLS12381G2KID(t *testing.T) {
   282  	seed := make([]byte, 32)
   283  
   284  	_, err := rand.Read(seed)
   285  	require.NoError(t, err)
   286  
   287  	pubKey, _, err := bbs12381g2pub.GenerateKeyPair(sha256.New, seed)
   288  	require.NoError(t, err)
   289  
   290  	pubKeyBytes, err := pubKey.Marshal()
   291  	require.NoError(t, err)
   292  
   293  	kid, err := CreateKID(pubKeyBytes, kms.BLS12381G2Type)
   294  	require.NoError(t, err)
   295  	require.NotEmpty(t, kid)
   296  
   297  	_, err = CreateKID(append(pubKeyBytes, []byte("larger key")...), kms.BLS12381G2Type)
   298  	require.EqualError(t, err, "createKID: invalid BBS+ key")
   299  }
   300  
   301  func TestCreateSecp256K1KID(t *testing.T) {
   302  	secp256k1Key, err := ecdsa.GenerateKey(btcec.S256(), rand.Reader)
   303  	require.NoError(t, err)
   304  
   305  	pubKeyBytes := elliptic.Marshal(secp256k1Key.Curve, secp256k1Key.X, secp256k1Key.Y)
   306  
   307  	t.Run("create kid for secp256k1 in DER format", func(t *testing.T) {
   308  		t.Skipf("Secp256k1 keys are not DER compliant")
   309  
   310  		kid, e := CreateKID(pubKeyBytes, kms.ECDSASecp256k1TypeDER)
   311  		require.NoError(t, e)
   312  		require.NotEmpty(t, kid)
   313  	})
   314  
   315  	t.Run("create kid for secp256k1 in IEEE-1363 format", func(t *testing.T) {
   316  		kid2, e := CreateKID(pubKeyBytes, kms.ECDSASecp256k1TypeIEEEP1363)
   317  		require.NoError(t, e)
   318  		require.NotEmpty(t, kid2)
   319  	})
   320  }
   321  
   322  func createED25519KID(t *testing.T, keyBytes []byte) string {
   323  	t.Helper()
   324  
   325  	const ed25519ThumbprintTemplate = `{"crv":"Ed25519","kty":"OKP","x":"%s"}`
   326  
   327  	lenKey := len(keyBytes)
   328  
   329  	require.True(t, lenKey <= ed25519.PublicKeySize, "createED25519KID: invalid Ed25519 key")
   330  
   331  	pad := make([]byte, ed25519.PublicKeySize-lenKey)
   332  	ed25519RawKey := append(pad, keyBytes...)
   333  
   334  	j := fmt.Sprintf(ed25519ThumbprintTemplate, base64.RawURLEncoding.EncodeToString(ed25519RawKey))
   335  
   336  	thumbprint := sha256Sum(j)
   337  
   338  	return base64.RawURLEncoding.EncodeToString(thumbprint)
   339  }