@@ -2,6 +2,8 @@ package jwt
22
33import (
44 "context"
5+ "crypto"
6+ "crypto/ecdsa"
57 "crypto/rsa"
68 "crypto/x509"
79 "encoding/json"
@@ -32,8 +34,8 @@ var byJwtTlsKeyPaths = sync.OnceValue(func() []string {
3234const expiryDuration = 30 * 24 * time .Hour
3335
3436// the first key (most recent version) is used to sign new JWTs
35- var byPrivateKeys = sync .OnceValue (func () []* rsa .PrivateKey {
36- keys := []* rsa .PrivateKey {}
37+ var byPrivateKeys = sync .OnceValue (func () []crypto .PrivateKey {
38+ keys := []crypto .PrivateKey {}
3739 glog .Infof ("[jwt]paths: %s" , byJwtTlsKeyPaths ())
3840 errs := []error {}
3941 for _ , jwtTlsKeyPath := range byJwtTlsKeyPaths () {
@@ -49,21 +51,27 @@ var byPrivateKeys = sync.OnceValue(func() []*rsa.PrivateKey {
4951 panic (err )
5052 }
5153 block , _ := pem .Decode (bytes )
54+ fmt .Printf ("KEY PATH %s\n " , path )
5255
5356 keyPathErrs := []error {}
54- if key , err := x509 .ParsePKCS8PrivateKey (block .Bytes ); err == nil {
55- glog .Errorf ("[jwt]loaded pkcs8 key \" %s\" \n " , path )
56- keys = append (keys , key .( * rsa. PrivateKey ) )
57+ if key , err := x509 .ParseECPrivateKey (block .Bytes ); err == nil {
58+ glog .Errorf ("[jwt]loaded ec key \" %s\" \n " , path )
59+ keys = append (keys , key )
5760 } else {
58- keyPathErrs = append (keyPathErrs , err )
59- if key , err := x509 .ParsePKCS1PrivateKey (block .Bytes ); err == nil {
60- glog .Errorf ("[jwt]loaded pkcs1 key \" %s\" \n " , path )
61+ if key , err := x509 .ParsePKCS8PrivateKey (block .Bytes ); err == nil {
62+ glog .Errorf ("[jwt]loaded pkcs8 key \" %s\" \n " , path )
6163 keys = append (keys , key )
6264 } else {
6365 keyPathErrs = append (keyPathErrs , err )
64- err = errors .Join (keyPathErrs ... )
65- glog .Errorf ("[jwt]could not load key \" %s\" . err = %s\n " , path , err )
66- errs = append (errs , err )
66+ if key , err := x509 .ParsePKCS1PrivateKey (block .Bytes ); err == nil {
67+ glog .Errorf ("[jwt]loaded pkcs1 key \" %s\" \n " , path )
68+ keys = append (keys , key )
69+ } else {
70+ keyPathErrs = append (keyPathErrs , err )
71+ err = errors .Join (keyPathErrs ... )
72+ glog .Errorf ("[jwt]could not load key \" %s\" . err = %s\n " , path , err )
73+ errs = append (errs , err )
74+ }
6775 }
6876 }
6977 }
@@ -75,8 +83,24 @@ var byPrivateKeys = sync.OnceValue(func() []*rsa.PrivateKey {
7583 return keys
7684})
7785
78- func bySigningKey () * rsa.PrivateKey {
79- return byPrivateKeys ()[0 ]
86+ func byRsaSigningKey () * rsa.PrivateKey {
87+ for _ , key := range byPrivateKeys () {
88+ switch v := key .(type ) {
89+ case * rsa.PrivateKey :
90+ return v
91+ }
92+ }
93+ return nil
94+ }
95+
96+ func byEcdsaSigningKey () * ecdsa.PrivateKey {
97+ for _ , key := range byPrivateKeys () {
98+ switch v := key .(type ) {
99+ case * ecdsa.PrivateKey :
100+ return v
101+ }
102+ }
103+ return nil
80104}
81105
82106// the bringyour authorization model is:
@@ -173,13 +197,13 @@ func ParseByJwt(ctx context.Context, jwtSigned string) (*ByJwt, error) {
173197 // todo - ParseWithClaims instead of jwt.Parse
174198 // this will get newly added RegisteredClaims which includes ExipiresAt
175199 token , err = gojwt .Parse (jwtSigned , func (token * gojwt.Token ) (any , error ) {
176- return byPrivateKey .Public (), nil
200+ return byPrivateKey .( interface { Public () crypto. PublicKey }). Public (), nil
177201 }, parserOptions ... )
178202 if err == nil {
179203 break
180204 }
181205 }
182- if err ! = nil {
206+ if token = = nil {
183207 return nil , errors .New ("Could not verify signed token." )
184208 }
185209
@@ -258,13 +282,7 @@ func ParseByJwtUnverified(ctx context.Context, jwtStr string) (*ByJwt, error) {
258282// }
259283
260284func (self * ByJwt ) Sign () string {
261-
262- token := gojwt .NewWithClaims (gojwt .SigningMethodRS512 , self )
263- jwtSigned , err := token .SignedString (bySigningKey ())
264- if err != nil {
265- panic (err )
266- }
267- return jwtSigned
285+ return sign (self )
268286}
269287
270288func (self * ByJwt ) Client (deviceId server.Id , clientId server.Id ) * ByJwt {
@@ -491,3 +509,37 @@ func IsByJwtActive(ctx context.Context, byJwt *ByJwt) bool {
491509
492510 return ! hasInactiveSession
493511}
512+
513+ func sign (claims gojwt.Claims ) string {
514+ var signingMethod gojwt.SigningMethod
515+ var key any
516+
517+ if ecdsaKey := byEcdsaSigningKey (); ecdsaKey != nil {
518+ switch bitLen := ecdsaKey .Curve .Params ().N .BitLen (); bitLen {
519+ case 256 :
520+ signingMethod = gojwt .SigningMethodES256
521+ case 384 :
522+ signingMethod = gojwt .SigningMethodES384
523+ case 512 :
524+ signingMethod = gojwt .SigningMethodES512
525+ default :
526+ panic (fmt .Errorf ("Unsupported ECDSA bit len %d" , bitLen ))
527+ }
528+ key = ecdsaKey
529+ } else if rsaKey := byRsaSigningKey (); rsaKey != nil {
530+ if bitLen := rsaKey .N .BitLen (); 2048 <= bitLen {
531+ signingMethod = gojwt .SigningMethodRS512
532+ } else {
533+ panic (fmt .Errorf ("Unsupported RSA bit len %d" , bitLen ))
534+ }
535+ key = rsaKey
536+ } else {
537+ panic (fmt .Errorf ("No signing key found" ))
538+ }
539+ token := gojwt .NewWithClaims (signingMethod , claims )
540+ jwtSigned , err := token .SignedString (key )
541+ if err != nil {
542+ panic (err )
543+ }
544+ return jwtSigned
545+ }
0 commit comments