Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Resolves #53 Smarter handling of keys marked for use with encryption" #55

Merged
merged 2 commits into from
Oct 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions example_jwks.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,19 +118,6 @@
"use": "sig",
"kid": "hmac",
"k": "V_8Ob8dVs6JuZx6expyjShoUgFgxoaovGjmGhesL2jA"
},
{
"kty": "RSA",
"use": "enc",
"kid": "WW91IGdldCBhIGdvbGQgc3RhciDwn4yfCg",
"alg": "RSA-OAEP",
"n": "ja99ybDrLvw11Z4CvNlDI-kkqJEBpSnvDf0pZF2DvBlvYmeVYL_ChqIe8E9GyHUmLMdtO_jifSgOqE5b8vILwi1kZnJR7N857uEnbWM9YTeevi_RZ-E_hr4frW2NKJ78YGvCzwLKG2GgtSjj0zuTLnSaK8fCGzqXgy6paXNhgHUSZgGwvO0YItpMlyJeqEj1wGTWz1IyA1sguF1cC7K0fojPbPoBwrhvaAeoGRPLraE0rrBsQv8iiLwnRBIez9B1j0NiUG8Iad953Y7UzaKOAw8crIEK45NIK_yxHUpxqcHLjPIcRyIyJGioRyGK7cp-_7iPLOCutQc-u46mom1_ZQ",
"e": "AQAB",
"x5c": [
"MIICmzCCAYMCBgF4BJRpbzANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjEwMzA1MjI0NzE4WhcNMzEwMzA1MjI0ODU4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCNr33JsOsu/DXVngK82UMj6SSokQGlKe8N/SlkXYO8GW9iZ5Vgv8KGoh7wT0bIdSYsx207+OJ9KA6oTlvy8gvCLWRmclHs3znu4SdtYz1hN56+L9Fn4T+Gvh+tbY0onvxga8LPAsobYaC1KOPTO5MudJorx8IbOpeDLqlpc2GAdRJmAbC87Rgi2kyXIl6oSPXAZNbPUjIDWyC4XVwLsrR+iM9s+gHCuG9oB6gZE8utoTSusGxC/yKIvCdEEh7P0HWPQ2JQbwhp33ndjtTNoo4DDxysgQrjk0gr/LEdSnGpwcuM8hxHIjIkaKhHIYrtyn7/uI8s4K61Bz67jqaibX9lAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAHrGJFhVNiQupIwkn2jiW/jBobm9CHUxOwQL5E7WdRz5uaOJ0v62PrynOQE9xim9Qk8bT3q7DThZs66U9bpIk3msKVRgXRfn5FZy1H5RKOlEEFZhGakPqSlC1yPbhUNhHXMs3GTzdGMLtYaGvSy6XM/8/zqVqVwgh6BpbAR9RfiSdyaiNTSBriu+n/tHW934G9J8UIzdfpVcb0Yt9y4o0UgIXt64NtGFq7zmNJijH88AxBZFB6eUUmQQCczebzoAjyYbVOes5gGFzboVWcyLe3iyD0vvsAVHJViXeiGoxhpKnc8ryISpRUBzsKngf5uZo3bnrD9PHLYBoGOHgzII1xw="
],
"x5t": "5GNr3LeRXHWI4YR8-QTSsF98oTI",
"x5t#S256": "Dgd0_wZZqvRuf4GEISPNHREX-1ixTMIsrPeGzk0bCxs"
}
]
}
5 changes: 1 addition & 4 deletions get.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ func Get(jwksURL string, options Options) (jwks *JWKS, err error) {
if jwks.refreshTimeout == 0 {
jwks.refreshTimeout = defaultRefreshTimeout
}
if len(jwks.allowedJWKUses) == 0 {
jwks.allowedJWKUses = []JWKUse{UseSignature, UseOmitted}
}

err = jwks.refresh()
if err != nil {
Expand Down Expand Up @@ -184,7 +181,7 @@ func (j *JWKS) refresh() (err error) {
}
}

j.keys[kid] = parsedKey{public: key.inter}
j.keys[kid] = key.inter
}
}

Expand Down
4 changes: 2 additions & 2 deletions given.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ type GivenKey struct {

// NewGiven creates a JWKS from a map of given keys.
func NewGiven(givenKeys map[string]GivenKey) (jwks *JWKS) {
keys := make(map[string]parsedKey)
keys := make(map[string]interface{})

for kid, given := range givenKeys {
keys[kid] = parsedKey{public: given.inter}
keys[kid] = given.inter
}

return &JWKS{
Expand Down
88 changes: 25 additions & 63 deletions jwks.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,11 @@ var (

// ErrMissingAssets indicates there are required assets are missing to create a public key.
ErrMissingAssets = errors.New("required assets are missing to create a public key")

// ErrJWKUse indicates that the given key was found in the JWKS, but that the use was not allowed.
ErrJWKUse = errors.New("the given key ID was found but the key use is not allowed")
)

// ErrorHandler is a function signature that consumes an error.
type ErrorHandler func(err error)

// JWKUse specifies a `use` for a JWK
type JWKUse string

const (
UseEncryption JWKUse = "enc"
UseOmitted JWKUse = ""
UseSignature JWKUse = "sig"
)

// jsonWebKey represents a raw key inside a JWKS.
type jsonWebKey struct {
Curve string `json:"crv"`
Expand All @@ -40,28 +28,20 @@ type jsonWebKey struct {
ID string `json:"kid"`
Modulus string `json:"n"`
Type string `json:"kty"`
Use string `json:"use"`
X string `json:"x"`
Y string `json:"y"`
}

// parsedKey represents a parsed JWK with assoicated metadata
type parsedKey struct {
use JWKUse
public interface{}
}

// JWKS represents a JSON Web Key Set (JWK Set).
type JWKS struct {
allowedJWKUses []JWKUse
cancel context.CancelFunc
client *http.Client
ctx context.Context
raw []byte
givenKeys map[string]GivenKey
givenKIDOverride bool
jwksURL string
keys map[string]parsedKey
keys map[string]interface{}
mux sync.RWMutex
refreshErrorHandler ErrorHandler
refreshInterval time.Duration
Expand All @@ -88,7 +68,7 @@ func NewJSON(jwksBytes json.RawMessage) (jwks *JWKS, err error) {

// Iterate through the keys in the raw JWKS. Add them to the JWKS.
jwks = &JWKS{
keys: make(map[string]parsedKey, len(rawKS.Keys)),
keys: make(map[string]interface{}, len(rawKS.Keys)),
}
for _, key := range rawKS.Keys {
var keyInter interface{}
Expand Down Expand Up @@ -118,10 +98,7 @@ func NewJSON(jwksBytes json.RawMessage) (jwks *JWKS, err error) {
continue
}

jwks.keys[key.ID] = parsedKey{
use: JWKUse(key.Use),
public: keyInter,
}
jwks.keys[key.ID] = keyInter
}

return jwks, nil
Expand Down Expand Up @@ -169,7 +146,7 @@ func (j *JWKS) ReadOnlyKeys() map[string]interface{} {
keys := make(map[string]interface{})
j.mux.Lock()
for kid, cryptoKey := range j.keys {
keys[kid] = cryptoKey.public
keys[kid] = cryptoKey
}
j.mux.Unlock()
return keys
Expand All @@ -178,50 +155,35 @@ func (j *JWKS) ReadOnlyKeys() map[string]interface{} {
// getKey gets the jsonWebKey from the given KID from the JWKS. It may refresh the JWKS if configured to.
func (j *JWKS) getKey(kid string) (jsonKey interface{}, err error) {
j.mux.RLock()
parsedKey, ok := j.keys[kid]
jsonKey, ok := j.keys[kid]
j.mux.RUnlock()

if !ok {
if !j.refreshUnknownKID {
return nil, ErrKIDNotFound
}

ctx, cancel := context.WithCancel(j.ctx)

// Refresh the JWKS.
select {
case <-j.ctx.Done():
return
case j.refreshRequests <- cancel:
default:
// If the j.refreshRequests channel is full, return the error early.
return nil, ErrKIDNotFound
}

// Wait for the JWKS refresh to finish.
<-ctx.Done()
if j.refreshUnknownKID {
ctx, cancel := context.WithCancel(j.ctx)

// Refresh the JWKS.
select {
case <-j.ctx.Done():
return
case j.refreshRequests <- cancel:
default:
// If the j.refreshRequests channel is full, return the error early.
return nil, ErrKIDNotFound
}

j.mux.RLock()
defer j.mux.RUnlock()
if parsedKey, ok = j.keys[kid]; !ok {
return nil, ErrKIDNotFound
}
}
// Wait for the JWKS refresh to finish.
<-ctx.Done()

// allowedJWKUses might be empty if the jwks was from keyfunc.NewJSON()
if len(j.allowedJWKUses) > 0 {
found := false
for _, use := range j.allowedJWKUses {
if parsedKey.use == use {
found = true
break
j.mux.RLock()
defer j.mux.RUnlock()
if jsonKey, ok = j.keys[kid]; ok {
return jsonKey, nil
}
}

if !found {
return nil, ErrJWKUse
}
return nil, ErrKIDNotFound
}

return parsedKey.public, nil
return jsonKey, nil
}
Loading