def test_basic_certificate_validator_tls_expired(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] validator = CertificateValidator(cert, other_certs) with self.assertRaisesRegexp(PathValidationError, 'expired'): validator.validate_tls('codexns.io')
def test_basic_certificate_validator_tls_expired(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] validator = CertificateValidator(cert, other_certs) with self.assertRaisesRegexp(PathValidationError, 'expired'): validator.validate_tls('codexns.io')
def test_basic_certificate_validator_tls_invalid_hostname(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] moment = datetime(2015, 1, 1, 0, 0, 0, tzinfo=timezone.utc) context = ValidationContext(moment=moment) validator = CertificateValidator(cert, other_certs, context) with self.assertRaisesRegexp(PathValidationError, 'not valid'): validator.validate_tls('google.com')
def test_basic_certificate_validator_tls_invalid_hostname(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] moment = datetime(2015, 1, 1, 0, 0, 0, tzinfo=timezone.utc) context = ValidationContext(moment=moment) validator = CertificateValidator(cert, other_certs, context) with self.assertRaisesRegexp(PathValidationError, 'not valid'): validator.validate_tls('google.com')
def test_basic_certificate_validator_tls_invalid_hostname(self): cert = self._load_cert_object('mozilla.org.crt') other_certs = [self._load_cert_object('digicert-sha2-secure-server-ca.crt')] moment = datetime(2019, 1, 1, 0, 0, 0, tzinfo=timezone.utc) context = ValidationContext(moment=moment) validator = CertificateValidator(cert, other_certs, context) with self.assertRaisesRegex(PathValidationError, 'not valid'): validator.validate_tls('google.com')
def test_basic_certificate_validator_tls_whitelist(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] context = ValidationContext(whitelisted_certs=[cert.sha1_fingerprint]) validator = CertificateValidator(cert, other_certs, context) # If whitelist does not work, this will raise exception for expiration validator.validate_tls('codexns.io') # If whitelist does not work, this will raise exception for hostname validator.validate_tls('google.com') # If whitelist does not work, this will raise exception for key usage validator.validate_usage(set(['crl_sign']))
def test_basic_certificate_validator_tls_whitelist(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] context = ValidationContext(whitelisted_certs=[cert.sha1_fingerprint]) validator = CertificateValidator(cert, other_certs, context) # If whitelist does not work, this will raise exception for expiration validator.validate_tls('codexns.io') # If whitelist does not work, this will raise exception for hostname validator.validate_tls('google.com') # If whitelist does not work, this will raise exception for key usage validator.validate_usage(set(['crl_sign']))
def test_basic_certificate_validator_tls(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] moment = datetime(2015, 1, 1, 0, 0, 0, tzinfo=timezone.utc) context = ValidationContext(moment=moment) validator = CertificateValidator(cert, other_certs, context) path = validator.validate_tls('codexns.io') self.assertEqual(3, len(path))
def test_basic_certificate_validator_tls(self): cert = self._load_cert_object('codex.crt') other_certs = [self._load_cert_object('GeoTrust_EV_SSL_CA_-_G4.crt')] moment = datetime(2015, 1, 1, 0, 0, 0, tzinfo=timezone.utc) context = ValidationContext(moment=moment) validator = CertificateValidator(cert, other_certs, context) path = validator.validate_tls('codexns.io') self.assertEqual(3, len(path))
def test_basic_certificate_validator_tls_whitelist(self): cert = self._load_cert_object('mozilla.org.crt') other_certs = [self._load_cert_object('digicert-sha2-secure-server-ca.crt')] moment = datetime(2020, 1, 1, 0, 0, 0, tzinfo=timezone.utc) context = ValidationContext( whitelisted_certs=[cert.sha1_fingerprint], moment=moment ) validator = CertificateValidator(cert, other_certs, context) # If whitelist does not work, this will raise exception for expiration validator.validate_tls('www.mozilla.org') # If whitelist does not work, this will raise exception for hostname validator.validate_tls('google.com') # If whitelist does not work, this will raise exception for key usage validator.validate_usage(set(['crl_sign']))
def test_basic_certificate_validator_tls(self): cert = self._load_cert_object('mozilla.org.crt') other_certs = [self._load_cert_object('digicert-sha2-secure-server-ca.crt')] moment = datetime(2019, 1, 1, 0, 0, 0, tzinfo=timezone.utc) context = ValidationContext(moment=moment) validator = CertificateValidator(cert, other_certs, context) path = validator.validate_tls('www.mozilla.org') self.assertEqual(3, len(path))
def _validate_chain_certvalidator(self, tlslite_connection): """Validate server certificate chain using 3rd party certvalidator library which uses oscrypt/libcrypto Note: oscrypt uses ctypes find_library() which does not work in certain distributions such as alpine. (e.g. see https://github.com/docker-library/python/issues/111) On such systems, users will have to rely on other server cert validation approaches such as using openssl or turning it off completely. """ try: from certvalidator import CertificateValidator from certvalidator import ValidationContext from asn1crypto import x509, pem # validate server certificate chain session = tlslite_connection.sock.session assert type(session.serverCertChain.x509List) == list # get the end-entity cert file_bytes = session.serverCertChain.x509List[0].bytes end_entity_cert = x509.Certificate.load(str(file_bytes)) def cert_files_exist(path, file_names): file_names = [os.path.join(path, f) for f in file_names] for f in file_names: if not os.path.isfile(f): return False return True def get_cert_bytes(cert_dir, file_names): file_names = [os.path.join(cert_dir, f) for f in file_names] result = [] for fname in file_names: arr = open(fname, "rb").read() cert_bytes = pem.unarmor(arr)[2] result.append(cert_bytes) return result intermediate_cert_names = [ "comodo_ca_intermediate.pem", "sectigo_ca_intermediate.pem", ] extra_trust_names = [ "scalyr_agent_ca_root.pem", "addtrust_external_ca_root.pem", ] # Determine the directory containing the certs. # First check the directory containing the _ca_file # but if we don't find the intermediate/extra certs there # then look in the relative `certs` directory. The latter # will typically be required if running directly from source all_cert_names = intermediate_cert_names + extra_trust_names cert_dir = os.path.dirname(self._ca_file) if not cert_files_exist(cert_dir, all_cert_names): path = os.path.dirname(os.path.abspath(__file__)) path = os.path.abspath(path + "../../certs") if cert_files_exist(path, all_cert_names): cert_dir = path trust_roots = None intermediate_certs = get_cert_bytes(cert_dir, intermediate_cert_names) extra_trust_roots = get_cert_bytes(cert_dir, extra_trust_names) if trust_roots: context = ValidationContext( trust_roots=trust_roots, extra_trust_roots=extra_trust_roots, other_certs=intermediate_certs, # whitelisted_certs=[end_entity_cert.sha1_fingerprint], ) else: context = ValidationContext( extra_trust_roots=extra_trust_roots, other_certs=intermediate_certs, # whitelisted_certs=[end_entity_cert.sha1_fingerprint], ) validator = CertificateValidator( end_entity_cert, validation_context=context ) validator.validate_tls(six.text_type(self._host)) log.info( "Scalyr server cert chain successfully validated via certvalidator library" ) except Exception as ce: log.exception("Error validating server certificate chain: %s" % ce) raise
def run(): """ Runs through TLS hosts in the Alexa top 1000 to test TLS functionality :return: A bool - if the test succeeded without any socket errors """ task_start = time.time() success = 0 tls_errors = 0 socket_errors = 0 mismatch_info = [] context = ValidationContext(allow_fetching=True) with open(os.path.join(fixtures_dir, 'alexa_top_1000.csv'), 'rb') as f: for line in f: domain = line.decode('utf-8').rstrip() os_result = None cv_result = None os_message = None cv_message = None try: os_start = time.time() con = tls.TLSSocket(domain, 443, timeout=3) con.close() success += 1 os_result = 'OK' os_message = 'Success' _color('green', 'OK', domain, os_start) except (TLSVerificationError) as e: tls_errors += 1 os_result = 'TLS' os_message = str_cls(e) _color('yellow', 'TLS', domain, os_start, str_cls(e)) except (socket.error) as e: socket_errors += 1 os_result = 'SOCK' os_message = str_cls(e) _color('red', 'SOCK', domain, os_start, str_cls(e)) try: cv_start = time.time() session = tls.TLSSession(manual_validation=True) con = tls.TLSSocket(domain, 443, timeout=3, session=session) validator = CertificateValidator(con.certificate, con.intermediates, context) validator.validate_tls(domain) con.close() success += 1 cv_result = 'OK' cv_message = 'Success' _color('green', 'OK', domain, cv_start) except (PathValidationError, PathBuildingError) as e: tls_errors += 1 cv_result = 'TLS' cv_message = str_cls(e) _color('yellow', 'TLS', domain, cv_start, str_cls(e)) except (socket.error) as e: socket_errors += 1 cv_result = 'SOCK' cv_message = str_cls(e) _color('red', 'SOCK', domain, cv_start, str_cls(e)) if os_result != cv_result: mismatch_info.append( [domain, os_result, os_message, cv_result, cv_message]) total_time = time.time() - task_start total_domains = success + tls_errors + socket_errors stats = [] if success > 0: stats.append('%d [%sOK%s]' % (success, Fore.GREEN, Fore.RESET)) if tls_errors > 0: stats.append('%d [%sTLS%s]' % (tls_errors, Fore.YELLOW, Fore.RESET)) if socket_errors > 0: stats.append('%d [%sSOCK%s]' % (socket_errors, Fore.RED, Fore.RESET)) print('') print('Checked %d domains in %.3f seconds - %s' % (total_domains, total_time, ' '.join(stats))) if mismatch_info: print('') for info in mismatch_info: os_result = '[%s] %s' % (info[1], info[2]) cv_result = '[%s] %s' % (info[3], info[4]) _color( 'red', 'DIFF', 'oscrypto and certvalidator results for %s are different' % info[0], None, os_result, cv_result) return socket_errors == 0
def run(): """ Runs through TLS hosts in the Alexa top 1000 to test TLS functionality :return: A bool - if the test succeeded without any socket errors """ task_start = time.time() success = 0 tls_errors = 0 socket_errors = 0 mismatch_info = [] context = ValidationContext(allow_fetching=True) with open(os.path.join(fixtures_dir, 'alexa_top_1000.csv'), 'rb') as f: for line in f: domain = line.decode('utf-8').rstrip() os_result = None cv_result = None os_message = None cv_message = None try: os_start = time.time() con = tls.TLSSocket(domain, 443, timeout=3) con.close() success += 1 os_result = 'OK' os_message = 'Success' _color('green', 'OK', domain, os_start) except (TLSVerificationError) as e: tls_errors += 1 os_result = 'TLS' os_message = str_cls(e) _color('yellow', 'TLS', domain, os_start, str_cls(e)) except (socket.error) as e: socket_errors += 1 os_result = 'SOCK' os_message = str_cls(e) _color('red', 'SOCK', domain, os_start, str_cls(e)) try: cv_start = time.time() session = tls.TLSSession(manual_validation=True) con = tls.TLSSocket(domain, 443, timeout=3, session=session) validator = CertificateValidator(con.certificate, con.intermediates, context) validator.validate_tls(domain) con.close() success += 1 cv_result = 'OK' cv_message = 'Success' _color('green', 'OK', domain, cv_start) except (PathValidationError, PathBuildingError) as e: tls_errors += 1 cv_result = 'TLS' cv_message = str_cls(e) _color('yellow', 'TLS', domain, cv_start, str_cls(e)) except (socket.error) as e: socket_errors += 1 cv_result = 'SOCK' cv_message = str_cls(e) _color('red', 'SOCK', domain, cv_start, str_cls(e)) if os_result != cv_result: mismatch_info.append([ domain, os_result, os_message, cv_result, cv_message ]) total_time = time.time() - task_start total_domains = success + tls_errors + socket_errors stats = [] if success > 0: stats.append('%d [%sOK%s]' % (success, Fore.GREEN, Fore.RESET)) if tls_errors > 0: stats.append('%d [%sTLS%s]' % (tls_errors, Fore.YELLOW, Fore.RESET)) if socket_errors > 0: stats.append('%d [%sSOCK%s]' % (socket_errors, Fore.RED, Fore.RESET)) print('') print('Checked %d domains in %.3f seconds - %s' % (total_domains, total_time, ' '.join(stats))) if mismatch_info: print('') for info in mismatch_info: os_result = '[%s] %s' % (info[1], info[2]) cv_result = '[%s] %s' % (info[3], info[4]) _color( 'red', 'DIFF', 'oscrypto and certvalidator results for %s are different' % info[0], None, os_result, cv_result ) return socket_errors == 0
def _verify_certificates(self, hostname): validator = CertificateValidator(self.certificates[0], self.certificates[1:]) validator.validate_tls(hostname)