class SNIMap(object): def __init__(self, mapping): self.mapping = mapping self._negotiationDataForContext = collections.defaultdict( _NegotiationData ) try: self.context = self.mapping['DEFAULT'].getContext() except KeyError: self.context = CertificateOptions().getContext() self.context.set_tlsext_servername_callback( self.selectContext ) def selectContext(self, connection): oldContext = connection.get_context() newContext = self.mapping[connection.get_servername()].getContext() negotiationData = self._negotiationDataForContext[oldContext] negotiationData.negotiateNPN(newContext) negotiationData.negotiateALPN(newContext) connection.set_context(newContext) def serverConnectionForTLS(self, protocol): """ Construct an OpenSSL server connection. @param protocol: The protocol initiating a TLS connection. @type protocol: L{TLSMemoryBIOProtocol} @return: a connection @rtype: L{OpenSSL.SSL.Connection} """ conn = Connection(self.context, None) return _ConnectionProxy(conn, self) def _npnAdvertiseCallbackForContext(self, context, callback): self._negotiationDataForContext[context].npnAdvertiseCallback = ( callback ) def _npnSelectCallbackForContext(self, context, callback): self._negotiationDataForContext[context].npnSelectCallback = callback def _alpnSelectCallbackForContext(self, context, callback): self._negotiationDataForContext[context].alpnSelectCallback = callback def _alpnProtocolsForContext(self, context, protocols): self._negotiationDataForContext[context].alpnProtocols = protocols
class SNIMap(object): def __init__(self, mapping): self.mapping = mapping self._negotiationDataForContext = collections.defaultdict( _NegotiationData ) try: self.context = self.mapping['DEFAULT'].getContext() except KeyError: self.context = CertificateOptions().getContext() self.context.set_tlsext_servername_callback( self.selectContext ) def selectContext(self, connection): oldContext = connection.get_context() newContext = self.mapping[connection.get_servername()].getContext() negotiationData = self._negotiationDataForContext[oldContext] negotiationData.negotiateNPN(newContext) negotiationData.negotiateALPN(newContext) connection.set_context(newContext) def serverConnectionForTLS(self, protocol): """ Construct an OpenSSL server connection. @param protocol: The protocol initiating a TLS connection. @type protocol: L{TLSMemoryBIOProtocol} @return: a connection @rtype: L{OpenSSL.SSL.Connection} """ conn = Connection(self.context, None) return _ConnectionProxy(conn, self) def _npnAdvertiseCallbackForContext(self, context, callback): self._negotiationDataForContext[context].npnAdvertiseCallback = ( callback ) def _npnSelectCallbackForContext(self, context, callback): self._negotiationDataForContext[context].npnSelectCallback = callback def _alpnSelectCallbackForContext(self, context, callback): self._negotiationDataForContext[context].alpnSelectCallback = callback def _alpnProtocolsForContext(self, context, protocols): self._negotiationDataForContext[context].alpnProtocols = protocols
class SNIMap(ContextFactory, object): def __init__(self, mapping): self.mapping = mapping try: self.context = self.mapping['DEFAULT'].getContext() except KeyError: self.context = CertificateOptions().getContext() self.context.set_tlsext_servername_callback( self.selectContext ) def getContext(self): return self.context def selectContext(self, connection): connection.set_context( self.mapping[connection.get_servername()] .getContext() )
class SNIMap(object): def __init__(self, mapping, acme_mapping=None): self.mapping = mapping self.acme_mapping = acme_mapping self._negotiationDataForContext = collections.defaultdict( _NegotiationData) try: self.context = self.mapping['DEFAULT'].getContext() except KeyError: self.context = CertificateOptions().getContext() self.context.set_tlsext_servername_callback(self.selectContext) def selectAlpn(self, default, connection, protocols): """ Trap alpn negotation, possibly intervene to choose a new certificate or protocol. Needs to happen after servername. Acme works by sending a special certificate based on this negotiation. If such a certificate exists in self.acme_mapping, we will respond. The acme protocol doesn't need to send or receive other data. """ ACME_TLS_1 = b'acme-tls/1' if not ACME_TLS_1 in protocols or not self.acme_mapping: return default() self.selectContext(connection, mapping=self.acme_mapping) # does this mess up 'normal' connections to the same context? # is this really a context from a separate directory? connection.get_context().set_alpn_protos([ACME_TLS_1]) return ACME_TLS_1 def selectContext(self, connection, mapping=None): mapping = mapping or self.mapping oldContext = connection.get_context() newContext = mapping[connection.get_servername()].getContext() negotiationData = self._negotiationDataForContext[oldContext] negotiationData.negotiateNPN(newContext) negotiationData.negotiateALPN(newContext) connection.set_context(newContext) def serverConnectionForTLS(self, protocol): """ Construct an OpenSSL server connection. @param protocol: The protocol initiating a TLS connection. @type protocol: L{TLSMemoryBIOProtocol} @return: a connection @rtype: L{OpenSSL.SSL.Connection} """ conn = Connection(self.context, None) return _ConnectionProxy(conn, self) def _npnAdvertiseCallbackForContext(self, context, callback): self._negotiationDataForContext[context].npnAdvertiseCallback = ( callback) def _npnSelectCallbackForContext(self, context, callback): self._negotiationDataForContext[context].npnSelectCallback = callback def _alpnSelectCallbackForContext(self, context, callback): self._negotiationDataForContext[context].alpnSelectCallback = callback def _alpnProtocolsForContext(self, context, protocols): self._negotiationDataForContext[context].alpnProtocols = protocols