1// Copyright 2018 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14// 15//////////////////////////////////////////////////////////////////////////////// 16 17package signature 18 19import ( 20 "crypto/ecdsa" 21 "crypto/rand" 22 "errors" 23 "fmt" 24 25 "google.golang.org/protobuf/proto" 26 "github.com/google/tink/go/keyset" 27 subtleSignature "github.com/google/tink/go/signature/subtle" 28 "github.com/google/tink/go/subtle" 29 commonpb "github.com/google/tink/go/proto/common_go_proto" 30 ecdsapb "github.com/google/tink/go/proto/ecdsa_go_proto" 31 tinkpb "github.com/google/tink/go/proto/tink_go_proto" 32) 33 34const ( 35 ecdsaSignerKeyVersion = 0 36 ecdsaSignerTypeURL = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey" 37) 38 39// common errors 40var errInvalidECDSASignKey = errors.New("ecdsa_signer_key_manager: invalid key") 41var errInvalidECDSASignKeyFormat = errors.New("ecdsa_signer_key_manager: invalid key format") 42 43// ecdsaSignerKeyManager is an implementation of KeyManager interface. 44// It generates new ECDSAPrivateKeys and produces new instances of ECDSASign subtle. 45type ecdsaSignerKeyManager struct{} 46 47// Primitive creates an ECDSASign subtle for the given serialized ECDSAPrivateKey proto. 48func (km *ecdsaSignerKeyManager) Primitive(serializedKey []byte) (interface{}, error) { 49 if len(serializedKey) == 0 { 50 return nil, errInvalidECDSASignKey 51 } 52 key := new(ecdsapb.EcdsaPrivateKey) 53 if err := proto.Unmarshal(serializedKey, key); err != nil { 54 return nil, errInvalidECDSASignKey 55 } 56 if err := km.validateKey(key); err != nil { 57 return nil, err 58 } 59 hash, curve, encoding := getECDSAParamNames(key.PublicKey.Params) 60 ret, err := subtleSignature.NewECDSASigner(hash, curve, encoding, key.KeyValue) 61 if err != nil { 62 return nil, fmt.Errorf("ecdsa_signer_key_manager: %s", err) 63 } 64 return ret, nil 65} 66 67// NewKey creates a new ECDSAPrivateKey according to specification the given serialized ECDSAKeyFormat. 68func (km *ecdsaSignerKeyManager) NewKey(serializedKeyFormat []byte) (proto.Message, error) { 69 if len(serializedKeyFormat) == 0 { 70 return nil, errInvalidECDSASignKeyFormat 71 } 72 keyFormat := new(ecdsapb.EcdsaKeyFormat) 73 if err := proto.Unmarshal(serializedKeyFormat, keyFormat); err != nil { 74 return nil, fmt.Errorf("ecdsa_signer_key_manager: invalid proto: %s", err) 75 } 76 if err := km.validateKeyFormat(keyFormat); err != nil { 77 return nil, fmt.Errorf("ecdsa_signer_key_manager: invalid key format: %s", err) 78 } 79 // generate key 80 params := keyFormat.Params 81 curve := commonpb.EllipticCurveType_name[int32(params.Curve)] 82 tmpKey, err := ecdsa.GenerateKey(subtle.GetCurve(curve), rand.Reader) 83 if err != nil { 84 return nil, fmt.Errorf("ecdsa_signer_key_manager: cannot generate ECDSA key: %s", err) 85 } 86 87 keyValue := tmpKey.D.Bytes() 88 pub := newECDSAPublicKey(ecdsaSignerKeyVersion, params, tmpKey.X.Bytes(), tmpKey.Y.Bytes()) 89 priv := newECDSAPrivateKey(ecdsaSignerKeyVersion, pub, keyValue) 90 return priv, nil 91} 92 93// NewKeyData creates a new KeyData according to specification in the given 94// serialized ECDSAKeyFormat. It should be used solely by the key management API. 95func (km *ecdsaSignerKeyManager) NewKeyData(serializedKeyFormat []byte) (*tinkpb.KeyData, error) { 96 key, err := km.NewKey(serializedKeyFormat) 97 if err != nil { 98 return nil, err 99 } 100 serializedKey, err := proto.Marshal(key) 101 if err != nil { 102 return nil, errInvalidECDSASignKeyFormat 103 } 104 return &tinkpb.KeyData{ 105 TypeUrl: ecdsaSignerTypeURL, 106 Value: serializedKey, 107 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PRIVATE, 108 }, nil 109} 110 111// PublicKeyData extracts the public key data from the private key. 112func (km *ecdsaSignerKeyManager) PublicKeyData(serializedPrivKey []byte) (*tinkpb.KeyData, error) { 113 privKey := new(ecdsapb.EcdsaPrivateKey) 114 if err := proto.Unmarshal(serializedPrivKey, privKey); err != nil { 115 return nil, errInvalidECDSASignKey 116 } 117 serializedPubKey, err := proto.Marshal(privKey.PublicKey) 118 if err != nil { 119 return nil, errInvalidECDSASignKey 120 } 121 return &tinkpb.KeyData{ 122 TypeUrl: ecdsaVerifierTypeURL, 123 Value: serializedPubKey, 124 KeyMaterialType: tinkpb.KeyData_ASYMMETRIC_PUBLIC, 125 }, nil 126} 127 128// DoesSupport indicates if this key manager supports the given key type. 129func (km *ecdsaSignerKeyManager) DoesSupport(typeURL string) bool { 130 return typeURL == ecdsaSignerTypeURL 131} 132 133// TypeURL returns the key type of keys managed by this key manager. 134func (km *ecdsaSignerKeyManager) TypeURL() string { 135 return ecdsaSignerTypeURL 136} 137 138// validateKey validates the given ECDSAPrivateKey. 139func (km *ecdsaSignerKeyManager) validateKey(key *ecdsapb.EcdsaPrivateKey) error { 140 if err := keyset.ValidateKeyVersion(key.Version, ecdsaSignerKeyVersion); err != nil { 141 return fmt.Errorf("ecdsa_signer_key_manager: invalid key: %s", err) 142 } 143 hash, curve, encoding := getECDSAParamNames(key.PublicKey.Params) 144 return subtleSignature.ValidateECDSAParams(hash, curve, encoding) 145} 146 147// validateKeyFormat validates the given ECDSAKeyFormat. 148func (km *ecdsaSignerKeyManager) validateKeyFormat(format *ecdsapb.EcdsaKeyFormat) error { 149 hash, curve, encoding := getECDSAParamNames(format.Params) 150 return subtleSignature.ValidateECDSAParams(hash, curve, encoding) 151} 152