Chapter 6 ■ tLS/SSL
10 0
while True:
data = ssl_sock.recv(1024)
if not data:
break
print(repr(data))
def server(host, port, certfile, cafile=None):
purpose = ssl.Purpose.CLIENT_AUTH
context = ssl.create_default_context(purpose, cafile=cafile)
context.load_cert_chain(certfile)
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listener.bind((host, port))
listener.listen(1)
print('Listening at interface {!r} and port {}'.format(host, port))
raw_sock, address = listener.accept()
print('Connection from host {!r} and port {}'.format(*address))
ssl_sock = context.wrap_socket(raw_sock, server_side=True)
ssl_sock.sendall('Simple is better than complex.'.encode('ascii'))
ssl_sock.close()
if name == 'main':
parser = argparse.ArgumentParser(description='Safe TLS client and server')
parser.add_argument('host', help='hostname or IP address')
parser.add_argument('port', type=int, help='TCP port number')
parser.add_argument('-a', metavar='cafile', default=None,
help='authority: path to CA certificate PEM file')
parser.add_argument('-s', metavar='certfile', default=None,
help='run as server: path to server PEM file')
args = parser.parse_args()
if args.s:
server(args.host, args.port, args.s, args.a)
else:
client(args.host, args.port, args.a)
You can see in the listing that securing a socket requires only three steps. First, create a TLS context object that
knows all of your preferences regarding certificate validation and choice of cipher. Second, use the context’s wrap_
socket() method to let the OpenSSL library take control of your TCP connection, exchange the necessary greetings
with the other end, and set up an encrypted channel. Finally, perform all further communication with the ssl_sock
that has been returned to you so that the TLS layer always has the chance to encrypt your data before it actually hits
the wire. This wrapper, you will note, offers all of the same methods as a normal socket, such as send() and recv()
and close() that you learned about from your experience with normal TCP sockets in Chapter 3.
The choice of whether you are creating a context for a client trying to verify the server to which it connects
(Purpose.SERVER_AUTH) or of a server needing to accept client connections (Purpose.CLIENT_AUTH) affects several
settings in the new context that is returned. The theory behind having two different sets of settings is the guess, on the
part of the Standard Library authors, that you want TLS clients to be a bit forgiving about older ciphers because they
will sometimes find themselves connecting to servers that are outside of your control and might be a bit