Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-python-jose for 
openSUSE:Factory checked in at 2024-05-06 17:55:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-python-jose (Old)
 and      /work/SRC/openSUSE:Factory/.python-python-jose.new.1880 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-python-jose"

Mon May  6 17:55:08 2024 rev:7 rq:1172135 version:3.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-python-jose/python-python-jose.changes    
2023-06-14 16:31:47.511372697 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-python-jose.new.1880/python-python-jose.changes
  2024-05-06 17:56:24.805990957 +0200
@@ -1,0 +2,8 @@
+Mon May  6 07:11:18 UTC 2024 - Daniel Garcia <[email protected]>
+
+- Add upstream patches:
+   * CVE-2024-33663.patch, bsc#1223417, gh#mpdavis/python-jose#349
+   * CVE-2024-33664.patch, bsc#1223422, gh#mpdavis/python-jose#345
+   * fix-tests-ecdsa-019.patch, gh#mpdavis/python-jose#350
+
+-------------------------------------------------------------------

New:
----
  CVE-2024-33663.patch
  CVE-2024-33664.patch
  fix-tests-ecdsa-019.patch

BETA DEBUG BEGIN:
  New:- Add upstream patches:
   * CVE-2024-33663.patch, bsc#1223417, gh#mpdavis/python-jose#349
   * CVE-2024-33664.patch, bsc#1223422, gh#mpdavis/python-jose#345
  New:   * CVE-2024-33663.patch, bsc#1223417, gh#mpdavis/python-jose#349
   * CVE-2024-33664.patch, bsc#1223422, gh#mpdavis/python-jose#345
   * fix-tests-ecdsa-019.patch, gh#mpdavis/python-jose#350
  New:   * CVE-2024-33664.patch, bsc#1223422, gh#mpdavis/python-jose#345
   * fix-tests-ecdsa-019.patch, gh#mpdavis/python-jose#350
BETA DEBUG END:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-python-jose.spec ++++++
--- /var/tmp/diff_new_pack.yih4FV/_old  2024-05-06 17:56:25.306009159 +0200
+++ /var/tmp/diff_new_pack.yih4FV/_new  2024-05-06 17:56:25.306009159 +0200
@@ -1,7 +1,7 @@
 #
-# spec file
+# spec file for package python-python-jose
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -47,6 +47,12 @@
 URL:            https://github.com/mpdavis/python-jose
 Source:         
https://files.pythonhosted.org/packages/source/p/python-jose/python-jose-%{version}.tar.gz
 Patch0:         unpin-deps.patch
+# PATCH-FIX-UPSTREAM CVE-2024-33664.patch gh#mpdavis/python-jose#345
+Patch1:         CVE-2024-33664.patch
+# PATCH-FIX-UPSTREAM CVE-2024-33663.patch gh#mpdavis/python-jose#349
+Patch2:         CVE-2024-33663.patch
+# PATCH-FIX-UPSTREAM fix-tests-ecdsa-019.patch gh#mpdavis/python-jose#350
+Patch3:         fix-tests-ecdsa-019.patch
 BuildRequires:  %{python_module setuptools >= 39.2.0}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
@@ -55,6 +61,7 @@
 Requires:       python-rsa
 BuildArch:      noarch
 %if %{with test}
+BuildRequires:  %{python_module pycryptodome}
 BuildRequires:  %{python_module pytest}
 %if %{with testcryptography}
 BuildRequires:  %{python_module python-jose-cryptography = %{version}}

++++++ CVE-2024-33663.patch ++++++
>From 34bd82c43ea31da5b9deaa25ff591905a180bdf7 Mon Sep 17 00:00:00 2001
From: Daniel Garcia Moreno <[email protected]>
Date: Thu, 2 May 2024 09:29:54 +0200
Subject: [PATCH 1/4] Improve asymmetric key check in CryptographyHMACKey

This change should fix https://github.com/mpdavis/python-jose/issues/346
security issue.

The code is based on pyjwt change:
https://github.com/jpadilla/pyjwt/commit/9c528670c455b8d948aff95ed50e22940d1ad3fc
---
 jose/backends/cryptography_backend.py | 72 ++++++++++++++++++++++++---
 tests/test_jwt.py                     | 35 ++++++++++++-
 2 files changed, 98 insertions(+), 9 deletions(-)

Index: python-jose-3.3.0/jose/backends/cryptography_backend.py
===================================================================
--- python-jose-3.3.0.orig/jose/backends/cryptography_backend.py
+++ python-jose-3.3.0/jose/backends/cryptography_backend.py
@@ -17,6 +17,7 @@ from cryptography.x509 import load_pem_x
 from ..constants import ALGORITHMS
 from ..exceptions import JWEError, JWKError
 from ..utils import base64_to_long, base64url_decode, base64url_encode, 
ensure_binary, long_to_base64
+from ..utils import is_pem_format, is_ssh_key
 from .base import Key
 
 _binding = None
@@ -552,14 +553,7 @@ class CryptographyHMACKey(Key):
         if isinstance(key, str):
             key = key.encode("utf-8")
 
-        invalid_strings = [
-            b"-----BEGIN PUBLIC KEY-----",
-            b"-----BEGIN RSA PUBLIC KEY-----",
-            b"-----BEGIN CERTIFICATE-----",
-            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 JWKError(
                 "The specified key is an asymmetric key or x509 certificate 
and"
                 " should not be used as an HMAC secret."
Index: python-jose-3.3.0/tests/test_jwt.py
===================================================================
--- python-jose-3.3.0.orig/tests/test_jwt.py
+++ python-jose-3.3.0/tests/test_jwt.py
@@ -5,7 +5,8 @@ from datetime import datetime, timedelta
 import pytest
 
 from jose import jws, jwt
-from jose.exceptions import JWTError
+from jose.constants import ALGORITHMS
+from jose.exceptions import JWTError, JWKError
 
 
 @pytest.fixture
@@ -56,7 +57,7 @@ class TestJWT:
         ],
     )
     def test_numeric_key(self, key, token):
-        token_info = jwt.decode(token, key)
+        token_info = jwt.decode(token, key, algorithms=ALGORITHMS.SUPPORTED)
         assert token_info == {"name": "test"}
 
     def test_invalid_claims_json(self):
@@ -108,7 +109,7 @@ class TestJWT:
 
     def test_non_default_headers(self, claims, key, headers):
         encoded = jwt.encode(claims, key, headers=headers)
-        decoded = jwt.decode(encoded, key)
+        decoded = jwt.decode(encoded, key, algorithms=ALGORITHMS.HS256)
         assert claims == decoded
         all_headers = jwt.get_unverified_headers(encoded)
         for k, v in headers.items():
@@ -161,7 +162,7 @@ class TestJWT:
 
         token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" ".eyJhIjoiYiJ9" 
".jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8"
 
-        decoded = jwt.decode(token, key)
+        decoded = jwt.decode(token, key, algorithms=ALGORITHMS.SUPPORTED)
 
         assert decoded == claims
 
@@ -193,7 +194,7 @@ class TestJWT:
         options = {"leeway": leeway}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, options=options)
+        jwt.decode(token, key, options=options, algorithms=ALGORITHMS.HS256)
 
     def test_iat_not_int(self, key):
 
@@ -202,7 +203,7 @@ class TestJWT:
         token = jwt.encode(claims, key)
 
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_nbf_not_int(self, key):
 
@@ -211,7 +212,7 @@ class TestJWT:
         token = jwt.encode(claims, key)
 
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_nbf_datetime(self, key):
 
@@ -220,7 +221,7 @@ class TestJWT:
         claims = {"nbf": nbf}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key)
+        jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_nbf_with_leeway(self, key):
 
@@ -233,7 +234,7 @@ class TestJWT:
         options = {"leeway": 10}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, options=options)
+        jwt.decode(token, key, options=options, algorithms=ALGORITHMS.HS256)
 
     def test_nbf_in_future(self, key):
 
@@ -244,7 +245,7 @@ class TestJWT:
         token = jwt.encode(claims, key)
 
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_nbf_skip(self, key):
 
@@ -255,11 +256,11 @@ class TestJWT:
         token = jwt.encode(claims, key)
 
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
         options = {"verify_nbf": False}
 
-        jwt.decode(token, key, options=options)
+        jwt.decode(token, key, options=options, algorithms=ALGORITHMS.HS256)
 
     def test_exp_not_int(self, key):
 
@@ -268,7 +269,7 @@ class TestJWT:
         token = jwt.encode(claims, key)
 
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_exp_datetime(self, key):
 
@@ -277,7 +278,7 @@ class TestJWT:
         claims = {"exp": exp}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key)
+        jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_exp_with_leeway(self, key):
 
@@ -290,7 +291,7 @@ class TestJWT:
         options = {"leeway": 10}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, options=options)
+        jwt.decode(token, key, options=options, algorithms=ALGORITHMS.HS256)
 
     def test_exp_in_past(self, key):
 
@@ -301,7 +302,7 @@ class TestJWT:
         token = jwt.encode(claims, key)
 
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_exp_skip(self, key):
 
@@ -312,11 +313,11 @@ class TestJWT:
         token = jwt.encode(claims, key)
 
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
         options = {"verify_exp": False}
 
-        jwt.decode(token, key, options=options)
+        jwt.decode(token, key, options=options, algorithms=ALGORITHMS.HS256)
 
     def test_aud_string(self, key):
 
@@ -325,7 +326,7 @@ class TestJWT:
         claims = {"aud": aud}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, audience=aud)
+        jwt.decode(token, key, audience=aud, algorithms=ALGORITHMS.HS256)
 
     def test_aud_list(self, key):
 
@@ -334,7 +335,7 @@ class TestJWT:
         claims = {"aud": [aud]}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, audience=aud)
+        jwt.decode(token, key, audience=aud, algorithms=ALGORITHMS.HS256)
 
     def test_aud_list_multiple(self, key):
 
@@ -343,7 +344,7 @@ class TestJWT:
         claims = {"aud": [aud, "another"]}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, audience=aud)
+        jwt.decode(token, key, audience=aud, algorithms=ALGORITHMS.HS256)
 
     def test_aud_list_is_strings(self, key):
 
@@ -353,7 +354,7 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key, audience=aud)
+            jwt.decode(token, key, audience=aud, algorithms=ALGORITHMS.HS256)
 
     def test_aud_case_sensitive(self, key):
 
@@ -363,14 +364,14 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key, audience="AUDIENCE")
+            jwt.decode(token, key, audience="AUDIENCE", 
algorithms=ALGORITHMS.HS256)
 
     def test_aud_empty_claim(self, claims, key):
 
         aud = "audience"
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, audience=aud)
+        jwt.decode(token, key, audience=aud, algorithms=ALGORITHMS.HS256)
 
     def test_aud_not_string_or_list(self, key):
 
@@ -380,7 +381,7 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_aud_given_number(self, key):
 
@@ -390,7 +391,7 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key, audience=1)
+            jwt.decode(token, key, audience=1, algorithms=ALGORITHMS.HS256)
 
     def test_iss_string(self, key):
 
@@ -399,7 +400,7 @@ class TestJWT:
         claims = {"iss": iss}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, issuer=iss)
+        jwt.decode(token, key, issuer=iss, algorithms=ALGORITHMS.HS256)
 
     def test_iss_list(self, key):
 
@@ -408,7 +409,7 @@ class TestJWT:
         claims = {"iss": iss}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, issuer=["https://issuer";, "issuer"])
+        jwt.decode(token, key, issuer=["https://issuer";, "issuer"], 
algorithms=ALGORITHMS.HS256)
 
     def test_iss_tuple(self, key):
 
@@ -417,7 +418,7 @@ class TestJWT:
         claims = {"iss": iss}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, issuer=("https://issuer";, "issuer"))
+        jwt.decode(token, key, issuer=("https://issuer";, "issuer"), 
algorithms=ALGORITHMS.HS256)
 
     def test_iss_invalid(self, key):
 
@@ -427,7 +428,7 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key, issuer="another")
+            jwt.decode(token, key, issuer="another", 
algorithms=ALGORITHMS.HS256)
 
     def test_sub_string(self, key):
 
@@ -436,7 +437,7 @@ class TestJWT:
         claims = {"sub": sub}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key)
+        jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_sub_invalid(self, key):
 
@@ -446,7 +447,7 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_sub_correct(self, key):
 
@@ -455,7 +456,7 @@ class TestJWT:
         claims = {"sub": sub}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key, subject=sub)
+        jwt.decode(token, key, subject=sub, algorithms=ALGORITHMS.HS256)
 
     def test_sub_incorrect(self, key):
 
@@ -465,7 +466,7 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key, subject="another")
+            jwt.decode(token, key, subject="another", 
algorithms=ALGORITHMS.HS256)
 
     def test_jti_string(self, key):
 
@@ -474,7 +475,7 @@ class TestJWT:
         claims = {"jti": jti}
 
         token = jwt.encode(claims, key)
-        jwt.decode(token, key)
+        jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_jti_invalid(self, key):
 
@@ -484,33 +485,33 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_at_hash(self, claims, key):
         access_token = "<ACCESS_TOKEN>"
         token = jwt.encode(claims, key, access_token=access_token)
-        payload = jwt.decode(token, key, access_token=access_token)
+        payload = jwt.decode(token, key, access_token=access_token, 
algorithms=ALGORITHMS.HS256)
         assert "at_hash" in payload
 
     def test_at_hash_invalid(self, claims, key):
         token = jwt.encode(claims, key, access_token="<ACCESS_TOKEN>")
         with pytest.raises(JWTError):
-            jwt.decode(token, key, access_token="<OTHER_TOKEN>")
+            jwt.decode(token, key, access_token="<OTHER_TOKEN>", 
algorithms=ALGORITHMS.HS256)
 
     def test_at_hash_missing_access_token(self, claims, key):
         token = jwt.encode(claims, key, access_token="<ACCESS_TOKEN>")
         with pytest.raises(JWTError):
-            jwt.decode(token, key)
+            jwt.decode(token, key, algorithms=ALGORITHMS.HS256)
 
     def test_at_hash_missing_claim(self, claims, key):
         token = jwt.encode(claims, key)
-        payload = jwt.decode(token, key, access_token="<ACCESS_TOKEN>")
+        payload = jwt.decode(token, key, access_token="<ACCESS_TOKEN>", 
algorithms=ALGORITHMS.HS256)
         assert "at_hash" not in payload
 
     def test_at_hash_unable_to_calculate(self, claims, key):
         token = jwt.encode(claims, key, access_token="<ACCESS_TOKEN>")
         with pytest.raises(JWTError):
-            jwt.decode(token, key, access_token="\xe2")
+            jwt.decode(token, key, access_token="\xe2", 
algorithms=ALGORITHMS.HS256)
 
     def test_bad_claims(self):
         bad_token = 
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.iOJ5SiNfaNO_pa2J4Umtb3b3zmk5C18-mhTCVNsjnck"
@@ -548,9 +549,48 @@ class TestJWT:
 
         token = jwt.encode(claims, key)
         with pytest.raises(JWTError):
-            jwt.decode(token, key, options=options, audience=str(value))
+            jwt.decode(token, key, options=options, audience=str(value), 
algorithms=ALGORITHMS.HS256)
 
         new_claims = dict(claims)
         new_claims[claim] = value
         token = jwt.encode(new_claims, key)
-        jwt.decode(token, key, options=options, audience=str(value))
+        jwt.decode(token, key, options=options, audience=str(value), 
algorithms=ALGORITHMS.HS256)
+
+    def test_CVE_2024_33663(self):
+        """Test based on https://github.com/mpdavis/python-jose/issues/346""";
+        try:
+            from Crypto.PublicKey import ECC
+            from Crypto.Hash import HMAC, SHA256
+        except ModuleNotFoundError:
+            pytest.skip("pycryptodome module not installed")
+
+        # ----- SETUP -----
+        # generate an asymmetric ECC keypair
+        # !! signing should only be possible with the private key !!
+        KEY = ECC.generate(curve='P-256')
+
+        # PUBLIC KEY, AVAILABLE TO USER
+        # CAN BE RECOVERED THROUGH E.G. PUBKEY RECOVERY WITH TWO SIGNATURES:
+        # 
https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery
+        # https://github.com/FlorianPicca/JWT-Key-Recovery
+        PUBKEY = KEY.public_key().export_key(format='OpenSSH').encode()
+
+        # ---- CLIENT SIDE -----
+        # without knowing the private key, a valid token can be constructed
+        # YIKES!!
+
+        b64 = lambda x:base64.urlsafe_b64encode(x).replace(b'=',b'')
+        payload = b64(b'{"alg":"HS256"}') + b'.' + b64(b'{"pwned":true}')
+        hasher = HMAC.new(PUBKEY, digestmod=SHA256)
+        hasher.update(payload)
+        evil_token = payload + b'.' + b64(hasher.digest())
+
+        # ---- SERVER SIDE -----
+        # verify and decode the token using the public key, as is custom
+        # algorithm field is left unspecified
+        # but the library will happily still verify without warning, trusting 
the user-controlled alg field of the token header
+        with pytest.raises(JWKError):
+            data = jwt.decode(evil_token, PUBKEY, algorithms=ALGORITHMS.HS256)
+
+        with pytest.raises(JWTError, match='.*required.*"algorithms".*'):
+            data = jwt.decode(evil_token, PUBKEY)
Index: python-jose-3.3.0/jose/jwt.py
===================================================================
--- python-jose-3.3.0.orig/jose/jwt.py
+++ python-jose-3.3.0/jose/jwt.py
@@ -138,6 +138,14 @@ def decode(token, key, algorithms=None,
 
     verify_signature = defaults.get("verify_signature", True)
 
+    # Forbid the usage of the jwt.decode without alogrightms parameter
+    # See https://github.com/mpdavis/python-jose/issues/346 for more
+    # information CVE-2024-33663
+    if verify_signature and algorithms is None:
+        raise JWTError("It is required that you pass in a value for "
+                       'the "algorithms" argument when calling '
+                       "decode().")
+
     try:
         payload = jws.verify(token, key, algorithms, verify=verify_signature)
     except JWSError as e:
Index: python-jose-3.3.0/jose/backends/native.py
===================================================================
--- python-jose-3.3.0.orig/jose/backends/native.py
+++ python-jose-3.3.0/jose/backends/native.py
@@ -6,6 +6,7 @@ from jose.backends.base import Key
 from jose.constants import ALGORITHMS
 from jose.exceptions import JWKError
 from jose.utils import base64url_decode, base64url_encode
+from jose.utils import is_pem_format, is_ssh_key
 
 
 def get_random_bytes(num_bytes):
@@ -36,14 +37,7 @@ class HMACKey(Key):
         if isinstance(key, str):
             key = key.encode("utf-8")
 
-        invalid_strings = [
-            b"-----BEGIN PUBLIC KEY-----",
-            b"-----BEGIN RSA PUBLIC KEY-----",
-            b"-----BEGIN CERTIFICATE-----",
-            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 JWKError(
                 "The specified key is an asymmetric key or x509 certificate 
and"
                 " should not be used as an HMAC secret."
Index: python-jose-3.3.0/jose/utils.py
===================================================================
--- python-jose-3.3.0.orig/jose/utils.py
+++ python-jose-3.3.0/jose/utils.py
@@ -1,3 +1,4 @@
+import re
 import base64
 import struct
 
@@ -106,3 +107,75 @@ def ensure_binary(s):
     if isinstance(s, str):
         return s.encode("utf-8", "strict")
     raise TypeError(f"not expecting type '{type(s)}'")
+
+
+# Based on 
https://github.com/jpadilla/pyjwt/commit/9c528670c455b8d948aff95ed50e22940d1ad3fc
+# 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):
+    """
+    Return True if the key is PEM format
+    This function uses the list of valid PEM headers defined in
+    _PEMS dict.
+    """
+    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"[email protected]"
+_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):
+    """
+    Return True if the key is a SSH key
+    This function uses the list of valid SSH key format defined in
+    _SSH_KEY_FORMATS dict.
+    """
+    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
Index: python-jose-3.3.0/tests/algorithms/test_HMAC.py
===================================================================
--- python-jose-3.3.0.orig/tests/algorithms/test_HMAC.py
+++ python-jose-3.3.0/tests/algorithms/test_HMAC.py
@@ -14,14 +14,17 @@ class TestHMACAlgorithm:
 
     def test_RSA_key(self):
         key = "-----BEGIN PUBLIC KEY-----"
+        key += "\n\n\n-----END PUBLIC KEY-----"
         with pytest.raises(JOSEError):
             HMACKey(key, ALGORITHMS.HS256)
 
         key = "-----BEGIN RSA PUBLIC KEY-----"
+        key += "\n\n\n-----END RSA PUBLIC KEY-----"
         with pytest.raises(JOSEError):
             HMACKey(key, ALGORITHMS.HS256)
 
         key = "-----BEGIN CERTIFICATE-----"
+        key += "\n\n\n-----END CERTIFICATE-----"
         with pytest.raises(JOSEError):
             HMACKey(key, ALGORITHMS.HS256)
 

++++++ CVE-2024-33664.patch ++++++
>From 483529ee93a3ab510ab579d4d4cc644dba926ade Mon Sep 17 00:00:00 2001
From: princekhunt <[email protected]>
Date: Wed, 20 Mar 2024 22:12:36 +0530
Subject: [PATCH] limit token size to 250 KB

---
 jose/jwe.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/jose/jwe.py b/jose/jwe.py
index 2c387ff4..1e0833e7 100644
--- a/jose/jwe.py
+++ b/jose/jwe.py
@@ -76,6 +76,11 @@ def decrypt(jwe_str, key):
         >>> jwe.decrypt(jwe_string, 'asecret128bitkey')
         'Hello, World!'
     """
+    
+    # limit the token size to 250 KB
+    if len(jwe_str) > 250 * 1024:
+        raise JWEError("JWE string exceeds 250 KB")
+    
     header, encoded_header, encrypted_key, iv, cipher_text, auth_tag = 
_jwe_compact_deserialize(jwe_str)
 
     # Verify that the implementation understands and can process all

++++++ fix-tests-ecdsa-019.patch ++++++
>From ec5c62249b4f67b15376d3cbc96d2b1d272d0552 Mon Sep 17 00:00:00 2001
From: Daniel Garcia Moreno <[email protected]>
Date: Thu, 2 May 2024 18:47:43 +0200
Subject: [PATCH] test: Fix tests with ecdsa 0.19.0

Fix https://github.com/mpdavis/python-jose/issues/348
---
 tests/algorithms/test_EC_compat.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Index: python-jose-3.3.0/tests/algorithms/test_EC_compat.py
===================================================================
--- python-jose-3.3.0.orig/tests/algorithms/test_EC_compat.py
+++ python-jose-3.3.0/tests/algorithms/test_EC_compat.py
@@ -37,7 +37,7 @@ class TestBackendEcdsaCompatibility:
         key = BackendFrom(private_key, ALGORITHMS.ES256)
         key2 = BackendTo(private_key, ALGORITHMS.ES256)
 
-        assert key.public_key().to_pem().strip() == 
key2.public_key().to_pem().strip()
+        assert key.public_key().to_pem().strip().replace(b"\n", b"") == 
key2.public_key().to_pem().strip().replace(b"\n", b"")
 
     @pytest.mark.parametrize("BackendFrom", [ECDSAECKey, CryptographyECKey])
     @pytest.mark.parametrize("BackendTo", [ECDSAECKey, CryptographyECKey])
@@ -45,7 +45,7 @@ class TestBackendEcdsaCompatibility:
         key = BackendFrom(private_key, ALGORITHMS.ES256)
         key2 = BackendTo(private_key, ALGORITHMS.ES256)
 
-        assert key.to_pem().strip() == key2.to_pem().strip()
+        assert key.to_pem().strip().replace(b"\n", b"") == 
key2.to_pem().strip().replace(b"\n", b"")
 
     @pytest.mark.parametrize("BackendFrom", [ECDSAECKey, CryptographyECKey])
     @pytest.mark.parametrize("BackendTo", [ECDSAECKey, CryptographyECKey])
@@ -57,7 +57,7 @@ class TestBackendEcdsaCompatibility:
 
         pub_target = BackendTo(pub_pem_source, ALGORITHMS.ES256)
 
-        assert pub_pem_source == pub_target.to_pem().strip()
+        assert pub_pem_source.replace(b"\n", b"") == 
pub_target.to_pem().strip().replace(b"\n", b"")
 
     @pytest.mark.parametrize("BackendFrom", [ECDSAECKey, CryptographyECKey])
     @pytest.mark.parametrize("BackendTo", [ECDSAECKey, CryptographyECKey])
@@ -68,4 +68,4 @@ class TestBackendEcdsaCompatibility:
 
         target = BackendTo(pem_source, ALGORITHMS.ES256)
 
-        assert pem_source == target.to_pem().strip()
+        assert pem_source.replace(b"\n", b"") == 
target.to_pem().strip().replace(b"\n", b"")
Index: python-jose-3.3.0/tests/algorithms/test_EC.py
===================================================================
--- python-jose-3.3.0.orig/tests/algorithms/test_EC.py
+++ python-jose-3.3.0/tests/algorithms/test_EC.py
@@ -104,7 +104,7 @@ class TestECAlgorithm:
     def test_to_pem(self):
         key = ECKey(private_key, ALGORITHMS.ES256)
         assert not key.is_public()
-        assert key.to_pem().strip() == private_key.strip().encode("utf-8")
+        assert key.to_pem().strip().replace(b"\n", b"") == 
private_key.strip().encode("utf-8").replace(b"\n", b"")
 
         public_pem = key.public_key().to_pem()
         assert ECKey(public_pem, ALGORITHMS.ES256).is_public()

Reply via email to