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

No support for alg="none" unsecured JWSes? #166

Open
ikirker opened this issue Aug 5, 2023 · 0 comments
Open

No support for alg="none" unsecured JWSes? #166

ikirker opened this issue Aug 5, 2023 · 0 comments

Comments

@ikirker
Copy link

ikirker commented Aug 5, 2023

I'm using josepy 1.13.0 via mozilla-django-oidc, and I came across this problem: if provided with an "unsecured" JWS then it fails during parsing with the error shown below.

That is, a JWS with the header:

{"typ":"JWT","alg":"none"}

Unfortunately, Azure AD appears to provide these during part of OIDC authentication.

As far as I can tell from a relevant part of the specs that seems to be a valid (unsecured) JWT, but it causes an error in josepy, apparently because there's no none _JWARS.

Example:

from josepy.jws import JWS

import base64

header =  b'{"typ":"JWT","alg":"none"}'
content = b'{"some_value": "blah"}'

b64 = base64.b64encode

token = (b64(header) + b'.' +
         b64(content) + b'.')

j = JWS.from_compact(token)

Produces:

(expand traceback)
Traceback (most recent call last):
  File "/Users/itme/Code/josepy/test.py", line 17, in <module>
    j = JWS.from_compact(token)
        ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/jws.py", line 335, in from_compact
    sig = cls.signature_cls(
          ^^^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/jws.py", line 181, in __init__
    kwargs = self._with_combined(kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/jws.py", line 192, in _with_combined
    combined = header + cls.header_cls.json_loads(protected)
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/interfaces.py", line 177, in json_loads
    return cls.from_json(loads)
           ^^^^^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/json_util.py", line 331, in from_json
    return cls(**cls.fields_from_json(jobj))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/json_util.py", line 321, in fields_from_json
    fields[slot] = field.decode(value)
                   ^^^^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/json_util.py", line 110, in decode
    return self.fdec(value)
           ^^^^^^^^^^^^^^^^
  File "/Users/itme/Code/josepy/env/lib/python3.11/site-packages/josepy/jwa.py", line 59, in from_json
    return cls.SIGNATURES[jobj]
           ~~~~~~~~~~~~~~^^^^^^
KeyError: 'none'

I tried adding a dud entry, in

like:

NO_ALG = JWASignature.register(_JWARS('none', None))

but I had trouble working out what properties that second argument was supposed to have that might make this work (and whether it was even a good idea), and I didn't have much luck trying to find a right place to work around it with special-cases elsewhere in the code.

I'd guessed that providing an object that resembled the others, that provided a function in place of a hashing one to take any input and return an empty string, might let it pretend to validate, but couldn't work out how to implement the correct interface successfully.

Are unsecured JWSes a deliberate omission? Have I misunderstood something here?

(I'm pretty unfamiliar with this collection of standards, so please forgive any incorrect terminology.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant