Jean-Paul Calderone | 7fb6b21 | 2011-06-06 08:31:28 -0400 | [diff] [blame] | 1 | # Copyright (C) Jean-Paul Calderone |
| 2 | # See LICENSE for details. |
| 3 | |
Alex Gaynor | ca749b5 | 2019-02-10 17:23:19 -0500 | [diff] [blame] | 4 | from __future__ import print_function |
| 5 | |
Jean-Paul Calderone | 7fb6b21 | 2011-06-06 08:31:28 -0400 | [diff] [blame] | 6 | from sys import stdout |
| 7 | from socket import SOL_SOCKET, SO_REUSEADDR, socket |
| 8 | |
| 9 | from OpenSSL.crypto import FILETYPE_PEM, load_privatekey, load_certificate |
| 10 | from OpenSSL.SSL import TLSv1_METHOD, Context, Connection |
| 11 | |
Hynek Schlawack | 8b7e455 | 2016-03-13 07:51:09 +0100 | [diff] [blame] | 12 | |
Jean-Paul Calderone | 7fb6b21 | 2011-06-06 08:31:28 -0400 | [diff] [blame] | 13 | def load(domain): |
| 14 | crt = open(domain + ".crt") |
| 15 | key = open(domain + ".key") |
| 16 | result = ( |
| 17 | load_privatekey(FILETYPE_PEM, key.read()), |
| 18 | load_certificate(FILETYPE_PEM, crt.read())) |
| 19 | crt.close() |
| 20 | key.close() |
| 21 | return result |
| 22 | |
| 23 | |
| 24 | def main(): |
| 25 | """ |
| 26 | Run an SNI-enabled server which selects between a few certificates in a |
| 27 | C{dict} based on the handshake request it receives from a client. |
| 28 | """ |
| 29 | port = socket() |
| 30 | port.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) |
| 31 | port.bind(('', 8443)) |
| 32 | port.listen(3) |
| 33 | |
Alex Gaynor | ca749b5 | 2019-02-10 17:23:19 -0500 | [diff] [blame] | 34 | print('Accepting...', end="") |
Jean-Paul Calderone | 7fb6b21 | 2011-06-06 08:31:28 -0400 | [diff] [blame] | 35 | stdout.flush() |
| 36 | server, addr = port.accept() |
Alex Gaynor | ca749b5 | 2019-02-10 17:23:19 -0500 | [diff] [blame] | 37 | print('accepted', addr) |
Jean-Paul Calderone | 7fb6b21 | 2011-06-06 08:31:28 -0400 | [diff] [blame] | 38 | |
| 39 | server_context = Context(TLSv1_METHOD) |
| 40 | server_context.set_tlsext_servername_callback(pick_certificate) |
| 41 | |
| 42 | server_ssl = Connection(server_context, server) |
| 43 | server_ssl.set_accept_state() |
| 44 | server_ssl.do_handshake() |
| 45 | server.close() |
| 46 | |
| 47 | |
| 48 | certificates = { |
| 49 | "example.invalid": load("example.invalid"), |
| 50 | "another.invalid": load("another.invalid"), |
Hynek Schlawack | 8b7e455 | 2016-03-13 07:51:09 +0100 | [diff] [blame] | 51 | } |
Jean-Paul Calderone | 7fb6b21 | 2011-06-06 08:31:28 -0400 | [diff] [blame] | 52 | |
| 53 | |
| 54 | def pick_certificate(connection): |
| 55 | try: |
| 56 | key, cert = certificates[connection.get_servername()] |
| 57 | except KeyError: |
| 58 | pass |
| 59 | else: |
| 60 | new_context = Context(TLSv1_METHOD) |
| 61 | new_context.use_privatekey(key) |
| 62 | new_context.use_certificate(cert) |
| 63 | connection.set_context(new_context) |
Hynek Schlawack | 8b7e455 | 2016-03-13 07:51:09 +0100 | [diff] [blame] | 64 | |
| 65 | |
| 66 | if __name__ == '__main__': |
| 67 | raise SystemExit(main()) |