Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions jwcrypto/jwa.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os
import struct
import warnings
from abc import ABCMeta, abstractmethod
from binascii import hexlify, unhexlify

Expand Down Expand Up @@ -41,6 +42,15 @@
actors providing a very high iteration count.
"""

default_warn_deprecated_algorithms = False
"""When True, emit a DeprecationWarning when instantiating an algorithm
whose status is 'deprecated'.

Disabled by default so that consumers are not disrupted by warnings for
algorithms that remain in wide use (e.g. EdDSA). Set to True to audit
your code for deprecated algorithm usage.
"""

default_enforce_hmac_key_length = True
"""Enforces that the HMAC key length is at least the size of the hash
function's output, as recommended by RFC 7518.
Expand Down Expand Up @@ -77,6 +87,12 @@ def algorithm_usage_location(self):
def algorithm_use(self):
"""One of 'sig', 'kex', 'enc'"""

status = 'active'
"""Algorithm status: 'active', 'deprecated', or 'prohibited'"""

deprecated_by = None
"""Replacement algorithm(s) for deprecated algorithms"""

@property
def input_keysize(self):
"""The input key size"""
Expand Down Expand Up @@ -883,6 +899,8 @@ class _EdDsa(_RawJWS, JWAAlgorithm):
algorithm_usage_location = 'alg'
algorithm_use = 'sig'
keysize = None
status = 'deprecated'
deprecated_by = 'Ed25519 or Ed448'

def sign(self, key, payload):
if key['crv'] in ['Ed25519', 'Ed448']:
Expand Down Expand Up @@ -1297,6 +1315,14 @@ def instantiate_alg(cls, name, use=None):
alg = cls.algorithms_registry[name]
if use is not None and alg.algorithm_use != use:
raise KeyError
if alg.status == 'prohibited':
raise InvalidJWAAlgorithm(
'%s is prohibited and must not be used' % name)
if alg.status == 'deprecated' and default_warn_deprecated_algorithms:
msg = '%s is deprecated' % name
if alg.deprecated_by:
msg += '; use %s instead' % alg.deprecated_by
warnings.warn(msg, DeprecationWarning, stacklevel=4)
return alg()

@classmethod
Expand Down
27 changes: 27 additions & 0 deletions jwcrypto/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2642,3 +2642,30 @@ def test_jws_ed448(self):
jws_obj.deserialize(serialized_jws, key)
self.assertTrue(jws_obj.is_valid)
self.assertEqual(jws_obj.payload, payload)

def test_eddsa_deprecation_warning(self):
import warnings
old = jwa.default_warn_deprecated_algorithms
try:
jwa.default_warn_deprecated_algorithms = True
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
jwa.JWA.signing_alg('EdDSA')
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, DeprecationWarning))
self.assertIn('EdDSA', str(w[0].message))
self.assertIn('Ed25519 or Ed448', str(w[0].message))
finally:
jwa.default_warn_deprecated_algorithms = old

def test_eddsa_no_warning_by_default(self):
import warnings
old = jwa.default_warn_deprecated_algorithms
try:
jwa.default_warn_deprecated_algorithms = False
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
jwa.JWA.signing_alg('EdDSA')
self.assertEqual(len(w), 0)
finally:
jwa.default_warn_deprecated_algorithms = old
Loading