def test_1000_sans_chain(self): # Ensure SSLyze can process a leaf cert with 1000 SANs server_test = ServerConnectivityTester(hostname='1000-sans.badssl.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin.process_task(server_info, CertificateInfoScanCommand())
def run_certificate_command(self, server_info, synchronous_scanner): certificate_chain = {} command = CertificateInfoScanCommand() scan_result = synchronous_scanner.run_scan_command( server_info, command) i = 0 for certificate in scan_result.received_certificate_chain: certificate_chain[i] = { "pem": certificate.public_bytes(Encoding.PEM).decode("ascii") } if (i > 0): certificate_chain[i]['is_CA'] = True else: certificate_chain[i]['is_CA'] = False i += 1 trusted_chain = False if (scan_result.verified_certificate_chain): trusted_chain = True result_by_trusted_store = {} for store_result in scan_result.path_validation_result_list: store_name = store_result.trust_store.name + store_result.trust_store.version result_by_trusted_store[ store_name] = store_result.was_validation_successful return { "certificate_chain": certificate_chain, "is_chain_trusted": trusted_chain, "oscp_response": scan_result.ocsp_response_is_trusted, "result_by_trusted_store": result_by_trusted_store }
def test_succeeds_when_client_auth_failed(self): # Given a server that requires client authentication try: with VulnerableOpenSslServer( client_auth_config= ClientAuthenticationServerConfigurationEnum.REQUIRED ) as server: # And the client does NOT provide a client certificate server_test = ServerConnectivityTester( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = server_test.perform() # CertificateInfoPlugin works even when a client cert was not supplied plugin = CertificateInfoPlugin() plugin_result = plugin.process_task( server_info, CertificateInfoScanCommand()) except NotOnLinux64Error: logging.warning('WARNING: Not on Linux - skipping test') return self.assertTrue(plugin_result.certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_ca_file_bad_file(self): server_test = ServerConnectivityTester(hostname='www.hotmail.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() with self.assertRaises(ValueError): plugin.process_task(server_info, CertificateInfoScanCommand(ca_file='doesntexist'))
def test_invalid_chain(self): server_test = ServerConnectivityTester( hostname='self-signed.badssl.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertIsNone(plugin_result.ocsp_response) self.assertEqual(len(plugin_result.certificate_chain), 1) self.assertEqual(len(plugin_result.path_validation_result_list), 5) for path_validation_result in plugin_result.path_validation_result_list: self.assertFalse(path_validation_result.is_certificate_trusted) self.assertEqual(plugin_result.certificate_included_scts_count, 0) self.assertEqual(len(plugin_result.path_validation_error_list), 0) self.assertEqual(plugin_result.certificate_matches_hostname, True) self.assertTrue(plugin_result.is_certificate_chain_order_valid) self.assertIsNone(plugin_result.has_anchor_in_certificate_chain) self.assertIsNone(plugin_result.has_sha1_in_certificate_chain) self.assertFalse(plugin_result.verified_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_invalid_chain(self): server_test = ServerConnectivityTester(hostname='self-signed.badssl.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) assert plugin_result.ocsp_response is None assert len(plugin_result.received_certificate_chain) == 1 assert len(plugin_result.path_validation_result_list) >= 5 for path_validation_result in plugin_result.path_validation_result_list: assert not path_validation_result.was_validation_successful assert plugin_result.leaf_certificate_signed_certificate_timestamps_count == 0 assert len(plugin_result.path_validation_error_list) == 0 assert plugin_result.leaf_certificate_subject_matches_hostname assert plugin_result.received_chain_has_valid_order assert plugin_result.received_chain_contains_anchor_certificate is None assert plugin_result.verified_chain_has_sha1_signature is None assert not plugin_result.verified_certificate_chain assert plugin_result.as_text() assert plugin_result.as_xml() # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue assert pickle.dumps(plugin_result)
def test_ca_file_bad_file(self): server_info = ServerConnectivityInfo(hostname=u'www.hotmail.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() with self.assertRaises(ValueError): plugin.process_task(server_info, CertificateInfoScanCommand(ca_file=u'doesntexist'))
def test_valid_chain_with_ev_cert(self): server_test = ServerConnectivityTester(hostname='www.comodo.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) assert plugin_result.leaf_certificate_is_ev assert len(plugin_result.received_certificate_chain) >= 3 assert len(plugin_result.verified_certificate_chain) >= 3 assert not plugin_result.received_chain_contains_anchor_certificate assert len(plugin_result.path_validation_result_list) == 5 for path_validation_result in plugin_result.path_validation_result_list: assert path_validation_result.was_validation_successful assert len(plugin_result.path_validation_error_list) == 0 assert plugin_result.leaf_certificate_subject_matches_hostname assert plugin_result.received_chain_has_valid_order assert plugin_result.as_text() assert plugin_result.as_xml() # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue assert pickle.dumps(plugin_result)
def test_valid_chain(self): server_info = ServerConnectivityInfo(hostname=u'www.hotmail.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.ocsp_response) self.assertTrue(plugin_result.is_ocsp_response_trusted) self.assertTrue(plugin_result.is_leaf_certificate_ev) self.assertEquals(len(plugin_result.certificate_chain), 2) self.assertEquals(len(plugin_result.verified_certificate_chain), 3) self.assertFalse(plugin_result.has_anchor_in_certificate_chain) self.assertEquals(len(plugin_result.path_validation_result_list), 5) for path_validation_result in plugin_result.path_validation_result_list: self.assertTrue(path_validation_result.is_certificate_trusted) self.assertEquals(len(plugin_result.path_validation_error_list), 0) self.assertEquals(plugin_result.hostname_validation_result, HostnameValidationResultEnum.NAME_MATCHES_SAN) self.assertTrue(plugin_result.is_certificate_chain_order_valid) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_valid_chain_with_ocsp_stapling(self): server_info = ServerConnectivityInfo(hostname='login.live.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.ocsp_response) self.assertTrue(plugin_result.is_ocsp_response_trusted) self.assertEqual(len(plugin_result.certificate_chain), 2) self.assertEqual(len(plugin_result.verified_certificate_chain), 3) self.assertFalse(plugin_result.has_anchor_in_certificate_chain) self.assertEqual(len(plugin_result.path_validation_result_list), 5) for path_validation_result in plugin_result.path_validation_result_list: self.assertTrue(path_validation_result.is_certificate_trusted) self.assertEqual(len(plugin_result.path_validation_error_list), 0) self.assertEqual(plugin_result.certificate_matches_hostname, True) self.assertTrue(plugin_result.is_certificate_chain_order_valid) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def scan_serial(scanner, server_info, data, options): logging.debug("\tRunning scans in serial.") logging.debug("\t\tSSLv2 scan.") sslv2 = scanner.run_scan_command(server_info, Sslv20ScanCommand()) logging.debug("\t\tSSLv3 scan.") sslv3 = scanner.run_scan_command(server_info, Sslv30ScanCommand()) logging.debug("\t\tTLSv1.0 scan.") tlsv1 = scanner.run_scan_command(server_info, Tlsv10ScanCommand()) logging.debug("\t\tTLSv1.1 scan.") tlsv1_1 = scanner.run_scan_command(server_info, Tlsv11ScanCommand()) logging.debug("\t\tTLSv1.2 scan.") tlsv1_2 = scanner.run_scan_command(server_info, Tlsv12ScanCommand()) logging.debug("\t\tTLSv1.3 scan.") tlsv1_3 = scanner.run_scan_command(server_info, Tlsv13ScanCommand()) certs = None if options.get("sslyze_certs", True) is True: try: logging.debug("\t\tCertificate information scan.") certs = scanner.run_scan_command(server_info, CertificateInfoScanCommand()) # Let generic exceptions bubble up. except idna.core.InvalidCodepoint: logging.warn(utils.format_last_exception()) data['errors'].append("Invalid certificate/OCSP for this domain.") certs = None else: certs = None logging.debug("\tDone scanning.") return sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2, tlsv1_3, certs
def test_valid_chain_with_ev_cert(self): server_test = ServerConnectivityTester(hostname='www.comodo.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.is_leaf_certificate_ev) self.assertEqual(len(plugin_result.certificate_chain), 4) self.assertEqual(len(plugin_result.verified_certificate_chain), 3) self.assertFalse(plugin_result.has_anchor_in_certificate_chain) self.assertEqual(len(plugin_result.path_validation_result_list), 5) for path_validation_result in plugin_result.path_validation_result_list: self.assertTrue(path_validation_result.is_certificate_trusted) self.assertEqual(len(plugin_result.path_validation_error_list), 0) self.assertEqual(plugin_result.certificate_matches_hostname, True) self.assertTrue(plugin_result.is_certificate_chain_order_valid) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def attack(results, host_name): print("Running 10.16 attack.py host name: {}".format(host_name)) report = {} try: server_tester = ServerConnectivityTester( hostname=host_name, port=443, tls_wrapped_protocol=TlsWrappedProtocolEnum.HTTPS) server_info = server_tester.perform() except ServerConnectivityError as e: results.append(AttackResult('10.16', host_name, False, e)) return plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) # Valid host name certificate_matches_hostname = plugin_result.certificate_matches_hostname # Chain order is valid is_certificate_chain_order_valid = plugin_result.is_certificate_chain_order_valid # All certificates are trusted certificates_are_trusted = True for path_validation_result in plugin_result.path_validation_result_list: if not path_validation_result.is_certificate_trusted: certificates_are_trusted = False result = certificate_matches_hostname and is_certificate_chain_order_valid and certificates_are_trusted details = '' if not certificate_matches_hostname: details += ' Certificate does not match hostname' if not is_certificate_chain_order_valid: details += ' Certificate chain order is invalid' if not certificates_are_trusted: details += ' Certificates are not trusted.' attackResult = None if not result: attackResult = AttackResult('hostname', host_name, result, details) else: attackResult = AttackResult( 'hostname', host_name, result, 'TLS certificates match hostname, are trusted and the chain order is valid' ) results.append(attackResult) #results = [] #attack(results, 'https://www.google.co.uk')
def test_valid_chain_print_full_certificate(self): server_info = ServerConnectivityInfo(hostname=u'www.hotmail.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand(print_full_certificate=True)) # The only difference with the previous test is the text output self.assertTrue(plugin_result.as_text())
def _check_certificate( self) -> Tuple[List[str], List[str], List[str], str]: result = self._scan(CertificateInfoScanCommand( ca_file=self.ca_file)) # type: CertificateInfoScanResult validation_errors = [] certificate = result.received_certificate_chain[0] ( profile_errors, cert_warnings, pub_key_type, ) = self._check_certificate_properties(certificate, result.ocsp_response_is_trusted) for r in result.path_validation_result_list: if not r.was_validation_successful: validation_errors.append( f"validation not successful: {r.verify_string} (trust store {r.trust_store.name})" ) if result.path_validation_error_list: validation_errors = (fail.error_message for fail in result.path_validation_error_list) validation_errors.append( f'Validation failed: {", ".join(validation_errors)}') if not result.leaf_certificate_subject_matches_hostname: validation_errors.append( f"Leaf certificate subject does not match hostname!") if not result.received_chain_has_valid_order: validation_errors.append(f"Certificate chain has wrong order.") if result.verified_chain_has_sha1_signature: validation_errors.append(f"SHA1 signature found in chain.") if result.verified_chain_has_legacy_symantec_anchor: validation_errors.append( f"Symantec legacy certificate found in chain.") sct_count = result.leaf_certificate_signed_certificate_timestamps_count if sct_count < 2 and certificate.not_valid_before >= self.SCT_REQUIRED_DATE: validation_errors.append( f"Certificates issued on or after 2018-04-01 need certificate transparency, " f"i.e., two signed SCTs in certificate. Leaf certificate only has {sct_count}." ) if len(validation_errors) == 0: log.debug(f"Certificate is ok") else: log.debug(f"Error validating certificate") for error in validation_errors: log.debug(f" → {error}") return validation_errors, profile_errors, cert_warnings, pub_key_type
def scan_serial(scanner, server_info, data, options): errors = 0 def run_scan(scan_type, command, errors): if (errors >= 2): return None, errors logging.debug("\t\t{} scan.".format(scan_type)) result = None try: result = scanner.run_scan_command(server_info, command) except Exception as err: logging.warning("{}: Error during {} scan.".format( server_info.hostname, scan_type)) logging.debug("{}: Exception during {} scan: {}".format( server_info.hostname, scan_type, err)) errors = errors + 1 return result, errors logging.debug("\tRunning scans in serial.") sslv2, errors = run_scan("SSLv2", Sslv20ScanCommand(), errors) sslv3, errors = run_scan("SSLv3", Sslv30ScanCommand(), errors) tlsv1, errors = run_scan("TLSv1.0", Tlsv10ScanCommand(), errors) tlsv1_1, errors = run_scan("TLSv1.1", Tlsv11ScanCommand(), errors) tlsv1_2, errors = run_scan("TLSv1.2", Tlsv12ScanCommand(), errors) tlsv1_3, errors = run_scan("TLSv1.3", Tlsv13ScanCommand(), errors) certs = None if errors < 2 and options.get("sslyze_certs", True) is True: try: logging.debug("\t\tCertificate information scan.") certs = scanner.run_scan_command( server_info, CertificateInfoScanCommand(ca_file=CA_FILE)) except idna.core.InvalidCodepoint: logging.warning(utils.format_last_exception()) data['errors'].append("Invalid certificate/OCSP for this domain.") certs = None except Exception as err: logging.warning( "{}: Error during certificate information scan.".format( server_info.hostname)) logging.debug( "{}: Exception during certificate information scan: {}".format( server_info.hostname, err)) else: certs = None reneg = None if options.get("sslyze_reneg", True) is True: reneg, errors = run_scan("Renegotiation", SessionRenegotiationScanCommand(), errors) else: reneg = None logging.debug("\tDone scanning.") return sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2, tlsv1_3, certs, reneg
def test_1000_sans_chain(self): # Ensure SSLyze can process a leaf cert with 1000 SANs server_info = ServerConnectivityInfo(hostname=u'1000-sans.badssl.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) san_list = plugin_result.certificate_chain[0].as_dict[u'extensions'][u'X509v3 Subject Alternative Name'][u'DNS'] self.assertEquals(len(san_list), 1000)
def test_optional_client_authentication(self): server_test = ServerConnectivityTester(hostname='client.badssl.com') server_info = server_test.perform() assert server_info.client_auth_requirement == ClientAuthenticationServerConfigurationEnum.OPTIONAL plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) assert plugin_result.as_text() assert plugin_result.as_xml()
def test_optional_client_authentication(self): server_info = ServerConnectivityInfo(hostname='xnet-eu.intellij.net') server_info.test_connectivity_to_server() self.assertEquals(server_info.client_auth_requirement, ClientAuthenticationServerConfigurationEnum.OPTIONAL) plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_not_trusted_by_mozilla_but_trusted_by_microsoft(self): server_info = ServerConnectivityInfo(hostname=u'webmail.russia.nasa.gov') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEqual(plugin_result.successful_trust_store.name, u'Microsoft') self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_chain_with_anchor(self): server_info = ServerConnectivityInfo(hostname=u'www.verizon.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.has_anchor_in_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_unicode_certificate(self): server_info = ServerConnectivityInfo(hostname=u'www.főgáz.hu') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_sha256_chain(self): server_info = ServerConnectivityInfo(hostname=u'sha256.badssl.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertFalse(plugin_result.has_sha1_in_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_ipv6(self): server_test = ServerConnectivityTester(hostname='www.google.com', ip_address='2607:f8b0:4005:804::2004') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) assert len(plugin_result.received_certificate_chain) >= 1 assert plugin_result.as_text() assert plugin_result.as_xml()
def test_sha1_chain(self): server_test = ServerConnectivityTester(hostname='sha1-intermediate.badssl.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.has_sha1_in_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_international_names(self): server_info = ServerConnectivityInfo(hostname='www.sociétégénérale.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEquals(len(plugin_result.certificate_chain), 3) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_international_names(self): server_test = ServerConnectivityTester(hostname='www.sociétégénérale.com') server_info = server_test.perform() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) assert len(plugin_result.received_certificate_chain) >= 1 assert plugin_result.as_text() assert plugin_result.as_xml()
def test_smtp_custom_port(self): server_info = ServerConnectivityInfo(hostname='smtp.gmail.com', port=587, tls_wrapped_protocol=TlsWrappedProtocolEnum.STARTTLS_SMTP) server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEquals(len(plugin_result.certificate_chain), 3) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_only_trusted_by_custom_ca_file(self): server_info = ServerConnectivityInfo(hostname=u'self-signed.badssl.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() ca_file_path = os.path.join(os.path.dirname(__file__), u'..', u'utils', u'self-signed.badssl.com.pem') plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand(ca_file=ca_file_path)) self.assertEqual(plugin_result.successful_trust_store.name, u'Custom --ca_file') self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_sha1_chain(self): # The test server no longer works return server_info = ServerConnectivityInfo(hostname=u'sha1-2017.badssl.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.has_sha1_in_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())