Skip to content

Commit 151761d

Browse files
committed
Merge pull request jpadilla#163 from mark-adams/fix-rsa-pss
RSA-PSS should use the proper salt value when creating and verifying signatures
2 parents b8f36aa + c990c44 commit 151761d

File tree

3 files changed

+36
-69
lines changed

3 files changed

+36
-69
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
88
-------------------------------------------------------------------------
99
### Fixed
1010
- ECDSA (ES256, ES384, ES512) signatures are now being properly serialized [#158][158]
11+
- RSA-PSS (PS256, PS384, PS512) signatures now use the proper salt length for PSS padding.
1112

1213
### Added
1314
- Added a new `jwt.get_unverified_header()` to parse and return the header portion of a token prior to signature verification.

jwt/algorithms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def sign(self, msg, key):
263263
signer = key.signer(
264264
padding.PSS(
265265
mgf=padding.MGF1(self.hash_alg()),
266-
salt_length=padding.PSS.MAX_LENGTH
266+
salt_length=self.hash_alg.digest_size
267267
),
268268
self.hash_alg()
269269
)
@@ -276,7 +276,7 @@ def verify(self, msg, key, sig):
276276
sig,
277277
padding.PSS(
278278
mgf=padding.MGF1(self.hash_alg()),
279-
salt_length=padding.PSS.MAX_LENGTH
279+
salt_length=self.hash_alg.digest_size
280280
),
281281
self.hash_alg()
282282
)

tests/test_algorithms.py

Lines changed: 33 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -131,26 +131,6 @@ def test_rsa_verify_should_return_false_if_signature_invalid(self):
131131
result = algo.verify(message, pub_key, sig)
132132
assert not result
133133

134-
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
135-
def test_rsa_verify_should_return_true_if_signature_valid(self):
136-
algo = RSAAlgorithm(RSAAlgorithm.SHA256)
137-
138-
message = ensure_bytes('Hello World!')
139-
140-
sig = base64.b64decode(ensure_bytes(
141-
'yS6zk9DBkuGTtcBzLUzSpo9gGJxJFOGvUqN01iLhWHrzBQ9ZEz3+Ae38AXp'
142-
'10RWwscp42ySC85Z6zoN67yGkLNWnfmCZSEv+xqELGEvBJvciOKsrhiObUl'
143-
'2mveSc1oeO/2ujkGDkkkJ2epn0YliacVjZF5+/uDmImUfAAj8lzjnHlzYix'
144-
'sn5jGz1H07jYYbi9diixN8IUhXeTafwFg02IcONhum29V40Wu6O5tAKWlJX'
145-
'fHJnNUzAEUOXS0WahHVb57D30pcgIji9z923q90p5c7E2cU8V+E1qe8NdCA'
146-
'APCDzZZ9zQ/dgcMVaBrGrgimrcLbPjueOKFgSO+SSjIElKA=='))
147-
148-
with open(key_path('testkey_rsa.pub'), 'r') as keyfile:
149-
pub_key = algo.prepare_key(keyfile.read())
150-
151-
result = algo.verify(message, pub_key, sig)
152-
assert result
153-
154134
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
155135
def test_ec_should_reject_non_string_key(self):
156136
algo = ECAlgorithm(ECAlgorithm.SHA256)
@@ -197,23 +177,6 @@ def test_ec_verify_should_return_false_if_signature_wrong_length(self):
197177
result = algo.verify(message, pub_key, sig)
198178
assert not result
199179

200-
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
201-
def test_ec_verify_should_return_true_if_signature_valid(self):
202-
algo = ECAlgorithm(ECAlgorithm.SHA256)
203-
204-
message = ensure_bytes('Hello World!')
205-
206-
sig = base64.b64decode(ensure_bytes(
207-
'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M'
208-
'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw'
209-
'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65'))
210-
211-
with open(key_path('testkey_ec.pub'), 'r') as keyfile:
212-
pub_key = algo.prepare_key(keyfile.read())
213-
214-
result = algo.verify(message, pub_key, sig)
215-
assert result
216-
217180
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
218181
def test_rsa_pss_sign_then_verify_should_return_true(self):
219182
algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256)
@@ -252,34 +215,20 @@ def test_rsa_pss_verify_should_return_false_if_signature_invalid(self):
252215
result = algo.verify(jwt_message, jwt_pub_key, jwt_sig)
253216
assert not result
254217

255-
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
256-
def test_rsa_pss_verify_should_return_true_if_signature_valid(self):
257-
algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256)
258-
259-
jwt_message = ensure_bytes('Hello World!')
260-
261-
jwt_sig = base64.b64decode(ensure_bytes(
262-
'ywKAUGRIDC//6X+tjvZA96yEtMqpOrSppCNfYI7NKyon3P7doud5v65oWNu'
263-
'vQsz0fzPGfF7mQFGo9Cm9Vn0nljm4G6PtqZRbz5fXNQBH9k10gq34AtM02c'
264-
'/cveqACQ8gF3zxWh6qr9jVqIpeMEaEBIkvqG954E0HT9s9ybHShgHX9mlWk'
265-
'186/LopP4xe5c/hxOQjwhv6yDlTiwJFiqjNCvj0GyBKsc4iECLGIIO+4mC4'
266-
'daOCWqbpZDuLb1imKpmm8Nsm56kAxijMLZnpCcnPgyb7CqG+B93W9GHglA5'
267-
'drUeR1gRtO7vqbZMsCAQ4bpjXxwbYyjQlEVuMl73UL6sOWg=='))
268-
269-
with open(key_path('testkey_rsa.pub'), 'r') as keyfile:
270-
jwt_pub_key = algo.prepare_key(keyfile.read())
271-
272-
result = algo.verify(jwt_message, jwt_pub_key, jwt_sig)
273-
assert result
274218

275-
276-
class TestAlgorithmsCookbook:
219+
class TestAlgorithmsRFC7520:
277220
"""
278-
These test vectors were taken from IETF JOSE Cookbook Draft
279-
(https://www.ietf.org/id/draft-ietf-jose-cookbook-08.txt)
221+
These test vectors were taken from RFC 7520
222+
(https://tools.ietf.org/html/rfc7520)
280223
"""
281224

282225
def test_hmac_verify_should_return_true_for_test_vector(self):
226+
"""
227+
This test verifies that HMAC verification works with a known good
228+
signature and key.
229+
230+
Reference: https://tools.ietf.org/html/rfc7520#section-4.4
231+
"""
283232
signing_input = ensure_bytes(
284233
'eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZ'
285234
'jMxNGJjNzAzNyJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ'
@@ -300,6 +249,12 @@ def test_hmac_verify_should_return_true_for_test_vector(self):
300249

301250
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
302251
def test_rsa_verify_should_return_true_for_test_vector(self):
252+
"""
253+
This test verifies that RSA PKCS v1.5 verification works with a known
254+
good signature and key.
255+
256+
Reference: https://tools.ietf.org/html/rfc7520#section-4.1
257+
"""
303258
signing_input = ensure_bytes(
304259
'eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb'
305260
'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb'
@@ -323,9 +278,14 @@ def test_rsa_verify_should_return_true_for_test_vector(self):
323278
result = algo.verify(signing_input, key, signature)
324279
assert result
325280

326-
@pytest.mark.skipif(True, "I'm not 100% sure if this test is correct")
327281
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
328282
def test_rsapss_verify_should_return_true_for_test_vector(self):
283+
"""
284+
This test verifies that RSA-PSS verification works with a known good
285+
signature and key.
286+
287+
Reference: https://tools.ietf.org/html/rfc7520#section-4.2
288+
"""
329289
signing_input = ensure_bytes(
330290
'eyJhbGciOiJQUzM4NCIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb'
331291
'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb'
@@ -335,12 +295,12 @@ def test_rsapss_verify_should_return_true_for_test_vector(self):
335295
)
336296

337297
signature = base64url_decode(ensure_bytes(
338-
'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN'
339-
'6-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvW'
340-
'Xzg-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ij'
341-
'Q7p8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6ui'
342-
'P1aCN_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmW'
343-
'jwZ6oD4ifKo8DYM-X72Eaw'
298+
'cu22eBqkYDKgIlTpzDXGvaFfz6WGoz7fUDcfT0kkOy42miAh2qyBzk1xEsnk2IpN6'
299+
'-tPid6VrklHkqsGqDqHCdP6O8TTB5dDDItllVo6_1OLPpcbUrhiUSMxbbXUvdvWXz'
300+
'g-UD8biiReQFlfz28zGWVsdiNAUf8ZnyPEgVFn442ZdNqiVJRmBqrYRXe8P_ijQ7p'
301+
'8Vdz0TTrxUeT3lm8d9shnr2lfJT8ImUjvAA2Xez2Mlp8cBE5awDzT0qI0n6uiP1aC'
302+
'N_2_jLAeQTlqRHtfa64QQSUmFAAjVKPbByi7xho0uTOcbH510a6GYmJUAfmWjwZ6o'
303+
'D4ifKo8DYM-X72Eaw'
344304
))
345305

346306
algo = RSAPSSAlgorithm(RSAPSSAlgorithm.SHA384)
@@ -351,6 +311,12 @@ def test_rsapss_verify_should_return_true_for_test_vector(self):
351311

352312
@pytest.mark.skipif(not has_crypto, reason='Not supported without cryptography library')
353313
def test_ec_verify_should_return_true_for_test_vector(self):
314+
"""
315+
This test verifies that ECDSA verification works with a known good
316+
signature and key.
317+
318+
Reference: https://tools.ietf.org/html/rfc7520#section-4.3
319+
"""
354320
signing_input = ensure_bytes(
355321
'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb'
356322
'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb'

0 commit comments

Comments
 (0)