def create_cert_req(keyType = crypto.TYPE_RSA, bits = 1024, messageDigest = "md5"): """ Create certificate request. Returns: certificate request PEM text, private key PEM text """ # Create certificate request req = crypto.X509Req() # Generate private key pkey = crypto.PKey() pkey.generate_key(keyType, bits) req.set_pubkey(pkey) req.sign(pkey, messageDigest) cert_req_pem = crypto.dump_certificate_request(crypto.FILETYPE_ASN1,req) key_pem = crypto.dump_privatekey(crypto.FILETYPE_PEM,pkey) # Nasty OpenSSL 1.0 Hack # OpenSSL 1.0 changes the headers from "RSA PRIVATE KEY" to "PRIVATE KEY" try: ssl_version = SSL.SSLeay_version(SSL.SSLEAY_VERSION) logger.debug('Using SSL: ' + ssl_version) if ssl_version.startswith("OpenSSL 1"): key_pem = re.sub(r'BEGIN PRIVATE KEY', r'BEGIN RSA PRIVATE KEY', key_pem) key_pem = re.sub(r'END PRIVATE KEY', r'END RSA PRIVATE KEY', key_pem) except Exception, e: logger.warn('Using older version of openSSL without SSLeay_version: %s' + e)
def assertTlsHandshakeFailure(self, client_cert, client_key, ciphers=None, ssl_method=None): """ Checks that the TLS handshake failure by varying the given parameters Args: client_cert: client certificate file in PEM format to use. client_key: associated key file in PEM format to use with the given |client_cert|. ciphers: optional cipher method ssl_method: optional ssl_method """ url = urlparse.urlparse('https://' + self._sas_admin._base_url) client = socket.socket() client.connect((url.hostname, url.port or 443)) logging.debug("OPENSSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION)) logging.debug('TLS handshake: connecting to: %s:%d', url.hostname, url.port or 443) logging.debug('TLS handshake: privatekey_file=%s', client_key) logging.debug('TLS handshake: certificate_file=%s', client_cert) if ssl_method is not None: ctx = SSL.Context(ssl_method) else: ctx = SSL.Context(SSL.TLSv1_2_METHOD) if ciphers is not None: ctx.set_cipher_list(ciphers) else: # cipher 'AES128-GCM-SHA256' will be added by default if cipher arg is passed as None ctx.set_cipher_list(self._sas._tls_config.ciphers[0]) ctx.use_certificate_file(client_cert) ctx.use_privatekey_file(client_key) client_ssl_informations = [] def _InfoCb(conn, where, ok): client_ssl_informations.append(conn.get_state_string()) logging.debug('TLS handshake info: %d|%d %s', where, ok, conn.get_state_string()) return ok ctx.set_info_callback(_InfoCb) client_ssl = SSL.Connection(ctx, client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(url.hostname) try: client_ssl.do_handshake() logging.debug('TLS handshake: succeed') self.fail( msg= "TLS Handshake is success. but Expected:TLS handshake failure") except SSL.Error as e: self.assertEquals(client_ssl.get_peer_finished(), None) finally: client_ssl.close()
def get_environ(self): """Return WSGI environ entries to be merged into each request.""" ssl_environ = { 'wsgi.url_scheme': 'https', 'HTTPS': 'on', 'SSL_VERSION_INTERFACE': '%s %s/%s Python/%s' % ( cheroot_server.HTTPServer.version, OpenSSL.version.__title__, OpenSSL.version.__version__, sys.version, ), 'SSL_VERSION_LIBRARY': SSL.SSLeay_version(SSL.SSLEAY_VERSION, ).decode(), } if self.certificate: # Server certificate attributes with open(self.certificate, 'rb') as cert_file: cert = crypto.load_certificate( crypto.FILETYPE_PEM, cert_file.read(), ) ssl_environ.update({ 'SSL_SERVER_M_VERSION': cert.get_version(), 'SSL_SERVER_M_SERIAL': cert.get_serial_number(), # 'SSL_SERVER_V_START': # Validity of server's certificate (start time), # 'SSL_SERVER_V_END': # Validity of server's certificate (end time), }) for prefix, dn in [ ('I', cert.get_issuer()), ('S', cert.get_subject()), ]: # X509Name objects don't seem to have a way to get the # complete DN string. Use str() and slice it instead, # because str(dn) == "<X509Name object '/C=US/ST=...'>" dnstr = str(dn)[18:-2] wsgikey = 'SSL_SERVER_%s_DN' % prefix ssl_environ[wsgikey] = dnstr # The DN should be of the form: /k1=v1/k2=v2, but we must allow # for any value to contain slashes itself (in a URL). while dnstr: pos = dnstr.rfind('=') dnstr, value = dnstr[:pos], dnstr[pos + 1:] pos = dnstr.rfind('/') dnstr, key = dnstr[:pos], dnstr[pos + 1:] if key and value: wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key) ssl_environ[wsgikey] = value return ssl_environ
def dump_system_info(): mitmproxy_version = version.get_dev_version() data = [ f"Mitmproxy: {mitmproxy_version}", f"Python: {platform.python_version()}", "OpenSSL: {}".format(SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode()), f"Platform: {platform.platform()}", ] return "\n".join(data)
def dump_system_info(): git_describe = 'release version' with utils.chdir( os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))): try: c = ['git', 'describe', '--tags', '--long'] git_describe = subprocess.check_output(c, stderr=subprocess.STDOUT) last_tag, tag_dist, commit = git_describe.decode().strip().rsplit( "-", 2) if last_tag.startswith('v'): # remove the 'v' prefix last_tag = last_tag[1:] if commit.startswith('g'): # remove the 'g' prefix added by recent git versions commit = commit[1:] # build the same version specifier as used for snapshots by rtool git_describe = "{version}dev{tag:04}-0x{commit}".format( version=last_tag, tag=int(tag_dist), commit=commit, ) except: pass bin_indicator = "" # PyInstaller builds indicator, if using precompiled binary if getattr(sys, 'frozen', False): bin_indicator = "Precompiled Binary" data = [ "Mitmproxy version: {} ({}) {}".format(version.VERSION, git_describe, bin_indicator), "Python version: {}".format(platform.python_version()), "Platform: {}".format(platform.platform()), "SSL version: {}".format( SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode()), ] d = platform.linux_distribution() t = "Linux distro: %s %s %s" % d if d[0]: # pragma: no cover data.append(t) d = platform.mac_ver() t = "Mac version: %s %s %s" % d if d[0]: # pragma: no cover data.append(t) d = platform.win32_ver() t = "Windows version: %s %s %s %s" % d if d[0]: # pragma: no cover data.append(t) return "\n".join(data)
def ssl_version(): if SSL: try: return SSL.SSLeay_version(SSL.SSLEAY_VERSION) except AttributeError: try: import ssl return ssl.OPENSSL_VERSION except (ImportError, AttributeError): return 'No OpenSSL installed' else: return None
def dump_system_info(): mitmproxy_version = version.VERSION here = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) try: git_describe = subprocess.check_output( ['git', 'describe', '--tags', '--long'], stderr=subprocess.STDOUT, cwd=here, ) except: pass else: last_tag, tag_dist, commit = git_describe.decode().strip().rsplit( "-", 2) commit = commit.lstrip( "g") # remove the 'g' prefix added by recent git versions tag_dist = int(tag_dist) if tag_dist > 0: tag_dist = "dev{:04}".format(tag_dist) else: tag_dist = "" mitmproxy_version += "{tag_dist} ({commit})".format( tag_dist=tag_dist, commit=commit, ) # PyInstaller builds indicator, if using precompiled binary if getattr(sys, 'frozen', False): bin_indicator = "binary" else: bin_indicator = "" data = [ "Mitmproxy: {} {}".format(mitmproxy_version, bin_indicator), "Python: {}".format(platform.python_version()), "OpenSSL: {}".format( SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode()), "Platform: {}".format(platform.platform()), ] return "\n".join(data)
def dump_system_info(): mitmproxy_version = version.get_version(True, True) mitmproxy_version = re.sub(r"-0x([0-9a-f]+)", r" (commit \1)", mitmproxy_version) # PyInstaller builds indicator, if using precompiled binary if getattr(sys, 'frozen', False): bin_indicator = "binary" else: bin_indicator = "" data = [ "Mitmproxy: {} {}".format(mitmproxy_version, bin_indicator), "Python: {}".format(platform.python_version()), "OpenSSL: {}".format( SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode()), "Platform: {}".format(platform.platform()), ] return "\n".join(data)
def sysinfo(): data = [ "Mitmproxy version: %s" % version.VERSION, "Python version: %s" % platform.python_version(), "Platform: %s" % platform.platform(), "SSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION).decode(), ] d = platform.linux_distribution() t = "Linux distro: %s %s %s" % d if d[0]: # pragma: no-cover data.append(t) d = platform.mac_ver() t = "Mac version: %s %s %s" % d if d[0]: # pragma: no-cover data.append(t) d = platform.win32_ver() t = "Windows version: %s %s %s %s" % d if d[0]: # pragma: no-cover data.append(t) return "\n".join(data)
import six import flextls openssl_enabled = False version_pyopenssl = None version_openssl = None try: import OpenSSL from OpenSSL import SSL version_pyopenssl = OpenSSL.__version__ version_openssl = SSL.SSLeay_version(0) if isinstance(version_openssl, six.binary_type): version_openssl = version_openssl.decode('ascii') except ImportError: OpenSSL = None def convert_version2method(protocol_version): """ Convert internal protocol version ID to OpenSSL method. :param Integer protocol_version: Version ID :return: OpenSSL method or None if not found :rtype: OpenSSL method or None """ if protocol_version == flextls.registry.version.SSLv2: return SSL.SSLv2_METHOD if protocol_version == flextls.registry.version.SSLv3: return SSL.SSLv3_METHOD if protocol_version == flextls.registry.version.TLSv10:
def main(): arguments = docopt(__doc__, version=__version__) if arguments['info']: return info(arguments) # Get the address from the user. server = arguments['<host>'] port = 443 if ':' in server: server, port = server.split(':', 1) port = int(port) threads = arguments['--threads'] if threads is None: threads = 5 else: threads = int(threads) ssl_version = SSL.SSLeay_version(SSL.SSLEAY_VERSION) if not isinstance(ssl_version, str): ssl_version = ssl_version.decode('ascii') print_box = lambda s, **kw: print('| ' + s.ljust(59) + '|', **kw) print("+" + "-" * 60 + "+") print_box("pySSLScan version %s" % (__version__,)) print_box(" OpenSSL version: %s" % (ssl_version,)) print_box(" Threads: : %d" % (threads,)) print_box(" Verbose: : %s" % (bool(arguments['-v']),)) print("+" + "-" * 60 + "+") print('') # Create host structure. host = HostInfo(server, port) # Note that this statement will wait for all executed things to finish. print("Scanning, please wait... ", end='') sys.stdout.flush() with futures.ThreadPoolExecutor(max_workers=threads) as executor: # Validate certificate chain for the server. executor.submit(validate_cert_chain, host) for method in SSL_METHODS: try: supported_ciphers = get_all_ciphers(method) except ValueError: print("Method not supported: %s" % (method,)) continue # Test each individual cipher. for cipher in supported_ciphers: executor.submit(test_single_cipher, host, method, cipher) # Test for the preferred cipher suite for this method. executor.submit(test_preferred_cipher, host, method) print('done!\n') # Print results. for method in SSL_METHODS: print("Ciphers for %s:" % (method,)) print("-" * 20) for cipher in sorted(host.accepted_ciphers_for(method)): print(' ' + cipher_as_str(cipher)) if arguments['-v']: for cipher in sorted(host.rejected_ciphers_for(method)): print(' (rejected) ' + cipher_as_str(cipher)) for cipher in sorted(host.errored_ciphers_for(method)): print(' (errored) ' + cipher_as_str(cipher)) print('') print('Preferred Ciphers:') print('-' * 20) for method in SSL_METHODS: preferred = host.preferred_ciphers.get(method) if preferred is not None: print(" %s: %s" % (method, cipher_as_str(preferred))) else: print(" %s: None" % (method,)) print('') # Lastly, print any problems found print('Problems:') print('-' * 20) if len(list(host.accepted_ciphers_for('SSLv2'))) > 0: print("- Host supports SSLv2") anon_ciphers = [] weak_ciphers = [] for method in SSL_METHODS: for cipher in sorted(host.accepted_ciphers_for(method)): if cipher.bits == 'Anon': anon_ciphers.append(cipher) elif cipher.bits == 'Unknown': # TODO: report? pass elif int(cipher.bits) < 128: weak_ciphers.append(cipher) if len(anon_ciphers) > 0: print('- Host supports anonymous cipher suites') for x in anon_ciphers: print(' - %s' % (x,)) if len(weak_ciphers) > 0: print('- Host supports weak cipher suites') for x in weak_ciphers: print(' - %s' % (x,))
def doTlsHandshake(self, base_url, client_cert, client_key, ciphers, ssl_method): """Reports the success or failure of a TLS handshake. Args: base_url: Target host (defaults to port 443) or host:port. client_cert: Filename of the client certificate file in PEM format. client_key: Filename of the PEM-formatted key to use with |client_cert|. ciphers: List of cipher method strings. ssl_method: OpenSSL.SSL.*_METHOD value to use. Returns: True if the handshake succeeded, or False if it failed. """ url = urlparse.urlparse('https://' + base_url) client = socket.socket() client.connect((url.hostname, url.port or 443)) logging.debug("OPENSSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION)) logging.debug('TLS handshake: connecting to: %s:%d', url.hostname, url.port or 443) logging.debug('TLS handshake: ciphers=%s', ':'.join(ciphers)) logging.debug('TLS handshake: privatekey_file=%s', client_key) logging.debug('TLS handshake: certificate_file=%s', client_cert) logging.debug('TLS handshake: certificate_chain_file=%s', self._sas._tls_config.ca_cert) ctx = SSL.Context(ssl_method) ctx.set_cipher_list(':'.join(ciphers)) ctx.use_certificate_file(client_cert) ctx.use_privatekey_file(client_key) ctx.load_verify_locations(self._sas._tls_config.ca_cert) client_ssl_informations = [] def _InfoCb(conn, where, ok): client_ssl_informations.append(conn.get_state_string()) logging.debug('TLS handshake info: %d|%d %s', where, ok, conn.get_state_string()) return ok ctx.set_info_callback(_InfoCb) # only for potential debugging info... def _VerifyCb(conn, cert, errnum, depth, ok): certsubject = crypto.X509Name(cert.get_subject()) commonname = certsubject.commonName logging.debug('TLS handshake verify: certificate: %s -> %d', commonname, ok) return ok ctx.set_verify(SSL.VERIFY_PEER, _VerifyCb) client_ssl = SSL.Connection(ctx, client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(url.hostname) try: client_ssl.do_handshake() logging.debug('TLS handshake: succeed') handshake_ok = True except SSL.Error as e: logging.debug('TLS handshake: failed:\n%s', '\n'.join(client_ssl_informations)) handshake_ok = False finally: client_ssl.close() self.assertEqual(client_ssl.get_cipher_list(), ciphers) known_ssl_methods = { SSL.TLSv1_1_METHOD: 'TLSv1.1', SSL.TLSv1_2_METHOD: 'TLSv1.2', } self.assertEqual(client_ssl.get_protocol_version_name(), known_ssl_methods[ssl_method]) if handshake_ok: # tricky part: exact logged message depends of the version of openssl... cipher_check_regex = re.compile(r"change.cipher.spec", re.I) finished_check_regex = re.compile( r"negotiation finished|finish_client_handshake", re.I) def findIndexMatching(array, regex): for i, x in enumerate(array): if regex.search(x): return i return -1 cipher_check_idx = findIndexMatching(client_ssl_informations, cipher_check_regex) finished_check_idx = findIndexMatching(client_ssl_informations, finished_check_regex) self.assertTrue(cipher_check_idx > 0) self.assertTrue(finished_check_idx > 0) self.assertTrue(finished_check_idx > cipher_check_idx) return handshake_ok
def main(): """ Launch tests to check required modules and OS-specific dependencies. Exit with a relevant error code. """ exit_code = 0 import sys print 'python %s' % (sys.version,) try: import zlib print 'zlib %s' % (zlib.__version__,) except: sys.stderr.write('"zlib" missing.\n') exit_code = 1 try: import _hashlib import ssl _hashlib print 'stdlib ssl %s' % (ssl.OPENSSL_VERSION,) except: sys.stderr.write('standard "ssl" missing.\n') exit_code = 2 # cryptography module and latest pyOpenSSL are only available on # systems with cffi. if BUILD_CFFI: try: from cryptography.hazmat.backends.openssl.backend import backend import cryptography openssl_version = backend.openssl_version_text() print 'cryptography %s - OpenSSL %s' % ( cryptography.__version__, openssl_version) if chevah_os == 'windows': # Check OpenSSL version on windows. expecting = u'OpenSSL 1.0.2g 1 Mar 2016' if openssl_version != expecting: sys.stderr.write('Expecting %s got %s.\n' % ( expecting, openssl_version)) exit_code = 3 except Exception as error: sys.stderr.write('"cryptography" failure. %s\n' % (error,)) exit_code = 14 try: from OpenSSL import SSL, crypto, rand, __version__ as pyopenssl_version crypto rand print 'pyopenssl %s - OpenSSL %s' % ( pyopenssl_version, SSL.SSLeay_version(SSL.SSLEAY_VERSION), ) except Exception as error: sys.stderr.write('"OpenSSL" missing. %s\n' % (error,)) exit_code = 3 try: import Crypto print 'PyCrypto %s' % (Crypto.__version__,) except: sys.stderr.write('"PyCrypto" missing.\n') exit_code = 4 if os.name != 'nt': # Module only available on Linux / Unix try: import crypt crypt except: sys.stderr.write('"crypt" missing.\n') exit_code = 5 try: import setproctitle setproctitle except: sys.stderr.write('"setproctitle" missing.\n') exit_code = 7 try: from Crypto.PublicKey import _fastmath _fastmath except: sys.stderr.write('"Crypto.PublicKey._fastmath" missing. No GMP?\n') exit_code = 10 try: from ctypes import CDLL import ctypes CDLL print 'ctypes %s' % (ctypes.__version__,) except: sys.stderr.write('"ctypes - CDLL" missing. %s\n') exit_code = 8 try: from ctypes.util import find_library find_library except: sys.stderr.write('"ctypes.utils - find_library" missing.\n') exit_code = 9 # Windows specific modules. if os.name == 'nt': try: from ctypes import windll windll except: sys.stderr.write('"ctypes - windll" missing.\n') exit_code = 1 try: import sqlite3 sqlite3 except: sys.stderr.write('"sqlite3" missing.\n') exit_code = 6 else: # Linux and Unix checks. try: import crypt crypt except: sys.stderr.write('"crypt" missing.\n') exit_code = 5 try: import pysqlite2 pysqlite2 except: sys.stderr.write('"pysqlite2" missing.\n') exit_code = 6 try: import setproctitle print 'setproctitle %s' % (setproctitle.__version__,) except: sys.stderr.write('"setproctitle" missing.\n') exit_code = 7 try: from Crypto.PublicKey import _fastmath _fastmath except: sys.stderr.write('Crypto.PublicKey._fastmath missing. No GMP?\n') exit_code = 10 if ( platform_system == 'linux' ) or ( platform_system == 'sunos' ): try: import spwd spwd except: sys.stderr.write('"spwd" missing.\n') exit_code = 1 # We compile the readline module using libedit only on selected platforms. if test_for_readline: try: import readline readline.get_history_length() except: sys.stderr.write('"readline" missing.\n') exit_code = 13 exit_code = test_dependencies() | exit_code sys.exit(exit_code)
def assertTlsHandshakeSucceed(self, base_url, ciphers, client_cert, client_key): """Checks that the TLS handshake succeed with the given parameters. Attempts to establish a TLS session with the given |base_url|, using the given |ciphers| list and the given certificate key pair. Checks that he SAS UUT response must satisfy all of the following conditions: - The SAS UUT agrees to use a cipher specified in the |ciphers| list - The SAS UUT agrees to use TLS Protocol Version 1.2 - Valid Finished message is returned by the SAS UUT immediately following the ChangeCipherSpec message """ url = urlparse.urlparse('https://' + base_url) client = socket.socket() client.connect((url.hostname, url.port or 443)) logging.debug("OPENSSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION)) logging.debug('TLS handshake: connecting to: %s:%d', url.hostname, url.port or 443) logging.debug('TLS handshake: ciphers=%s', ':'.join(ciphers)) logging.debug('TLS handshake: privatekey_file=%s', client_key) logging.debug('TLS handshake: certificate_file=%s', client_cert) logging.debug('TLS handshake: certificate_chain_file=%s', self._sas._tls_config.ca_cert) ctx = SSL.Context(SSL.TLSv1_2_METHOD) ctx.set_cipher_list(':'.join(ciphers)) ctx.use_certificate_file(client_cert) ctx.use_privatekey_file(client_key) ctx.load_verify_locations(self._sas._tls_config.ca_cert) client_ssl_informations = [] def _InfoCb(conn, where, ok): client_ssl_informations.append(conn.get_state_string()) logging.debug('TLS handshake info: %d|%d %s', where, ok, conn.get_state_string()) return ok ctx.set_info_callback(_InfoCb) # only for potential debugging info... def _VerifyCb(conn, cert, errnum, depth, ok): certsubject = crypto.X509Name(cert.get_subject()) commonname = certsubject.commonName logging.debug('TLS handshake verify: certificate: %s -> %d', commonname, ok) return ok ctx.set_verify(SSL.VERIFY_PEER, _VerifyCb) client_ssl = SSL.Connection(ctx, client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(url.hostname) try: client_ssl.do_handshake() logging.debug('TLS handshake: succeed') except SSL.Error as e: logging.exception('TLS handshake: failed:\n%s', '\n'.join(client_ssl_informations)) raise AssertionError('TLS handshake: failure: %s' % e.message) finally: client_ssl.close() self.assertEqual(client_ssl.get_cipher_list(), ciphers) self.assertEqual(client_ssl.get_protocol_version_name(), 'TLSv1.2') # tricky part: exact logged message depends of the version of openssl... cipher_check_regex = re.compile(r"change.cipher.spec", re.I) finished_check_regex = re.compile( r"negotiation finished|finish_client_handshake", re.I) def findIndexMatching(array, regex): for i, x in enumerate(array): if regex.search(x): return i return -1 cipher_check_idx = findIndexMatching(client_ssl_informations, cipher_check_regex) finished_check_idx = findIndexMatching(client_ssl_informations, finished_check_regex) self.assertTrue(cipher_check_idx > 0) self.assertTrue(finished_check_idx > 0) self.assertTrue(finished_check_idx > cipher_check_idx)