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 }