From c519657d852b264b146dae005e44f0a4404058fc Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sat, 12 Apr 2025 10:50:26 -0700 Subject: [PATCH] allow IDNA2008 encoded email addresses with warning --- CHANGELOG | 3 ++- jc/parsers/asn1crypto/x509.py | 2 +- tests/fixtures/generic/x509-cert-bad-email2.der | Bin 0 -> 354 bytes tests/fixtures/generic/x509-cert-bad-email2.json | 1 + tests/test_x509_cert.py | 14 +++++++++++++- 5 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/generic/x509-cert-bad-email2.der create mode 100644 tests/fixtures/generic/x509-cert-bad-email2.json diff --git a/CHANGELOG b/CHANGELOG index 38774f41..5f4703df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,12 @@ jc changelog -20250402 v1.25.5 +20250412 v1.25.5 - Add `amixer` command parser - Fix `bluetoothctl` parser failing to parse controllers with power state prop - Fix `lsblk` command parser to support multiple mountpoints. Also, added byte conversions for size fields. - Fix `time` command parser for output that does not contain centiseconds +- Fix `x509-cert` parser to handle IDNA2008 encoded email addresses with a warning - Fix typing for upcoming python v3.14 - Fix timezone setting for tests to support minimal chrooted builds diff --git a/jc/parsers/asn1crypto/x509.py b/jc/parsers/asn1crypto/x509.py index 563fa3bd..07beee6f 100644 --- a/jc/parsers/asn1crypto/x509.py +++ b/jc/parsers/asn1crypto/x509.py @@ -255,7 +255,7 @@ class EmailAddress(IA5String): # fix to allow incorrectly encoded email addresses to succeed with warning try: self._unicode = mailbox.decode('cp1252') + '@' + hostname.decode('idna') - except UnicodeDecodeError: + except (UnicodeDecodeError, UnicodeError): ascii_mailbox = mailbox.decode('ascii', errors='backslashreplace') ascii_hostname = hostname.decode('ascii', errors='backslashreplace') from jc.utils import warning_message diff --git a/tests/fixtures/generic/x509-cert-bad-email2.der b/tests/fixtures/generic/x509-cert-bad-email2.der new file mode 100644 index 0000000000000000000000000000000000000000..20ce02b5ffef745c9f2a41b471ffa78f31ba101a GIT binary patch literal 354 zcmXqLVvI9rVq{*x%*4pVBw{Y)y!hnn((Q@)mht?)E3agwCmu53V&l+i^EhYA!pvkK zZ769V&c+3TLi&YJj4HSWnmK9`?GLUE# zD^4v=%yp>9)7335DN0P$%`Z&UOG!ocC$lGmfg6(|!yIdi*VlrcczXMANwS2wrWyMG zJ<$6m=XhdbqXS21$|0bVp9?KsMSVD^S95UE-X99(cLS26bL+ZHHKy-3*l_zo>qh{n CK65Jo literal 0 HcmV?d00001 diff --git a/tests/fixtures/generic/x509-cert-bad-email2.json b/tests/fixtures/generic/x509-cert-bad-email2.json new file mode 100644 index 00000000..6743f076 --- /dev/null +++ b/tests/fixtures/generic/x509-cert-bad-email2.json @@ -0,0 +1 @@ +[{"tbs_certificate":{"version":"v3","serial_number":"37:12:43:a3:c9:eb:75:b7:61:6f:39:5f:0f:4d:a9:d4:6a:67:61:c2","signature":{"algorithm":"sha256_ecdsa","parameters":null},"issuer":{"common_name":"idna issues Inc."},"validity":{"not_before":1744299375,"not_after":2059659375,"not_before_iso":"2025-04-10T15:36:15+00:00","not_after_iso":"2035-04-08T15:36:15+00:00"},"subject":{"common_name":"idna issues Inc."},"subject_public_key_info":{"algorithm":{"algorithm":"ec","parameters":"secp256r1"},"public_key":"04:c4:e7:a0:b8:d0:5a:d3:77:86:e9:b2:b4:0d:4c:4f:52:25:0b:53:5b:21:5e:f1:50:1e:4f:6c:f4:8f:44:03:50:c2:ee:0e:61:2b:56:09:25:5c:4c:17:2a:78:cd:d2:ff:f5:8f:0e:68:eb:c9:4b:8a:18:0d:62:8d:9b:46:5f:71"},"issuer_unique_id":null,"subject_unique_id":null,"extensions":[{"extn_id":"subject_alt_name","critical":false,"extn_value":["sesam@xn--strae-oqa.de"]}],"serial_number_str":"314401798066465365584221074488388179068992315842"},"signature_algorithm":{"algorithm":"sha256_ecdsa","parameters":null},"signature_value":"30:46:02:21:00:9c:3b:38:eb:d6:52:e4:49:4b:4c:0a:19:04:56:45:66:31:4f:fd:c0:8d:ec:6c:c7:61:61:81:40:08:55:64:c2:02:21:00:f9:a1:38:ea:5a:f0:c1:2e:7c:c1:92:bd:f8:20:77:dd:50:63:5b:6d:7e:8a:35:28:97:bf:30:b0:db:d0:85:f1"}] diff --git a/tests/test_x509_cert.py b/tests/test_x509_cert.py index 36421d66..66a3b767 100644 --- a/tests/test_x509_cert.py +++ b/tests/test_x509_cert.py @@ -33,6 +33,9 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-negative-serial.pem'), 'rb') as f: x509_cert_negative_serial = f.read() + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-cert-bad-email2.der'), 'rb') as f: + x509_cert_bad_email2 = f.read() + # output with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-ca-cert.json'), 'r', encoding='utf-8') as f: x509_ca_cert_json = json.loads(f.read()) @@ -54,10 +57,13 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-cert-superfluous-bits.json'), 'r', encoding='utf-8') as f: x509_cert_superfluous_bits_json = json.loads(f.read()) - + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-negative-serial.json'), 'r', encoding='utf-8') as f: x509_cert_negative_serial_json = json.loads(f.read()) + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/x509-cert-bad-email2.json'), 'r', encoding='utf-8') as f: + x509_cert_bad_email2_json = json.loads(f.read()) + def test_x509_cert_nodata(self): """ @@ -113,6 +119,12 @@ class MyTests(unittest.TestCase): """ self.assertEqual(jc.parsers.x509_cert.parse(self.x509_cert_negative_serial, quiet=True), self.x509_cert_negative_serial_json) + def test_x509_cert_bad_email2(self): + """ + Test 'cat x509-cert-bad-email2.der' (DER file with a non-compliant email address - IDNA2008 encoded) + """ + self.assertEqual(jc.parsers.x509_cert.parse(self.x509_cert_bad_email2, quiet=True), self.x509_cert_bad_email2_json) + if __name__ == '__main__': unittest.main()