forked from cerc-io/plugeth
c76ad94492
This commit adds a build step to travis to auto-delete unstable archives older than 14 days (our regular release schedule) from Azure via ci.go purge. The commit also pulls in the latest Azure storage code, also switching over from the old import path (github.com/Azure/azure-sdk-for-go) to the new split one (github.com/Azure/azure-storage-go).
148 lines
3.5 KiB
Go
148 lines
3.5 KiB
Go
package jwt
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/ecdsa"
|
|
"crypto/rand"
|
|
"errors"
|
|
"math/big"
|
|
)
|
|
|
|
var (
|
|
// Sadly this is missing from crypto/ecdsa compared to crypto/rsa
|
|
ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
|
|
)
|
|
|
|
// Implements the ECDSA family of signing methods signing methods
|
|
type SigningMethodECDSA struct {
|
|
Name string
|
|
Hash crypto.Hash
|
|
KeySize int
|
|
CurveBits int
|
|
}
|
|
|
|
// Specific instances for EC256 and company
|
|
var (
|
|
SigningMethodES256 *SigningMethodECDSA
|
|
SigningMethodES384 *SigningMethodECDSA
|
|
SigningMethodES512 *SigningMethodECDSA
|
|
)
|
|
|
|
func init() {
|
|
// ES256
|
|
SigningMethodES256 = &SigningMethodECDSA{"ES256", crypto.SHA256, 32, 256}
|
|
RegisterSigningMethod(SigningMethodES256.Alg(), func() SigningMethod {
|
|
return SigningMethodES256
|
|
})
|
|
|
|
// ES384
|
|
SigningMethodES384 = &SigningMethodECDSA{"ES384", crypto.SHA384, 48, 384}
|
|
RegisterSigningMethod(SigningMethodES384.Alg(), func() SigningMethod {
|
|
return SigningMethodES384
|
|
})
|
|
|
|
// ES512
|
|
SigningMethodES512 = &SigningMethodECDSA{"ES512", crypto.SHA512, 66, 521}
|
|
RegisterSigningMethod(SigningMethodES512.Alg(), func() SigningMethod {
|
|
return SigningMethodES512
|
|
})
|
|
}
|
|
|
|
func (m *SigningMethodECDSA) Alg() string {
|
|
return m.Name
|
|
}
|
|
|
|
// Implements the Verify method from SigningMethod
|
|
// For this verify method, key must be an ecdsa.PublicKey struct
|
|
func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
|
|
var err error
|
|
|
|
// Decode the signature
|
|
var sig []byte
|
|
if sig, err = DecodeSegment(signature); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Get the key
|
|
var ecdsaKey *ecdsa.PublicKey
|
|
switch k := key.(type) {
|
|
case *ecdsa.PublicKey:
|
|
ecdsaKey = k
|
|
default:
|
|
return ErrInvalidKeyType
|
|
}
|
|
|
|
if len(sig) != 2*m.KeySize {
|
|
return ErrECDSAVerification
|
|
}
|
|
|
|
r := big.NewInt(0).SetBytes(sig[:m.KeySize])
|
|
s := big.NewInt(0).SetBytes(sig[m.KeySize:])
|
|
|
|
// Create hasher
|
|
if !m.Hash.Available() {
|
|
return ErrHashUnavailable
|
|
}
|
|
hasher := m.Hash.New()
|
|
hasher.Write([]byte(signingString))
|
|
|
|
// Verify the signature
|
|
if verifystatus := ecdsa.Verify(ecdsaKey, hasher.Sum(nil), r, s); verifystatus == true {
|
|
return nil
|
|
} else {
|
|
return ErrECDSAVerification
|
|
}
|
|
}
|
|
|
|
// Implements the Sign method from SigningMethod
|
|
// For this signing method, key must be an ecdsa.PrivateKey struct
|
|
func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
|
|
// Get the key
|
|
var ecdsaKey *ecdsa.PrivateKey
|
|
switch k := key.(type) {
|
|
case *ecdsa.PrivateKey:
|
|
ecdsaKey = k
|
|
default:
|
|
return "", ErrInvalidKeyType
|
|
}
|
|
|
|
// Create the hasher
|
|
if !m.Hash.Available() {
|
|
return "", ErrHashUnavailable
|
|
}
|
|
|
|
hasher := m.Hash.New()
|
|
hasher.Write([]byte(signingString))
|
|
|
|
// Sign the string and return r, s
|
|
if r, s, err := ecdsa.Sign(rand.Reader, ecdsaKey, hasher.Sum(nil)); err == nil {
|
|
curveBits := ecdsaKey.Curve.Params().BitSize
|
|
|
|
if m.CurveBits != curveBits {
|
|
return "", ErrInvalidKey
|
|
}
|
|
|
|
keyBytes := curveBits / 8
|
|
if curveBits%8 > 0 {
|
|
keyBytes += 1
|
|
}
|
|
|
|
// We serialize the outpus (r and s) into big-endian byte arrays and pad
|
|
// them with zeros on the left to make sure the sizes work out. Both arrays
|
|
// must be keyBytes long, and the output must be 2*keyBytes long.
|
|
rBytes := r.Bytes()
|
|
rBytesPadded := make([]byte, keyBytes)
|
|
copy(rBytesPadded[keyBytes-len(rBytes):], rBytes)
|
|
|
|
sBytes := s.Bytes()
|
|
sBytesPadded := make([]byte, keyBytes)
|
|
copy(sBytesPadded[keyBytes-len(sBytes):], sBytes)
|
|
|
|
out := append(rBytesPadded, sBytesPadded...)
|
|
|
|
return EncodeSegment(out), nil
|
|
} else {
|
|
return "", err
|
|
}
|
|
}
|