Commit 6cf24a1d authored by Simo Sorce's avatar Simo Sorce

Add property to change the allowed algorithms

Also adds a module level variable with the default allowed algs.
This list explicitly excludes 'none' as the spec suggests that
the 'none' alg should be used only if the application explicitly
allows it.

Tests adjusted accordingly.
Signed-off-by: default avatarSimo Sorce <>
parent 74070abd
......@@ -19,6 +19,11 @@ Classes
.. autodata:: jwcrypto.jws.default_allowed_algs
......@@ -29,6 +29,13 @@ JWSHeaderRegistry = {'alg': ('Algorithm', True),
'crit': ('Critical', True)}
"""Registry of valid header parameters"""
default_allowed_algs = [
'HS256', 'HS384', 'HS512',
'RS256', 'RS384', 'RS512',
'ES256', 'ES384', 'ES512',
'PS256', 'PS384', 'PS512']
"""Default allowed algorithms"""
class InvalidJWSSignature(Exception):
"""Invalid JWS Signature.
......@@ -184,7 +191,7 @@ class JWSCore(object):
def __init__(self, alg, key, header, payload):
def __init__(self, alg, key, header, payload, algs=None):
"""Core JWS token handling.
:param alg: The algorithm used to produce the signature.
......@@ -193,13 +200,14 @@ class JWSCore(object):
type for the "alg" provided in the 'protected' json string.
:param header: A JSON string representing the protected header.
:param payload(bytes): An arbitrary value
:param algs: An optional list of allowed algorithms
:raises ValueError: if the key is not a :class:`JWK` object
:raises InvalidJWAAlgorithm: if the algorithm is not valid, is
unknown or otherwise not yet implemented.
self.alg = alg
self.engine = self._jwa(alg)
self.engine = self._jwa(alg, algs)
if not isinstance(key, JWK):
raise ValueError('key is not a JWK object')
self.key = key
......@@ -255,12 +263,17 @@ class JWSCore(object):
def _jwa_none(self):
return _raw_none()
def _jwa(self, name):
def _jwa(self, name, allowed):
if allowed is None:
allowed = default_allowed_algs
attr = '_jwa_%s' % name
return getattr(self, attr)()
fn = getattr(self, attr)
except (KeyError, AttributeError):
raise InvalidJWAAlgorithm()
if name not in allowed:
raise InvalidJWSOperation('Algorithm not allowed')
return fn()
def sign(self):
"""Generates a signature"""
......@@ -298,6 +311,7 @@ class JWS(object):
if payload:
self.objects['payload'] = payload
self.verifylog = None
self._allowed_algs = None
def _check_crit(self, crit):
for k in crit:
......@@ -309,6 +323,25 @@ class JWS(object):
raise InvalidJWSSignature('Unsupported critical '
'header: "%s"' % k)
def allowed_algs(self):
"""Allowed algorithms.
The list of allowed algorithms.
Can be changed by setting a list of algorithm names.
if self._allowed_algs:
return self._allowed_algs
return default_allowed_algs
def allowed_algs(self, algs):
if not isinstance(algs, list):
raise TypeError('Allowed Algs must be a list')
self._allowed_algs = algs
def is_valid(self):
return self.objects.get('valid', False)
......@@ -351,9 +384,9 @@ class JWS(object):
a = p['alg']
# the following will verify the "alg" is upported and the signature
# the following will verify the "alg" is supported and the signature
# verifies
S = JWSCore(a, key, protected, payload)
S = JWSCore(a, key, protected, payload, self._allowed_algs)
def verify(self, key, alg=None):
......@@ -388,7 +388,8 @@ class TestJWS(unittest.TestCase):
S = jws.JWSCore(test['alg'],
test.get('allowed_algs', None))
sig = S.sign()
decsig = base64url_decode(sig['signature'])
......@@ -415,7 +416,11 @@ class TestJWS(unittest.TestCase):
def test_A5(self):
self.check_sign, A5_example)
A5_bis = {'allowed_algs': ['none']}
def test_A6(self):
S = jws.JWS(A6_example['payload'])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment