Documentation
¶
Overview ¶
Package pki provides interfaces and implementations for cryptographic signing operations. It supports multiple backends including software keys and PKCS#11 hardware security modules.
Example (TransparentKeyLoading) ¶
Example demonstrates transparent key loading with KeyConfig
// Example: Source-transparent key loading using KeyConfig
// This demonstrates how components don't need to care about key sources
package main
import (
"crypto"
"crypto/rand"
"fmt"
"github.com/SUNET/vc/pkg/pki"
)
// SigningService doesn't care whether keys come from files or HSM
type SigningService struct {
keyLoader *pki.KeyLoader
keyConfig *pki.KeyConfig
}
func (s *SigningService) Sign(data []byte) ([]byte, error) {
// Same code for both file and HSM keys!
km, err := s.keyLoader.LoadKeyMaterial(s.keyConfig)
if err != nil {
return nil, fmt.Errorf("failed to load key: %w", err)
}
// Use standard crypto.Signer interface
signer := km.PrivateKey.(crypto.Signer)
hash := crypto.SHA256.New()
hash.Write(data)
digest := hash.Sum(nil)
signature, err := signer.Sign(rand.Reader, digest, crypto.SHA256)
if err != nil {
return nil, fmt.Errorf("signing failed: %w", err)
}
fmt.Printf("Signed with algorithm: %s\n", km.SigningMethod.Alg())
return signature, nil
}
// Example demonstrates transparent key loading with KeyConfig
func main() {
data := []byte("data to sign")
keyLoader := pki.NewKeyLoader()
// Scenario 1: Development with file-based keys
fmt.Println("=== Development (File-based keys) ===")
devConfig := &pki.KeyConfig{
PrivateKeyPath: "/path/to/dev/key.pem",
ChainPath: "/path/to/dev/chain.pem",
}
devService := &SigningService{
keyLoader: keyLoader,
keyConfig: devConfig,
}
sig, err := devService.Sign(data)
if err != nil {
fmt.Printf("Dev signing error: %v\n", err)
} else {
fmt.Printf("Signature length: %d bytes\n\n", len(sig))
}
// Scenario 2: Production with HSM keys
// SAME component code, just different KeyConfig!
fmt.Println("=== Production (HSM keys) ===")
prodConfig := &pki.KeyConfig{
PrivateKeyPath: "production-signing-key", // HSM label
PKCS11: &pki.PKCS11Config{
ModulePath: "/usr/lib/softhsm/libsofthsm2.so",
SlotID: 0,
PIN: "1234",
KeyID: "prod-key-1",
},
}
prodService := &SigningService{
keyLoader: keyLoader,
keyConfig: prodConfig,
}
sig, err = prodService.Sign(data)
if err != nil {
fmt.Printf("Production signing error: %v\n", err)
} else {
fmt.Printf("Signature length: %d bytes\n", len(sig))
}
// Scenario 3: Fallback configuration (try HSM first, fall back to file)
fmt.Println("=== Fallback (HSM → File) ===")
fallbackConfig := &pki.KeyConfig{
PrivateKeyPath: "/backup/key.pem",
ChainPath: "/backup/chain.pem",
PKCS11: &pki.PKCS11Config{
ModulePath: "/usr/lib/softhsm/libsofthsm2.so",
SlotID: 0,
PIN: "1234",
KeyID: "fallback-key",
},
Priority: []pki.KeySource{pki.KeySourceHSM, pki.KeySourceFile},
}
fallbackService := &SigningService{
keyLoader: keyLoader,
keyConfig: fallbackConfig,
}
sig, err = fallbackService.Sign(data)
if err != nil {
fmt.Printf("Fallback signing error: %v\n", err)
} else {
fmt.Printf("Signature length: %d bytes\n", len(sig))
}
// Key benefits:
// 1. SigningService code is identical for all scenarios
// 2. Switch sources by changing only KeyConfig
// 3. No conditional logic based on key source
// 4. Support fallback scenarios with Priority
// 5. Enable/disable sources with flags
}
Output:
Index ¶
- Variables
- func DecodeECDSASignature(signature []byte, curve elliptic.Curve) (*big.Int, *big.Int, error)
- func EncodeECDSASignature(r, s *big.Int, curve elliptic.Curve) ([]byte, error)
- func GetKeySizeForCurve(curve elliptic.Curve) int
- func ParseCertificate(der []byte, ext *cryptoutil.Extensions) (*x509.Certificate, error)
- type KeyConfig
- type KeyLoader
- func (kl *KeyLoader) GetKeyAlgorithm(key crypto.PrivateKey) (string, error)
- func (kl *KeyLoader) LoadCertificateChain(path string) ([]*x509.Certificate, []string, error)
- func (kl *KeyLoader) LoadKeyMaterial(config *KeyConfig) (*KeyMaterial, error)
- func (kl *KeyLoader) LoadPrivateKey(path string) (crypto.PrivateKey, error)
- func (kl *KeyLoader) ValidateKeyType(key crypto.PrivateKey, expectedType string) error
- type KeyMaterial
- type KeyMaterialSigner
- func (s *KeyMaterialSigner) Algorithm() string
- func (s *KeyMaterialSigner) GetCertificate() *x509.Certificate
- func (s *KeyMaterialSigner) GetCertificateChain() []string
- func (s *KeyMaterialSigner) KeyID() string
- func (s *KeyMaterialSigner) PrivateKey() crypto.PrivateKey
- func (s *KeyMaterialSigner) PublicKey() any
- func (s *KeyMaterialSigner) Sign(ctx context.Context, data []byte) ([]byte, error)
- func (s *KeyMaterialSigner) SignDigest(ctx context.Context, digest []byte) ([]byte, error)
- func (s *KeyMaterialSigner) SigningMethod() jwt.SigningMethod
- type KeySource
- type PKCS11Config
- type PKCS11Signer
- type RawSigner
- type Signer
- type SignerConfig
- func (sc *SignerConfig) GetCertificate() (*x509.Certificate, error)
- func (sc *SignerConfig) GetCertificateChain() ([]string, error)
- func (sc *SignerConfig) GetJWK() (*jose.JSONWebKey, error)
- func (sc *SignerConfig) GetKeyMaterial() (*KeyMaterial, error)
- func (sc *SignerConfig) GetPrivateKey() (crypto.PrivateKey, error)
- func (sc *SignerConfig) RawSigner() (RawSigner, error)
- func (sc *SignerConfig) Sign(data []byte) ([]byte, error)
- func (sc *SignerConfig) SignJWT(claims jwt.Claims) (string, error)
- type SoftwareSigner
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrPKCS11NotSupported = errors.New("PKCS#11 support not compiled in; rebuild with -tags=pkcs11")
ErrPKCS11NotSupported is returned when PKCS#11 support is not compiled in.
Functions ¶
func DecodeECDSASignature ¶
DecodeECDSASignature decodes an IEEE P1363 format ECDSA signature to (r, s) big integers. This is the inverse of EncodeECDSASignature.
func EncodeECDSASignature ¶
EncodeECDSASignature converts ECDSA signature components (r, s) to IEEE P1363 format. This is the fixed-size R||S concatenation format required by JWT (RFC 7518 section 3.4). ASN.1 DER encoding is NOT used for JWT ECDSA signatures.
func GetKeySizeForCurve ¶
GetKeySizeForCurve returns the key size in bytes for a given curve.
func ParseCertificate ¶ added in v0.5.4
func ParseCertificate(der []byte, ext *cryptoutil.Extensions) (*x509.Certificate, error)
ParseCertificate parses a DER-encoded certificate using extension-aware parsing if ext is non-nil, falling back to standard x509.ParseCertificate.
Types ¶
type KeyConfig ¶
type KeyConfig struct {
// File-based configuration
PrivateKeyPath string `yaml:"private_key_path" validate:"required_without=PKCS11"` // Path to PEM key file
ChainPath string `yaml:"chain_path"` // Path to certificate chain (optional)
// HSM-based configuration
PKCS11 *PKCS11Config `yaml:"pkcs11" validate:"required_without=PrivateKeyPath"` // PKCS#11 HSM config (optional)
// Source selection (determines which config to use)
// If empty, tries in order: File (if FilePath set), then HSM (if HSM set)
Source KeySource `yaml:"source"`
// EnableFile enables file-based key loading (default: true if FilePath set)
EnableFile bool `yaml:"enable_file"`
// EnableHSM enables HSM-based key loading (default: true if HSM set)
EnableHSM bool `yaml:"enable_hsm"`
// Priority defines fallback order when both are enabled
// If nil, uses Source field or auto-detects based on what's configured
Priority []KeySource `yaml:"priority" doc_example:"[\"hsm\", \"file\"]"`
}
KeyConfig holds configuration for loading keys from various sources. Supports both file-based and HSM-based keys with explicit control.
type KeyLoader ¶
type KeyLoader struct {
// CryptoExt provides extended algorithm and certificate support
// (e.g. brainpool curves). Must be set before concurrent use and
// not mutated afterwards.
CryptoExt *cryptoutil.Extensions
}
KeyLoader provides centralized key and certificate loading functionality. Methods are safe for concurrent use after initialization.
func NewKeyLoader ¶
func NewKeyLoader() *KeyLoader
NewKeyLoader creates a new KeyLoader instance.
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/pki"
)
func main() {
kl := pki.NewKeyLoader()
fmt.Printf("%T\n", kl)
}
Output: *pki.KeyLoader
func NewKeyLoaderWithExtensions ¶ added in v0.5.4
func NewKeyLoaderWithExtensions(ext *cryptoutil.Extensions) *KeyLoader
NewKeyLoaderWithExtensions creates a new KeyLoader with crypto extensions.
func (*KeyLoader) GetKeyAlgorithm ¶
func (kl *KeyLoader) GetKeyAlgorithm(key crypto.PrivateKey) (string, error)
GetKeyAlgorithm returns the algorithm name for a given key
func (*KeyLoader) LoadCertificateChain ¶
LoadCertificateChain loads a certificate chain from a PEM file. Returns the certificates and their base64-encoded DER format for x5c.
func (*KeyLoader) LoadKeyMaterial ¶
func (kl *KeyLoader) LoadKeyMaterial(config *KeyConfig) (*KeyMaterial, error)
LoadKeyMaterial loads a private key based on the provided configuration. The config determines whether to load from file, HSM, or try multiple sources.
func (*KeyLoader) LoadPrivateKey ¶
func (kl *KeyLoader) LoadPrivateKey(path string) (crypto.PrivateKey, error)
LoadPrivateKey loads a private key from a PEM file. Supports PKCS#8, PKCS#1 (RSA), and SEC1 (EC) formats.
func (*KeyLoader) ValidateKeyType ¶
func (kl *KeyLoader) ValidateKeyType(key crypto.PrivateKey, expectedType string) error
ValidateKeyType checks if the private key is of the expected type
type KeyMaterial ¶
type KeyMaterial struct {
PrivateKey crypto.PrivateKey
Cert *x509.Certificate
Chain []string // Base64-encoded DER certificates for x5c
SigningMethod jwt.SigningMethod // JWT signing method determined from key type
}
KeyMaterial holds a private key with its optional certificate and chain
type KeyMaterialSigner ¶
type KeyMaterialSigner struct {
// contains filtered or unexported fields
}
KeyMaterialSigner implements the Signer interface using KeyMaterial. It provides a concrete implementation for services that need signing capabilities.
Example ¶
ExampleKeyMaterialSigner demonstrates using the Signer interface implementation
package main
import (
"context"
"fmt"
"log"
"github.com/SUNET/vc/pkg/pki"
)
func main() {
// Load key material
keyLoader := pki.NewKeyLoader()
km, err := keyLoader.LoadKeyMaterial(&pki.KeyConfig{
PrivateKeyPath: "/path/to/private-key.pem",
ChainPath: "/path/to/certificate-chain.pem",
})
if err != nil {
log.Fatalf("failed to load key material: %v", err)
}
// Create a signer from the key material
signer := pki.NewKeyMaterialSigner(km)
// Sign data using the Signer interface
ctx := context.Background()
data := []byte("data to sign")
signature, err := signer.Sign(ctx, data)
if err != nil {
log.Fatalf("failed to sign: %v", err)
}
fmt.Printf("Algorithm: %s\n", signer.Algorithm())
fmt.Printf("Key ID: %s\n", signer.KeyID())
fmt.Printf("Signature: %d bytes\n", len(signature))
}
Output:
Example (WithCredentials) ¶
ExampleKeyMaterialSigner_withCredentials demonstrates using KeyMaterialSigner with credential issuance
package main
import (
"context"
"fmt"
"log"
"github.com/SUNET/vc/pkg/pki"
)
func main() {
// Load signing key
keyLoader := pki.NewKeyLoader()
km, err := keyLoader.LoadKeyMaterial(&pki.KeyConfig{
PrivateKeyPath: "/etc/issuer/signing-key.pem",
ChainPath: "/etc/issuer/chain.pem",
})
if err != nil {
log.Fatalf("failed to load key: %v", err)
}
// Create signer implementing the Signer interface
signer := pki.NewKeyMaterialSigner(km)
// Function that requires a Signer interface (like credential issuance libraries)
issueCredential := func(s pki.Signer, claims map[string]any) error {
ctx := context.Background()
// Credential issuance would use:
// - s.Sign(ctx, data) for signing
// - s.Algorithm() for JWT header
// - s.KeyID() for kid claim
// - s.PublicKey() for verification
fmt.Printf("Issuing credential with key: %s\n", s.KeyID())
fmt.Printf("Using algorithm: %s\n", s.Algorithm())
// Example signing
data := []byte("credential data")
_, err := s.Sign(ctx, data)
return err
}
// Pass the signer to credential issuance
err = issueCredential(signer, map[string]any{
"sub": "did:example:123",
"vc": map[string]any{
"type": []string{"VerifiableCredential"},
},
})
if err != nil {
log.Fatalf("failed to issue credential: %v", err)
}
}
Output:
func NewKeyMaterialSigner ¶
func NewKeyMaterialSigner(km *KeyMaterial) *KeyMaterialSigner
NewKeyMaterialSigner creates a new Signer from KeyMaterial. The keyID is automatically determined from the certificate if available, or generated from the public key hash.
func (*KeyMaterialSigner) Algorithm ¶
func (s *KeyMaterialSigner) Algorithm() string
Algorithm returns the JWT algorithm name based on the key type.
func (*KeyMaterialSigner) GetCertificate ¶
func (s *KeyMaterialSigner) GetCertificate() *x509.Certificate
GetCertificate returns the certificate if available.
func (*KeyMaterialSigner) GetCertificateChain ¶
func (s *KeyMaterialSigner) GetCertificateChain() []string
GetCertificateChain returns the certificate chain if available.
func (*KeyMaterialSigner) KeyID ¶
func (s *KeyMaterialSigner) KeyID() string
KeyID returns the key identifier for JWT headers.
func (*KeyMaterialSigner) PrivateKey ¶
func (s *KeyMaterialSigner) PrivateKey() crypto.PrivateKey
PrivateKey returns the underlying private key. This is useful when integrating with libraries that need the raw crypto.PrivateKey.
func (*KeyMaterialSigner) PublicKey ¶
func (s *KeyMaterialSigner) PublicKey() any
PublicKey returns the public key for verification.
func (*KeyMaterialSigner) SignDigest ¶
SignDigest signs a pre-computed digest without additional hashing. This is useful for protocols like W3C Data Integrity that control the hashing process.
func (*KeyMaterialSigner) SigningMethod ¶
func (s *KeyMaterialSigner) SigningMethod() jwt.SigningMethod
SigningMethod returns the JWT signing method for this key material.
type PKCS11Config ¶
type PKCS11Config struct {
// ModulePath is the path to the PKCS#11 library
ModulePath string `yaml:"module_path" doc_example:"\"/usr/lib/softhsm/libsofthsm2.so\""`
// SlotID is the HSM slot ID
SlotID uint `yaml:"slot_id" doc_example:"0"`
// PIN is the user PIN for the slot
PIN string `yaml:"pin" doc_example:"\"1234\""`
// KeyLabel is the label of the key to use
KeyLabel string `yaml:"key_label" doc_example:"\"my-signing-key\""`
// KeyID is the identifier for the JWT kid header
KeyID string `yaml:"key_id" doc_example:"\"key-1\""`
}
PKCS11Config holds configuration for PKCS#11 HSM connection.
type PKCS11Signer ¶
type PKCS11Signer struct{}
PKCS11Signer is a stub when PKCS#11 support is not compiled in.
func NewPKCS11Signer ¶
func NewPKCS11Signer(config *PKCS11Config) (*PKCS11Signer, error)
NewPKCS11Signer returns an error when PKCS#11 support is not compiled in.
func (*PKCS11Signer) Algorithm ¶
func (s *PKCS11Signer) Algorithm() string
Algorithm is not supported without PKCS#11.
func (*PKCS11Signer) KeyID ¶
func (s *PKCS11Signer) KeyID() string
KeyID is not supported without PKCS#11.
func (*PKCS11Signer) PublicKey ¶
func (s *PKCS11Signer) PublicKey() any
PublicKey is not supported without PKCS#11.
type RawSigner ¶
type RawSigner interface {
Signer
// SignDigest signs a pre-computed digest without additional hashing.
//
// For ECDSA, the digest should be the appropriate size for the curve:
// - P-256: SHA-256 (32 bytes)
// - P-384: SHA-384 (48 bytes)
// - P-521: SHA-512 (64 bytes)
//
// For EdDSA (Ed25519), note that Ed25519 does not use pre-hashing in standard mode.
// The implementation may need to use Ed25519ph (pre-hashed) or handle this specially.
//
// The returned signature is in IEEE P1363 format for ECDSA (R||S concatenation).
SignDigest(ctx context.Context, digest []byte) ([]byte, error)
}
RawSigner extends Signer with direct signature operations for advanced use cases like W3C Data Integrity proofs where the caller controls hashing.
This interface is particularly useful for: - VC 2.0 Data Integrity cryptosuites (ecdsa-rdfc-2019, eddsa-rdfc-2022, etc.) - Any protocol that requires signing pre-computed digests - Fine-grained control over the hash-then-sign process
type Signer ¶
type Signer interface {
// Sign signs the provided data and returns the signature.
//
// For ECDSA algorithms (ES256, ES384, ES512), the returned signature SHOULD be
// in IEEE P1363 format (fixed-size R||S concatenation) as required by JWS (RFC 7518 §3.4).
// If the implementation returns ASN.1 DER-encoded ECDSA signatures instead (as is
// common with crypto.Signer and some HSM backends), the jose.MakeJWT function will
// automatically convert them to JWS format. However, returning IEEE P1363 directly
// avoids the conversion overhead.
//
// For RSA algorithms (RS256, RS384, RS512), the signature is PKCS#1 v1.5 encoded
// and requires no format conversion.
Sign(ctx context.Context, data []byte) ([]byte, error)
// Algorithm returns the JWT algorithm name (e.g., "RS256", "ES256").
Algorithm() string
// KeyID returns the key identifier for the JWT kid header.
KeyID() string
// PublicKey returns the public key for verification purposes.
PublicKey() any
}
Signer defines the interface for cryptographic signing operations. Implementations can use software keys, HSMs via PKCS#11, cloud KMS, etc.
func LoadSigner ¶
LoadSigner loads key material and creates a pki.Signer from the configuration. Supports both software keys and HSM-backed keys. Returns the signer, signing certificate, and certificate chain.
type SignerConfig ¶
type SignerConfig struct {
// KeyConfig contains the underlying key configuration
KeyConfig
// contains filtered or unexported fields
}
SignerConfig provides a high-level interface for cryptographic operations without requiring services to directly handle KeyMaterial. It supports both file-based keys and HSM-based keys through PKCS#11.
Example (Fallback) ¶
ExampleSignerConfig_fallback demonstrates fallback from HSM to file
package main
import (
"fmt"
"log"
"github.com/SUNET/vc/pkg/pki"
)
func main() {
// Configure with both HSM and file-based keys, preferring HSM
config := pki.NewSignerConfig(&pki.KeyConfig{
PrivateKeyPath: "/path/to/backup-key.pem",
ChainPath: "/path/to/backup-chain.pem",
PKCS11: &pki.PKCS11Config{
ModulePath: "/usr/lib/softhsm/libsofthsm2.so",
PIN: "1234",
KeyLabel: "signing-key",
},
Priority: []pki.KeySource{pki.KeySourceHSM, pki.KeySourceFile},
EnableHSM: true,
EnableFile: true,
})
// Sign - will try HSM first, fall back to file if HSM fails
data := []byte("data to sign")
signature, err := config.Sign(data)
if err != nil {
log.Fatalf("failed to sign data: %v", err)
}
fmt.Printf("Signed with fallback: %d bytes\n", len(signature))
}
Output:
Example (FileBasedSigning) ¶
ExampleSignerConfig_fileBasedSigning demonstrates using SignerConfig with file-based keys
// Create a signer config with file-based keys
config := pki.NewSignerConfig(&pki.KeyConfig{
PrivateKeyPath: "/path/to/private-key.pem",
ChainPath: "/path/to/certificate-chain.pem",
})
// Sign arbitrary data
data := []byte("important data to sign")
signature, err := config.Sign(data)
if err != nil {
log.Fatalf("failed to sign data: %v", err)
}
fmt.Printf("Signature length: %d bytes\n", len(signature))
// Sign a JWT
claims := jwt.MapClaims{
"sub": "user123",
"iss": "my-service",
"exp": 1234567890,
}
token, err := config.SignJWT(claims)
if err != nil {
log.Fatalf("failed to sign JWT: %v", err)
}
fmt.Printf("JWT: %s\n", token)
// Get public key as JWK
jwk, err := config.GetJWK()
if err != nil {
log.Fatalf("failed to get JWK: %v", err)
}
fmt.Printf("JWK Algorithm: %s\n", jwk.Algorithm)
Example (HsmSigning) ¶
ExampleSignerConfig_hsmSigning demonstrates using SignerConfig with HSM
// Create a signer config with HSM
config := pki.NewSignerConfig(&pki.KeyConfig{
PKCS11: &pki.PKCS11Config{
ModulePath: "/usr/lib/softhsm/libsofthsm2.so",
PIN: "1234",
KeyLabel: "signing-key",
},
})
// Use the same interface for HSM-based signing
claims := jwt.MapClaims{
"sub": "user456",
"iss": "secure-service",
}
token, err := config.SignJWT(claims)
if err != nil {
log.Fatalf("failed to sign JWT with HSM: %v", err)
}
fmt.Printf("HSM-signed JWT: %s\n", token)
// Get certificate from HSM
cert, err := config.GetCertificate()
if err != nil {
log.Fatalf("failed to get certificate: %v", err)
}
fmt.Printf("Certificate subject: %s\n", cert.Subject)
Example (ServiceUsage) ¶
ExampleSignerConfig_serviceUsage demonstrates typical service usage
// In a real service, this config would come from application config
signerConfig := pki.NewSignerConfig(&pki.KeyConfig{
PrivateKeyPath: "/etc/myservice/signing-key.pem",
ChainPath: "/etc/myservice/signing-chain.pem",
})
// Service method that needs to sign something
generateAccessToken := func(userID string) (string, error) {
claims := jwt.MapClaims{
"sub": userID,
"iss": "my-service",
"iat": 1234567890,
"exp": 1234571490,
}
return signerConfig.SignJWT(claims)
}
// Use in service
token, err := generateAccessToken("user789")
if err != nil {
log.Fatalf("failed to generate token: %v", err)
}
fmt.Printf("Access token: %s\n", token)
// Get public key for verification endpoint
jwk, err := signerConfig.GetJWK()
if err != nil {
log.Fatalf("failed to get public key: %v", err)
}
fmt.Printf("Public key algorithm: %s\n", jwk.Algorithm)
func NewSignerConfig ¶
func NewSignerConfig(config *KeyConfig) *SignerConfig
NewSignerConfig creates a new SignerConfig with the specified configuration. Keys are loaded lazily on first use.
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/pki"
)
func main() {
config := pki.NewSignerConfig(&pki.KeyConfig{
PrivateKeyPath: "/path/to/key.pem",
ChainPath: "/path/to/chain.pem",
})
fmt.Printf("%T\n", config)
}
Output: *pki.SignerConfig
func (*SignerConfig) GetCertificate ¶
func (sc *SignerConfig) GetCertificate() (*x509.Certificate, error)
GetCertificate returns the X.509 certificate associated with the key.
func (*SignerConfig) GetCertificateChain ¶
func (sc *SignerConfig) GetCertificateChain() ([]string, error)
GetCertificateChain returns the full certificate chain as base64-encoded DER.
func (*SignerConfig) GetJWK ¶
func (sc *SignerConfig) GetJWK() (*jose.JSONWebKey, error)
GetJWK returns the public key as a JSON Web Key (JWK). The kid is derived using the same logic as KeyMaterialSigner.KeyID() to ensure consistency between JWT headers and JWKS endpoints.
func (*SignerConfig) GetKeyMaterial ¶
func (sc *SignerConfig) GetKeyMaterial() (*KeyMaterial, error)
GetKeyMaterial returns the underlying KeyMaterial. This method should be used sparingly - prefer using the specific methods instead.
func (*SignerConfig) GetPrivateKey ¶
func (sc *SignerConfig) GetPrivateKey() (crypto.PrivateKey, error)
GetPrivateKey returns the underlying private key. This method should be used sparingly - prefer using Sign() or SignJWT() instead.
func (*SignerConfig) RawSigner ¶
func (sc *SignerConfig) RawSigner() (RawSigner, error)
RawSigner returns a RawSigner interface for advanced signing operations. This is useful for protocols like W3C Data Integrity that need to sign pre-computed digests.
type SoftwareSigner ¶
type SoftwareSigner struct {
// contains filtered or unexported fields
}
SoftwareSigner implements Signer using software-based keys.
func NewSoftwareSigner ¶
func NewSoftwareSigner(privateKey crypto.PrivateKey, keyID string) (*SoftwareSigner, error)
NewSoftwareSigner creates a new SoftwareSigner from a private key.
func (*SoftwareSigner) Algorithm ¶
func (s *SoftwareSigner) Algorithm() string
Algorithm returns the JWT algorithm name.
func (*SoftwareSigner) KeyID ¶
func (s *SoftwareSigner) KeyID() string
KeyID returns the key identifier.
func (*SoftwareSigner) PublicKey ¶
func (s *SoftwareSigner) PublicKey() any
PublicKey returns the public key.
func (*SoftwareSigner) SignDigest ¶
SignDigest signs a pre-computed digest without additional hashing. This is useful for protocols like W3C Data Integrity that control the hashing process.