From 8e78ce7e13060a66bde819d2974d97ac6ed04847 Mon Sep 17 00:00:00 2001 From: Spitap Date: Mon, 1 Aug 2022 00:49:39 +0200 Subject: [PATCH] refacor of PKCS8 parsing, added pkcs8 test --- dkim/crypto.py | 18 ++++++------ dkim/tests/data/2048_testkey_PKCS8.key | 28 +++++++++++++++++++ .../tests/data/2048_testkey_PKCS8.key.pub.txt | 1 + dkim/tests/test_dkim_rsavariants.py | 15 ++++++++-- 4 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 dkim/tests/data/2048_testkey_PKCS8.key create mode 100644 dkim/tests/data/2048_testkey_PKCS8.key.pub.txt diff --git a/dkim/crypto.py b/dkim/crypto.py index 3c5d685..6af19f2 100644 --- a/dkim/crypto.py +++ b/dkim/crypto.py @@ -145,8 +145,14 @@ def parse_private_key(data): """ try: pka = asn1_parse(ASN1_RSAPrivateKey, data) - except ASN1FormatError as e: - raise UnparsableKeyError('Unparsable private key: ' + str(e)) + except ASN1FormatError: + try: + #If it fails it might be because of PKCS#8 (key generated with openSSL 3.X) + pkt = asn1_parse(ASN1_PKCS8_PrivateKey, data) + pka = asn1_parse(ASN1_RSAPrivateKey, pkt[0][2]) + except ASN1FormatError as e: + raise UnparsableKeyError("Unparsable private key (are your sure it is encoded in PKCS#1 or PKCS#8 standard ?):\n" + str(e)) + pk = { 'version': pka[0][0], 'modulus': pka[0][1], @@ -174,13 +180,7 @@ def parse_pem_private_key(data): pkdata = base64.b64decode(m.group(1)) except TypeError as e: raise UnparsableKeyError(str(e)) - try: - pk = parse_private_key(pkdata) - except UnparsableKeyError: - #If it fails it might be because of PKCS#8 (key generated with openSSL 3.X) - pka = asn1_parse(ASN1_PKCS8_PrivateKey, pkdata) - pk = parse_private_key(pka[0][2]) - return pk + return parse_private_key(pkdata) def EMSA_PKCS1_v1_5_encode(hash, mlen): diff --git a/dkim/tests/data/2048_testkey_PKCS8.key b/dkim/tests/data/2048_testkey_PKCS8.key new file mode 100644 index 0000000..85a1c0f --- /dev/null +++ b/dkim/tests/data/2048_testkey_PKCS8.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDYMGhEok34XiUg +szO7cuYph/dw0lliI18+wwX0ybUNwjkmc89jfRNZ6OEF5BfuyMYAoHB96D9EhIAI +qXzjmvFtjZIrYTyzb2X/4Cml7uxGLiekSFjrANL1mybg36FKeMAV59s078++IrcQ +Trr1E6e7q127/YRwCGy+KZQ0Sl2CrL+IdPuCK5WAJtYT1zQ/h3PQ/xUcHLnUtem5 +BOirg7sweoxdfZWsXu7WeGDYiFOOV5pMmdueFfun5CJe8MfdEJ4YsXqxCxa2yqrN +klkX4RSphEfwreU/sv0DsWj/eaWmFDhagvd2AwixId/lFYGsY2X7G6bs/SqThoBk +9GftRGihAgMBAAECggEAYiHjCpiUBPQTLVs61dEridmWp8dL3IDK6K3VA88VmMe7 +cmlqT7JEOPE9R5PIi1Lmkf1B4t0r7tmoVoY80wIPqhdzrK5IQ/kCl1n0/cXMyXSE ++Q0AE7h9ihAh3zyTtb7HDop+1fIvXhLa/xOFyN5hqo34j+9dkQ858T3lcLD67mfO +1/lpBhwEeF/7+wg2MiwM/4Rd217ReUgdgXTKZ8DYtLr+TFagv/8E8zAgHVqnklHf +yEGR5+O94WYpqbanagfivxmogHsW6Eu5Ub/RJuWj06AvhRQSkPgVV5pl1zv0EP2w +vhAl2YVzorRJDEzclmP+PyTzp+sPbrIqywof+K89WwKBgQDddD6eqISrWC4Vo2CZ +WvBetiC48KKKjWwcFGERHGYqrmZMTDVYKqSUO7PvcgHIVyElYnlcqJWqyyQDBhy/ +ShOZjQ0oy9SblZMoVjLYONS0iFDoz2of8/kvY+kuzh+3iU9Qg6BI+lfRSd8KjGBB +xsLOoUhzQceXqmx5SmOGIn6EmwKBgQD56efYqmYj/GGLz/gyfyElsQFUWG0tyNjm +ujufTxjhEDWw3pnS3vUVG/gleGJH7f9vzCfEI4WlBuZUidrwM64cnF4QXQwuhT7p +5U+nKNVfJpMeglehgVl6vSi/L1ovilCNo5A4aQJxyS73KTcU1UAZ4/VZnrvYrV/f +ysxWTrx1cwKBgDAAyKofoVJ69NJf7cqQOdZt6D3ue21JJowXpsrMuyC5WRdk1ZNc ++vvezSw0LEq/CEJQTDpXmMnC6vV017pnVkRMnPOg618mVxXBSZgxCXpwqgktHLX8 +bqFlKOCqcZmZPAYZ4h6vlWWae6yPrTXU3dlogInrUlZ/7K+F/njO9VnNAoGBAOvp +QsPDruGfd9GMQ2YfngG/glrFkmKa6y16dZfgCcNDEvvgVeK6Ny5zFZ8Bcf0mjG9T +j+JWCe2LgtggvfzrPBuj/COEQmCTxZzzq2pHYIwOlOhC8Ef0G6yCbbl0ELU54uqh +kR2++uDAokYMsQNIftcx2kR8VCSpHQzbmmKKttpDAoGBAIGVTOJtRi3nvmz1q3Zy +vad1gTrkyy/gtjuE+8KNKhWwnC+MYXsSOykh+x6GQQ1gHRjk6GMsQxwl3xbHvzdG +yp7Fc3aWkJbARSINOcAblH8JWdCMGBY/FlSogl0ptROVFxkyM2DnchM1bSsJ9wvf +xB4hqm1VSknnOCCK+NekIC48 +-----END PRIVATE KEY----- diff --git a/dkim/tests/data/2048_testkey_PKCS8.key.pub.txt b/dkim/tests/data/2048_testkey_PKCS8.key.pub.txt new file mode 100644 index 0000000..6ae39c8 --- /dev/null +++ b/dkim/tests/data/2048_testkey_PKCS8.key.pub.txt @@ -0,0 +1 @@ +v=DKIM1; g=*; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2DBoRKJN+F4lILMzu3LmKYf3cNJZYiNfPsMF9Mm1DcI5JnPPY30TWejhBeQX7sjGAKBwfeg/RISACKl845rxbY2SK2E8s29l/+Appe7sRi4npEhY6wDS9Zsm4N+hSnjAFefbNO/PviK3EE669ROnu6tdu/2EcAhsvimUNEpdgqy/iHT7giuVgCbWE9c0P4dz0P8VHBy51LXpuQToq4O7MHqMXX2VrF7u1nhg2IhTjleaTJnbnhX7p+QiXvDH3RCeGLF6sQsWtsqqzZJZF+EUqYRH8K3lP7L9A7Fo/3mlphQ4WoL3dgMIsSHf5RWBrGNl+xum7P0qk4aAZPRn7URooQIDAQAB diff --git a/dkim/tests/test_dkim_rsavariants.py b/dkim/tests/test_dkim_rsavariants.py index 308f7a9..992d466 100644 --- a/dkim/tests/test_dkim_rsavariants.py +++ b/dkim/tests/test_dkim_rsavariants.py @@ -41,6 +41,7 @@ class TestSignAndVerify(unittest.TestCase): self.message = read_test_data("test.message") self.key1024 = read_test_data("1024_testkey.key") self.key2048 = read_test_data("2048_testkey.key") + self.key2048PKCS8 = read_test_data("2048_testkey_PKCS8.key") def dnsfunc(self, domain, timeout=5): _dns_responses = { @@ -48,6 +49,7 @@ class TestSignAndVerify(unittest.TestCase): 'test2._domainkey.example.com.': read_test_data("1024_testkey_wo_markers.pub.rsa.txt"), 'test3._domainkey.example.com.': read_test_data("2048_testkey_wo_markers.pub.txt"), 'test4._domainkey.example.com.': read_test_data("2048_testkey_wo_markers.pub.rsa.txt"), + 'test5._domainkey.example.com.': read_test_data("2048_testkey_PKCS8.key.pub.txt") } try: domain = domain.decode('ascii') @@ -56,7 +58,6 @@ class TestSignAndVerify(unittest.TestCase): self.assertTrue(domain in _dns_responses,domain) return _dns_responses[domain] - def test_verifies_SubjectPublicKeyInfo1024(self): # A message verifies after being signed. for header_algo in (b"simple", b"relaxed"): @@ -67,8 +68,6 @@ class TestSignAndVerify(unittest.TestCase): res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc) self.assertTrue(res) - - def test_verifies_RSAPublicKey1024(self): # A message verifies after being signed. for header_algo in (b"simple", b"relaxed"): @@ -102,6 +101,16 @@ class TestSignAndVerify(unittest.TestCase): self.assertTrue(res) + def test_verifies_RSAPublicKey2048PKCS8(self): + #A message verifies after being signed (with PKCS8 private key) + for header_algo in (b"simple", b"relaxed"): + for body_algo in (b"simple", b"relaxed"): + sig = dkim.sign( + self.message, b"test5", b"example.com", self.key2048PKCS8, + canonicalize=(header_algo, body_algo)) + res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc) + self.assertTrue(res) + def test_suite(): from unittest import TestLoader return TestLoader().loadTestsFromName(__name__)