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 }