435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
96 lines
2.4 KiB
Go
96 lines
2.4 KiB
Go
package jwt
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/hmac"
|
|
"errors"
|
|
)
|
|
|
|
// Implements the HMAC-SHA family of signing methods signing methods
|
|
// Expects key type of []byte for both signing and validation
|
|
type SigningMethodHMAC struct {
|
|
Name string
|
|
Hash crypto.Hash
|
|
}
|
|
|
|
// Specific instances for HS256 and company
|
|
var (
|
|
SigningMethodHS256 *SigningMethodHMAC
|
|
SigningMethodHS384 *SigningMethodHMAC
|
|
SigningMethodHS512 *SigningMethodHMAC
|
|
ErrSignatureInvalid = errors.New("signature is invalid")
|
|
)
|
|
|
|
func init() {
|
|
// HS256
|
|
SigningMethodHS256 = &SigningMethodHMAC{"HS256", crypto.SHA256}
|
|
RegisterSigningMethod(SigningMethodHS256.Alg(), func() SigningMethod {
|
|
return SigningMethodHS256
|
|
})
|
|
|
|
// HS384
|
|
SigningMethodHS384 = &SigningMethodHMAC{"HS384", crypto.SHA384}
|
|
RegisterSigningMethod(SigningMethodHS384.Alg(), func() SigningMethod {
|
|
return SigningMethodHS384
|
|
})
|
|
|
|
// HS512
|
|
SigningMethodHS512 = &SigningMethodHMAC{"HS512", crypto.SHA512}
|
|
RegisterSigningMethod(SigningMethodHS512.Alg(), func() SigningMethod {
|
|
return SigningMethodHS512
|
|
})
|
|
}
|
|
|
|
func (m *SigningMethodHMAC) Alg() string {
|
|
return m.Name
|
|
}
|
|
|
|
// Verify the signature of HSXXX tokens. Returns nil if the signature is valid.
|
|
func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
|
|
// Verify the key is the right type
|
|
keyBytes, ok := key.([]byte)
|
|
if !ok {
|
|
return ErrInvalidKeyType
|
|
}
|
|
|
|
// Decode signature, for comparison
|
|
sig, err := DecodeSegment(signature)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Can we use the specified hashing method?
|
|
if !m.Hash.Available() {
|
|
return ErrHashUnavailable
|
|
}
|
|
|
|
// This signing method is symmetric, so we validate the signature
|
|
// by reproducing the signature from the signing string and key, then
|
|
// comparing that against the provided signature.
|
|
hasher := hmac.New(m.Hash.New, keyBytes)
|
|
hasher.Write([]byte(signingString))
|
|
if !hmac.Equal(sig, hasher.Sum(nil)) {
|
|
return ErrSignatureInvalid
|
|
}
|
|
|
|
// No validation errors. Signature is good.
|
|
return nil
|
|
}
|
|
|
|
// Implements the Sign method from SigningMethod for this signing method.
|
|
// Key must be []byte
|
|
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
|
|
if keyBytes, ok := key.([]byte); ok {
|
|
if !m.Hash.Available() {
|
|
return "", ErrHashUnavailable
|
|
}
|
|
|
|
hasher := hmac.New(m.Hash.New, keyBytes)
|
|
hasher.Write([]byte(signingString))
|
|
|
|
return EncodeSegment(hasher.Sum(nil)), nil
|
|
}
|
|
|
|
return "", ErrInvalidKeyType
|
|
}
|