Skip to content

Commit ada5b9c

Browse files
committed
oidc: ignore JWKs with unsupported key types rather than failing
Fixes #498
1 parent 75dfa5c commit ada5b9c

2 files changed

Lines changed: 83 additions & 0 deletions

File tree

oidc/jwks.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,20 @@ func (j *jwkJSON) UnmarshalJSON(data []byte) error {
278278
}
279279
var jwk jose.JSONWebKey
280280
if err := json.Unmarshal(key, &jwk); err != nil {
281+
// Ignore keys with types that go-jose doesn't support, such as
282+
// OKP keys with Ed448 or X448 curves. Some providers include
283+
// them in their key sets without an "alg" value, so the check
284+
// above doesn't catch them.
285+
//
286+
// https://datatracker.ietf.org/doc/html/rfc7517#section-5
287+
//
288+
// Implementations SHOULD ignore JWKs within a JWK Set that use
289+
// "kty" (key type) values that are not understood by them, that
290+
// are missing required members, or for which values are out of
291+
// the supported ranges.
292+
if errors.Is(err, jose.ErrUnsupportedKeyType) {
293+
continue
294+
}
281295
return err
282296
}
283297
j.Keys = append(j.Keys, jwk)

oidc/jwks_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,3 +426,72 @@ func TestJWKParseWithIgnoredKeys(t *testing.T) {
426426
t.Errorf("expected payload %q got %q", "payload", string(got))
427427
}
428428
}
429+
430+
func TestJWKParseWithUnsupportedKeys(t *testing.T) {
431+
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
432+
if err != nil {
433+
t.Fatal(err)
434+
}
435+
pubKey := jose.JSONWebKey{
436+
Key: priv.Public(),
437+
Use: "sig",
438+
Algorithm: string(jose.ES256),
439+
KeyID: "key1",
440+
}
441+
pubRaw, err := json.Marshal(pubKey)
442+
if err != nil {
443+
t.Fatal(err)
444+
}
445+
privKey := jose.JSONWebKey{
446+
Key: priv,
447+
Use: "sig",
448+
Algorithm: string(jose.ES256),
449+
KeyID: "key1",
450+
}
451+
452+
hf := func(w http.ResponseWriter, r *http.Request) {
453+
w.Header().Set("Content-Type", "application/json")
454+
io.WriteString(w, `{
455+
"keys": [
456+
`+string(pubRaw)+`,
457+
{
458+
"kty": "OKP",
459+
"crv": "Ed448",
460+
"kid": "oidc-ed448-1",
461+
"use": "sig",
462+
"x": "gH1eRK-6hW6ZoAy2k11U4L5uaIaMaZTMCf1cAbsxsYLvTqV2-TQG1PNyLOrhZkMyzUJulMc1wAfH"
463+
},
464+
{
465+
"kty": "OKP",
466+
"crv": "X448",
467+
"kid": "oidc-x448-1",
468+
"use": "enc",
469+
"x": "5Tegc13rI3bLqrCiUo-Cg1Ijjaj0l1aZrkVfUFbp-B5CGSj5z3wdAr3B0K7pPYDm9qbtjmMKOf0"
470+
}
471+
]
472+
}`)
473+
}
474+
475+
ks := NewRemoteKeySet(t.Context(), httptest.NewServer(http.HandlerFunc(hf)).URL)
476+
477+
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: &privKey}, nil)
478+
if err != nil {
479+
t.Fatal(err)
480+
}
481+
jws, err := signer.Sign([]byte("payload"))
482+
if err != nil {
483+
t.Fatal(err)
484+
}
485+
serialized, err := jws.CompactSerialize()
486+
if err != nil {
487+
t.Fatal(err)
488+
}
489+
490+
got, err := ks.VerifySignature(t.Context(), serialized)
491+
if err != nil {
492+
t.Fatalf("failed to verify signature: %v", err)
493+
}
494+
if string(got) != "payload" {
495+
t.Errorf("expected payload %q got %q", "payload", string(got))
496+
}
497+
}

0 commit comments

Comments
 (0)