Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-joserfc for openSUSE:Factory checked in at 2026-09-02 17:00:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-joserfc (Old) and /work/SRC/openSUSE:Factory/.python-joserfc.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-joserfc" Wed Sep 2 17:00:53 2026 rev:15 rq:1375236 version:1.7.5 Changes: -------- --- /work/SRC/openSUSE:Factory/python-joserfc/python-joserfc.changes 2026-08-01 18:37:09.435997647 +0200 +++ /work/SRC/openSUSE:Factory/.python-joserfc.new.1265/python-joserfc.changes 2026-09-02 17:01:03.899835628 +0200 @@ -1,0 +2,8 @@ +Tue Sep 1 21:37:09 UTC 2026 - Dirk Müller <[email protected]> + +- update to 1.7.5: + * JWK: Ignore keys with unknown kty values when importing a key + set. + * JWE: Add max_recipients to JWERegistry. + +------------------------------------------------------------------- Old: ---- joserfc-1.7.4.tar.gz New: ---- joserfc-1.7.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-joserfc.spec ++++++ --- /var/tmp/diff_new_pack.O9a94T/_old 2026-09-02 17:01:04.501856309 +0200 +++ /var/tmp/diff_new_pack.O9a94T/_new 2026-09-02 17:01:04.502856343 +0200 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-joserfc -Version: 1.7.4 +Version: 1.7.5 Release: 0 Summary: The ultimate Python library for JOSE RFCs License: BSD-3-Clause ++++++ joserfc-1.7.4.tar.gz -> joserfc-1.7.5.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/PKG-INFO new/joserfc-1.7.5/PKG-INFO --- old/joserfc-1.7.4/PKG-INFO 2026-07-19 17:42:30.915866400 +0200 +++ new/joserfc-1.7.5/PKG-INFO 2026-08-29 15:05:19.208686000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: joserfc -Version: 1.7.4 +Version: 1.7.5 Summary: The ultimate Python library for JOSE RFCs, including JWS, JWE, JWK, JWA, JWT Author-email: Hsiaoming Yang <[email protected]> License: BSD-3-Clause diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/docs/changelog.rst new/joserfc-1.7.5/docs/changelog.rst --- old/joserfc-1.7.4/docs/changelog.rst 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/docs/changelog.rst 2026-08-29 15:05:08.757169700 +0200 @@ -12,6 +12,14 @@ .. module:: joserfc :noindex: +1.7.5 +----- + +**Released on August 29, 2026** + +- **JWK**: Ignore keys with unknown ``kty`` values when importing a key set. +- **JWE**: Add ``max_recipients`` to ``JWERegistry``. + 1.7.4 ----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/docs/conf.py new/joserfc-1.7.5/docs/conf.py --- old/joserfc-1.7.4/docs/conf.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/docs/conf.py 2026-08-29 15:05:08.757169700 +0200 @@ -33,7 +33,7 @@ ] iconify_script_url = "" -sponsors_json_url = "https://cdn.jsdelivr.net/gh/lepture/lepture/sponsors.json" +sponsors_json_url = "https://cdn.jsdelivr.net/gh/authlib/assets/sponsors.json" extlinks = { "user": ("https://github.com/%s", "@%s"), @@ -69,7 +69,11 @@ }, ], }, - {"title": "Support us", "url": "/en/sponsors"}, + { + "title": "Sponsors", + "url": "https://authlib.org/sponsors/", + "external": True, + }, ], } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/src/joserfc/__init__.py new/joserfc-1.7.5/src/joserfc/__init__.py --- old/joserfc-1.7.4/src/joserfc/__init__.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/src/joserfc/__init__.py 2026-08-29 15:05:08.759605600 +0200 @@ -1,4 +1,4 @@ -__version__ = "1.7.4" +__version__ = "1.7.5" __homepage__ = "https://jose.authlib.org/en/" __author__ = "Hsiaoming Yang <[email protected]>" __license__ = "BSD-3-Clause" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/src/joserfc/_keys.py new/joserfc-1.7.5/src/joserfc/_keys.py --- old/joserfc-1.7.4/src/joserfc/_keys.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/src/joserfc/_keys.py 2026-08-29 15:05:08.759626900 +0200 @@ -167,7 +167,13 @@ keys: list[Key] = [] for data in value["keys"]: - keys.append(cls.registry_cls.import_key(data, parameters=parameters)) + # RFC 7517, Section 5: ignore a key whose "kty" is not understood + # rather than failing the whole set (for example a post-quantum key + # published alongside classical ones). + try: + keys.append(cls.registry_cls.import_key(data, parameters=parameters)) + except InvalidKeyTypeError: + continue if not keys: raise MissingKeyError("No keys to import") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/src/joserfc/_rfc7516/json.py new/joserfc-1.7.5/src/joserfc/_rfc7516/json.py --- old/joserfc-1.7.4/src/joserfc/_rfc7516/json.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/src/joserfc/_rfc7516/json.py 2026-08-29 15:05:08.759827400 +0200 @@ -76,12 +76,14 @@ protected = json_b64decode(protected_segment) unprotected = data.get("unprotected") + recipients = data["recipients"] + registry.validate_recipient_count(recipients) base64_segments, bytes_segments, aad = __extract_segments(data, registry) obj = GeneralJSONEncryption(protected, None, unprotected, aad) obj.base64_segments = base64_segments obj.bytes_segments = bytes_segments - for item in data["recipients"]: + for item in recipients: recipient = __extract_recipient(obj, item, registry) obj.recipients.append(recipient) return obj diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/src/joserfc/_rfc7516/message.py new/joserfc-1.7.5/src/joserfc/_rfc7516/message.py --- old/joserfc-1.7.4/src/joserfc/_rfc7516/message.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/src/joserfc/_rfc7516/message.py 2026-08-29 15:05:08.759827400 +0200 @@ -102,17 +102,20 @@ cek_set = set() for recipient in obj.recipients: - headers = recipient.headers() - registry.check_header(headers, True) - # Step 6, Determine the Key Management Mode employed by the algorithm - # specified by the "alg" (algorithm) Header Parameter. - alg = registry.get_alg(headers["alg"]) try: + headers = recipient.headers() + registry.check_header(headers, True) + # Step 6, Determine the Key Management Mode employed by the algorithm + # specified by the "alg" (algorithm) Header Parameter. + alg = registry.get_alg(headers["alg"]) cek = decrypt_recipient(alg, enc, recipient, tag) cek_set.add(cek) except (AssertionError, JoseError) as error: if registry.verify_all_recipients: raise error + else: + if not registry.verify_all_recipients: + break if not cek_set: raise DecodeError("Invalid recipients") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/src/joserfc/_rfc7516/registry.py new/joserfc-1.7.5/src/joserfc/_rfc7516/registry.py --- old/joserfc-1.7.4/src/joserfc/_rfc7516/registry.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/src/joserfc/_rfc7516/registry.py 2026-08-29 15:05:08.759827400 +0200 @@ -43,6 +43,7 @@ :param algorithms: allowed algorithms to be used :param verify_all_recipients: validating all recipients in a JSON serialization :param strict_check_header: only allow header key in the registry to be used + :param max_recipients: max number of recipients in JWE General JSON Serialization """ algorithms: AlgorithmsDict = { @@ -62,6 +63,8 @@ max_ciphertext_length: int = 65536 # 64KB #: max auth tag's size in bytes max_auth_tag_length: int = 64 + #: max number of recipients in JWE General JSON Serialization + max_recipients: int = 16 def __init__( self, @@ -69,6 +72,7 @@ algorithms: Collection[str] | None = None, verify_all_recipients: bool = True, strict_check_header: bool = True, + max_recipients: int | None = None, ): self.header_registry: HeaderRegistryDict = {} self.header_registry.update(JWE_HEADER_REGISTRY) @@ -77,6 +81,8 @@ self.allowed = algorithms self.verify_all_recipients = verify_all_recipients self.strict_check_header = strict_check_header + if max_recipients is not None: + self.max_recipients = max_recipients @classmethod def register(cls, model: JWEAlgorithm) -> None: @@ -122,6 +128,10 @@ if tag and len(tag) > self.max_auth_tag_length: raise ExceededSizeError(f"Auth tag size exceeds {self.max_auth_tag_length} bytes.") + def validate_recipient_count(self, recipients: Collection[t.Any]) -> None: + if len(recipients) > self.max_recipients: + raise ExceededSizeError(f"Recipient count exceeds {self.max_recipients}.") + def get_alg(self, name: str) -> JWEAlgModel: """Get the allowed ("alg") algorithm instance of the given name. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/src/joserfc.egg-info/PKG-INFO new/joserfc-1.7.5/src/joserfc.egg-info/PKG-INFO --- old/joserfc-1.7.4/src/joserfc.egg-info/PKG-INFO 2026-07-19 17:42:30.000000000 +0200 +++ new/joserfc-1.7.5/src/joserfc.egg-info/PKG-INFO 2026-08-29 15:05:19.177635200 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: joserfc -Version: 1.7.4 +Version: 1.7.5 Summary: The ultimate Python library for JOSE RFCs, including JWS, JWE, JWK, JWA, JWT Author-email: Hsiaoming Yang <[email protected]> License: BSD-3-Clause diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/tests/jwe/test_json.py new/joserfc-1.7.5/tests/jwe/test_json.py --- old/joserfc-1.7.4/tests/jwe/test_json.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/tests/jwe/test_json.py 2026-08-29 15:05:08.761375000 +0200 @@ -1,14 +1,33 @@ from unittest import TestCase from joserfc import jwe from joserfc.jwe import GeneralJSONEncryption, FlattenedJSONEncryption +from joserfc.jwa import JWEKeyEncryption from joserfc.jwk import KeySet, RSAKey, ECKey, OctKey from joserfc.errors import ( DecodeError, ConflictAlgorithmError, InvalidKeyTypeError, + ExceededSizeError, ) +class CountingKeyEncryption(JWEKeyEncryption): + name = "TEST-COUNT" + description = "Counting test key encryption" + key_types = ["oct"] + + def __init__(self): + self.decrypt_count = 0 + + def encrypt_cek(self, cek, recipient): + return cek + + def decrypt_cek(self, recipient): + self.decrypt_count += 1 + assert recipient.encrypted_key is not None + return recipient.encrypted_key + + class TestJWEJSON(TestCase): rsa_key = RSAKey.generate_key() ec_key = ECKey.generate_key() @@ -87,6 +106,41 @@ del value["recipients"][0]["encrypted_key"] self.assertRaises(DecodeError, jwe.decrypt_json, value, self.rsa_key) + def test_general_json_recipients_exceeded_size_error(self): + key = OctKey.generate_key(128) + limit = jwe.JWERegistry.max_recipients + obj = GeneralJSONEncryption({"enc": "A128CBC-HS256"}, b"i") + for _ in range(limit + 1): + obj.add_recipient({"alg": "A128KW"}, key) + + value = jwe.encrypt_json(obj, None) + self.assertRaises(ExceededSizeError, jwe.decrypt_json, value, key) + + registry = jwe.JWERegistry(max_recipients=limit + 1) + obj1 = jwe.decrypt_json(value, key, registry=registry) + self.assertEqual(obj1.plaintext, b"i") + + def test_verify_one_recipient_stops_after_success(self): + key = OctKey.generate_key(128) + alg = CountingKeyEncryption() + jwe.JWERegistry.register(alg) + try: + registry = jwe.JWERegistry( + algorithms=[alg.name, "A128GCM"], + verify_all_recipients=False, + ) + obj = GeneralJSONEncryption({"enc": "A128GCM"}, b"i") + obj.add_recipient({"alg": alg.name}, key) + obj.add_recipient({"alg": alg.name}, key) + value = jwe.encrypt_json(obj, None, registry=registry) + alg.decrypt_count = 0 + obj1 = jwe.decrypt_json(value, key, registry=registry) + finally: + del jwe.JWERegistry.algorithms["alg"][alg.name] + + self.assertEqual(obj1.plaintext, b"i") + self.assertEqual(alg.decrypt_count, 1) + def test_flattened_encryption(self): key = OctKey.generate_key(128) protected = {"enc": "A128CBC-HS256"} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/joserfc-1.7.4/tests/jwk/test_jwk_set.py new/joserfc-1.7.5/tests/jwk/test_jwk_set.py --- old/joserfc-1.7.4/tests/jwk/test_jwk_set.py 2026-07-19 17:42:25.000000000 +0200 +++ new/joserfc-1.7.5/tests/jwk/test_jwk_set.py 2026-08-29 15:05:08.761608600 +0200 @@ -11,6 +11,16 @@ def test_import_empty_key_set(self): self.assertRaises(MissingKeyError, KeySet.import_key_set, {"keys": []}) + def test_import_key_set_ignores_unknown_kty(self): + # RFC 7517 Section 5: a key with an unrecognised "kty" is ignored, not fatal. + jwks = {"keys": [ + {"kty": "unknown", "alg": "X", "kid": "unknown"}, + {"kty": "oct", "k": "MDEyMzQ1Njc4OWFiY2RlZg", "kid": "classical"}, + ]} + key_set = KeySet.import_key_set(jwks) + self.assertEqual(len(key_set.keys), 1) + self.assertEqual(key_set.keys[0].kid, "classical") + def test_generate_and_import_key_set(self): jwks1 = KeySet.generate_key_set("RSA", 2048) self.assertEqual(len(jwks1.keys), 4)
