Skip to content

Commit 9ff8bcd

Browse files
committed
[FIXED] Possible panic if server receives a maliciously crafted JWT
This addresses [CVE-2020-26521](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-26521) This is mainly a port of #1624 with some other updates related to tests. Signed-off-by: Ivan Kozlovic <[email protected]>
1 parent c0b574f commit 9ff8bcd

19 files changed

+112
-51
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module github.com/nats-io/nats-server/v2
22

33
require (
4-
github.com/nats-io/jwt v0.3.2
4+
github.com/nats-io/jwt v1.1.0
55
github.com/nats-io/nats.go v1.10.0
66
github.com/nats-io/nkeys v0.1.4
77
github.com/nats-io/nuid v1.0.1

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
1010
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
1111
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
1212
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
13+
github.com/nats-io/jwt v1.1.0 h1:+vOlgtM0ZsF46GbmUoadq0/2rChNS45gtxHEa3H1gqM=
14+
github.com/nats-io/jwt v1.1.0/go.mod h1:n3cvmLfBfnpV4JJRN7lRYCyZnw48ksGsbThGXEk4w9M=
1315
github.com/nats-io/nats.go v1.10.0 h1:L8qnKaofSfNFbXg0C5F71LdjPRnmQwSsA4ukmkt1TvY=
1416
github.com/nats-io/nats.go v1.10.0/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE=
1517
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=

server/accounts.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -1546,14 +1546,14 @@ func (a *Account) checkActivation(importAcc *Account, claim *jwt.Import, expTime
15461546
if err != nil {
15471547
return false
15481548
}
1549+
if !a.isIssuerClaimTrusted(act) {
1550+
return false
1551+
}
15491552
vr = jwt.CreateValidationResults()
15501553
act.Validate(vr)
15511554
if vr.IsBlocking(true) {
15521555
return false
15531556
}
1554-
if !a.isIssuerClaimTrusted(act) {
1555-
return false
1556-
}
15571557
if act.Expires != 0 {
15581558
tn := time.Now().Unix()
15591559
if act.Expires <= tn {

server/jwt_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -1575,13 +1575,14 @@ func TestAccountURLResolver(t *testing.T) {
15751575
defer ts.Close()
15761576

15771577
confTemplate := `
1578+
operator: %s
15781579
listen: -1
15791580
resolver: URL("%s/ngs/v1/accounts/jwt/")
15801581
resolver_tls {
15811582
insecure: true
15821583
}
15831584
`
1584-
conf := createConfFile(t, []byte(fmt.Sprintf(confTemplate, ts.URL)))
1585+
conf := createConfFile(t, []byte(fmt.Sprintf(confTemplate, ojwt, ts.URL)))
15851586
defer os.Remove(conf)
15861587

15871588
s, opts := RunServerWithConfig(conf)
@@ -1660,10 +1661,11 @@ func TestAccountURLResolverNoFetchOnReload(t *testing.T) {
16601661
defer ts.Close()
16611662

16621663
confTemplate := `
1664+
operator: %s
16631665
listen: -1
16641666
resolver: URL("%s/ngs/v1/accounts/jwt/")
16651667
`
1666-
conf := createConfFile(t, []byte(fmt.Sprintf(confTemplate, ts.URL)))
1668+
conf := createConfFile(t, []byte(fmt.Sprintf(confTemplate, ojwt, ts.URL)))
16671669
defer os.Remove(conf)
16681670

16691671
s, _ := RunServerWithConfig(conf)
@@ -1685,7 +1687,7 @@ func TestAccountURLResolverNoFetchOnReload(t *testing.T) {
16851687
}))
16861688
defer ts.Close()
16871689

1688-
changeCurrentConfigContentWithNewContent(t, conf, []byte(fmt.Sprintf(confTemplate, ts.URL)))
1690+
changeCurrentConfigContentWithNewContent(t, conf, []byte(fmt.Sprintf(confTemplate, ojwt, ts.URL)))
16891691

16901692
if err := s.Reload(); err != nil {
16911693
t.Fatalf("Error on reload: %v", err)

server/server.go

+3
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,9 @@ func (s *Server) verifyAccountClaims(claimJWT string) (*jwt.AccountClaims, strin
10831083
if err != nil {
10841084
return nil, _EMPTY_, err
10851085
}
1086+
if !s.isTrustedIssuer(accClaims.Issuer) {
1087+
return nil, _EMPTY_, ErrAccountValidation
1088+
}
10861089
vr := jwt.CreateValidationResults()
10871090
accClaims.Validate(vr)
10881091
if vr.IsBlocking(true) {

test/operator_test.go

+28-14
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,15 @@ func runOperatorServer(t *testing.T) (*server.Server, *server.Options) {
155155
return RunServerWithConfig(testOpConfig)
156156
}
157157

158-
func createAccountForOperatorKey(t *testing.T, s *server.Server, seed []byte) (*server.Account, nkeys.KeyPair) {
158+
func publicKeyFromKeyPair(t *testing.T, pair nkeys.KeyPair) (pkey string) {
159+
var err error
160+
if pkey, err = pair.PublicKey(); err != nil {
161+
t.Fatalf("Expected no error %v", err)
162+
}
163+
return
164+
}
165+
166+
func createAccountForOperatorKey(t *testing.T, s *server.Server, seed []byte) nkeys.KeyPair {
159167
t.Helper()
160168
okp, _ := nkeys.FromSeed(seed)
161169
akp, _ := nkeys.CreateAccount()
@@ -165,16 +173,18 @@ func createAccountForOperatorKey(t *testing.T, s *server.Server, seed []byte) (*
165173
if err := s.AccountResolver().Store(pub, jwt); err != nil {
166174
t.Fatalf("Account Resolver returned an error: %v", err)
167175
}
168-
acc, err := s.LookupAccount(pub)
169-
if err != nil {
170-
t.Fatalf("Error looking up account: %v", err)
171-
}
172-
return acc, akp
176+
return akp
173177
}
174178

175-
func createAccount(t *testing.T, s *server.Server) (*server.Account, nkeys.KeyPair) {
179+
func createAccount(t *testing.T, s *server.Server) (acc *server.Account, akp nkeys.KeyPair) {
176180
t.Helper()
177-
return createAccountForOperatorKey(t, s, oSeed)
181+
akp = createAccountForOperatorKey(t, s, oSeed)
182+
if pub, err := akp.PublicKey(); err != nil {
183+
t.Fatalf("Expected this to pass, got %v", err)
184+
} else if acc, err = s.LookupAccount(pub); err != nil {
185+
t.Fatalf("Error looking up account: %v", err)
186+
}
187+
return acc, akp
178188
}
179189

180190
func createUserCreds(t *testing.T, s *server.Server, akp nkeys.KeyPair) nats.Option {
@@ -215,11 +225,15 @@ func TestOperatorServer(t *testing.T) {
215225
// Now create an account from another operator, this should fail.
216226
okp, _ := nkeys.CreateOperator()
217227
seed, _ := okp.Seed()
218-
_, akp = createAccountForOperatorKey(t, s, seed)
228+
akp = createAccountForOperatorKey(t, s, seed)
219229
_, err = nats.Connect(url, createUserCreds(t, s, akp))
220230
if err == nil {
221231
t.Fatalf("Expected error on connect")
222232
}
233+
// The account should not be in memory either
234+
if v, err := s.LookupAccount(publicKeyFromKeyPair(t, akp)); err == nil {
235+
t.Fatalf("Expected account to NOT be in memory: %v", v)
236+
}
223237
}
224238

225239
func TestOperatorSystemAccount(t *testing.T) {
@@ -229,15 +243,15 @@ func TestOperatorSystemAccount(t *testing.T) {
229243
// Create an account from another operator, this should fail if used as a system account.
230244
okp, _ := nkeys.CreateOperator()
231245
seed, _ := okp.Seed()
232-
acc, _ := createAccountForOperatorKey(t, s, seed)
233-
if err := s.SetSystemAccount(acc.Name); err == nil {
246+
akp := createAccountForOperatorKey(t, s, seed)
247+
if err := s.SetSystemAccount(publicKeyFromKeyPair(t, akp)); err == nil {
234248
t.Fatalf("Expected this to fail")
235249
}
236250
if acc := s.SystemAccount(); acc != nil {
237251
t.Fatalf("Expected no account to be set for system account")
238252
}
239253

240-
acc, _ = createAccount(t, s)
254+
acc, _ := createAccount(t, s)
241255
if err := s.SetSystemAccount(acc.Name); err != nil {
242256
t.Fatalf("Expected this succeed, got %v", err)
243257
}
@@ -251,10 +265,10 @@ func TestOperatorSigningKeys(t *testing.T) {
251265
defer s.Shutdown()
252266

253267
// Create an account with a signing key, not the master key.
254-
acc, akp := createAccountForOperatorKey(t, s, skSeed)
268+
akp := createAccountForOperatorKey(t, s, skSeed)
255269

256270
// Make sure we can set system account.
257-
if err := s.SetSystemAccount(acc.Name); err != nil {
271+
if err := s.SetSystemAccount(publicKeyFromKeyPair(t, akp)); err != nil {
258272
t.Fatalf("Expected this succeed, got %v", err)
259273
}
260274

vendor/github.com/nats-io/jwt/.travis.yml

+2-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/account_claims.go

+17-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/creds_utils.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/exports.go

+14-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/go.mod

+3-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/go.sum

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/header.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/imports.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/operator_claims.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/revocation_list.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/nats-io/jwt/types.go

-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)