python-jwt icon indicating copy to clipboard operation
python-jwt copied to clipboard

jwt.exceptions.UnsupportedKeyTypeError: could not deserialize

Open Moraxyc opened this issue 8 months ago • 0 comments

First encountered in https://github.com/NixOS/nixpkgs/issues/418879; confirmed as an upstream issue and reported here.

Steps to Reproduce

docker run -it --rm python:3.13.4 bash
git clone https://github.com/GehirnInc/python-jwt --depth 1
cd python-jwt
pip install -r ./requirements-dev.txt
sed -i 's/--flake8//' setup.cfg
pytest

Log

jwt/jwk.py:345: ValueError: 
    Could not deserialize key data. The data may be in an incorrect format, 
    it may be encrypted with an unsupported algorithm, or it may be an unsupported key type 
    (e.g. EC curves with explicit parameters). 
    Details: ASN.1 parsing error: unexpected tag (got Tag { value: 2, constructed: false, class: Universal })

jwt/jwk.py:350: UnsupportedKeyTypeError: this is probably a public key

jwt/jwk.py:371: UnsupportedKeyTypeError: could not deserialize

jwt/tests/test_jwk.py:90: in test_jwk_from_der
    jwk_priv = jwk_from_der(load_testdata('rsa_privkey.der'))
==========short test summary info ==========
FAILED jwt/tests/test_jwk.py::test_jwk_from_der - jwt.exceptions.UnsupportedKeyTypeError: could not deserialize
======================================================= test session starts =======================================================
platform linux -- Python 3.13.4, pytest-6.2.5, py-1.11.0, pluggy-1.6.0
rootdir: /workdir/python-jwt, configfile: setup.cfg
plugins: flake8-1.1.0, cov-6.2.1
collected 48 items

jwt/tests/test_jwa.py ....                                                                                                  [  8%]
jwt/tests/test_jwk.py .......F................                                                                              [ 58%]
jwt/tests/test_jwkset.py ...                                                                                                [ 64%]
jwt/tests/test_jws.py ...                                                                                                   [ 70%]
jwt/tests/test_jwt.py .......                                                                                               [ 85%]
jwt/tests/test_utils.py .......                                                                                             [100%]

============================================================ FAILURES =============================================================
________________________________________________________ test_jwk_from_der ________________________________________________________

content = b'0\x82\x04\xa4\x02\x01\x00\x02\x82\x01\x01\x00\xb4\xcf\xd1^3)\xec\x0b\xcf\xaev\xf5\xfe-\xc8\x99\xc6xy\xb9\x18\xf8\x0b...7X\xc4\x9d\x1a\xa9\x03\x01\x1d\xc3\xb4\xbe\xf2]2W&\x8d\x92n\xbay\x12<\xd2\x9f\xb0\xdc\x0cMm/a\'\xfe\xd4\x95]\xe5\x18\n'
private_loader = <built-in function load_der_private_key>

    @jwk_from_bytes_argument_conversion
    def jwk_from_private_bytes(
        content: bytes,
        private_loader: PrivateKeyLoaderT,
        *,
        password: Optional[str] = None,
        backend: Optional[object] = None,
        options: Optional[Mapping[str, object]] = None,
    ) -> AbstractJWKBase:
        """This function is meant to be called from jwk_from_bytes"""
        if options is None:
            options = {}
        try:
>           privkey = private_loader(content, password, backend)  # type: ignore[operator]  # noqa: E501
E           ValueError: Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters). Details: ASN.1 parsing error: unexpected tag (got Tag { value: 2, constructed: false, class: Universal })

jwt/jwk.py:345: ValueError

The above exception was the direct cause of the following exception:

content = b'0\x82\x04\xa4\x02\x01\x00\x02\x82\x01\x01\x00\xb4\xcf\xd1^3)\xec\x0b\xcf\xaev\xf5\xfe-\xc8\x99\xc6xy\xb9\x18\xf8\x0b...7X\xc4\x9d\x1a\xa9\x03\x01\x1d\xc3\xb4\xbe\xf2]2W&\x8d\x92n\xbay\x12<\xd2\x9f\xb0\xdc\x0cMm/a\'\xfe\xd4\x95]\xe5\x18\n'
private_loader = 'load_der_private_key', public_loader = 'load_der_public_key'

    def jwk_from_bytes(
        content: bytes,
        private_loader: PrivateKeyLoaderT,
        public_loader: PublicKeyLoaderT,
        *,
        private_password: Optional[str] = None,
        backend: Optional[object] = None,
        options: Optional[Mapping[str, object]] = None,
    ) -> AbstractJWKBase:
        try:
>           return jwk_from_private_bytes(
                content,
                private_loader,
                password=private_password,
                backend=backend,
                options=options,
            )

jwt/jwk.py:384:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

content = b'0\x82\x04\xa4\x02\x01\x00\x02\x82\x01\x01\x00\xb4\xcf\xd1^3)\xec\x0b\xcf\xaev\xf5\xfe-\xc8\x99\xc6xy\xb9\x18\xf8\x0b...7X\xc4\x9d\x1a\xa9\x03\x01\x1d\xc3\xb4\xbe\xf2]2W&\x8d\x92n\xbay\x12<\xd2\x9f\xb0\xdc\x0cMm/a\'\xfe\xd4\x95]\xe5\x18\n'
loader = <built-in function load_der_private_key>, kwargs = {'backend': None, 'options': {}, 'password': None}

    @wraps(func)
    def wrapper(content, loader, **kwargs):
        # now convert it to a Callable if it's a string
        if isinstance(loader, str):
            loader = getattr(serialization_module, loader)

        if kwargs.get('options') is None:
            kwargs['options'] = {}

>       return func(content, loader, **kwargs)

jwt/jwk.py:328:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

content = b'0\x82\x04\xa4\x02\x01\x00\x02\x82\x01\x01\x00\xb4\xcf\xd1^3)\xec\x0b\xcf\xaev\xf5\xfe-\xc8\x99\xc6xy\xb9\x18\xf8\x0b...7X\xc4\x9d\x1a\xa9\x03\x01\x1d\xc3\xb4\xbe\xf2]2W&\x8d\x92n\xbay\x12<\xd2\x9f\xb0\xdc\x0cMm/a\'\xfe\xd4\x95]\xe5\x18\n'
private_loader = <built-in function load_der_private_key>

    @jwk_from_bytes_argument_conversion
    def jwk_from_private_bytes(
        content: bytes,
        private_loader: PrivateKeyLoaderT,
        *,
        password: Optional[str] = None,
        backend: Optional[object] = None,
        options: Optional[Mapping[str, object]] = None,
    ) -> AbstractJWKBase:
        """This function is meant to be called from jwk_from_bytes"""
        if options is None:
            options = {}
        try:
            privkey = private_loader(content, password, backend)  # type: ignore[operator]  # noqa: E501
            if isinstance(privkey, RSAPrivateKey):
                return RSAJWK(privkey, **options)
            raise UnsupportedKeyTypeError('unsupported key type')
        except ValueError as ex:
>           raise UnsupportedKeyTypeError('this is probably a public key') from ex
E           jwt.exceptions.UnsupportedKeyTypeError: this is probably a public key

jwt/jwk.py:350: UnsupportedKeyTypeError

During handling of the above exception, another exception occurred:

content = b'0\x82\x04\xa4\x02\x01\x00\x02\x82\x01\x01\x00\xb4\xcf\xd1^3)\xec\x0b\xcf\xaev\xf5\xfe-\xc8\x99\xc6xy\xb9\x18\xf8\x0b...7X\xc4\x9d\x1a\xa9\x03\x01\x1d\xc3\xb4\xbe\xf2]2W&\x8d\x92n\xbay\x12<\xd2\x9f\xb0\xdc\x0cMm/a\'\xfe\xd4\x95]\xe5\x18\n'
public_loader = <built-in function load_der_public_key>

    @jwk_from_bytes_argument_conversion
    def jwk_from_public_bytes(
        content: bytes,
        public_loader: PublicKeyLoaderT,
        *,
        backend: Optional[object] = None,
        options: Optional[Mapping[str, object]] = None
    ) -> AbstractJWKBase:
        """This function is meant to be called from jwk_from_bytes"""
        if options is None:
            options = {}
        try:
>           pubkey = public_loader(content, backend)  # type: ignore[operator]
E           ValueError: Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters). Details: ASN.1 parsing error: unexpected tag (got Tag { value: 2, constructed: false, class: Universal })

jwt/jwk.py:365: ValueError

The above exception was the direct cause of the following exception:

    def test_jwk_from_der():
>       jwk_priv = jwk_from_der(load_testdata('rsa_privkey.der'))

jwt/tests/test_jwk.py:90:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
jwt/jwk.py:420: in jwk_from_der
    return jwk_from_bytes(
jwt/jwk.py:392: in jwk_from_bytes
    return jwk_from_public_bytes(
jwt/jwk.py:328: in wrapper
    return func(content, loader, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

content = b'0\x82\x04\xa4\x02\x01\x00\x02\x82\x01\x01\x00\xb4\xcf\xd1^3)\xec\x0b\xcf\xaev\xf5\xfe-\xc8\x99\xc6xy\xb9\x18\xf8\x0b...7X\xc4\x9d\x1a\xa9\x03\x01\x1d\xc3\xb4\xbe\xf2]2W&\x8d\x92n\xbay\x12<\xd2\x9f\xb0\xdc\x0cMm/a\'\xfe\xd4\x95]\xe5\x18\n'
public_loader = <built-in function load_der_public_key>

    @jwk_from_bytes_argument_conversion
    def jwk_from_public_bytes(
        content: bytes,
        public_loader: PublicKeyLoaderT,
        *,
        backend: Optional[object] = None,
        options: Optional[Mapping[str, object]] = None
    ) -> AbstractJWKBase:
        """This function is meant to be called from jwk_from_bytes"""
        if options is None:
            options = {}
        try:
            pubkey = public_loader(content, backend)  # type: ignore[operator]
            if isinstance(pubkey, RSAPublicKey):
                return RSAJWK(pubkey, **options)
            raise UnsupportedKeyTypeError(
                'unsupported key type')  # pragma: no cover
        except ValueError as why:
>           raise UnsupportedKeyTypeError('could not deserialize') from why
E           jwt.exceptions.UnsupportedKeyTypeError: could not deserialize

jwt/jwk.py:371: UnsupportedKeyTypeError
======================================================== warnings summary =========================================================
../../usr/local/lib/python3.13/site-packages/_pytest/assertion/rewrite.py:689
  /usr/local/lib/python3.13/site-packages/_pytest/assertion/rewrite.py:689: DeprecationWarning: ast.Str is deprecated and will be removed in Python 3.14; use ast.Constant instead
    and isinstance(item.value, ast.Str)

../../usr/local/lib/python3.13/site-packages/_pytest/assertion/rewrite.py:691
  /usr/local/lib/python3.13/site-packages/_pytest/assertion/rewrite.py:691: DeprecationWarning: Attribute s is deprecated and will be removed in Python 3.14; use value instead
    doc = item.value.s

jwt/tests/test_jwa.py: 4 warnings
jwt/tests/test_jwk.py: 16 warnings
jwt/tests/test_jwkset.py: 3 warnings
jwt/tests/test_jws.py: 3 warnings
jwt/tests/test_jwt.py: 7 warnings
  /usr/local/lib/python3.13/unittest/case.py:597: RuntimeWarning: TestResult has no addDuration method
    warnings.warn("TestResult has no addDuration method",

-- Docs: https://docs.pytest.org/en/stable/warnings.html
========================================================= tests coverage ==========================================================
_________________________________________ coverage: platform linux, python 3.13.4-final-0 _________________________________________

Name                       Stmts   Miss  Cover   Missing
--------------------------------------------------------
jwt/__init__.py                6      0   100%
jwt/exceptions.py             15      0   100%
jwt/jwa.py                    80     12    85%   38-44, 77, 109, 111, 146, 148
jwt/jwk.py                   191      3    98%   176, 343, 363
jwt/jwkset.py                 22      1    95%   23
jwt/jws.py                    46      6    87%   50-51, 78-79, 97, 102
jwt/jwt.py                    46     12    74%   60-61, 68-69, 91-92, 95-96, 104-105, 114-115
jwt/tests/__init__.py          0      0   100%
jwt/tests/helper.py            6      0   100%
jwt/tests/test_jwa.py         25      0   100%
jwt/tests/test_jwk.py        106      2    98%   92-93
jwt/tests/test_jwkset.py      25      0   100%
jwt/tests/test_jws.py         23      0   100%
jwt/tests/test_jwt.py         41      0   100%
jwt/tests/test_utils.py       23      0   100%
jwt/utils.py                  29      0   100%
--------------------------------------------------------
TOTAL                        684     36    95%
===================================================== short test summary info =====================================================
FAILED jwt/tests/test_jwk.py::test_jwk_from_der - jwt.exceptions.UnsupportedKeyTypeError: could not deserialize
============================================ 1 failed, 47 passed, 35 warnings in 1.32s ============================================

Moraxyc avatar Jun 22 '25 05:06 Moraxyc