Skip to content

Commit 6544351

Browse files
committed
For JSON serialized signed JWT allow the verifier to not have all keys
necessary to verify all the signatures. If so chosen only one signature MUSt be verified correctly.
1 parent d5b02bb commit 6544351

File tree

2 files changed

+138
-70
lines changed

2 files changed

+138
-70
lines changed

src/cryptojwt/jws/jws.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
import logging
44

5+
from cryptojwt.jws.exception import JWSException
56

67
try:
78
from builtins import str
@@ -292,11 +293,15 @@ def create_signature(protected, unprotected):
292293

293294
return json.dumps(res)
294295

295-
def verify_json(self, jws, keys=None, allow_none=False, sigalg=None):
296+
def verify_json(self, jws, keys=None, allow_none=False, at_least_one=False):
296297
"""
297298
298-
:param jws:
299-
:param keys:
299+
:param jws: The JSON document representing the signed JSON
300+
:param keys: Keys that might be useful for verifying the signatures
301+
:param allow_none: Allow the None signature algorithm. Is the same
302+
as allowing no signature at all.
303+
:param at_least_one: At least one of the signatures must verify
304+
correctly. No suitable signing key is the only allow exception.
300305
:return:
301306
"""
302307

@@ -317,7 +322,7 @@ def verify_json(self, jws, keys=None, allow_none=False, sigalg=None):
317322
signature[key] = _jwss[key]
318323
_signs = [signature]
319324

320-
_claim = None
325+
_claim = last_exception = None
321326
for _sign in _signs:
322327
protected_headers = _sign.get("protected", "")
323328
token = b".".join([protected_headers.encode(), _payload.encode(),
@@ -329,13 +334,28 @@ def verify_json(self, jws, keys=None, allow_none=False, sigalg=None):
329334
json.loads(b64d_enc_dec(protected_headers) or {}))
330335
self.__init__(**all_headers)
331336

332-
_tmp = self.verify_compact(token, keys, allow_none, sigalg)
337+
try:
338+
_tmp = self.verify_compact(token, keys, allow_none)
339+
except NoSuitableSigningKeys:
340+
if at_least_one is True:
341+
logger.warning(
342+
'Could not verify signature with headers: {}'.format(
343+
all_headers))
344+
continue
345+
else:
346+
raise
347+
except JWSException as err:
348+
raise
349+
333350
if _claim is None:
334351
_claim = _tmp
335352
else:
336353
if _claim != _tmp:
337354
raise ValueError()
338355

356+
if not _claim:
357+
raise NoSuitableSigningKeys('None')
358+
339359
return _claim
340360

341361
def is_jws(self, jws):

tests/test_06_jws.py

Lines changed: 113 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,18 @@ def full_path(local_file):
4040

4141
PRIV_KEY = full_path("server.key")
4242

43-
JWK_a = {"keys": [{'alg': 'RSA',
43+
JWK_a = {
44+
"keys": [{
45+
'alg': 'RSA',
4446
'use': 'foo',
4547
'e': 'AQAB',
4648
'n': (
4749
'wf-wiusGhA-gleZYQAOPQlNUIucPiqXdPVyieDqQbXXOPBe3nuggtV'
4850
'zeq7pVFH1dZz4dY2Q2LA5DaegvP8kRvoSB_87ds3dy3Rfym_GUSc5B'
4951
'0l1TgEobcyaep8jguRoHto6GWHfCfKqoUYZq4N8vh4LLMQwLR6zi6J'
50-
'tu82nB5k8')}]}
52+
'tu82nB5k8')
53+
}]
54+
}
5155

5256
# 64*8 = 256 bits
5357
HMAC_KEY = [3, 35, 53, 75, 43, 15, 165, 188, 131, 126, 6, 101, 119, 123, 166,
@@ -56,42 +60,48 @@ def full_path(local_file):
5660
119, 98, 61, 34, 61, 46, 33, 114, 5, 46, 79, 8, 192, 205, 154, 245,
5761
103, 208, 128, 163]
5862

59-
JWKS_a = {"keys": [
60-
{'e': 'AQAB', 'kty': 'RSA', 'alg': 'RSA256',
61-
'n': 'qYJqXTXsDroPYyQBBmSolK3bJtrSerEm'
62-
'-nrmbSpfn8Rz3y3oXLydvUqj8869PkcEzoJIY5Xf7xDN1Co_qyT9qge'
63-
'-3C6DEwGVHXOwRoXRGQ_h50Vsh60MB5MIuDN188EeZnQ30dtCTBB9KDTSEA2DunplhwLCq4xphnMNUaeHdEk',
64-
'kid': 'rsa1'},
65-
{
66-
"k":
67-
b"YTEyZjBlMDgxMGI4YWU4Y2JjZDFiYTFlZTBjYzljNDU3YWM0ZWNiNzhmNmFlYTNkNTY0NzMzYjE",
68-
"kty": "oct",
69-
}]}
70-
71-
JWKS_b = {"keys": [
72-
{
73-
"n":
74-
b"zkpUgEgXICI54blf6iWiD2RbMDCOO1jV0VSff1MFFnujM4othfMsad7H1kRo50YM5S_X9TdvrpdOfpz5aBaKFhT6Ziv0nhtcekq1eRl8mjBlvGKCE5XGk-0LFSDwvqgkJoFYInq7bu0a4JEzKs5AyJY75YlGh879k1Uu2Sv3ZZOunfV1O1Orta-NvS-aG_jN5cstVbCGWE20H0vFVrJKNx0Zf-u-aA-syM4uX7wdWgQ-owoEMHge0GmGgzso2lwOYf_4znanLwEuO3p5aabEaFoKNR4K6GjQcjBcYmDEE4CtfRU9AEmhcD1kleiTB9TjPWkgDmT9MXsGxBHf3AKT5w",
75-
"e": b"AQAB",
76-
"kty": "RSA",
77-
"kid": "rsa1",
78-
"use": "sig"
79-
},
80-
{
81-
"k":
82-
b"YTEyZjBlMDgxMGI4YWU4Y2JjZDFiYTFlZTBjYzljNDU3YWM0ZWNiNzhmNmFlYTNkNTY0NzMzYjE",
83-
"kty": "oct",
84-
"use": "sig"
85-
},
86-
{
87-
"kty": "EC",
88-
"kid": "ec1",
89-
"use": "sig",
90-
"x": "q0WbWhflRbxyQZKFuQvh2nZvg98ak-twRoO5uo2L7Po",
91-
"y": "GOd2jL_6wa0cfnyA0SmEhok9fkYEnAHFKLLM79BZ8_E",
92-
"crv": "P-256"
63+
JWKS_a = {
64+
"keys": [
65+
{
66+
'e': 'AQAB', 'kty': 'RSA', 'alg': 'RSA256',
67+
'n': 'qYJqXTXsDroPYyQBBmSolK3bJtrSerEm'
68+
'-nrmbSpfn8Rz3y3oXLydvUqj8869PkcEzoJIY5Xf7xDN1Co_qyT9qge'
69+
'-3C6DEwGVHXOwRoXRGQ_h50Vsh60MB5MIuDN188EeZnQ30dtCTBB9KDTSEA2DunplhwLCq4xphnMNUaeHdEk',
70+
'kid': 'rsa1'
71+
},
72+
{
73+
"k":
74+
b"YTEyZjBlMDgxMGI4YWU4Y2JjZDFiYTFlZTBjYzljNDU3YWM0ZWNiNzhmNmFlYTNkNTY0NzMzYjE",
75+
"kty": "oct",
76+
}]
77+
}
78+
79+
JWKS_b = {
80+
"keys": [
81+
{
82+
"n":
83+
b"zkpUgEgXICI54blf6iWiD2RbMDCOO1jV0VSff1MFFnujM4othfMsad7H1kRo50YM5S_X9TdvrpdOfpz5aBaKFhT6Ziv0nhtcekq1eRl8mjBlvGKCE5XGk-0LFSDwvqgkJoFYInq7bu0a4JEzKs5AyJY75YlGh879k1Uu2Sv3ZZOunfV1O1Orta-NvS-aG_jN5cstVbCGWE20H0vFVrJKNx0Zf-u-aA-syM4uX7wdWgQ-owoEMHge0GmGgzso2lwOYf_4znanLwEuO3p5aabEaFoKNR4K6GjQcjBcYmDEE4CtfRU9AEmhcD1kleiTB9TjPWkgDmT9MXsGxBHf3AKT5w",
84+
"e": b"AQAB",
85+
"kty": "RSA",
86+
"kid": "rsa1",
87+
"use": "sig"
88+
},
89+
{
90+
"k":
91+
b"YTEyZjBlMDgxMGI4YWU4Y2JjZDFiYTFlZTBjYzljNDU3YWM0ZWNiNzhmNmFlYTNkNTY0NzMzYjE",
92+
"kty": "oct",
93+
"use": "sig"
94+
},
95+
{
96+
"kty": "EC",
97+
"kid": "ec1",
98+
"use": "sig",
99+
"x": "q0WbWhflRbxyQZKFuQvh2nZvg98ak-twRoO5uo2L7Po",
100+
"y": "GOd2jL_6wa0cfnyA0SmEhok9fkYEnAHFKLLM79BZ8_E",
101+
"crv": "P-256"
102+
}
103+
]
93104
}
94-
]}
95105

96106
JWK_b = {
97107
"keys": [
@@ -105,9 +115,9 @@ def full_path(local_file):
105115
"use": "sig",
106116
"x5c": [
107117
"MIIDPjCCAiqgAwIBAgIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAMC0xKzApBgNVBAMTImFjY291bnRzLmFjY2Vzc2NvbnRyb2wud2luZG93cy5uZXQwHhcNMTQwMTAxMDcwMDAwWhcNMTYwMTAxMDcwMDAwWjAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkSCWg6q9iYxvJE2NIhSyOiKvqoWCO2GFipgH0sTSAs5FalHQosk9ZNTztX0ywS/AHsBeQPqYygfYVJL6/EgzVuwRk5txr9e3n1uml94fLyq/AXbwo9yAduf4dCHTP8CWR1dnDR+Qnz/4PYlWVEuuHHONOw/blbfdMjhY+C/BYM2E3pRxbohBb3x//CfueV7ddz2LYiH3wjz0QS/7kjPiNCsXcNyKQEOTkbHFi3mu0u13SQwNddhcynd/GTgWN8A+6SN1r4hzpjFKFLbZnBt77ACSiYx+IHK4Mp+NaVEi5wQtSsjQtI++XsokxRDqYLwus1I1SihgbV/STTg5enufuwIDAQABo2IwYDBeBgNVHQEEVzBVgBDLebM6bK3BjWGqIBrBNFeNoS8wLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldIIQsRiM0jheFZhKk49YD0SK1TAJBgUrDgMCHQUAA4IBAQCJ4JApryF77EKC4zF5bUaBLQHQ1PNtA1uMDbdNVGKCmSf8M65b8h0NwlIjGGGy/unK8P6jWFdm5IlZ0YPTOgzcRZguXDPj7ajyvlVEQ2K2ICvTYiRQqrOhEhZMSSZsTKXFVwNfW6ADDkN3bvVOVbtpty+nBY5UqnI7xbcoHLZ4wYD251uj5+lo13YLnsVrmQ16NCBYq2nQFNPuNJw6t3XUbwBHXpF46aLT1/eGf/7Xx6iy8yPJX4DyrpFTutDz882RWofGEO5t4Cw+zZg70dJ/hH/ODYRMorfXEW+8uKmXMKmX2wyxMKvfiPbTy5LmAU8Jvjs2tLg4rOBcXWLAIarZ"
108-
],
118+
],
109119
"x5t": "kriMPdmBvx68skT8-mPAB3BseeA"
110-
},
120+
},
111121
{
112122
"e": "AQAB",
113123
"issuer": "https://login.microsoftonline.com/{tenantid}/v2.0/",
@@ -118,9 +128,9 @@ def full_path(local_file):
118128
"use": "sig",
119129
"x5c": [
120130
"MIIC4jCCAcqgAwIBAgIQQNXrmzhLN4VGlUXDYCRT3zANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE0MTAyODAwMDAwMFoXDTE2MTAyNzAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALyKs/uPhEf7zVizjfcr/ISGFe9+yUOqwpel38zgutvLHmFD39E2hpPdQhcXn4c4dt1fU5KvkbcDdVbP8+e4TvNpJMy/nEB2V92zCQ/hhBjilwhF1ETe1TMmVjALs0KFvbxW9ZN3EdUVvxFvz/gvG29nQhl4QWKj3x8opr89lmq14Z7T0mzOV8kub+cgsOU/1bsKqrIqN1fMKKFhjKaetctdjYTfGzVQ0AJAzzbtg0/Q1wdYNAnhSDafygEv6kNiquk0r0RyasUUevEXs2LY3vSgKsKseI8ZZlQEMtE9/k/iAG7JNcEbVg53YTurNTrPnXJOU88mf3TToX14HpYsS1ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAfolx45w0i8CdAUjjeAaYdhG9+NDHxop0UvNOqlGqYJexqPLuvX8iyUaYxNGzZxFgGI3GpKfmQP2JQWQ1E5JtY/n8iNLOKRMwqkuxSCKJxZJq4Sl/m/Yv7TS1P5LNgAj8QLCypxsWrTAmq2HSpkeSk4JBtsYxX6uhbGM/K1sEktKybVTHu22/7TmRqWTmOUy9wQvMjJb2IXdMGLG3hVntN/WWcs5w8vbt1i8Kk6o19W2MjZ95JaECKjBDYRlhG1KmSBtrsKsCBQoBzwH/rXfksTO9JoUYLXiW0IppB7DhNH4PJ5hZI91R8rR0H3/bKkLSuDaKLWSqMhozdhXsIIKvJQ=="
121-
],
131+
],
122132
"x5t": "MnC_VZcATfM5pOYiJHMba9goEKY"
123-
},
133+
},
124134
{
125135
"e": "AQAB",
126136
"issuer": "https://login.microsoftonline.com/9188040d-6c67-4c5b"
@@ -134,9 +144,9 @@ def full_path(local_file):
134144
"use": "sig",
135145
"x5c": [
136146
"MIICWzCCAcSgAwIBAgIJAKVzMH2FfC12MA0GCSqGSIb3DQEBBQUAMCkxJzAlBgNVBAMTHkxpdmUgSUQgU1RTIFNpZ25pbmcgUHVibGljIEtleTAeFw0xMzExMTExODMzMDhaFw0xNjExMTAxODMzMDhaMCkxJzAlBgNVBAMTHkxpdmUgSUQgU1RTIFNpZ25pbmcgUHVibGljIEtleTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5ymq/xwmst1nstPr8YFOTyD1J5N4idYmrph7AyAv95RbWXfDRqy8CMRG7sJq+UWOKVOA4MVrd/NdV+ejj1DE5MPSiG+mZK/5iqRCDFvPYqOyRj539xaTlARNY4jeXZ0N6irZYKqSfYACjkkKxbLKcijSu1pJ48thXOTED0oNa6UCAwEAAaOBijCBhzAdBgNVHQ4EFgQURCN+4cb0pvkykJCUmpjyfUfnRMowWQYDVR0jBFIwUIAURCN+4cb0pvkykJCUmpjyfUfnRMqhLaQrMCkxJzAlBgNVBAMTHkxpdmUgSUQgU1RTIFNpZ25pbmcgUHVibGljIEtleYIJAKVzMH2FfC12MAsGA1UdDwQEAwIBxjANBgkqhkiG9w0BAQUFAAOBgQB8v8G5/vUl8k7xVuTmMTDA878AcBKBrJ/Hp6RShmdqEGVI7SFR7IlBN1//NwD0n+IqzmnRV2PPZ7iRgMF/Fyvqi96Gd8X53ds/FaiQpZjUUtcO3fk0hDRQPtCYMII5jq+YAYjSybvF84saB7HGtucVRn2nMZc5cAC42QNYIlPMqA=="
137-
],
147+
],
138148
"x5t": "GvnPApfWMdLRi8PDmisFn7bprKg"
139-
},
149+
},
140150
{
141151
"e": "AQAB",
142152
"issuer": "https://login.microsoftonline.com/9188040d-6c67-4c5b"
@@ -148,22 +158,25 @@ def full_path(local_file):
148158
"use": "sig",
149159
"x5c": [
150160
"MIICWzCCAcSgAwIBAgIJAL3MzqqEFMYjMA0GCSqGSIb3DQEBBQUAMCkxJzAlBgNVBAMTHkxpdmUgSUQgU1RTIFNpZ25pbmcgUHVibGljIEtleTAeFw0xMzExMTExOTA1MDJaFw0xOTExMTAxOTA1MDJaMCkxJzAlBgNVBAMTHkxpdmUgSUQgU1RTIFNpZ25pbmcgUHVibGljIEtleTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAx7HNcD9ZxTFRaAgZ7+gdYLkgQua3zvQseqBJIt8Uq3MimInMZoE9QGQeSML7qZPlowb5BUakdLI70ayM4vN36++0ht8+oCHhl8YjGFQkU+Iv2yahWHEP+1EK6eOEYu6INQP9Lk0HMk3QViLwshwb+KXVD02jdmX2HNdYJdPyc0cCAwEAAaOBijCBhzAdBgNVHQ4EFgQULR0aj9AtiNMgqIY8ZyXZGsHcJ5gwWQYDVR0jBFIwUIAULR0aj9AtiNMgqIY8ZyXZGsHcJ5ihLaQrMCkxJzAlBgNVBAMTHkxpdmUgSUQgU1RTIFNpZ25pbmcgUHVibGljIEtleYIJAL3MzqqEFMYjMAsGA1UdDwQEAwIBxjANBgkqhkiG9w0BAQUFAAOBgQBshrsF9yls4ArxOKqXdQPDgHrbynZL8m1iinLI4TeSfmTCDevXVBJrQ6SgDkihl3aCj74IEte2MWN78sHvLLTWTAkiQSlGf1Zb0durw+OvlunQ2AKbK79Qv0Q+wwGuK+oymWc3GSdP1wZqk9dhrQxb3FtdU2tMke01QTut6wr7ig=="
151-
],
161+
],
152162
"x5t": "dEtpjbEvbhfgwUI-bdK5xAU_9UQ"
153-
}
154-
]
155-
}
163+
}
164+
]
165+
}
156166

157167
SIGJWKS = KeyBundle(JWKS_b)
158168

159169

160170
def P256():
161171
return ec.generate_private_key(ec.SECP256R1(), default_backend())
162172

173+
163174
def test_1():
164-
claimset = {"iss": "joe",
165-
"exp": 1300819380,
166-
"http://example.com/is_root": True}
175+
claimset = {
176+
"iss": "joe",
177+
"exp": 1300819380,
178+
"http://example.com/is_root": True
179+
}
167180

168181
_jws = JWS(claimset, cty="JWT", alg='none')
169182
_jwt = _jws.sign_compact()
@@ -361,7 +374,7 @@ def test_jws_mm():
361374
(ec.SECP256R1, "ES256"),
362375
(ec.SECP384R1, "ES384"),
363376
(ec.SECP521R1, "ES512"),
364-
])
377+
])
365378
def test_signer_es(ec_func, alg):
366379
payload = "Please take a moment to register today"
367380
eck = ec.generate_private_key(ec_func(), default_backend())
@@ -469,17 +482,20 @@ def test_no_alg_and_alg_none_same():
469482

470483

471484
def test_sign_2():
472-
keyset = {"keys": [
473-
{"alg": "RS512",
474-
"kty": "RSA",
475-
"d": "ckLyXxkbjC4szg8q8G0ERBZV"
476-
"-9CszeOxpRtx1KM9BLl0Do3li_Km2vvFvfXJ7MxQpiZ18pBoCcyYQEU262ym8wI22JWMPrZe24HCNxLxqzr_JEuBhpKFxQF6EFTSvJEJD1FkoTuCTvN0zD7YHGaJQG6JzVEuFUY3ewxjH0FYNa_ppTnPP3LC-T9u_GX9Yqyuw1KOYoHSzhWSWQOeAgs4dH9-iAxN1wdZ6eH1jFWAs43svk_rhwdgyJMlihFtV9MAInBlfi_Zu8wRVhVl5urkJrLf0tGFnMbnzb6dYSlUXxEYClpY12W7kXW9aePDqkCwI4oZyxmOmgq4hunKGR1dAQ",
477-
"e": "AQAB",
478-
"use": "sig",
479-
"kid": "af22448d-4c7b-464d-b63a-f5bd90f6d7d1",
480-
"n": "o9g8DpUwBW6B1qmcm-TfEh4rNX7n1t38jdo4Gkl_cI3q"
481-
"--7n0Blg0kN88LHZvyZjUB2NhBdFYNxMP8ucy0dOXvWGWzaPmGnq3DM__lN8P4WjD1cCTAVEYKawNBAmGKqrFj1SgpPNsSqiqK-ALM1w6mZ-QGimjOgwCyJy3l9lzZh5D8tKnS2t1pZgE0X5P7lZQWHYpHPqp4jKhETzrCpPGfv0Rl6nmmjp7NlRYBkWKf_HEKE333J6M039m2FbKgxrBg3zmYYpmHuMzVgxxb8LSiv5aqyeyJjxM-YDUAgNQBfKNhONqXyu9DqtSprNkw6sqmuxK0QUVrNYl3b03PgS5Q"
482-
}]}
485+
keyset = {
486+
"keys": [
487+
{
488+
"alg": "RS512",
489+
"kty": "RSA",
490+
"d": "ckLyXxkbjC4szg8q8G0ERBZV"
491+
"-9CszeOxpRtx1KM9BLl0Do3li_Km2vvFvfXJ7MxQpiZ18pBoCcyYQEU262ym8wI22JWMPrZe24HCNxLxqzr_JEuBhpKFxQF6EFTSvJEJD1FkoTuCTvN0zD7YHGaJQG6JzVEuFUY3ewxjH0FYNa_ppTnPP3LC-T9u_GX9Yqyuw1KOYoHSzhWSWQOeAgs4dH9-iAxN1wdZ6eH1jFWAs43svk_rhwdgyJMlihFtV9MAInBlfi_Zu8wRVhVl5urkJrLf0tGFnMbnzb6dYSlUXxEYClpY12W7kXW9aePDqkCwI4oZyxmOmgq4hunKGR1dAQ",
492+
"e": "AQAB",
493+
"use": "sig",
494+
"kid": "af22448d-4c7b-464d-b63a-f5bd90f6d7d1",
495+
"n": "o9g8DpUwBW6B1qmcm-TfEh4rNX7n1t38jdo4Gkl_cI3q"
496+
"--7n0Blg0kN88LHZvyZjUB2NhBdFYNxMP8ucy0dOXvWGWzaPmGnq3DM__lN8P4WjD1cCTAVEYKawNBAmGKqrFj1SgpPNsSqiqK-ALM1w6mZ-QGimjOgwCyJy3l9lzZh5D8tKnS2t1pZgE0X5P7lZQWHYpHPqp4jKhETzrCpPGfv0Rl6nmmjp7NlRYBkWKf_HEKE333J6M039m2FbKgxrBg3zmYYpmHuMzVgxxb8LSiv5aqyeyJjxM-YDUAgNQBfKNhONqXyu9DqtSprNkw6sqmuxK0QUVrNYl3b03PgS5Q"
497+
}]
498+
}
483499

484500
keys = KeyBundle(keyset)
485501
jws = JWS("payload", alg="RS512")
@@ -524,10 +540,10 @@ def test_verify_protected_headers():
524540
header=dict(alg=u"ES256", jwk=_key.serialize()),
525541
protected=protectedHeader,
526542
signature=sig,
527-
)
528-
])
543+
)
544+
])
529545

530-
#_pub_key = ECKey().load_key(eck.public_key())
546+
# _pub_key = ECKey().load_key(eck.public_key())
531547
_jws = JWS()
532548
assert _jws.verify_json(json.dumps(data)) == payload
533549

@@ -828,3 +844,35 @@ def test_factory_verify_alg():
828844
_jws = _signer.sign_compact(keys, abc=123)
829845
_verifier = factory(_jws)
830846
assert _verifier.jwt.verify_headers(alg='RS512') is False
847+
848+
849+
def test_verify_json_missing_key():
850+
ec_key = ECKey().load_key(P256())
851+
sym_key = SYMKey(key=b'My hollow echo chamber', alg="HS384")
852+
853+
protected_headers_1 = {"foo": "bar", 'alg': 'ES256'}
854+
unprotected_headers_1 = {"abc": "xyz"}
855+
protected_headers_2 = {"foo": "bar", 'alg': 'HS384'}
856+
unprotected_headers_2 = {"abc": "zeb"}
857+
payload = "hello world"
858+
_jwt = JWS(msg=payload).sign_json(
859+
headers=[
860+
(protected_headers_1, unprotected_headers_1),
861+
(protected_headers_2, unprotected_headers_2)],
862+
keys=[ec_key, sym_key])
863+
864+
# Only the EC key
865+
vkeys = [ECKey().load_key(ec_key.public_key())]
866+
with pytest.raises(NoSuitableSigningKeys):
867+
JWS().verify_json(_jwt, keys=vkeys)
868+
869+
assert JWS().verify_json(_jwt, keys=vkeys, at_least_one=True)
870+
871+
# Only the SYM key
872+
with pytest.raises(NoSuitableSigningKeys):
873+
JWS().verify_json(_jwt, keys=[sym_key])
874+
875+
assert JWS().verify_json(_jwt, keys=[sym_key], at_least_one=True)
876+
877+
# With both
878+
assert JWS().verify_json(_jwt, keys=[vkeys[0], sym_key])

0 commit comments

Comments
 (0)