Skip to content

Commit 79d30da

Browse files
committed
feat(jwe): allow verify only one recipient
#16
1 parent c7e960a commit 79d30da

4 files changed

Lines changed: 42 additions & 4 deletions

File tree

src/joserfc/rfc7516/message.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
)
1515
from .registry import JWERegistry
1616
from ..errors import (
17+
JoseError,
1718
DecodeError,
1819
InvalidCEKLengthError,
1920
InvalidEncryptedKeyError,
@@ -99,8 +100,15 @@ def _perform_decrypt(obj: EncryptionData, registry: JWERegistry) -> None:
99100
# Step 6, Determine the Key Management Mode employed by the algorithm
100101
# specified by the "alg" (algorithm) Header Parameter.
101102
alg = registry.get_alg(headers["alg"])
102-
cek = decrypt_recipient(alg, enc, recipient, tag)
103-
cek_set.add(cek)
103+
try:
104+
cek = decrypt_recipient(alg, enc, recipient, tag)
105+
cek_set.add(cek)
106+
except (AssertionError, JoseError) as error:
107+
if registry.verify_all_recipients:
108+
raise error
109+
110+
if not cek_set:
111+
raise DecodeError('Invalid recipients')
104112

105113
if len(cek_set) > 1: # pragma: no cover
106114
raise DecodeError('Multiple "cek" found')

src/joserfc/rfc7516/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def generate_iv(self) -> bytes:
173173
return os.urandom(self.iv_size // 8)
174174

175175
def check_iv(self, iv: bytes) -> bytes:
176-
if len(iv) * 8 != self.iv_size:
176+
if len(iv) * 8 != self.iv_size: # pragma: no cover
177177
raise ValueError('Invalid "iv" size')
178178
return iv
179179

src/joserfc/rfc7516/registry.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ def __init__(
3838
self,
3939
header_registry: t.Optional[HeaderRegistryDict] = None,
4040
algorithms: t.Optional[t.List[str]] = None,
41+
verify_all_recipients: bool = True,
4142
strict_check_header: bool = True):
4243
self.header_registry: HeaderRegistryDict = {}
4344
self.header_registry.update(JWE_HEADER_REGISTRY)
4445
if header_registry is not None:
4546
self.header_registry.update(header_registry)
4647
self.allowed = algorithms
48+
self.verify_all_recipients = verify_all_recipients
4749
self.strict_check_header = strict_check_header
4850

4951
@classmethod

tests/jwe/test_json.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
from joserfc import jwe
33
from joserfc.jwe import GeneralJSONEncryption
44
from joserfc.jwk import KeySet, RSAKey, ECKey, OctKey
5-
from joserfc.errors import ConflictAlgorithmError
5+
from joserfc.errors import (
6+
DecodeError,
7+
ConflictAlgorithmError,
8+
InvalidKeyTypeError,
9+
)
610

711

812
class TestJWEJSON(TestCase):
@@ -43,3 +47,27 @@ def test_with_aad(self):
4347
value = jwe.encrypt_json(obj, None)
4448
obj1 = jwe.decrypt_json(value, key1)
4549
self.assertEqual(obj1.aad, b"foo")
50+
51+
def test_decode_multiple_recipients(self):
52+
key1 = RSAKey.generate_key()
53+
key2 = ECKey.generate_key()
54+
obj = GeneralJSONEncryption({"enc": "A128CBC-HS256"}, b"i")
55+
obj.add_recipient({"alg": "RSA-OAEP"}, key1)
56+
obj.add_recipient({"alg": "ECDH-ES+A128KW"}, key2)
57+
value = jwe.encrypt_json(obj, None)
58+
self.assertRaises(
59+
InvalidKeyTypeError,
60+
jwe.decrypt_json,
61+
value, key1,
62+
)
63+
registry = jwe.JWERegistry(verify_all_recipients=False)
64+
obj1 = jwe.decrypt_json(value, key1, registry=registry)
65+
self.assertEqual(obj1.plaintext, b"i")
66+
67+
key3 = OctKey.generate_key()
68+
self.assertRaises(
69+
DecodeError,
70+
jwe.decrypt_json,
71+
value, key3,
72+
registry=registry,
73+
)

0 commit comments

Comments
 (0)