summaryrefslogtreecommitdiffstats
path: root/src/lib/tlslite/integration
diff options
context:
space:
mode:
authorNarayan Desai <desai@mcs.anl.gov>2007-03-12 16:22:51 +0000
committerNarayan Desai <desai@mcs.anl.gov>2007-03-12 16:22:51 +0000
commit6e5e9c8e969207e68665f12665a54768090897e4 (patch)
treede198777d5041073db4634a24ca37efad2a1017f /src/lib/tlslite/integration
parentac3eb44f16bc14e41ed62169ca36e9992509d7d6 (diff)
downloadbcfg2-6e5e9c8e969207e68665f12665a54768090897e4.tar.gz
bcfg2-6e5e9c8e969207e68665f12665a54768090897e4.tar.bz2
bcfg2-6e5e9c8e969207e68665f12665a54768090897e4.zip
Merged in certs branch in preparation for 0.9.3pre2
git-svn-id: https://svn.mcs.anl.gov/repos/bcfg/trunk/bcfg2@2928 ce84e21b-d406-0410-9b95-82705330c041
Diffstat (limited to 'src/lib/tlslite/integration')
-rwxr-xr-xsrc/lib/tlslite/integration/AsyncStateMachine.py235
-rwxr-xr-xsrc/lib/tlslite/integration/ClientHelper.py163
-rwxr-xr-xsrc/lib/tlslite/integration/HTTPTLSConnection.py169
-rwxr-xr-xsrc/lib/tlslite/integration/IMAP4_TLS.py132
-rwxr-xr-xsrc/lib/tlslite/integration/IntegrationHelper.py52
-rwxr-xr-xsrc/lib/tlslite/integration/POP3_TLS.py142
-rwxr-xr-xsrc/lib/tlslite/integration/SMTP_TLS.py114
-rwxr-xr-xsrc/lib/tlslite/integration/TLSAsyncDispatcherMixIn.py139
-rwxr-xr-xsrc/lib/tlslite/integration/TLSSocketServerMixIn.py59
-rwxr-xr-xsrc/lib/tlslite/integration/TLSTwistedProtocolWrapper.py196
-rwxr-xr-xsrc/lib/tlslite/integration/XMLRPCTransport.py137
-rwxr-xr-xsrc/lib/tlslite/integration/__init__.py17
12 files changed, 1555 insertions, 0 deletions
diff --git a/src/lib/tlslite/integration/AsyncStateMachine.py b/src/lib/tlslite/integration/AsyncStateMachine.py
new file mode 100755
index 000000000..abed60432
--- /dev/null
+++ b/src/lib/tlslite/integration/AsyncStateMachine.py
@@ -0,0 +1,235 @@
+"""
+A state machine for using TLS Lite with asynchronous I/O.
+"""
+
+class AsyncStateMachine:
+ """
+ This is an abstract class that's used to integrate TLS Lite with
+ asyncore and Twisted.
+
+ This class signals wantsReadsEvent() and wantsWriteEvent(). When
+ the underlying socket has become readable or writeable, the event
+ should be passed to this class by calling inReadEvent() or
+ inWriteEvent(). This class will then try to read or write through
+ the socket, and will update its state appropriately.
+
+ This class will forward higher-level events to its subclass. For
+ example, when a complete TLS record has been received,
+ outReadEvent() will be called with the decrypted data.
+ """
+
+ def __init__(self):
+ self._clear()
+
+ def _clear(self):
+ #These store the various asynchronous operations (i.e.
+ #generators). Only one of them, at most, is ever active at a
+ #time.
+ self.handshaker = None
+ self.closer = None
+ self.reader = None
+ self.writer = None
+
+ #This stores the result from the last call to the
+ #currently active operation. If 0 it indicates that the
+ #operation wants to read, if 1 it indicates that the
+ #operation wants to write. If None, there is no active
+ #operation.
+ self.result = None
+
+ def _checkAssert(self, maxActive=1):
+ #This checks that only one operation, at most, is
+ #active, and that self.result is set appropriately.
+ activeOps = 0
+ if self.handshaker:
+ activeOps += 1
+ if self.closer:
+ activeOps += 1
+ if self.reader:
+ activeOps += 1
+ if self.writer:
+ activeOps += 1
+
+ if self.result == None:
+ if activeOps != 0:
+ raise AssertionError()
+ elif self.result in (0,1):
+ if activeOps != 1:
+ raise AssertionError()
+ else:
+ raise AssertionError()
+ if activeOps > maxActive:
+ raise AssertionError()
+
+ def wantsReadEvent(self):
+ """If the state machine wants to read.
+
+ If an operation is active, this returns whether or not the
+ operation wants to read from the socket. If an operation is
+ not active, this returns None.
+
+ @rtype: bool or None
+ @return: If the state machine wants to read.
+ """
+ if self.result != None:
+ return self.result == 0
+ return None
+
+ def wantsWriteEvent(self):
+ """If the state machine wants to write.
+
+ If an operation is active, this returns whether or not the
+ operation wants to write to the socket. If an operation is
+ not active, this returns None.
+
+ @rtype: bool or None
+ @return: If the state machine wants to write.
+ """
+ if self.result != None:
+ return self.result == 1
+ return None
+
+ def outConnectEvent(self):
+ """Called when a handshake operation completes.
+
+ May be overridden in subclass.
+ """
+ pass
+
+ def outCloseEvent(self):
+ """Called when a close operation completes.
+
+ May be overridden in subclass.
+ """
+ pass
+
+ def outReadEvent(self, readBuffer):
+ """Called when a read operation completes.
+
+ May be overridden in subclass."""
+ pass
+
+ def outWriteEvent(self):
+ """Called when a write operation completes.
+
+ May be overridden in subclass."""
+ pass
+
+ def inReadEvent(self):
+ """Tell the state machine it can read from the socket."""
+ try:
+ self._checkAssert()
+ if self.handshaker:
+ self._doHandshakeOp()
+ elif self.closer:
+ self._doCloseOp()
+ elif self.reader:
+ self._doReadOp()
+ elif self.writer:
+ self._doWriteOp()
+ else:
+ self.reader = self.tlsConnection.readAsync(16384)
+ self._doReadOp()
+ except:
+ self._clear()
+ raise
+
+ def inWriteEvent(self):
+ """Tell the state machine it can write to the socket."""
+ try:
+ self._checkAssert()
+ if self.handshaker:
+ self._doHandshakeOp()
+ elif self.closer:
+ self._doCloseOp()
+ elif self.reader:
+ self._doReadOp()
+ elif self.writer:
+ self._doWriteOp()
+ else:
+ self.outWriteEvent()
+ except:
+ self._clear()
+ raise
+
+ def _doHandshakeOp(self):
+ try:
+ self.result = self.handshaker.next()
+ except StopIteration:
+ self.handshaker = None
+ self.result = None
+ self.outConnectEvent()
+
+ def _doCloseOp(self):
+ try:
+ self.result = self.closer.next()
+ except StopIteration:
+ self.closer = None
+ self.result = None
+ self.outCloseEvent()
+
+ def _doReadOp(self):
+ self.result = self.reader.next()
+ if not self.result in (0,1):
+ readBuffer = self.result
+ self.reader = None
+ self.result = None
+ self.outReadEvent(readBuffer)
+
+ def _doWriteOp(self):
+ try:
+ self.result = self.writer.next()
+ except StopIteration:
+ self.writer = None
+ self.result = None
+
+ def setHandshakeOp(self, handshaker):
+ """Start a handshake operation.
+
+ @type handshaker: generator
+ @param handshaker: A generator created by using one of the
+ asynchronous handshake functions (i.e. handshakeServerAsync, or
+ handshakeClientxxx(..., async=True).
+ """
+ try:
+ self._checkAssert(0)
+ self.handshaker = handshaker
+ self._doHandshakeOp()
+ except:
+ self._clear()
+ raise
+
+ def setServerHandshakeOp(self, **args):
+ """Start a handshake operation.
+
+ The arguments passed to this function will be forwarded to
+ L{tlslite.TLSConnection.TLSConnection.handshakeServerAsync}.
+ """
+ handshaker = self.tlsConnection.handshakeServerAsync(**args)
+ self.setHandshakeOp(handshaker)
+
+ def setCloseOp(self):
+ """Start a close operation.
+ """
+ try:
+ self._checkAssert(0)
+ self.closer = self.tlsConnection.closeAsync()
+ self._doCloseOp()
+ except:
+ self._clear()
+ raise
+
+ def setWriteOp(self, writeBuffer):
+ """Start a write operation.
+
+ @type writeBuffer: str
+ @param writeBuffer: The string to transmit.
+ """
+ try:
+ self._checkAssert(0)
+ self.writer = self.tlsConnection.writeAsync(writeBuffer)
+ self._doWriteOp()
+ except:
+ self._clear()
+ raise
+
diff --git a/src/lib/tlslite/integration/ClientHelper.py b/src/lib/tlslite/integration/ClientHelper.py
new file mode 100755
index 000000000..6de4ab7a0
--- /dev/null
+++ b/src/lib/tlslite/integration/ClientHelper.py
@@ -0,0 +1,163 @@
+"""
+A helper class for using TLS Lite with stdlib clients
+(httplib, xmlrpclib, imaplib, poplib).
+"""
+
+from Bcfg2.tlslite.Checker import Checker
+
+class ClientHelper:
+ """This is a helper class used to integrate TLS Lite with various
+ TLS clients (e.g. poplib, smtplib, httplib, etc.)"""
+
+ def __init__(self,
+ username=None, password=None, sharedKey=None,
+ certChain=None, privateKey=None,
+ cryptoID=None, protocol=None,
+ x509Fingerprint=None,
+ x509TrustList=None, x509CommonName=None,
+ settings = None):
+ """
+ For client authentication, use one of these argument
+ combinations:
+ - username, password (SRP)
+ - username, sharedKey (shared-key)
+ - certChain, privateKey (certificate)
+
+ For server authentication, you can either rely on the
+ implicit mutual authentication performed by SRP or
+ shared-keys, or you can do certificate-based server
+ authentication with one of these argument combinations:
+ - cryptoID[, protocol] (requires cryptoIDlib)
+ - x509Fingerprint
+ - x509TrustList[, x509CommonName] (requires cryptlib_py)
+
+ Certificate-based server authentication is compatible with
+ SRP or certificate-based client authentication. It is
+ not compatible with shared-keys.
+
+ The constructor does not perform the TLS handshake itself, but
+ simply stores these arguments for later. The handshake is
+ performed only when this class needs to connect with the
+ server. Then you should be prepared to handle TLS-specific
+ exceptions. See the client handshake functions in
+ L{tlslite.TLSConnection.TLSConnection} for details on which
+ exceptions might be raised.
+
+ @type username: str
+ @param username: SRP or shared-key username. Requires the
+ 'password' or 'sharedKey' argument.
+
+ @type password: str
+ @param password: SRP password for mutual authentication.
+ Requires the 'username' argument.
+
+ @type sharedKey: str
+ @param sharedKey: Shared key for mutual authentication.
+ Requires the 'username' argument.
+
+ @type certChain: L{tlslite.X509CertChain.X509CertChain} or
+ L{cryptoIDlib.CertChain.CertChain}
+ @param certChain: Certificate chain for client authentication.
+ Requires the 'privateKey' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
+ @param privateKey: Private key for client authentication.
+ Requires the 'certChain' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type cryptoID: str
+ @param cryptoID: cryptoID for server authentication. Mutually
+ exclusive with the 'x509...' arguments.
+
+ @type protocol: str
+ @param protocol: cryptoID protocol URI for server
+ authentication. Requires the 'cryptoID' argument.
+
+ @type x509Fingerprint: str
+ @param x509Fingerprint: Hex-encoded X.509 fingerprint for
+ server authentication. Mutually exclusive with the 'cryptoID'
+ and 'x509TrustList' arguments.
+
+ @type x509TrustList: list of L{tlslite.X509.X509}
+ @param x509TrustList: A list of trusted root certificates. The
+ other party must present a certificate chain which extends to
+ one of these root certificates. The cryptlib_py module must be
+ installed to use this parameter. Mutually exclusive with the
+ 'cryptoID' and 'x509Fingerprint' arguments.
+
+ @type x509CommonName: str
+ @param x509CommonName: The end-entity certificate's 'CN' field
+ must match this value. For a web server, this is typically a
+ server name such as 'www.amazon.com'. Mutually exclusive with
+ the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
+ 'x509TrustList' argument.
+
+ @type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
+ @param settings: Various settings which can be used to control
+ the ciphersuites, certificate types, and SSL/TLS versions
+ offered by the client.
+ """
+
+ self.username = None
+ self.password = None
+ self.sharedKey = None
+ self.certChain = None
+ self.privateKey = None
+ self.checker = None
+
+ #SRP Authentication
+ if username and password and not \
+ (sharedKey or certChain or privateKey):
+ self.username = username
+ self.password = password
+
+ #Shared Key Authentication
+ elif username and sharedKey and not \
+ (password or certChain or privateKey):
+ self.username = username
+ self.sharedKey = sharedKey
+
+ #Certificate Chain Authentication
+ elif certChain and privateKey and not \
+ (username or password or sharedKey):
+ self.certChain = certChain
+ self.privateKey = privateKey
+
+ #No Authentication
+ elif not password and not username and not \
+ sharedKey and not certChain and not privateKey:
+ pass
+
+ else:
+ raise ValueError("Bad parameters")
+
+ #Authenticate the server based on its cryptoID or fingerprint
+ if sharedKey and (cryptoID or protocol or x509Fingerprint):
+ raise ValueError("Can't use shared keys with other forms of"\
+ "authentication")
+
+ self.checker = Checker(cryptoID, protocol, x509Fingerprint,
+ x509TrustList, x509CommonName)
+ self.settings = settings
+
+ self.tlsSession = None
+
+ def _handshake(self, tlsConnection):
+ if self.username and self.password:
+ tlsConnection.handshakeClientSRP(username=self.username,
+ password=self.password,
+ checker=self.checker,
+ settings=self.settings,
+ session=self.tlsSession)
+ elif self.username and self.sharedKey:
+ tlsConnection.handshakeClientSharedKey(username=self.username,
+ sharedKey=self.sharedKey,
+ settings=self.settings)
+ else:
+ tlsConnection.handshakeClientCert(certChain=self.certChain,
+ privateKey=self.privateKey,
+ checker=self.checker,
+ settings=self.settings,
+ session=self.tlsSession)
+ self.tlsSession = tlsConnection.session
diff --git a/src/lib/tlslite/integration/HTTPTLSConnection.py b/src/lib/tlslite/integration/HTTPTLSConnection.py
new file mode 100755
index 000000000..a20400893
--- /dev/null
+++ b/src/lib/tlslite/integration/HTTPTLSConnection.py
@@ -0,0 +1,169 @@
+"""TLS Lite + httplib."""
+
+import socket
+import httplib
+from Bcfg2.tlslite.TLSConnection import TLSConnection
+from Bcfg2.tlslite.integration.ClientHelper import ClientHelper
+
+
+class HTTPBaseTLSConnection(httplib.HTTPConnection):
+ """This abstract class provides a framework for adding TLS support
+ to httplib."""
+
+ default_port = 443
+
+ def __init__(self, host, port=None, strict=None):
+ if strict == None:
+ #Python 2.2 doesn't support strict
+ httplib.HTTPConnection.__init__(self, host, port)
+ else:
+ httplib.HTTPConnection.__init__(self, host, port, strict)
+
+ def connect(self):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ if hasattr(sock, 'settimeout'):
+ sock.settimeout(10)
+ sock.connect((self.host, self.port))
+
+ #Use a TLSConnection to emulate a socket
+ self.sock = TLSConnection(sock)
+
+ #When httplib closes this, close the socket
+ self.sock.closeSocket = True
+ self._handshake(self.sock)
+
+ def _handshake(self, tlsConnection):
+ """Called to perform some sort of handshake.
+
+ This method must be overridden in a subclass to do some type of
+ handshake. This method will be called after the socket has
+ been connected but before any data has been sent. If this
+ method does not raise an exception, the TLS connection will be
+ considered valid.
+
+ This method may (or may not) be called every time an HTTP
+ request is performed, depending on whether the underlying HTTP
+ connection is persistent.
+
+ @type tlsConnection: L{tlslite.TLSConnection.TLSConnection}
+ @param tlsConnection: The connection to perform the handshake
+ on.
+ """
+ raise NotImplementedError()
+
+
+class HTTPTLSConnection(HTTPBaseTLSConnection, ClientHelper):
+ """This class extends L{HTTPBaseTLSConnection} to support the
+ common types of handshaking."""
+
+ def __init__(self, host, port=None,
+ username=None, password=None, sharedKey=None,
+ certChain=None, privateKey=None,
+ cryptoID=None, protocol=None,
+ x509Fingerprint=None,
+ x509TrustList=None, x509CommonName=None,
+ settings = None):
+ """Create a new HTTPTLSConnection.
+
+ For client authentication, use one of these argument
+ combinations:
+ - username, password (SRP)
+ - username, sharedKey (shared-key)
+ - certChain, privateKey (certificate)
+
+ For server authentication, you can either rely on the
+ implicit mutual authentication performed by SRP or
+ shared-keys, or you can do certificate-based server
+ authentication with one of these argument combinations:
+ - cryptoID[, protocol] (requires cryptoIDlib)
+ - x509Fingerprint
+ - x509TrustList[, x509CommonName] (requires cryptlib_py)
+
+ Certificate-based server authentication is compatible with
+ SRP or certificate-based client authentication. It is
+ not compatible with shared-keys.
+
+ The constructor does not perform the TLS handshake itself, but
+ simply stores these arguments for later. The handshake is
+ performed only when this class needs to connect with the
+ server. Thus you should be prepared to handle TLS-specific
+ exceptions when calling methods inherited from
+ L{httplib.HTTPConnection} such as request(), connect(), and
+ send(). See the client handshake functions in
+ L{tlslite.TLSConnection.TLSConnection} for details on which
+ exceptions might be raised.
+
+ @type host: str
+ @param host: Server to connect to.
+
+ @type port: int
+ @param port: Port to connect to.
+
+ @type username: str
+ @param username: SRP or shared-key username. Requires the
+ 'password' or 'sharedKey' argument.
+
+ @type password: str
+ @param password: SRP password for mutual authentication.
+ Requires the 'username' argument.
+
+ @type sharedKey: str
+ @param sharedKey: Shared key for mutual authentication.
+ Requires the 'username' argument.
+
+ @type certChain: L{tlslite.X509CertChain.X509CertChain} or
+ L{cryptoIDlib.CertChain.CertChain}
+ @param certChain: Certificate chain for client authentication.
+ Requires the 'privateKey' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
+ @param privateKey: Private key for client authentication.
+ Requires the 'certChain' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type cryptoID: str
+ @param cryptoID: cryptoID for server authentication. Mutually
+ exclusive with the 'x509...' arguments.
+
+ @type protocol: str
+ @param protocol: cryptoID protocol URI for server
+ authentication. Requires the 'cryptoID' argument.
+
+ @type x509Fingerprint: str
+ @param x509Fingerprint: Hex-encoded X.509 fingerprint for
+ server authentication. Mutually exclusive with the 'cryptoID'
+ and 'x509TrustList' arguments.
+
+ @type x509TrustList: list of L{tlslite.X509.X509}
+ @param x509TrustList: A list of trusted root certificates. The
+ other party must present a certificate chain which extends to
+ one of these root certificates. The cryptlib_py module must be
+ installed to use this parameter. Mutually exclusive with the
+ 'cryptoID' and 'x509Fingerprint' arguments.
+
+ @type x509CommonName: str
+ @param x509CommonName: The end-entity certificate's 'CN' field
+ must match this value. For a web server, this is typically a
+ server name such as 'www.amazon.com'. Mutually exclusive with
+ the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
+ 'x509TrustList' argument.
+
+ @type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
+ @param settings: Various settings which can be used to control
+ the ciphersuites, certificate types, and SSL/TLS versions
+ offered by the client.
+ """
+
+ HTTPBaseTLSConnection.__init__(self, host, port)
+
+ ClientHelper.__init__(self,
+ username, password, sharedKey,
+ certChain, privateKey,
+ cryptoID, protocol,
+ x509Fingerprint,
+ x509TrustList, x509CommonName,
+ settings)
+
+ def _handshake(self, tlsConnection):
+ ClientHelper._handshake(self, tlsConnection)
diff --git a/src/lib/tlslite/integration/IMAP4_TLS.py b/src/lib/tlslite/integration/IMAP4_TLS.py
new file mode 100755
index 000000000..2b005dc7e
--- /dev/null
+++ b/src/lib/tlslite/integration/IMAP4_TLS.py
@@ -0,0 +1,132 @@
+"""TLS Lite + imaplib."""
+
+import socket
+from imaplib import IMAP4
+from Bcfg2.tlslite.TLSConnection import TLSConnection
+from Bcfg2.tlslite.integration.ClientHelper import ClientHelper
+
+# IMAP TLS PORT
+IMAP4_TLS_PORT = 993
+
+class IMAP4_TLS(IMAP4, ClientHelper):
+ """This class extends L{imaplib.IMAP4} with TLS support."""
+
+ def __init__(self, host = '', port = IMAP4_TLS_PORT,
+ username=None, password=None, sharedKey=None,
+ certChain=None, privateKey=None,
+ cryptoID=None, protocol=None,
+ x509Fingerprint=None,
+ x509TrustList=None, x509CommonName=None,
+ settings=None):
+ """Create a new IMAP4_TLS.
+
+ For client authentication, use one of these argument
+ combinations:
+ - username, password (SRP)
+ - username, sharedKey (shared-key)
+ - certChain, privateKey (certificate)
+
+ For server authentication, you can either rely on the
+ implicit mutual authentication performed by SRP or
+ shared-keys, or you can do certificate-based server
+ authentication with one of these argument combinations:
+ - cryptoID[, protocol] (requires cryptoIDlib)
+ - x509Fingerprint
+ - x509TrustList[, x509CommonName] (requires cryptlib_py)
+
+ Certificate-based server authentication is compatible with
+ SRP or certificate-based client authentication. It is
+ not compatible with shared-keys.
+
+ The caller should be prepared to handle TLS-specific
+ exceptions. See the client handshake functions in
+ L{tlslite.TLSConnection.TLSConnection} for details on which
+ exceptions might be raised.
+
+ @type host: str
+ @param host: Server to connect to.
+
+ @type port: int
+ @param port: Port to connect to.
+
+ @type username: str
+ @param username: SRP or shared-key username. Requires the
+ 'password' or 'sharedKey' argument.
+
+ @type password: str
+ @param password: SRP password for mutual authentication.
+ Requires the 'username' argument.
+
+ @type sharedKey: str
+ @param sharedKey: Shared key for mutual authentication.
+ Requires the 'username' argument.
+
+ @type certChain: L{tlslite.X509CertChain.X509CertChain} or
+ L{cryptoIDlib.CertChain.CertChain}
+ @param certChain: Certificate chain for client authentication.
+ Requires the 'privateKey' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
+ @param privateKey: Private key for client authentication.
+ Requires the 'certChain' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type cryptoID: str
+ @param cryptoID: cryptoID for server authentication. Mutually
+ exclusive with the 'x509...' arguments.
+
+ @type protocol: str
+ @param protocol: cryptoID protocol URI for server
+ authentication. Requires the 'cryptoID' argument.
+
+ @type x509Fingerprint: str
+ @param x509Fingerprint: Hex-encoded X.509 fingerprint for
+ server authentication. Mutually exclusive with the 'cryptoID'
+ and 'x509TrustList' arguments.
+
+ @type x509TrustList: list of L{tlslite.X509.X509}
+ @param x509TrustList: A list of trusted root certificates. The
+ other party must present a certificate chain which extends to
+ one of these root certificates. The cryptlib_py module must be
+ installed to use this parameter. Mutually exclusive with the
+ 'cryptoID' and 'x509Fingerprint' arguments.
+
+ @type x509CommonName: str
+ @param x509CommonName: The end-entity certificate's 'CN' field
+ must match this value. For a web server, this is typically a
+ server name such as 'www.amazon.com'. Mutually exclusive with
+ the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
+ 'x509TrustList' argument.
+
+ @type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
+ @param settings: Various settings which can be used to control
+ the ciphersuites, certificate types, and SSL/TLS versions
+ offered by the client.
+ """
+
+ ClientHelper.__init__(self,
+ username, password, sharedKey,
+ certChain, privateKey,
+ cryptoID, protocol,
+ x509Fingerprint,
+ x509TrustList, x509CommonName,
+ settings)
+
+ IMAP4.__init__(self, host, port)
+
+
+ def open(self, host = '', port = IMAP4_TLS_PORT):
+ """Setup connection to remote server on "host:port".
+
+ This connection will be used by the routines:
+ read, readline, send, shutdown.
+ """
+ self.host = host
+ self.port = port
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.connect((host, port))
+ self.sock = TLSConnection(self.sock)
+ self.sock.closeSocket = True
+ ClientHelper._handshake(self, self.sock)
+ self.file = self.sock.makefile('rb')
diff --git a/src/lib/tlslite/integration/IntegrationHelper.py b/src/lib/tlslite/integration/IntegrationHelper.py
new file mode 100755
index 000000000..af5193b48
--- /dev/null
+++ b/src/lib/tlslite/integration/IntegrationHelper.py
@@ -0,0 +1,52 @@
+
+class IntegrationHelper:
+
+ def __init__(self,
+ username=None, password=None, sharedKey=None,
+ certChain=None, privateKey=None,
+ cryptoID=None, protocol=None,
+ x509Fingerprint=None,
+ x509TrustList=None, x509CommonName=None,
+ settings = None):
+
+ self.username = None
+ self.password = None
+ self.sharedKey = None
+ self.certChain = None
+ self.privateKey = None
+ self.checker = None
+
+ #SRP Authentication
+ if username and password and not \
+ (sharedKey or certChain or privateKey):
+ self.username = username
+ self.password = password
+
+ #Shared Key Authentication
+ elif username and sharedKey and not \
+ (password or certChain or privateKey):
+ self.username = username
+ self.sharedKey = sharedKey
+
+ #Certificate Chain Authentication
+ elif certChain and privateKey and not \
+ (username or password or sharedKey):
+ self.certChain = certChain
+ self.privateKey = privateKey
+
+ #No Authentication
+ elif not password and not username and not \
+ sharedKey and not certChain and not privateKey:
+ pass
+
+ else:
+ raise ValueError("Bad parameters")
+
+ #Authenticate the server based on its cryptoID or fingerprint
+ if sharedKey and (cryptoID or protocol or x509Fingerprint):
+ raise ValueError("Can't use shared keys with other forms of"\
+ "authentication")
+
+ self.checker = Checker(cryptoID, protocol, x509Fingerprint,
+ x509TrustList, x509CommonName)
+ self.settings = settings \ No newline at end of file
diff --git a/src/lib/tlslite/integration/POP3_TLS.py b/src/lib/tlslite/integration/POP3_TLS.py
new file mode 100755
index 000000000..8245a13ca
--- /dev/null
+++ b/src/lib/tlslite/integration/POP3_TLS.py
@@ -0,0 +1,142 @@
+"""TLS Lite + poplib."""
+
+import socket
+from poplib import POP3
+from Bcfg2.tlslite.TLSConnection import TLSConnection
+from Bcfg2.tlslite.integration.ClientHelper import ClientHelper
+
+# POP TLS PORT
+POP3_TLS_PORT = 995
+
+class POP3_TLS(POP3, ClientHelper):
+ """This class extends L{poplib.POP3} with TLS support."""
+
+ def __init__(self, host, port = POP3_TLS_PORT,
+ username=None, password=None, sharedKey=None,
+ certChain=None, privateKey=None,
+ cryptoID=None, protocol=None,
+ x509Fingerprint=None,
+ x509TrustList=None, x509CommonName=None,
+ settings=None):
+ """Create a new POP3_TLS.
+
+ For client authentication, use one of these argument
+ combinations:
+ - username, password (SRP)
+ - username, sharedKey (shared-key)
+ - certChain, privateKey (certificate)
+
+ For server authentication, you can either rely on the
+ implicit mutual authentication performed by SRP or
+ shared-keys, or you can do certificate-based server
+ authentication with one of these argument combinations:
+ - cryptoID[, protocol] (requires cryptoIDlib)
+ - x509Fingerprint
+ - x509TrustList[, x509CommonName] (requires cryptlib_py)
+
+ Certificate-based server authentication is compatible with
+ SRP or certificate-based client authentication. It is
+ not compatible with shared-keys.
+
+ The caller should be prepared to handle TLS-specific
+ exceptions. See the client handshake functions in
+ L{tlslite.TLSConnection.TLSConnection} for details on which
+ exceptions might be raised.
+
+ @type host: str
+ @param host: Server to connect to.
+
+ @type port: int
+ @param port: Port to connect to.
+
+ @type username: str
+ @param username: SRP or shared-key username. Requires the
+ 'password' or 'sharedKey' argument.
+
+ @type password: str
+ @param password: SRP password for mutual authentication.
+ Requires the 'username' argument.
+
+ @type sharedKey: str
+ @param sharedKey: Shared key for mutual authentication.
+ Requires the 'username' argument.
+
+ @type certChain: L{tlslite.X509CertChain.X509CertChain} or
+ L{cryptoIDlib.CertChain.CertChain}
+ @param certChain: Certificate chain for client authentication.
+ Requires the 'privateKey' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
+ @param privateKey: Private key for client authentication.
+ Requires the 'certChain' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type cryptoID: str
+ @param cryptoID: cryptoID for server authentication. Mutually
+ exclusive with the 'x509...' arguments.
+
+ @type protocol: str
+ @param protocol: cryptoID protocol URI for server
+ authentication. Requires the 'cryptoID' argument.
+
+ @type x509Fingerprint: str
+ @param x509Fingerprint: Hex-encoded X.509 fingerprint for
+ server authentication. Mutually exclusive with the 'cryptoID'
+ and 'x509TrustList' arguments.
+
+ @type x509TrustList: list of L{tlslite.X509.X509}
+ @param x509TrustList: A list of trusted root certificates. The
+ other party must present a certificate chain which extends to
+ one of these root certificates. The cryptlib_py module must be
+ installed to use this parameter. Mutually exclusive with the
+ 'cryptoID' and 'x509Fingerprint' arguments.
+
+ @type x509CommonName: str
+ @param x509CommonName: The end-entity certificate's 'CN' field
+ must match this value. For a web server, this is typically a
+ server name such as 'www.amazon.com'. Mutually exclusive with
+ the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
+ 'x509TrustList' argument.
+
+ @type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
+ @param settings: Various settings which can be used to control
+ the ciphersuites, certificate types, and SSL/TLS versions
+ offered by the client.
+ """
+
+ self.host = host
+ self.port = port
+ msg = "getaddrinfo returns an empty list"
+ self.sock = None
+ for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
+ af, socktype, proto, canonname, sa = res
+ try:
+ self.sock = socket.socket(af, socktype, proto)
+ self.sock.connect(sa)
+ except socket.error, msg:
+ if self.sock:
+ self.sock.close()
+ self.sock = None
+ continue
+ break
+ if not self.sock:
+ raise socket.error, msg
+
+ ### New code below (all else copied from poplib)
+ ClientHelper.__init__(self,
+ username, password, sharedKey,
+ certChain, privateKey,
+ cryptoID, protocol,
+ x509Fingerprint,
+ x509TrustList, x509CommonName,
+ settings)
+
+ self.sock = TLSConnection(self.sock)
+ self.sock.closeSocket = True
+ ClientHelper._handshake(self, self.sock)
+ ###
+
+ self.file = self.sock.makefile('rb')
+ self._debugging = 0
+ self.welcome = self._getresp()
diff --git a/src/lib/tlslite/integration/SMTP_TLS.py b/src/lib/tlslite/integration/SMTP_TLS.py
new file mode 100755
index 000000000..203cc0b7f
--- /dev/null
+++ b/src/lib/tlslite/integration/SMTP_TLS.py
@@ -0,0 +1,114 @@
+"""TLS Lite + smtplib."""
+
+from smtplib import SMTP
+from Bcfg2.tlslite.TLSConnection import TLSConnection
+from Bcfg2.tlslite.integration.ClientHelper import ClientHelper
+
+class SMTP_TLS(SMTP):
+ """This class extends L{smtplib.SMTP} with TLS support."""
+
+ def starttls(self,
+ username=None, password=None, sharedKey=None,
+ certChain=None, privateKey=None,
+ cryptoID=None, protocol=None,
+ x509Fingerprint=None,
+ x509TrustList=None, x509CommonName=None,
+ settings=None):
+ """Puts the connection to the SMTP server into TLS mode.
+
+ If the server supports TLS, this will encrypt the rest of the SMTP
+ session.
+
+ For client authentication, use one of these argument
+ combinations:
+ - username, password (SRP)
+ - username, sharedKey (shared-key)
+ - certChain, privateKey (certificate)
+
+ For server authentication, you can either rely on the
+ implicit mutual authentication performed by SRP or
+ shared-keys, or you can do certificate-based server
+ authentication with one of these argument combinations:
+ - cryptoID[, protocol] (requires cryptoIDlib)
+ - x509Fingerprint
+ - x509TrustList[, x509CommonName] (requires cryptlib_py)
+
+ Certificate-based server authentication is compatible with
+ SRP or certificate-based client authentication. It is
+ not compatible with shared-keys.
+
+ The caller should be prepared to handle TLS-specific
+ exceptions. See the client handshake functions in
+ L{tlslite.TLSConnection.TLSConnection} for details on which
+ exceptions might be raised.
+
+ @type username: str
+ @param username: SRP or shared-key username. Requires the
+ 'password' or 'sharedKey' argument.
+
+ @type password: str
+ @param password: SRP password for mutual authentication.
+ Requires the 'username' argument.
+
+ @type sharedKey: str
+ @param sharedKey: Shared key for mutual authentication.
+ Requires the 'username' argument.
+
+ @type certChain: L{tlslite.X509CertChain.X509CertChain} or
+ L{cryptoIDlib.CertChain.CertChain}
+ @param certChain: Certificate chain for client authentication.
+ Requires the 'privateKey' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
+ @param privateKey: Private key for client authentication.
+ Requires the 'certChain' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type cryptoID: str
+ @param cryptoID: cryptoID for server authentication. Mutually
+ exclusive with the 'x509...' arguments.
+
+ @type protocol: str
+ @param protocol: cryptoID protocol URI for server
+ authentication. Requires the 'cryptoID' argument.
+
+ @type x509Fingerprint: str
+ @param x509Fingerprint: Hex-encoded X.509 fingerprint for
+ server authentication. Mutually exclusive with the 'cryptoID'
+ and 'x509TrustList' arguments.
+
+ @type x509TrustList: list of L{tlslite.X509.X509}
+ @param x509TrustList: A list of trusted root certificates. The
+ other party must present a certificate chain which extends to
+ one of these root certificates. The cryptlib_py module must be
+ installed to use this parameter. Mutually exclusive with the
+ 'cryptoID' and 'x509Fingerprint' arguments.
+
+ @type x509CommonName: str
+ @param x509CommonName: The end-entity certificate's 'CN' field
+ must match this value. For a web server, this is typically a
+ server name such as 'www.amazon.com'. Mutually exclusive with
+ the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
+ 'x509TrustList' argument.
+
+ @type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
+ @param settings: Various settings which can be used to control
+ the ciphersuites, certificate types, and SSL/TLS versions
+ offered by the client.
+ """
+ (resp, reply) = self.docmd("STARTTLS")
+ if resp == 220:
+ helper = ClientHelper(
+ username, password, sharedKey,
+ certChain, privateKey,
+ cryptoID, protocol,
+ x509Fingerprint,
+ x509TrustList, x509CommonName,
+ settings)
+ conn = TLSConnection(self.sock)
+ conn.closeSocket = True
+ helper._handshake(conn)
+ self.sock = conn
+ self.file = conn.makefile('rb')
+ return (resp, reply)
diff --git a/src/lib/tlslite/integration/TLSAsyncDispatcherMixIn.py b/src/lib/tlslite/integration/TLSAsyncDispatcherMixIn.py
new file mode 100755
index 000000000..9201e5cba
--- /dev/null
+++ b/src/lib/tlslite/integration/TLSAsyncDispatcherMixIn.py
@@ -0,0 +1,139 @@
+"""TLS Lite + asyncore."""
+
+
+import asyncore
+from Bcfg2.tlslite.TLSConnection import TLSConnection
+from AsyncStateMachine import AsyncStateMachine
+
+
+class TLSAsyncDispatcherMixIn(AsyncStateMachine):
+ """This class can be "mixed in" with an
+ L{asyncore.dispatcher} to add TLS support.
+
+ This class essentially sits between the dispatcher and the select
+ loop, intercepting events and only calling the dispatcher when
+ applicable.
+
+ In the case of handle_read(), a read operation will be activated,
+ and when it completes, the bytes will be placed in a buffer where
+ the dispatcher can retrieve them by calling recv(), and the
+ dispatcher's handle_read() will be called.
+
+ In the case of handle_write(), the dispatcher's handle_write() will
+ be called, and when it calls send(), a write operation will be
+ activated.
+
+ To use this class, you must combine it with an asyncore.dispatcher,
+ and pass in a handshake operation with setServerHandshakeOp().
+
+ Below is an example of using this class with medusa. This class is
+ mixed in with http_channel to create http_tls_channel. Note:
+ 1. the mix-in is listed first in the inheritance list
+
+ 2. the input buffer size must be at least 16K, otherwise the
+ dispatcher might not read all the bytes from the TLS layer,
+ leaving some bytes in limbo.
+
+ 3. IE seems to have a problem receiving a whole HTTP response in a
+ single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't
+ be displayed on IE.
+
+ Add the following text into 'start_medusa.py', in the 'HTTP Server'
+ section::
+
+ from tlslite.api import *
+ s = open("./serverX509Cert.pem").read()
+ x509 = X509()
+ x509.parse(s)
+ certChain = X509CertChain([x509])
+
+ s = open("./serverX509Key.pem").read()
+ privateKey = parsePEMKey(s, private=True)
+
+ class http_tls_channel(TLSAsyncDispatcherMixIn,
+ http_server.http_channel):
+ ac_in_buffer_size = 16384
+
+ def __init__ (self, server, conn, addr):
+ http_server.http_channel.__init__(self, server, conn, addr)
+ TLSAsyncDispatcherMixIn.__init__(self, conn)
+ self.tlsConnection.ignoreAbruptClose = True
+ self.setServerHandshakeOp(certChain=certChain,
+ privateKey=privateKey)
+
+ hs.channel_class = http_tls_channel
+
+ If the TLS layer raises an exception, the exception will be caught
+ in asyncore.dispatcher, which will call close() on this class. The
+ TLS layer always closes the TLS connection before raising an
+ exception, so the close operation will complete right away, causing
+ asyncore.dispatcher.close() to be called, which closes the socket
+ and removes this instance from the asyncore loop.
+
+ """
+
+
+ def __init__(self, sock=None):
+ AsyncStateMachine.__init__(self)
+
+ if sock:
+ self.tlsConnection = TLSConnection(sock)
+
+ #Calculate the sibling I'm being mixed in with.
+ #This is necessary since we override functions
+ #like readable(), handle_read(), etc., but we
+ #also want to call the sibling's versions.
+ for cl in self.__class__.__bases__:
+ if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine:
+ self.siblingClass = cl
+ break
+ else:
+ raise AssertionError()
+
+ def readable(self):
+ result = self.wantsReadEvent()
+ if result != None:
+ return result
+ return self.siblingClass.readable(self)
+
+ def writable(self):
+ result = self.wantsWriteEvent()
+ if result != None:
+ return result
+ return self.siblingClass.writable(self)
+
+ def handle_read(self):
+ self.inReadEvent()
+
+ def handle_write(self):
+ self.inWriteEvent()
+
+ def outConnectEvent(self):
+ self.siblingClass.handle_connect(self)
+
+ def outCloseEvent(self):
+ asyncore.dispatcher.close(self)
+
+ def outReadEvent(self, readBuffer):
+ self.readBuffer = readBuffer
+ self.siblingClass.handle_read(self)
+
+ def outWriteEvent(self):
+ self.siblingClass.handle_write(self)
+
+ def recv(self, bufferSize=16384):
+ if bufferSize < 16384 or self.readBuffer == None:
+ raise AssertionError()
+ returnValue = self.readBuffer
+ self.readBuffer = None
+ return returnValue
+
+ def send(self, writeBuffer):
+ self.setWriteOp(writeBuffer)
+ return len(writeBuffer)
+
+ def close(self):
+ if hasattr(self, "tlsConnection"):
+ self.setCloseOp()
+ else:
+ asyncore.dispatcher.close(self)
diff --git a/src/lib/tlslite/integration/TLSSocketServerMixIn.py b/src/lib/tlslite/integration/TLSSocketServerMixIn.py
new file mode 100755
index 000000000..fe9f303b4
--- /dev/null
+++ b/src/lib/tlslite/integration/TLSSocketServerMixIn.py
@@ -0,0 +1,59 @@
+"""TLS Lite + SocketServer."""
+
+from Bcfg2.tlslite.TLSConnection import TLSConnection
+
+class TLSSocketServerMixIn:
+ """
+ This class can be mixed in with any L{SocketServer.TCPServer} to
+ add TLS support.
+
+ To use this class, define a new class that inherits from it and
+ some L{SocketServer.TCPServer} (with the mix-in first). Then
+ implement the handshake() method, doing some sort of server
+ handshake on the connection argument. If the handshake method
+ returns True, the RequestHandler will be triggered. Below is a
+ complete example of a threaded HTTPS server::
+
+ from SocketServer import *
+ from BaseHTTPServer import *
+ from SimpleHTTPServer import *
+ from tlslite.api import *
+
+ s = open("./serverX509Cert.pem").read()
+ x509 = X509()
+ x509.parse(s)
+ certChain = X509CertChain([x509])
+
+ s = open("./serverX509Key.pem").read()
+ privateKey = parsePEMKey(s, private=True)
+
+ sessionCache = SessionCache()
+
+ class MyHTTPServer(ThreadingMixIn, TLSSocketServerMixIn,
+ HTTPServer):
+ def handshake(self, tlsConnection):
+ try:
+ tlsConnection.handshakeServer(certChain=certChain,
+ privateKey=privateKey,
+ sessionCache=sessionCache)
+ tlsConnection.ignoreAbruptClose = True
+ return True
+ except TLSError, error:
+ print "Handshake failure:", str(error)
+ return False
+
+ httpd = MyHTTPServer(('localhost', 443), SimpleHTTPRequestHandler)
+ httpd.serve_forever()
+ """
+
+
+ def finish_request(self, sock, client_address):
+ tlsConnection = TLSConnection(sock)
+ if self.handshake(tlsConnection) == True:
+ self.RequestHandlerClass(tlsConnection, client_address, self)
+ tlsConnection.close()
+
+ #Implement this method to do some form of handshaking. Return True
+ #if the handshake finishes properly and the request is authorized.
+ def handshake(self, tlsConnection):
+ raise NotImplementedError()
diff --git a/src/lib/tlslite/integration/TLSTwistedProtocolWrapper.py b/src/lib/tlslite/integration/TLSTwistedProtocolWrapper.py
new file mode 100755
index 000000000..b9d2f8529
--- /dev/null
+++ b/src/lib/tlslite/integration/TLSTwistedProtocolWrapper.py
@@ -0,0 +1,196 @@
+"""TLS Lite + Twisted."""
+
+from twisted.protocols.policies import ProtocolWrapper, WrappingFactory
+from twisted.python.failure import Failure
+
+from AsyncStateMachine import AsyncStateMachine
+from Bcfg2.tlslite.TLSConnection import TLSConnection
+from Bcfg2.tlslite.errors import *
+
+import socket
+import errno
+
+
+#The TLSConnection is created around a "fake socket" that
+#plugs it into the underlying Twisted transport
+class _FakeSocket:
+ def __init__(self, wrapper):
+ self.wrapper = wrapper
+ self.data = ""
+
+ def send(self, data):
+ ProtocolWrapper.write(self.wrapper, data)
+ return len(data)
+
+ def recv(self, numBytes):
+ if self.data == "":
+ raise socket.error, (errno.EWOULDBLOCK, "")
+ returnData = self.data[:numBytes]
+ self.data = self.data[numBytes:]
+ return returnData
+
+class TLSTwistedProtocolWrapper(ProtocolWrapper, AsyncStateMachine):
+ """This class can wrap Twisted protocols to add TLS support.
+
+ Below is a complete example of using TLS Lite with a Twisted echo
+ server.
+
+ There are two server implementations below. Echo is the original
+ protocol, which is oblivious to TLS. Echo1 subclasses Echo and
+ negotiates TLS when the client connects. Echo2 subclasses Echo and
+ negotiates TLS when the client sends "STARTTLS"::
+
+ from twisted.internet.protocol import Protocol, Factory
+ from twisted.internet import reactor
+ from twisted.protocols.policies import WrappingFactory
+ from twisted.protocols.basic import LineReceiver
+ from twisted.python import log
+ from twisted.python.failure import Failure
+ import sys
+ from tlslite.api import *
+
+ s = open("./serverX509Cert.pem").read()
+ x509 = X509()
+ x509.parse(s)
+ certChain = X509CertChain([x509])
+
+ s = open("./serverX509Key.pem").read()
+ privateKey = parsePEMKey(s, private=True)
+
+ verifierDB = VerifierDB("verifierDB")
+ verifierDB.open()
+
+ class Echo(LineReceiver):
+ def connectionMade(self):
+ self.transport.write("Welcome to the echo server!\\r\\n")
+
+ def lineReceived(self, line):
+ self.transport.write(line + "\\r\\n")
+
+ class Echo1(Echo):
+ def connectionMade(self):
+ if not self.transport.tlsStarted:
+ self.transport.setServerHandshakeOp(certChain=certChain,
+ privateKey=privateKey,
+ verifierDB=verifierDB)
+ else:
+ Echo.connectionMade(self)
+
+ def connectionLost(self, reason):
+ pass #Handle any TLS exceptions here
+
+ class Echo2(Echo):
+ def lineReceived(self, data):
+ if data == "STARTTLS":
+ self.transport.setServerHandshakeOp(certChain=certChain,
+ privateKey=privateKey,
+ verifierDB=verifierDB)
+ else:
+ Echo.lineReceived(self, data)
+
+ def connectionLost(self, reason):
+ pass #Handle any TLS exceptions here
+
+ factory = Factory()
+ factory.protocol = Echo1
+ #factory.protocol = Echo2
+
+ wrappingFactory = WrappingFactory(factory)
+ wrappingFactory.protocol = TLSTwistedProtocolWrapper
+
+ log.startLogging(sys.stdout)
+ reactor.listenTCP(1079, wrappingFactory)
+ reactor.run()
+
+ This class works as follows:
+
+ Data comes in and is given to the AsyncStateMachine for handling.
+ AsyncStateMachine will forward events to this class, and we'll
+ pass them on to the ProtocolHandler, which will proxy them to the
+ wrapped protocol. The wrapped protocol may then call back into
+ this class, and these calls will be proxied into the
+ AsyncStateMachine.
+
+ The call graph looks like this:
+ - self.dataReceived
+ - AsyncStateMachine.inReadEvent
+ - self.out(Connect|Close|Read)Event
+ - ProtocolWrapper.(connectionMade|loseConnection|dataReceived)
+ - self.(loseConnection|write|writeSequence)
+ - AsyncStateMachine.(setCloseOp|setWriteOp)
+ """
+
+ #WARNING: IF YOU COPY-AND-PASTE THE ABOVE CODE, BE SURE TO REMOVE
+ #THE EXTRA ESCAPING AROUND "\\r\\n"
+
+ def __init__(self, factory, wrappedProtocol):
+ ProtocolWrapper.__init__(self, factory, wrappedProtocol)
+ AsyncStateMachine.__init__(self)
+ self.fakeSocket = _FakeSocket(self)
+ self.tlsConnection = TLSConnection(self.fakeSocket)
+ self.tlsStarted = False
+ self.connectionLostCalled = False
+
+ def connectionMade(self):
+ try:
+ ProtocolWrapper.connectionMade(self)
+ except TLSError, e:
+ self.connectionLost(Failure(e))
+ ProtocolWrapper.loseConnection(self)
+
+ def dataReceived(self, data):
+ try:
+ if not self.tlsStarted:
+ ProtocolWrapper.dataReceived(self, data)
+ else:
+ self.fakeSocket.data += data
+ while self.fakeSocket.data:
+ AsyncStateMachine.inReadEvent(self)
+ except TLSError, e:
+ self.connectionLost(Failure(e))
+ ProtocolWrapper.loseConnection(self)
+
+ def connectionLost(self, reason):
+ if not self.connectionLostCalled:
+ ProtocolWrapper.connectionLost(self, reason)
+ self.connectionLostCalled = True
+
+
+ def outConnectEvent(self):
+ ProtocolWrapper.connectionMade(self)
+
+ def outCloseEvent(self):
+ ProtocolWrapper.loseConnection(self)
+
+ def outReadEvent(self, data):
+ if data == "":
+ ProtocolWrapper.loseConnection(self)
+ else:
+ ProtocolWrapper.dataReceived(self, data)
+
+
+ def setServerHandshakeOp(self, **args):
+ self.tlsStarted = True
+ AsyncStateMachine.setServerHandshakeOp(self, **args)
+
+ def loseConnection(self):
+ if not self.tlsStarted:
+ ProtocolWrapper.loseConnection(self)
+ else:
+ AsyncStateMachine.setCloseOp(self)
+
+ def write(self, data):
+ if not self.tlsStarted:
+ ProtocolWrapper.write(self, data)
+ else:
+ #Because of the FakeSocket, write operations are guaranteed to
+ #terminate immediately.
+ AsyncStateMachine.setWriteOp(self, data)
+
+ def writeSequence(self, seq):
+ if not self.tlsStarted:
+ ProtocolWrapper.writeSequence(self, seq)
+ else:
+ #Because of the FakeSocket, write operations are guaranteed to
+ #terminate immediately.
+ AsyncStateMachine.setWriteOp(self, "".join(seq))
diff --git a/src/lib/tlslite/integration/XMLRPCTransport.py b/src/lib/tlslite/integration/XMLRPCTransport.py
new file mode 100755
index 000000000..61d03428b
--- /dev/null
+++ b/src/lib/tlslite/integration/XMLRPCTransport.py
@@ -0,0 +1,137 @@
+"""TLS Lite + xmlrpclib."""
+
+import xmlrpclib
+import httplib
+from Bcfg2.tlslite.integration.HTTPTLSConnection import HTTPTLSConnection
+from Bcfg2.tlslite.integration.ClientHelper import ClientHelper
+
+
+class XMLRPCTransport(xmlrpclib.Transport, ClientHelper):
+ """Handles an HTTPS transaction to an XML-RPC server."""
+
+ def __init__(self,
+ username=None, password=None, sharedKey=None,
+ certChain=None, privateKey=None,
+ cryptoID=None, protocol=None,
+ x509Fingerprint=None,
+ x509TrustList=None, x509CommonName=None,
+ settings=None):
+ """Create a new XMLRPCTransport.
+
+ An instance of this class can be passed to L{xmlrpclib.ServerProxy}
+ to use TLS with XML-RPC calls::
+
+ from tlslite.api import XMLRPCTransport
+ from xmlrpclib import ServerProxy
+
+ transport = XMLRPCTransport(user="alice", password="abra123")
+ server = ServerProxy("https://localhost", transport)
+
+ For client authentication, use one of these argument
+ combinations:
+ - username, password (SRP)
+ - username, sharedKey (shared-key)
+ - certChain, privateKey (certificate)
+
+ For server authentication, you can either rely on the
+ implicit mutual authentication performed by SRP or
+ shared-keys, or you can do certificate-based server
+ authentication with one of these argument combinations:
+ - cryptoID[, protocol] (requires cryptoIDlib)
+ - x509Fingerprint
+ - x509TrustList[, x509CommonName] (requires cryptlib_py)
+
+ Certificate-based server authentication is compatible with
+ SRP or certificate-based client authentication. It is
+ not compatible with shared-keys.
+
+ The constructor does not perform the TLS handshake itself, but
+ simply stores these arguments for later. The handshake is
+ performed only when this class needs to connect with the
+ server. Thus you should be prepared to handle TLS-specific
+ exceptions when calling methods of L{xmlrpclib.ServerProxy}. See the
+ client handshake functions in
+ L{tlslite.TLSConnection.TLSConnection} for details on which
+ exceptions might be raised.
+
+ @type username: str
+ @param username: SRP or shared-key username. Requires the
+ 'password' or 'sharedKey' argument.
+
+ @type password: str
+ @param password: SRP password for mutual authentication.
+ Requires the 'username' argument.
+
+ @type sharedKey: str
+ @param sharedKey: Shared key for mutual authentication.
+ Requires the 'username' argument.
+
+ @type certChain: L{tlslite.X509CertChain.X509CertChain} or
+ L{cryptoIDlib.CertChain.CertChain}
+ @param certChain: Certificate chain for client authentication.
+ Requires the 'privateKey' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
+ @param privateKey: Private key for client authentication.
+ Requires the 'certChain' argument. Excludes the SRP or
+ shared-key related arguments.
+
+ @type cryptoID: str
+ @param cryptoID: cryptoID for server authentication. Mutually
+ exclusive with the 'x509...' arguments.
+
+ @type protocol: str
+ @param protocol: cryptoID protocol URI for server
+ authentication. Requires the 'cryptoID' argument.
+
+ @type x509Fingerprint: str
+ @param x509Fingerprint: Hex-encoded X.509 fingerprint for
+ server authentication. Mutually exclusive with the 'cryptoID'
+ and 'x509TrustList' arguments.
+
+ @type x509TrustList: list of L{tlslite.X509.X509}
+ @param x509TrustList: A list of trusted root certificates. The
+ other party must present a certificate chain which extends to
+ one of these root certificates. The cryptlib_py module must be
+ installed to use this parameter. Mutually exclusive with the
+ 'cryptoID' and 'x509Fingerprint' arguments.
+
+ @type x509CommonName: str
+ @param x509CommonName: The end-entity certificate's 'CN' field
+ must match this value. For a web server, this is typically a
+ server name such as 'www.amazon.com'. Mutually exclusive with
+ the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
+ 'x509TrustList' argument.
+
+ @type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
+ @param settings: Various settings which can be used to control
+ the ciphersuites, certificate types, and SSL/TLS versions
+ offered by the client.
+ """
+
+ ClientHelper.__init__(self,
+ username, password, sharedKey,
+ certChain, privateKey,
+ cryptoID, protocol,
+ x509Fingerprint,
+ x509TrustList, x509CommonName,
+ settings)
+ self._use_datetime = 0
+
+ def make_connection(self, host):
+ # create a HTTPS connection object from a host descriptor
+ host, extra_headers, x509 = self.get_host_info(host)
+ http = HTTPTLSConnection(host, None,
+ self.username, self.password,
+ self.sharedKey,
+ self.certChain, self.privateKey,
+ self.checker.cryptoID,
+ self.checker.protocol,
+ self.checker.x509Fingerprint,
+ self.checker.x509TrustList,
+ self.checker.x509CommonName,
+ self.settings)
+ http2 = httplib.HTTP()
+ http2._setup(http)
+ return http2
diff --git a/src/lib/tlslite/integration/__init__.py b/src/lib/tlslite/integration/__init__.py
new file mode 100755
index 000000000..960f4065f
--- /dev/null
+++ b/src/lib/tlslite/integration/__init__.py
@@ -0,0 +1,17 @@
+"""Classes for integrating TLS Lite with other packages."""
+
+__all__ = ["AsyncStateMachine",
+ "HTTPTLSConnection",
+ "POP3_TLS",
+ "IMAP4_TLS",
+ "SMTP_TLS",
+ "XMLRPCTransport",
+ "TLSSocketServerMixIn",
+ "TLSAsyncDispatcherMixIn",
+ "TLSTwistedProtocolWrapper"]
+
+try:
+ import twisted
+ del twisted
+except ImportError:
+ del __all__[__all__.index("TLSTwistedProtocolWrapper")]