mirror of
https://github.com/golang/oauth2.git
synced 2025-07-21 00:00:09 +08:00
The fix for CVE-2025-22868 relies on strings.Count, which isn't ideal because it precludes failing fast when the token contains an unexpected number of periods. Moreover, Verify still allocates more than necessary. Eschew strings.Count in favor of strings.Cut. Some benchmark results: goos: darwin goarch: amd64 pkg: golang.org/x/oauth2/jws cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz │ old │ new │ │ sec/op │ sec/op vs base │ Verify/full_of_periods-8 24862.50n ± 1% 57.87n ± 0% -99.77% (p=0.000 n=20) Verify/two_trailing_periods-8 3.485m ± 1% 3.445m ± 1% -1.13% (p=0.003 n=20) geomean 294.3µ 14.12µ -95.20% │ old │ new │ │ B/op │ B/op vs base │ Verify/full_of_periods-8 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=20) ¹ Verify/two_trailing_periods-8 2.001Mi ± 0% 1.001Mi ± 0% -49.98% (p=0.000 n=20) geomean 5.658Ki 4.002Ki -29.27% ¹ all samples are equal │ old │ new │ │ allocs/op │ allocs/op vs base │ Verify/full_of_periods-8 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=20) ¹ Verify/two_trailing_periods-8 12.000 ± 0% 9.000 ± 0% -25.00% (p=0.000 n=20) geomean 3.464 3.000 -13.40% ¹ all samples are equal Also, remove all remaining calls to strings.Split. Updates golang/go#71490 Change-Id: Icac3c7a81562161ab6533d892ba19247d6d5b943 GitHub-Last-Rev: 3a82900f747798f5f36065126385880277c0fce7 GitHub-Pull-Request: golang/oauth2#774 Reviewed-on: https://go-review.googlesource.com/c/oauth2/+/655455 Commit-Queue: Neal Patel <nealpatel@google.com> Reviewed-by: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Neal Patel <nealpatel@google.com> Auto-Submit: Neal Patel <nealpatel@google.com>
98 lines
1.7 KiB
Go
98 lines
1.7 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package jws
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestSignAndVerify(t *testing.T) {
|
|
header := &Header{
|
|
Algorithm: "RS256",
|
|
Typ: "JWT",
|
|
}
|
|
payload := &ClaimSet{
|
|
Iss: "http://google.com/",
|
|
Aud: "",
|
|
Exp: 3610,
|
|
Iat: 10,
|
|
}
|
|
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
token, err := Encode(header, payload, privateKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = Verify(token, &privateKey.PublicKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestVerifyFailsOnMalformedClaim(t *testing.T) {
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
}{
|
|
{
|
|
desc: "no periods",
|
|
token: "aa",
|
|
}, {
|
|
desc: "only one period",
|
|
token: "a.a",
|
|
}, {
|
|
desc: "more than two periods",
|
|
token: "a.a.a.a",
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
f := func(t *testing.T) {
|
|
err := Verify(tc.token, nil)
|
|
if err == nil {
|
|
t.Error("got no errors; want improperly formed JWT not to be verified")
|
|
}
|
|
}
|
|
t.Run(tc.desc, f)
|
|
}
|
|
}
|
|
|
|
func BenchmarkVerify(b *testing.B) {
|
|
cases := []struct {
|
|
desc string
|
|
token string
|
|
}{
|
|
{
|
|
desc: "full of periods",
|
|
token: strings.Repeat(".", http.DefaultMaxHeaderBytes),
|
|
}, {
|
|
desc: "two trailing periods",
|
|
token: strings.Repeat("a", http.DefaultMaxHeaderBytes-2) + "..",
|
|
},
|
|
}
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
for _, bc := range cases {
|
|
f := func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for range b.N {
|
|
Verify(bc.token, &privateKey.PublicKey)
|
|
}
|
|
}
|
|
b.Run(bc.desc, f)
|
|
}
|
|
}
|