github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/appengine/login/googlesignin/jwt-go/ecdsa.go (about) 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 type SigningMethodECDSA struct { 18 Name string 19 Hash crypto.Hash 20 KeySize int 21 CurveBits int 22 } 23 24 // Specific instances for EC256 and company 25 var ( 26 SigningMethodES256 *SigningMethodECDSA 27 SigningMethodES384 *SigningMethodECDSA 28 SigningMethodES512 *SigningMethodECDSA 29 ) 30 31 func init() { 32 // ES256 33 SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256} 34 RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod { 35 return SigningMethodES256 36 }) 37 38 // ES384 39 SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384} 40 RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod { 41 return SigningMethodES384 42 }) 43 44 // ES512 45 SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521} 46 RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod { 47 return SigningMethodES512 48 }) 49 } 50 51 func (m *SigningMethodECDSA) Alg() string { 52 return m.Name 53 } 54 55 // Implements the Verify method from SigningMethod 56 // For this verify method, key must be an ecdsa.PublicKey struct 57 func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error { 58 var err error 59 60 // Decode the signature 61 var sig []byte 62 if sig, err = DecodeSegment(signature); err != nil { 63 return err 64 } 65 66 // Get the key 67 var ecdsaKey *ecdsa.PublicKey 68 switch k := key.(type) { 69 case *ecdsa.PublicKey: 70 ecdsaKey = k 71 default: 72 return ErrInvalidKey 73 } 74 75 if len(sig) != 2*m.KeySize { 76 return ErrECDSAVerification 77 } 78 79 r := big.NewInt(0).SetBytes(sig[:m.KeySize]) 80 s := big.NewInt(0).SetBytes(sig[m.KeySize:]) 81 82 // Create hasher 83 if !m.Hash.Available() { 84 return ErrHashUnavailable 85 } 86 hasher := m.Hash.New() 87 hasher.Write([]byte(signingString)) 88 89 // Verify the signature 90 if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true { 91 return nil 92 } else { 93 return ErrECDSAVerification 94 } 95 } 96 97 // Implements the Sign method from SigningMethod 98 // For this signing method, key must be an ecdsa.PrivateKey struct 99 func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) { 100 // Get the key 101 var ecdsaKey *ecdsa.PrivateKey 102 switch k := key.(type) { 103 case *ecdsa.PrivateKey: 104 ecdsaKey = k 105 default: 106 return "", ErrInvalidKey 107 } 108 109 // Create the hasher 110 if !m.Hash.Available() { 111 return "", ErrHashUnavailable 112 } 113 114 hasher := m.Hash.New() 115 hasher.Write([]byte(signingString)) 116 117 // Sign the string and return r, s 118 if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil { 119 curveBits := ecdsaKey.Curve.Params().BitSize 120 121 if m.CurveBits != curveBits { 122 return "", ErrInvalidKey 123 } 124 125 keyBytes := curveBits / 8 126 if curveBits%8 > 0 { 127 keyBytes += 1 128 } 129 130 // We serialize the outpus (r and s) into big-endian byte arrays and pad 131 // them with zeros on the left to make sure the sizes work out. Both arrays 132 // must be keyBytes long, and the output must be 2*keyBytes long. 133 rBytes := r.Bytes() 134 rBytesPadded := make([]byte, keyBytes) 135 copy(rBytesPadded[keyBytes-len(rBytes):], rBytes) 136 137 sBytes := s.Bytes() 138 sBytesPadded := make([]byte, keyBytes) 139 copy(sBytesPadded[keyBytes-len(sBytes):], sBytes) 140 141 out := append(rBytesPadded, sBytesPadded...) 142 143 return EncodeSegment(out), nil 144 } else { 145 return "", err 146 } 147 }