Skip to content

Commit

Permalink
Allow flexible key usage values
Browse files Browse the repository at this point in the history
  • Loading branch information
Daisuke Maki committed Oct 3, 2024
1 parent acb931c commit 4b3d083
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 21 deletions.
17 changes: 17 additions & 0 deletions jwk/jwk.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,3 +619,20 @@ func IsKeyValidationError(err error) bool {
var kve keyValidationError
return errors.Is(err, &kve)
}

// Configure is used to configure global behavior of the jwk package.
func Configure(options ...GlobalOption) {
var strictKeyUsagePtr *bool
//nolint:forcetypeassert
for _, option := range options {
switch option.Ident() {
case identStrictKeyUsage{}:
v := option.Value().(bool)
strictKeyUsagePtr = &v
}
}

if strictKeyUsagePtr != nil {
strictKeyUsage.Store(*strictKeyUsagePtr)
}
}
8 changes: 2 additions & 6 deletions jwk/jwk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -783,13 +783,9 @@ func TestAccept(t *testing.T) {
for _, test := range testcases {
var usage jwk.KeyUsageType
if test.Error {
if !assert.Error(t, usage.Accept(test.Args), `KeyUsage.Accept should fail`) {
return
}
require.Error(t, usage.Accept(test.Args), `KeyUsage.Accept should fail`)
} else {
if !assert.NoError(t, usage.Accept(test.Args), `KeyUsage.Accept should succeed`) {
return
}
require.NoError(t, usage.Accept(test.Args), `KeyUsage.Accept should succeed`)
}
}
})
Expand Down
21 changes: 20 additions & 1 deletion jwk/options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ interfaces:
- parseOption
comment: |
RegisterFetchOption describes options that can be passed to `(jwk.Cache).Register()` and `jwk.Fetch()`
- name: GlobalOption
comment: |
GlobalOption is a type of Option that can be passed to the `jwk.Configure()` to
change the global configuration of the jwk package.
options:
- ident: HTTPClient
interface: RegisterFetchOption
Expand Down Expand Up @@ -109,4 +113,19 @@ options:
first fetch is done before returning from the `Register()` call.
This option is by default true. Specify a false value if you would
like to return immediately from the `Register()` call.
like to return immediately from the `Register()` call.
This options is exactly the same as `httprc.WithWaitReady()`
- ident: StrictKeyUsage
interface: GlobalOption
argument_type: bool
comment: |
WithStrictKeyUsage specifies if during JWK parsing, the "use" field
should be confined to the values that have been registered via
`jwk.RegisterKeyType()`. By default this option is true, and the
initial allowed values are "use" and "enc" only.
If this option is set to false, then the "use" field can be any
value. If this options is set to true, then the "use" field must
be one of the registered values, and otherwise an error will be
reported during parsing / assignment to `jwk.KeyUsageType`
33 changes: 33 additions & 0 deletions jwk/options_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions jwk/options_gen_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 58 additions & 14 deletions jwk/usage.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
package jwk

import "fmt"
import (
"fmt"
"sync"
"sync/atomic"
)

var strictKeyUsage = atomic.Bool{}
var keyUsageNames = map[string]struct{}{}
var muKeyUsageName sync.RWMutex

// RegisterKeyUsage registers a possible value that can be used for KeyUsageType.
// Normally, key usage (or the "use" field in a JWK) is either "sig" or "enc",
// but other values may be used.
//
// While this module only works with "sig" and "enc", it is possible that
// systems choose to use other values. This function allows users to register
// new values to be accepted as valid key usage types. Values are case sensitive.
//
// Furthermore, the check against registered values can be completely turned off
// by setting the global option `jwk.WithStrictKeyUsage(false)`.
func RegisterKeyUsage(v string) {
muKeyUsageName.Lock()
defer muKeyUsageName.Unlock()
keyUsageNames[v] = struct{}{}
}

func UnregisterKeyUsage(v string) {
muKeyUsageName.Lock()
defer muKeyUsageName.Unlock()
delete(keyUsageNames, v)
}

func init() {
strictKeyUsage.Store(true)
RegisterKeyUsage("sig")
RegisterKeyUsage("enc")
}

func isValidUsage(v string) bool {
// This function can return true if strictKeyUsage is false
if !strictKeyUsage.Load() {
return true
}

muKeyUsageName.RLock()
defer muKeyUsageName.RUnlock()
_, ok := keyUsageNames[v]
return ok
}

func (k KeyUsageType) String() string {
return string(k)
Expand All @@ -9,22 +57,18 @@ func (k KeyUsageType) String() string {
func (k *KeyUsageType) Accept(v interface{}) error {
switch v := v.(type) {
case KeyUsageType:
switch v {
case ForSignature, ForEncryption:
*k = v
return nil
default:
return fmt.Errorf("invalid key usage type %s", v)
if !isValidUsage(v.String()) {
return fmt.Errorf("invalid key usage type: %q", v)
}
*k = v
return nil
case string:
switch v {
case ForSignature.String(), ForEncryption.String():
*k = KeyUsageType(v)
return nil
default:
return fmt.Errorf("invalid key usage type %s", v)
if !isValidUsage(v) {
return fmt.Errorf("invalid key usage type: %q", v)
}
*k = KeyUsageType(v)
return nil
}

return fmt.Errorf("invalid value for key usage type %s", v)
return fmt.Errorf("invalid Go type for key usage type: %T", v)
}

0 comments on commit 4b3d083

Please sign in to comment.