def start(keystore, keystorealias, keypass, keystorepassphrase, hostandport, timeout): verify(keystore, keystorealias, keypass, keystorepassphrase, hostandport) sslContext = getOpensslContext(keystore, keystorealias, keypass, keystorepassphrase) socket = socket_any_family() socket.settimeout(timeout) hostandport = hostandport.split(":", 2) socket.connect((hostandport[0], int(hostandport[1]))) sslConnection = Connection(sslContext, socket) sslConnection.set_connect_state() sslConnection.set_tlsext_host_name(hostandport[0].encode('utf-8')) while True: try: sslConnection.do_handshake() except OpenSSL.SSL.WantReadError: rd, _, _ = select.select([socket], [], [], socket.gettimeout()) if not rd: raise timeout('select timed out') continue except OpenSSL.SSL.Error as e: raise ssl.SSLError('bad handshake: %r' % e) break sslContext.set_timeout(timeout) sslConnection.send(b"GET / HTTP/1.0\r\n\r\n") socket.recv(1024)
def _ssl_handshake(self): """ Perform an SSL handshake w/ the server. Precondition: a successful STARTTLS exchange has taken place with Riak returns True upon success, otherwise an exception is raised """ if self._client._credentials: ssl_ctx = \ Context(self._client._credentials.ssl_version) try: configure_context(ssl_ctx, self._client._credentials) # attempt to upgrade the socket to SSL ssl_socket = Connection(ssl_ctx, self._socket) ssl_socket.set_connect_state() ssl_socket.do_handshake() # ssl handshake successful self._socket = ssl_socket self._client._credentials._check_revoked_cert(ssl_socket) return True except Exception as e: # fail if *any* exceptions are thrown during SSL handshake raise SecurityError(e.message)
def _ssl_handshake(self): """ Perform an SSL handshake w/ the server. Precondition: a successful STARTTLS exchange has taken place with Riak returns True upon success, otherwise an exception is raised """ if self._client._credentials: ssl_ctx = \ Context(self._client._credentials.ssl_version) try: configure_context(ssl_ctx, self._client._credentials) # attempt to upgrade the socket to SSL ssl_socket = Connection(ssl_ctx, self._socket) ssl_socket.set_connect_state() ssl_socket.do_handshake() # ssl handshake successful self._socket = ssl_socket if self._client._credentials.has_credential('crl'): self._client._credentials.check_revoked_cert(ssl_socket) return True except Exception as e: # fail if *any* exceptions are thrown during SSL handshake raise RiakError(e.message)
def testPFSCipher(host,port,cipher): try: # Construct the socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.settimeout(10) client.connect((host, port)) # Define the method as serverpreferred and use the Cipher from the test contextToUse = Context(pfsCipherList[cipher]) contextToUse.set_cipher_list(cipher) # Estabilish a SSL connection using the server's preferred connection client_ssl = Connection(contextToUse, client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(host) # Try to perform an SSL handshake client_ssl.do_handshake() # Close the connection client_ssl.close() client.close() return True except openSSLError as e: # Server may be down or avoiding SSL connection return False except ValueError as e: # Not configured or not allowed return False pass
def test_set_default_verify_paths(self): """ L{Context.set_default_verify_paths} causes the platform-specific CA certificate locations to be used for verification purposes. """ # Testing this requires a server with a certificate signed by one of # the CAs in the platform CA location. Getting one of those costs # money. Fortunately (or unfortunately, depending on your # perspective), it's easy to think of a public server on the # internet which has such a certificate. Connecting to the network # in a unit test is bad, but it's the only way I can think of to # really test this. -exarkun # Arg, verisign.com doesn't speak TLSv1 context = Context(SSLv3_METHOD) context.set_default_verify_paths() context.set_verify( VERIFY_PEER, lambda conn, cert, errno, depth, preverify_ok: preverify_ok) client = socket() client.connect(('verisign.com', 443)) clientSSL = Connection(context, client) clientSSL.set_connect_state() clientSSL.do_handshake() clientSSL.send('GET / HTTP/1.0\r\n\r\n') self.assertTrue(clientSSL.recv(1024))
def printcert(host, port, hostname): con = Connection(Context(TLSv1_METHOD), socket(AF_INET, SOCK_STREAM)) con.connect((host, port)) con.set_tlsext_host_name(hostname if hostname else host) con.do_handshake() con.shutdown() con.close() print dump_certificate(FILETYPE_PEM, walkchain(con.get_peer_cert_chain()))
def _openssl_connect(hostname): client = socket() client.connect((hostname, 443)) client_ssl = Connection(Context(SSLv23_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(hostname.encode('utf-8')) client_ssl.do_handshake() return client_ssl
def do_handshake(self): while True: try: _Connection.do_handshake(self) break except WantReadError: exc_clear() wait_read(self._sock.fileno(), timeout=self._timeout) except WantWriteError: exc_clear() wait_write(self._sock.fileno(), timeout=self._timeout)
def _dump_all_certs(self, cert_file, address): # This will also include intermediate certs context = Context(SSLv23_METHOD) context.set_default_verify_paths() client = socket.socket() client.connect((address, 443)) clientSSL = Connection(context, client) clientSSL.set_connect_state() clientSSL.do_handshake() chains = clientSSL.get_peer_cert_chain() for chain in chains: cert_file.write(dump_certificate(FILETYPE_PEM, chain).decode())
def main(): """ Connect to an SNI-enabled server and request a specific hostname, specified by argv[1], of it. """ if len(argv) < 2: print 'Usage: %s <hostname> [port]' % (argv[0], ) return 1 port = 443 if len(argv) == 3: port = int(argv[2]) hostname = argv[1] client = socket() #client.settimeout(2) #print 'Connecting...', stdout.flush() client.connect((hostname, port)) #print 'connected', client.getpeername() client_ssl = Connection(Context(TLSv1_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(hostname) client_ssl.do_handshake() host = client_ssl.getpeername() servername = client_ssl.get_servername() x509 = client_ssl.get_peer_certificate() notAfter = datetime.strptime(x509.get_notAfter(), '%Y%m%d%H%M%SZ') cert_chain = client_ssl.get_peer_cert_chain() now = datetime.now() timedelta = notAfter - now DNS = '' for i in xrange(x509.get_extension_count()): ret = str(x509.get_extension(i)) if re.match('^DNS:', ret): DNS = ret.replace('DNS:', '') print "servername: %s, host: %s, port: %s" % (servername, host[0], host[1]) print "\tnotAfter: %s, remain: %s days" % (notAfter, timedelta.days) print "\tDNS: ", DNS print '\tCert Chain:' for i, v in enumerate(cert_chain): print '\t%s,i,%s' % (i, v.get_subject()) print '\t%s,s,%s' % (i, v.get_issuer()) client_ssl.close()
class ManInTheMiddle: def __init__(self, client_socket, host, port): self.client_socket = client_socket self.host = host self.port = port self.sni = None self.client_ssl_sock = None self.server_ssl_sock = None def start_hacking(self): self.client_socket.sendall(('HTTP/1.1 %d %s\r\n\r\n' % (200, 'OK')).encode('latin-1', 'strict')) self.accept_client_conn() def accept_client_conn(self): context = Context(SSLv23_METHOD) context.set_tlsext_servername_callback(self.prepare_handshake) self.client_ssl_sock = Connection(context, self.client_socket) self.client_ssl_sock.set_accept_state() self.client_ssl_sock.do_handshake() def prepare_handshake(self, connection): raw_sni = connection.get_servername() if raw_sni is not None: self.sni = str(raw_sni, 'ascii') self.build_server_conn() cert_dict = self.server_ssl_sock.getpeercert() crt_dir = generate_fake_cert(cert_dict) try: key, cert = load(crt_dir) except crypto.Error: raise CertificateRaceCondition new_context = Context(SSLv23_METHOD) new_context.use_privatekey(key) new_context.use_certificate(cert) connection.set_context(new_context) def build_server_conn(self): server_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) server_context.verify_mode = ssl.CERT_OPTIONAL # context.load_verify_locations('/etc/ssl/certs/ca-bundle.crt') server_context.set_default_verify_paths() ssl_sock = server_context.wrap_socket(socket.socket(socket.AF_INET), server_hostname=self.sni) try: ssl_sock.connect((self.host, self.port)) except socket.gaierror: print(self.host, self.port) raise ServerConnectionError self.server_ssl_sock = ssl_sock
def server_ok(serverarg, capath, timeout): "Check if the server is active and responsive" server_ctx = Context(TLSv1_METHOD) server_ctx.load_verify_locations(None, capath) def verify_cb(conn, cert, errnum, depth, ok): return ok server_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb) serverarg = re.split("/*", serverarg)[1] if ':' in serverarg: serverarg = serverarg.split(':') server = serverarg[0] port = int(serverarg[1] if not '?' in serverarg[1] else serverarg[1].split('?')[0]) else: server = serverarg port = DEFAULT_PORT try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((server, port)) server_conn = Connection(server_ctx, sock) server_conn.set_connect_state() try: def handler(signum, frame): raise socket.error([('Timeout', 'after', str(timeout) + 's')]) signal.signal(signal.SIGALRM, handler) signal.alarm(timeout) server_conn.do_handshake() signal.alarm(0) except socket.timeout as e: nagios_out('Critical', 'Connection error %s - %s' % (server + ':' + str(port), errmsg_from_excp(e)),2) server_conn.shutdown() server_conn.close() except (SSLError, socket.error) as e: if 'sslv3 alert handshake failure' in errmsg_from_excp(e): pass else: nagios_out('Critical', 'Connection error %s - %s' % (server + ':' + str(port), errmsg_from_excp(e)), 2) return True
def server_ok(serverarg, capath, timeout): server_ctx = Context(TLSv1_METHOD) server_ctx.load_verify_locations(None, capath) def verify_cb(conn, cert, errnum, depth, ok): return ok server_ctx.set_verify(VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb) serverarg = re.split("/*", serverarg)[1] if ':' in serverarg: serverarg = serverarg.split(':') server = serverarg[0] port = int(serverarg[1] if not '?' in serverarg[1] else serverarg[1]. split('?')[0]) else: server = serverarg port = DEFAULT_PORT try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((server, port)) server_conn = Connection(server_ctx, sock) server_conn.set_connect_state() try: def handler(signum, frame): raise socket.error([('Timeout', 'after', str(timeout) + 's')]) signal.signal(signal.SIGALRM, handler) signal.alarm(timeout) server_conn.do_handshake() signal.alarm(0) except socket.timeout as e: nagios_out( 'Critical', 'Connection error %s - %s' % (server + ':' + str(port), errmsg_from_excp(e)), 2) server_conn.shutdown() server_conn.close() except (SSLError, socket.error) as e: if 'sslv3 alert handshake failure' in errmsg_from_excp(e): pass else: nagios_out( 'Critical', 'Connection error %s - %s' % (server + ':' + str(port), errmsg_from_excp(e)), 2) return True
def testWeakCipher(host,port,protocolList): # Create a list to put all analysed data protoDataList = [] # Test the size of the cipher for each protocol avaiable and get the Cipher Suite for proto in protocolList: try: # Construct the socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((host, port)) # Estabilish a SSL connection client_ssl = Connection(Context(methods[proto]), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(host) # Try to perform an SSL handshake client_ssl.do_handshake() # Obtain the name of the protocol being used protoName = (client_ssl.get_protocol_version_name()) # Obtain the size of the cipher being used by the protocol bitSize = (client_ssl.get_cipher_bits()) # Obtain the Cipher Suite suite = client_ssl.get_cipher_name() # Create a compiled data data = (protoName,bitSize,suite) # Put the data obtained on the list protoDataList.append(data) # Close the connection client_ssl.close() client.close() except openSSLError as e: # Server may be down or avoiding SSL connection print _('Servidor nao esta respondendo') return except ValueError as e: # Not configured or not allowed print _('Servidor nao esta configurado') return # Print the results print bcolors.BOLD + _("Protocolo\tTamanho da Cifra\tCifra") + bcolors.ENDC for protoData in protoDataList: print protoData[0] + '\t\t' + str(protoData[1]) + ' bits' + ( '(OK)' if (protoData[1] >=128) else _('(FRACA)')) + '\the\t' + str(protoData[2])
def main(): def err_exit(ret, msg): ret['failed'] = True ret['msg'] = msg module.fail_json(**ret) module = AnsibleModule(argument_spec=dict( host=dict(required=True, type='str'), certificates=dict(required=True, type='dict'), ), ) host = module.params['host'] certificates = copy.copy(module.params['certificates']) split = host.split(':') split.reverse() host = split.pop() ret['host'] = host ret['port'] = None ret['downloaded'] = False ret['ansible_facts'] = dict(certificates=certificates) try: port = int(split.pop()) if split else 443 hostport = "{}:{}".format(host, port) ret['port'] = port if host in certificates and hostport not in certificates: certificates[hostport] = certificates[host] if hostport not in certificates or certificates[hostport] is None: s = socket(AF_INET, SOCK_STREAM) ctx = Context(TLSv1_METHOD) con = Connection(ctx, s) con.connect((host, port)) con.do_handshake() x509 = con.get_peer_cert_chain()[-1] con.shutdown() con.close() ret['downloaded'] = True certificates[hostport] = dump_certificate(FILETYPE_PEM, x509) if host not in certificates or certificates[host] is None: certificates[host] = certificates[hostport] module.exit_json(**ret) except Exception as e: msg_ = traceback.format_exc() module.fail_json(msg="{}: {}".format(repr(e), msg_))
def identifyProtocol(host,port): # Create a list to put all analysed data protoDataList = [] try: # Construct the socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((host, port)) # Estabilish a SSL connection using the server's preferred connection client_ssl = Connection(Context(SSLv23_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(host) # Try to perform an SSL handshake client_ssl.do_handshake() # Obtain the name of the protocol being used protoName = (client_ssl.get_protocol_version_name()) # Obtain the size of the cipher being used by the protocol bitSize = (client_ssl.get_cipher_bits()) # Obtain the Cipher Suite suite = client_ssl.get_cipher_name() # Create a compiled data data = (protoName,bitSize,suite) # Put the data obtained on the list protoDataList.append(data) # Close the connection client_ssl.close() client.close() # Shpw the data print _('Preferido: ') + str(protoName) + _('\nCifra: ') + str(suite) + _('\nTamanho em bits: ') + str(bitSize) # Return the protocol method used by pyOpenSSL return methodName[protoName] except openSSLError as e: # Server may be down or avoiding SSL connection print _('\nNao foi possivel identificar o protocolo padrao\n') return 0 except ValueError as e: # Not configured or not allowed print _('\nNao foi possivel identificar o protocolo padrao\n') return 0
def get_certificate(hostname, port=443): """ Return TLS certificate (f.i. for https or smtps) """ client = socket() client.connect((hostname, port)) client_ssl = Connection(Context(TLSv1_2_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(hostname.encode("ascii")) # SNI client_ssl.do_handshake() cert = client_ssl.get_peer_certificate() client_ssl.close() return cert
class OpenSSLSNI(object): """This class implements the functionality of obtaining certificates secure connection using apache TLS Extension Server Name Indication (SNI) """ def connection(func): def wrapped(self): self._connect() try: return func(self) finally: self._close() return wrapped def __init__(self, host, port): #Set host name self._host = str(host).split('//')[-1].split(':')[0] #Set port self._port = int(port) if str(port).isdigit() else 443 def _connect(self): """This method implements the functionality of establishing a secure connection using TLS Extension""" self._socket_client = socket() self._socket_client.connect((self._host, self._port)) self._ssl_client = Connection(Context(TLSv1_METHOD), self._socket_client) self._ssl_client.set_connect_state() self._ssl_client.set_tlsext_host_name(self._host) self._ssl_client.do_handshake() def _close(self): """This method implements the functional termination created connection""" self._ssl_client.close() del self._socket_client @property @connection def serial_number(self): """Returns certificates serial number""" return self._ssl_client.get_peer_certificate().get_serial_number() @property @connection def certificate(self): """Returns certificate""" return OpenSSL.crypto.dump_certificate(FILETYPE_PEM, self._ssl_client.get_peer_certificate())
def get_ssl(url): print(Fore.RED+"[+] ssl certificate:"+Fore.GREEN) first_try = re.findall(r":([0-9]+)", str(url)) if len(first_try) != 0: for i in range(len(first_try)): port = ''.join(first_try[i]) else: port = int('443') second_try = re.findall(r"/([0-9a-zA-Z\.%&#]+)", str(url)) if len(second_try) != 0: for i in range(len(second_try)): host = ''.join(second_try[i]) try: try: ssl_connection_setting = Context(SSLv3_METHOD) except ValueError: ssl_connection_setting = Context(TLSv1_2_METHOD) ssl_connection_setting.set_timeout(5) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((host, int(port))) c = Connection(ssl_connection_setting, s) c.set_tlsext_host_name(str.encode(host)) c.set_connect_state() c.do_handshake() cert = c.get_peer_certificate() print(Fore.RED+" --> "+Fore.GREEN+"Is Expired: ", cert.has_expired()) print(Fore.RED+" --> "+Fore.GREEN+"Issuer: ", cert.get_issuer()) subject_list = cert.get_subject().get_components() cert_byte_arr_decoded = {} for item in subject_list: cert_byte_arr_decoded.update({item[0].decode('utf-8'): item[1].decode('utf-8')}) if len(cert_byte_arr_decoded) > 0: print(Fore.RED+" --> "+Fore.GREEN+"Subject: ", cert_byte_arr_decoded) if cert_byte_arr_decoded["CN"]: print(Fore.RED+" --> "+Fore.GREEN+"Common Name: ", cert_byte_arr_decoded["CN"]) end_date = datetime.strptime(str(cert.get_notAfter().decode('utf-8')), "%Y%m%d%H%M%SZ") print(Fore.RED+" --> "+Fore.GREEN+"Not After (UTC Time): ", end_date) diff = end_date - datetime.now() print(Fore.RED+" --> "+Fore.GREEN+'Summary: "{}" SSL certificate expires on {} i.e. {} days.'.format(host, end_date, diff.days)) c.shutdown() s.close() except: print(Fore.RED+" --> "+Fore.GREEN+"Not found") pass
def main(): if len(argv) < 3: print('Usage: %s <hostname> <port>'.format(argv[0])) return 1 hostname = str(argv[1]) port = int(argv[2]) client = socket() print('Connecting...') stdout.flush() client.connect((hostname, port)) print('Connected to', client.getpeername()) client_ssl = Connection(Context(TLSv1_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(hostname.encode('utf-8')) client_ssl.do_handshake() chain = client_ssl.get_peer_cert_chain() print("\n>> Certificate Chain:\n") i = 0 for cert in reversed(chain): i += 1 asterisks = "*" * i print(" [+] {:<10} {}".format(asterisks, cert.get_subject())) print("\n>> Certificate Details:\n") for cert in reversed(chain): pkey = cert.get_pubkey() print("." * 80) print("- [Subject]:\t\t{}".format(cert.get_subject())) print("- [Issuer]:\t\t{}".format(cert.get_issuer())) print("- [Valid from]:\t\t{}".format(cert.get_notBefore())) print("- [Valid until]:\t{}".format(cert.get_notAfter())) print("- [Has Expired]:\t{}".format(cert.has_expired())) print("\n") client_ssl.close() return 0
def netflix_openssl_test_retry(ip): client = socket() print 'Connecting...', stdout.flush() client.connect((ip, port)) print 'connected', client.getpeername() client_ssl = Connection(Context(TLSv1_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(hostname) client_ssl.do_handshake() cert = client_ssl.get_peer_certificate().get_subject() cn = [comp for comp in cert.get_components() if comp[0] in ['CN']] client_ssl.close() print cn if hostname in cn[0][1]: return True else: return False
def connect(self, ctx=None, session=None, port=7080): sock = socket.create_connection(('127.0.0.1', port)) if ctx is None: ctx = Context(TLSv1_2_METHOD) client = Connection(ctx, sock) client.set_connect_state() if session is not None: client.set_session(session) client.do_handshake() client.shutdown() return ( client.get_session(), ctx, _lib.SSL_session_reused(client._ssl), )
def ip_ssl_connect(self, ip): logging.basicConfig(filename=self.basedir+'/output/log/get_cert_from_ip.log', level=logging.DEBUG, format='%(asctime)s %(message)s') try: sslcontext = Context(TLSv1_METHOD) sslcontext.set_timeout(30) s = socket() s.connect((ip, 443)) c = Connection(sslcontext, s) c.set_connect_state() logging.info("try to establish handshake with %s..." % ip) c.do_handshake() cert = c.get_peer_certificate() logging.info("got certificate!") c.shutdown() s.close() return cert except Exception as e: logging.info(e) logging.info("fail to connect to port 443 with %s" % ip) return None
def _validate_certificate_hostname_pyopenssl(self): """ Use pyOpenSSL check if the host's certifcate matches the hostname. Python < 2.7.9 is not able to provide a server hostname for SNI, so this is a fallback that opens an additional connection if the initial validation failed. Returns: bool: Whether or not the hostname is valid on the certificate. """ client = socket.socket() client.connect((self.host, self.port)) client_ssl = Connection(Context(TLSv1_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(self.host) client_ssl.do_handshake() cert = client_ssl.get_peer_certificate() client_ssl.close() common_name = cert.get_subject().commonName return self._cert_host_matches_hostname(common_name, self.host)
class SSLSock(TcpSock): def __init__(self,*args,**kwargs): TcpSock.__init__(self,*args,**kwargs) self.raw_sock=self.sock self.sock=Connection(Context(TLSv1_METHOD),self.raw_sock) self.sock.set_connect_state() self.sock.do_handshake() def sock_recv(self,size,nodata_delay): if size is None: size=self.recv_size try: return self.sock.read(size) except WantReadError: tmout=self.timeout if tmout is None: raise if not select.select([self.sock],[],[],tmout)[0]: raise socket.timeout,"No data in %s seconds"%(tmout,) try: return self.sock.read(size) except ZeroReturnError: return "" except ZeroReturnError: return "" except SysCallError,e: if e[0]==-1: return "" raise
def main(): """ Connect to an SNI-enabled server and request a specific hostname, specified by argv[1], of it. """ if len(argv) < 2: print 'Usage: %s <hostname>' % (argv[0], ) return 1 client = socket() print 'Connecting...', stdout.flush() client.connect(('127.0.0.1', 8443)) print 'connected', client.getpeername() client_ssl = Connection(Context(TLSv1_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(argv[1]) client_ssl.do_handshake() print 'Server subject is', client_ssl.get_peer_certificate().get_subject() client_ssl.close()
def check_cerificate_invalidtime(domain, port=443): from datetime import datetime from OpenSSL.SSL import TLSv1_METHOD, Context, Connection import socket client = socket.socket() try: client.connect((domain, port)) ssl = Connection(Context(TLSv1_METHOD), client) ssl.set_connect_state() ssl.set_tlsext_host_name(domain.encode('utf-8')) ssl.do_handshake() cerificate = ssl.get_peer_certificate() invalid = cerificate.get_notAfter().decode()[0:-1] invalidtime = datetime.strptime(invalid, '%Y%m%d%H%M%S') diff_day = invalidtime - datetime.now() return True, {"invaliddate": invalidtime, "invalidday": diff_day.days} except Exception as e: return False, e.args finally: client.close() pass
def main(): """ Run an SNI-enabled server which selects between a few certificates in a C{dict} based on the handshake request it receives from a client. """ port = socket() port.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) port.bind(('', 8443)) port.listen(3) print 'Accepting...', stdout.flush() server, addr = port.accept() print 'accepted', addr server_context = Context(TLSv1_METHOD) server_context.set_tlsext_servername_callback(pick_certificate) server_ssl = Connection(server_context, server) server_ssl.set_accept_state() server_ssl.do_handshake() server.close()
def main(): """ Connect to an SNI-enabled server and request a specific hostname, specified by argv[1], of it. """ if len(argv) < 2: print 'Usage: %s <hostname>' % (argv[0],) return 1 client = socket() print 'Connecting...', stdout.flush() client.connect(('127.0.0.1', 8443)) print 'connected', client.getpeername() client_ssl = Connection(Context(TLSv1_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(argv[1]) client_ssl.do_handshake() print 'Server subject is', client_ssl.get_peer_certificate().get_subject() client_ssl.close()
def connect(self, ctx=None, session=None): sock = socket.create_connection(('127.0.0.1', 7080)) if ctx is None: ctx = Context(TLSv1_2_METHOD) ctx.set_session_cache_mode(SESS_CACHE_CLIENT) ctx.set_options(OP_NO_TICKET) client = Connection(ctx, sock) client.set_connect_state() if session is not None: client.set_session(session) client.do_handshake() client.shutdown() return ( client, client.get_session(), ctx, _lib.SSL_session_reused(client._ssl), )
def verifyOpenProtocol(host,port,proto): try: # Construct the socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((host, port)) # Estabilish a SSL connection client_ssl = Connection(Context(proto), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(host) # Try to perform an SSL handshake client_ssl.do_handshake() # Close the connection client_ssl.close() client.close() except openSSLError as e: # Server not configured to use return False except ValueError as e: # Not present return False # Success return True
def checkCertificate(url_base, url_rest, req_headers={}, request_type='GET'): connection = http.client.HTTPSConnection(url_base, timeout=1) certificate_is_valid = None certificate_host_names = None try: client = socket.socket() client.connect((url_base, 443)) client_ssl = Connection(Context(TLSv1_2_METHOD), client) client_ssl.set_connect_state() client_ssl.set_tlsext_host_name(url_base.encode('UTF-8')) client_ssl.do_handshake() certificate_host_names = get_certificate_hosts( client_ssl.get_peer_certificate()) except: pass finally: if client: client.close() try: connection.request(request_type, url_rest, headers=req_headers) certificate_is_valid = True except: certificate_is_valid = False return (certificate_is_valid, certificate_host_names)
soc.connect((host, int(port))) except socket.error, err: log(("Socket Error Encountered : %s" % err), sink) exit(1) pass # --- Connect to remote host soc_context = Context(SSLv23_METHOD) soc_ssl = Connection(soc_context, soc) soc_ssl.set_connect_state() soc_ssl.set_tlsext_host_name(argv[1]) try: soc_ssl.do_handshake() except OpenSSL.SSL.Error, msg: print " \n\n Unable to complet the SSL Handshake %s" % msg exit(1) pass #--- Get the remote host name rhost = soc.getpeername() log(("\nRemote Host name :" + host), sink) log(("\nRemote Host IPv4 :" + rhost[0]), sink) log(("\nRemote Host Port :" + str(rhost[1])), sink) #--- Get and Analyse Server Certificate
from OpenSSL.SSL import Connection, Context, SSLv3_METHOD, TLSv1_2_METHOD host = 'www.baidu.com' try: ssl_connection_setting = Context(SSLv3_METHOD) except ValueError: ssl_connection_setting = Context(TLSv1_2_METHOD) ssl_connection_setting.set_timeout(30) s = socket() s.connect((host, 443)) c = Connection(ssl_connection_setting, s) c.set_connect_state() c.do_handshake() cert = c.get_peer_certificate() print "Issuer: ", cert.get_issuer() print "Subject: ", cert.get_subject().get_components() subject_list = cert.get_subject().get_components() print "Common Name:", dict(subject_list).get("CN") print "notAfter(UTC time): ", cert.get_notAfter() UTC_FORMAT = "%Y%m%d%H%M%SZ" utc_to_local_offset = datetime.datetime.fromtimestamp(time.time()) - datetime.datetime.utcfromtimestamp(time.time()) utc_time = time.mktime(time.strptime(cert.get_notAfter(), UTC_FORMAT)) local_time = utc_time + utc_to_local_offset.seconds print "notAfter(Local Time): ", datetime.datetime.fromtimestamp(local_time) print "is_expired:", cert.has_expired() c.shutdown() s.close()
class TLSMemoryBIOProtocol(ProtocolWrapper): """ L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a memory BIO to encrypt bytes written to it before sending them on to the underlying transport and decrypts bytes received from the underlying transport before delivering them to the wrapped protocol. In addition to producer events from the underlying transport, the need to wait for reads before a write can proceed means the L{TLSMemoryBIOProtocol} may also want to pause a producer. Pause/resume events are therefore merged using the L{_ProducerMembrane} wrapper. Non-streaming (pull) producers are supported by wrapping them with L{_PullToPush}. @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is encrypted and decrypting this connection. @ivar _lostTLSConnection: A flag indicating whether connection loss has already been dealt with (C{True}) or not (C{False}). TLS disconnection is distinct from the underlying connection being lost. @ivar _writeBlockedOnRead: A flag indicating whether further writing must wait for data to be received (C{True}) or not (C{False}). @ivar _appSendBuffer: A C{list} of C{str} of application-level (cleartext) data which is waiting for C{_writeBlockedOnRead} to be reset to C{False} so it can be passed to and perhaps accepted by C{_tlsConnection.send}. @ivar _connectWrapped: A flag indicating whether or not to call C{makeConnection} on the wrapped protocol. This is for the reactor's L{twisted.internet.interfaces.ITLSTransport.startTLS} implementation, since it has a protocol which it has already called C{makeConnection} on, and which has no interest in a new transport. See #3821. @ivar _handshakeDone: A flag indicating whether or not the handshake is known to have completed successfully (C{True}) or not (C{False}). This is used to control error reporting behavior. If the handshake has not completed, the underlying L{OpenSSL.SSL.Error} will be passed to the application's C{connectionLost} method. If it has completed, any unexpected L{OpenSSL.SSL.Error} will be turned into a L{ConnectionLost}. This is weird; however, it is simply an attempt at a faithful re-implementation of the behavior provided by L{twisted.internet.ssl}. @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes the connection to be lost, it is saved here. If appropriate, this may be used as the reason passed to the application protocol's C{connectionLost} method. @ivar _producer: The current producer registered via C{registerProducer}, or C{None} if no producer has been registered or a previous one was unregistered. """ _reason = None _handshakeDone = False _lostTLSConnection = False _writeBlockedOnRead = False _producer = None def __init__(self, factory, wrappedProtocol, _connectWrapped=True): ProtocolWrapper.__init__(self, factory, wrappedProtocol) self._connectWrapped = _connectWrapped def getHandle(self): """ Return the L{OpenSSL.SSL.Connection} object being used to encrypt and decrypt this connection. This is done for the benefit of L{twisted.internet.ssl.Certificate}'s C{peerFromTransport} and C{hostFromTransport} methods only. A different system handle may be returned by future versions of this method. """ return self._tlsConnection def makeConnection(self, transport): """ Connect this wrapper to the given transport and initialize the necessary L{OpenSSL.SSL.Connection} with a memory BIO. """ tlsContext = self.factory._contextFactory.getContext() self._tlsConnection = Connection(tlsContext, None) if self.factory._isClient: self._tlsConnection.set_connect_state() else: self._tlsConnection.set_accept_state() self._appSendBuffer = [] # Add interfaces provided by the transport we are wrapping: for interface in providedBy(transport): directlyProvides(self, interface) # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) self.factory.registerProtocol(self) if self._connectWrapped: # Now that the TLS layer is initialized, notify the application of # the connection. ProtocolWrapper.makeConnection(self, transport) # Now that we ourselves have a transport (initialized by the # ProtocolWrapper.makeConnection call above), kick off the TLS # handshake. try: self._tlsConnection.do_handshake() except WantReadError: # This is the expected case - there's no data in the connection's # input buffer yet, so it won't be able to complete the whole # handshake now. If this is the speak-first side of the # connection, then some bytes will be in the send buffer now; flush # them. self._flushSendBIO() def _flushSendBIO(self): """ Read any bytes out of the send BIO and write them to the underlying transport. """ try: bytes = self._tlsConnection.bio_read(2**15) except WantReadError: # There may be nothing in the send BIO right now. pass else: self.transport.write(bytes) def _flushReceiveBIO(self): """ Try to receive any application-level bytes which are now available because of a previous write into the receive BIO. This will take care of delivering any application-level bytes which are received to the protocol, as well as handling of the various exceptions which can come from trying to get such bytes. """ # Keep trying this until an error indicates we should stop or we # close the connection. Looping is necessary to make sure we # process all of the data which was put into the receive BIO, as # there is no guarantee that a single recv call will do it all. while not self._lostTLSConnection: try: bytes = self._tlsConnection.recv(2**15) except WantReadError: # The newly received bytes might not have been enough to produce # any application data. break except ZeroReturnError: # TLS has shut down and no more TLS data will be received over # this connection. self._shutdownTLS() # Passing in None means the user protocol's connnectionLost # will get called with reason from underlying transport: self._tlsShutdownFinished(None) except Error as e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. # Squash EOF in violation of protocol into ConnectionLost; we # create Failure before calling _flushSendBio so that no new # exception will get thrown in the interim. if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': failure = Failure(CONNECTION_LOST) else: failure = Failure() self._flushSendBIO() self._tlsShutdownFinished(failure) else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. self._handshakeDone = True ProtocolWrapper.dataReceived(self, bytes) # The received bytes might have generated a response which needs to be # sent now. For example, the handshake involves several round-trip # exchanges without ever producing application-bytes. self._flushSendBIO() def dataReceived(self, bytes): """ Deliver any received bytes to the receive BIO and then read and deliver to the application any application-level data which becomes available as a result of this. """ self._tlsConnection.bio_write(bytes) if self._writeBlockedOnRead: # A read just happened, so we might not be blocked anymore. Try to # flush all the pending application bytes. self._writeBlockedOnRead = False appSendBuffer = self._appSendBuffer self._appSendBuffer = [] for bytes in appSendBuffer: self._write(bytes) if (not self._writeBlockedOnRead and self.disconnecting and self.producer is None): self._shutdownTLS() if self._producer is not None: self._producer.resumeProducing() self._flushReceiveBIO() def _shutdownTLS(self): """ Initiate, or reply to, the shutdown handshake of the TLS layer. """ shutdownSuccess = self._tlsConnection.shutdown() self._flushSendBIO() if shutdownSuccess: # Both sides have shutdown, so we can start closing lower-level # transport. This will also happen if we haven't started # negotiation at all yet, in which case shutdown succeeds # immediately. self.transport.loseConnection() def _tlsShutdownFinished(self, reason): """ Called when TLS connection has gone away; tell underlying transport to disconnect. """ self._reason = reason self._lostTLSConnection = True # Using loseConnection causes the application protocol's # connectionLost method to be invoked non-reentrantly, which is always # a nice feature. However, for error cases (reason != None) we might # want to use abortConnection when it becomes available. The # loseConnection call is basically tested by test_handshakeFailure. # At least one side will need to do it or the test never finishes. self.transport.loseConnection() def connectionLost(self, reason): """ Handle the possible repetition of calls to this method (due to either the underlying transport going away or due to an error at the TLS layer) and make sure the base implementation only gets invoked once. """ if not self._lostTLSConnection: # Tell the TLS connection that it's not going to get any more data # and give it a chance to finish reading. self._tlsConnection.bio_shutdown() self._flushReceiveBIO() self._lostTLSConnection = True reason = self._reason or reason self._reason = None ProtocolWrapper.connectionLost(self, reason) def loseConnection(self): """ Send a TLS close alert and close the underlying connection. """ if self.disconnecting: return self.disconnecting = True if not self._writeBlockedOnRead and self._producer is None: self._shutdownTLS() def write(self, bytes): """ Process the given application bytes and send any resulting TLS traffic which arrives in the send BIO. If C{loseConnection} was called, subsequent calls to C{write} will drop the bytes on the floor. """ if isinstance(bytes, unicode): raise TypeError( "Must write bytes to a TLS transport, not unicode.") # Writes after loseConnection are not supported, unless a producer has # been registered, in which case writes can happen until the producer # is unregistered: if self.disconnecting and self._producer is None: return self._write(bytes) def _write(self, bytes): """ Process the given application bytes and send any resulting TLS traffic which arrives in the send BIO. This may be called by C{dataReceived} with bytes that were buffered before C{loseConnection} was called, which is why this function doesn't check for disconnection but accepts the bytes regardless. """ if self._lostTLSConnection: return leftToSend = bytes while leftToSend: try: sent = self._tlsConnection.send(leftToSend) except WantReadError: self._writeBlockedOnRead = True self._appSendBuffer.append(leftToSend) if self._producer is not None: self._producer.pauseProducing() break except Error: # Pretend TLS connection disconnected, which will trigger # disconnect of underlying transport. The error will be passed # to the application protocol's connectionLost method. The # other SSL implementation doesn't, but losing helpful # debugging information is a bad idea. self._tlsShutdownFinished(Failure()) break else: # If we sent some bytes, the handshake must be done. Keep # track of this to control error reporting behavior. self._handshakeDone = True self._flushSendBIO() leftToSend = leftToSend[sent:] def writeSequence(self, iovec): """ Write a sequence of application bytes by joining them into one string and passing them to L{write}. """ iovec = [x.encode('latin-1') for x in iovec] self.write(b"".join(iovec)) def getPeerCertificate(self): return self._tlsConnection.get_peer_certificate() def registerProducer(self, producer, streaming): # If we've already disconnected, nothing to do here: if self._lostTLSConnection: producer.stopProducing() return # If we received a non-streaming producer, wrap it so it becomes a # streaming producer: if not streaming: producer = streamingProducer = _PullToPush(producer, self) producer = _ProducerMembrane(producer) # This will raise an exception if a producer is already registered: self.transport.registerProducer(producer, True) self._producer = producer # If we received a non-streaming producer, we need to start the # streaming wrapper: if not streaming: streamingProducer.startStreaming() def unregisterProducer(self): # If we received a non-streaming producer, we need to stop the # streaming wrapper: if isinstance(self._producer._producer, _PullToPush): self._producer._producer.stopStreaming() self._producer = None self._producerPaused = False self.transport.unregisterProducer() if self.disconnecting and not self._writeBlockedOnRead: self._shutdownTLS()
Create Date: 2016/12/1 Create Time: 13:58 """ from socket import socket from OpenSSL.SSL import Connection, Context, SSLv3_METHOD import datetime import time sslcontext = Context(SSLv3_METHOD) sslcontext.set_timeout(30) ip = 'www.baidu.com' s = socket() s.connect((ip, 443)) c = Connection(sslcontext, s) c.set_connect_state() c.do_handshake() cert = c.get_peer_certificate() print "Issuer: ", cert.get_issuer() print "Subject: ", cert.get_subject().get_components() subject_list = cert.get_subject().get_components() print "Common Name:", dict(subject_list).get("CN") print "notAfter(UTC time): ", cert.get_notAfter() UTC_FORMAT = "%Y%m%d%H%M%SZ" utc_to_local_offset = datetime.datetime.fromtimestamp( time.time()) - datetime.datetime.utcfromtimestamp(time.time()) utc_time = time.mktime(time.strptime(cert.get_notAfter(), UTC_FORMAT)) local_time = utc_time + utc_to_local_offset.seconds print "notAfter(Local Time): ", datetime.datetime.fromtimestamp(local_time) print "is_expired:", cert.has_expired() c.shutdown()
if (":" in host and has_ipv6 == True) or (len(argv) >= 4 and ":" in phost and has_ipv6 == True): proxy = socket(AF_INET6, SOCK_STREAM) else: proxy = socket(AF_INET, SOCK_STREAM) try: proxy.connect((host, port)) except socket_error: proxy.close() exit("[-] problem connecting to " + str(host) + ":" + str(port)) ssl = SSL_Connection(ctx, proxy) ssl.setblocking(True) try: ssl.set_connect_state() ssl.do_handshake() except: exit(1) digest = ssl.get_peer_certificate().digest("sha1") proxy.close() checkcert = digest.replace(":", "").lower() + ".certs.googlednstest.com" try: response = query(checkcert, "TXT") except: exit(0) if not response: print "No response from the DNS for this cert" exit(0)
class TLSMemoryBIOProtocol(ProtocolWrapper): """ L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a memory BIO to encrypt bytes written to it before sending them on to the underlying transport and decrypts bytes received from the underlying transport before delivering them to the wrapped protocol. In addition to producer events from the underlying transport, the need to wait for reads before a write can proceed means the L{TLSMemoryBIOProtocol} may also want to pause a producer. Pause/resume events are therefore merged using the L{_ProducerMembrane} wrapper. Non-streaming (pull) producers are supported by wrapping them with L{_PullToPush}. @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is encrypted and decrypting this connection. @ivar _lostTLSConnection: A flag indicating whether connection loss has already been dealt with (C{True}) or not (C{False}). TLS disconnection is distinct from the underlying connection being lost. @ivar _writeBlockedOnRead: A flag indicating whether further writing must wait for data to be received (C{True}) or not (C{False}). @ivar _appSendBuffer: A C{list} of C{str} of application-level (cleartext) data which is waiting for C{_writeBlockedOnRead} to be reset to C{False} so it can be passed to and perhaps accepted by C{_tlsConnection.send}. @ivar _connectWrapped: A flag indicating whether or not to call C{makeConnection} on the wrapped protocol. This is for the reactor's L{twisted.internet.interfaces.ITLSTransport.startTLS} implementation, since it has a protocol which it has already called C{makeConnection} on, and which has no interest in a new transport. See #3821. @ivar _handshakeDone: A flag indicating whether or not the handshake is known to have completed successfully (C{True}) or not (C{False}). This is used to control error reporting behavior. If the handshake has not completed, the underlying L{OpenSSL.SSL.Error} will be passed to the application's C{connectionLost} method. If it has completed, any unexpected L{OpenSSL.SSL.Error} will be turned into a L{ConnectionLost}. This is weird; however, it is simply an attempt at a faithful re-implementation of the behavior provided by L{twisted.internet.ssl}. @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes the connection to be lost, it is saved here. If appropriate, this may be used as the reason passed to the application protocol's C{connectionLost} method. @ivar _producer: The current producer registered via C{registerProducer}, or C{None} if no producer has been registered or a previous one was unregistered. """ _reason = None _handshakeDone = False _lostTLSConnection = False _writeBlockedOnRead = False _producer = None def __init__(self, factory, wrappedProtocol, _connectWrapped=True): ProtocolWrapper.__init__(self, factory, wrappedProtocol) self._connectWrapped = _connectWrapped def getHandle(self): """ Return the L{OpenSSL.SSL.Connection} object being used to encrypt and decrypt this connection. This is done for the benefit of L{twisted.internet.ssl.Certificate}'s C{peerFromTransport} and C{hostFromTransport} methods only. A different system handle may be returned by future versions of this method. """ return self._tlsConnection def makeConnection(self, transport): """ Connect this wrapper to the given transport and initialize the necessary L{OpenSSL.SSL.Connection} with a memory BIO. """ tlsContext = self.factory._contextFactory.getContext() self._tlsConnection = Connection(tlsContext, None) if self.factory._isClient: self._tlsConnection.set_connect_state() else: self._tlsConnection.set_accept_state() self._appSendBuffer = [] # Add interfaces provided by the transport we are wrapping: for interface in providedBy(transport): directlyProvides(self, interface) # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) self.factory.registerProtocol(self) if self._connectWrapped: # Now that the TLS layer is initialized, notify the application of # the connection. ProtocolWrapper.makeConnection(self, transport) # Now that we ourselves have a transport (initialized by the # ProtocolWrapper.makeConnection call above), kick off the TLS # handshake. try: self._tlsConnection.do_handshake() except WantReadError: # This is the expected case - there's no data in the connection's # input buffer yet, so it won't be able to complete the whole # handshake now. If this is the speak-first side of the # connection, then some bytes will be in the send buffer now; flush # them. self._flushSendBIO() def _flushSendBIO(self): """ Read any bytes out of the send BIO and write them to the underlying transport. """ try: bytes = self._tlsConnection.bio_read(2 ** 15) except WantReadError: # There may be nothing in the send BIO right now. pass else: self.transport.write(bytes) def _flushReceiveBIO(self): """ Try to receive any application-level bytes which are now available because of a previous write into the receive BIO. This will take care of delivering any application-level bytes which are received to the protocol, as well as handling of the various exceptions which can come from trying to get such bytes. """ # Keep trying this until an error indicates we should stop or we # close the connection. Looping is necessary to make sure we # process all of the data which was put into the receive BIO, as # there is no guarantee that a single recv call will do it all. while not self._lostTLSConnection: try: bytes = self._tlsConnection.recv(2 ** 15) except WantReadError: # The newly received bytes might not have been enough to produce # any application data. break except ZeroReturnError: # TLS has shut down and no more TLS data will be received over # this connection. self._shutdownTLS() # Passing in None means the user protocol's connnectionLost # will get called with reason from underlying transport: self._tlsShutdownFinished(None) except Error as e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. # Squash EOF in violation of protocol into ConnectionLost; we # create Failure before calling _flushSendBio so that no new # exception will get thrown in the interim. if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': failure = Failure(CONNECTION_LOST) else: failure = Failure() self._flushSendBIO() self._tlsShutdownFinished(failure) else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. self._handshakeDone = True ProtocolWrapper.dataReceived(self, bytes) # The received bytes might have generated a response which needs to be # sent now. For example, the handshake involves several round-trip # exchanges without ever producing application-bytes. self._flushSendBIO() def dataReceived(self, bytes): """ Deliver any received bytes to the receive BIO and then read and deliver to the application any application-level data which becomes available as a result of this. """ self._tlsConnection.bio_write(bytes) if self._writeBlockedOnRead: # A read just happened, so we might not be blocked anymore. Try to # flush all the pending application bytes. self._writeBlockedOnRead = False appSendBuffer = self._appSendBuffer self._appSendBuffer = [] for bytes in appSendBuffer: self._write(bytes) if (not self._writeBlockedOnRead and self.disconnecting and self.producer is None): self._shutdownTLS() if self._producer is not None: self._producer.resumeProducing() self._flushReceiveBIO() def _shutdownTLS(self): """ Initiate, or reply to, the shutdown handshake of the TLS layer. """ shutdownSuccess = self._tlsConnection.shutdown() self._flushSendBIO() if shutdownSuccess: # Both sides have shutdown, so we can start closing lower-level # transport. This will also happen if we haven't started # negotiation at all yet, in which case shutdown succeeds # immediately. self.transport.loseConnection() def _tlsShutdownFinished(self, reason): """ Called when TLS connection has gone away; tell underlying transport to disconnect. """ self._reason = reason self._lostTLSConnection = True # Using loseConnection causes the application protocol's # connectionLost method to be invoked non-reentrantly, which is always # a nice feature. However, for error cases (reason != None) we might # want to use abortConnection when it becomes available. The # loseConnection call is basically tested by test_handshakeFailure. # At least one side will need to do it or the test never finishes. self.transport.loseConnection() def connectionLost(self, reason): """ Handle the possible repetition of calls to this method (due to either the underlying transport going away or due to an error at the TLS layer) and make sure the base implementation only gets invoked once. """ if not self._lostTLSConnection: # Tell the TLS connection that it's not going to get any more data # and give it a chance to finish reading. self._tlsConnection.bio_shutdown() self._flushReceiveBIO() self._lostTLSConnection = True reason = self._reason or reason self._reason = None ProtocolWrapper.connectionLost(self, reason) def loseConnection(self): """ Send a TLS close alert and close the underlying connection. """ if self.disconnecting: return self.disconnecting = True if not self._writeBlockedOnRead and self._producer is None: self._shutdownTLS() def write(self, bytes): """ Process the given application bytes and send any resulting TLS traffic which arrives in the send BIO. If C{loseConnection} was called, subsequent calls to C{write} will drop the bytes on the floor. """ if isinstance(bytes, unicode): raise TypeError("Must write bytes to a TLS transport, not unicode.") # Writes after loseConnection are not supported, unless a producer has # been registered, in which case writes can happen until the producer # is unregistered: if self.disconnecting and self._producer is None: return self._write(bytes) def _write(self, bytes): """ Process the given application bytes and send any resulting TLS traffic which arrives in the send BIO. This may be called by C{dataReceived} with bytes that were buffered before C{loseConnection} was called, which is why this function doesn't check for disconnection but accepts the bytes regardless. """ if self._lostTLSConnection: return leftToSend = bytes while leftToSend: try: sent = self._tlsConnection.send(leftToSend) except WantReadError: self._writeBlockedOnRead = True self._appSendBuffer.append(leftToSend) if self._producer is not None: self._producer.pauseProducing() break except Error: # Pretend TLS connection disconnected, which will trigger # disconnect of underlying transport. The error will be passed # to the application protocol's connectionLost method. The # other SSL implementation doesn't, but losing helpful # debugging information is a bad idea. self._tlsShutdownFinished(Failure()) break else: # If we sent some bytes, the handshake must be done. Keep # track of this to control error reporting behavior. self._handshakeDone = True self._flushSendBIO() leftToSend = leftToSend[sent:] def writeSequence(self, iovec): """ Write a sequence of application bytes by joining them into one string and passing them to L{write}. """ self.write(b"".join(iovec)) def getPeerCertificate(self): return self._tlsConnection.get_peer_certificate() def registerProducer(self, producer, streaming): # If we've already disconnected, nothing to do here: if self._lostTLSConnection: producer.stopProducing() return # If we received a non-streaming producer, wrap it so it becomes a # streaming producer: if not streaming: producer = streamingProducer = _PullToPush(producer, self) producer = _ProducerMembrane(producer) # This will raise an exception if a producer is already registered: self.transport.registerProducer(producer, True) self._producer = producer # If we received a non-streaming producer, we need to start the # streaming wrapper: if not streaming: streamingProducer.startStreaming() def unregisterProducer(self): # If we received a non-streaming producer, we need to stop the # streaming wrapper: if isinstance(self._producer._producer, _PullToPush): self._producer._producer.stopStreaming() self._producer = None self._producerPaused = False self.transport.unregisterProducer() if self.disconnecting and not self._writeBlockedOnRead: self._shutdownTLS()
class TLSMemoryBIOProtocol(ProtocolWrapper): """ L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a memory BIO to encrypt bytes written to it before sending them on to the underlying transport and decrypts bytes received from the underlying transport before delivering them to the wrapped protocol. In addition to producer events from the underlying transport, the need to wait for reads before a write can proceed means the L{TLSMemoryBIOProtocol} may also want to pause a producer. Pause/resume events are therefore merged using the L{_ProducerMembrane} wrapper. Non-streaming (pull) producers are supported by wrapping them with L{_PullToPush}. @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is encrypted and decrypting this connection. @ivar _lostTLSConnection: A flag indicating whether connection loss has already been dealt with (C{True}) or not (C{False}). TLS disconnection is distinct from the underlying connection being lost. @ivar _writeBlockedOnRead: A flag indicating whether further writing must wait for data to be received (C{True}) or not (C{False}). @ivar _appSendBuffer: A C{list} of C{str} of application-level (cleartext) data which is waiting for C{_writeBlockedOnRead} to be reset to C{False} so it can be passed to and perhaps accepted by C{_tlsConnection.send}. @ivar _connectWrapped: A flag indicating whether or not to call C{makeConnection} on the wrapped protocol. This is for the reactor's L{twisted.internet.interfaces.ITLSTransport.startTLS} implementation, since it has a protocol which it has already called C{makeConnection} on, and which has no interest in a new transport. See #3821. @ivar _handshakeDone: A flag indicating whether or not the handshake is known to have completed successfully (C{True}) or not (C{False}). This is used to control error reporting behavior. If the handshake has not completed, the underlying L{OpenSSL.SSL.Error} will be passed to the application's C{connectionLost} method. If it has completed, any unexpected L{OpenSSL.SSL.Error} will be turned into a L{ConnectionLost}. This is weird; however, it is simply an attempt at a faithful re-implementation of the behavior provided by L{twisted.internet.ssl}. @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes the connection to be lost, it is saved here. If appropriate, this may be used as the reason passed to the application protocol's C{connectionLost} method. @ivar _producer: The current producer registered via C{registerProducer}, or C{None} if no producer has been registered or a previous one was unregistered. """ implements(ISystemHandle, ISSLTransport) _reason = None _handshakeDone = False _lostTLSConnection = False _writeBlockedOnRead = False _producer = None def __init__(self, factory, wrappedProtocol, _connectWrapped=True): ProtocolWrapper.__init__(self, factory, wrappedProtocol) self._connectWrapped = _connectWrapped def getHandle(self): """ Return the L{OpenSSL.SSL.Connection} object being used to encrypt and decrypt this connection. This is done for the benefit of L{twisted.internet.ssl.Certificate}'s C{peerFromTransport} and C{hostFromTransport} methods only. A different system handle may be returned by future versions of this method. """ return self._tlsConnection def makeConnection(self, transport): """ Connect this wrapper to the given transport and initialize the necessary L{OpenSSL.SSL.Connection} with a memory BIO. """ tlsContext = self.factory._contextFactory.getContext() self._tlsConnection = Connection(tlsContext, None) if self.factory._isClient: self._tlsConnection.set_connect_state() else: self._tlsConnection.set_accept_state() self._appSendBuffer = [] # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) self.factory.registerProtocol(self) if self._connectWrapped: # Now that the TLS layer is initialized, notify the application of # the connection. ProtocolWrapper.makeConnection(self, transport) # Now that we ourselves have a transport (initialized by the # ProtocolWrapper.makeConnection call above), kick off the TLS # handshake. try: self._tlsConnection.do_handshake() except WantReadError: # This is the expected case - there's no data in the connection's # input buffer yet, so it won't be able to complete the whole # handshake now. If this is the speak-first side of the # connection, then some bytes will be in the send buffer now; flush # them. self._flushSendBIO() def _flushSendBIO(self): """ Read any bytes out of the send BIO and write them to the underlying transport. """ try: bytes = self._tlsConnection.bio_read(2 ** 15) except WantReadError: # There may be nothing in the send BIO right now. pass else: self.transport.write(bytes) def _flushReceiveBIO(self): """ Try to receive any application-level bytes which are now available because of a previous write into the receive BIO. This will take care of delivering any application-level bytes which are received to the protocol, as well as handling of the various exceptions which can come from trying to get such bytes. """ # Keep trying this until an error indicates we should stop or we # close the connection. Looping is necessary to make sure we # process all of the data which was put into the receive BIO, as # there is no guarantee that a single recv call will do it all. while not self._lostTLSConnection: try: bytes = self._tlsConnection.recv(2 ** 15) except WantReadError: # The newly received bytes might not have been enough to produce # any application data. break except ZeroReturnError: # TLS has shut down and no more TLS data will be received over # this connection. self._shutdownTLS() # Passing in None means the user protocol's connnectionLost # will get called with reason from underlying transport: self._tlsShutdownFinished(None) except Error, e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. # Squash EOF in violation of protocol into ConnectionLost; we # create Failure before calling _flushSendBio so that no new # exception will get thrown in the interim. if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': failure = Failure(CONNECTION_LOST) else: failure = Failure() self._flushSendBIO() self._tlsShutdownFinished(failure) else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. self._handshakeDone = True ProtocolWrapper.dataReceived(self, bytes) # The received bytes might have generated a response which needs to be # sent now. For example, the handshake involves several round-trip # exchanges without ever producing application-bytes. self._flushSendBIO()
class TLSMemoryBIOProtocol(ProtocolWrapper): """ L{TLSMemoryBIOProtocol} is a protocol wrapper which uses OpenSSL via a memory BIO to encrypt bytes written to it before sending them on to the underlying transport and decrypts bytes received from the underlying transport before delivering them to the wrapped protocol. In addition to producer events from the underlying transport, the need to wait for reads before a write can proceed means the L{TLSMemoryBIOProtocol} may also want to pause a producer. Pause/resume events are therefore merged using the L{_ProducerMembrane} wrapper. Non-streaming (pull) producers are supported by wrapping them with L{_PullToPush}. @ivar _tlsConnection: The L{OpenSSL.SSL.Connection} instance which is encrypted and decrypting this connection. @ivar _lostTLSConnection: A flag indicating whether connection loss has already been dealt with (C{True}) or not (C{False}). TLS disconnection is distinct from the underlying connection being lost. @ivar _writeBlockedOnRead: A flag indicating whether further writing must wait for data to be received (C{True}) or not (C{False}). @ivar _appSendBuffer: A C{list} of C{str} of application-level (cleartext) data which is waiting for C{_writeBlockedOnRead} to be reset to C{False} so it can be passed to and perhaps accepted by C{_tlsConnection.send}. @ivar _connectWrapped: A flag indicating whether or not to call C{makeConnection} on the wrapped protocol. This is for the reactor's L{twisted.internet.interfaces.ITLSTransport.startTLS} implementation, since it has a protocol which it has already called C{makeConnection} on, and which has no interest in a new transport. See #3821. @ivar _handshakeDone: A flag indicating whether or not the handshake is known to have completed successfully (C{True}) or not (C{False}). This is used to control error reporting behavior. If the handshake has not completed, the underlying L{OpenSSL.SSL.Error} will be passed to the application's C{connectionLost} method. If it has completed, any unexpected L{OpenSSL.SSL.Error} will be turned into a L{ConnectionLost}. This is weird; however, it is simply an attempt at a faithful re-implementation of the behavior provided by L{twisted.internet.ssl}. @ivar _reason: If an unexpected L{OpenSSL.SSL.Error} occurs which causes the connection to be lost, it is saved here. If appropriate, this may be used as the reason passed to the application protocol's C{connectionLost} method. @ivar _producer: The current producer registered via C{registerProducer}, or C{None} if no producer has been registered or a previous one was unregistered. """ implements(ISystemHandle, ISSLTransport) _reason = None _handshakeDone = False _lostTLSConnection = False _writeBlockedOnRead = False _producer = None def __init__(self, factory, wrappedProtocol, _connectWrapped=True): ProtocolWrapper.__init__(self, factory, wrappedProtocol) self._connectWrapped = _connectWrapped def getHandle(self): """ Return the L{OpenSSL.SSL.Connection} object being used to encrypt and decrypt this connection. This is done for the benefit of L{twisted.internet.ssl.Certificate}'s C{peerFromTransport} and C{hostFromTransport} methods only. A different system handle may be returned by future versions of this method. """ return self._tlsConnection def makeConnection(self, transport): """ Connect this wrapper to the given transport and initialize the necessary L{OpenSSL.SSL.Connection} with a memory BIO. """ tlsContext = self.factory._contextFactory.getContext() self._tlsConnection = Connection(tlsContext, None) if self.factory._isClient: self._tlsConnection.set_connect_state() else: self._tlsConnection.set_accept_state() self._appSendBuffer = [] # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) self.factory.registerProtocol(self) if self._connectWrapped: # Now that the TLS layer is initialized, notify the application of # the connection. ProtocolWrapper.makeConnection(self, transport) # Now that we ourselves have a transport (initialized by the # ProtocolWrapper.makeConnection call above), kick off the TLS # handshake. try: self._tlsConnection.do_handshake() except WantReadError: # This is the expected case - there's no data in the connection's # input buffer yet, so it won't be able to complete the whole # handshake now. If this is the speak-first side of the # connection, then some bytes will be in the send buffer now; flush # them. self._flushSendBIO() def _flushSendBIO(self): """ Read any bytes out of the send BIO and write them to the underlying transport. """ try: bytes = self._tlsConnection.bio_read(2**15) except WantReadError: # There may be nothing in the send BIO right now. pass else: self.transport.write(bytes) def _flushReceiveBIO(self): """ Try to receive any application-level bytes which are now available because of a previous write into the receive BIO. This will take care of delivering any application-level bytes which are received to the protocol, as well as handling of the various exceptions which can come from trying to get such bytes. """ # Keep trying this until an error indicates we should stop or we # close the connection. Looping is necessary to make sure we # process all of the data which was put into the receive BIO, as # there is no guarantee that a single recv call will do it all. while not self._lostTLSConnection: try: bytes = self._tlsConnection.recv(2**15) except WantReadError: # The newly received bytes might not have been enough to produce # any application data. break except ZeroReturnError: # TLS has shut down and no more TLS data will be received over # this connection. self._shutdownTLS() # Passing in None means the user protocol's connnectionLost # will get called with reason from underlying transport: self._tlsShutdownFinished(None) except Error, e: # Something went pretty wrong. For example, this might be a # handshake failure (because there were no shared ciphers, because # a certificate failed to verify, etc). TLS can no longer proceed. # Squash EOF in violation of protocol into ConnectionLost; we # create Failure before calling _flushSendBio so that no new # exception will get thrown in the interim. if e.args[0] == -1 and e.args[1] == 'Unexpected EOF': failure = Failure(CONNECTION_LOST) else: failure = Failure() self._flushSendBIO() self._tlsShutdownFinished(failure) else: # If we got application bytes, the handshake must be done by # now. Keep track of this to control error reporting later. self._handshakeDone = True ProtocolWrapper.dataReceived(self, bytes) # The received bytes might have generated a response which needs to be # sent now. For example, the handshake involves several round-trip # exchanges without ever producing application-bytes. self._flushSendBIO()