Skip to content

Commit 5058c76

Browse files
author
Earl Warren
committed
Merge pull request '[v9.0/forgejo] bug: correctly generate oauth2 jwt signing key' (go-gitea#5992) from bp-v9.0/forgejo-7d59060 into v9.0/forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/5992 Reviewed-by: Earl Warren <[email protected]>
2 parents 6569f1f + 90e05e7 commit 5058c76

File tree

2 files changed

+136
-2
lines changed

2 files changed

+136
-2
lines changed

services/auth/source/oauth2/jwtsigningkey.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,30 @@ func loadOrCreateAsymmetricKey() (any, error) {
347347
key, err := func() (any, error) {
348348
switch {
349349
case strings.HasPrefix(setting.OAuth2.JWTSigningAlgorithm, "RS"):
350-
return rsa.GenerateKey(rand.Reader, 4096)
350+
var bits int
351+
switch setting.OAuth2.JWTSigningAlgorithm {
352+
case "RS256":
353+
bits = 2048
354+
case "RS384":
355+
bits = 3072
356+
case "RS512":
357+
bits = 4096
358+
}
359+
return rsa.GenerateKey(rand.Reader, bits)
351360
case setting.OAuth2.JWTSigningAlgorithm == "EdDSA":
352361
_, pk, err := ed25519.GenerateKey(rand.Reader)
353362
return pk, err
354363
default:
355-
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
364+
var curve elliptic.Curve
365+
switch setting.OAuth2.JWTSigningAlgorithm {
366+
case "ES256":
367+
curve = elliptic.P256()
368+
case "ES384":
369+
curve = elliptic.P384()
370+
case "ES512":
371+
curve = elliptic.P521()
372+
}
373+
return ecdsa.GenerateKey(curve, rand.Reader)
356374
}
357375
}()
358376
if err != nil {
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2024 The Forgejo Authors. All rights reserved.
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
package oauth2
5+
6+
import (
7+
"crypto/ecdsa"
8+
"crypto/ed25519"
9+
"crypto/rsa"
10+
"crypto/x509"
11+
"encoding/pem"
12+
"os"
13+
"path/filepath"
14+
"testing"
15+
16+
"code.gitea.io/gitea/modules/setting"
17+
"code.gitea.io/gitea/modules/test"
18+
19+
"github.com/stretchr/testify/assert"
20+
"github.com/stretchr/testify/require"
21+
)
22+
23+
func TestLoadOrCreateAsymmetricKey(t *testing.T) {
24+
loadKey := func(t *testing.T) any {
25+
t.Helper()
26+
loadOrCreateAsymmetricKey()
27+
28+
fileContent, err := os.ReadFile(setting.OAuth2.JWTSigningPrivateKeyFile)
29+
require.NoError(t, err)
30+
31+
block, _ := pem.Decode(fileContent)
32+
assert.NotNil(t, block)
33+
assert.EqualValues(t, "PRIVATE KEY", block.Type)
34+
35+
parsedKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
36+
require.NoError(t, err)
37+
38+
return parsedKey
39+
}
40+
t.Run("RSA-2048", func(t *testing.T) {
41+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningPrivateKeyFile, filepath.Join(t.TempDir(), "jwt-rsa-2048.priv"))()
42+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "RS256")()
43+
44+
parsedKey := loadKey(t)
45+
46+
rsaPrivateKey := parsedKey.(*rsa.PrivateKey)
47+
assert.EqualValues(t, 2048, rsaPrivateKey.N.BitLen())
48+
49+
t.Run("Load key with differ specified algorithm", func(t *testing.T) {
50+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "EdDSA")()
51+
52+
parsedKey := loadKey(t)
53+
rsaPrivateKey := parsedKey.(*rsa.PrivateKey)
54+
assert.EqualValues(t, 2048, rsaPrivateKey.N.BitLen())
55+
})
56+
})
57+
58+
t.Run("RSA-3072", func(t *testing.T) {
59+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningPrivateKeyFile, filepath.Join(t.TempDir(), "jwt-rsa-3072.priv"))()
60+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "RS384")()
61+
62+
parsedKey := loadKey(t)
63+
64+
rsaPrivateKey := parsedKey.(*rsa.PrivateKey)
65+
assert.EqualValues(t, 3072, rsaPrivateKey.N.BitLen())
66+
})
67+
68+
t.Run("RSA-4096", func(t *testing.T) {
69+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningPrivateKeyFile, filepath.Join(t.TempDir(), "jwt-rsa-4096.priv"))()
70+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "RS512")()
71+
72+
parsedKey := loadKey(t)
73+
74+
rsaPrivateKey := parsedKey.(*rsa.PrivateKey)
75+
assert.EqualValues(t, 4096, rsaPrivateKey.N.BitLen())
76+
})
77+
78+
t.Run("ECDSA-256", func(t *testing.T) {
79+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningPrivateKeyFile, filepath.Join(t.TempDir(), "jwt-ecdsa-256.priv"))()
80+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "ES256")()
81+
82+
parsedKey := loadKey(t)
83+
84+
ecdsaPrivateKey := parsedKey.(*ecdsa.PrivateKey)
85+
assert.EqualValues(t, 256, ecdsaPrivateKey.Params().BitSize)
86+
})
87+
88+
t.Run("ECDSA-384", func(t *testing.T) {
89+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningPrivateKeyFile, filepath.Join(t.TempDir(), "jwt-ecdsa-384.priv"))()
90+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "ES384")()
91+
92+
parsedKey := loadKey(t)
93+
94+
ecdsaPrivateKey := parsedKey.(*ecdsa.PrivateKey)
95+
assert.EqualValues(t, 384, ecdsaPrivateKey.Params().BitSize)
96+
})
97+
98+
t.Run("ECDSA-512", func(t *testing.T) {
99+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningPrivateKeyFile, filepath.Join(t.TempDir(), "jwt-ecdsa-512.priv"))()
100+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "ES512")()
101+
102+
parsedKey := loadKey(t)
103+
104+
ecdsaPrivateKey := parsedKey.(*ecdsa.PrivateKey)
105+
assert.EqualValues(t, 521, ecdsaPrivateKey.Params().BitSize)
106+
})
107+
108+
t.Run("EdDSA", func(t *testing.T) {
109+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningPrivateKeyFile, filepath.Join(t.TempDir(), "jwt-eddsa.priv"))()
110+
defer test.MockVariableValue(&setting.OAuth2.JWTSigningAlgorithm, "EdDSA")()
111+
112+
parsedKey := loadKey(t)
113+
114+
assert.NotNil(t, parsedKey.(ed25519.PrivateKey))
115+
})
116+
}

0 commit comments

Comments
 (0)