open-vault/vendor/github.com/briankassouf/jose/crypto/ecdsa.go

139 lines
3.3 KiB
Go
Raw Normal View History

2018-06-20 03:03:22 +00:00
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
}
var keySize int
switch m.Name {
case "ES256":
keySize = 32
case "ES384":
keySize = 48
case "ES512":
keySize = 66
}
if len(signature) == 2*keySize {
r := big.NewInt(0).SetBytes(signature[:keySize])
s := big.NewInt(0).SetBytes(signature[keySize:])
// If verification succeeds return
if ecdsa.Verify(ecdsaKey, m.sum(raw), r, s) {
return nil
}
}
// Fall back to the old method
// 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)