ecdsa.go raw

   1  package jwt
   2  
   3  import (
   4  	"crypto"
   5  	"crypto/ecdsa"
   6  	"crypto/rand"
   7  	"errors"
   8  	"math/big"
   9  )
  10  
  11  var (
  12  	// Sadly this is missing from crypto/ecdsa compared to crypto/rsa
  13  	ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
  14  )
  15  
  16  // SigningMethodECDSA implements the ECDSA family of signing methods.
  17  // Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
  18  type SigningMethodECDSA struct {
  19  	Name      string
  20  	Hash      crypto.Hash
  21  	KeySize   int
  22  	CurveBits int
  23  }
  24  
  25  // Specific instances for EC256 and company
  26  var (
  27  	SigningMethodES256 *SigningMethodECDSA
  28  	SigningMethodES384 *SigningMethodECDSA
  29  	SigningMethodES512 *SigningMethodECDSA
  30  )
  31  
  32  func init() {
  33  	// ES256
  34  	SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
  35  	RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
  36  		return SigningMethodES256
  37  	})
  38  
  39  	// ES384
  40  	SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
  41  	RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
  42  		return SigningMethodES384
  43  	})
  44  
  45  	// ES512
  46  	SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
  47  	RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
  48  		return SigningMethodES512
  49  	})
  50  }
  51  
  52  func (m *SigningMethodECDSA) Alg() string {
  53  	return m.Name
  54  }
  55  
  56  // Verify implements token verification for the SigningMethod.
  57  // For this verify method, key must be an ecdsa.PublicKey struct
  58  func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
  59  	var err error
  60  
  61  	// Decode the signature
  62  	var sig []byte
  63  	if sig, err = DecodeSegment(signature); err != nil {
  64  		return err
  65  	}
  66  
  67  	// Get the key
  68  	var ecdsaKey *ecdsa.PublicKey
  69  	switch k := key.(type) {
  70  	case *ecdsa.PublicKey:
  71  		ecdsaKey = k
  72  	default:
  73  		return ErrInvalidKeyType
  74  	}
  75  
  76  	if len(sig) != 2*m.KeySize {
  77  		return ErrECDSAVerification
  78  	}
  79  
  80  	r := big.NewInt(0).SetBytes(sig[:m.KeySize])
  81  	s := big.NewInt(0).SetBytes(sig[m.KeySize:])
  82  
  83  	// Create hasher
  84  	if !m.Hash.Available() {
  85  		return ErrHashUnavailable
  86  	}
  87  	hasher := m.Hash.New()
  88  	hasher.Write([]byte(signingString))
  89  
  90  	// Verify the signature
  91  	if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus {
  92  		return nil
  93  	}
  94  
  95  	return ErrECDSAVerification
  96  }
  97  
  98  // Sign implements token signing for the SigningMethod.
  99  // For this signing method, key must be an ecdsa.PrivateKey struct
 100  func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
 101  	// Get the key
 102  	var ecdsaKey *ecdsa.PrivateKey
 103  	switch k := key.(type) {
 104  	case *ecdsa.PrivateKey:
 105  		ecdsaKey = k
 106  	default:
 107  		return "", ErrInvalidKeyType
 108  	}
 109  
 110  	// Create the hasher
 111  	if !m.Hash.Available() {
 112  		return "", ErrHashUnavailable
 113  	}
 114  
 115  	hasher := m.Hash.New()
 116  	hasher.Write([]byte(signingString))
 117  
 118  	// Sign the string and return r, s
 119  	if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
 120  		curveBits := ecdsaKey.Curve.Params().BitSize
 121  
 122  		if m.CurveBits != curveBits {
 123  			return "", ErrInvalidKey
 124  		}
 125  
 126  		keyBytes := curveBits / 8
 127  		if curveBits%8 > 0 {
 128  			keyBytes += 1
 129  		}
 130  
 131  		// We serialize the outputs (r and s) into big-endian byte arrays
 132  		// padded with zeros on the left to make sure the sizes work out.
 133  		// Output must be 2*keyBytes long.
 134  		out := make([]byte, 2*keyBytes)
 135  		r.FillBytes(out[0:keyBytes]) // r is assigned to the first half of output.
 136  		s.FillBytes(out[keyBytes:])  // s is assigned to the second half of output.
 137  
 138  		return EncodeSegment(out), nil
 139  	} else {
 140  		return "", err
 141  	}
 142  }
 143