def _pick_certificate_cb(self, connection: SSL.Connection) -> None: """SNI certificate callback. This method will set a new OpenSSL context object for this connection when an incoming connection provides an SNI name (in order to serve the appropriate certificate, if any). :param connection: The TLS connection object on which the SNI extension was received. :type connection: :class:`OpenSSL.Connection` """ pair = self.cert_selection(connection) if pair is None: logger.debug( "Certificate selection for server name %s failed, dropping SSL", connection.get_servername()) return key, cert = pair new_context = SSL.Context(self.method) new_context.set_options(SSL.OP_NO_SSLv2) new_context.set_options(SSL.OP_NO_SSLv3) new_context.use_privatekey(key) new_context.use_certificate(cert) if self.alpn_selection is not None: new_context.set_alpn_select_callback(self.alpn_selection) connection.set_context(new_context)
def __call__( self, connection: SSL.Connection ) -> Optional[Tuple[crypto.PKey, crypto.X509]]: server_name = connection.get_servername() if server_name: return self.certs.get(server_name, None) return None # pragma: no cover
def _cert_selection( self, connection: SSL.Connection ) -> Optional[Tuple[crypto.PKey, crypto.X509]]: # pragma: no cover """Callback selecting certificate for connection.""" server_name = connection.get_servername() if server_name: return self.certs.get(server_name, None) return None
def _cert_selection(self, connection: SSL.Connection) -> Tuple[crypto.PKey, crypto.X509]: # TODO: We would like to serve challenge cert only if asked for it via # ALPN. To do this, we need to retrieve the list of protos from client # hello, but this is currently impossible with openssl [0], and ALPN # negotiation is done after cert selection. # Therefore, currently we always return challenge cert, and terminate # handshake in alpn_selection() if ALPN protos are not what we expect. # [0] https://github.com/openssl/openssl/issues/4952 server_name = connection.get_servername() logger.debug("Serving challenge cert for server name %s", server_name) return self.challenge_certs[server_name]
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()