Skip to content

Commit

Permalink
Merge pull request #77 from cerberauth/jwt-signed-with-same-method
Browse files Browse the repository at this point in the history
feat: use the same jwt alg as the token
  • Loading branch information
emmanuelgautier authored Apr 2, 2024
2 parents e0c3cf1 + 82ef1d1 commit 05665d9
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 9 deletions.
63 changes: 63 additions & 0 deletions jwt/generate_keys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package jwt

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"errors"

"github.com/golang-jwt/jwt/v5"
)

func generateKey(method jwt.SigningMethod) (interface{}, error) {
switch method.Alg() {
case jwt.SigningMethodRS256.Alg(),
jwt.SigningMethodRS384.Alg(),
jwt.SigningMethodRS512.Alg(),
jwt.SigningMethodPS256.Alg(),
jwt.SigningMethodPS384.Alg(),
jwt.SigningMethodPS512.Alg():
privateKeyRS, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return "", err
}
return privateKeyRS, nil

case jwt.SigningMethodES256.Alg():
privateKeyES256, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return "", err
}
return privateKeyES256, nil

case jwt.SigningMethodES384.Alg():
privateKeyES384, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
if err != nil {
return "", err
}
return privateKeyES384, nil

case jwt.SigningMethodES512.Alg():
privateKeyES512, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
if err != nil {
return "", err
}
return privateKeyES512, nil

case jwt.SigningMethodHS256.Alg(),
jwt.SigningMethodHS384.Alg(),
jwt.SigningMethodHS512.Alg():
keyHS := make([]byte, 64)
_, err := rand.Read(keyHS)
if err != nil {
return "", err
}
return keyHS, nil

case jwt.SigningMethodNone.Alg():
return nil, nil
}

return "", errors.New("unsupported signing method")
}
11 changes: 8 additions & 3 deletions jwt/jwt_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ type JWTWriter struct {
}

func NewJWTWriter(token string) (*JWTWriter, error) {
// Parse the original JWT token
originalToken, _, err := new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
if err != nil {
return nil, err
Expand All @@ -25,10 +24,8 @@ func NewJWTWriter(token string) (*JWTWriter, error) {
}

func (j *JWTWriter) SignWithMethodAndKey(method jwt.SigningMethod, key interface{}) (string, error) {
// Create a new token with the new claims
newToken := jwt.NewWithClaims(method, j.Token.Claims)

// Sign the new token with the new secret key
tokenString, err := newToken.SignedString(key)
if err != nil {
return "", err
Expand All @@ -37,6 +34,14 @@ func (j *JWTWriter) SignWithMethodAndKey(method jwt.SigningMethod, key interface
return tokenString, nil
}

func (j *JWTWriter) SignWithMethodAndRandomKey(method jwt.SigningMethod) (string, error) {
key, err := generateKey(method)
if err != nil {
return "", err
}
return j.SignWithMethodAndKey(method, key)
}

func (j *JWTWriter) SignWithKey(key interface{}) (string, error) {
return j.SignWithMethodAndKey(j.Token.Method, key)
}
72 changes: 72 additions & 0 deletions jwt/jwt_writer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package jwt_test

import (
"testing"

"github.com/cerberauth/vulnapi/jwt"
libjwt "github.com/golang-jwt/jwt/v5"
"github.com/stretchr/testify/assert"
)

func TestJWTWriter_SignWithMethodAndRandomKey_WhenSigningMethodIsHS256(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
writer, _ := jwt.NewJWTWriter(token)

token, err := writer.SignWithMethodAndRandomKey(libjwt.SigningMethodHS256)
assert.NoError(t, err)
assert.NotEmpty(t, token)
}

func TestJWTWriter_SignWithMethodAndRandomKey_WhenSigningMethodIsRS256(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
writer, _ := jwt.NewJWTWriter(token)

token, err := writer.SignWithMethodAndRandomKey(libjwt.SigningMethodRS256)
assert.NoError(t, err)
assert.NotEmpty(t, token)
}

func TestJWTWriter_SignWithMethodAndRandomKey_WhenSigningMethodIsRS384(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
writer, _ := jwt.NewJWTWriter(token)

token, err := writer.SignWithMethodAndRandomKey(libjwt.SigningMethodRS384)
assert.NoError(t, err)
assert.NotEmpty(t, token)
}

func TestJWTWriter_SignWithMethodAndRandomKey_WhenSigningMethodIsRS512(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
writer, _ := jwt.NewJWTWriter(token)

token, err := writer.SignWithMethodAndRandomKey(libjwt.SigningMethodRS512)
assert.NoError(t, err)
assert.NotEmpty(t, token)
}

func TestJWTWriter_SignWithMethodAndRandomKey_WhenSigningMethodIsES256(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
writer, _ := jwt.NewJWTWriter(token)

token, err := writer.SignWithMethodAndRandomKey(libjwt.SigningMethodES256)
assert.NoError(t, err)
assert.NotEmpty(t, token)
}

func TestJWTWriter_SignWithMethodAndRandomKey_WhenSigningMethodIsES384(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
writer, _ := jwt.NewJWTWriter(token)

token, err := writer.SignWithMethodAndRandomKey(libjwt.SigningMethodES384)
assert.NoError(t, err)
assert.NotEmpty(t, token)
}

func TestJWTWriter_SignWithMethodAndRandomKey_WhenSigningMethodIsES512(t *testing.T) {
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
writer, _ := jwt.NewJWTWriter(token)

token, err := writer.SignWithMethodAndRandomKey(libjwt.SigningMethodES512)
assert.NoError(t, err)
assert.NotEmpty(t, token)
}
7 changes: 1 addition & 6 deletions scan/jwt/not_verified.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/cerberauth/vulnapi/internal/scan"
"github.com/cerberauth/vulnapi/jwt"
"github.com/cerberauth/vulnapi/report"
jwtlib "github.com/golang-jwt/jwt/v5"
)

const (
Expand All @@ -22,11 +21,7 @@ func NotVerifiedScanHandler(operation *request.Operation, ss auth.SecurityScheme
}

valueWriter := ss.GetValidValueWriter().(*jwt.JWTWriter)
method := jwtlib.SigningMethodHS256
if valueWriter.Token.Method == method {
method = jwtlib.SigningMethodHS384
}
newToken, err := valueWriter.SignWithMethodAndKey(method, []byte("a"))
newToken, err := valueWriter.SignWithMethodAndRandomKey(valueWriter.Token.Method)
if err != nil {
return r, err
}
Expand Down

0 comments on commit 05665d9

Please sign in to comment.