move nearly everything into /src to make git.io/gam cleaner w/o a readme tree

This commit is contained in:
Jay Lee
2015-09-30 09:14:32 -04:00
parent 8b19040e45
commit c1225178d6
225 changed files with 2015 additions and 2015 deletions

View File

View File

@ -1,21 +1,21 @@
rmdir /q /s gam rmdir /q /s gam
rmdir /q /s gam-64 rmdir /q /s gam-64
rmdir /q /s build rmdir /q /s build
rmdir /q /s dist rmdir /q /s dist
del /q /f gam-%1-windows.zip del /q /f gam-%1-windows.zip
del /q /f gam-%1-windows-x64.zip del /q /f gam-%1-windows-x64.zip
c:\python27-32\scripts\pyinstaller -F --distpath=gam gam.spec c:\python27-32\scripts\pyinstaller -F --distpath=gam gam.spec
xcopy LICENSE gam\ xcopy LICENSE gam\
xcopy whatsnew.txt gam\ xcopy whatsnew.txt gam\
xcopy admin-settings-v1.json gam\ xcopy admin-settings-v1.json gam\
xcopy cloudprint-v2.json gam\ xcopy cloudprint-v2.json gam\
del gam\w9xpopen.exe del gam\w9xpopen.exe
"%ProgramFiles(x86)%\7-Zip\7z.exe" a -tzip gam-%1-windows.zip gam\ -xr!.svn "%ProgramFiles(x86)%\7-Zip\7z.exe" a -tzip gam-%1-windows.zip gam\ -xr!.svn
c:\python27\scripts\pyinstaller -F --distpath=gam-64 gam.spec c:\python27\scripts\pyinstaller -F --distpath=gam-64 gam.spec
xcopy LICENSE gam-64\ xcopy LICENSE gam-64\
xcopy whatsnew.txt gam-64\ xcopy whatsnew.txt gam-64\
xcopy admin-settings-v1.json gam-64\ xcopy admin-settings-v1.json gam-64\
xcopy cloudprint-v2.json gam-64\ xcopy cloudprint-v2.json gam-64\
"%ProgramFiles(x86)%\7-Zip\7z.exe" a -tzip gam-%1-windows-x64.zip gam-64\ -xr!.svn "%ProgramFiles(x86)%\7-Zip\7z.exe" a -tzip gam-%1-windows-x64.zip gam-64\ -xr!.svn

0
gam.py → src/gam.py Executable file → Normal file
View File

View File

@ -1,17 +1,17 @@
1. Moved oauth.py to __init__.py 1. Moved oauth.py to __init__.py
2. Refactored __init__.py for compatibility with python 2.2 (Issue 59) 2. Refactored __init__.py for compatibility with python 2.2 (Issue 59)
3. Refactored rsa.py for compatibility with python 2.2 (Issue 59) 3. Refactored rsa.py for compatibility with python 2.2 (Issue 59)
4. Refactored OAuthRequest.from_token_and_callback since the callback url was 4. Refactored OAuthRequest.from_token_and_callback since the callback url was
getting double url-encoding the callback url in place of single. (Issue 43) getting double url-encoding the callback url in place of single. (Issue 43)
5. Added build_signature_base_string method to rsa.py since it used the 5. Added build_signature_base_string method to rsa.py since it used the
implementation of this method from oauth.OAuthSignatureMethod_HMAC_SHA1 which implementation of this method from oauth.OAuthSignatureMethod_HMAC_SHA1 which
was incorrect since it enforced the presence of a consumer secret and a token was incorrect since it enforced the presence of a consumer secret and a token
secret. Also, changed its super class from oauth.OAuthSignatureMethod_HMAC_SHA1 secret. Also, changed its super class from oauth.OAuthSignatureMethod_HMAC_SHA1
to oauth.OAuthSignatureMethod (Issue 64) to oauth.OAuthSignatureMethod (Issue 64)
6. Refactored <OAuthRequest>.to_header method since it returned non-oauth params 6. Refactored <OAuthRequest>.to_header method since it returned non-oauth params
as well which was incorrect. (Issue 31) as well which was incorrect. (Issue 31)

File diff suppressed because it is too large Load Diff

View File

@ -1,120 +1,120 @@
"""Base class for SharedKeyDB and VerifierDB.""" """Base class for SharedKeyDB and VerifierDB."""
import anydbm import anydbm
import thread import thread
class BaseDB: class BaseDB:
def __init__(self, filename, type): def __init__(self, filename, type):
self.type = type self.type = type
self.filename = filename self.filename = filename
if self.filename: if self.filename:
self.db = None self.db = None
else: else:
self.db = {} self.db = {}
self.lock = thread.allocate_lock() self.lock = thread.allocate_lock()
def create(self): def create(self):
"""Create a new on-disk database. """Create a new on-disk database.
@raise anydbm.error: If there's a problem creating the database. @raise anydbm.error: If there's a problem creating the database.
""" """
if self.filename: if self.filename:
self.db = anydbm.open(self.filename, "n") #raises anydbm.error self.db = anydbm.open(self.filename, "n") #raises anydbm.error
self.db["--Reserved--type"] = self.type self.db["--Reserved--type"] = self.type
self.db.sync() self.db.sync()
else: else:
self.db = {} self.db = {}
def open(self): def open(self):
"""Open a pre-existing on-disk database. """Open a pre-existing on-disk database.
@raise anydbm.error: If there's a problem opening the database. @raise anydbm.error: If there's a problem opening the database.
@raise ValueError: If the database is not of the right type. @raise ValueError: If the database is not of the right type.
""" """
if not self.filename: if not self.filename:
raise ValueError("Can only open on-disk databases") raise ValueError("Can only open on-disk databases")
self.db = anydbm.open(self.filename, "w") #raises anydbm.error self.db = anydbm.open(self.filename, "w") #raises anydbm.error
try: try:
if self.db["--Reserved--type"] != self.type: if self.db["--Reserved--type"] != self.type:
raise ValueError("Not a %s database" % self.type) raise ValueError("Not a %s database" % self.type)
except KeyError: except KeyError:
raise ValueError("Not a recognized database") raise ValueError("Not a recognized database")
def __getitem__(self, username): def __getitem__(self, username):
if self.db == None: if self.db == None:
raise AssertionError("DB not open") raise AssertionError("DB not open")
self.lock.acquire() self.lock.acquire()
try: try:
valueStr = self.db[username] valueStr = self.db[username]
finally: finally:
self.lock.release() self.lock.release()
return self._getItem(username, valueStr) return self._getItem(username, valueStr)
def __setitem__(self, username, value): def __setitem__(self, username, value):
if self.db == None: if self.db == None:
raise AssertionError("DB not open") raise AssertionError("DB not open")
valueStr = self._setItem(username, value) valueStr = self._setItem(username, value)
self.lock.acquire() self.lock.acquire()
try: try:
self.db[username] = valueStr self.db[username] = valueStr
if self.filename: if self.filename:
self.db.sync() self.db.sync()
finally: finally:
self.lock.release() self.lock.release()
def __delitem__(self, username): def __delitem__(self, username):
if self.db == None: if self.db == None:
raise AssertionError("DB not open") raise AssertionError("DB not open")
self.lock.acquire() self.lock.acquire()
try: try:
del(self.db[username]) del(self.db[username])
if self.filename: if self.filename:
self.db.sync() self.db.sync()
finally: finally:
self.lock.release() self.lock.release()
def __contains__(self, username): def __contains__(self, username):
"""Check if the database contains the specified username. """Check if the database contains the specified username.
@type username: str @type username: str
@param username: The username to check for. @param username: The username to check for.
@rtype: bool @rtype: bool
@return: True if the database contains the username, False @return: True if the database contains the username, False
otherwise. otherwise.
""" """
if self.db == None: if self.db == None:
raise AssertionError("DB not open") raise AssertionError("DB not open")
self.lock.acquire() self.lock.acquire()
try: try:
return self.db.has_key(username) return self.db.has_key(username)
finally: finally:
self.lock.release() self.lock.release()
def check(self, username, param): def check(self, username, param):
value = self.__getitem__(username) value = self.__getitem__(username)
return self._checkItem(value, username, param) return self._checkItem(value, username, param)
def keys(self): def keys(self):
"""Return a list of usernames in the database. """Return a list of usernames in the database.
@rtype: list @rtype: list
@return: The usernames in the database. @return: The usernames in the database.
""" """
if self.db == None: if self.db == None:
raise AssertionError("DB not open") raise AssertionError("DB not open")
self.lock.acquire() self.lock.acquire()
try: try:
usernames = self.db.keys() usernames = self.db.keys()
finally: finally:
self.lock.release() self.lock.release()
usernames = [u for u in usernames if not u.startswith("--Reserved--")] usernames = [u for u in usernames if not u.startswith("--Reserved--")]
return usernames return usernames

View File

@ -1,181 +1,181 @@
"""Class representing an X.509 certificate chain.""" """Class representing an X.509 certificate chain."""
from utils import cryptomath from utils import cryptomath
class X509CertChain: class X509CertChain:
"""This class represents a chain of X.509 certificates. """This class represents a chain of X.509 certificates.
@type x509List: list @type x509List: list
@ivar x509List: A list of L{tlslite.X509.X509} instances, @ivar x509List: A list of L{tlslite.X509.X509} instances,
starting with the end-entity certificate and with every starting with the end-entity certificate and with every
subsequent certificate certifying the previous. subsequent certificate certifying the previous.
""" """
def __init__(self, x509List=None): def __init__(self, x509List=None):
"""Create a new X509CertChain. """Create a new X509CertChain.
@type x509List: list @type x509List: list
@param x509List: A list of L{tlslite.X509.X509} instances, @param x509List: A list of L{tlslite.X509.X509} instances,
starting with the end-entity certificate and with every starting with the end-entity certificate and with every
subsequent certificate certifying the previous. subsequent certificate certifying the previous.
""" """
if x509List: if x509List:
self.x509List = x509List self.x509List = x509List
else: else:
self.x509List = [] self.x509List = []
def getNumCerts(self): def getNumCerts(self):
"""Get the number of certificates in this chain. """Get the number of certificates in this chain.
@rtype: int @rtype: int
""" """
return len(self.x509List) return len(self.x509List)
def getEndEntityPublicKey(self): def getEndEntityPublicKey(self):
"""Get the public key from the end-entity certificate. """Get the public key from the end-entity certificate.
@rtype: L{tlslite.utils.RSAKey.RSAKey} @rtype: L{tlslite.utils.RSAKey.RSAKey}
""" """
if self.getNumCerts() == 0: if self.getNumCerts() == 0:
raise AssertionError() raise AssertionError()
return self.x509List[0].publicKey return self.x509List[0].publicKey
def getFingerprint(self): def getFingerprint(self):
"""Get the hex-encoded fingerprint of the end-entity certificate. """Get the hex-encoded fingerprint of the end-entity certificate.
@rtype: str @rtype: str
@return: A hex-encoded fingerprint. @return: A hex-encoded fingerprint.
""" """
if self.getNumCerts() == 0: if self.getNumCerts() == 0:
raise AssertionError() raise AssertionError()
return self.x509List[0].getFingerprint() return self.x509List[0].getFingerprint()
def getCommonName(self): def getCommonName(self):
"""Get the Subject's Common Name from the end-entity certificate. """Get the Subject's Common Name from the end-entity certificate.
The cryptlib_py module must be installed in order to use this The cryptlib_py module must be installed in order to use this
function. function.
@rtype: str or None @rtype: str or None
@return: The CN component of the certificate's subject DN, if @return: The CN component of the certificate's subject DN, if
present. present.
""" """
if self.getNumCerts() == 0: if self.getNumCerts() == 0:
raise AssertionError() raise AssertionError()
return self.x509List[0].getCommonName() return self.x509List[0].getCommonName()
def validate(self, x509TrustList): def validate(self, x509TrustList):
"""Check the validity of the certificate chain. """Check the validity of the certificate chain.
This checks that every certificate in the chain validates with This checks that every certificate in the chain validates with
the subsequent one, until some certificate validates with (or the subsequent one, until some certificate validates with (or
is identical to) one of the passed-in root certificates. is identical to) one of the passed-in root certificates.
The cryptlib_py module must be installed in order to use this The cryptlib_py module must be installed in order to use this
function. function.
@type x509TrustList: list of L{tlslite.X509.X509} @type x509TrustList: list of L{tlslite.X509.X509}
@param x509TrustList: A list of trusted root certificates. The @param x509TrustList: A list of trusted root certificates. The
certificate chain must extend to one of these certificates to certificate chain must extend to one of these certificates to
be considered valid. be considered valid.
""" """
import cryptlib_py import cryptlib_py
c1 = None c1 = None
c2 = None c2 = None
lastC = None lastC = None
rootC = None rootC = None
try: try:
rootFingerprints = [c.getFingerprint() for c in x509TrustList] rootFingerprints = [c.getFingerprint() for c in x509TrustList]
#Check that every certificate in the chain validates with the #Check that every certificate in the chain validates with the
#next one #next one
for cert1, cert2 in zip(self.x509List, self.x509List[1:]): for cert1, cert2 in zip(self.x509List, self.x509List[1:]):
#If we come upon a root certificate, we're done. #If we come upon a root certificate, we're done.
if cert1.getFingerprint() in rootFingerprints: if cert1.getFingerprint() in rootFingerprints:
return True return True
c1 = cryptlib_py.cryptImportCert(cert1.writeBytes(), c1 = cryptlib_py.cryptImportCert(cert1.writeBytes(),
cryptlib_py.CRYPT_UNUSED) cryptlib_py.CRYPT_UNUSED)
c2 = cryptlib_py.cryptImportCert(cert2.writeBytes(), c2 = cryptlib_py.cryptImportCert(cert2.writeBytes(),
cryptlib_py.CRYPT_UNUSED) cryptlib_py.CRYPT_UNUSED)
try: try:
cryptlib_py.cryptCheckCert(c1, c2) cryptlib_py.cryptCheckCert(c1, c2)
except: except:
return False return False
cryptlib_py.cryptDestroyCert(c1) cryptlib_py.cryptDestroyCert(c1)
c1 = None c1 = None
cryptlib_py.cryptDestroyCert(c2) cryptlib_py.cryptDestroyCert(c2)
c2 = None c2 = None
#If the last certificate is one of the root certificates, we're #If the last certificate is one of the root certificates, we're
#done. #done.
if self.x509List[-1].getFingerprint() in rootFingerprints: if self.x509List[-1].getFingerprint() in rootFingerprints:
return True return True
#Otherwise, find a root certificate that the last certificate #Otherwise, find a root certificate that the last certificate
#chains to, and validate them. #chains to, and validate them.
lastC = cryptlib_py.cryptImportCert(self.x509List[-1].writeBytes(), lastC = cryptlib_py.cryptImportCert(self.x509List[-1].writeBytes(),
cryptlib_py.CRYPT_UNUSED) cryptlib_py.CRYPT_UNUSED)
for rootCert in x509TrustList: for rootCert in x509TrustList:
rootC = cryptlib_py.cryptImportCert(rootCert.writeBytes(), rootC = cryptlib_py.cryptImportCert(rootCert.writeBytes(),
cryptlib_py.CRYPT_UNUSED) cryptlib_py.CRYPT_UNUSED)
if self._checkChaining(lastC, rootC): if self._checkChaining(lastC, rootC):
try: try:
cryptlib_py.cryptCheckCert(lastC, rootC) cryptlib_py.cryptCheckCert(lastC, rootC)
return True return True
except: except:
return False return False
return False return False
finally: finally:
if not (c1 is None): if not (c1 is None):
cryptlib_py.cryptDestroyCert(c1) cryptlib_py.cryptDestroyCert(c1)
if not (c2 is None): if not (c2 is None):
cryptlib_py.cryptDestroyCert(c2) cryptlib_py.cryptDestroyCert(c2)
if not (lastC is None): if not (lastC is None):
cryptlib_py.cryptDestroyCert(lastC) cryptlib_py.cryptDestroyCert(lastC)
if not (rootC is None): if not (rootC is None):
cryptlib_py.cryptDestroyCert(rootC) cryptlib_py.cryptDestroyCert(rootC)
def _checkChaining(self, lastC, rootC): def _checkChaining(self, lastC, rootC):
import cryptlib_py import cryptlib_py
import array import array
def compareNames(name): def compareNames(name):
try: try:
length = cryptlib_py.cryptGetAttributeString(lastC, name, None) length = cryptlib_py.cryptGetAttributeString(lastC, name, None)
lastName = array.array('B', [0] * length) lastName = array.array('B', [0] * length)
cryptlib_py.cryptGetAttributeString(lastC, name, lastName) cryptlib_py.cryptGetAttributeString(lastC, name, lastName)
lastName = lastName.tostring() lastName = lastName.tostring()
except cryptlib_py.CryptException, e: except cryptlib_py.CryptException, e:
if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND: if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND:
lastName = None lastName = None
try: try:
length = cryptlib_py.cryptGetAttributeString(rootC, name, None) length = cryptlib_py.cryptGetAttributeString(rootC, name, None)
rootName = array.array('B', [0] * length) rootName = array.array('B', [0] * length)
cryptlib_py.cryptGetAttributeString(rootC, name, rootName) cryptlib_py.cryptGetAttributeString(rootC, name, rootName)
rootName = rootName.tostring() rootName = rootName.tostring()
except cryptlib_py.CryptException, e: except cryptlib_py.CryptException, e:
if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND: if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND:
rootName = None rootName = None
return lastName == rootName return lastName == rootName
cryptlib_py.cryptSetAttribute(lastC, cryptlib_py.cryptSetAttribute(lastC,
cryptlib_py.CRYPT_CERTINFO_ISSUERNAME, cryptlib_py.CRYPT_CERTINFO_ISSUERNAME,
cryptlib_py.CRYPT_UNUSED) cryptlib_py.CRYPT_UNUSED)
if not compareNames(cryptlib_py.CRYPT_CERTINFO_COUNTRYNAME): if not compareNames(cryptlib_py.CRYPT_CERTINFO_COUNTRYNAME):
return False return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_LOCALITYNAME): if not compareNames(cryptlib_py.CRYPT_CERTINFO_LOCALITYNAME):
return False return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONNAME): if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONNAME):
return False return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONALUNITNAME): if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONALUNITNAME):
return False return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_COMMONNAME): if not compareNames(cryptlib_py.CRYPT_CERTINFO_COMMONNAME):
return False return False
return True return True

View File

@ -1,235 +1,235 @@
""" """
A state machine for using TLS Lite with asynchronous I/O. A state machine for using TLS Lite with asynchronous I/O.
""" """
class AsyncStateMachine: class AsyncStateMachine:
""" """
This is an abstract class that's used to integrate TLS Lite with This is an abstract class that's used to integrate TLS Lite with
asyncore and Twisted. asyncore and Twisted.
This class signals wantsReadsEvent() and wantsWriteEvent(). When This class signals wantsReadsEvent() and wantsWriteEvent(). When
the underlying socket has become readable or writeable, the event the underlying socket has become readable or writeable, the event
should be passed to this class by calling inReadEvent() or should be passed to this class by calling inReadEvent() or
inWriteEvent(). This class will then try to read or write through inWriteEvent(). This class will then try to read or write through
the socket, and will update its state appropriately. the socket, and will update its state appropriately.
This class will forward higher-level events to its subclass. For This class will forward higher-level events to its subclass. For
example, when a complete TLS record has been received, example, when a complete TLS record has been received,
outReadEvent() will be called with the decrypted data. outReadEvent() will be called with the decrypted data.
""" """
def __init__(self): def __init__(self):
self._clear() self._clear()
def _clear(self): def _clear(self):
#These store the various asynchronous operations (i.e. #These store the various asynchronous operations (i.e.
#generators). Only one of them, at most, is ever active at a #generators). Only one of them, at most, is ever active at a
#time. #time.
self.handshaker = None self.handshaker = None
self.closer = None self.closer = None
self.reader = None self.reader = None
self.writer = None self.writer = None
#This stores the result from the last call to the #This stores the result from the last call to the
#currently active operation. If 0 it indicates that the #currently active operation. If 0 it indicates that the
#operation wants to read, if 1 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 wants to write. If None, there is no active
#operation. #operation.
self.result = None self.result = None
def _checkAssert(self, maxActive=1): def _checkAssert(self, maxActive=1):
#This checks that only one operation, at most, is #This checks that only one operation, at most, is
#active, and that self.result is set appropriately. #active, and that self.result is set appropriately.
activeOps = 0 activeOps = 0
if self.handshaker: if self.handshaker:
activeOps += 1 activeOps += 1
if self.closer: if self.closer:
activeOps += 1 activeOps += 1
if self.reader: if self.reader:
activeOps += 1 activeOps += 1
if self.writer: if self.writer:
activeOps += 1 activeOps += 1
if self.result == None: if self.result == None:
if activeOps != 0: if activeOps != 0:
raise AssertionError() raise AssertionError()
elif self.result in (0,1): elif self.result in (0,1):
if activeOps != 1: if activeOps != 1:
raise AssertionError() raise AssertionError()
else: else:
raise AssertionError() raise AssertionError()
if activeOps > maxActive: if activeOps > maxActive:
raise AssertionError() raise AssertionError()
def wantsReadEvent(self): def wantsReadEvent(self):
"""If the state machine wants to read. """If the state machine wants to read.
If an operation is active, this returns whether or not the If an operation is active, this returns whether or not the
operation wants to read from the socket. If an operation is operation wants to read from the socket. If an operation is
not active, this returns None. not active, this returns None.
@rtype: bool or None @rtype: bool or None
@return: If the state machine wants to read. @return: If the state machine wants to read.
""" """
if self.result != None: if self.result != None:
return self.result == 0 return self.result == 0
return None return None
def wantsWriteEvent(self): def wantsWriteEvent(self):
"""If the state machine wants to write. """If the state machine wants to write.
If an operation is active, this returns whether or not the If an operation is active, this returns whether or not the
operation wants to write to the socket. If an operation is operation wants to write to the socket. If an operation is
not active, this returns None. not active, this returns None.
@rtype: bool or None @rtype: bool or None
@return: If the state machine wants to write. @return: If the state machine wants to write.
""" """
if self.result != None: if self.result != None:
return self.result == 1 return self.result == 1
return None return None
def outConnectEvent(self): def outConnectEvent(self):
"""Called when a handshake operation completes. """Called when a handshake operation completes.
May be overridden in subclass. May be overridden in subclass.
""" """
pass pass
def outCloseEvent(self): def outCloseEvent(self):
"""Called when a close operation completes. """Called when a close operation completes.
May be overridden in subclass. May be overridden in subclass.
""" """
pass pass
def outReadEvent(self, readBuffer): def outReadEvent(self, readBuffer):
"""Called when a read operation completes. """Called when a read operation completes.
May be overridden in subclass.""" May be overridden in subclass."""
pass pass
def outWriteEvent(self): def outWriteEvent(self):
"""Called when a write operation completes. """Called when a write operation completes.
May be overridden in subclass.""" May be overridden in subclass."""
pass pass
def inReadEvent(self): def inReadEvent(self):
"""Tell the state machine it can read from the socket.""" """Tell the state machine it can read from the socket."""
try: try:
self._checkAssert() self._checkAssert()
if self.handshaker: if self.handshaker:
self._doHandshakeOp() self._doHandshakeOp()
elif self.closer: elif self.closer:
self._doCloseOp() self._doCloseOp()
elif self.reader: elif self.reader:
self._doReadOp() self._doReadOp()
elif self.writer: elif self.writer:
self._doWriteOp() self._doWriteOp()
else: else:
self.reader = self.tlsConnection.readAsync(16384) self.reader = self.tlsConnection.readAsync(16384)
self._doReadOp() self._doReadOp()
except: except:
self._clear() self._clear()
raise raise
def inWriteEvent(self): def inWriteEvent(self):
"""Tell the state machine it can write to the socket.""" """Tell the state machine it can write to the socket."""
try: try:
self._checkAssert() self._checkAssert()
if self.handshaker: if self.handshaker:
self._doHandshakeOp() self._doHandshakeOp()
elif self.closer: elif self.closer:
self._doCloseOp() self._doCloseOp()
elif self.reader: elif self.reader:
self._doReadOp() self._doReadOp()
elif self.writer: elif self.writer:
self._doWriteOp() self._doWriteOp()
else: else:
self.outWriteEvent() self.outWriteEvent()
except: except:
self._clear() self._clear()
raise raise
def _doHandshakeOp(self): def _doHandshakeOp(self):
try: try:
self.result = self.handshaker.next() self.result = self.handshaker.next()
except StopIteration: except StopIteration:
self.handshaker = None self.handshaker = None
self.result = None self.result = None
self.outConnectEvent() self.outConnectEvent()
def _doCloseOp(self): def _doCloseOp(self):
try: try:
self.result = self.closer.next() self.result = self.closer.next()
except StopIteration: except StopIteration:
self.closer = None self.closer = None
self.result = None self.result = None
self.outCloseEvent() self.outCloseEvent()
def _doReadOp(self): def _doReadOp(self):
self.result = self.reader.next() self.result = self.reader.next()
if not self.result in (0,1): if not self.result in (0,1):
readBuffer = self.result readBuffer = self.result
self.reader = None self.reader = None
self.result = None self.result = None
self.outReadEvent(readBuffer) self.outReadEvent(readBuffer)
def _doWriteOp(self): def _doWriteOp(self):
try: try:
self.result = self.writer.next() self.result = self.writer.next()
except StopIteration: except StopIteration:
self.writer = None self.writer = None
self.result = None self.result = None
def setHandshakeOp(self, handshaker): def setHandshakeOp(self, handshaker):
"""Start a handshake operation. """Start a handshake operation.
@type handshaker: generator @type handshaker: generator
@param handshaker: A generator created by using one of the @param handshaker: A generator created by using one of the
asynchronous handshake functions (i.e. handshakeServerAsync, or asynchronous handshake functions (i.e. handshakeServerAsync, or
handshakeClientxxx(..., async=True). handshakeClientxxx(..., async=True).
""" """
try: try:
self._checkAssert(0) self._checkAssert(0)
self.handshaker = handshaker self.handshaker = handshaker
self._doHandshakeOp() self._doHandshakeOp()
except: except:
self._clear() self._clear()
raise raise
def setServerHandshakeOp(self, **args): def setServerHandshakeOp(self, **args):
"""Start a handshake operation. """Start a handshake operation.
The arguments passed to this function will be forwarded to The arguments passed to this function will be forwarded to
L{tlslite.TLSConnection.TLSConnection.handshakeServerAsync}. L{tlslite.TLSConnection.TLSConnection.handshakeServerAsync}.
""" """
handshaker = self.tlsConnection.handshakeServerAsync(**args) handshaker = self.tlsConnection.handshakeServerAsync(**args)
self.setHandshakeOp(handshaker) self.setHandshakeOp(handshaker)
def setCloseOp(self): def setCloseOp(self):
"""Start a close operation. """Start a close operation.
""" """
try: try:
self._checkAssert(0) self._checkAssert(0)
self.closer = self.tlsConnection.closeAsync() self.closer = self.tlsConnection.closeAsync()
self._doCloseOp() self._doCloseOp()
except: except:
self._clear() self._clear()
raise raise
def setWriteOp(self, writeBuffer): def setWriteOp(self, writeBuffer):
"""Start a write operation. """Start a write operation.
@type writeBuffer: str @type writeBuffer: str
@param writeBuffer: The string to transmit. @param writeBuffer: The string to transmit.
""" """
try: try:
self._checkAssert(0) self._checkAssert(0)
self.writer = self.tlsConnection.writeAsync(writeBuffer) self.writer = self.tlsConnection.writeAsync(writeBuffer)
self._doWriteOp() self._doWriteOp()
except: except:
self._clear() self._clear()
raise raise

View File

@ -1,163 +1,163 @@
""" """
A helper class for using TLS Lite with stdlib clients A helper class for using TLS Lite with stdlib clients
(httplib, xmlrpclib, imaplib, poplib). (httplib, xmlrpclib, imaplib, poplib).
""" """
from gdata.tlslite.Checker import Checker from gdata.tlslite.Checker import Checker
class ClientHelper: class ClientHelper:
"""This is a helper class used to integrate TLS Lite with various """This is a helper class used to integrate TLS Lite with various
TLS clients (e.g. poplib, smtplib, httplib, etc.)""" TLS clients (e.g. poplib, smtplib, httplib, etc.)"""
def __init__(self, def __init__(self,
username=None, password=None, sharedKey=None, username=None, password=None, sharedKey=None,
certChain=None, privateKey=None, certChain=None, privateKey=None,
cryptoID=None, protocol=None, cryptoID=None, protocol=None,
x509Fingerprint=None, x509Fingerprint=None,
x509TrustList=None, x509CommonName=None, x509TrustList=None, x509CommonName=None,
settings = None): settings = None):
""" """
For client authentication, use one of these argument For client authentication, use one of these argument
combinations: combinations:
- username, password (SRP) - username, password (SRP)
- username, sharedKey (shared-key) - username, sharedKey (shared-key)
- certChain, privateKey (certificate) - certChain, privateKey (certificate)
For server authentication, you can either rely on the For server authentication, you can either rely on the
implicit mutual authentication performed by SRP or implicit mutual authentication performed by SRP or
shared-keys, or you can do certificate-based server shared-keys, or you can do certificate-based server
authentication with one of these argument combinations: authentication with one of these argument combinations:
- cryptoID[, protocol] (requires cryptoIDlib) - cryptoID[, protocol] (requires cryptoIDlib)
- x509Fingerprint - x509Fingerprint
- x509TrustList[, x509CommonName] (requires cryptlib_py) - x509TrustList[, x509CommonName] (requires cryptlib_py)
Certificate-based server authentication is compatible with Certificate-based server authentication is compatible with
SRP or certificate-based client authentication. It is SRP or certificate-based client authentication. It is
not compatible with shared-keys. not compatible with shared-keys.
The constructor does not perform the TLS handshake itself, but The constructor does not perform the TLS handshake itself, but
simply stores these arguments for later. The handshake is simply stores these arguments for later. The handshake is
performed only when this class needs to connect with the performed only when this class needs to connect with the
server. Then you should be prepared to handle TLS-specific server. Then you should be prepared to handle TLS-specific
exceptions. See the client handshake functions in exceptions. See the client handshake functions in
L{tlslite.TLSConnection.TLSConnection} for details on which L{tlslite.TLSConnection.TLSConnection} for details on which
exceptions might be raised. exceptions might be raised.
@type username: str @type username: str
@param username: SRP or shared-key username. Requires the @param username: SRP or shared-key username. Requires the
'password' or 'sharedKey' argument. 'password' or 'sharedKey' argument.
@type password: str @type password: str
@param password: SRP password for mutual authentication. @param password: SRP password for mutual authentication.
Requires the 'username' argument. Requires the 'username' argument.
@type sharedKey: str @type sharedKey: str
@param sharedKey: Shared key for mutual authentication. @param sharedKey: Shared key for mutual authentication.
Requires the 'username' argument. Requires the 'username' argument.
@type certChain: L{tlslite.X509CertChain.X509CertChain} or @type certChain: L{tlslite.X509CertChain.X509CertChain} or
L{cryptoIDlib.CertChain.CertChain} L{cryptoIDlib.CertChain.CertChain}
@param certChain: Certificate chain for client authentication. @param certChain: Certificate chain for client authentication.
Requires the 'privateKey' argument. Excludes the SRP or Requires the 'privateKey' argument. Excludes the SRP or
shared-key related arguments. shared-key related arguments.
@type privateKey: L{tlslite.utils.RSAKey.RSAKey} @type privateKey: L{tlslite.utils.RSAKey.RSAKey}
@param privateKey: Private key for client authentication. @param privateKey: Private key for client authentication.
Requires the 'certChain' argument. Excludes the SRP or Requires the 'certChain' argument. Excludes the SRP or
shared-key related arguments. shared-key related arguments.
@type cryptoID: str @type cryptoID: str
@param cryptoID: cryptoID for server authentication. Mutually @param cryptoID: cryptoID for server authentication. Mutually
exclusive with the 'x509...' arguments. exclusive with the 'x509...' arguments.
@type protocol: str @type protocol: str
@param protocol: cryptoID protocol URI for server @param protocol: cryptoID protocol URI for server
authentication. Requires the 'cryptoID' argument. authentication. Requires the 'cryptoID' argument.
@type x509Fingerprint: str @type x509Fingerprint: str
@param x509Fingerprint: Hex-encoded X.509 fingerprint for @param x509Fingerprint: Hex-encoded X.509 fingerprint for
server authentication. Mutually exclusive with the 'cryptoID' server authentication. Mutually exclusive with the 'cryptoID'
and 'x509TrustList' arguments. and 'x509TrustList' arguments.
@type x509TrustList: list of L{tlslite.X509.X509} @type x509TrustList: list of L{tlslite.X509.X509}
@param x509TrustList: A list of trusted root certificates. The @param x509TrustList: A list of trusted root certificates. The
other party must present a certificate chain which extends to other party must present a certificate chain which extends to
one of these root certificates. The cryptlib_py module must be one of these root certificates. The cryptlib_py module must be
installed to use this parameter. Mutually exclusive with the installed to use this parameter. Mutually exclusive with the
'cryptoID' and 'x509Fingerprint' arguments. 'cryptoID' and 'x509Fingerprint' arguments.
@type x509CommonName: str @type x509CommonName: str
@param x509CommonName: The end-entity certificate's 'CN' field @param x509CommonName: The end-entity certificate's 'CN' field
must match this value. For a web server, this is typically a must match this value. For a web server, this is typically a
server name such as 'www.amazon.com'. Mutually exclusive with server name such as 'www.amazon.com'. Mutually exclusive with
the 'cryptoID' and 'x509Fingerprint' arguments. Requires the the 'cryptoID' and 'x509Fingerprint' arguments. Requires the
'x509TrustList' argument. 'x509TrustList' argument.
@type settings: L{tlslite.HandshakeSettings.HandshakeSettings} @type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
@param settings: Various settings which can be used to control @param settings: Various settings which can be used to control
the ciphersuites, certificate types, and SSL/TLS versions the ciphersuites, certificate types, and SSL/TLS versions
offered by the client. offered by the client.
""" """
self.username = None self.username = None
self.password = None self.password = None
self.sharedKey = None self.sharedKey = None
self.certChain = None self.certChain = None
self.privateKey = None self.privateKey = None
self.checker = None self.checker = None
#SRP Authentication #SRP Authentication
if username and password and not \ if username and password and not \
(sharedKey or certChain or privateKey): (sharedKey or certChain or privateKey):
self.username = username self.username = username
self.password = password self.password = password
#Shared Key Authentication #Shared Key Authentication
elif username and sharedKey and not \ elif username and sharedKey and not \
(password or certChain or privateKey): (password or certChain or privateKey):
self.username = username self.username = username
self.sharedKey = sharedKey self.sharedKey = sharedKey
#Certificate Chain Authentication #Certificate Chain Authentication
elif certChain and privateKey and not \ elif certChain and privateKey and not \
(username or password or sharedKey): (username or password or sharedKey):
self.certChain = certChain self.certChain = certChain
self.privateKey = privateKey self.privateKey = privateKey
#No Authentication #No Authentication
elif not password and not username and not \ elif not password and not username and not \
sharedKey and not certChain and not privateKey: sharedKey and not certChain and not privateKey:
pass pass
else: else:
raise ValueError("Bad parameters") raise ValueError("Bad parameters")
#Authenticate the server based on its cryptoID or fingerprint #Authenticate the server based on its cryptoID or fingerprint
if sharedKey and (cryptoID or protocol or x509Fingerprint): if sharedKey and (cryptoID or protocol or x509Fingerprint):
raise ValueError("Can't use shared keys with other forms of"\ raise ValueError("Can't use shared keys with other forms of"\
"authentication") "authentication")
self.checker = Checker(cryptoID, protocol, x509Fingerprint, self.checker = Checker(cryptoID, protocol, x509Fingerprint,
x509TrustList, x509CommonName) x509TrustList, x509CommonName)
self.settings = settings self.settings = settings
self.tlsSession = None self.tlsSession = None
def _handshake(self, tlsConnection): def _handshake(self, tlsConnection):
if self.username and self.password: if self.username and self.password:
tlsConnection.handshakeClientSRP(username=self.username, tlsConnection.handshakeClientSRP(username=self.username,
password=self.password, password=self.password,
checker=self.checker, checker=self.checker,
settings=self.settings, settings=self.settings,
session=self.tlsSession) session=self.tlsSession)
elif self.username and self.sharedKey: elif self.username and self.sharedKey:
tlsConnection.handshakeClientSharedKey(username=self.username, tlsConnection.handshakeClientSharedKey(username=self.username,
sharedKey=self.sharedKey, sharedKey=self.sharedKey,
settings=self.settings) settings=self.settings)
else: else:
tlsConnection.handshakeClientCert(certChain=self.certChain, tlsConnection.handshakeClientCert(certChain=self.certChain,
privateKey=self.privateKey, privateKey=self.privateKey,
checker=self.checker, checker=self.checker,
settings=self.settings, settings=self.settings,
session=self.tlsSession) session=self.tlsSession)
self.tlsSession = tlsConnection.session self.tlsSession = tlsConnection.session

View File

@ -1,52 +1,52 @@
class IntegrationHelper: class IntegrationHelper:
def __init__(self, def __init__(self,
username=None, password=None, sharedKey=None, username=None, password=None, sharedKey=None,
certChain=None, privateKey=None, certChain=None, privateKey=None,
cryptoID=None, protocol=None, cryptoID=None, protocol=None,
x509Fingerprint=None, x509Fingerprint=None,
x509TrustList=None, x509CommonName=None, x509TrustList=None, x509CommonName=None,
settings = None): settings = None):
self.username = None self.username = None
self.password = None self.password = None
self.sharedKey = None self.sharedKey = None
self.certChain = None self.certChain = None
self.privateKey = None self.privateKey = None
self.checker = None self.checker = None
#SRP Authentication #SRP Authentication
if username and password and not \ if username and password and not \
(sharedKey or certChain or privateKey): (sharedKey or certChain or privateKey):
self.username = username self.username = username
self.password = password self.password = password
#Shared Key Authentication #Shared Key Authentication
elif username and sharedKey and not \ elif username and sharedKey and not \
(password or certChain or privateKey): (password or certChain or privateKey):
self.username = username self.username = username
self.sharedKey = sharedKey self.sharedKey = sharedKey
#Certificate Chain Authentication #Certificate Chain Authentication
elif certChain and privateKey and not \ elif certChain and privateKey and not \
(username or password or sharedKey): (username or password or sharedKey):
self.certChain = certChain self.certChain = certChain
self.privateKey = privateKey self.privateKey = privateKey
#No Authentication #No Authentication
elif not password and not username and not \ elif not password and not username and not \
sharedKey and not certChain and not privateKey: sharedKey and not certChain and not privateKey:
pass pass
else: else:
raise ValueError("Bad parameters") raise ValueError("Bad parameters")
#Authenticate the server based on its cryptoID or fingerprint #Authenticate the server based on its cryptoID or fingerprint
if sharedKey and (cryptoID or protocol or x509Fingerprint): if sharedKey and (cryptoID or protocol or x509Fingerprint):
raise ValueError("Can't use shared keys with other forms of"\ raise ValueError("Can't use shared keys with other forms of"\
"authentication") "authentication")
self.checker = Checker(cryptoID, protocol, x509Fingerprint, self.checker = Checker(cryptoID, protocol, x509Fingerprint,
x509TrustList, x509CommonName) x509TrustList, x509CommonName)
self.settings = settings self.settings = settings

View File

@ -1,139 +1,139 @@
"""TLS Lite + asyncore.""" """TLS Lite + asyncore."""
import asyncore import asyncore
from gdata.tlslite.TLSConnection import TLSConnection from gdata.tlslite.TLSConnection import TLSConnection
from AsyncStateMachine import AsyncStateMachine from AsyncStateMachine import AsyncStateMachine
class TLSAsyncDispatcherMixIn(AsyncStateMachine): class TLSAsyncDispatcherMixIn(AsyncStateMachine):
"""This class can be "mixed in" with an """This class can be "mixed in" with an
L{asyncore.dispatcher} to add TLS support. L{asyncore.dispatcher} to add TLS support.
This class essentially sits between the dispatcher and the select This class essentially sits between the dispatcher and the select
loop, intercepting events and only calling the dispatcher when loop, intercepting events and only calling the dispatcher when
applicable. applicable.
In the case of handle_read(), a read operation will be activated, 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 and when it completes, the bytes will be placed in a buffer where
the dispatcher can retrieve them by calling recv(), and the the dispatcher can retrieve them by calling recv(), and the
dispatcher's handle_read() will be called. dispatcher's handle_read() will be called.
In the case of handle_write(), the dispatcher's handle_write() will In the case of handle_write(), the dispatcher's handle_write() will
be called, and when it calls send(), a write operation will be be called, and when it calls send(), a write operation will be
activated. activated.
To use this class, you must combine it with an asyncore.dispatcher, To use this class, you must combine it with an asyncore.dispatcher,
and pass in a handshake operation with setServerHandshakeOp(). and pass in a handshake operation with setServerHandshakeOp().
Below is an example of using this class with medusa. This class is Below is an example of using this class with medusa. This class is
mixed in with http_channel to create http_tls_channel. Note: mixed in with http_channel to create http_tls_channel. Note:
1. the mix-in is listed first in the inheritance list 1. the mix-in is listed first in the inheritance list
2. the input buffer size must be at least 16K, otherwise the 2. the input buffer size must be at least 16K, otherwise the
dispatcher might not read all the bytes from the TLS layer, dispatcher might not read all the bytes from the TLS layer,
leaving some bytes in limbo. leaving some bytes in limbo.
3. IE seems to have a problem receiving a whole HTTP response in a 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 single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't
be displayed on IE. be displayed on IE.
Add the following text into 'start_medusa.py', in the 'HTTP Server' Add the following text into 'start_medusa.py', in the 'HTTP Server'
section:: section::
from tlslite.api import * from tlslite.api import *
s = open("./serverX509Cert.pem").read() s = open("./serverX509Cert.pem").read()
x509 = X509() x509 = X509()
x509.parse(s) x509.parse(s)
certChain = X509CertChain([x509]) certChain = X509CertChain([x509])
s = open("./serverX509Key.pem").read() s = open("./serverX509Key.pem").read()
privateKey = parsePEMKey(s, private=True) privateKey = parsePEMKey(s, private=True)
class http_tls_channel(TLSAsyncDispatcherMixIn, class http_tls_channel(TLSAsyncDispatcherMixIn,
http_server.http_channel): http_server.http_channel):
ac_in_buffer_size = 16384 ac_in_buffer_size = 16384
def __init__ (self, server, conn, addr): def __init__ (self, server, conn, addr):
http_server.http_channel.__init__(self, server, conn, addr) http_server.http_channel.__init__(self, server, conn, addr)
TLSAsyncDispatcherMixIn.__init__(self, conn) TLSAsyncDispatcherMixIn.__init__(self, conn)
self.tlsConnection.ignoreAbruptClose = True self.tlsConnection.ignoreAbruptClose = True
self.setServerHandshakeOp(certChain=certChain, self.setServerHandshakeOp(certChain=certChain,
privateKey=privateKey) privateKey=privateKey)
hs.channel_class = http_tls_channel hs.channel_class = http_tls_channel
If the TLS layer raises an exception, the exception will be caught If the TLS layer raises an exception, the exception will be caught
in asyncore.dispatcher, which will call close() on this class. The in asyncore.dispatcher, which will call close() on this class. The
TLS layer always closes the TLS connection before raising an TLS layer always closes the TLS connection before raising an
exception, so the close operation will complete right away, causing exception, so the close operation will complete right away, causing
asyncore.dispatcher.close() to be called, which closes the socket asyncore.dispatcher.close() to be called, which closes the socket
and removes this instance from the asyncore loop. and removes this instance from the asyncore loop.
""" """
def __init__(self, sock=None): def __init__(self, sock=None):
AsyncStateMachine.__init__(self) AsyncStateMachine.__init__(self)
if sock: if sock:
self.tlsConnection = TLSConnection(sock) self.tlsConnection = TLSConnection(sock)
#Calculate the sibling I'm being mixed in with. #Calculate the sibling I'm being mixed in with.
#This is necessary since we override functions #This is necessary since we override functions
#like readable(), handle_read(), etc., but we #like readable(), handle_read(), etc., but we
#also want to call the sibling's versions. #also want to call the sibling's versions.
for cl in self.__class__.__bases__: for cl in self.__class__.__bases__:
if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine: if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine:
self.siblingClass = cl self.siblingClass = cl
break break
else: else:
raise AssertionError() raise AssertionError()
def readable(self): def readable(self):
result = self.wantsReadEvent() result = self.wantsReadEvent()
if result != None: if result != None:
return result return result
return self.siblingClass.readable(self) return self.siblingClass.readable(self)
def writable(self): def writable(self):
result = self.wantsWriteEvent() result = self.wantsWriteEvent()
if result != None: if result != None:
return result return result
return self.siblingClass.writable(self) return self.siblingClass.writable(self)
def handle_read(self): def handle_read(self):
self.inReadEvent() self.inReadEvent()
def handle_write(self): def handle_write(self):
self.inWriteEvent() self.inWriteEvent()
def outConnectEvent(self): def outConnectEvent(self):
self.siblingClass.handle_connect(self) self.siblingClass.handle_connect(self)
def outCloseEvent(self): def outCloseEvent(self):
asyncore.dispatcher.close(self) asyncore.dispatcher.close(self)
def outReadEvent(self, readBuffer): def outReadEvent(self, readBuffer):
self.readBuffer = readBuffer self.readBuffer = readBuffer
self.siblingClass.handle_read(self) self.siblingClass.handle_read(self)
def outWriteEvent(self): def outWriteEvent(self):
self.siblingClass.handle_write(self) self.siblingClass.handle_write(self)
def recv(self, bufferSize=16384): def recv(self, bufferSize=16384):
if bufferSize < 16384 or self.readBuffer == None: if bufferSize < 16384 or self.readBuffer == None:
raise AssertionError() raise AssertionError()
returnValue = self.readBuffer returnValue = self.readBuffer
self.readBuffer = None self.readBuffer = None
return returnValue return returnValue
def send(self, writeBuffer): def send(self, writeBuffer):
self.setWriteOp(writeBuffer) self.setWriteOp(writeBuffer)
return len(writeBuffer) return len(writeBuffer)
def close(self): def close(self):
if hasattr(self, "tlsConnection"): if hasattr(self, "tlsConnection"):
self.setCloseOp() self.setCloseOp()
else: else:
asyncore.dispatcher.close(self) asyncore.dispatcher.close(self)

View File

@ -1,196 +1,196 @@
"""TLS Lite + Twisted.""" """TLS Lite + Twisted."""
from twisted.protocols.policies import ProtocolWrapper, WrappingFactory from twisted.protocols.policies import ProtocolWrapper, WrappingFactory
from twisted.python.failure import Failure from twisted.python.failure import Failure
from AsyncStateMachine import AsyncStateMachine from AsyncStateMachine import AsyncStateMachine
from gdata.tlslite.TLSConnection import TLSConnection from gdata.tlslite.TLSConnection import TLSConnection
from gdata.tlslite.errors import * from gdata.tlslite.errors import *
import socket import socket
import errno import errno
#The TLSConnection is created around a "fake socket" that #The TLSConnection is created around a "fake socket" that
#plugs it into the underlying Twisted transport #plugs it into the underlying Twisted transport
class _FakeSocket: class _FakeSocket:
def __init__(self, wrapper): def __init__(self, wrapper):
self.wrapper = wrapper self.wrapper = wrapper
self.data = "" self.data = ""
def send(self, data): def send(self, data):
ProtocolWrapper.write(self.wrapper, data) ProtocolWrapper.write(self.wrapper, data)
return len(data) return len(data)
def recv(self, numBytes): def recv(self, numBytes):
if self.data == "": if self.data == "":
raise socket.error, (errno.EWOULDBLOCK, "") raise socket.error, (errno.EWOULDBLOCK, "")
returnData = self.data[:numBytes] returnData = self.data[:numBytes]
self.data = self.data[numBytes:] self.data = self.data[numBytes:]
return returnData return returnData
class TLSTwistedProtocolWrapper(ProtocolWrapper, AsyncStateMachine): class TLSTwistedProtocolWrapper(ProtocolWrapper, AsyncStateMachine):
"""This class can wrap Twisted protocols to add TLS support. """This class can wrap Twisted protocols to add TLS support.
Below is a complete example of using TLS Lite with a Twisted echo Below is a complete example of using TLS Lite with a Twisted echo
server. server.
There are two server implementations below. Echo is the original There are two server implementations below. Echo is the original
protocol, which is oblivious to TLS. Echo1 subclasses Echo and 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 connects. Echo2 subclasses Echo and
negotiates TLS when the client sends "STARTTLS":: negotiates TLS when the client sends "STARTTLS"::
from twisted.internet.protocol import Protocol, Factory from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor from twisted.internet import reactor
from twisted.protocols.policies import WrappingFactory from twisted.protocols.policies import WrappingFactory
from twisted.protocols.basic import LineReceiver from twisted.protocols.basic import LineReceiver
from twisted.python import log from twisted.python import log
from twisted.python.failure import Failure from twisted.python.failure import Failure
import sys import sys
from tlslite.api import * from tlslite.api import *
s = open("./serverX509Cert.pem").read() s = open("./serverX509Cert.pem").read()
x509 = X509() x509 = X509()
x509.parse(s) x509.parse(s)
certChain = X509CertChain([x509]) certChain = X509CertChain([x509])
s = open("./serverX509Key.pem").read() s = open("./serverX509Key.pem").read()
privateKey = parsePEMKey(s, private=True) privateKey = parsePEMKey(s, private=True)
verifierDB = VerifierDB("verifierDB") verifierDB = VerifierDB("verifierDB")
verifierDB.open() verifierDB.open()
class Echo(LineReceiver): class Echo(LineReceiver):
def connectionMade(self): def connectionMade(self):
self.transport.write("Welcome to the echo server!\\r\\n") self.transport.write("Welcome to the echo server!\\r\\n")
def lineReceived(self, line): def lineReceived(self, line):
self.transport.write(line + "\\r\\n") self.transport.write(line + "\\r\\n")
class Echo1(Echo): class Echo1(Echo):
def connectionMade(self): def connectionMade(self):
if not self.transport.tlsStarted: if not self.transport.tlsStarted:
self.transport.setServerHandshakeOp(certChain=certChain, self.transport.setServerHandshakeOp(certChain=certChain,
privateKey=privateKey, privateKey=privateKey,
verifierDB=verifierDB) verifierDB=verifierDB)
else: else:
Echo.connectionMade(self) Echo.connectionMade(self)
def connectionLost(self, reason): def connectionLost(self, reason):
pass #Handle any TLS exceptions here pass #Handle any TLS exceptions here
class Echo2(Echo): class Echo2(Echo):
def lineReceived(self, data): def lineReceived(self, data):
if data == "STARTTLS": if data == "STARTTLS":
self.transport.setServerHandshakeOp(certChain=certChain, self.transport.setServerHandshakeOp(certChain=certChain,
privateKey=privateKey, privateKey=privateKey,
verifierDB=verifierDB) verifierDB=verifierDB)
else: else:
Echo.lineReceived(self, data) Echo.lineReceived(self, data)
def connectionLost(self, reason): def connectionLost(self, reason):
pass #Handle any TLS exceptions here pass #Handle any TLS exceptions here
factory = Factory() factory = Factory()
factory.protocol = Echo1 factory.protocol = Echo1
#factory.protocol = Echo2 #factory.protocol = Echo2
wrappingFactory = WrappingFactory(factory) wrappingFactory = WrappingFactory(factory)
wrappingFactory.protocol = TLSTwistedProtocolWrapper wrappingFactory.protocol = TLSTwistedProtocolWrapper
log.startLogging(sys.stdout) log.startLogging(sys.stdout)
reactor.listenTCP(1079, wrappingFactory) reactor.listenTCP(1079, wrappingFactory)
reactor.run() reactor.run()
This class works as follows: This class works as follows:
Data comes in and is given to the AsyncStateMachine for handling. Data comes in and is given to the AsyncStateMachine for handling.
AsyncStateMachine will forward events to this class, and we'll AsyncStateMachine will forward events to this class, and we'll
pass them on to the ProtocolHandler, which will proxy them to the pass them on to the ProtocolHandler, which will proxy them to the
wrapped protocol. The wrapped protocol may then call back into wrapped protocol. The wrapped protocol may then call back into
this class, and these calls will be proxied into the this class, and these calls will be proxied into the
AsyncStateMachine. AsyncStateMachine.
The call graph looks like this: The call graph looks like this:
- self.dataReceived - self.dataReceived
- AsyncStateMachine.inReadEvent - AsyncStateMachine.inReadEvent
- self.out(Connect|Close|Read)Event - self.out(Connect|Close|Read)Event
- ProtocolWrapper.(connectionMade|loseConnection|dataReceived) - ProtocolWrapper.(connectionMade|loseConnection|dataReceived)
- self.(loseConnection|write|writeSequence) - self.(loseConnection|write|writeSequence)
- AsyncStateMachine.(setCloseOp|setWriteOp) - AsyncStateMachine.(setCloseOp|setWriteOp)
""" """
#WARNING: IF YOU COPY-AND-PASTE THE ABOVE CODE, BE SURE TO REMOVE #WARNING: IF YOU COPY-AND-PASTE THE ABOVE CODE, BE SURE TO REMOVE
#THE EXTRA ESCAPING AROUND "\\r\\n" #THE EXTRA ESCAPING AROUND "\\r\\n"
def __init__(self, factory, wrappedProtocol): def __init__(self, factory, wrappedProtocol):
ProtocolWrapper.__init__(self, factory, wrappedProtocol) ProtocolWrapper.__init__(self, factory, wrappedProtocol)
AsyncStateMachine.__init__(self) AsyncStateMachine.__init__(self)
self.fakeSocket = _FakeSocket(self) self.fakeSocket = _FakeSocket(self)
self.tlsConnection = TLSConnection(self.fakeSocket) self.tlsConnection = TLSConnection(self.fakeSocket)
self.tlsStarted = False self.tlsStarted = False
self.connectionLostCalled = False self.connectionLostCalled = False
def connectionMade(self): def connectionMade(self):
try: try:
ProtocolWrapper.connectionMade(self) ProtocolWrapper.connectionMade(self)
except TLSError, e: except TLSError, e:
self.connectionLost(Failure(e)) self.connectionLost(Failure(e))
ProtocolWrapper.loseConnection(self) ProtocolWrapper.loseConnection(self)
def dataReceived(self, data): def dataReceived(self, data):
try: try:
if not self.tlsStarted: if not self.tlsStarted:
ProtocolWrapper.dataReceived(self, data) ProtocolWrapper.dataReceived(self, data)
else: else:
self.fakeSocket.data += data self.fakeSocket.data += data
while self.fakeSocket.data: while self.fakeSocket.data:
AsyncStateMachine.inReadEvent(self) AsyncStateMachine.inReadEvent(self)
except TLSError, e: except TLSError, e:
self.connectionLost(Failure(e)) self.connectionLost(Failure(e))
ProtocolWrapper.loseConnection(self) ProtocolWrapper.loseConnection(self)
def connectionLost(self, reason): def connectionLost(self, reason):
if not self.connectionLostCalled: if not self.connectionLostCalled:
ProtocolWrapper.connectionLost(self, reason) ProtocolWrapper.connectionLost(self, reason)
self.connectionLostCalled = True self.connectionLostCalled = True
def outConnectEvent(self): def outConnectEvent(self):
ProtocolWrapper.connectionMade(self) ProtocolWrapper.connectionMade(self)
def outCloseEvent(self): def outCloseEvent(self):
ProtocolWrapper.loseConnection(self) ProtocolWrapper.loseConnection(self)
def outReadEvent(self, data): def outReadEvent(self, data):
if data == "": if data == "":
ProtocolWrapper.loseConnection(self) ProtocolWrapper.loseConnection(self)
else: else:
ProtocolWrapper.dataReceived(self, data) ProtocolWrapper.dataReceived(self, data)
def setServerHandshakeOp(self, **args): def setServerHandshakeOp(self, **args):
self.tlsStarted = True self.tlsStarted = True
AsyncStateMachine.setServerHandshakeOp(self, **args) AsyncStateMachine.setServerHandshakeOp(self, **args)
def loseConnection(self): def loseConnection(self):
if not self.tlsStarted: if not self.tlsStarted:
ProtocolWrapper.loseConnection(self) ProtocolWrapper.loseConnection(self)
else: else:
AsyncStateMachine.setCloseOp(self) AsyncStateMachine.setCloseOp(self)
def write(self, data): def write(self, data):
if not self.tlsStarted: if not self.tlsStarted:
ProtocolWrapper.write(self, data) ProtocolWrapper.write(self, data)
else: else:
#Because of the FakeSocket, write operations are guaranteed to #Because of the FakeSocket, write operations are guaranteed to
#terminate immediately. #terminate immediately.
AsyncStateMachine.setWriteOp(self, data) AsyncStateMachine.setWriteOp(self, data)
def writeSequence(self, seq): def writeSequence(self, seq):
if not self.tlsStarted: if not self.tlsStarted:
ProtocolWrapper.writeSequence(self, seq) ProtocolWrapper.writeSequence(self, seq)
else: else:
#Because of the FakeSocket, write operations are guaranteed to #Because of the FakeSocket, write operations are guaranteed to
#terminate immediately. #terminate immediately.
AsyncStateMachine.setWriteOp(self, "".join(seq)) AsyncStateMachine.setWriteOp(self, "".join(seq))

View File

@ -1,5 +1,5 @@
"""Pure-Python RSA implementation.""" """Pure-Python RSA implementation."""
from cryptomath import * from cryptomath import *
import xmltools import xmltools
from ASN1Parser import ASN1Parser from ASN1Parser import ASN1Parser
@ -8,7 +8,7 @@ from RSAKey import *
class Python_RSAKey(RSAKey): class Python_RSAKey(RSAKey):
def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0): def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0):
if (n and not e) or (e and not n): if (n and not e) or (e and not n):
raise AssertionError() raise AssertionError()
self.n = n self.n = n
self.e = e self.e = e
self.d = d self.d = d
@ -122,61 +122,61 @@ class Python_RSAKey(RSAKey):
bytes = base64ToBytes(s) bytes = base64ToBytes(s)
return Python_RSAKey._parsePKCS8(bytes) return Python_RSAKey._parsePKCS8(bytes)
else: else:
start = s.find("-----BEGIN RSA PRIVATE KEY-----") start = s.find("-----BEGIN RSA PRIVATE KEY-----")
if start != -1: if start != -1:
end = s.find("-----END RSA PRIVATE KEY-----") end = s.find("-----END RSA PRIVATE KEY-----")
if end == -1: if end == -1:
raise SyntaxError("Missing PEM Postfix") raise SyntaxError("Missing PEM Postfix")
s = s[start+len("-----BEGIN RSA PRIVATE KEY -----") : end] s = s[start+len("-----BEGIN RSA PRIVATE KEY -----") : end]
bytes = base64ToBytes(s) bytes = base64ToBytes(s)
return Python_RSAKey._parseSSLeay(bytes) return Python_RSAKey._parseSSLeay(bytes)
raise SyntaxError("Missing PEM Prefix") raise SyntaxError("Missing PEM Prefix")
parsePEM = staticmethod(parsePEM) parsePEM = staticmethod(parsePEM)
def parseXML(s): def parseXML(s):
element = xmltools.parseAndStripWhitespace(s) element = xmltools.parseAndStripWhitespace(s)
return Python_RSAKey._parseXML(element) return Python_RSAKey._parseXML(element)
parseXML = staticmethod(parseXML) parseXML = staticmethod(parseXML)
def _parsePKCS8(bytes): def _parsePKCS8(bytes):
p = ASN1Parser(bytes) p = ASN1Parser(bytes)
version = p.getChild(0).value[0] version = p.getChild(0).value[0]
if version != 0: if version != 0:
raise SyntaxError("Unrecognized PKCS8 version") raise SyntaxError("Unrecognized PKCS8 version")
rsaOID = p.getChild(1).value rsaOID = p.getChild(1).value
if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]: if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]:
raise SyntaxError("Unrecognized AlgorithmIdentifier") raise SyntaxError("Unrecognized AlgorithmIdentifier")
#Get the privateKey #Get the privateKey
privateKeyP = p.getChild(2) privateKeyP = p.getChild(2)
#Adjust for OCTET STRING encapsulation #Adjust for OCTET STRING encapsulation
privateKeyP = ASN1Parser(privateKeyP.value) privateKeyP = ASN1Parser(privateKeyP.value)
return Python_RSAKey._parseASN1PrivateKey(privateKeyP) return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
_parsePKCS8 = staticmethod(_parsePKCS8) _parsePKCS8 = staticmethod(_parsePKCS8)
def _parseSSLeay(bytes): def _parseSSLeay(bytes):
privateKeyP = ASN1Parser(bytes) privateKeyP = ASN1Parser(bytes)
return Python_RSAKey._parseASN1PrivateKey(privateKeyP) return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
_parseSSLeay = staticmethod(_parseSSLeay) _parseSSLeay = staticmethod(_parseSSLeay)
def _parseASN1PrivateKey(privateKeyP): def _parseASN1PrivateKey(privateKeyP):
version = privateKeyP.getChild(0).value[0] version = privateKeyP.getChild(0).value[0]
if version != 0: if version != 0:
raise SyntaxError("Unrecognized RSAPrivateKey version") raise SyntaxError("Unrecognized RSAPrivateKey version")
n = bytesToNumber(privateKeyP.getChild(1).value) n = bytesToNumber(privateKeyP.getChild(1).value)
e = bytesToNumber(privateKeyP.getChild(2).value) e = bytesToNumber(privateKeyP.getChild(2).value)
d = bytesToNumber(privateKeyP.getChild(3).value) d = bytesToNumber(privateKeyP.getChild(3).value)
p = bytesToNumber(privateKeyP.getChild(4).value) p = bytesToNumber(privateKeyP.getChild(4).value)
q = bytesToNumber(privateKeyP.getChild(5).value) q = bytesToNumber(privateKeyP.getChild(5).value)
dP = bytesToNumber(privateKeyP.getChild(6).value) dP = bytesToNumber(privateKeyP.getChild(6).value)
dQ = bytesToNumber(privateKeyP.getChild(7).value) dQ = bytesToNumber(privateKeyP.getChild(7).value)
qInv = bytesToNumber(privateKeyP.getChild(8).value) qInv = bytesToNumber(privateKeyP.getChild(8).value)
return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv) return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
_parseASN1PrivateKey = staticmethod(_parseASN1PrivateKey) _parseASN1PrivateKey = staticmethod(_parseASN1PrivateKey)
def _parseXML(element): def _parseXML(element):
try: try:

Some files were not shown because too many files have changed in this diff Show More