Skip to content

Commit 88a9fc5

Browse files
committed
Merge pull request #109 from mark-adams/algo-validation-fixes
Added some fixes related to algorithm and key choice
2 parents 1e6b6c5 + f6d0ff2 commit 88a9fc5

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

jwt/algorithms.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import hmac
33

44
from .compat import constant_time_compare, string_types, text_type
5+
from .exceptions import InvalidKeyError
56

67
try:
78
from cryptography.hazmat.primitives import interfaces, hashes
@@ -68,7 +69,13 @@ class NoneAlgorithm(Algorithm):
6869
operations are required.
6970
"""
7071
def prepare_key(self, key):
71-
return None
72+
if key == '':
73+
key = None
74+
75+
if key is not None:
76+
raise InvalidKeyError('When alg = "none", key value must be None.')
77+
78+
return key
7279

7380
def sign(self, msg, key):
7481
return b''
@@ -96,6 +103,17 @@ def prepare_key(self, key):
96103
if isinstance(key, text_type):
97104
key = key.encode('utf-8')
98105

106+
invalid_strings = [
107+
b'-----BEGIN PUBLIC KEY-----',
108+
b'-----BEGIN CERTIFICATE-----',
109+
b'ssh-rsa'
110+
]
111+
112+
if any([string_value in key for string_value in invalid_strings]):
113+
raise InvalidKeyError(
114+
'The specified key is an assymetric key or x509 certificate and'
115+
' should not be used as an HMAC secret.')
116+
99117
return key
100118

101119
def sign(self, msg, key):

jwt/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class InvalidIssuerError(InvalidTokenError):
1818
pass
1919

2020

21+
class InvalidKeyError(Exception):
22+
pass
23+
24+
2125
# Compatibility aliases (deprecated)
2226
ExpiredSignature = ExpiredSignatureError
2327
InvalidAudience = InvalidAudienceError

tests/keys/testkey_rsa.cer

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDhTCCAm2gAwIBAgIJANE4sir3EkX8MA0GCSqGSIb3DQEBCwUAMFkxCzAJBgNV
3+
BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEPMA0GA1UEBwwGQXVzdGluMQ4wDAYDVQQK
4+
DAVQeUpXVDEZMBcGA1UECwwQVGVzdCBDZXJ0aWZpY2F0ZTAeFw0xNTAzMTgwMTE2
5+
MTRaFw0xODAzMTcwMTE2MTRaMFkxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhh
6+
czEPMA0GA1UEBwwGQXVzdGluMQ4wDAYDVQQKDAVQeUpXVDEZMBcGA1UECwwQVGVz
7+
dCBDZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANR4
8+
MwXyb9nDo0K8gsHvDRHpa4jkzRVimVIr3r1K0YZanJmSXQr7giUa/sQjfjpjvKsI
9+
CSUffH3jbo8VYPifS7N/1DgOB3BfZ2B+mqlVxCwBPB5PwC78YveprNQw7gL0BmmG
10+
fpQDcZb8XkBTmUm45M//ZofGi3hisKiS6d6fjoVAUKcLwFAD4PNvjlLYE1t50pY4
11+
3ha9eAfKgJ3hknP8JdJ4vvtUkWVFxUqL83KkDpJWt1tu66y36w+i14I/07A7OLw9
12+
T5yJtc3FXpyk+032CNe27Bvzv1nnMM9jZdfaS+4A6LDa7hd6ICVjatS8p/4oz0J5
13+
Dy6WR8ob7osnGHCNw4kCAwEAAaNQME4wHQYDVR0OBBYEFDR6fVdFxZED6YMmD62W
14+
LlBW+qEBMB8GA1UdIwQYMBaAFDR6fVdFxZED6YMmD62WLlBW+qEBMAwGA1UdEwQF
15+
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFwDNwm+lU/kGfWwiWM0Lv2aosXotoiG
16+
TsBSWIn2iYphq0vzlgChcNocN9zkaOz3zc9pcREP6lyqHpE0OEbNucHHDdU1L2he
17+
lLFOLOmkpP5fyPDXs9nKYhO8ygMByEonHm3K/VvCgrsSgJ3JuxMLUxnE55jQXGWV
18+
OqYQNo2J5h93Zd2HTTe19jCz+bbWnRBP5VvLAAAo5YSmk3iroWSPWAKkWOOecJ2Q
19+
/xnRyuWERsfvZiF/m9q7yDJ55LXVVm3Rufmy76SoTnJ2acap+XQNXBH/AxayeLUS
20+
OYmHWH61dUcsQtwXYHYRB8TTtMIwUCXGmthXkDJydEfrGcD0y6APIh8=
21+
-----END CERTIFICATE-----

tests/test_algorithms.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import base64
22

3-
from jwt.algorithms import Algorithm, HMACAlgorithm
3+
from jwt.algorithms import Algorithm, HMACAlgorithm, NoneAlgorithm
4+
from jwt.exceptions import InvalidKeyError
45

56
from .compat import unittest
67
from .utils import ensure_bytes, ensure_unicode, key_path
@@ -35,6 +36,12 @@ def test_algorithm_should_throw_exception_if_verify_not_impl(self):
3536
with self.assertRaises(NotImplementedError):
3637
algo.verify('message', 'key', 'signature')
3738

39+
def test_none_algorithm_should_throw_exception_if_key_is_not_none(self):
40+
algo = NoneAlgorithm()
41+
42+
with self.assertRaises(InvalidKeyError):
43+
algo.prepare_key('123')
44+
3845
def test_hmac_should_reject_nonstring_key(self):
3946
algo = HMACAlgorithm(HMACAlgorithm.SHA256)
4047

@@ -49,6 +56,38 @@ def test_hmac_should_accept_unicode_key(self):
4956

5057
algo.prepare_key(ensure_unicode('awesome'))
5158

59+
@unittest.skipIf(not has_crypto, 'Not supported without cryptography library')
60+
def test_hmac_should_throw_exception_if_key_is_pem_public_key(self):
61+
algo = HMACAlgorithm(HMACAlgorithm.SHA256)
62+
63+
with self.assertRaises(InvalidKeyError):
64+
with open(key_path('testkey2_rsa.pub.pem'), 'r') as keyfile:
65+
algo.prepare_key(keyfile.read())
66+
67+
@unittest.skipIf(not has_crypto, 'Not supported without cryptography library')
68+
def test_hmac_should_throw_exception_if_key_is_x509_certificate(self):
69+
algo = HMACAlgorithm(HMACAlgorithm.SHA256)
70+
71+
with self.assertRaises(InvalidKeyError):
72+
with open(key_path('testkey_rsa.cer'), 'r') as keyfile:
73+
algo.prepare_key(keyfile.read())
74+
75+
@unittest.skipIf(not has_crypto, 'Not supported without cryptography library')
76+
def test_hmac_should_throw_exception_if_key_is_ssh_public_key(self):
77+
algo = HMACAlgorithm(HMACAlgorithm.SHA256)
78+
79+
with self.assertRaises(InvalidKeyError):
80+
with open(key_path('testkey_rsa.pub'), 'r') as keyfile:
81+
algo.prepare_key(keyfile.read())
82+
83+
@unittest.skipIf(not has_crypto, 'Not supported without cryptography library')
84+
def test_hmac_should_throw_exception_if_key_is_x509_cert(self):
85+
algo = HMACAlgorithm(HMACAlgorithm.SHA256)
86+
87+
with self.assertRaises(InvalidKeyError):
88+
with open(key_path('testkey2_rsa.pub.pem'), 'r') as keyfile:
89+
algo.prepare_key(keyfile.read())
90+
5291
@unittest.skipIf(not has_crypto, 'Not supported without cryptography library')
5392
def test_rsa_should_parse_pem_public_key(self):
5493
algo = RSAAlgorithm(RSAAlgorithm.SHA256)

0 commit comments

Comments
 (0)