jwtsigner

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2024 License: Apache-2.0 Imports: 10 Imported by: 1

README

golang-jwt for crypto.Signer

Another extension for go-jwt that allows creating and verifying JWT tokens where the private key is abstracted as something that is accessible through the crypto.Signer interface.

The out of the obx go-jwt normally expects you to directly provide an rsa.PrivateKey object. That is normally just fine if you have a key bytes handy in some sort of local storage.

go-jwt can be extended to support arbitrary providers holding the key. In this case, you can have the private key saved into KMS, Yubikeys, Hashicorp Vault or even a Trusted Platform Module.

Each 'backend' you choose to save the keys to requires you to import that package and use that directly.

In contrast, the implementation describes here takes it a step back where you define any key backend that would implement the crypto.Signer interface and then provide that directly into a library.

Instead of importing a use-specific golang-jwt implementation and using that, what we'll do here is just provide a generic Signer.

This code is NOT supported by google

For other references, see:

Supported Algorithms
  • RS256
  • PS256
  • ES256
Usage

Using this is really easy...you just need something that surfaces that interface.

I've written some simple ones here...the examples/ folder uses a PEM Signer (yes i'm well aware go-jwt already supports PEM format keys...i just happened to make a Signer so i could test the other ones)

The following shows the PEM signer and Google Cloud KMS based signers:

package main

import (

	//"github.com/go-piv/piv-go/piv"
	jwt "github.com/golang-jwt/jwt/v5"
	jwtsigner "github.com/salrashid123/golang-jwt-signer"

	// salkms "github.com/salrashid123/signer/kms"
	// saltpm "github.com/salrashid123/signer/tpm"
	// "github.com/ThalesIgnite/crypto11"
	// salpkcs "github.com/salrashid123/mtls_pkcs11/signer/pkcs"
)

var ()

func main() {

	ctx := context.Background()

	// // rsa.PrivateKey also implements  crypto.Signer
	// // https://pkg.go.dev/crypto/rsa#PrivateKey.Sign
	privatePEM, err := os.ReadFile("client_rsa.key")
	rblock, _ := pem.Decode(privatePEM)
	r, err := x509.ParsePKCS1PrivateKey(rblock.Bytes)

	// ############# KMS

	// r, err := salkms.NewKMSCrypto(&salkms.KMS{
	// 	ProjectId:          "mineral-minutia-820",
	// 	LocationId:         "us-central1",
	// 	KeyRing:            "kr",
	// 	Key:                "s",
	// 	KeyVersion:         "1",
	// })

	// ############# TPM

	// r, err := saltpm.NewTPMCrypto(&saltpm.TPM{
	// 	TpmDevice:     "/dev/tpm0",
	// 	TpmHandleFile: "/tmp/key.bin",
	// 	//TpmHandle:     0x81010002,
	// })

	// ############# Yubikey

	// cards, err := piv.Cards()
	// var ykey *piv.YubiKey
	// for _, card := range cards {
	// 	if strings.Contains(strings.ToLower(card), "yubikey") {
	// 		if ykey, err = piv.Open(card); err != nil {
	// 			fmt.Printf("unable to open yubikey %v", err)
	// 			os.Exit(1)
	// 		}
	// 		break
	// 	}
	// }
	// defer ykey.Close()

	// cert, err := ykey.Certificate(piv.SlotSignature)
	// auth := piv.KeyAuth{PIN: piv.DefaultPIN}
	// priv, err := ykey.PrivateKey(piv.SlotSignature, cert.PublicKey, auth)
	// r, ok := priv.(crypto.Signer)


	// ############# PKCS11

	// export SOFTHSM2_CONF=/path/to/softhsm.conf
	// config := &crypto11.Config{
	// 	Path:       "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",
	// 	TokenLabel: "token1",
	// 	Pin:        "mynewpin",
	// }

	// cctx, err := crypto11.Configure(config)

	// defer cctx.Close()

	// r, err := salpkcs.NewPKCSCrypto(&salpkcs.PKCS{
	// 	Context:        cctx,
	// 	PkcsId:         nil,                 //softhsm
	// 	PkcsLabel:      []byte("keylabel1"), //softhsm
	// 	PublicCertFile: "client.crt",        //softhsm
	// })


	// ===================================

	claims := &jwt.RegisteredClaims{
		ExpiresAt: &jwt.NumericDate{time.Now().Add(time.Minute * 1)},
		Issuer:    "test",
	}

	jwtsigner.SigningMethodSignerRS256.Override()
	token := jwt.NewWithClaims(jwtsigner.SigningMethodSignerRS256, claims)

	keyctx, err := jwtsigner.NewSignerContext(ctx, &jwtsigner.SignerConfig{
		Signer: r,
	})

	token.Header["kid"] = "1212"

	tokenString, err := token.SignedString(keyctx)

	fmt.Printf("TOKEN: %s\n", tokenString)

	// // verify with embedded publickey
	keyFunc, err := jwtsigner.SignerVerfiyKeyfunc(ctx, &jwtsigner.SignerConfig{
		Signer: r,
	})

	vtoken, err := jwt.Parse(tokenString, keyFunc)

	if vtoken.Valid {
		log.Println("     verified with Signer PublicKey")
	}

}

The output is a signed JWT

# cd examples/

$ go run main.go 
TOKEN: eyJhbGciOiJSUzI1NiIsImtpZCI6IjEyMTIiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE2NjAzMjk2OTcsImlzcyI6InRlc3QifQ.jcvMEHXKVAdjgGQM6n7U9y0wkJKIdwCmQu2SNrz67L6G5gN0aGBGVaANcQ4iCJ3BM-r92GCdzIr3SlDtBs9C-9EDXzIygp41Xct66jbeqcJ4Udkf_5nHDgKyyMuxLnlkQO5SD9aZYHacJtv34P7THeAA6WUoVhsTYg5QvE0pDDkWf4PYeADh_gP7wnFha1jjjwMDPWhNyJhxSICBQ4I8s_s8FhWNr_shXqMwYPZj3fEabHbsRAZIEr8Y2nQAsQHAE97rU8CutShsQeY59WkHy04zx2HHbBepM6nnSHqtWFkh12eT4-8TvaMBNX9yv20ln6OHaKaIf3RpsreAFPf_TQ
2022/08/12 14:40:37      verified with Signer PublicKey
2022/08/12 14:40:37      verified with exported PubicKey

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewSignerContext

func NewSignerContext(parent context.Context, val *SignerConfig) (context.Context, error)

func SignerVerfiyKeyfunc

func SignerVerfiyKeyfunc(ctx context.Context, config *SignerConfig) (jwt.Keyfunc, error)

Types

type SignerConfig

type SignerConfig struct {
	Signer crypto.Signer
	// contains filtered or unexported fields
}

func SignerFromContext

func SignerFromContext(ctx context.Context) (*SignerConfig, bool)

func (*SignerConfig) GetPublicKey

func (k *SignerConfig) GetPublicKey() crypto.PublicKey

type SigningMethodCryptoSigner

type SigningMethodCryptoSigner struct {
	// contains filtered or unexported fields
}
var (
	SigningMethodSignerRS256 *SigningMethodCryptoSigner
	SigningMethodSignerPS256 *SigningMethodCryptoSigner
	SigningMethodSignerES256 *SigningMethodCryptoSigner
)

func (*SigningMethodCryptoSigner) Alg

func (*SigningMethodCryptoSigner) Hash

func (*SigningMethodCryptoSigner) Override

func (s *SigningMethodCryptoSigner) Override()

func (*SigningMethodCryptoSigner) Sign

func (s *SigningMethodCryptoSigner) Sign(signingString string, key interface{}) ([]byte, error)

func (*SigningMethodCryptoSigner) Verify

func (s *SigningMethodCryptoSigner) Verify(signingString string, signature []byte, key interface{}) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL