Foundations of Python Network Programming

(WallPaper) #1
Chapter 6 ■ tLS/SSL

109

for category, count in sorted(context.cert_store_stats().items()):
say('Certificates loaded of type {}'.format(category), count)


try:
protocol_version = SSL_get_version(ssl_sock)
except Exception:
if debug:
raise
else:
say('Protocol version negotiated', protocol_version)


cipher, version, bits = ssl_sock.cipher()
compression = ssl_sock.compression()


say('Cipher chosen for this connection', cipher)
say('Cipher defined in TLS version', version)
say('Cipher key has this many bits', bits)
say('Compression algorithm in use', compression or 'none')


return cert


class PySSLSocket(ctypes.Structure):
"""The first few fields of a PySSLSocket (see Python's Modules/_ssl.c)."""


fields = [('ob_refcnt', ctypes.c_ulong), ('ob_type', ctypes.c_void_p),
('Socket', ctypes.c_void_p), ('ssl', ctypes.c_void_p)]


def SSL_get_version(ssl_sock):
"""Reach behind the scenes for a socket's TLS protocol version."""


lib = ctypes.CDLL(ssl._ssl.file)
lib.SSL_get_version.restype = ctypes.c_char_p
address = id(ssl_sock._sslobj)
struct = ctypes.cast(address, ctypes.POINTER(PySSLSocket)).contents
version_bytestring = lib.SSL_get_version(struct.ssl)
return version_bytestring.decode('ascii')


def lookup(prefix, name):
if not name.startswith(prefix):
name = prefix + name
try:
return getattr(ssl, name)
except AttributeError:
matching_names = (s for s in dir(ssl) if s.startswith(prefix))
message = 'Error: {!r} is not one of the available names:\n {}'.format(
name, ' '.join(sorted(matching_names)))
print(fill(message), file=sys.stderr)
sys.exit(2)


def say(title, *words):
print(fill(title.ljust(36, '.') + ' ' + ' '.join(str(w) for w in words)))


def fill(text):
return textwrap.fill(text, subsequent_indent=' ',
break_long_words=False, break_on_hyphens=False)

Free download pdf