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 | |
| 4 | if __name__ == '__main__': |
| 5 | import server |
| 6 | raise SystemExit(server.main()) |
| 7 | |
| 8 | from sys import stdout |
| 9 | from socket import SOL_SOCKET, SO_REUSEADDR, socket |
| 10 | |
| 11 | from OpenSSL.crypto import FILETYPE_PEM, load_privatekey, load_certificate |
| 12 | from OpenSSL.SSL import TLSv1_METHOD, Context, Connection |
| 13 | |
| 14 | def load(domain): |
| 15 | crt = open(domain + ".crt") |
| 16 | key = open(domain + ".key") |
| 17 | result = ( |
| 18 | load_privatekey(FILETYPE_PEM, key.read()), |
| 19 | load_certificate(FILETYPE_PEM, crt.read())) |
| 20 | crt.close() |
| 21 | key.close() |
| 22 | return result |
| 23 | |
| 24 | |
| 25 | def main(): |
| 26 | """ |
| 27 | Run an SNI-enabled server which selects between a few certificates in a |
| 28 | C{dict} based on the handshake request it receives from a client. |
| 29 | """ |
| 30 | port = socket() |
| 31 | port.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) |
| 32 | port.bind(('', 8443)) |
| 33 | port.listen(3) |
| 34 | |
| 35 | print 'Accepting...', |
| 36 | stdout.flush() |
| 37 | server, addr = port.accept() |
| 38 | print 'accepted', addr |
| 39 | |
| 40 | server_context = Context(TLSv1_METHOD) |
| 41 | server_context.set_tlsext_servername_callback(pick_certificate) |
| 42 | |
| 43 | server_ssl = Connection(server_context, server) |
| 44 | server_ssl.set_accept_state() |
| 45 | server_ssl.do_handshake() |
| 46 | server.close() |
| 47 | |
| 48 | |
| 49 | certificates = { |
| 50 | "example.invalid": load("example.invalid"), |
| 51 | "another.invalid": load("another.invalid"), |
| 52 | } |
| 53 | |
| 54 | |
| 55 | def pick_certificate(connection): |
| 56 | try: |
| 57 | key, cert = certificates[connection.get_servername()] |
| 58 | except KeyError: |
| 59 | pass |
| 60 | else: |
| 61 | new_context = Context(TLSv1_METHOD) |
| 62 | new_context.use_privatekey(key) |
| 63 | new_context.use_certificate(cert) |
| 64 | connection.set_context(new_context) |