fix: handle keys without use in FindMatchingKey

This commit is contained in:
Livio Amstutz 2022-01-28 09:42:42 +01:00
parent f103b56e95
commit bcd9ec8d85
2 changed files with 129 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 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) //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) { func FindMatchingKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (key jose.JSONWebKey, err error) {
var validKeys []jose.JSONWebKey var validKeys []jose.JSONWebKey
for _, k := range keys { 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.KeyID == keyID && keyID != "" { if k.Use != use && k.Use != "" {
return k, nil continue
} }
if k.KeyID == "" || keyID == "" { //ignore all keys with wrong algorithm type
validKeys = append(validKeys, k) 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 { if len(validKeys) == 1 {
return validKeys[0], nil return validKeys[0], nil
} }

View file

@ -139,6 +139,27 @@ func TestFindKey(t *testing.T) {
err: nil, 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", "single key wrong kid, ErrKeyNone",
args{ args{
@ -304,6 +325,94 @@ func TestFindKey(t *testing.T) {
err: nil, 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 { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {