|  | package crypto | 
|  |  | 
|  | import ( | 
|  | "crypto" | 
|  | "crypto/ecdsa" | 
|  | "crypto/rand" | 
|  | "encoding/asn1" | 
|  | "encoding/json" | 
|  | "errors" | 
|  | "math/big" | 
|  | ) | 
|  |  | 
|  | // ErrECDSAVerification is missing from crypto/ecdsa compared to crypto/rsa | 
|  | var ErrECDSAVerification = errors.New("crypto/ecdsa: verification error") | 
|  |  | 
|  | // SigningMethodECDSA implements the ECDSA family of signing methods signing | 
|  | // methods | 
|  | type SigningMethodECDSA struct { | 
|  | Name string | 
|  | Hash crypto.Hash | 
|  | _    struct{} | 
|  | } | 
|  |  | 
|  | // ECPoint is a marshalling structure for the EC points R and S. | 
|  | type ECPoint struct { | 
|  | R *big.Int | 
|  | S *big.Int | 
|  | } | 
|  |  | 
|  | // Specific instances of EC SigningMethods. | 
|  | var ( | 
|  | // SigningMethodES256 implements ES256. | 
|  | SigningMethodES256 = &SigningMethodECDSA{ | 
|  | Name: "ES256", | 
|  | Hash: crypto.SHA256, | 
|  | } | 
|  |  | 
|  | // SigningMethodES384 implements ES384. | 
|  | SigningMethodES384 = &SigningMethodECDSA{ | 
|  | Name: "ES384", | 
|  | Hash: crypto.SHA384, | 
|  | } | 
|  |  | 
|  | // SigningMethodES512 implements ES512. | 
|  | SigningMethodES512 = &SigningMethodECDSA{ | 
|  | Name: "ES512", | 
|  | Hash: crypto.SHA512, | 
|  | } | 
|  | ) | 
|  |  | 
|  | // Alg returns the name of the SigningMethodECDSA instance. | 
|  | func (m *SigningMethodECDSA) Alg() string { return m.Name } | 
|  |  | 
|  | // Verify implements the Verify method from SigningMethod. | 
|  | // For this verify method, key must be an *ecdsa.PublicKey. | 
|  | func (m *SigningMethodECDSA) Verify(raw []byte, signature Signature, key interface{}) error { | 
|  |  | 
|  | ecdsaKey, ok := key.(*ecdsa.PublicKey) | 
|  | if !ok { | 
|  | return ErrInvalidKey | 
|  | } | 
|  |  | 
|  | // Unmarshal asn1 ECPoint | 
|  | var ecpoint ECPoint | 
|  | if _, err := asn1.Unmarshal(signature, &ecpoint); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Verify the signature | 
|  | if !ecdsa.Verify(ecdsaKey, m.sum(raw), ecpoint.R, ecpoint.S) { | 
|  | return ErrECDSAVerification | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // Sign implements the Sign method from SigningMethod. | 
|  | // For this signing method, key must be an *ecdsa.PrivateKey. | 
|  | func (m *SigningMethodECDSA) Sign(data []byte, key interface{}) (Signature, error) { | 
|  |  | 
|  | ecdsaKey, ok := key.(*ecdsa.PrivateKey) | 
|  | if !ok { | 
|  | return nil, ErrInvalidKey | 
|  | } | 
|  |  | 
|  | r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, m.sum(data)) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | signature, err := asn1.Marshal(ECPoint{R: r, S: s}) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  | return Signature(signature), nil | 
|  | } | 
|  |  | 
|  | func (m *SigningMethodECDSA) sum(b []byte) []byte { | 
|  | h := m.Hash.New() | 
|  | h.Write(b) | 
|  | return h.Sum(nil) | 
|  | } | 
|  |  | 
|  | // Hasher implements the Hasher method from SigningMethod. | 
|  | func (m *SigningMethodECDSA) Hasher() crypto.Hash { | 
|  | return m.Hash | 
|  | } | 
|  |  | 
|  | // MarshalJSON is in case somebody decides to place SigningMethodECDSA | 
|  | // inside the Header, presumably because they (wrongly) decided it was a good | 
|  | // idea to use the SigningMethod itself instead of the SigningMethod's Alg | 
|  | // method. In order to keep things sane, marshalling this will simply | 
|  | // return the JSON-compatible representation of m.Alg(). | 
|  | func (m *SigningMethodECDSA) MarshalJSON() ([]byte, error) { | 
|  | return []byte(`"` + m.Alg() + `"`), nil | 
|  | } | 
|  |  | 
|  | var _ json.Marshaler = (*SigningMethodECDSA)(nil) |