github.com/trustbloc/kms-go@v1.1.2/crypto/tinkcrypto/primitive/secp256k1/secp256k1_signer_key_manager_test.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package secp256k1_test 8 9 import ( 10 "crypto/ecdsa" 11 "crypto/rand" 12 "fmt" 13 "math/big" 14 "testing" 15 16 "github.com/google/tink/go/core/registry" 17 commonpb "github.com/google/tink/go/proto/common_go_proto" 18 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 19 "github.com/google/tink/go/subtle/random" 20 "github.com/stretchr/testify/require" 21 "google.golang.org/protobuf/proto" 22 23 secp256k1pb "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/proto/secp256k1_go_proto" 24 "github.com/trustbloc/kms-go/crypto/tinkcrypto/primitive/secp256k1/subtle" 25 ) 26 27 const ( 28 secp256k1SignerKeyVersion = uint32(0) 29 secp256k1SignerTypeURL = "type.googleapis.com/google.crypto.tink.secp256k1PrivateKey" 30 ) 31 32 type secp256k1Params struct { 33 hashType commonpb.HashType 34 curve secp256k1pb.BitcoinCurveType 35 } 36 37 func TestSecp256k1SignerGetPrimitiveBasic(t *testing.T) { 38 testParams := genValidSecp256k1Params() 39 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 40 require.NoError(t, err) 41 42 for i := 0; i < len(testParams); i++ { 43 serializedKey, e := proto.Marshal(NewRandomSecp256K1PrivateKey(testParams[i].hashType, testParams[i].curve)) 44 require.NoError(t, e) 45 46 _, err = km.Primitive(serializedKey) 47 require.NoErrorf(t, err, "unexpect error in test case %d ", i) 48 } 49 } 50 51 func TestECDSASecp256K1SignGetPrimitiveWithInvalidInput(t *testing.T) { 52 // invalid params 53 testParams := genInvalidSecp256k1Params() 54 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 55 require.NoError(t, err) 56 57 for i := 0; i < len(testParams); i++ { 58 serializedKey, e := proto.Marshal(NewRandomSecp256K1PrivateKey(testParams[i].hashType, testParams[i].curve)) 59 if testParams[i].curve != secp256k1pb.BitcoinCurveType_INVALID_BITCOIN_CURVE { 60 require.NoError(t, e) 61 } 62 63 _, err = km.Primitive(serializedKey) 64 require.Errorf(t, err, "expect an error in test case %d", i) 65 } 66 67 // invalid version 68 key := NewRandomSecp256K1PrivateKey(commonpb.HashType_SHA256, 69 secp256k1pb.BitcoinCurveType_SECP256K1) 70 key.Version = secp256k1SignerKeyVersion + 1 71 serializedKey, e := proto.Marshal(key) 72 require.NoError(t, e) 73 74 _, err = km.Primitive(serializedKey) 75 require.Error(t, err, "expect an error when version is invalid") 76 77 // nil input 78 _, err = km.Primitive(nil) 79 require.Error(t, err, "expect an error when input is nil") 80 81 _, err = km.Primitive([]byte{}) 82 require.Error(t, err, "expect an error when input is empty slice") 83 } 84 85 func TestECDSASecp256K1SignNewKeyBasic(t *testing.T) { 86 testParams := genValidSecp256k1Params() 87 88 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 89 require.NoError(t, err) 90 91 for i := 0; i < len(testParams); i++ { 92 params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve, 93 secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER) 94 95 serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params)) 96 require.NoError(t, e) 97 98 tmp, e := km.NewKey(serializedFormat) 99 require.NoError(t, e) 100 101 key, ok := tmp.(*secp256k1pb.Secp256K1PrivateKey) 102 require.True(t, ok) 103 104 err = validateECDSASecp256K1PrivateKey(t, key, params) 105 require.NoErrorf(t, err, "invalid private key in test case %d", i) 106 } 107 } 108 109 func TestECDSASecp256K1SignNewKeyWithInvalidInput(t *testing.T) { 110 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 111 require.NoError(t, err) 112 113 // invalid hash and curve type 114 testParams := genInvalidSecp256k1Params() 115 for i := 0; i < len(testParams); i++ { 116 params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve, 117 secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER) 118 119 serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params)) 120 require.NoError(t, e) 121 122 _, err = km.NewKey(serializedFormat) 123 require.Errorf(t, err, "expect an error in test case %d", i) 124 } 125 126 // invalid encoding 127 testParams = genValidSecp256k1Params() 128 for i := 0; i < len(testParams); i++ { 129 params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve, 130 secp256k1pb.Secp256K1SignatureEncoding_UNKNOWN_BITCOIN_ENCODING) 131 132 serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params)) 133 require.NoError(t, e) 134 135 _, err = km.NewKey(serializedFormat) 136 require.Errorf(t, err, "expect an error in test case %d", i) 137 } 138 139 // nil input 140 _, err = km.NewKey(nil) 141 require.Error(t, err, "expect an error when input is nil") 142 143 _, err = km.NewKey([]byte{}) 144 require.Error(t, err, "expect an error when input is empty slice") 145 } 146 147 func TestECDSASecp256K1SignNewKeyMultipleTimes(t *testing.T) { 148 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 149 require.NoError(t, err) 150 151 testParams := genValidSecp256k1Params() 152 153 nTest := 27 154 155 for i := 0; i < len(testParams); i++ { 156 keys := make(map[string]bool) 157 params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve, 158 secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER) 159 format := newSecp256K1KeyFormat(params) 160 161 serializedFormat, e := proto.Marshal(format) 162 require.NoError(t, e) 163 164 for j := 0; j < nTest; j++ { 165 key, e := km.NewKey(serializedFormat) 166 require.NoError(t, e) 167 168 serializedKey, e := proto.Marshal(key) 169 require.NoError(t, e) 170 171 keys[string(serializedKey)] = true 172 173 keyData, e := km.NewKeyData(serializedFormat) 174 require.NoError(t, e) 175 176 serializedKey = keyData.Value 177 keys[string(serializedKey)] = true 178 } 179 180 require.Equalf(t, len(keys), nTest*2, "key is repeated with params: %s", params) 181 } 182 } 183 184 func TestECDSASecp256K1SignNewKeyDataBasic(t *testing.T) { 185 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 186 require.NoError(t, err) 187 188 testParams := genValidSecp256k1Params() 189 for i := 0; i < len(testParams); i++ { 190 params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve, 191 secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER) 192 serializedFormat, e := proto.Marshal(newSecp256K1KeyFormat(params)) 193 require.NoError(t, e) 194 195 keyData, e := km.NewKeyData(serializedFormat) 196 require.NoErrorf(t, e, "unexpected error in test case %d", i) 197 198 require.Equalf(t, keyData.TypeUrl, secp256k1SignerTypeURL, 199 "incorrect type url in test case %d: expect %s, got %s", 200 i, secp256k1SignerTypeURL, keyData.TypeUrl) 201 202 require.Equalf(t, keyData.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PRIVATE, 203 "incorrect key material type in test case %d: expect %s, got %s", 204 i, tinkpb.KeyData_ASYMMETRIC_PRIVATE, keyData.KeyMaterialType) 205 206 key := new(secp256k1pb.Secp256K1PrivateKey) 207 err = proto.Unmarshal(keyData.Value, key) 208 require.NoErrorf(t, err, "unexpect error in test case %d", i) 209 210 err = validateECDSASecp256K1PrivateKey(t, key, params) 211 require.NoErrorf(t, err, "invalid private key in test case %d", i) 212 } 213 } 214 215 func TestECDSASecp256K1SignNewKeyDataWithInvalidInput(t *testing.T) { 216 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 217 require.NoError(t, err) 218 219 testParams := genInvalidSecp256k1Params() 220 for i := 0; i < len(testParams); i++ { 221 params := NewSecp256K1Params(testParams[i].hashType, testParams[i].curve, 222 secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER) 223 format := newSecp256K1KeyFormat(params) 224 225 serializedFormat, e := proto.Marshal(format) 226 require.NoError(t, e) 227 228 _, err = km.NewKeyData(serializedFormat) 229 require.Errorf(t, err, "expect an error in test case %d", i) 230 } 231 232 // nil input 233 _, err = km.NewKeyData(nil) 234 require.Errorf(t, err, "expect an error when input is nil") 235 } 236 237 func TestPublicKeyDataBasic(t *testing.T) { 238 testParams := genValidSecp256k1Params() 239 240 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 241 require.NoError(t, err) 242 243 pkm, ok := km.(registry.PrivateKeyManager) 244 require.True(t, ok, "cannot obtain private key manager") 245 246 for i := 0; i < len(testParams); i++ { 247 key := NewRandomSecp256K1PrivateKey(testParams[i].hashType, testParams[i].curve) 248 serializedKey, e := proto.Marshal(key) 249 require.NoError(t, e) 250 251 pubKeyData, e := pkm.PublicKeyData(serializedKey) 252 require.NoErrorf(t, e, "unexpect error in test case %d", i) 253 254 require.Equalf(t, pubKeyData.TypeUrl, secp256k1VerifierTypeURL, "incorrect type url: %s", pubKeyData.TypeUrl) 255 256 require.Equalf(t, pubKeyData.KeyMaterialType, tinkpb.KeyData_ASYMMETRIC_PUBLIC, 257 "incorrect key material type: %d", pubKeyData.KeyMaterialType) 258 259 pubKey := new(secp256k1pb.Secp256K1PublicKey) 260 err = proto.Unmarshal(pubKeyData.Value, pubKey) 261 require.NoError(t, err) 262 } 263 } 264 265 func TestPublicKeyDataWithInvalidInput(t *testing.T) { 266 km, err := registry.GetKeyManager(secp256k1SignerTypeURL) 267 require.NoError(t, err) 268 269 pkm, ok := km.(registry.PrivateKeyManager) 270 require.True(t, ok, "cannot obtain private key manager") 271 272 // modified key 273 key := NewRandomSecp256K1PrivateKey(commonpb.HashType_SHA256, secp256k1pb.BitcoinCurveType_SECP256K1) 274 serializedKey, err := proto.Marshal(key) 275 require.NoError(t, err) 276 277 serializedKey[0] = 0 278 279 _, err = pkm.PublicKeyData(serializedKey) 280 require.Error(t, err, "expect an error when input is a modified serialized key") 281 } 282 283 var errSmallKey = fmt.Errorf("private key doesn't have adequate size") 284 285 func validateECDSASecp256K1PrivateKey(t *testing.T, key *secp256k1pb.Secp256K1PrivateKey, 286 params *secp256k1pb.Secp256K1Params) error { 287 require.Equalf(t, key.Version, secp256k1SignerKeyVersion, "incorrect private key's version: expect %d, got %d", 288 secp256k1SignerKeyVersion, key.Version) 289 290 publicKey := key.PublicKey 291 require.Equalf(t, publicKey.Version, secp256k1SignerKeyVersion, "incorrect public key's version: expect %d, got %d", 292 secp256k1SignerKeyVersion, key.Version) 293 294 if params.HashType != publicKey.Params.HashType || 295 params.Curve != publicKey.Params.Curve || 296 params.Encoding != publicKey.Params.Encoding { 297 return fmt.Errorf("incorrect params: expect %s, got %s", params, publicKey.Params) 298 } 299 300 if len(publicKey.X) == 0 || len(publicKey.Y) == 0 { 301 return fmt.Errorf("public points are not initialized") 302 } 303 304 // check private key's size 305 d := new(big.Int).SetBytes(key.KeyValue) 306 keySize := len(d.Bytes()) 307 308 if params.Curve == secp256k1pb.BitcoinCurveType_SECP256K1 { 309 if keySize < 256/8-8 || keySize > 256/8+1 { 310 return errSmallKey 311 } 312 } 313 314 // try to sign and verify with the key 315 hash, curve, encoding := getSecp256K1ParamNames(publicKey.Params) 316 signer, err := subtle.NewSecp256K1Signer(hash, curve, encoding, key.KeyValue) 317 require.NoError(t, err, "unexpected error when creating Secp256K1Sign") 318 319 verifier, err := subtle.NewSecp256K1Verifier(hash, curve, encoding, publicKey.X, publicKey.Y) 320 require.NoError(t, err, "unexpected error when creating Secp256K1Verify") 321 322 data := random.GetRandomBytes(1281) 323 324 signature, err := signer.Sign(data) 325 require.NoError(t, err, "unexpected error when signing") 326 327 err = verifier.Verify(signature, data) 328 require.NoError(t, err, "unexpected error when verifying signature") 329 330 return nil 331 } 332 333 func genValidSecp256k1Params() []secp256k1Params { 334 return []secp256k1Params{ 335 { 336 hashType: commonpb.HashType_SHA256, 337 curve: secp256k1pb.BitcoinCurveType_SECP256K1, 338 }, 339 } 340 } 341 342 func genInvalidSecp256k1Params() []secp256k1Params { 343 return []secp256k1Params{ 344 { 345 hashType: commonpb.HashType_SHA1, 346 curve: secp256k1pb.BitcoinCurveType_SECP256K1, 347 }, 348 { 349 hashType: commonpb.HashType_SHA1, 350 curve: secp256k1pb.BitcoinCurveType_INVALID_BITCOIN_CURVE, 351 }, 352 } 353 } 354 355 // NewRandomSecp256K1PrivateKey creates an ECDSAPrivateKey with randomly generated key material. 356 func NewRandomSecp256K1PrivateKey(hashType commonpb.HashType, 357 curve secp256k1pb.BitcoinCurveType) *secp256k1pb.Secp256K1PrivateKey { 358 curveName := secp256k1pb.BitcoinCurveType_name[int32(curve)] 359 if curveName == secp256k1pb.BitcoinCurveType_INVALID_BITCOIN_CURVE.String() { 360 return nil 361 } 362 363 priv, e := ecdsa.GenerateKey(subtle.GetCurve(curveName), rand.Reader) 364 if e != nil { 365 return nil 366 } 367 368 params := NewSecp256K1Params(hashType, curve, secp256k1pb.Secp256K1SignatureEncoding_Bitcoin_DER) 369 publicKey := newSecp256K1PublicKey(secp256k1SignerKeyVersion, params, priv.X.Bytes(), priv.Y.Bytes()) 370 371 return newSecp256K1APrivateKey(secp256k1SignerKeyVersion, publicKey, priv.D.Bytes()) 372 } 373 374 // NewSecp256K1Params creates a ECDSAParams with the specified parameters. 375 func NewSecp256K1Params(hashType commonpb.HashType, 376 curve secp256k1pb.BitcoinCurveType, 377 encoding secp256k1pb.Secp256K1SignatureEncoding) *secp256k1pb.Secp256K1Params { 378 return &secp256k1pb.Secp256K1Params{ 379 HashType: hashType, 380 Curve: curve, 381 Encoding: encoding, 382 } 383 } 384 385 // newSecp256K1KeyFormat creates a ECDSAKeyFormat with the specified parameters. 386 func newSecp256K1KeyFormat(params *secp256k1pb.Secp256K1Params) *secp256k1pb.Secp256K1KeyFormat { 387 return &secp256k1pb.Secp256K1KeyFormat{Params: params} 388 } 389 390 // newSecp256K1APrivateKey creates a ECDSAPrivateKey with the specified parameters. 391 func newSecp256K1APrivateKey(version uint32, publicKey *secp256k1pb.Secp256K1PublicKey, 392 keyValue []byte) *secp256k1pb.Secp256K1PrivateKey { 393 return &secp256k1pb.Secp256K1PrivateKey{ 394 Version: version, 395 PublicKey: publicKey, 396 KeyValue: keyValue, 397 } 398 } 399 400 // newSecp256K1PublicKey creates a ECDSAPublicKey with the specified parameters. 401 func newSecp256K1PublicKey(version uint32, params *secp256k1pb.Secp256K1Params, 402 x []byte, y []byte) *secp256k1pb.Secp256K1PublicKey { 403 return &secp256k1pb.Secp256K1PublicKey{ 404 Version: version, 405 Params: params, 406 X: x, 407 Y: y, 408 } 409 } 410 411 // getSecp256K1ParamNames returns the string representations of each parameter in 412 // the given Secp256K1Params. 413 func getSecp256K1ParamNames(params *secp256k1pb.Secp256K1Params) (string, string, string) { 414 hashName := commonpb.HashType_name[int32(params.HashType)] 415 curveName := secp256k1pb.BitcoinCurveType_name[int32(params.Curve)] 416 encodingName := secp256k1pb.Secp256K1SignatureEncoding_name[int32(params.Encoding)] 417 418 return hashName, curveName, encodingName 419 }