1// Copyright 2020 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 subtle 18 19import ( 20 "crypto/ecdsa" 21 "errors" 22 "fmt" 23 "hash" 24 "math/big" 25 26 "github.com/google/tink/go/subtle" 27) 28 29var errInvalidECDSASignature = errors.New("ecdsa_verifier: invalid signature") 30 31// ECDSAVerifier is an implementation of Verifier for ECDSA. 32// At the moment, the implementation only accepts signatures with strict DER encoding. 33type ECDSAVerifier struct { 34 publicKey *ecdsa.PublicKey 35 hashFunc func() hash.Hash 36 encoding string 37} 38 39// NewECDSAVerifier creates a new instance of ECDSAVerifier. 40func NewECDSAVerifier(hashAlg string, curve string, encoding string, x []byte, y []byte) (*ECDSAVerifier, error) { 41 publicKey := &ecdsa.PublicKey{ 42 Curve: subtle.GetCurve(curve), 43 X: new(big.Int).SetBytes(x), 44 Y: new(big.Int).SetBytes(y), 45 } 46 return NewECDSAVerifierFromPublicKey(hashAlg, encoding, publicKey) 47} 48 49// NewECDSAVerifierFromPublicKey creates a new instance of ECDSAVerifier. 50func NewECDSAVerifierFromPublicKey(hashAlg string, encoding string, publicKey *ecdsa.PublicKey) (*ECDSAVerifier, error) { 51 if publicKey.Curve == nil { 52 return nil, errors.New("ecdsa_verifier: invalid curve") 53 } 54 if !publicKey.Curve.IsOnCurve(publicKey.X, publicKey.Y) { 55 return nil, fmt.Errorf("ecdsa_verifier: invalid public key") 56 } 57 curve := subtle.ConvertCurveName(publicKey.Curve.Params().Name) 58 if err := ValidateECDSAParams(hashAlg, curve, encoding); err != nil { 59 return nil, fmt.Errorf("ecdsa_verifier: %s", err) 60 } 61 hashFunc := subtle.GetHashFunc(hashAlg) 62 return &ECDSAVerifier{ 63 publicKey: publicKey, 64 hashFunc: hashFunc, 65 encoding: encoding, 66 }, nil 67} 68 69// Verify verifies whether the given signature is valid for the given data. 70// It returns an error if the signature is not valid; nil otherwise. 71func (e *ECDSAVerifier) Verify(signatureBytes, data []byte) error { 72 signature, err := DecodeECDSASignature(signatureBytes, e.encoding) 73 if err != nil { 74 return fmt.Errorf("ecdsa_verifier: %s", err) 75 } 76 hashed, err := subtle.ComputeHash(e.hashFunc, data) 77 if err != nil { 78 return err 79 } 80 valid := ecdsa.Verify(e.publicKey, hashed, signature.R, signature.S) 81 if !valid { 82 return errInvalidECDSASignature 83 } 84 return nil 85} 86