Skip to content

Commit 28ac4a7

Browse files
Aliaksandr Mianzhynskilunnytechknowlogick
authored
Add EdDSA JWT signing algorithm (#16786)
* Add EdDSA signing algorithm * Fix typo Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
1 parent 29b971b commit 28ac4a7

File tree

4 files changed

+76
-9
lines changed

4 files changed

+76
-9
lines changed

Diff for: custom/conf/app.example.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ INTERNAL_TOKEN=
392392
;; Enables OAuth2 provider
393393
ENABLE = true
394394
;;
395-
;; Algorithm used to sign OAuth2 tokens. Valid values: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512
395+
;; Algorithm used to sign OAuth2 tokens. Valid values: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, EdDSA
396396
;JWT_SIGNING_ALGORITHM = RS256
397397
;;
398398
;; Private key file path used to sign OAuth2 tokens. The path is relative to APP_DATA_PATH.

Diff for: routers/web/user/oauth.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ func AccessTokenOAuth(ctx *context.Context) {
546546

547547
signingKey := oauth2.DefaultSigningKey
548548
if signingKey.IsSymmetric() {
549-
clientKey, err := oauth2.CreateJWTSingingKey(signingKey.SigningMethod().Alg(), []byte(form.ClientSecret))
549+
clientKey, err := oauth2.CreateJWTSigningKey(signingKey.SigningMethod().Alg(), []byte(form.ClientSecret))
550550
if err != nil {
551551
handleAccessTokenError(ctx, AccessTokenError{
552552
ErrorCode: AccessTokenErrorCodeInvalidRequest,

Diff for: routers/web/user/oauth_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
func createAndParseToken(t *testing.T, grant *models.OAuth2Grant) *oauth2.OIDCToken {
18-
signingKey, err := oauth2.CreateJWTSingingKey("HS256", make([]byte, 32))
18+
signingKey, err := oauth2.CreateJWTSigningKey("HS256", make([]byte, 32))
1919
assert.NoError(t, err)
2020
assert.NotNil(t, signingKey)
2121
oauth2.DefaultSigningKey = signingKey

Diff for: services/auth/source/oauth2/jwtsigningkey.go

+73-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package oauth2
66

77
import (
88
"crypto/ecdsa"
9+
"crypto/ed25519"
910
"crypto/elliptic"
1011
"crypto/rand"
1112
"crypto/rsa"
@@ -129,6 +130,57 @@ func (key rsaSingingKey) PreProcessToken(token *jwt.Token) {
129130
token.Header["kid"] = key.id
130131
}
131132

133+
type eddsaSigningKey struct {
134+
signingMethod jwt.SigningMethod
135+
key ed25519.PrivateKey
136+
id string
137+
}
138+
139+
func newEdDSASingingKey(signingMethod jwt.SigningMethod, key ed25519.PrivateKey) (eddsaSigningKey, error) {
140+
kid, err := createPublicKeyFingerprint(key.Public().(ed25519.PublicKey))
141+
if err != nil {
142+
return eddsaSigningKey{}, err
143+
}
144+
145+
return eddsaSigningKey{
146+
signingMethod,
147+
key,
148+
base64.RawURLEncoding.EncodeToString(kid),
149+
}, nil
150+
}
151+
152+
func (key eddsaSigningKey) IsSymmetric() bool {
153+
return false
154+
}
155+
156+
func (key eddsaSigningKey) SigningMethod() jwt.SigningMethod {
157+
return key.signingMethod
158+
}
159+
160+
func (key eddsaSigningKey) SignKey() interface{} {
161+
return key.key
162+
}
163+
164+
func (key eddsaSigningKey) VerifyKey() interface{} {
165+
return key.key.Public()
166+
}
167+
168+
func (key eddsaSigningKey) ToJWK() (map[string]string, error) {
169+
pubKey := key.key.Public().(ed25519.PublicKey)
170+
171+
return map[string]string{
172+
"alg": key.SigningMethod().Alg(),
173+
"kid": key.id,
174+
"kty": "OKP",
175+
"crv": "Ed25519",
176+
"x": base64.RawURLEncoding.EncodeToString(pubKey),
177+
}, nil
178+
}
179+
180+
func (key eddsaSigningKey) PreProcessToken(token *jwt.Token) {
181+
token.Header["kid"] = key.id
182+
}
183+
132184
type ecdsaSingingKey struct {
133185
signingMethod jwt.SigningMethod
134186
key *ecdsa.PrivateKey
@@ -194,8 +246,8 @@ func createPublicKeyFingerprint(key interface{}) ([]byte, error) {
194246
return checksum[:], nil
195247
}
196248

197-
// CreateJWTSingingKey creates a signing key from an algorithm / key pair.
198-
func CreateJWTSingingKey(algorithm string, key interface{}) (JWTSigningKey, error) {
249+
// CreateJWTSigningKey creates a signing key from an algorithm / key pair.
250+
func CreateJWTSigningKey(algorithm string, key interface{}) (JWTSigningKey, error) {
199251
var signingMethod jwt.SigningMethod
200252
switch algorithm {
201253
case "HS256":
@@ -218,11 +270,19 @@ func CreateJWTSingingKey(algorithm string, key interface{}) (JWTSigningKey, erro
218270
signingMethod = jwt.SigningMethodES384
219271
case "ES512":
220272
signingMethod = jwt.SigningMethodES512
273+
case "EdDSA":
274+
signingMethod = jwt.SigningMethodEdDSA
221275
default:
222276
return nil, ErrInvalidAlgorithmType{algorithm}
223277
}
224278

225279
switch signingMethod.(type) {
280+
case *jwt.SigningMethodEd25519:
281+
privateKey, ok := key.(ed25519.PrivateKey)
282+
if !ok {
283+
return nil, jwt.ErrInvalidKeyType
284+
}
285+
return newEdDSASingingKey(signingMethod, privateKey)
226286
case *jwt.SigningMethodECDSA:
227287
privateKey, ok := key.(*ecdsa.PrivateKey)
228288
if !ok {
@@ -271,17 +331,19 @@ func InitSigningKey() error {
271331
case "ES384":
272332
fallthrough
273333
case "ES512":
334+
fallthrough
335+
case "EdDSA":
274336
key, err = loadOrCreateAsymmetricKey()
275337

276338
default:
277339
return ErrInvalidAlgorithmType{setting.OAuth2.JWTSigningAlgorithm}
278340
}
279341

280342
if err != nil {
281-
return fmt.Errorf("Error while loading or creating symmetric key: %v", err)
343+
return fmt.Errorf("Error while loading or creating JWT key: %v", err)
282344
}
283345

284-
signingKey, err := CreateJWTSingingKey(setting.OAuth2.JWTSigningAlgorithm, key)
346+
signingKey, err := CreateJWTSigningKey(setting.OAuth2.JWTSigningAlgorithm, key)
285347
if err != nil {
286348
return err
287349
}
@@ -324,10 +386,15 @@ func loadOrCreateAsymmetricKey() (interface{}, error) {
324386
if !isExist {
325387
err := func() error {
326388
key, err := func() (interface{}, error) {
327-
if strings.HasPrefix(setting.OAuth2.JWTSigningAlgorithm, "RS") {
389+
switch {
390+
case strings.HasPrefix(setting.OAuth2.JWTSigningAlgorithm, "RS"):
328391
return rsa.GenerateKey(rand.Reader, 4096)
392+
case setting.OAuth2.JWTSigningAlgorithm == "EdDSA":
393+
_, pk, err := ed25519.GenerateKey(rand.Reader)
394+
return pk, err
395+
default:
396+
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
329397
}
330-
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
331398
}()
332399
if err != nil {
333400
return err

0 commit comments

Comments
 (0)