Skip to content

Commit

Permalink
Merge pull request #82 from artooro/fix-ed25519
Browse files Browse the repository at this point in the history
add support for EdDSA signing keys
ggicci authored May 28, 2024
2 parents 41ea1be + cc116c2 commit 5f1c2a8
Showing 2 changed files with 52 additions and 0 deletions.
9 changes: 9 additions & 0 deletions jwt.go
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package caddyjwt

import (
"context"
"crypto/ed25519"
"crypto/x509"
"encoding/base64"
"encoding/json"
@@ -232,6 +233,14 @@ func (ja *JWTAuth) keyProvider() jws.KeyProviderFunc {
return fmt.Errorf("key specified by kid %q not found in JWKs", kid)
}
sink.Key(ja.determineSigningAlgorithm(key.Algorithm(), sig.ProtectedHeaders().Algorithm()), key)
} else if ja.SignAlgorithm == string(jwa.EdDSA) {
if signKey, ok := ja.parsedSignKey.([]byte); !ok {
return fmt.Errorf("EdDSA key must be base64 encoded bytes")
} else if len(signKey) != ed25519.PublicKeySize {
return fmt.Errorf("key is not a proper ed25519 length")
} else {
sink.Key(jwa.EdDSA, ed25519.PublicKey(signKey))
}
} else {
sink.Key(ja.determineSigningAlgorithm(sig.ProtectedHeaders().Algorithm()), ja.parsedSignKey)
}
43 changes: 43 additions & 0 deletions jwt_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package caddyjwt

import (
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"encoding/base64"
@@ -47,6 +48,10 @@ hwIDAQAB
jwkPubKey jwk.Key // public key
jwkPubKeySet jwk.Set // public key set
jwkPubKeySetInapplicable jwk.Set // public key set (inapplicable)

// EdDSA test
jwkKeyEd25519 jwk.Key // private key for EdDSA test
TestSignKeyEd25519 string // base64 encoded public key
)

func init() {
@@ -61,6 +66,8 @@ func init() {
anotherPubKeyII, err := generateJWK().PublicKey()
panicOnError(err)

jwkKeyEd25519 = generateEdDSAJWK()

jwkPubKeySet = jwk.NewSet()
jwkPubKeySet.AddKey(anotherPubKeyI)
jwkPubKeySet.AddKey(jwkPubKey)
@@ -83,6 +90,18 @@ func generateJWK() jwk.Key {
return key
}

func generateEdDSAJWK() jwk.Key {
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
panicOnError(err)
TestSignKeyEd25519 = base64.StdEncoding.EncodeToString(publicKey)
key, err := jwk.FromRaw(privateKey)
panicOnError(err)
jwk.AssignKeyID(key)
key.Set(jwk.AlgorithmKey, jwa.EdDSA)
key.Set(jwk.KeyUsageKey, jwk.ForSignature)
return key
}

func publishJWKsOnLocalServer() {
go func() {
http.HandleFunc("/key", func(w http.ResponseWriter, r *http.Request) {
@@ -124,6 +143,16 @@ func issueTokenString(claims MapClaims) string {
return string(tokenBytes)
}

// issueTokenString issues a token string with the given claims,
// using EdDSA signing algorithm.
func issueTokenStringEdDSA(claims MapClaims) string {
token := buildToken(claims)
tokenBytes, err := jwt.Sign(token, jwt.WithKey(jwa.EdDSA, jwkKeyEd25519))
panicOnError(err)

return string(tokenBytes)
}

func issueTokenStringJWK(claims MapClaims) string {
token := buildToken(claims)
tokenBytes, err := jwt.Sign(token, jwt.WithKey(jwa.RS256, jwkKey))
@@ -186,6 +215,20 @@ func TestAuthenticate_FromAuthorizationHeader(t *testing.T) {
assert.Equal(t, User{ID: "ggicci"}, gotUser)
}

func TestAuthenticate_EdDSA(t *testing.T) {
claims := MapClaims{"sub": "ggicci"}
ja := &JWTAuth{SignKey: TestSignKeyEd25519, SignAlgorithm: string(jwa.EdDSA), logger: testLogger}
assert.Nil(t, ja.Validate())

rw := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/", nil)
r.Header.Add("Authorization", "Bearer "+issueTokenStringEdDSA(claims))
gotUser, authenticated, err := ja.Authenticate(rw, r)
assert.Nil(t, err)
assert.True(t, authenticated)
assert.Equal(t, User{ID: "ggicci"}, gotUser)
}

func TestAuthenticate_FromCustomHeader(t *testing.T) {
claims := MapClaims{"sub": "ggicci"}
ja := &JWTAuth{

0 comments on commit 5f1c2a8

Please sign in to comment.