From c164908904a3087e17cf946d0e65d5b99f3978f1 Mon Sep 17 00:00:00 2001 From: dominicriordan Date: Fri, 28 Apr 2023 16:39:29 +0100 Subject: [PATCH 1/2] create all available generic signers --- pkgs/jwt-signer/ecdsa/ecdsa.go | 44 ------------ pkgs/jwt-signer/ed25519/ed25519.go | 44 ------------ pkgs/jwt-signer/rsa256/rsa256.go | 44 ------------ pkgs/jwt-signer/rsa512/rsa512.go | 44 ------------ pkgs/jwt-signer/signer.go | 105 ++++++++++++++++++++++++----- 5 files changed, 90 insertions(+), 191 deletions(-) delete mode 100644 pkgs/jwt-signer/ecdsa/ecdsa.go delete mode 100644 pkgs/jwt-signer/ed25519/ed25519.go delete mode 100644 pkgs/jwt-signer/rsa256/rsa256.go delete mode 100644 pkgs/jwt-signer/rsa512/rsa512.go diff --git a/pkgs/jwt-signer/ecdsa/ecdsa.go b/pkgs/jwt-signer/ecdsa/ecdsa.go deleted file mode 100644 index 3c955c6..0000000 --- a/pkgs/jwt-signer/ecdsa/ecdsa.go +++ /dev/null @@ -1,44 +0,0 @@ -package ecdsa - -import ( - "crypto/ecdsa" - "github.com/domsolutions/gopayloader/pkgs/jwt-signer/definition" - "github.com/golang-jwt/jwt" - "github.com/pterm/pterm" -) - -type SignerECDSA struct { - kid string - privKey *ecdsa.PrivateKey -} - -func Signer(privKey []byte, kid string) (definition.Signer, error) { - ecdsaKey, err := jwt.ParseECPrivateKeyFromPEM(privKey) - if err != nil { - pterm.Debug.Printf("Failed to parse ECDSA private key %v", err) - return nil, err - } - - s := &SignerECDSA{ - kid: kid, - privKey: ecdsaKey, - } - claim := make(jwt.MapClaims) - claim["test"] = true - if _, err := s.Generate(claim); err != nil { - pterm.Debug.Printf("Failed to generate ECDSA jwt %v", err) - return nil, err - } - return s, nil -} - -func (e *SignerECDSA) Generate(claims jwt.MapClaims) (string, error) { - token := jwt.NewWithClaims(jwt.SigningMethodES256, claims) - token.Header["kid"] = e.kid - - t, err := token.SignedString(e.privKey) - if err != nil { - return "", err - } - return t, nil -} diff --git a/pkgs/jwt-signer/ed25519/ed25519.go b/pkgs/jwt-signer/ed25519/ed25519.go deleted file mode 100644 index 8dd5749..0000000 --- a/pkgs/jwt-signer/ed25519/ed25519.go +++ /dev/null @@ -1,44 +0,0 @@ -package ecdsa - -import ( - "crypto/ed25519" - "github.com/domsolutions/gopayloader/pkgs/jwt-signer/definition" - "github.com/golang-jwt/jwt" - "github.com/pterm/pterm" -) - -type SignerED25519 struct { - kid string - privKey ed25519.PrivateKey -} - -func Signer(privKey []byte, kid string) (definition.Signer, error) { - edKey, err := jwt.ParseEdPrivateKeyFromPEM(privKey) - if err != nil { - pterm.Debug.Printf("Failed to parse ED25519 private key %v", err) - return nil, err - } - - s := &SignerED25519{ - kid: kid, - privKey: edKey.(ed25519.PrivateKey), - } - claim := make(jwt.MapClaims) - claim["test"] = true - if _, err := s.Generate(claim); err != nil { - pterm.Debug.Printf("Failed to generate ED25519 jwt %v", err) - return nil, err - } - return s, nil -} - -func (e *SignerED25519) Generate(claims jwt.MapClaims) (string, error) { - token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, claims) - token.Header["kid"] = e.kid - - t, err := token.SignedString(e.privKey) - if err != nil { - return "", err - } - return t, nil -} diff --git a/pkgs/jwt-signer/rsa256/rsa256.go b/pkgs/jwt-signer/rsa256/rsa256.go deleted file mode 100644 index dff1e9c..0000000 --- a/pkgs/jwt-signer/rsa256/rsa256.go +++ /dev/null @@ -1,44 +0,0 @@ -package rsa256 - -import ( - "crypto/rsa" - "github.com/domsolutions/gopayloader/pkgs/jwt-signer/definition" - "github.com/golang-jwt/jwt" - "github.com/pterm/pterm" -) - -type SignerRSA256 struct { - kid string - privKey *rsa.PrivateKey -} - -func Signer(privKey []byte, kid string) (definition.Signer, error) { - rsaKey, err := jwt.ParseRSAPrivateKeyFromPEM(privKey) - if err != nil { - pterm.Debug.Printf("Failed to parse RSA256 private key %v", err) - return nil, err - } - - s := &SignerRSA256{ - kid: kid, - privKey: rsaKey, - } - claim := make(jwt.MapClaims) - claim["test"] = true - if _, err := s.Generate(claim); err != nil { - pterm.Debug.Printf("Failed to generate RSA256 jwt %v", err) - return nil, err - } - return s, nil -} - -func (e *SignerRSA256) Generate(claims jwt.MapClaims) (string, error) { - token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) - token.Header["kid"] = e.kid - - t, err := token.SignedString(e.privKey) - if err != nil { - return "", err - } - return t, nil -} diff --git a/pkgs/jwt-signer/rsa512/rsa512.go b/pkgs/jwt-signer/rsa512/rsa512.go deleted file mode 100644 index d4a12b1..0000000 --- a/pkgs/jwt-signer/rsa512/rsa512.go +++ /dev/null @@ -1,44 +0,0 @@ -package rsa256 - -import ( - "crypto/rsa" - "github.com/domsolutions/gopayloader/pkgs/jwt-signer/definition" - "github.com/golang-jwt/jwt" - "github.com/pterm/pterm" -) - -type SignerRSA512 struct { - kid string - privKey *rsa.PrivateKey -} - -func Signer(privKey []byte, kid string) (definition.Signer, error) { - rsaKey, err := jwt.ParseRSAPrivateKeyFromPEM(privKey) - if err != nil { - pterm.Debug.Printf("Failed to parse RSA512 private key %v", err) - return nil, err - } - - s := &SignerRSA512{ - kid: kid, - privKey: rsaKey, - } - claim := make(jwt.MapClaims) - claim["test"] = true - if _, err := s.Generate(claim); err != nil { - pterm.Debug.Printf("Failed to generate RSA512 jwt %v", err) - return nil, err - } - return s, nil -} - -func (e *SignerRSA512) Generate(claims jwt.MapClaims) (string, error) { - token := jwt.NewWithClaims(jwt.SigningMethodRS512, claims) - token.Header["kid"] = e.kid - - t, err := token.SignedString(e.privKey) - if err != nil { - return "", err - } - return t, nil -} diff --git a/pkgs/jwt-signer/signer.go b/pkgs/jwt-signer/signer.go index a8d9c9c..bad7611 100644 --- a/pkgs/jwt-signer/signer.go +++ b/pkgs/jwt-signer/signer.go @@ -1,30 +1,105 @@ package jwt_signer import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" "errors" "github.com/domsolutions/gopayloader/pkgs/jwt-signer/definition" - "github.com/domsolutions/gopayloader/pkgs/jwt-signer/ecdsa" - ed25519 "github.com/domsolutions/gopayloader/pkgs/jwt-signer/ed25519" - "github.com/domsolutions/gopayloader/pkgs/jwt-signer/rsa256" - rsa512 "github.com/domsolutions/gopayloader/pkgs/jwt-signer/rsa512" + "github.com/golang-jwt/jwt" + "github.com/pterm/pterm" ) -type Signer func(privKey []byte, kid string) (definition.Signer, error) +func CreateSigner(privKey []byte, kid string) (definition.Signer, error) { + var signer definition.Signer -// TODO add more signers, use generics? + signer, err := createSigner[*ecdsa.PrivateKey](privKey, kid, jwt.ParseECPrivateKeyFromPEM, jwt.SigningMethodES256) + if err == nil { + return signer, nil + } + signer, err = createSigner[*ecdsa.PrivateKey](privKey, kid, jwt.ParseECPrivateKeyFromPEM, jwt.SigningMethodES384) + if err == nil { + return signer, nil + } + signer, err = createSigner[*ecdsa.PrivateKey](privKey, kid, jwt.ParseECPrivateKeyFromPEM, jwt.SigningMethodES512) + if err == nil { + return signer, nil + } + signer, err = createSigner[crypto.PrivateKey](privKey, kid, jwt.ParseEdPrivateKeyFromPEM, jwt.SigningMethodEdDSA) + if err == nil { + return signer, nil + } + signer, err = createSigner[*rsa.PrivateKey](privKey, kid, jwt.ParseRSAPrivateKeyFromPEM, jwt.SigningMethodRS512) + if err == nil { + return signer, nil + } + signer, err = createSigner[*rsa.PrivateKey](privKey, kid, jwt.ParseRSAPrivateKeyFromPEM, jwt.SigningMethodRS256) + if err == nil { + return signer, nil + } + signer, err = createSigner[*rsa.PrivateKey](privKey, kid, jwt.ParseRSAPrivateKeyFromPEM, jwt.SigningMethodRS384) + if err == nil { + return signer, nil + } -var signers = []Signer{ecdsa.Signer, ed25519.Signer, rsa256.Signer, rsa512.Signer} + signer, err = createSigner[[]byte](privKey, kid, func(key []byte) ([]byte, error) { + return key, nil + }, jwt.SigningMethodHS256) + if err == nil { + return signer, nil + } -func CreateSigner(privKey []byte, kid string) (definition.Signer, error) { - var signer definition.Signer - var err error - for _, s := range signers { - signer, err = s(privKey, kid) - if err != nil { - continue - } + signer, err = createSigner[[]byte](privKey, kid, func(key []byte) ([]byte, error) { + return key, nil + }, jwt.SigningMethodHS384) + if err == nil { + return signer, nil + } + + signer, err = createSigner[[]byte](privKey, kid, func(key []byte) ([]byte, error) { + return key, nil + }, jwt.SigningMethodHS512) + if err == nil { return signer, nil } return nil, errors.New("no supported jwt signer") } + +type signer struct { + kid string + privKey any + method jwt.SigningMethod +} + +func (e *signer) Generate(claims jwt.MapClaims) (string, error) { + token := jwt.NewWithClaims(e.method, claims) + token.Header["kid"] = e.kid + + t, err := token.SignedString(e.privKey) + if err != nil { + return "", err + } + return t, nil +} + +func createSigner[k any](privKey []byte, kid string, genPrivKey func(key []byte) (k, error), method jwt.SigningMethod) (definition.Signer, error) { + key, err := genPrivKey(privKey) + if err != nil { + pterm.Debug.Printf("Failed to parse private key %v", err) + return nil, err + } + + s := &signer{ + kid: kid, + privKey: key, + method: method, + } + claim := make(jwt.MapClaims) + claim["test"] = true + if _, err := s.Generate(claim); err != nil { + pterm.Debug.Printf("Failed to generate jwt %v", err) + return nil, err + } + return s, nil +} From 7d37c3fded70f88bf0f443d6f644e297b5e91364 Mon Sep 17 00:00:00 2001 From: dominicriordan Date: Fri, 28 Apr 2023 18:11:34 +0100 Subject: [PATCH 2/2] fix bug where does not read jwt count correctly as jwt count of 10 uint64 format contains new line ascii code --- .gitignore | 3 +++ build-release.sh | 5 ++++ pkgs/jwt-generator/cache.go | 14 +++++++----- pkgs/jwt-generator/jwt.go | 2 +- pkgs/payloader/payloader_test.go | 39 ++++++++++++++++++++++++++++++++ test/rsa.private | 15 ++++++++++++ 6 files changed, 71 insertions(+), 7 deletions(-) create mode 100755 build-release.sh create mode 100644 test/rsa.private diff --git a/.gitignore b/.gitignore index 647e318..7a4cace 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ server_* *.qlog gopayloader.exe gopayloader.zip +gopayloader-darwin-amd64 +gopayloader-linux-amd64 +gopayloader-windows-amd64.exe diff --git a/build-release.sh b/build-release.sh new file mode 100755 index 0000000..f9d096e --- /dev/null +++ b/build-release.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +GOOS=windows go build -o gopayloader-windows-amd64.exe ./ +GOOS=linux go build -o gopayloader-linux-amd64 ./ +GOOS=darwin go build -o gopayloader-darwin-amd64 ./ \ No newline at end of file diff --git a/pkgs/jwt-generator/cache.go b/pkgs/jwt-generator/cache.go index 5d7e5f2..885ea8c 100644 --- a/pkgs/jwt-generator/cache.go +++ b/pkgs/jwt-generator/cache.go @@ -22,12 +22,12 @@ func newCache(f *os.File) (*cache, error) { c.scanner = bufio.NewScanner(c.f) c.scanner.Split(bufio.ScanLines) if c.scanner.Scan() { - meta := c.scanner.Bytes() - if len(meta) < 8 { - return nil, fmt.Errorf("jwt_generator: corrupt jwt cache, wanted 8 bytes got %d", len(meta)) + bb := make([]byte, 8) + _, err := f.ReadAt(bb, 0) + if err != nil { + return nil, err } - c.count = int64(binary.LittleEndian.Uint64(meta[0:8])) - + c.count = int64(binary.LittleEndian.Uint64(bb)) return &c, nil } return &c, nil @@ -115,11 +115,13 @@ func (c *cache) save(tokens []string) error { } b := make([]byte, 8) - binary.LittleEndian.PutUint64(b, uint64(int64(add)+c.count)) + newCount := uint64(int64(add) + c.count) + binary.LittleEndian.PutUint64(b, newCount) _, err = c.f.WriteAt(b, 0) if err != nil { return err } + _, err = c.f.WriteAt([]byte{byte('\n')}, 9) if err != nil { return err diff --git a/pkgs/jwt-generator/jwt.go b/pkgs/jwt-generator/jwt.go index fc67247..5bb279d 100644 --- a/pkgs/jwt-generator/jwt.go +++ b/pkgs/jwt-generator/jwt.go @@ -81,7 +81,7 @@ func (j *JWTGenerator) Generate(reqJwtCount int64, dir string, retrying bool) er return err } f.Close() - pterm.Error.Printf("jwt cache %s file corrupt, attempting to delete and recreate", fname) + pterm.Debug.Printf("jwt cache %s file corrupt, attempting to delete and recreate; got error; %v \n", fname, err) if err := os.Remove(fname); err != nil { pterm.Error.Printf("Couldn't remove cache file %s; %v", fname, err) return err diff --git a/pkgs/payloader/payloader_test.go b/pkgs/payloader/payloader_test.go index a6be4d5..c1f372e 100644 --- a/pkgs/payloader/payloader_test.go +++ b/pkgs/payloader/payloader_test.go @@ -277,6 +277,45 @@ func testPayLoader_Run(t *testing.T, addr, client string) { } }, }, + { + name: "GET RSA JWT", + fields: fields{config: &config.Config{ + Ctx: context.Background(), + ReqURI: addr, + ReqTarget: 10, + Conns: 1, + ReadTimeout: 5 * time.Second, + WriteTimeout: 5 * time.Second, + Method: "GET", + Client: client, + VerboseTicker: time.Second, + Headers: []string{"content-type: application/json"}, + JwtHeader: "some-jwt", + JwtAud: "some-aud", + JwtSub: "some-subject", + JwtIss: "some-issuer", + JwtKID: "13325575tevdfbdsfsf", + JwtKey: filepath.Join("..", "..", "test", "rsa.private"), + SkipVerify: true, + }}, + want: &GoPayloaderResults{ + CompletedReqs: 10, + FailedReqs: 0, + Responses: map[worker.ResponseCode]int64{ + 200: 10, + }, + Errors: nil, + }, + check: func(t *testing.T) { + _, err := os.OpenFile(filepath.Join(JwtCacheDir, "gopayloader-jwtstore-ce2db7adfae3270cb01fd7053b035243213d6e6bbd9ea917ee656eacb94e22e2.txt"), os.O_RDONLY, os.ModePerm) + if err != nil { + if os.IsNotExist(err) { + t.Fatal(err) + } + t.Fatal(err) + } + }, + }, { name: "Error hostname incorrect format - missing port", fields: fields{config: &config.Config{ diff --git a/test/rsa.private b/test/rsa.private new file mode 100644 index 0000000..26f0f92 --- /dev/null +++ b/test/rsa.private @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDShDiKX/Lexe5b0Ew4FE/puWYiKuSHQgsa1D0EJurpUY4BIEe6 +EdYHtPq2Vv2xT1xOCQEKSd8BwOu78btVsrTCPPkJw7+ll9DZSDAjbesE1n15/aCW +FaO9myWM5O+RQ0HXAHACL5BWFNAvAoyD+JR9Yw1Z+7cHIPKiwDBgD42KKwIDAQAB +AoGAWciYkLOxUr/aFAB3sWdAWe9/lszyYJmTQOMKDu5GPDJTPTm2Pa6DuQ+/6eqa +EnhFZubCMdAls4rDP4oumrM4EeTJ+wogKOyQ8m7iZIxVl/dpPBd1RaC6nSVM7J+o +t3LhhssVQ/o9TF/dwk1WmKPFwtmyI1scUyYzuZ2ouTznXtkCQQD9I6mAac+EgU6Q +ZtS+iFnKe4l1vzrf5/uYr+3Gm1eqcRX5q09PyolwJUoi8wB8K1UQBRFWpHxC14EW +aBa2LOenAkEA1OU//HPuj0SrlzgNefEoygjG0vPNLtyvaKBNeuBdNdqaUL5/Yywz +ArWzMdtGTR6poBO2rWjx6yY+LjLLz8vZ3QJBAKWAi3HJvEOFxzfiA3YO76XS3yx8 +uqFpqrVJUMxpBAgLp7J0roYchX8s4iu3dLm6GwM+TPe40wVgoKVlqHOzKEECQFRX +Gbk+iFSzpLK8nwIfGsSnI3Uw5qlY/hiZ4Pf76JFML/Qq87ZrLS42o23t63Tj39kt +1iHuwGAi/2E3+Gwy2vUCQQC4VHT+5z2qHMngQgDBg3N6hfg3FBQ4wDCvsiZVeE1o +VXSt148WA4oAPPMwNettx7KK9uWQsNysaIoq1uJX9AoR +-----END RSA PRIVATE KEY-----