gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

ecdsa.go (3493B)


      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 // Implements the ECDSA family of signing methods 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 // Implements the Verify method from 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 // Implements the Sign method from 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 }