@@ -6,6 +6,7 @@ package oauth2
66
77import (
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+
132184type 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