From 02e005a983d4e1993767dbeea026e8eba800897b Mon Sep 17 00:00:00 2001 From: jhughesbiot Date: Wed, 13 Mar 2024 10:18:25 -0600 Subject: [PATCH 1/4] Initial tls module report --- modules/test/tls/python/src/tls_module.py | 176 +++++++++++++++++- testing/unit/run_tests.sh | 22 +-- testing/unit/tls/{ => captures}/monitor.pcap | Bin testing/unit/tls/{ => captures}/no_tls.pcap | Bin testing/unit/tls/captures/tls.pcap | Bin 0 -> 44043 bytes testing/unit/tls/captures/tls_ext.pcap | Bin 0 -> 3732 bytes .../tls/{ => captures}/unsupported_tls.pcap | Bin .../unit/tls/reports/tls_report_ext_local.md | 33 ++++ testing/unit/tls/reports/tls_report_local.md | 35 ++++ testing/unit/tls/tls_module_test.py | 70 ++++++- 10 files changed, 313 insertions(+), 23 deletions(-) rename testing/unit/tls/{ => captures}/monitor.pcap (100%) rename testing/unit/tls/{ => captures}/no_tls.pcap (100%) create mode 100644 testing/unit/tls/captures/tls.pcap create mode 100644 testing/unit/tls/captures/tls_ext.pcap rename testing/unit/tls/{ => captures}/unsupported_tls.pcap (100%) create mode 100644 testing/unit/tls/reports/tls_report_ext_local.md create mode 100644 testing/unit/tls/reports/tls_report_local.md diff --git a/modules/test/tls/python/src/tls_module.py b/modules/test/tls/python/src/tls_module.py index b00cccc8d..7dcfb2834 100644 --- a/modules/test/tls/python/src/tls_module.py +++ b/modules/test/tls/python/src/tls_module.py @@ -14,23 +14,188 @@ """Baseline test module""" from test_module import TestModule from tls_util import TLSUtil +import os +import pyshark +from cryptography import x509 +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa, dsa, ec LOG_NAME = 'test_tls' -LOGGER = None +MODULE_REPORT_FILE_NAME = 'tls_report.md' STARTUP_CAPTURE_FILE = '/runtime/device/startup.pcap' MONITOR_CAPTURE_FILE = '/runtime/device/monitor.pcap' GATEWAY_CAPTURE_FILE = '/runtime/network/gateway.pcap' +LOGGER = None + class TLSModule(TestModule): """An example testing module.""" - def __init__(self, module): - super().__init__(module_name=module, log_name=LOG_NAME) + def __init__(self, + module, + log_dir=None, + conf_file=None, + results_dir=None, + startup_capture_file=STARTUP_CAPTURE_FILE, + monitor_capture_file=MONITOR_CAPTURE_FILE, + gateway_capture_file=GATEWAY_CAPTURE_FILE): + super().__init__(module_name=module, + log_name=LOG_NAME, + log_dir=log_dir, + conf_file=conf_file, + results_dir=results_dir) + self.startup_capture_file = startup_capture_file + self.monitor_capture_file = monitor_capture_file + self.gateway_capture_file = gateway_capture_file global LOGGER LOGGER = self._get_logger() self._tls_util = TLSUtil(LOGGER) + def generate_module_report(self): + summary = '## Summary' + + summary_header = (f'''| {'#': ^5} ''' + f'''| {'Expiry': ^{25}} ''' + f'''| {'Length': ^{8}} ''' + f'''| {'Type': ^{6}} ''' + f'''| {'Port No.': ^{10}} ''' + f'''| {'Signed by': ^{11}} | ''') + summary_header_line = (f'''|{'-' * 7}''' + f'''|{'-' * 27}''' + f'''|{'-' * 10}''' + f'''|{'-' * 8}''' + f'''|{'-' * 12}''' + f'''|{'-' * 13}|''') + summary_table = f'{summary_header}\n{summary_header_line}' + + # List of capture files to scan + pcap_files = [ + self.startup_capture_file, self.monitor_capture_file, + self.gateway_capture_file + ] + certificates = self.extract_certificates_from_pcap(pcap_files, + self._device_mac) + cert_tables = [] + for cert_num, ((ip_address, port), cert) in enumerate(certificates.items()): + # Extract certificate data + not_valid_before = cert.not_valid_before + not_valid_after = cert.not_valid_after + version_value = f'{cert.version.value + 1} ({hex(cert.version.value)})' + signature_alg_value = cert.signature_algorithm_oid._name # pylint: disable=W0212 + not_before = str(not_valid_before) + not_after = str(not_valid_after) + public_key = cert.public_key() + signed_by = 'None' + if isinstance(public_key, rsa.RSAPublicKey): + public_key_type = "RSA" + elif isinstance(public_key, dsa.DSAPublicKey): + public_key_type = "DSA" + elif isinstance(public_key, ec.EllipticCurvePublicKey): + public_key_type = "EC" + else: + public_key_type = "Unknown" + # Calculate certificate length + cert_length = len(cert.public_bytes(encoding=serialization.Encoding.DER)) + # Generate the Certificate table + cert_table = (f'| Property | Value |\n' + f'|---|---|\n' + f"| {'Version':<17} | {version_value:^25} |\n" + f"| {'Signature Alg.':<17} | {signature_alg_value:^25} |\n" + f"| {'Validity from':<17} | {not_before:^25} |\n" + f"| {'Valid to':<17} | {not_after:^25} |") + + # Generate the Subject table + subj_table = ('| Distinguished Name | Value |\n' + '|---|---|') + for val in cert.subject.rdns: + dn = val.rfc4514_string().split('=') + subj_table += f'\n| {dn[0]} | {dn[1]}' + + # Generate the Issuer table + iss_table = ('| Distinguished Name | Value |\n' + '|---|---|') + for val in cert.issuer.rdns: + dn = val.rfc4514_string().split('=') + iss_table += f'\n| {dn[0]} | {dn[1]}' + if 'CN' in dn[0]: + signed_by = dn[1] + + ext_table = None + if cert.extensions: + ext_table = ('| Extension | Value |\n' + '|---|---|') + for extension in cert.extensions: + for extension_value in extension.value: + ext_table += f'\n| {extension.oid._name} | {extension_value.value}' # pylint: disable=W0212 + cert_table = f'### Certificate\n{cert_table}' + cert_table += f'\n\n### Subject\n{subj_table}' + cert_table += f'\n\n### Issuer\n{iss_table}' + if ext_table is not None: + cert_table += f'\n\n### Extensions\n{ext_table}' + cert_tables.append(cert_table) + summary_table_row = (f'''| {cert_num+1: ^5} ''' + f'''| {not_after: ^25} ''' + f'''| {cert_length: ^8} ''' + f'''| {public_key_type: ^6} ''' + f'''| {port: ^10} ''' + f'''| {signed_by: ^11} |''') + summary_table+=f'\n{summary_table_row}' + + markdown_template = '# Connection Module\n' + '\n'.join( + '\n' + tables for tables in cert_tables) + + summary = f'## Summary\n\n{summary_table}' + + markdown_template += f'\n\n{summary}' + LOGGER.debug('Markdown Report:\n' + markdown_template) + + # Use os.path.join to create the complete file path + report_path = os.path.join(self._results_dir, MODULE_REPORT_FILE_NAME) + + # Write the content to a file + with open(report_path, 'w', encoding='utf-8') as file: + file.write(markdown_template) + + LOGGER.info('Module report generated at: ' + str(report_path)) + return report_path + + def extract_certificates_from_pcap(self, pcap_files, mac_address): + # Initialize a list to store packets + all_packets = [] + # Iterate over each file + for pcap_file in pcap_files: + # Open the capture file + packets = pyshark.FileCapture(pcap_file) + try: + # Iterate over each packet in the file and add it to the list + for packet in packets: + all_packets.append(packet) + finally: + # Close the capture file + packets.close() + + certificates = {} + # Loop through each item (packet) + for packet in all_packets: + if 'TLS' in packet: + # Check if the packet's source matches the target MAC address + if 'eth' in packet and (packet.eth.src == mac_address): + # Look for attribute of x509 + if hasattr(packet['TLS'], 'x509sat_utf8string'): + certificate_bytes = bytes.fromhex( + packet['TLS'].handshake_certificate.replace(':', '')) + # Parse the certificate bytes + certificate = x509.load_der_x509_certificate( + certificate_bytes, default_backend()) + # Extract IP address and port from packet + ip_address = packet.ip.src + port = packet.tcp.srcport if 'tcp' in packet else packet.udp.srcport + # Store certificate in dictionary with IP address and port as key + certificates[(ip_address, port)] = certificate + return certificates + def _security_tls_v1_2_server(self): LOGGER.info('Running security.tls.v1_2_server') self._resolve_device_ip() @@ -81,8 +246,9 @@ def _validate_tls_client(self, client_ip, tls_version): client_results = self._tls_util.validate_tls_client( client_ip=client_ip, tls_version=tls_version, - capture_files=[MONITOR_CAPTURE_FILE,STARTUP_CAPTURE_FILE, - GATEWAY_CAPTURE_FILE]) + capture_files=[ + MONITOR_CAPTURE_FILE, STARTUP_CAPTURE_FILE, GATEWAY_CAPTURE_FILE + ]) # Generate results based on the state result_message = 'No outbound connections were found.' diff --git a/testing/unit/run_tests.sh b/testing/unit/run_tests.sh index fe186c8db..d7d8700c1 100644 --- a/testing/unit/run_tests.sh +++ b/testing/unit/run_tests.sh @@ -34,23 +34,23 @@ PYTHONPATH="$PYTHONPATH:$PWD/modules/test/ntp/python/src" # Set the python path with all sources export PYTHONPATH -# Run the DHCP Unit tests -python3 -u $PWD/modules/network/dhcp-1/python/src/grpc_server/dhcp_config_test.py -python3 -u $PWD/modules/network/dhcp-2/python/src/grpc_server/dhcp_config_test.py +# # Run the DHCP Unit tests +# python3 -u $PWD/modules/network/dhcp-1/python/src/grpc_server/dhcp_config_test.py +# python3 -u $PWD/modules/network/dhcp-2/python/src/grpc_server/dhcp_config_test.py # Run the TLS Module Unit Tests python3 -u $PWD/testing/unit/tls/tls_module_test.py -# Run the DNS Module Unit Tests -python3 -u $PWD/testing/unit/dns/dns_module_test.py +# # Run the DNS Module Unit Tests +# python3 -u $PWD/testing/unit/dns/dns_module_test.py -# Run the NMAP Module Unit Tests -python3 -u $PWD/testing/unit/nmap/nmap_module_test.py +# # Run the NMAP Module Unit Tests +# python3 -u $PWD/testing/unit/nmap/nmap_module_test.py -# Run the NTP Module Unit Tests -python3 -u $PWD/testing/unit/ntp/ntp_module_test.py +# # Run the NTP Module Unit Tests +# python3 -u $PWD/testing/unit/ntp/ntp_module_test.py -# # Run the Report Unit Tests -python3 -u $PWD/testing/unit/report/report_test.py +# # # Run the Report Unit Tests +# python3 -u $PWD/testing/unit/report/report_test.py popd >/dev/null 2>&1 \ No newline at end of file diff --git a/testing/unit/tls/monitor.pcap b/testing/unit/tls/captures/monitor.pcap similarity index 100% rename from testing/unit/tls/monitor.pcap rename to testing/unit/tls/captures/monitor.pcap diff --git a/testing/unit/tls/no_tls.pcap b/testing/unit/tls/captures/no_tls.pcap similarity index 100% rename from testing/unit/tls/no_tls.pcap rename to testing/unit/tls/captures/no_tls.pcap diff --git a/testing/unit/tls/captures/tls.pcap b/testing/unit/tls/captures/tls.pcap new file mode 100644 index 0000000000000000000000000000000000000000..3d49a4551d9586e34fc3ce74fc49c2fd6c36d0b9 GIT binary patch literal 44043 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 literal 0 HcmV?d00001 diff --git a/testing/unit/tls/captures/tls_ext.pcap b/testing/unit/tls/captures/tls_ext.pcap new file mode 100644 index 0000000000000000000000000000000000000000..09d75837a0f70b0526bfdbb5bce40743523d65dc GIT binary patch literal 3732 zcmeH~XH-+!7RS%MHwh^q_&|aRp^89++z^TkQbLU#DdQkTkgjwBqat+%Y^dN95m1T< z!XTqG1wo852qFdrrKzA4M~bMRV#Rka&RCdP^FF@!!K}5j&dJKzXaDzI>;Jp^R()A6 z3<%)!hX5dK<890KT33dEE^Lj5ntI~m4q^tpo^gOe29^Lc7p0p5QxAzpD8 zs!46Qm_n9pZ?=(vUaCC;KpKI-F)Up=f-s6E;19RcWZIOHN~b~fFRe|Q7aco{7J2J1 zs(&;bI|Kkjutb0gm;zQyQA?pfMW7~77AywYAPZ~(KHvkE#um^30Ra#Us6Z48IY0*t zFdxVOWvoPLEa+H>0S%x=K!^wlA&Zd7WD1!|rjZF`BAG;hh!6=v5ClSC0!)NSFs^ft zHxcAwEx_ZW!jEckorHf=(r}%GJX|BL6{@MYi)&165O8c{>_-N2aGeOj8wS7{K?)vv zw^NHsz*-F<_=L-c)0K_qM zm_EFE8h|0}3yB6uBtW*J@dzJ{hn#Z|7=mF5;;L5}4CxZ%;kZjYrdwVuDn_DcB=Qoc z#2|=91gH+1hEhm~1A!z7JJ_+M(0}0@swi!_y@G{bgkP9nP#{|zJB9s2C;)XtB}pP!p+X}VB9Uhn2qc1-0fLBQn!D5qboA;I zVS#{fS$`qHS8&ZcX-oJ+4iWN3C0oj^t#@CpAgAd}9^z@YIb@7~*OBGLKe}KtQQ?v5 zk)k{%jBinF<(KZX37Qcud@(6H79(ACpz{l8R84x^fhf(6tb9AVYV?Y zl*r5p&43Kr(k%u>F=v{`LOzIZ=VjF?X3`rfD4q-4^wzU_@7BE3m7A`<_p2;1#_G5< zE_V6ORW2Y^Pi{WKV{!(nbVcr9JaKnkhE~3^nzHhx_9;CCu{gc+7%K5 zyTCB3B3Lea4KD?aoMe;Tkr|GD)(0xq7d);XXcpLzM0%liU7>c4hgEPp-f9I$C3%vwM(wQ_u&IT}Glec$X7hjT?C>D$cT}dn4)PW}-&|BeleMPF(ss zz4*8{R-TiG%~Wi!yKc;$;wnDf(3Dq?MyyIhb4CR}IhDArj2euywed+l?e^B%;>Xz2 z=GNu`SIwrb!RulC7fsvvv2fVBTZgzx^BhNg}?86TUg}%vn9RUwt5HA zS9wF{*ogdz7YeQx$?p}N?)TqRwqvT2HMm9jPdXpIxW-cZKGwpwf6;dprW8>CQV>Ar z5~kYJee>kRt|diH`!^c>)=;L&I4d!FHf(raM9)A=ig9N2y;B92bLt$dp7&T>O*G#+ z$m0m!^c;{j6e`Vy>FY7S;-OZsBIu7w-)8@Wm$YC?s9!EY-q?N8V>rSnvhJyw&|qgIha4-hP5z+2r95O9)B_B zf}+eBW8V9Ym|v*yUoBaUN-otdHqn0jft5`wCAhse?zs%XSEr(l-q+P zdUp!F-BQ=^^W)07;O-C&R$jlbu1@}cNVV-HA|MAN8XmJ7OgKn6IzzSWFB;rGqtV3d z3QjepTOXG(SH1Tok)A7rEDuZ>Aiu8L|II8$75uQ zx+AJoTzAvW4d1BtjcVVh_J2sVnLQU?h2r$B6fX82;#=5P5`;}4DEMLA7?fGtS25PGTn1?Y4hEd$)-(L8f zY_|CU79|T$Mgd=&AC}0(Oo*9Zzum<@l0h@LeIG~$bo})ki`kVylwl^GOzp_0%EqCZ z{@97kpUTUFabl=1#+?)bcd^r52r@a5J$Kcu`dE{xPH&3I_ZFH5lg{mOiCF8kEa*eH zbQxbE#>QoxXjQx;eZG}#P_5Zbky8nwmcKV&QjHxDHKgjL0J0=3iAX{-6Vc8uCL(Dd z^?4$~<_QRbAp|1KnvEDh_Mc`Wzyt`45P&8&hCqM=RDlYXRKZ+60+vr$uCd#U*cel( zP!+COu(o5%+hT{REwltCFy4&6mCz}l9^l{fJQr^h`TZ9?AIDqNA3M1N>v^#z Date: Wed, 13 Mar 2024 12:59:11 -0600 Subject: [PATCH 2/4] Fix report title add dependencies to tls test module change gateway capture to tls module capture --- modules/test/tls/python/requirements.txt | 4 +++- modules/test/tls/python/src/run.py | 1 + modules/test/tls/python/src/tls_module.py | 10 +++++----- testing/unit/tls/reports/tls_report_ext_local.md | 2 +- testing/unit/tls/reports/tls_report_local.md | 2 +- testing/unit/tls/tls_module_test.py | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/modules/test/tls/python/requirements.txt b/modules/test/tls/python/requirements.txt index 432116ff2..719299488 100644 --- a/modules/test/tls/python/requirements.txt +++ b/modules/test/tls/python/requirements.txt @@ -1,2 +1,4 @@ cryptography -pyOpenSSL \ No newline at end of file +pyOpenSSL +pyshark +cryptography \ No newline at end of file diff --git a/modules/test/tls/python/src/run.py b/modules/test/tls/python/src/run.py index 51bc82f8f..2b7ea7e0f 100644 --- a/modules/test/tls/python/src/run.py +++ b/modules/test/tls/python/src/run.py @@ -37,6 +37,7 @@ def __init__(self, module): self._test_module = TLSModule(module) self._test_module.run_tests() + self._test_module.generate_module_report() def _handler(self, signum): LOGGER.debug('SigtermEnum: ' + str(signal.SIGTERM)) diff --git a/modules/test/tls/python/src/tls_module.py b/modules/test/tls/python/src/tls_module.py index 7dcfb2834..a6dc4e8fe 100644 --- a/modules/test/tls/python/src/tls_module.py +++ b/modules/test/tls/python/src/tls_module.py @@ -25,7 +25,7 @@ MODULE_REPORT_FILE_NAME = 'tls_report.md' STARTUP_CAPTURE_FILE = '/runtime/device/startup.pcap' MONITOR_CAPTURE_FILE = '/runtime/device/monitor.pcap' -GATEWAY_CAPTURE_FILE = '/runtime/network/gateway.pcap' +TLS_CAPTURE_FILE = '/runtime/output/tls.pcap' LOGGER = None @@ -40,7 +40,7 @@ def __init__(self, results_dir=None, startup_capture_file=STARTUP_CAPTURE_FILE, monitor_capture_file=MONITOR_CAPTURE_FILE, - gateway_capture_file=GATEWAY_CAPTURE_FILE): + tls_capture_file=TLS_CAPTURE_FILE): super().__init__(module_name=module, log_name=LOG_NAME, log_dir=log_dir, @@ -48,7 +48,7 @@ def __init__(self, results_dir=results_dir) self.startup_capture_file = startup_capture_file self.monitor_capture_file = monitor_capture_file - self.gateway_capture_file = gateway_capture_file + self.tls_capture_file = tls_capture_file global LOGGER LOGGER = self._get_logger() self._tls_util = TLSUtil(LOGGER) @@ -73,7 +73,7 @@ def generate_module_report(self): # List of capture files to scan pcap_files = [ self.startup_capture_file, self.monitor_capture_file, - self.gateway_capture_file + self.tls_capture_file ] certificates = self.extract_certificates_from_pcap(pcap_files, self._device_mac) @@ -143,7 +143,7 @@ def generate_module_report(self): f'''| {signed_by: ^11} |''') summary_table+=f'\n{summary_table_row}' - markdown_template = '# Connection Module\n' + '\n'.join( + markdown_template = '# TLS Module\n' + '\n'.join( '\n' + tables for tables in cert_tables) summary = f'## Summary\n\n{summary_table}' diff --git a/testing/unit/tls/reports/tls_report_ext_local.md b/testing/unit/tls/reports/tls_report_ext_local.md index afe740753..878fa0743 100644 --- a/testing/unit/tls/reports/tls_report_ext_local.md +++ b/testing/unit/tls/reports/tls_report_ext_local.md @@ -1,4 +1,4 @@ -# Connection Module +# TLS Module ### Certificate | Property | Value | diff --git a/testing/unit/tls/reports/tls_report_local.md b/testing/unit/tls/reports/tls_report_local.md index 49d261ece..dc3866dc6 100644 --- a/testing/unit/tls/reports/tls_report_local.md +++ b/testing/unit/tls/reports/tls_report_local.md @@ -1,4 +1,4 @@ -# Connection Module +# TLS Module ### Certificate | Property | Value | diff --git a/testing/unit/tls/tls_module_test.py b/testing/unit/tls/tls_module_test.py index 8e3f2a3cf..2212d7048 100644 --- a/testing/unit/tls/tls_module_test.py +++ b/testing/unit/tls/tls_module_test.py @@ -305,7 +305,7 @@ def tls_module_report_test(self): results_dir=OUTPUT_DIR, startup_capture_file=pcap_file, monitor_capture_file=pcap_file, - gateway_capture_file=pcap_file) + tls_capture_file=pcap_file) report_out_path = tls.generate_module_report() with open(report_out_path, 'r', encoding='utf-8') as file: @@ -327,7 +327,7 @@ def tls_module_report_ext_test(self): results_dir=OUTPUT_DIR, startup_capture_file=pcap_file, monitor_capture_file=pcap_file, - gateway_capture_file=pcap_file) + tls_capture_file=pcap_file) report_out_path = tls.generate_module_report() # Read the generated report From 14ffbe10c9cee148090c69214a4097d57b98f194 Mon Sep 17 00:00:00 2001 From: jhughesbiot Date: Wed, 13 Mar 2024 13:40:38 -0600 Subject: [PATCH 3/4] Add no cert result --- modules/test/tls/python/src/tls_module.py | 136 +++++++++--------- .../tls/reports/tls_report_no_cert_local.md | 9 ++ testing/unit/tls/tls_module_test.py | 17 ++- 3 files changed, 96 insertions(+), 66 deletions(-) create mode 100644 testing/unit/tls/reports/tls_report_no_cert_local.md diff --git a/modules/test/tls/python/src/tls_module.py b/modules/test/tls/python/src/tls_module.py index a6dc4e8fe..72a6b1c92 100644 --- a/modules/test/tls/python/src/tls_module.py +++ b/modules/test/tls/python/src/tls_module.py @@ -77,77 +77,83 @@ def generate_module_report(self): ] certificates = self.extract_certificates_from_pcap(pcap_files, self._device_mac) - cert_tables = [] - for cert_num, ((ip_address, port), cert) in enumerate(certificates.items()): - # Extract certificate data - not_valid_before = cert.not_valid_before - not_valid_after = cert.not_valid_after - version_value = f'{cert.version.value + 1} ({hex(cert.version.value)})' - signature_alg_value = cert.signature_algorithm_oid._name # pylint: disable=W0212 - not_before = str(not_valid_before) - not_after = str(not_valid_after) - public_key = cert.public_key() - signed_by = 'None' - if isinstance(public_key, rsa.RSAPublicKey): - public_key_type = "RSA" - elif isinstance(public_key, dsa.DSAPublicKey): - public_key_type = "DSA" - elif isinstance(public_key, ec.EllipticCurvePublicKey): - public_key_type = "EC" - else: - public_key_type = "Unknown" - # Calculate certificate length - cert_length = len(cert.public_bytes(encoding=serialization.Encoding.DER)) - # Generate the Certificate table - cert_table = (f'| Property | Value |\n' - f'|---|---|\n' - f"| {'Version':<17} | {version_value:^25} |\n" - f"| {'Signature Alg.':<17} | {signature_alg_value:^25} |\n" - f"| {'Validity from':<17} | {not_before:^25} |\n" - f"| {'Valid to':<17} | {not_after:^25} |") + if len(certificates)>0: + cert_tables = [] + for cert_num, ((ip_address, port), cert) in enumerate(certificates.items()): + # Extract certificate data + not_valid_before = cert.not_valid_before + not_valid_after = cert.not_valid_after + version_value = f'{cert.version.value + 1} ({hex(cert.version.value)})' + signature_alg_value = cert.signature_algorithm_oid._name # pylint: disable=W0212 + not_before = str(not_valid_before) + not_after = str(not_valid_after) + public_key = cert.public_key() + signed_by = 'None' + if isinstance(public_key, rsa.RSAPublicKey): + public_key_type = "RSA" + elif isinstance(public_key, dsa.DSAPublicKey): + public_key_type = "DSA" + elif isinstance(public_key, ec.EllipticCurvePublicKey): + public_key_type = "EC" + else: + public_key_type = "Unknown" + # Calculate certificate length + cert_length = len(cert.public_bytes(encoding=serialization.Encoding.DER)) + # Generate the Certificate table + cert_table = (f'| Property | Value |\n' + f'|---|---|\n' + f"| {'Version':<17} | {version_value:^25} |\n" + f"| {'Signature Alg.':<17} | {signature_alg_value:^25} |\n" + f"| {'Validity from':<17} | {not_before:^25} |\n" + f"| {'Valid to':<17} | {not_after:^25} |") - # Generate the Subject table - subj_table = ('| Distinguished Name | Value |\n' - '|---|---|') - for val in cert.subject.rdns: - dn = val.rfc4514_string().split('=') - subj_table += f'\n| {dn[0]} | {dn[1]}' + # Generate the Subject table + subj_table = ('| Distinguished Name | Value |\n' + '|---|---|') + for val in cert.subject.rdns: + dn = val.rfc4514_string().split('=') + subj_table += f'\n| {dn[0]} | {dn[1]}' - # Generate the Issuer table - iss_table = ('| Distinguished Name | Value |\n' - '|---|---|') - for val in cert.issuer.rdns: - dn = val.rfc4514_string().split('=') - iss_table += f'\n| {dn[0]} | {dn[1]}' - if 'CN' in dn[0]: - signed_by = dn[1] - - ext_table = None - if cert.extensions: - ext_table = ('| Extension | Value |\n' + # Generate the Issuer table + iss_table = ('| Distinguished Name | Value |\n' '|---|---|') - for extension in cert.extensions: - for extension_value in extension.value: - ext_table += f'\n| {extension.oid._name} | {extension_value.value}' # pylint: disable=W0212 - cert_table = f'### Certificate\n{cert_table}' - cert_table += f'\n\n### Subject\n{subj_table}' - cert_table += f'\n\n### Issuer\n{iss_table}' - if ext_table is not None: - cert_table += f'\n\n### Extensions\n{ext_table}' - cert_tables.append(cert_table) - summary_table_row = (f'''| {cert_num+1: ^5} ''' - f'''| {not_after: ^25} ''' - f'''| {cert_length: ^8} ''' - f'''| {public_key_type: ^6} ''' - f'''| {port: ^10} ''' - f'''| {signed_by: ^11} |''') - summary_table+=f'\n{summary_table_row}' + for val in cert.issuer.rdns: + dn = val.rfc4514_string().split('=') + iss_table += f'\n| {dn[0]} | {dn[1]}' + if 'CN' in dn[0]: + signed_by = dn[1] - markdown_template = '# TLS Module\n' + '\n'.join( - '\n' + tables for tables in cert_tables) + ext_table = None + if cert.extensions: + ext_table = ('| Extension | Value |\n' + '|---|---|') + for extension in cert.extensions: + for extension_value in extension.value: + ext_table += f'\n| {extension.oid._name} | {extension_value.value}' # pylint: disable=W0212 + cert_table = f'### Certificate\n{cert_table}' + cert_table += f'\n\n### Subject\n{subj_table}' + cert_table += f'\n\n### Issuer\n{iss_table}' + if ext_table is not None: + cert_table += f'\n\n### Extensions\n{ext_table}' + cert_tables.append(cert_table) + summary_table_row = (f'''| {cert_num+1: ^5} ''' + f'''| {not_after: ^25} ''' + f'''| {cert_length: ^8} ''' + f'''| {public_key_type: ^6} ''' + f'''| {port: ^10} ''' + f'''| {signed_by: ^11} |''') + summary_table+=f'\n{summary_table_row}' - summary = f'## Summary\n\n{summary_table}' + markdown_template = '# TLS Module\n' + '\n'.join( + '\n' + tables for tables in cert_tables) + # summary = f'## Summary\n\n{summary_table}' + # markdown_template += f'\n\n{summary}' + else: + markdown_template = (f'''# TLS Module\n''' + f'''\n- No device certificates detected\n''') + + summary = f'## Summary\n\n{summary_table}' markdown_template += f'\n\n{summary}' LOGGER.debug('Markdown Report:\n' + markdown_template) diff --git a/testing/unit/tls/reports/tls_report_no_cert_local.md b/testing/unit/tls/reports/tls_report_no_cert_local.md new file mode 100644 index 000000000..6de5bb88a --- /dev/null +++ b/testing/unit/tls/reports/tls_report_no_cert_local.md @@ -0,0 +1,9 @@ +# TLS Module + +- No device certificates detected + + +## Summary + +| # | Expiry | Length | Type | Port No. | Signed by | +|-------|---------------------------|----------|--------|------------|-------------| \ No newline at end of file diff --git a/testing/unit/tls/tls_module_test.py b/testing/unit/tls/tls_module_test.py index 2212d7048..86870e46a 100644 --- a/testing/unit/tls/tls_module_test.py +++ b/testing/unit/tls/tls_module_test.py @@ -33,6 +33,7 @@ LOCAL_REPORT = os.path.join(REPORTS_DIR,'tls_report_local.md') LOCAL_REPORT_EXT = os.path.join(REPORTS_DIR,'tls_report_ext_local.md') +LOCAL_REPORT_NO_CERT = os.path.join(REPORTS_DIR,'tls_report_no_cert_local.md') CONF_FILE = 'modules/test/' + MODULE + '/conf/module_config.json' TLS_UTIL = None @@ -330,12 +331,25 @@ def tls_module_report_ext_test(self): tls_capture_file=pcap_file) report_out_path = tls.generate_module_report() + def tls_module_report_no_cert_test(self): + print('\ntls_module_report_no_cert_test') + os.environ['DEVICE_MAC'] = '' + pcap_file = os.path.join(CAPTURES_DIR,'tls_ext.pcap') + tls = TLSModule(module=MODULE, + log_dir=OUTPUT_DIR, + conf_file=CONF_FILE, + results_dir=OUTPUT_DIR, + startup_capture_file=pcap_file, + monitor_capture_file=pcap_file, + tls_capture_file=pcap_file) + report_out_path = tls.generate_module_report() + # Read the generated report with open(report_out_path, 'r', encoding='utf-8') as file: report_out = file.read() # Read the local good report - with open(LOCAL_REPORT_EXT, 'r', encoding='utf-8') as file: + with open(LOCAL_REPORT_NO_CERT, 'r', encoding='utf-8') as file: report_local = file.read() self.assertEqual(report_out, report_local) @@ -455,6 +469,7 @@ def get_interface_ip(self, interface_name): # Test various report module outputs suite.addTest(TLSModuleTest('tls_module_report_test')) suite.addTest(TLSModuleTest('tls_module_report_ext_test')) + suite.addTest(TLSModuleTest('tls_module_report_no_cert_test')) runner = unittest.TextTestRunner() runner.run(suite) From 26071f2e70fc2cf0ef49369668bf2e2854932aaa Mon Sep 17 00:00:00 2001 From: jhughesbiot Date: Wed, 13 Mar 2024 14:06:45 -0600 Subject: [PATCH 4/4] Additional formatting for tls report header --- framework/python/src/common/testreport.py | 13 +++++++++++++ testing/unit/report/report_test.py | 1 + testing/unit/run_tests.sh | 22 +++++++++++----------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/framework/python/src/common/testreport.py b/framework/python/src/common/testreport.py index 8c24fe240..c9bde77f7 100644 --- a/framework/python/src/common/testreport.py +++ b/framework/python/src/common/testreport.py @@ -239,6 +239,8 @@ def generate_module_pages(self, json_data, module_reports): content_size += 40 + header_padding elif '' in line: content_size += 39 elif '
  • ' in line: @@ -310,6 +312,7 @@ def generate_module_reports(self, json_data): content = content.replace('', '
    ') content = content.replace('

    ', '

    ') content = content.replace('

    ', '

    ') + content = content.replace('

    ', '

    ') content = self.generate_module_pages(json_data=json_data, module_reports=content) @@ -797,6 +800,16 @@ def generate_css(self): font-weight: bold; } + .markdown-header-h3{ + margin-left:20px; + margin-top:20px; + margin-bottom:24px; + margin-right:0px; + + font-size: 1.17em; + font-weight: bold; + } + .module-page-content{ /*Page height minus header(93px), footer(30px), and a 20px bottom padding.*/ diff --git a/testing/unit/report/report_test.py b/testing/unit/report/report_test.py index 4a46b81f7..b8bdcfba8 100644 --- a/testing/unit/report/report_test.py +++ b/testing/unit/report/report_test.py @@ -44,6 +44,7 @@ def report_test(self): # Load all module markdown reports reports_md = [] + reports_md.append(self.get_module_md_report('tls')) reports_md.append(self.get_module_md_report('dns')) reports_md.append(self.get_module_md_report('nmap')) reports_md.append(self.get_module_md_report('ntp')) diff --git a/testing/unit/run_tests.sh b/testing/unit/run_tests.sh index d7d8700c1..fe186c8db 100644 --- a/testing/unit/run_tests.sh +++ b/testing/unit/run_tests.sh @@ -34,23 +34,23 @@ PYTHONPATH="$PYTHONPATH:$PWD/modules/test/ntp/python/src" # Set the python path with all sources export PYTHONPATH -# # Run the DHCP Unit tests -# python3 -u $PWD/modules/network/dhcp-1/python/src/grpc_server/dhcp_config_test.py -# python3 -u $PWD/modules/network/dhcp-2/python/src/grpc_server/dhcp_config_test.py +# Run the DHCP Unit tests +python3 -u $PWD/modules/network/dhcp-1/python/src/grpc_server/dhcp_config_test.py +python3 -u $PWD/modules/network/dhcp-2/python/src/grpc_server/dhcp_config_test.py # Run the TLS Module Unit Tests python3 -u $PWD/testing/unit/tls/tls_module_test.py -# # Run the DNS Module Unit Tests -# python3 -u $PWD/testing/unit/dns/dns_module_test.py +# Run the DNS Module Unit Tests +python3 -u $PWD/testing/unit/dns/dns_module_test.py -# # Run the NMAP Module Unit Tests -# python3 -u $PWD/testing/unit/nmap/nmap_module_test.py +# Run the NMAP Module Unit Tests +python3 -u $PWD/testing/unit/nmap/nmap_module_test.py -# # Run the NTP Module Unit Tests -# python3 -u $PWD/testing/unit/ntp/ntp_module_test.py +# Run the NTP Module Unit Tests +python3 -u $PWD/testing/unit/ntp/ntp_module_test.py -# # # Run the Report Unit Tests -# python3 -u $PWD/testing/unit/report/report_test.py +# # Run the Report Unit Tests +python3 -u $PWD/testing/unit/report/report_test.py popd >/dev/null 2>&1 \ No newline at end of file