Skip to content

Commit edc4438

Browse files
committed
convert ASN1 check values to hex for better readability and add check for known legacy prefix in legacy parsing
1 parent 9a4ec31 commit edc4438

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed

jose/backends/rsa_backend.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import binascii
2+
13
import six
24
from pyasn1.codec.der import decoder, encoder
35
from pyasn1.error import PyAsn1Error
@@ -13,7 +15,16 @@
1315
from jose.utils import base64_to_long, long_to_base64
1416

1517

16-
LEGACY_INVALID_PKCS8_RSA_HEADER = b'0\x82\x04\xbd\x02\x01\x000\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00'
18+
LEGACY_INVALID_PKCS8_RSA_HEADER = binascii.unhexlify(
19+
"30" # sequence
20+
"8204BD" # DER-encoded sequence contents length of 1213 bytes -- INCORRECT STATIC LENGTH
21+
"020100" # integer: 0 -- Version
22+
"30" # sequence
23+
"0D" # DER-encoded sequence contents length of 13 bytes -- PrivateKeyAlgorithmIdentifier
24+
"06092A864886F70D010101" # OID -- rsaEncryption
25+
"0500" # NULL -- parameters
26+
)
27+
ASN1_SEQUENCE_ID = binascii.unhexlify("30")
1728
RSA_ENCRYPTION_ASN1_OID = "1.2.840.113549.1.1.1"
1829

1930
# Functions gcd and rsa_recover_prime_factors were copied from cryptography 1.9
@@ -86,15 +97,21 @@ def pem_to_spki(pem, fmt='PKCS8'):
8697
return key.to_pem(fmt)
8798

8899

89-
def _legacy_private_key_pkcs8_to_pkcs1(der_key):
100+
def _legacy_private_key_pkcs8_to_pkcs1(pkcs8_key):
90101
"""Legacy RSA private key PKCS8-to-PKCS1 conversion.
91102
92103
.. warning::
93104
94105
This is incorrect parsing and only works because the legacy PKCS1-to-PKCS8
95106
encoding was also incorrect.
96107
"""
97-
return der_key[len(LEGACY_INVALID_PKCS8_RSA_HEADER):]
108+
# Only allow this processing if the prefix matches
109+
# AND the following byte indicates an ASN1 sequence,
110+
# as we would expect with the legacy encoding.
111+
if not pkcs8_key.startswith(LEGACY_INVALID_PKCS8_RSA_HEADER + ASN1_SEQUENCE_ID):
112+
raise ValueError("Invalid private key encoding")
113+
114+
return pkcs8_key[len(LEGACY_INVALID_PKCS8_RSA_HEADER):]
98115

99116

100117
class PKCS8RsaPrivateKeyAlgorithm(univ.Sequence):

tests/algorithms/test_RSA.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,55 @@
268268
pskDwcHyZmbKZuk+NU/FJ8IAcmvk9y7m25nSSc8="""
269269

270270

271+
def _legacy_invalid_private_key_pkcs8_der():
272+
legacy_key = LEGACY_INVALID_PRIVATE_KEY_PKCS8_PEM.strip()
273+
legacy_key = legacy_key[legacy_key.index(b"\n"):legacy_key.rindex(b"\n")]
274+
return base64.b64decode(legacy_key)
275+
276+
277+
def _actually_invalid_private_key_pkcs8_der():
278+
legacy_key = _legacy_invalid_private_key_pkcs8_der()
279+
invalid_key = legacy_key[:len(rsa_backend.LEGACY_INVALID_PKCS8_RSA_HEADER)]
280+
invalid_key += b"\x00"
281+
invalid_key += legacy_key[len(rsa_backend.LEGACY_INVALID_PKCS8_RSA_HEADER):]
282+
return invalid_key
283+
284+
285+
def _actually_invalid_private_key_pkcs8_pem():
286+
invalid_key = b"-----BEGIN PRIVATE KEY-----\n"
287+
invalid_key += base64.b64encode(_actually_invalid_private_key_pkcs8_der())
288+
invalid_key += b"\n-----END PRIVATE KEY-----\n"
289+
return invalid_key
290+
291+
271292
@pytest.mark.skipif(PurePythonRSAKey is None, reason="python-rsa backend not available")
272293
class TestPurePythonRsa(object):
294+
273295
def test_python_rsa_legacy_pem_read(self):
274296
key = PurePythonRSAKey(LEGACY_INVALID_PRIVATE_KEY_PKCS8_PEM, ALGORITHMS.RS256)
275297
new_pem = key.to_pem(pem_format="PKCS8")
276298
assert new_pem != LEGACY_INVALID_PRIVATE_KEY_PKCS8_PEM
277299

300+
def test_python_rsa_legacy_pem_invalid(self):
301+
with pytest.raises(JWKError) as excinfo:
302+
PurePythonRSAKey(_actually_invalid_private_key_pkcs8_pem(), ALGORITHMS.RS256)
303+
304+
excinfo.match("Invalid private key encoding")
305+
306+
def test_python_rsa_legacy_private_key_pkcs8_to_pkcs1(self):
307+
legacy_key = _legacy_invalid_private_key_pkcs8_der()
308+
legacy_pkcs1 = legacy_key[len(rsa_backend.LEGACY_INVALID_PKCS8_RSA_HEADER):]
309+
310+
assert rsa_backend._legacy_private_key_pkcs8_to_pkcs1(legacy_key) == legacy_pkcs1
311+
312+
def test_python_rsa_legacy_private_key_pkcs8_to_pkcs1_invalid(self):
313+
invalid_key = _actually_invalid_private_key_pkcs8_der()
314+
315+
with pytest.raises(ValueError) as excinfo:
316+
rsa_backend._legacy_private_key_pkcs8_to_pkcs1(invalid_key)
317+
318+
excinfo.match("Invalid private key encoding")
319+
278320
def test_python_rsa_private_key_pkcs1_to_pkcs8(self):
279321
pkcs1 = base64.b64decode(PKCS1_PRIVATE_KEY)
280322
pkcs8 = base64.b64decode(PKCS8_PRIVATE_KEY)

0 commit comments

Comments
 (0)