155 lines
4.4 KiB
Go
155 lines
4.4 KiB
Go
package jws
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/lestrrat-go/jwx/v3/jwa"
|
|
"github.com/lestrrat-go/jwx/v3/jws/jwsbb"
|
|
)
|
|
|
|
type defaultVerifier struct {
|
|
alg jwa.SignatureAlgorithm
|
|
}
|
|
|
|
func (v defaultVerifier) Algorithm() jwa.SignatureAlgorithm {
|
|
return v.alg
|
|
}
|
|
|
|
func (v defaultVerifier) Verify(key any, payload, signature []byte) error {
|
|
if err := jwsbb.Verify(key, v.alg.String(), payload, signature); err != nil {
|
|
return verifyError{verificationError{err}}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Verifier2 interface {
|
|
Verify(key any, payload, signature []byte) error
|
|
}
|
|
|
|
var muVerifier2DB sync.RWMutex
|
|
var verifier2DB = make(map[jwa.SignatureAlgorithm]Verifier2)
|
|
|
|
type verifierAdapter struct {
|
|
v Verifier
|
|
}
|
|
|
|
func (v verifierAdapter) Verify(key any, payload, signature []byte) error {
|
|
if err := v.v.Verify(payload, signature, key); err != nil {
|
|
return verifyError{verificationError{err}}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// VerifierFor returns a Verifier2 for the given signature algorithm.
|
|
//
|
|
// Currently, this function will never fail. It will always return a
|
|
// valid Verifier2 object. The heuristic is as follows:
|
|
// 1. If a Verifier2 is registered for the given algorithm, it will return that.
|
|
// 2. If a legacy Verifier(Factory) is registered for the given algorithm, it will
|
|
// return a Verifier2 that wraps the legacy Verifier.
|
|
// 3. If no Verifier2 or legacy Verifier(Factory) is registered, it will return a
|
|
// default verifier that uses jwsbb.Verify.
|
|
//
|
|
// jwsbb.Verify knows how to handle a static set of algorithms, so if the
|
|
// algorithm is not supported, it will return an error when you call
|
|
// `Verify` on the default verifier.
|
|
func VerifierFor(alg jwa.SignatureAlgorithm) (Verifier2, error) {
|
|
muVerifier2DB.RLock()
|
|
defer muVerifier2DB.RUnlock()
|
|
|
|
v2, ok := verifier2DB[alg]
|
|
if ok {
|
|
return v2, nil
|
|
}
|
|
|
|
v1, err := NewVerifier(alg)
|
|
if err == nil {
|
|
return verifierAdapter{v: v1}, nil
|
|
}
|
|
|
|
return defaultVerifier{alg: alg}, nil
|
|
}
|
|
|
|
type VerifierFactory interface {
|
|
Create() (Verifier, error)
|
|
}
|
|
type VerifierFactoryFn func() (Verifier, error)
|
|
|
|
func (fn VerifierFactoryFn) Create() (Verifier, error) {
|
|
return fn()
|
|
}
|
|
|
|
var muVerifierDB sync.RWMutex
|
|
var verifierDB = make(map[jwa.SignatureAlgorithm]VerifierFactory)
|
|
|
|
// RegisterVerifier is used to register a verifier for the given
|
|
// algorithm.
|
|
//
|
|
// Please note that this function is intended to be passed a
|
|
// verifier object as its second argument, but due to historical
|
|
// reasons the function signature is defined as taking `any` type.
|
|
//
|
|
// You should create a signer object that implements the `Verifier2`
|
|
// interface to register a signer, unless you have legacy code that
|
|
// plugged into the `SignerFactory` interface.
|
|
//
|
|
// Unlike the `UnregisterVerifier` function, this function automatically
|
|
// calls `jwa.RegisterSignatureAlgorithm` to register the algorithm
|
|
// in this module's algorithm database.
|
|
func RegisterVerifier(alg jwa.SignatureAlgorithm, f any) error {
|
|
jwa.RegisterSignatureAlgorithm(alg)
|
|
switch v := f.(type) {
|
|
case Verifier2:
|
|
muVerifier2DB.Lock()
|
|
verifier2DB[alg] = v
|
|
muVerifier2DB.Unlock()
|
|
|
|
muVerifierDB.Lock()
|
|
delete(verifierDB, alg)
|
|
muVerifierDB.Unlock()
|
|
case VerifierFactory:
|
|
muVerifierDB.Lock()
|
|
verifierDB[alg] = v
|
|
muVerifierDB.Unlock()
|
|
|
|
muVerifier2DB.Lock()
|
|
delete(verifier2DB, alg)
|
|
muVerifier2DB.Unlock()
|
|
default:
|
|
return fmt.Errorf(`jws.RegisterVerifier: unsupported type %T for algorithm %q`, f, alg)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UnregisterVerifier removes the signer factory associated with
|
|
// the given algorithm.
|
|
//
|
|
// Note that when you call this function, the algorithm itself is
|
|
// not automatically unregistered from this module's algorithm database.
|
|
// This is because the algorithm may still be required for signing or
|
|
// some other operation (however unlikely, it is still possible).
|
|
// Therefore, in order to completely remove the algorithm, you must
|
|
// call `jwa.UnregisterSignatureAlgorithm` yourself.
|
|
func UnregisterVerifier(alg jwa.SignatureAlgorithm) {
|
|
muVerifier2DB.Lock()
|
|
delete(verifier2DB, alg)
|
|
muVerifier2DB.Unlock()
|
|
|
|
muVerifierDB.Lock()
|
|
delete(verifierDB, alg)
|
|
muVerifierDB.Unlock()
|
|
}
|
|
|
|
// NewVerifier creates a verifier that signs payloads using the given signature algorithm.
|
|
func NewVerifier(alg jwa.SignatureAlgorithm) (Verifier, error) {
|
|
muVerifierDB.RLock()
|
|
f, ok := verifierDB[alg]
|
|
muVerifierDB.RUnlock()
|
|
|
|
if ok {
|
|
return f.Create()
|
|
}
|
|
return nil, fmt.Errorf(`jws.NewVerifier: unsupported signature algorithm "%s"`, alg)
|
|
}
|