| 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) |