165 lines
3.8 KiB
Go
165 lines
3.8 KiB
Go
package jwt
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/hmac"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"fmt"
|
|
)
|
|
|
|
type hashLinkError struct {
|
|
name string
|
|
}
|
|
|
|
func (e *hashLinkError) Error() string {
|
|
return fmt.Sprintf("jws: Hash %s is not linked into binary", e.name)
|
|
}
|
|
|
|
// A Signer is able to crypto-sign a JWS object.
|
|
type Signer interface {
|
|
// Sign returns the signature of a binary payload. It should
|
|
// returns the signature in binary format
|
|
Sign([]byte) ([]byte, error)
|
|
// Verify check if the signed binary paylod correspond to the
|
|
// provided binary siganture. It assumes a binary format
|
|
// signature.
|
|
Verify(signed, signature []byte) error
|
|
// Algorithm is returning a string idnetifying the algorithm used
|
|
// as defined in RFC 7518.
|
|
Algorithm() string
|
|
}
|
|
|
|
// A HMACSigner is a Signer using HMAC based algorithm
|
|
type HMACSigner struct {
|
|
name string
|
|
hash crypto.Hash
|
|
key []byte
|
|
}
|
|
|
|
// NewHMAC256Signer returs a HMACSigner using a SHA256 hash.
|
|
func NewHMAC256Signer(key []byte) Signer {
|
|
return &HMACSigner{
|
|
name: "HS256",
|
|
hash: crypto.SHA256,
|
|
key: key,
|
|
}
|
|
}
|
|
|
|
// NewHMAC384Signer returs a HMACSigner using a SHA384 hash.
|
|
func NewHMAC384Signer(key []byte) Signer {
|
|
return &HMACSigner{
|
|
name: "HS384",
|
|
hash: crypto.SHA384,
|
|
key: key,
|
|
}
|
|
}
|
|
|
|
// NewHMAC512Signer returs a HMACSigner using a SHA512 hash.
|
|
func NewHMAC512Signer(key []byte) Signer {
|
|
return &HMACSigner{
|
|
name: "HS512",
|
|
hash: crypto.SHA512,
|
|
key: key,
|
|
}
|
|
}
|
|
|
|
// Algorithm return 'HSXXX' where XXX is either 256|384|512 depending
|
|
// on the SHA Hash used.
|
|
func (s *HMACSigner) Algorithm() string {
|
|
return s.name
|
|
}
|
|
|
|
// Sign compute the binary signature for data.
|
|
func (s *HMACSigner) Sign(data []byte) ([]byte, error) {
|
|
if s.hash.Available() == false {
|
|
return nil, &hashLinkError{s.name}
|
|
}
|
|
|
|
hasher := hmac.New(s.hash.New, s.key)
|
|
hasher.Write(data)
|
|
return hasher.Sum(nil), nil
|
|
}
|
|
|
|
// Verify returns an error if the binary provided signature does not
|
|
// correspond to signed. It return nil if the signature is correct.
|
|
func (s *HMACSigner) Verify(signed, signature []byte) error {
|
|
expected, err := s.Sign(signed)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if hmac.Equal(signature, expected) == false {
|
|
return fmt.Errorf("jws: Invalid %s signature", s.name)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// A RSASigner is a Signer using a PKS 1v15 algorithm.
|
|
type RSASigner struct {
|
|
name string
|
|
hash crypto.Hash
|
|
key *rsa.PrivateKey
|
|
}
|
|
|
|
// NewRSA256Signer returns a RSASigner using a SHA 256 hash.
|
|
func NewRSA256Signer(key *rsa.PrivateKey) Signer {
|
|
return &RSASigner{
|
|
name: "RS256",
|
|
hash: crypto.SHA256,
|
|
key: key,
|
|
}
|
|
}
|
|
|
|
// NewRSA384Signer returns a RSASigner using a SHA 384 hash.
|
|
func NewRSA384Signer(key *rsa.PrivateKey) Signer {
|
|
return &RSASigner{
|
|
name: "RS384",
|
|
hash: crypto.SHA384,
|
|
key: key,
|
|
}
|
|
}
|
|
|
|
// NewRSA512Signer returns a RSASigner using a SHA 512 hash.
|
|
func NewRSA512Signer(key *rsa.PrivateKey) Signer {
|
|
return &RSASigner{
|
|
name: "RS512",
|
|
hash: crypto.SHA512,
|
|
key: key,
|
|
}
|
|
}
|
|
|
|
// Sign compute the binary signature for data.
|
|
func (s *RSASigner) Sign(data []byte) ([]byte, error) {
|
|
if s.hash.Available() == false {
|
|
return nil, &hashLinkError{s.name}
|
|
}
|
|
|
|
hasher := s.hash.New()
|
|
hasher.Write(data)
|
|
res, err := rsa.SignPKCS1v15(rand.Reader, s.key, s.hash, hasher.Sum(nil))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
// Verify returns an error if the binary provided signature does not
|
|
// correspond to signed. It return nil if the signature is correct.
|
|
func (s *RSASigner) Verify(signed, signature []byte) error {
|
|
if s.hash.Available() == false {
|
|
return &hashLinkError{s.name}
|
|
}
|
|
|
|
hasher := s.hash.New()
|
|
hasher.Write(signed)
|
|
|
|
return rsa.VerifyPKCS1v15(s.key.Public().(*rsa.PublicKey), s.hash, hasher.Sum(nil), signature)
|
|
}
|
|
|
|
// Algorithm return 'RSXXX' where XXX is either 256|384|512 depending
|
|
// on the SHA Hash used.
|
|
func (s *RSASigner) Algorithm() string {
|
|
return s.name
|
|
}
|