67 lines
1.7 KiB
Go
67 lines
1.7 KiB
Go
|
|
package authjwt
|
||
|
|
|
||
|
|
import (
|
||
|
|
"crypto/ecdsa"
|
||
|
|
"crypto/x509"
|
||
|
|
"encoding/pem"
|
||
|
|
"fmt"
|
||
|
|
|
||
|
|
"github.com/golang-jwt/jwt/v5"
|
||
|
|
)
|
||
|
|
|
||
|
|
var _ Signer = (*ecSigner)(nil)
|
||
|
|
|
||
|
|
type ecSigner struct {
|
||
|
|
private *ecdsa.PrivateKey
|
||
|
|
public *ecdsa.PublicKey
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewECSigner returns a Signer backed by ECDSA.
|
||
|
|
// The signing algorithm is auto-detected from the key's curve:
|
||
|
|
// P-256→ES256, P-384→ES384, P-521→ES512.
|
||
|
|
func NewECSigner(privateKey *ecdsa.PrivateKey) Signer {
|
||
|
|
return &ecSigner{private: privateKey, public: &privateKey.PublicKey}
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewECSignerFromPEM parses a PKCS#8 PEM-encoded ECDSA private key.
|
||
|
|
func NewECSignerFromPEM(pemKey []byte) (Signer, error) {
|
||
|
|
block, _ := pem.Decode(pemKey)
|
||
|
|
if block == nil {
|
||
|
|
return nil, fmt.Errorf("no PEM block found")
|
||
|
|
}
|
||
|
|
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("parse EC private key: %w", err)
|
||
|
|
}
|
||
|
|
ecKey, ok := key.(*ecdsa.PrivateKey)
|
||
|
|
if !ok {
|
||
|
|
return nil, fmt.Errorf("PEM key is not an EC private key")
|
||
|
|
}
|
||
|
|
return NewECSigner(ecKey), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *ecSigner) Sign(claims jwt.Claims) (string, error) {
|
||
|
|
return jwt.NewWithClaims(ecAlg(s.private), claims).SignedString(s.private)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *ecSigner) Verify(tokenString string) (*jwt.Token, error) {
|
||
|
|
alg := ecAlg(s.private)
|
||
|
|
return jwt.Parse(tokenString, func(t *jwt.Token) (any, error) {
|
||
|
|
if t.Method.Alg() != alg.Alg() {
|
||
|
|
return nil, fmt.Errorf("unexpected signing method %q", t.Header["alg"])
|
||
|
|
}
|
||
|
|
return s.public, nil
|
||
|
|
}, jwt.WithJSONNumber())
|
||
|
|
}
|
||
|
|
|
||
|
|
func ecAlg(key *ecdsa.PrivateKey) *jwt.SigningMethodECDSA {
|
||
|
|
switch key.Curve.Params().Name {
|
||
|
|
case "P-384":
|
||
|
|
return jwt.SigningMethodES384
|
||
|
|
case "P-521":
|
||
|
|
return jwt.SigningMethodES512
|
||
|
|
default:
|
||
|
|
return jwt.SigningMethodES256
|
||
|
|
}
|
||
|
|
}
|