diff --git a/PyJWT-2.3.0.tar.gz b/PyJWT-2.3.0.tar.gz deleted file mode 100644 index 5e1baf4b33f45661eab1ba5d099c48800bc56e65..0000000000000000000000000000000000000000 Binary files a/PyJWT-2.3.0.tar.gz and /dev/null differ diff --git a/PyJWT-2.5.0.tar.gz b/PyJWT-2.5.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..4015f58f4ec73b96d4fb9ad519d9b8d131234fc6 Binary files /dev/null and b/PyJWT-2.5.0.tar.gz differ diff --git a/backport-CVE-2022-29217.patch b/backport-CVE-2022-29217.patch deleted file mode 100644 index e821b8bfd1543f7de42478d663d02ea95a30161b..0000000000000000000000000000000000000000 --- a/backport-CVE-2022-29217.patch +++ /dev/null @@ -1,294 +0,0 @@ -From 9c528670c455b8d948aff95ed50e22940d1ad3fc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jos=C3=A9=20Padilla?= -Date: Thu, 12 May 2022 14:31:00 -0400 -Subject: [PATCH] Merge pull request from GHSA-ffqj-6fqr-9h24 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Co-authored-by: José Padilla ---- - jwt/algorithms.py | 39 ++++++++--------- - jwt/utils.py | 61 ++++++++++++++++++++++++++ - tests/test_advisory.py | 109 +++++++++++++++++++++++++++++++++++++++++++++++ - tests/test_algorithms.py | 2 +- - 4 files changed, 189 insertions(+), 22 deletions(-) - create mode 100644 tests/test_advisory.py - -diff --git a/jwt/algorithms.py b/jwt/algorithms.py -index 1f8865a..1aa30ed 100644 ---- a/jwt/algorithms.py -+++ b/jwt/algorithms.py -@@ -9,6 +9,8 @@ from .utils import ( - der_to_raw_signature, - force_bytes, - from_base64url_uint, -+ is_pem_format, -+ is_ssh_key, - raw_to_der_signature, - to_base64url_uint, - ) -@@ -183,14 +185,7 @@ class HMACAlgorithm(Algorithm): - def prepare_key(self, key): - key = force_bytes(key) - -- invalid_strings = [ -- b"-----BEGIN PUBLIC KEY-----", -- b"-----BEGIN CERTIFICATE-----", -- b"-----BEGIN RSA PUBLIC KEY-----", -- b"ssh-rsa", -- ] -- -- if any(string_value in key for string_value in invalid_strings): -+ if is_pem_format(key) or is_ssh_key(key): - raise InvalidKeyError( - "The specified key is an asymmetric key or x509 certificate and" - " should not be used as an HMAC secret." -@@ -545,26 +540,28 @@ if has_crypto: - pass - - def prepare_key(self, key): -- -- if isinstance( -- key, -- (Ed25519PrivateKey, Ed25519PublicKey, Ed448PrivateKey, Ed448PublicKey), -- ): -- return key -- - if isinstance(key, (bytes, str)): - if isinstance(key, str): - key = key.encode("utf-8") - str_key = key.decode("utf-8") - - if "-----BEGIN PUBLIC" in str_key: -- return load_pem_public_key(key) -- if "-----BEGIN PRIVATE" in str_key: -- return load_pem_private_key(key, password=None) -- if str_key[0:4] == "ssh-": -- return load_ssh_public_key(key) -+ key = load_pem_public_key(key) -+ elif "-----BEGIN PRIVATE" in str_key: -+ key = load_pem_private_key(key, password=None) -+ elif str_key[0:4] == "ssh-": -+ key = load_ssh_public_key(key) -+ -+ # Explicit check the key to prevent confusing errors from cryptography -+ if not isinstance( -+ key, -+ (Ed25519PrivateKey, Ed25519PublicKey, Ed448PrivateKey, Ed448PublicKey), -+ ): -+ raise InvalidKeyError( -+ "Expecting a EllipticCurvePrivateKey/EllipticCurvePublicKey. Wrong key provided for EdDSA algorithms" -+ ) - -- raise TypeError("Expecting a PEM-formatted or OpenSSH key.") -+ return key - - def sign(self, msg, key): - """ -diff --git a/jwt/utils.py b/jwt/utils.py -index 9dde10c..8ab73b4 100644 ---- a/jwt/utils.py -+++ b/jwt/utils.py -@@ -1,5 +1,6 @@ - import base64 - import binascii -+import re - from typing import Any, Union - - try: -@@ -97,3 +98,63 @@ def raw_to_der_signature(raw_sig: bytes, curve: EllipticCurve) -> bytes: - s = bytes_to_number(raw_sig[num_bytes:]) - - return encode_dss_signature(r, s) -+ -+ -+# Based on https://github.com/hynek/pem/blob/7ad94db26b0bc21d10953f5dbad3acfdfacf57aa/src/pem/_core.py#L224-L252 -+_PEMS = { -+ b"CERTIFICATE", -+ b"TRUSTED CERTIFICATE", -+ b"PRIVATE KEY", -+ b"PUBLIC KEY", -+ b"ENCRYPTED PRIVATE KEY", -+ b"OPENSSH PRIVATE KEY", -+ b"DSA PRIVATE KEY", -+ b"RSA PRIVATE KEY", -+ b"RSA PUBLIC KEY", -+ b"EC PRIVATE KEY", -+ b"DH PARAMETERS", -+ b"NEW CERTIFICATE REQUEST", -+ b"CERTIFICATE REQUEST", -+ b"SSH2 PUBLIC KEY", -+ b"SSH2 ENCRYPTED PRIVATE KEY", -+ b"X509 CRL", -+} -+ -+_PEM_RE = re.compile( -+ b"----[- ]BEGIN (" -+ + b"|".join(_PEMS) -+ + b""")[- ]----\r? -+.+?\r? -+----[- ]END \\1[- ]----\r?\n?""", -+ re.DOTALL, -+) -+ -+ -+def is_pem_format(key: bytes) -> bool: -+ return bool(_PEM_RE.search(key)) -+ -+ -+# Based on https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b/src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46 -+_CERT_SUFFIX = b"-cert-v01@openssh.com" -+_SSH_PUBKEY_RC = re.compile(br"\A(\S+)[ \t]+(\S+)") -+_SSH_KEY_FORMATS = [ -+ b"ssh-ed25519", -+ b"ssh-rsa", -+ b"ssh-dss", -+ b"ecdsa-sha2-nistp256", -+ b"ecdsa-sha2-nistp384", -+ b"ecdsa-sha2-nistp521", -+] -+ -+ -+def is_ssh_key(key: bytes) -> bool: -+ if any(string_value in key for string_value in _SSH_KEY_FORMATS): -+ return True -+ -+ ssh_pubkey_match = _SSH_PUBKEY_RC.match(key) -+ if ssh_pubkey_match: -+ key_type = ssh_pubkey_match.group(1) -+ if _CERT_SUFFIX == key_type[-len(_CERT_SUFFIX) :]: -+ return True -+ -+ return False -diff --git a/tests/test_advisory.py b/tests/test_advisory.py -new file mode 100644 -index 0000000..f70f54b ---- /dev/null -+++ b/tests/test_advisory.py -@@ -0,0 +1,109 @@ -+import jwt -+import pytest -+from jwt.exceptions import InvalidKeyError -+ -+priv_key_bytes = b'''-----BEGIN PRIVATE KEY----- -+MC4CAQAwBQYDK2VwBCIEIIbBhdo2ah7X32i50GOzrCr4acZTe6BezUdRIixjTAdL -+-----END PRIVATE KEY-----''' -+ -+pub_key_bytes = b'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPL1I9oiq+B8crkmuV4YViiUnhdLjCp3hvy1bNGuGfNL' -+ -+ssh_priv_key_bytes = b"""-----BEGIN EC PRIVATE KEY----- -+MHcCAQEEIOWc7RbaNswMtNtc+n6WZDlUblMr2FBPo79fcGXsJlGQoAoGCCqGSM49 -+AwEHoUQDQgAElcy2RSSSgn2RA/xCGko79N+7FwoLZr3Z0ij/ENjow2XpUDwwKEKk -+Ak3TDXC9U8nipMlGcY7sDpXp2XyhHEM+Rw== -+-----END EC PRIVATE KEY-----""" -+ -+ssh_key_bytes = b"""ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJXMtkUkkoJ9kQP8QhpKO/TfuxcKC2a92dIo/xDY6MNl6VA8MChCpAJN0w1wvVPJ4qTJRnGO7A6V6dl8oRxDPkc=""" -+ -+ -+class TestAdvisory: -+ def test_ghsa_ffqj_6fqr_9h24(self): -+ # Generate ed25519 private key -+ # private_key = ed25519.Ed25519PrivateKey.generate() -+ -+ # Get private key bytes as they would be stored in a file -+ # priv_key_bytes = private_key.private_bytes( -+ # encoding=serialization.Encoding.PEM, -+ # format=serialization.PrivateFormat.PKCS8, -+ # encryption_algorithm=serialization.NoEncryption(), -+ # ) -+ -+ # Get public key bytes as they would be stored in a file -+ # pub_key_bytes = private_key.public_key().public_bytes( -+ # encoding=serialization.Encoding.OpenSSH, -+ # format=serialization.PublicFormat.OpenSSH, -+ # ) -+ -+ # Making a good jwt token that should work by signing it -+ # with the private key -+ # encoded_good = jwt.encode({"test": 1234}, priv_key_bytes, algorithm="EdDSA") -+ encoded_good = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJ0ZXN0IjoxMjM0fQ.M5y1EEavZkHSlj9i8yi9nXKKyPBSAUhDRTOYZi3zZY11tZItDaR3qwAye8pc74_lZY3Ogt9KPNFbVOSGnUBHDg' -+ -+ # Using HMAC with the public key to trick the receiver to think that the -+ # public key is a HMAC secret -+ encoded_bad = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0ZXN0IjoxMjM0fQ.6ulDpqSlbHmQ8bZXhZRLFko9SwcHrghCwh8d-exJEE4' -+ -+ # Both of the jwt tokens are validated as valid -+ jwt.decode( -+ encoded_good, -+ pub_key_bytes, -+ algorithms=jwt.algorithms.get_default_algorithms(), -+ ) -+ -+ with pytest.raises(InvalidKeyError): -+ jwt.decode( -+ encoded_bad, -+ pub_key_bytes, -+ algorithms=jwt.algorithms.get_default_algorithms(), -+ ) -+ -+ # Of course the receiver should specify ed25519 algorithm to be used if -+ # they specify ed25519 public key. However, if other algorithms are used, -+ # the POC does not work -+ # HMAC specifies illegal strings for the HMAC secret in jwt/algorithms.py -+ # -+ # invalid_str ings = [ -+ # b"-----BEGIN PUBLIC KEY-----", -+ # b"-----BEGIN CERTIFICATE-----", -+ # b"-----BEGIN RSA PUBLIC KEY-----", -+ # b"ssh-rsa", -+ # ] -+ # -+ # However, OKPAlgorithm (ed25519) accepts the following in jwt/algorithms.py: -+ # -+ # if "-----BEGIN PUBLIC" in str_key: -+ # return load_pem_public_key(key) -+ # if "-----BEGIN PRIVATE" in str_key: -+ # return load_pem_private_key(key, password=None) -+ # if str_key[0:4] == "ssh-": -+ # return load_ssh_public_key(key) -+ # -+ # These should most likely made to match each other to prevent this behavior -+ -+ # POC for the ecdsa-sha2-nistp256 format. -+ # openssl ecparam -genkey -name prime256v1 -noout -out ec256-key-priv.pem -+ # openssl ec -in ec256-key-priv.pem -pubout > ec256-key-pub.pem -+ # ssh-keygen -y -f ec256-key-priv.pem > ec256-key-ssh.pub -+ -+ # Making a good jwt token that should work by signing it with the private key -+ # encoded_good = jwt.encode({"test": 1234}, ssh_priv_key_bytes, algorithm="ES256") -+ encoded_good = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoxMjM0fQ.NX42mS8cNqYoL3FOW9ZcKw8Nfq2mb6GqJVADeMA1-kyHAclilYo_edhdM_5eav9tBRQTlL0XMeu_WFE_mz3OXg" -+ -+ # Using HMAC with the ssh public key to trick the receiver to think that the public key is a HMAC secret -+ # encoded_bad = jwt.encode({"test": 1234}, ssh_key_bytes, algorithm="HS256") -+ encoded_bad = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoxMjM0fQ.5eYfbrbeGYmWfypQ6rMWXNZ8bdHcqKng5GPr9MJZITU" -+ -+ # Both of the jwt tokens are validated as valid -+ jwt.decode( -+ encoded_good, -+ ssh_key_bytes, -+ algorithms=jwt.algorithms.get_default_algorithms() -+ ) -+ -+ with pytest.raises(InvalidKeyError): -+ jwt.decode( -+ encoded_bad, -+ ssh_key_bytes, -+ algorithms=jwt.algorithms.get_default_algorithms() -+ ) -diff --git a/tests/test_algorithms.py b/tests/test_algorithms.py -index b6a73fc..777c108 100644 ---- a/tests/test_algorithms.py -+++ b/tests/test_algorithms.py -@@ -669,7 +669,7 @@ class TestOKPAlgorithms: - def test_okp_ed25519_should_reject_non_string_key(self): - algo = OKPAlgorithm() - -- with pytest.raises(TypeError): -+ with pytest.raises(InvalidKeyError): - algo.prepare_key(None) - - with open(key_path("testkey_ed25519")) as keyfile: --- -1.8.3.1 - diff --git a/backport-chore-fix-lint-errors.patch b/backport-chore-fix-lint-errors.patch deleted file mode 100644 index e107052775a9bd8ca5e776d2e58cce71cf1ad176..0000000000000000000000000000000000000000 --- a/backport-chore-fix-lint-errors.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 23feb3b068deb5f077e37c98541e7151782e544f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jos=C3=A9=20Padilla?= -Date: Sun, 15 May 2022 15:18:29 -0400 -Subject: [PATCH] chore: fix lint errors - ---- - jwt/utils.py | 2 +- - tests/test_advisory.py | 19 +++++++++++-------- - 2 files changed, 12 insertions(+), 9 deletions(-) - -diff --git a/jwt/utils.py b/jwt/utils.py -index 8ab73b4..b8ad5fa 100644 ---- a/jwt/utils.py -+++ b/jwt/utils.py -@@ -136,7 +136,7 @@ def is_pem_format(key: bytes) -> bool: - - # Based on https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b/src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46 - _CERT_SUFFIX = b"-cert-v01@openssh.com" --_SSH_PUBKEY_RC = re.compile(br"\A(\S+)[ \t]+(\S+)") -+_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)") - _SSH_KEY_FORMATS = [ - b"ssh-ed25519", - b"ssh-rsa", -diff --git a/tests/test_advisory.py b/tests/test_advisory.py -index a4a7d23..ed768d4 100644 ---- a/tests/test_advisory.py -+++ b/tests/test_advisory.py -@@ -1,14 +1,17 @@ --import jwt - import pytest -+ -+import jwt - from jwt.exceptions import InvalidKeyError - - from .utils import crypto_required - --priv_key_bytes = b'''-----BEGIN PRIVATE KEY----- -+priv_key_bytes = b"""-----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIIbBhdo2ah7X32i50GOzrCr4acZTe6BezUdRIixjTAdL -------END PRIVATE KEY-----''' -+-----END PRIVATE KEY-----""" - --pub_key_bytes = b'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPL1I9oiq+B8crkmuV4YViiUnhdLjCp3hvy1bNGuGfNL' -+pub_key_bytes = ( -+ b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPL1I9oiq+B8crkmuV4YViiUnhdLjCp3hvy1bNGuGfNL" -+) - - ssh_priv_key_bytes = b"""-----BEGIN EC PRIVATE KEY----- - MHcCAQEEIOWc7RbaNswMtNtc+n6WZDlUblMr2FBPo79fcGXsJlGQoAoGCCqGSM49 -@@ -41,11 +44,11 @@ class TestAdvisory: - # Making a good jwt token that should work by signing it - # with the private key - # encoded_good = jwt.encode({"test": 1234}, priv_key_bytes, algorithm="EdDSA") -- encoded_good = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJ0ZXN0IjoxMjM0fQ.M5y1EEavZkHSlj9i8yi9nXKKyPBSAUhDRTOYZi3zZY11tZItDaR3qwAye8pc74_lZY3Ogt9KPNFbVOSGnUBHDg' -+ encoded_good = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJ0ZXN0IjoxMjM0fQ.M5y1EEavZkHSlj9i8yi9nXKKyPBSAUhDRTOYZi3zZY11tZItDaR3qwAye8pc74_lZY3Ogt9KPNFbVOSGnUBHDg" - - # Using HMAC with the public key to trick the receiver to think that the - # public key is a HMAC secret -- encoded_bad = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0ZXN0IjoxMjM0fQ.6ulDpqSlbHmQ8bZXhZRLFko9SwcHrghCwh8d-exJEE4' -+ encoded_bad = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0ZXN0IjoxMjM0fQ.6ulDpqSlbHmQ8bZXhZRLFko9SwcHrghCwh8d-exJEE4" - - # Both of the jwt tokens are validated as valid - jwt.decode( -@@ -101,12 +104,12 @@ class TestAdvisory: - jwt.decode( - encoded_good, - ssh_key_bytes, -- algorithms=jwt.algorithms.get_default_algorithms() -+ algorithms=jwt.algorithms.get_default_algorithms(), - ) - - with pytest.raises(InvalidKeyError): - jwt.decode( - encoded_bad, - ssh_key_bytes, -- algorithms=jwt.algorithms.get_default_algorithms() -+ algorithms=jwt.algorithms.get_default_algorithms(), - ) --- -2.23.0 \ No newline at end of file diff --git a/backport-fix-failing-advisory-test.patch b/backport-fix-failing-advisory-test.patch deleted file mode 100644 index 22b0dc234abde22cf58b6a75a9b1ccfacbc1d32f..0000000000000000000000000000000000000000 --- a/backport-fix-failing-advisory-test.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 96f3f0275745c5a455c019a0d3476a054980e8ea Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jos=C3=A9=20Padilla?= -Date: Thu, 12 May 2022 14:44:55 -0400 -Subject: [PATCH] fix: failing advisory test - ---- - tests/test_advisory.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/tests/test_advisory.py b/tests/test_advisory.py -index f70f54b..a4a7d23 100644 ---- a/tests/test_advisory.py -+++ b/tests/test_advisory.py -@@ -2,6 +2,8 @@ import jwt - import pytest - from jwt.exceptions import InvalidKeyError - -+from .utils import crypto_required -+ - priv_key_bytes = b'''-----BEGIN PRIVATE KEY----- - MC4CAQAwBQYDK2VwBCIEIIbBhdo2ah7X32i50GOzrCr4acZTe6BezUdRIixjTAdL - -----END PRIVATE KEY-----''' -@@ -18,6 +20,7 @@ ssh_key_bytes = b"""ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz - - - class TestAdvisory: -+ @crypto_required - def test_ghsa_ffqj_6fqr_9h24(self): - # Generate ed25519 private key - # private_key = ed25519.Ed25519PrivateKey.generate() --- -2.23.0 \ No newline at end of file diff --git a/python-jwt.spec b/python-jwt.spec index 19dbefced7f5e52d2d4390a0b4e6feb5a84df4a3..a39ad968116369b2f3b29ba8383556bcb04c99cd 100644 --- a/python-jwt.spec +++ b/python-jwt.spec @@ -1,17 +1,14 @@ %global srcname jwt %bcond_without tests Name: python-jwt -Version: 2.3.0 -Release: 4 +Version: 2.5.0 +Release: 1 Summary: JSON Web Token implementation in Python License: MIT URL: https://github.com/jpadilla/pyjwt Source0: https://files.pythonhosted.org/packages/source/P/PyJWT/PyJWT-%{version}.tar.gz BuildArch: noarch -Patch6000: backport-CVE-2022-29217.patch -Patch6001: backport-fix-failing-advisory-test.patch -Patch6002: backport-chore-fix-lint-errors.patch %if %{with tests} BuildRequires: python3-pytest python3-pytest-cov python3-pytest-runner @@ -51,12 +48,14 @@ Requires: python%{python3_pkgversion}-cryptography %license LICENSE %{python3_sitelib}/%{srcname}/ %{python3_sitelib}/*.egg-info -#%{_bindir}/pyjwt %files help %doc README.rst %changelog +* Mon Apr 08 2024 wangjing - 2.5.0-1 +- update package of version 2.5.0 + * Mon Jul 18 2022 yanglongkang - 2.3.0-4 - fix failing advisory test and fix lint errors