Merge pull request #150 from caos/key-selection

fix: handle keys without `use` in FindMatchingKey
This commit is contained in:
Fabi 2022-01-28 09:53:29 +01:00 committed by GitHub
commit 219ba4e038
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 130 additions and 8 deletions

View file

@ -53,7 +53,7 @@ func FindKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (jose.JSON
return key, err == nil
}
//FindMatchingKey searches the given JSON Web Keys for the requested key ID, usage and key type
//FindMatchingKey searches the given JSON Web Keys for the requested key ID, usage and alg type
//
//will return the key immediately if matches exact (id, usage, type)
//
@ -61,15 +61,27 @@ func FindKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (jose.JSON
func FindMatchingKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (key jose.JSONWebKey, err error) {
var validKeys []jose.JSONWebKey
for _, k := range keys {
if k.Use == use && algToKeyType(k.Key, expectedAlg) {
//ignore all keys with wrong use (let empty use of published key pass)
if k.Use != use && k.Use != "" {
continue
}
//ignore all keys with wrong algorithm type
if !algToKeyType(k.Key, expectedAlg) {
continue
}
//if we get here, use and alg match, so an equal (not empty) keyID is an exact match
if k.KeyID == keyID && keyID != "" {
return k, nil
}
//keyIDs did not match or at least one was empty (if later, then it could be a match)
if k.KeyID == "" || keyID == "" {
validKeys = append(validKeys, k)
}
}
}
//if we get here, no match was possible at all (use / alg) or no exact match due to
//the signed JWT and / or the published keys didn't have a kid
//if later applies and only one key could be found, we'll return it
//otherwise a corresponding error will be thrown
if len(validKeys) == 1 {
return validKeys[0], nil
}

View file

@ -1,6 +1,7 @@
package oidc
import (
"crypto/ecdsa"
"crypto/rsa"
"errors"
"reflect"
@ -139,6 +140,27 @@ func TestFindKey(t *testing.T) {
err: nil,
},
},
{
"single key no use, jwt with kid, match",
args{
keyID: "id",
use: KeyUseSignature,
expectedAlg: "RS256",
keys: []jose.JSONWebKey{
{
KeyID: "id",
Key: &rsa.PublicKey{},
},
},
},
res{
key: jose.JSONWebKey{
KeyID: "id",
Key: &rsa.PublicKey{},
},
err: nil,
},
},
{
"single key wrong kid, ErrKeyNone",
args{
@ -304,6 +326,94 @@ func TestFindKey(t *testing.T) {
err: nil,
},
},
{
"multiple keys, no use, jwt with kid, match",
args{
keyID: "id1",
use: KeyUseSignature,
expectedAlg: "RS256",
keys: []jose.JSONWebKey{
{
KeyID: "id1",
Key: &rsa.PublicKey{},
},
{
KeyID: "id2",
Key: &rsa.PublicKey{},
},
},
},
res{
key: jose.JSONWebKey{
KeyID: "id1",
Key: &rsa.PublicKey{},
},
err: nil,
},
},
{
"multiple keys, no use, jwt without kid, ErrKeyMultiple",
args{
use: KeyUseSignature,
expectedAlg: "RS256",
keys: []jose.JSONWebKey{
{
KeyID: "id1",
Key: &rsa.PublicKey{},
},
{
KeyID: "id2",
Key: &rsa.PublicKey{},
},
},
},
res{
key: jose.JSONWebKey{},
err: ErrKeyMultiple,
},
},
{
"multiple keys, no use or id, jwt with kid, ErrKeyMultiple",
args{
use: KeyUseSignature,
expectedAlg: "RS256",
keyID: "id1",
keys: []jose.JSONWebKey{
{
Key: &rsa.PublicKey{},
},
{
Key: &rsa.PublicKey{},
},
},
},
res{
key: jose.JSONWebKey{},
err: ErrKeyMultiple,
},
},
{
"multiple keys (only one matching alg), jwt with kid, match",
args{
use: KeyUseSignature,
expectedAlg: "RS256",
keyID: "id1",
keys: []jose.JSONWebKey{
{
Key: &rsa.PublicKey{},
},
{
Key: &ecdsa.PublicKey{},
},
},
},
res{
key: jose.JSONWebKey{
Key: &rsa.PublicKey{},
},
err: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {