mpdavis / python-jose

A JOSE implementation in Python
MIT License
1.55k stars 237 forks source link

jwk construction: impossible to NOT raise an exception with A256GCM algo #202

Open jsimonlane opened 3 years ago

jsimonlane commented 3 years ago

Hi everyone,

There is an issue constructing jwk's. I'm using the [cryptography] module.

NOTE: I got around this issue by just using jwe directly.

Consider the following example:

from jose import jwk
hmac_key = {
    "kty": "oct",
    "use": "enc",
    "alg": 'A256GCM',
    "k":  b'\xfe\xd6\xbf\xcf<Z\xcc\x18\xc4\x92\xe1\xb7\xe7p\xeb\x92Z\x02\xfcP\xde\xa5p\xbc\x0c\xbe"/\xb2\xce\xf3a',
    "key_ops": ['encrypt, decrypt']
}

jwk.construct(hmac_key)

This calls the following code, which assumes first that key_data is supposed to be a dictionary, but later in the function call, it is supposed to be a key itself (failing the len(32) condition in the key_class constructor).

def construct(key_data, algorithm=None):
    """
    Construct a Key object for the given algorithm with the given
    key_data.
    """

    # Allow for pulling the algorithm off of the passed in jwk.
    if not algorithm and isinstance(key_data, dict):
        algorithm = key_data.get('alg', None)

    if not algorithm:
        raise JWKError('Unable to find an algorithm for key: %s' % key_data)

    key_class = get_key(algorithm)
    if not key_class:
        raise JWKError('Unable to find an algorithm for key: %s' % key_data)
    # problem -- key_class for 'a256GCM' expects a key!!!
    return key_class(key_data, algorithm)
    # return key_class(key_data['k'], algorithm) # my proposed workaround

However, my guess is that some key classes take a dictionary, others take a key itself. So that workaround I proposed would likely break things. At the very least, the A256GCM algorithm key class needs to be updated to extract the key dict.

ljluestc commented 8 months ago
def construct(key_data, algorithm=None):
    """
    Construct a Key object for the given algorithm with the given
    key_data.
    """

    # Allow for pulling the algorithm off of the passed-in JWK.
    if not algorithm and isinstance(key_data, dict):
        algorithm = key_data.get('alg', None)

    if not algorithm:
        raise JWKError('Unable to find an algorithm for key: %s' % key_data)

    key_class = get_key(algorithm)
    if not key_class:
        raise JWKError('Unable to find an algorithm for key: %s' % key_data)

    # Check if key_data is a dictionary or a key
    if isinstance(key_data, dict):
        key = key_data.get('k')
    else:
        key = key_data

    # Construct the key object
    return key_class(key, algorithm)