Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
TLS Lite is a free python library that implements SSL 3.0 and TLS 1.0.
TLS Lite supports non-traditional authentication methods such as SRP,
shared keys,
and cryptoIDs, in addition to X.509 certificates. TLS Lite is pure
Python, however it can access OpenSSL or
cryptlib for faster crypto operations.
Internet-Draft: Using SRP for TLS Authentication (.txt, .html)
SRP is the best way to do password authentication
across a network. TLS (aka SSL v3.1)
is the best way to do channel security. What could go better together?
This draft modifies the TLS handshake to use SRP. This combination of
password-based mutual authentication and the TLS record layer is
ideal for protecting protocols like POP3 and HTTP.
The OASISDigital Signature Service Technical Committee
is designing protocols for signing, verifying, and
time-stamping of XML documents and other data. The idea is to perform these
operations on servers, thus freeing clients from having to manage private
keys, calculate certificate paths, and so on.
Also listed is a paper arguing for the server-based approach vs. client-side PKI.
This is a python script that generates java, python, and C# wrappers for
cryptlib. A set of wrappers for
cryptlib 3.1 is included in the .zip file. The python and C# wrappers are also included in the latest cryptlib distribution.
Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
TLS Lite is a free python library that implements SSL 3.0 and TLS 1.0.
TLS Lite supports non-traditional authentication methods such as SRP,
shared keys,
and cryptoIDs, in addition to X.509 certificates. TLS Lite is pure
Python, however it can access OpenSSL or
cryptlib for faster crypto operations.
Internet-Draft: Using SRP for TLS Authentication (.txt, .html)
SRP is the best way to do password authentication
across a network. TLS (aka SSL v3.1)
is the best way to do channel security. What could go better together?
This draft modifies the TLS handshake to use SRP. This combination of
password-based mutual authentication and the TLS record layer is
ideal for protecting protocols like POP3 and HTTP.
The OASISDigital Signature Service Technical Committee
is designing protocols for signing, verifying, and
time-stamping of XML documents and other data. The idea is to perform these
operations on servers, thus freeing clients from having to manage private
keys, calculate certificate paths, and so on.
Also listed is a paper arguing for the server-based approach vs. client-side PKI.
This is a python script that generates java, python, and C# wrappers for
cryptlib. A set of wrappers for
cryptlib 3.1 is included in the .zip file. The python and C# wrappers are also included in the latest cryptlib distribution.
Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
TLS Lite is a free python library that implements SSL 3.0 and TLS 1.0.
TLS Lite supports non-traditional authentication methods such as SRP,
shared keys,
and cryptoIDs, in addition to X.509 certificates. TLS Lite is pure
Python, however it can access OpenSSL or
cryptlib for faster crypto operations.
Internet-Draft: Using SRP for TLS Authentication (.txt, .html)
SRP is the best way to do password authentication
across a network. TLS (aka SSL v3.1)
is the best way to do channel security. What could go better together?
This draft modifies the TLS handshake to use SRP. This combination of
password-based mutual authentication and the TLS record layer is
ideal for protecting protocols like POP3 and HTTP.
The OASISDigital Signature Service Technical Committee
is designing protocols for signing, verifying, and
time-stamping of XML documents and other data. The idea is to perform these
operations on servers, thus freeing clients from having to manage private
keys, calculate certificate paths, and so on.
Also listed is a paper arguing for the server-based approach vs. client-side PKI.
This is a python script that generates java, python, and C# wrappers for
cryptlib. A set of wrappers for
cryptlib 3.1 is included in the .zip file. The python and C# wrappers are also included in the latest cryptlib distribution.
Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
TLS Lite is a free python library that implements SSL 3.0 and TLS 1.0.
TLS Lite supports non-traditional authentication methods such as SRP,
shared keys,
and cryptoIDs, in addition to X.509 certificates. TLS Lite is pure
Python, however it can access OpenSSL or
cryptlib for faster crypto operations.
Internet-Draft: Using SRP for TLS Authentication (.txt, .html)
SRP is the best way to do password authentication
across a network. TLS (aka SSL v3.1)
is the best way to do channel security. What could go better together?
This draft modifies the TLS handshake to use SRP. This combination of
password-based mutual authentication and the TLS record layer is
ideal for protecting protocols like POP3 and HTTP.
The OASISDigital Signature Service Technical Committee
is designing protocols for signing, verifying, and
time-stamping of XML documents and other data. The idea is to perform these
operations on servers, thus freeing clients from having to manage private
keys, calculate certificate paths, and so on.
Also listed is a paper arguing for the server-based approach vs. client-side PKI.
This is a python script that generates java, python, and C# wrappers for
cryptlib. A set of wrappers for
cryptlib 3.1 is included in the .zip file. The python and C# wrappers are also included in the latest cryptlib distribution.
Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
TLS Lite is a free python library that implements SSL 3.0 and TLS 1.0.
TLS Lite supports non-traditional authentication methods such as SRP,
shared keys,
and cryptoIDs, in addition to X.509 certificates. TLS Lite is pure
Python, however it can access OpenSSL or
cryptlib for faster crypto operations.
Internet-Draft: Using SRP for TLS Authentication (.txt, .html)
SRP is the best way to do password authentication
across a network. TLS (aka SSL v3.1)
is the best way to do channel security. What could go better together?
This draft modifies the TLS handshake to use SRP. This combination of
password-based mutual authentication and the TLS record layer is
ideal for protecting protocols like POP3 and HTTP.
The OASISDigital Signature Service Technical Committee
is designing protocols for signing, verifying, and
time-stamping of XML documents and other data. The idea is to perform these
operations on servers, thus freeing clients from having to manage private
keys, calculate certificate paths, and so on.
Also listed is a paper arguing for the server-based approach vs. client-side PKI.
This is a python script that generates java, python, and C# wrappers for
cryptlib. A set of wrappers for
cryptlib 3.1 is included in the .zip file. The python and C# wrappers are also included in the latest cryptlib distribution.
Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
TLS Lite is a free python library that implements SSL 3.0 and TLS 1.0.
TLS Lite supports non-traditional authentication methods such as SRP,
shared keys,
and cryptoIDs, in addition to X.509 certificates. TLS Lite is pure
Python, however it can access OpenSSL or
cryptlib for faster crypto operations.
Internet-Draft: Using SRP for TLS Authentication (.txt, .html)
SRP is the best way to do password authentication
across a network. TLS (aka SSL v3.1)
is the best way to do channel security. What could go better together?
This draft modifies the TLS handshake to use SRP. This combination of
password-based mutual authentication and the TLS record layer is
ideal for protecting protocols like POP3 and HTTP.
The OASISDigital Signature Service Technical Committee
is designing protocols for signing, verifying, and
time-stamping of XML documents and other data. The idea is to perform these
operations on servers, thus freeing clients from having to manage private
keys, calculate certificate paths, and so on.
Also listed is a paper arguing for the server-based approach vs. client-side PKI.
This is a python script that generates java, python, and C# wrappers for
cryptlib. A set of wrappers for
cryptlib 3.1 is included in the .zip file. The python and C# wrappers are also included in the latest cryptlib distribution.
Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
TLS Lite is a free python library that implements SSL 3.0 and TLS 1.0.
TLS Lite supports non-traditional authentication methods such as SRP,
shared keys,
and cryptoIDs, in addition to X.509 certificates. TLS Lite is pure
Python, however it can access OpenSSL or
cryptlib for faster crypto operations.
Internet-Draft: Using SRP for TLS Authentication (.txt, .html)
SRP is the best way to do password authentication
across a network. TLS (aka SSL v3.1)
is the best way to do channel security. What could go better together?
This draft modifies the TLS handshake to use SRP. This combination of
password-based mutual authentication and the TLS record layer is
ideal for protecting protocols like POP3 and HTTP.
The OASISDigital Signature Service Technical Committee
is designing protocols for signing, verifying, and
time-stamping of XML documents and other data. The idea is to perform these
operations on servers, thus freeing clients from having to manage private
keys, calculate certificate paths, and so on.
Also listed is a paper arguing for the server-based approach vs. client-side PKI.
This is a python script that generates java, python, and C# wrappers for
cryptlib. A set of wrappers for
cryptlib 3.1 is included in the .zip file. The python and C# wrappers are also included in the latest cryptlib distribution.
Paper 1: Public Key Distribution through "cryptoIDs" (.pdf, .html) (presented at NSPW 2003) Paper 2: The CryptoID Key Management Protocols (.pdf) (the best introduction) Schema: XML Schema for <certChain> (.xsd) Code: CryptoIDlib Python and Java library and command-line tool v0.1.8 (.zip, readme.txt)
PKI isn't working for person-to-person communications. Few people use
secure email, voice, instant-messaging, or anything else.
CryptoIDs are an alternative. The idea is for people to exchange small,
user-friendly fingerprints (aka "cryptoIDs") like 'cyhf4.9ajd8.kbdx4.rk98c'.
These could be passed around and stored in address books as if they were phone
numbers or postal addresses.
The cryptoID for each user would correspond to that user's root key.
The user would keep his root key in a safe place - his employer or
some commercial service might hold it for him. The rootholder would operate
an online service which would issue short-lived subkey certificates or validation signatures to the user.
CryptoIDs, then, are about combining fingerprint-based public-key distribution with
certificate-based private-key management. The first paper above presents the
cryptoID fingerprint and certificate formats, which are designed specifically for
this. CryptoIDlib lets you test-drive these formats.
The second paper presents private-key management protocols for use with online servers.
Support for these is being added to cryptoIDlib.
9Ppe0a8m80bzc9Uv7Ix8valp1qF4901xOMI98XGGiO+NMa+DZnypVSc6FV9WUmT4BRs9eMpNRWiL0I+H/O45zw==gJbfcWP62cGH2vWGnbdvd5BK5sg5Yirv4xYtBZMXuwDjTEJCyHKEBDHifprC911sL00VPamVMPBivpfPlbwbcw==o1GUi8oZ94SiTTjKnbL908ZGjxZQpN5LeywpS6EEW0peIR+s7v3GOMTRY5TkNu36rhIo+zGI2PBdNbUFU0l73w==XJ1sKQDEzji46Xfg08m2y66COjLNguW5DW7SNVKEbsS9f6C4Wpt2bA806pqn/6lTiv4h2DSGTKh/RzH6Ztdmdg==
tlslite-0.3.8/test/clientX509Key.pem 0000700 0001750 0001750 00000001567 10016012471 016177 0 ustar clint clint -----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+
dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH
dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB
AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc
esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO
gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl
aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV
VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV
CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv
i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP
wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG
6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH
h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe
-----END RSA PRIVATE KEY-----
tlslite-0.3.8/test/clientCryptoIDChain.xml 0000700 0001750 0001750 00000001227 10062003041 017523 0 ustar clint clint I3xggvcPVOmIBsOzO87lCPNA4Rg=191550P1JB0+Rp+h+wjzyox1RsZtarpaFWCyLYy3SXhTrIOpebu3Ojx2A1iFzzblaUsjVhgRxNmEpBRe31QKKsIhmRCHJwhPkHkf6JsLCTVnM6LpZnvlsSRs0SW/8Rk4xVotESs5jz7dA0nHJi5WcqA2SffgEJ3KPPVNAFsCv4NYMQzU=Aw==
tlslite-0.3.8/test/twistedserver.py 0000700 0001750 0001750 00000003552 10025505376 016452 0 ustar clint clint
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()
tlslite-0.3.8/readme.txt 0000700 0001750 0001750 00000073074 10206512512 014202 0 ustar clint clint
tlslite version 0.3.8 February 21, 2005
Trevor Perrin
http://trevp.net/tlslite/
============================================================================
Table of Contents
==================
1 Introduction
2 License/Acknowledgements
3 Installation
4 Getting Started with the Command-Line Tools
5 Getting Started with the Library
6 Using TLS Lite with httplib
7 Using TLS Lite with xmlrpclib
8 Using TLS Lite with poplib or imaplib
9 Using TLS Lite with smtplib
10 Using TLS Lite with SocketServer
11 Using TLS Lite with asyncore
12 Using TLS Lite with Twisted
13 SECURITY CONSIDERATIONS
14 History
15 References
1 Introduction
===============
TLS Lite is a free python library that implements SSL v3, TLS v1, and
TLS v1.1 [0]. TLS Lite supports non-traditional authentication methods
such as SRP [1], shared keys [2], and cryptoIDs [3], in addition to X.509
certificates. TLS Lite is pure python, however it can access OpenSSL [4],
cryptlib [5], pycrypto [9], and GMPY [10] for faster crypto operations. TLS
Lite integrates with httplib, xmlrpclib, poplib, imaplib, smtplib,
SocketServer, asyncore, and Twisted.
API documentation is available in the 'docs' directory.
If you have questions or feedback, feel free to contact me.
2 Licenses/Acknowledgements
============================
All code here is public domain.
Thanks to Bram Cohen for his public domain Rijndael implementation.
Thanks to Edward Loper for Epydoc, which generated the API docs.
3 Installation
===============
Requirements:
Python 2.2 or greater is required.
Options:
- If you have cryptoIDlib [8], you can use cryptoID certificate chains for
authentication. CryptoIDlib is the sister library to TLS Lite; it was
written by the same author, and has a similar interface.
- If you have the M2Crypto [6] interface to OpenSSL, this will be used for
fast RSA operations and fast ciphers.
- If you have the cryptlib_py [7] interface to cryptlib, this will be used
for random number generation and fast ciphers. If TLS Lite can't find an
OS-level random-number generator (i.e. /dev/urandom on UNIX or CryptoAPI on
Windows), then you must MUST install cryptlib.
- If you have pycrypto [9], this will be used for fast ciphers and fast RSA
operations.
- If you have the GMPY [10] interface to GMP, this will be used for fast RSA
and SRP operations.
- These modules don't need to be present at installation - you can install
them any time.
On Windows:
Run the installer in the 'installers' directory.
*OR*
Run 'setup.py install' (this only works if your system has a compiler
available).
Anywhere else:
- Run 'python setup.py install'
Test the Installation:
- The 'tls.py' script should have been copied onto your path. If not,
you may have to copy it there manually.
- From the distribution's ./test subdirectory, run:
tls.py servertest localhost:4443 .
- While the test server is waiting, run:
tls.py clienttest localhost:4443 .
If both say "Test succeeded" at the end, you're ready to go.
(WARNING: Be careful running these (or any) scripts from the distribution's
root directory. Depending on your path, the scripts may load the local copy
of the library instead of the installed version, with unpredictable
results).
4 Getting Started with the Command-Line Tools
==============================================
tlslite comes with two command-line scripts: 'tlsdb.py' and 'tls.py'. They
can be run with no arguments to see a list of commands.
'tlsdb.py' lets you manage shared key or verifier databases. These databases
store usernames associated with either shared keys, or SRP password verifiers.
These databases are used by a TLS server when authenticating clients with
shared keys or SRP.
'tls.py' lets you run test clients and servers. It can be used for testing
other TLS implementations, or as example code for using tlslite. To run an
SRP server, try something like:
tlsdb.py createsrp verifierDB
tlsdb.py add verifierDB alice abra123cadabra 1024
tlsdb.py add verifierDB bob swordfish 2048
tls.py serversrp localhost:443 verifierDB
Then you can try connecting to the server with:
tls.py clientsrp localhost:443 alice abra123cadabra
5 Getting Started with the Library
===================================
Using the library is simple. Whether you're writing a client or server, there
are six steps:
1) Create a socket and connect it to the other party.
2) Construct a TLSConnection instance with the socket.
3) Call a handshake function on TLSConnection to perform the TLS handshake.
4) Check the results to make sure you're talking to the right party.
5) Use the TLSConnection to exchange data.
6) Call close() on the TLSConnection when you're done.
TLS Lite also integrates with httplib, xmlrpclib, poplib, imaplib, smtplib,
SocketServer, asyncore, and Twisted. When used with these, some of the steps
are performed for you. See the sections following this one for details.
5 Step 1 - create a socket
---------------------------
Below demonstrates a socket connection to Amazon's secure site. It's a good
idea to set the timeout value, so if the other side fails to respond you won't
end up waiting forever.
from socket import *
sock = socket(AF_INET, SOCK_STREAM)
sock.connect( ("www.amazon.com", 443) )
sock.settimeout(10) #Only on python 2.3 or greater
5 Step 2 - construct a TLSConnection
-------------------------------------
from tlslite.api import *
connection = TLSConnection(sock)
5 Step 3 - call a handshake function (client)
----------------------------------------------
If you're a client, there's several different handshake functions you can
call, depending on how you want to authenticate:
connection.handshakeClientCert()
connection.handshakeClientCert(certChain, privateKey)
connection.handshakeClientSRP("alice", "abra123cadabra")
connection.handshakeClientSharedKey("alice", "PaVBVZkYqAjCQCu6UBL2xgsnZhw")
connection.handshakeClientUnknown(srpCallback, certCallback)
The ClientCert function without arguments is used when connecting to a site
like Amazon, which doesn't require client authentication. The server will
authenticate with a certificate chain.
The ClientCert function can also be used to do client authentication with an
X.509 or cryptoID certificate chain. To use cryptoID chains, you'll need the
cryptoIDlib library [8]. To use X.509 chains, you'll need some way of
creating these, such as OpenSSL (see http://www.openssl.org/docs/HOWTO/ for
details).
Below are examples of loading cryptoID and X.509 certificate chains:
#Load cryptoID certChain and privateKey. Requires cryptoIDlib.
from cryptoIDlib.CertChain import CertChain
s = open("./test/clientCryptoIDChain.xml").read()
certChain = CertChain()
certChain.parse(s)
s = open("./test/clientCryptoIDKey.xml").read()
privateKey = parseXMLKey(s, private=True)
#Load X.509 certChain and privateKey.
s = open("./test/clientX509Cert.pem").read()
x509 = X509()
x509.parse(s)
certChain = X509CertChain([x509])
s = open("./test/clientX509Key.pem").read()
privateKey = parsePEMKey(s, private=True)
The SRP and SharedKey functions both do mutual authentication with a username
and password. The difference is this: SRP is slow but safer when using low-
entropy passwords, since the SRP protocol is not vulnerable to offline
dictionary attacks. Using shared keys is faster, but it's only safe when
used with high-entropy secrets. In general, you should prefer SRP for human-
memorable passwords, and use shared keys only when your performance needs
outweigh the inconvenience of handling large random strings.
[WARNING: shared keys and SRP are internet-drafts; these protocols may change,
which means future versions of tlslite may not be compatible with this one.
This is less likely with SRP, more likely with shared-keys.]
The Unknown function is used when you're not sure if the server requires
client authentication. If the server requests SRP or certificate-based
authentication, the appropriate callback will be triggered, and you should
return a tuple containing either a (username, password) or (certChain,
privateKey), as appropriate. Alternatively, you can return None, which will
cancel the handshake from an SRP callback, or cause it to continue without
client authentication (if the server is willing) from a certificate callback.
If you want more control over the handshake, you can pass in a
HandshakeSettings instance. For example, if you're performing SRP, but you
only want to use SRP parameters of at least 2048 bits, and you only want to use
the AES-256 cipher, and you only want to allow TLS (version 3.1), not SSL
(version 3.0), you can do:
settings = HandshakeSettings()
settings.minKeySize = 2048
settings.cipherNames = ["aes256"]
settings.minVersion = (3,1)
connection.handshakeClientSRP("alice", "abra123cadabra", settings=settings)
Finally, every TLSConnection has a session object. You can try to resume a
previous session by passing in the session object from the old session. If
the server remembers this old session and supports resumption, the handshake
will finish more quickly. Otherwise, the full handshake will be done. For
example:
connection.handshakeClientSRP("alice", "abra123cadabra")
.
.
oldSession = connection.session
connection2.handshakeClientSRP("alice", "abra123cadabra", session=
oldSession)
5 Step 3 - call a handshake function (server)
----------------------------------------------
If you're a server, there's only one handshake function, but you can pass it
several different parameters, depending on which types of authentication
you're willing to perform.
To perform SRP authentication, you have to pass in a database of password
verifiers. The VerifierDB class manages an in-memory or on-disk verifier
database.
#On-disk database (use no-arg constructor if you want an in-memory DB)
verifierDB = VerifierDB("./test/verifierDB")
#Open the pre-existing database (can also 'create()' a new one)
verifierDB.open()
#Add to the database
verifier = VerifierDB.makeVerifier("alice", "abra123cadabra", 2048)
verifierDB["alice"] = verifier
#Perform a handshake using the database
connection.handshakeServer(verifierDB=verifierDB)
To perform shared key authentication, you have to pass in a database of shared
keys. The SharedKeyDB class manages an in-memory or on-disk shared key
database.
sharedKeyDB = SharedKeyDB("./test/sharedkeyDB")
sharedKeyDB.open()
sharedKeyDB["alice"] = "PaVBVZkYqAjCQCu6UBL2xgsnZhw"
connection.handshakeServer(sharedKeyDB=sharedKeyDB)
To perform authentication with a certificate and private key, the server must
load these as described in the previous section, then pass them in. If the
server sets the reqCert boolean to True, a certificate chain will be requested
from the client.
connection.handshakeServer(certChain=certChain, privateKey=privateKey,
reqCert=True)
You can pass in any combination of a verifier database, a shared key database,
and a certificate chain/private key. The client will use one of them to
authenticate. In the case of SRP and a certificate chain/private key, they
both may be used.
You can also pass in a HandshakeSettings object, as described in the last
section, for finer control over handshaking details. Finally, the server can
maintain a SessionCache, which will allow clients to use session resumption:
sessionCache = SessionCache()
connection.handshakeServer(verifierDB=verifierDB, sessionCache=sessionCache)
It should be noted that the session cache, and the verifier and shared key
databases, are all thread-safe.
5 Step 4 - check the results
-----------------------------
If the handshake completes without raising an exception, authentication
results will be stored in the connection's session object. The following
variables will be populated if applicable, or else set to None:
connection.session.srpUsername #string
connection.session.sharedKeyUsername #string
connection.session.clientCertChain #X509CertChain or
#cryptoIDlib.CertChain.CertChain
connection.session.serverCertChain #X509CertChain or
#cryptoIDlib.CertChain.CertChain
Both types of certificate chain object support the getFingerprint() function,
but with a difference. X.509 objects return the end-entity fingerprint, and
ignore the other certificates. CryptoID fingerprints (aka "cryptoIDs") are
based on the root cryptoID certificate, so you have to call validate() on the
CertChain to be sure you're really talking to the cryptoID.
X.509 certificate chain objects may also be validated against a list of
trusted root certificates. See the API documentation for details.
To save yourself the trouble of inspecting fingerprints after the handshake,
you can pass a Checker object into the handshake function. The checker will be
called if the handshake completes successfully. If the other party's
certificate chain isn't approved by the checker, a subclass of
TLSAuthenticationError will be raised. For example, to perform a handshake
with a server based on its X.509 fingerprint, do:
try:
checker = Checker(\
x509Fingerprint='e049ff930af76d43ff4c658b268786f4df1296f2')
connection.handshakeClientCert(checker=checker)
except TLSAuthenticationError:
print "Authentication failure"
If the handshake fails for any reason, an exception will be raised. If the
socket timed out or was unexpectedly closed, a socket.error or
TLSAbruptCloseError will be raised. Otherwise, either a TLSLocalAlert or
TLSRemoteAlert will be raised, depending on whether the local or remote
implementation signalled the error. The exception object has a 'description'
member which identifies the error based on the codes in RFC 2246. A
TLSLocalAlert also has a 'message' string that may have more details.
Example of handling a remote alert:
try:
[...]
except TLSRemoteAlert, alert:
if alert.description == AlertDescription.unknown_srp_username:
print "Unknown user."
[...]
Figuring out what went wrong based on the alert may require some
interpretation, particularly with remote alerts where you don't have an error
string, and where the remote implementation may not be signalling alerts
properly. Many alerts signal an implementation error, and so should rarely be
seen in normal operation (unexpected_message, decode_error, illegal_parameter,
internal_error, etc.).
Others alerts are more likely to occur. Below are some common alerts and
their probable causes, and whether they are signalled by the client or server.
Client bad_record_mac:
- bad shared key password
Client handshake failure:
- SRP parameters are not recognized by client
Client user_canceled:
- The client might have returned None from an SRP callback.
Client insufficient_security:
- SRP parameters are too small
Client protocol_version:
- Client doesn't support the server's protocol version
Server protocol_version:
- Server doesn't support the client's protocol version
Server bad_record_mac:
- bad SRP username or password
Server unknown_srp_username
- bad SRP username (bad_record_mac could be used for the same thing)
Server handshake_failure:
- bad shared key username
- no matching cipher suites
5 Step 5 - exchange data
-------------------------
Now that you have a connection, you can call read() and write() as if it were
a socket.SSL object. You can also call send(), sendall(), recv(), and
makefile() as if it were a socket. These calls may raise TLSLocalAlert,
TLSRemoteAlert, socket.error, or TLSAbruptCloseError, just like the handshake
functions.
Once the TLS connection is closed by the other side, calls to read() or recv()
will return an empty string. If the socket is closed by the other side
without first closing the TLS connection, calls to read() or recv() will return
a TLSAbruptCloseError, and calls to write() or send() will return a
socket.error.
5 Step 6 - close the connection
--------------------------------
When you're finished sending data, you should call close() to close the
connection down. When the connection is closed properly, the socket stays
open and can be used for exchanging non-secure data, the session object can be
used for session resumption, and the connection object can be re-used by
calling another handshake function.
If an exception is raised, the connection will be automatically closed; you
don't need to call close(). Furthermore, you will probably not be able to re-
use the socket, the connection object, or the session object, and you
shouldn't even try.
By default, calling close() will leave the socket open. If you set the
connection's closeSocket flag to True, the connection will take ownership of
the socket, and close it when the connection is closed.
6 Using TLS Lite with httplib
==============================
TLS Lite comes with an HTTPTLSConnection class that extends httplib to work
over SSL/TLS connections. Depending on how you construct it, it will do
different types of authentication.
#No authentication whatsoever
h = HTTPTLSConnection("www.amazon.com", 443)
h.request("GET", "")
r = h.getresponse()
[...]
#Authenticate server based on its X.509 fingerprint
h = HTTPTLSConnection("www.amazon.com", 443,
x509Fingerprint="e049ff930af76d43ff4c658b268786f4df1296f2")
[...]
#Authenticate server based on its X.509 chain (requires cryptlib_py [7])
h = HTTPTLSConnection("www.amazon.com", 443,
x509TrustList=[verisignCert],
x509CommonName="www.amazon.com")
[...]
#Authenticate server based on its cryptoID
h = HTTPTLSConnection("localhost", 443,
cryptoID="dmqb6.fq345.cxk6g.5fha3")
[...]
#Mutually authenticate with SRP
h = HTTPTLSConnection("localhost", 443,
username="alice", password="abra123cadabra")
[...]
#Mutually authenticate with a shared key
h = HTTPTLSConnection("localhost", 443,
username="alice", sharedKey="PaVBVZkYqAjCQCu6UBL2xgsnZhw")
[...]
#Mutually authenticate with SRP, *AND* authenticate the server based
#on its cryptoID
h = HTTPTLSConnection("localhost", 443,
username="alice", password="abra123cadabra",
cryptoID="dmqb6.fq345.cxk6g.5fha3")
[...]
7 Using TLS Lite with xmlrpclib
================================
TLS Lite comes with an XMLRPCTransport class that extends xmlrpclib to work
over SSL/TLS connections. This class accepts the same parameters as
HTTPTLSConnection (see previous section), and behaves similarly. Depending on
how you construct it, it will do different types of authentication.
from tlslite.api import XMLRPCTransport
from xmlrpclib import ServerProxy
#No authentication whatsoever
transport = XMLRPCTransport()
server = ServerProxy("https://localhost", transport)
server.someFunc(2, 3)
[...]
#Authenticate server based on its X.509 fingerprint
transport = XMLRPCTransport(\
x509Fingerprint="e049ff930af76d43ff4c658b268786f4df1296f2")
[...]
8 Using TLS Lite with poplib or imaplib
========================================
TLS Lite comes with POP3_TLS and IMAP4_TLS classes that extend poplib and
imaplib to work over SSL/TLS connections. These classes can be constructed
with the same parameters as HTTPTLSConnection (see previous section), and
behave similarly.
#To connect to a POP3 server over SSL and display its fingerprint:
from tlslite.api import *
p = POP3_TLS("---------.net")
print p.sock.session.serverCertChain.getFingerprint()
[...]
#To connect to an IMAP server once you know its fingerprint:
from tlslite.api import *
i = IMAP4_TLS("cyrus.andrew.cmu.edu",
x509Fingerprint="00c14371227b3b677ddb9c4901e6f2aee18d3e45")
[...]
9 Using TLS Lite with smtplib
==============================
TLS Lite comes with an SMTP_TLS class that extends smtplib to work
over SSL/TLS connections. This class accepts the same parameters as
HTTPTLSConnection (see previous section), and behaves similarly. Depending
on how you call starttls(), it will do different types of authentication.
#To connect to an SMTP server once you know its fingerprint:
from tlslite.api import *
s = SMTP_TLS("----------.net")
s.starttls(x509Fingerprint="7e39be84a2e3a7ad071752e3001d931bf82c32dc")
[...]
10 Using TLS Lite with SocketServer
====================================
You can use TLS Lite to implement servers using Python's SocketServer
framework. TLS Lite comes with a TLSSocketServerMixIn class. You can combine
this with a TCPServer such as HTTPServer. To combine them, define a new class
that inherits from both of them (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()
11 Using TLS Lite with asyncore
================================
TLS Lite can be used with subclasses of asyncore.dispatcher. See the comments
in TLSAsyncDispatcherMixIn.py for details. This is still experimental, and
may not work with all asyncore.dispatcher subclasses.
Below is an example of combining Medusa's http_channel with
TLSAsyncDispatcherMixIn:
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)
12 Using TLS Lite with Twisted
===============================
TLS Lite can be used with Twisted protocols. 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()
13 Security Considerations
===========================
TLS Lite is beta-quality code. It hasn't received much security analysis.
Use at your own risk.
14 History
===========
0.3.8 - 2/21/2005
- Added support for poplib, imaplib, and smtplib
- Added python 2.4 windows installer
- Fixed occassional timing problems with test suite
0.3.7 - 10/05/2004
- Added support for Python 2.2
- Cleaned up compatibility code, and docs, a bit
0.3.6 - 9/28/2004
- Fixed script installation on UNIX
- Give better error message on old Python versions
0.3.5 - 9/16/2004
- TLS 1.1 support
- os.urandom() support
- Fixed win32prng on some systems
0.3.4 - 9/12/2004
- Updated for TLS/SRP draft 8
- Bugfix: was setting _versioncheck on SRP 1st hello, causing problems
with GnuTLS (which was offering TLS 1.1)
- Removed _versioncheck checking, since it could cause interop problems
- Minor bugfix: when cryptlib_py and and cryptoIDlib present, cryptlib
was complaining about being initialized twice
0.3.3 - 6/10/2004
- Updated for TLS/SRP draft 7
- Updated test cryptoID cert chains for cryptoIDlib 0.3.1
0.3.2 - 5/21/2004
- fixed bug when handling multiple handshake messages per record (e.g. IIS)
0.3.1 - 4/21/2004
- added xmlrpclib integration
- fixed hanging bug in Twisted integration
- fixed win32prng to work on a wider range of win32 sytems
- fixed import problem with cryptoIDlib
- fixed port allocation problem when test scripts are run on some UNIXes
- made tolerant of buggy IE sending wrong version in premaster secret
0.3.0 - 3/20/2004
- added API docs thanks to epydoc
- added X.509 path validation via cryptlib
- much cleaning/tweaking/re-factoring/minor fixes
0.2.7 - 3/12/2004
- changed Twisted error handling to use connectionLost()
- added ignoreAbruptClose
0.2.6 - 3/11/2004
- added Twisted errorHandler
- added TLSAbruptCloseError
- added 'integration' subdirectory
0.2.5 - 3/10/2004
- improved asynchronous support a bit
- added first-draft of Twisted support
0.2.4 - 3/5/2004
- cleaned up asyncore support
- added proof-of-concept for Twisted
0.2.3 - 3/4/2004
- added pycrypto RSA support
- added asyncore support
0.2.2 - 3/1/2004
- added GMPY support
- added pycrypto support
- added support for PEM-encoded private keys, in pure python
0.2.1 - 2/23/2004
- improved PRNG use (cryptlib, or /dev/random, or CryptoAPI)
- added RSA blinding, to avoid timing attacks
- don't install local copy of M2Crypto, too problematic
0.2.0 - 2/19/2004
- changed VerifierDB to take per-user parameters
- renamed tls_lite -> tlslite
0.1.9 - 2/16/2004
- added post-handshake 'Checker'
- made compatible with Python 2.2
- made more forgiving of abrupt closure, since everyone does it:
if the socket is closed while sending/recv'ing close_notify,
just ignore it.
0.1.8 - 2/12/2004
- TLSConnections now emulate sockets, including makefile()
- HTTPTLSConnection and TLSMixIn simplified as a result
0.1.7 - 2/11/2004
- fixed httplib.HTTPTLSConnection with multiple requests
- fixed SocketServer to handle close_notify
- changed handshakeClientNoAuth() to ignore CertificateRequests
- changed handshakeClient() to ignore non-resumable session arguments
0.1.6 - 2/10/2004
- fixed httplib support
0.1.5 - 2/09/2004
- added support for httplib and SocketServer
- added support for SSLv3
- added support for 3DES
- cleaned up read()/write() behavior
- improved HMAC speed
0.1.4 - 2/06/2004
- fixed dumb bug in tls.py
0.1.3 - 2/05/2004
- change read() to only return requested number of bytes
- added support for shared-key and in-memory databases
- added support for PEM-encoded X.509 certificates
- added support for SSLv2 ClientHello
- fixed shutdown/re-handshaking behavior
- cleaned up handling of missing_srp_username
- renamed readString()/writeString() -> read()/write()
- added documentation
0.1.2 - 2/04/2004
- added clienttest/servertest functions
- improved OpenSSL cipher wrappers speed
- fixed server when it has a key, but client selects plain SRP
- fixed server to postpone errors until it has read client's messages
- fixed ServerHello to only include extension data if necessary
0.1.1 - 2/02/2004
- fixed close_notify behavior
- fixed handling of empty application data packets
- fixed socket reads to not consume extra bytes
- added testing functions to tls.py
0.1.0 - 2/01/2004
- first release
15 References
==============
[0] http://www.ietf.org/html.charters/tls-charter.html
[1] http://www.trevp.net/tls_srp/draft-ietf-tls-srp-07.html
[2] http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt
[3] http://www.trevp.net/cryptoID/
[4] http://www.openssl.org/
[5] http://www.cs.auckland.ac.nz/~pgut001/cryptlib/
[6] http://sandbox.rulemaker.net/ngps/m2/
[7] http://trevp.net/cryptlibConverter/
[8] http://www.trevp.net/cryptoID/
[9] http://www.amk.ca/python/code/crypto.html
[10] http://gmpy.sourceforge.net/
tlslite-0.3.8/tlslite/ 0000700 0001750 0001750 00000000000 10206516251 013652 5 ustar clint clint tlslite-0.3.8/tlslite/mathtls.py 0000700 0001750 0001750 00000026577 10130676033 015725 0 ustar clint clint """Miscellaneous helper functions."""
from utils.compat import *
from utils.cryptomath import *
import hmac
import md5
import sha
#1024, 1536, 2048, 3072, 4096, 6144, and 8192 bit groups]
goodGroupParameters = [(2,0xEEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3),\
(2,0x9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA9614B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F84380B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0BE3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF56EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734AF7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB),\
(2,0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73),\
(2,0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF),\
(5,0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF),\
(5,0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF),\
(5,0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF)]
def P_hash(hashModule, secret, seed, length):
bytes = createByteArrayZeros(length)
secret = bytesToString(secret)
seed = bytesToString(seed)
A = seed
index = 0
while 1:
A = hmac.HMAC(secret, A, hashModule).digest()
output = hmac.HMAC(secret, A+seed, hashModule).digest()
for c in output:
if index >= length:
return bytes
bytes[index] = ord(c)
index += 1
return bytes
def PRF(secret, label, seed, length):
#Split the secret into left and right halves
S1 = secret[ : int(math.ceil(len(secret)/2.0))]
S2 = secret[ int(math.floor(len(secret)/2.0)) : ]
#Run the left half through P_MD5 and the right half through P_SHA1
p_md5 = P_hash(md5, S1, concatArrays(stringToBytes(label), seed), length)
p_sha1 = P_hash(sha, S2, concatArrays(stringToBytes(label), seed), length)
#XOR the output values and return the result
for x in range(length):
p_md5[x] ^= p_sha1[x]
return p_md5
def PRF_SSL(secret, seed, length):
secretStr = bytesToString(secret)
seedStr = bytesToString(seed)
bytes = createByteArrayZeros(length)
index = 0
for x in range(26):
A = chr(ord('A')+x) * (x+1) # 'A', 'BB', 'CCC', etc..
input = secretStr + sha.sha(A + secretStr + seedStr).digest()
output = md5.md5(input).digest()
for c in output:
if index >= length:
return bytes
bytes[index] = ord(c)
index += 1
return bytes
def makeX(salt, username, password):
if len(username)>=256:
raise ValueError("username too long")
if len(salt)>=256:
raise ValueError("salt too long")
return stringToNumber(sha.sha(salt + sha.sha(username + ":" + password)\
.digest()).digest())
#This function is used by VerifierDB.makeVerifier
def makeVerifier(username, password, bits):
bitsIndex = {1024:0, 1536:1, 2048:2, 3072:3, 4096:4, 6144:5, 8192:6}[bits]
g,N = goodGroupParameters[bitsIndex]
salt = bytesToString(getRandomBytes(16))
x = makeX(salt, username, password)
verifier = powMod(g, x, N)
return N, g, salt, verifier
def PAD(n, x):
nLength = len(numberToString(n))
s = numberToString(x)
if len(s) < nLength:
s = ("\0" * (nLength-len(s))) + s
return s
def makeU(N, A, B):
return stringToNumber(sha.sha(PAD(N, A) + PAD(N, B)).digest())
def makeK(N, g):
return stringToNumber(sha.sha(numberToString(N) + PAD(N, g)).digest())
"""
MAC_SSL
Modified from Python HMAC by Trevor
"""
class MAC_SSL:
"""MAC_SSL class.
This supports the API for Cryptographic Hash Functions (PEP 247).
"""
def __init__(self, key, msg = None, digestmod = None):
"""Create a new MAC_SSL object.
key: key for the keyed hash object.
msg: Initial input for the hash, if provided.
digestmod: A module supporting PEP 247. Defaults to the md5 module.
"""
if digestmod is None:
import md5
digestmod = md5
if key == None: #TREVNEW - for faster copying
return #TREVNEW
self.digestmod = digestmod
self.outer = digestmod.new()
self.inner = digestmod.new()
self.digest_size = digestmod.digest_size
ipad = "\x36" * 40
opad = "\x5C" * 40
self.inner.update(key)
self.inner.update(ipad)
self.outer.update(key)
self.outer.update(opad)
if msg is not None:
self.update(msg)
def update(self, msg):
"""Update this hashing object with the string msg.
"""
self.inner.update(msg)
def copy(self):
"""Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
"""
other = MAC_SSL(None) #TREVNEW - for faster copying
other.digest_size = self.digest_size #TREVNEW
other.digestmod = self.digestmod
other.inner = self.inner.copy()
other.outer = self.outer.copy()
return other
def digest(self):
"""Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is
not altered in any way by this function; you can continue
updating the object after calling this function.
"""
h = self.outer.copy()
h.update(self.inner.digest())
return h.digest()
def hexdigest(self):
"""Like digest(), but returns a string of hexadecimal digits instead.
"""
return "".join([hex(ord(x))[2:].zfill(2)
for x in tuple(self.digest())])
tlslite-0.3.8/tlslite/X509.py 0000700 0001750 0001750 00000010277 10026720667 014713 0 ustar clint clint """Class representing an X.509 certificate."""
from utils.ASN1Parser import ASN1Parser
from utils.cryptomath import *
from utils.keyfactory import _createPublicRSAKey
class X509:
"""This class represents an X.509 certificate.
@type bytes: L{array.array} of unsigned bytes
@ivar bytes: The DER-encoded ASN.1 certificate
@type publicKey: L{tlslite.utils.RSAKey.RSAKey}
@ivar publicKey: The subject public key from the certificate.
"""
def __init__(self):
self.bytes = createByteArraySequence([])
self.publicKey = None
def parse(self, s):
"""Parse a PEM-encoded X.509 certificate.
@type s: str
@param s: A PEM-encoded X.509 certificate (i.e. a base64-encoded
certificate wrapped with "-----BEGIN CERTIFICATE-----" and
"-----END CERTIFICATE-----" tags).
"""
start = s.find("-----BEGIN CERTIFICATE-----")
end = s.find("-----END CERTIFICATE-----")
if start == -1:
raise SyntaxError("Missing PEM prefix")
if end == -1:
raise SyntaxError("Missing PEM postfix")
s = s[start+len("-----BEGIN CERTIFICATE-----") : end]
bytes = base64ToBytes(s)
self.parseBinary(bytes)
return self
def parseBinary(self, bytes):
"""Parse a DER-encoded X.509 certificate.
@type bytes: str or L{array.array} of unsigned bytes
@param bytes: A DER-encoded X.509 certificate.
"""
if isinstance(bytes, type("")):
bytes = stringToBytes(bytes)
self.bytes = bytes
p = ASN1Parser(bytes)
#Get the tbsCertificate
tbsCertificateP = p.getChild(0)
#Is the optional version field present?
#This determines which index the key is at.
if tbsCertificateP.value[0]==0xA0:
subjectPublicKeyInfoIndex = 6
else:
subjectPublicKeyInfoIndex = 5
#Get the subjectPublicKeyInfo
subjectPublicKeyInfoP = tbsCertificateP.getChild(\
subjectPublicKeyInfoIndex)
#Get the algorithm
algorithmP = subjectPublicKeyInfoP.getChild(0)
rsaOID = algorithmP.value
if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]:
raise SyntaxError("Unrecognized AlgorithmIdentifier")
#Get the subjectPublicKey
subjectPublicKeyP = subjectPublicKeyInfoP.getChild(1)
#Adjust for BIT STRING encapsulation
if (subjectPublicKeyP.value[0] !=0):
raise SyntaxError()
subjectPublicKeyP = ASN1Parser(subjectPublicKeyP.value[1:])
#Get the modulus and exponent
modulusP = subjectPublicKeyP.getChild(0)
publicExponentP = subjectPublicKeyP.getChild(1)
#Decode them into numbers
n = bytesToNumber(modulusP.value)
e = bytesToNumber(publicExponentP.value)
#Create a public key instance
self.publicKey = _createPublicRSAKey(n, e)
def getFingerprint(self):
"""Get the hex-encoded fingerprint of this certificate.
@rtype: str
@return: A hex-encoded fingerprint.
"""
return sha.sha(self.bytes).hexdigest()
def getCommonName(self):
"""Get the Subject's Common Name from the certificate.
The cryptlib_py module must be installed in order to use this
function.
@rtype: str or None
@return: The CN component of the certificate's subject DN, if
present.
"""
import cryptlib_py
import array
c = cryptlib_py.cryptImportCert(self.bytes, cryptlib_py.CRYPT_UNUSED)
name = cryptlib_py.CRYPT_CERTINFO_COMMONNAME
try:
try:
length = cryptlib_py.cryptGetAttributeString(c, name, None)
returnVal = array.array('B', [0] * length)
cryptlib_py.cryptGetAttributeString(c, name, returnVal)
returnVal = returnVal.tostring()
except cryptlib_py.CryptException, e:
if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND:
returnVal = None
return returnVal
finally:
cryptlib_py.cryptDestroyCert(c)
def writeBytes(self):
return self.bytes
tlslite-0.3.8/tlslite/Checker.py 0000700 0001750 0001750 00000014235 10076624155 015610 0 ustar clint clint """Class for post-handshake certificate checking."""
from utils.cryptomath import hashAndBase64
from X509 import X509
from X509CertChain import X509CertChain
from errors import *
class Checker:
"""This class is passed to a handshake function to check the other
party's certificate chain.
If a handshake function completes successfully, but the Checker
judges the other party's certificate chain to be missing or
inadequate, a subclass of
L{tlslite.errors.TLSAuthenticationError} will be raised.
Currently, the Checker can check either an X.509 or a cryptoID
chain (for the latter, cryptoIDlib must be installed).
"""
def __init__(self, cryptoID=None, protocol=None,
x509Fingerprint=None,
x509TrustList=None, x509CommonName=None,
checkResumedSession=False):
"""Create a new Checker instance.
You must pass in one of these argument combinations:
- cryptoID[, protocol] (requires cryptoIDlib)
- x509Fingerprint
- x509TrustList[, x509CommonName] (requires cryptlib_py)
@type cryptoID: str
@param cryptoID: A cryptoID which the other party's certificate
chain must match. The cryptoIDlib module must be installed.
Mutually exclusive with all of the 'x509...' arguments.
@type protocol: str
@param protocol: A cryptoID protocol URI which the other
party's certificate chain must match. Requires the 'cryptoID'
argument.
@type x509Fingerprint: str
@param x509Fingerprint: A hex-encoded X.509 end-entity
fingerprint which the other party's end-entity certificate must
match. 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. 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 checkResumedSession: bool
@param checkResumedSession: If resumed sessions should be
checked. This defaults to False, on the theory that if the
session was checked once, we don't need to bother
re-checking it.
"""
if cryptoID and (x509Fingerprint or x509TrustList):
raise ValueError()
if x509Fingerprint and x509TrustList:
raise ValueError()
if x509CommonName and not x509TrustList:
raise ValueError()
if protocol and not cryptoID:
raise ValueError()
if cryptoID:
import cryptoIDlib #So we raise an error here
if x509TrustList:
import cryptlib_py #So we raise an error here
self.cryptoID = cryptoID
self.protocol = protocol
self.x509Fingerprint = x509Fingerprint
self.x509TrustList = x509TrustList
self.x509CommonName = x509CommonName
self.checkResumedSession = checkResumedSession
def __call__(self, connection):
"""Check a TLSConnection.
When a Checker is passed to a handshake function, this will
be called at the end of the function.
@type connection: L{tlslite.TLSConnection.TLSConnection}
@param connection: The TLSConnection to examine.
@raise tlslite.errors.TLSAuthenticationError: If the other
party's certificate chain is missing or bad.
"""
if not self.checkResumedSession and connection.resumed:
return
if self.cryptoID or self.x509Fingerprint or self.x509TrustList:
if connection._client:
chain = connection.session.serverCertChain
else:
chain = connection.session.clientCertChain
if self.x509Fingerprint or self.x509TrustList:
if isinstance(chain, X509CertChain):
if self.x509Fingerprint:
if chain.getFingerprint() != self.x509Fingerprint:
raise TLSFingerprintError(\
"X.509 fingerprint mismatch: %s, %s" % \
(chain.getFingerprint(), self.x509Fingerprint))
else: #self.x509TrustList
if not chain.validate(self.x509TrustList):
raise TLSValidationError("X.509 validation failure")
if self.x509CommonName and \
(chain.getCommonName() != self.x509CommonName):
raise TLSAuthorizationError(\
"X.509 Common Name mismatch: %s, %s" % \
(chain.getCommonName(), self.x509CommonName))
elif chain:
raise TLSAuthenticationTypeError()
else:
raise TLSNoAuthenticationError()
elif self.cryptoID:
import cryptoIDlib.CertChain
if isinstance(chain, cryptoIDlib.CertChain.CertChain):
if chain.cryptoID != self.cryptoID:
raise TLSFingerprintError(\
"cryptoID mismatch: %s, %s" % \
(chain.cryptoID, self.cryptoID))
if self.protocol:
if not chain.checkProtocol(self.protocol):
raise TLSAuthorizationError(\
"cryptoID protocol mismatch")
if not chain.validate():
raise TLSValidationError("cryptoID validation failure")
elif chain:
raise TLSAuthenticationTypeError()
else:
raise TLSNoAuthenticationError()
tlslite-0.3.8/tlslite/SessionCache.py 0000700 0001750 0001750 00000006616 10027154175 016613 0 ustar clint clint """Class for caching TLS sessions."""
import thread
import time
class SessionCache:
"""This class is used by the server to cache TLS sessions.
Caching sessions allows the client to use TLS session resumption
and avoid the expense of a full handshake. To use this class,
simply pass a SessionCache instance into the server handshake
function.
This class is thread-safe.
"""
#References to these instances
#are also held by the caller, who may change the 'resumable'
#flag, so the SessionCache must return the same instances
#it was passed in.
def __init__(self, maxEntries=10000, maxAge=14400):
"""Create a new SessionCache.
@type maxEntries: int
@param maxEntries: The maximum size of the cache. When this
limit is reached, the oldest sessions will be deleted as
necessary to make room for new ones. The default is 10000.
@type maxAge: int
@param maxAge: The number of seconds before a session expires
from the cache. The default is 14400 (i.e. 4 hours)."""
self.lock = thread.allocate_lock()
# Maps sessionIDs to sessions
self.entriesDict = {}
#Circular list of (sessionID, timestamp) pairs
self.entriesList = [(None,None)] * maxEntries
self.firstIndex = 0
self.lastIndex = 0
self.maxAge = maxAge
def __getitem__(self, sessionID):
self.lock.acquire()
try:
self._purge() #Delete old items, so we're assured of a new one
session = self.entriesDict[sessionID]
#When we add sessions they're resumable, but it's possible
#for the session to be invalidated later on (if a fatal alert
#is returned), so we have to check for resumability before
#returning the session.
if session.valid():
return session
else:
raise KeyError()
finally:
self.lock.release()
def __setitem__(self, sessionID, session):
self.lock.acquire()
try:
#Add the new element
self.entriesDict[sessionID] = session
self.entriesList[self.lastIndex] = (sessionID, time.time())
self.lastIndex = (self.lastIndex+1) % len(self.entriesList)
#If the cache is full, we delete the oldest element to make an
#empty space
if self.lastIndex == self.firstIndex:
del(self.entriesDict[self.entriesList[self.firstIndex][0]])
self.firstIndex = (self.firstIndex+1) % len(self.entriesList)
finally:
self.lock.release()
#Delete expired items
def _purge(self):
currentTime = time.time()
#Search through the circular list, deleting expired elements until
#we reach a non-expired element. Since elements in list are
#ordered in time, we can break once we reach the first non-expired
#element
index = self.firstIndex
while index != self.lastIndex:
if currentTime - self.entriesList[index][1] > self.maxAge:
del(self.entriesDict[self.entriesList[index][0]])
index = (index+1) % len(self.entriesList)
else:
break
self.firstIndex = index
def _test():
import doctest, SessionCache
return doctest.testmod(SessionCache)
if __name__ == "__main__":
_test()
tlslite-0.3.8/tlslite/__init__.py 0000700 0001750 0001750 00000002151 10206510660 015763 0 ustar clint clint """
TLS Lite is a free python library that implements SSL v3, TLS v1, and
TLS v1.1. TLS Lite supports non-traditional authentication methods
such as SRP, shared keys, and cryptoIDs, in addition to X.509
certificates. TLS Lite is pure python, however it can access OpenSSL,
cryptlib, pycrypto, and GMPY for faster crypto operations. TLS Lite
integrates with httplib, xmlrpclib, poplib, imaplib, smtplib,
SocketServer, asyncore, and Twisted.
To use, do::
from tlslite.api import *
Then use the L{tlslite.TLSConnection.TLSConnection} class with a socket,
or use one of the integration classes in L{tlslite.integration}.
@version: 0.3.8
"""
__version__ = "0.3.8"
__all__ = ["api",
"BaseDB",
"Checker",
"constants",
"errors",
"FileObject",
"HandshakeSettings",
"mathtls",
"messages",
"Session",
"SessionCache",
"SharedKeyDB",
"TLSConnection",
"TLSRecordLayer",
"VerifierDB",
"X509",
"X509CertChain",
"integration",
"utils"]
tlslite-0.3.8/tlslite/SharedKeyDB.py 0000700 0001750 0001750 00000003572 10130676061 016325 0 ustar clint clint """Class for storing shared keys."""
from utils.cryptomath import *
from utils.compat import *
from mathtls import *
from Session import Session
from BaseDB import BaseDB
class SharedKeyDB(BaseDB):
"""This class represent an in-memory or on-disk database of shared
keys.
A SharedKeyDB can be passed to a server handshake function to
authenticate a client based on one of the shared keys.
This class is thread-safe.
"""
def __init__(self, filename=None):
"""Create a new SharedKeyDB.
@type filename: str
@param filename: Filename for an on-disk database, or None for
an in-memory database. If the filename already exists, follow
this with a call to open(). To create a new on-disk database,
follow this with a call to create().
"""
BaseDB.__init__(self, filename, "shared key")
def _getItem(self, username, valueStr):
session = Session()
session._createSharedKey(username, valueStr)
return session
def __setitem__(self, username, sharedKey):
"""Add a shared key to the database.
@type username: str
@param username: The username to associate the shared key with.
Must be less than or equal to 16 characters in length, and must
not already be in the database.
@type sharedKey: str
@param sharedKey: The shared key to add. Must be less than 48
characters in length.
"""
BaseDB.__setitem__(self, username, sharedKey)
def _setItem(self, username, value):
if len(username)>16:
raise ValueError("username too long")
if len(value)>=48:
raise ValueError("shared key too long")
return value
def _checkItem(self, value, username, param):
newSession = self._getItem(username, param)
return value.masterSecret == newSession.masterSecret tlslite-0.3.8/tlslite/X509CertChain.py 0000700 0001750 0001750 00000015315 10026721506 016463 0 ustar clint clint """Class representing an X.509 certificate chain."""
from utils import cryptomath
class X509CertChain:
"""This class represents a chain of X.509 certificates.
@type x509List: list
@ivar x509List: A list of L{tlslite.X509.X509} instances,
starting with the end-entity certificate and with every
subsequent certificate certifying the previous.
"""
def __init__(self, x509List=None):
"""Create a new X509CertChain.
@type x509List: list
@param x509List: A list of L{tlslite.X509.X509} instances,
starting with the end-entity certificate and with every
subsequent certificate certifying the previous.
"""
if x509List:
self.x509List = x509List
else:
self.x509List = []
def getNumCerts(self):
"""Get the number of certificates in this chain.
@rtype: int
"""
return len(self.x509List)
def getEndEntityPublicKey(self):
"""Get the public key from the end-entity certificate.
@rtype: L{tlslite.utils.RSAKey.RSAKey}
"""
if self.getNumCerts() == 0:
raise AssertionError()
return self.x509List[0].publicKey
def getFingerprint(self):
"""Get the hex-encoded fingerprint of the end-entity certificate.
@rtype: str
@return: A hex-encoded fingerprint.
"""
if self.getNumCerts() == 0:
raise AssertionError()
return self.x509List[0].getFingerprint()
def getCommonName(self):
"""Get the Subject's Common Name from the end-entity certificate.
The cryptlib_py module must be installed in order to use this
function.
@rtype: str or None
@return: The CN component of the certificate's subject DN, if
present.
"""
if self.getNumCerts() == 0:
raise AssertionError()
return self.x509List[0].getCommonName()
def validate(self, x509TrustList):
"""Check the validity of the certificate chain.
This checks that every certificate in the chain validates with
the subsequent one, until some certificate validates with (or
is identical to) one of the passed-in root certificates.
The cryptlib_py module must be installed in order to use this
function.
@type x509TrustList: list of L{tlslite.X509.X509}
@param x509TrustList: A list of trusted root certificates. The
certificate chain must extend to one of these certificates to
be considered valid.
"""
import cryptlib_py
c1 = None
c2 = None
lastC = None
rootC = None
try:
rootFingerprints = [c.getFingerprint() for c in x509TrustList]
#Check that every certificate in the chain validates with the
#next one
for cert1, cert2 in zip(self.x509List, self.x509List[1:]):
#If we come upon a root certificate, we're done.
if cert1.getFingerprint() in rootFingerprints:
return True
c1 = cryptlib_py.cryptImportCert(cert1.writeBytes(),
cryptlib_py.CRYPT_UNUSED)
c2 = cryptlib_py.cryptImportCert(cert2.writeBytes(),
cryptlib_py.CRYPT_UNUSED)
try:
cryptlib_py.cryptCheckCert(c1, c2)
except:
return False
cryptlib_py.cryptDestroyCert(c1)
c1 = None
cryptlib_py.cryptDestroyCert(c2)
c2 = None
#If the last certificate is one of the root certificates, we're
#done.
if self.x509List[-1].getFingerprint() in rootFingerprints:
return True
#Otherwise, find a root certificate that the last certificate
#chains to, and validate them.
lastC = cryptlib_py.cryptImportCert(self.x509List[-1].writeBytes(),
cryptlib_py.CRYPT_UNUSED)
for rootCert in x509TrustList:
rootC = cryptlib_py.cryptImportCert(rootCert.writeBytes(),
cryptlib_py.CRYPT_UNUSED)
if self._checkChaining(lastC, rootC):
try:
cryptlib_py.cryptCheckCert(lastC, rootC)
return True
except:
return False
return False
finally:
if not (c1 is None):
cryptlib_py.cryptDestroyCert(c1)
if not (c2 is None):
cryptlib_py.cryptDestroyCert(c2)
if not (lastC is None):
cryptlib_py.cryptDestroyCert(lastC)
if not (rootC is None):
cryptlib_py.cryptDestroyCert(rootC)
def _checkChaining(self, lastC, rootC):
import cryptlib_py
import array
def compareNames(name):
try:
length = cryptlib_py.cryptGetAttributeString(lastC, name, None)
lastName = array.array('B', [0] * length)
cryptlib_py.cryptGetAttributeString(lastC, name, lastName)
lastName = lastName.tostring()
except cryptlib_py.CryptException, e:
if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND:
lastName = None
try:
length = cryptlib_py.cryptGetAttributeString(rootC, name, None)
rootName = array.array('B', [0] * length)
cryptlib_py.cryptGetAttributeString(rootC, name, rootName)
rootName = rootName.tostring()
except cryptlib_py.CryptException, e:
if e[0] == cryptlib_py.CRYPT_ERROR_NOTFOUND:
rootName = None
return lastName == rootName
cryptlib_py.cryptSetAttribute(lastC,
cryptlib_py.CRYPT_CERTINFO_ISSUERNAME,
cryptlib_py.CRYPT_UNUSED)
if not compareNames(cryptlib_py.CRYPT_CERTINFO_COUNTRYNAME):
return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_LOCALITYNAME):
return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONNAME):
return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_ORGANIZATIONALUNITNAME):
return False
if not compareNames(cryptlib_py.CRYPT_CERTINFO_COMMONNAME):
return False
return True tlslite-0.3.8/tlslite/FileObject.py 0000700 0001750 0001750 00000015227 10025502224 016236 0 ustar clint clint """Class returned by TLSConnection.makefile()."""
class FileObject:
"""This class provides a file object interface to a
L{tlslite.TLSConnection.TLSConnection}.
Call makefile() on a TLSConnection to create a FileObject instance.
This class was copied, with minor modifications, from the
_fileobject class in socket.py. Note that fileno() is not
implemented."""
default_bufsize = 16384 #TREV: changed from 8192
def __init__(self, sock, mode='rb', bufsize=-1):
self._sock = sock
self.mode = mode # Not actually used in this version
if bufsize < 0:
bufsize = self.default_bufsize
self.bufsize = bufsize
self.softspace = False
if bufsize == 0:
self._rbufsize = 1
elif bufsize == 1:
self._rbufsize = self.default_bufsize
else:
self._rbufsize = bufsize
self._wbufsize = bufsize
self._rbuf = "" # A string
self._wbuf = [] # A list of strings
def _getclosed(self):
return self._sock is not None
closed = property(_getclosed, doc="True if the file is closed")
def close(self):
try:
if self._sock:
for result in self._sock._decrefAsync(): #TREV
pass
finally:
self._sock = None
def __del__(self):
try:
self.close()
except:
# close() may fail if __init__ didn't complete
pass
def flush(self):
if self._wbuf:
buffer = "".join(self._wbuf)
self._wbuf = []
self._sock.sendall(buffer)
#def fileno(self):
# raise NotImplementedError() #TREV
def write(self, data):
data = str(data) # XXX Should really reject non-string non-buffers
if not data:
return
self._wbuf.append(data)
if (self._wbufsize == 0 or
self._wbufsize == 1 and '\n' in data or
self._get_wbuf_len() >= self._wbufsize):
self.flush()
def writelines(self, list):
# XXX We could do better here for very long lists
# XXX Should really reject non-string non-buffers
self._wbuf.extend(filter(None, map(str, list)))
if (self._wbufsize <= 1 or
self._get_wbuf_len() >= self._wbufsize):
self.flush()
def _get_wbuf_len(self):
buf_len = 0
for x in self._wbuf:
buf_len += len(x)
return buf_len
def read(self, size=-1):
data = self._rbuf
if size < 0:
# Read until EOF
buffers = []
if data:
buffers.append(data)
self._rbuf = ""
if self._rbufsize <= 1:
recv_size = self.default_bufsize
else:
recv_size = self._rbufsize
while True:
data = self._sock.recv(recv_size)
if not data:
break
buffers.append(data)
return "".join(buffers)
else:
# Read until size bytes or EOF seen, whichever comes first
buf_len = len(data)
if buf_len >= size:
self._rbuf = data[size:]
return data[:size]
buffers = []
if data:
buffers.append(data)
self._rbuf = ""
while True:
left = size - buf_len
recv_size = max(self._rbufsize, left)
data = self._sock.recv(recv_size)
if not data:
break
buffers.append(data)
n = len(data)
if n >= left:
self._rbuf = data[left:]
buffers[-1] = data[:left]
break
buf_len += n
return "".join(buffers)
def readline(self, size=-1):
data = self._rbuf
if size < 0:
# Read until \n or EOF, whichever comes first
if self._rbufsize <= 1:
# Speed up unbuffered case
assert data == ""
buffers = []
recv = self._sock.recv
while data != "\n":
data = recv(1)
if not data:
break
buffers.append(data)
return "".join(buffers)
nl = data.find('\n')
if nl >= 0:
nl += 1
self._rbuf = data[nl:]
return data[:nl]
buffers = []
if data:
buffers.append(data)
self._rbuf = ""
while True:
data = self._sock.recv(self._rbufsize)
if not data:
break
buffers.append(data)
nl = data.find('\n')
if nl >= 0:
nl += 1
self._rbuf = data[nl:]
buffers[-1] = data[:nl]
break
return "".join(buffers)
else:
# Read until size bytes or \n or EOF seen, whichever comes first
nl = data.find('\n', 0, size)
if nl >= 0:
nl += 1
self._rbuf = data[nl:]
return data[:nl]
buf_len = len(data)
if buf_len >= size:
self._rbuf = data[size:]
return data[:size]
buffers = []
if data:
buffers.append(data)
self._rbuf = ""
while True:
data = self._sock.recv(self._rbufsize)
if not data:
break
buffers.append(data)
left = size - buf_len
nl = data.find('\n', 0, left)
if nl >= 0:
nl += 1
self._rbuf = data[nl:]
buffers[-1] = data[:nl]
break
n = len(data)
if n >= left:
self._rbuf = data[left:]
buffers[-1] = data[:left]
break
buf_len += n
return "".join(buffers)
def readlines(self, sizehint=0):
total = 0
list = []
while True:
line = self.readline()
if not line:
break
list.append(line)
total += len(line)
if sizehint and total >= sizehint:
break
return list
# Iterator protocols
def __iter__(self):
return self
def next(self):
line = self.readline()
if not line:
raise StopIteration
return line
tlslite-0.3.8/tlslite/api.py 0000700 0001750 0001750 00000005625 10206517761 015017 0 ustar clint clint """Import this module for easy access to TLS Lite objects.
The TLS Lite API consists of classes, functions, and variables spread
throughout this package. Instead of importing them individually with::
from tlslite.TLSConnection import TLSConnection
from tlslite.HandshakeSettings import HandshakeSettings
from tlslite.errors import *
.
.
It's easier to do::
from tlslite.api import *
This imports all the important objects (TLSConnection, Checker,
HandshakeSettings, etc.) into the global namespace. In particular, it
imports::
from constants import AlertLevel, AlertDescription, Fault
from errors import *
from Checker import Checker
from HandshakeSettings import HandshakeSettings
from Session import Session
from SessionCache import SessionCache
from SharedKeyDB import SharedKeyDB
from TLSConnection import TLSConnection
from VerifierDB import VerifierDB
from X509 import X509
from X509CertChain import X509CertChain
from integration.HTTPTLSConnection import HTTPTLSConnection
from integration.POP3_TLS import POP3_TLS
from integration.IMAP4_TLS import IMAP4_TLS
from integration.SMTP_TLS import SMTP_TLS
from integration.XMLRPCTransport import XMLRPCTransport
from integration.TLSSocketServerMixIn import TLSSocketServerMixIn
from integration.TLSAsyncDispatcherMixIn import TLSAsyncDispatcherMixIn
from integration.TLSTwistedProtocolWrapper import TLSTwistedProtocolWrapper
from utils.cryptomath import cryptlibpyLoaded, m2cryptoLoaded,
gmpyLoaded, pycryptoLoaded, prngName
from utils.keyfactory import generateRSAKey, parsePEMKey, parseXMLKey,
parseAsPublicKey, parsePrivateKey
"""
from constants import AlertLevel, AlertDescription, Fault
from errors import *
from Checker import Checker
from HandshakeSettings import HandshakeSettings
from Session import Session
from SessionCache import SessionCache
from SharedKeyDB import SharedKeyDB
from TLSConnection import TLSConnection
from VerifierDB import VerifierDB
from X509 import X509
from X509CertChain import X509CertChain
from integration.HTTPTLSConnection import HTTPTLSConnection
from integration.TLSSocketServerMixIn import TLSSocketServerMixIn
from integration.TLSAsyncDispatcherMixIn import TLSAsyncDispatcherMixIn
from integration.POP3_TLS import POP3_TLS
from integration.IMAP4_TLS import IMAP4_TLS
from integration.SMTP_TLS import SMTP_TLS
from integration.XMLRPCTransport import XMLRPCTransport
try:
import twisted
del(twisted)
from integration.TLSTwistedProtocolWrapper import TLSTwistedProtocolWrapper
except ImportError:
pass
from utils.cryptomath import cryptlibpyLoaded, m2cryptoLoaded, gmpyLoaded, \
pycryptoLoaded, prngName
from utils.keyfactory import generateRSAKey, parsePEMKey, parseXMLKey, \
parseAsPublicKey, parsePrivateKey
tlslite-0.3.8/tlslite/integration/ 0000700 0001750 0001750 00000000000 10206516252 016176 5 ustar clint clint tlslite-0.3.8/tlslite/integration/POP3_TLS.py 0000700 0001750 0001750 00000012515 10206511711 020015 0 ustar clint clint """TLS Lite + poplib."""
import socket
from poplib import POP3
from tlslite.TLSConnection import TLSConnection
from 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() tlslite-0.3.8/tlslite/integration/XMLRPCTransport.py 0000700 0001750 0001750 00000013247 10204011347 021475 0 ustar clint clint """TLS Lite + xmlrpclib."""
import xmlrpclib
import httplib
from tlslite.integration.HTTPTLSConnection import HTTPTLSConnection
from 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)
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 tlslite-0.3.8/tlslite/integration/TLSSocketServerMixIn.py 0000700 0001750 0001750 00000004224 10026001322 022507 0 ustar clint clint """TLS Lite + SocketServer."""
from 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() tlslite-0.3.8/tlslite/integration/__init__.py 0000700 0001750 0001750 00000000712 10206512760 020312 0 ustar clint clint """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")]
tlslite-0.3.8/tlslite/integration/ClientHelper.py 0000700 0001750 0001750 00000015545 10206512126 021137 0 ustar clint clint """
A helper class for using TLS Lite with stdlib clients
(httplib, xmlrpclib, imaplib, poplib).
"""
from 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 tlslite-0.3.8/tlslite/integration/IntegrationHelper.py 0000700 0001750 0001750 00000003457 10204000134 022170 0 ustar clint clint
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 tlslite-0.3.8/tlslite/integration/SMTP_TLS.py 0000700 0001750 0001750 00000011166 10206511721 020061 0 ustar clint clint """TLS Lite + smtplib."""
from smtplib import SMTP
from tlslite.TLSConnection import TLSConnection
from 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) tlslite-0.3.8/tlslite/integration/IMAP4_TLS.py 0000700 0001750 0001750 00000012014 10206511714 020103 0 ustar clint clint """TLS Lite + imaplib."""
import socket
from imaplib import IMAP4
from tlslite.TLSConnection import TLSConnection
from 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') tlslite-0.3.8/tlslite/integration/TLSTwistedProtocolWrapper.py 0000700 0001750 0001750 00000015553 10041647702 023657 0 ustar clint clint """TLS Lite + Twisted."""
from twisted.protocols.policies import ProtocolWrapper, WrappingFactory
from twisted.python.failure import Failure
from AsyncStateMachine import AsyncStateMachine
from tlslite.TLSConnection import TLSConnection
from 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)) tlslite-0.3.8/tlslite/integration/AsyncStateMachine.py 0000700 0001750 0001750 00000016036 10041606141 022116 0 ustar clint clint """
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
tlslite-0.3.8/tlslite/integration/HTTPTLSConnection.py 0000700 0001750 0001750 00000014777 10204012152 021741 0 ustar clint clint """TLS Lite + httplib."""
import socket
import httplib
from tlslite.TLSConnection import TLSConnection
from 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) tlslite-0.3.8/tlslite/integration/TLSAsyncDispatcherMixIn.py 0000700 0001750 0001750 00000011406 10025502510 023160 0 ustar clint clint """TLS Lite + asyncore."""
import asyncore
from 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) tlslite-0.3.8/tlslite/Session.py 0000700 0001750 0001750 00000011175 10130676052 015661 0 ustar clint clint """Class representing a TLS session."""
from utils.compat import *
from mathtls import *
from constants import *
class Session:
"""
This class represents a TLS session.
TLS distinguishes between connections and sessions. A new
handshake creates both a connection and a session. Data is
transmitted over the connection.
The session contains a more permanent record of the handshake. The
session can be inspected to determine handshake results. The
session can also be used to create a new connection through
"session resumption". If the client and server both support this,
they can create a new connection based on an old session without
the overhead of a full handshake.
The session for a L{tlslite.TLSConnection.TLSConnection} can be
retrieved from the connection's 'session' attribute.
@type srpUsername: str
@ivar srpUsername: The client's SRP username (or None).
@type sharedKeyUsername: str
@ivar sharedKeyUsername: The client's shared-key username (or
None).
@type clientCertChain: L{tlslite.X509CertChain.X509CertChain} or
L{cryptoIDlib.CertChain.CertChain}
@ivar clientCertChain: The client's certificate chain (or None).
@type serverCertChain: L{tlslite.X509CertChain.X509CertChain} or
L{cryptoIDlib.CertChain.CertChain}
@ivar serverCertChain: The server's certificate chain (or None).
"""
def __init__(self):
self.masterSecret = createByteArraySequence([])
self.sessionID = createByteArraySequence([])
self.cipherSuite = 0
self.srpUsername = None
self.sharedKeyUsername = None
self.clientCertChain = None
self.serverCertChain = None
self.resumable = False
self.sharedKey = False
def _clone(self):
other = Session()
other.masterSecret = self.masterSecret
other.sessionID = self.sessionID
other.cipherSuite = self.cipherSuite
other.srpUsername = self.srpUsername
other.sharedKeyUsername = self.sharedKeyUsername
other.clientCertChain = self.clientCertChain
other.serverCertChain = self.serverCertChain
other.resumable = self.resumable
other.sharedKey = self.sharedKey
return other
def _calcMasterSecret(self, version, premasterSecret, clientRandom,
serverRandom):
if version == (3,0):
self.masterSecret = PRF_SSL(premasterSecret,
concatArrays(clientRandom, serverRandom), 48)
elif version in ((3,1), (3,2)):
self.masterSecret = PRF(premasterSecret, "master secret",
concatArrays(clientRandom, serverRandom), 48)
else:
raise AssertionError()
def valid(self):
"""If this session can be used for session resumption.
@rtype: bool
@return: If this session can be used for session resumption.
"""
return self.resumable or self.sharedKey
def _setResumable(self, boolean):
#Only let it be set if this isn't a shared key
if not self.sharedKey:
#Only let it be set to True if the sessionID is non-null
if (not boolean) or (boolean and self.sessionID):
self.resumable = boolean
def getCipherName(self):
"""Get the name of the cipher used with this connection.
@rtype: str
@return: The name of the cipher used with this connection.
Either 'aes128', 'aes256', 'rc4', or '3des'.
"""
if self.cipherSuite in CipherSuite.aes128Suites:
return "aes128"
elif self.cipherSuite in CipherSuite.aes256Suites:
return "aes256"
elif self.cipherSuite in CipherSuite.rc4Suites:
return "rc4"
elif self.cipherSuite in CipherSuite.tripleDESSuites:
return "3des"
else:
return None
def _createSharedKey(self, sharedKeyUsername, sharedKey):
if len(sharedKeyUsername)>16:
raise ValueError()
if len(sharedKey)>47:
raise ValueError()
self.sharedKeyUsername = sharedKeyUsername
self.sessionID = createByteArrayZeros(16)
for x in range(len(sharedKeyUsername)):
self.sessionID[x] = ord(sharedKeyUsername[x])
premasterSecret = createByteArrayZeros(48)
sharedKey = chr(len(sharedKey)) + sharedKey
for x in range(48):
premasterSecret[x] = ord(sharedKey[x % len(sharedKey)])
self.masterSecret = PRF(premasterSecret, "shared secret",
createByteArraySequence([]), 48)
self.sharedKey = True
return self
tlslite-0.3.8/tlslite/HandshakeSettings.py 0000700 0001750 0001750 00000014334 10122477701 017646 0 ustar clint clint """Class for setting handshake parameters."""
from constants import CertificateType
from utils import cryptomath
from utils import cipherfactory
class HandshakeSettings:
"""This class encapsulates various parameters that can be used with
a TLS handshake.
@sort: minKeySize, maxKeySize, cipherNames, certificateTypes,
minVersion, maxVersion
@type minKeySize: int
@ivar minKeySize: The minimum bit length for asymmetric keys.
If the other party tries to use SRP, RSA, or Diffie-Hellman
parameters smaller than this length, an alert will be
signalled. The default is 1023.
@type maxKeySize: int
@ivar maxKeySize: The maximum bit length for asymmetric keys.
If the other party tries to use SRP, RSA, or Diffie-Hellman
parameters larger than this length, an alert will be signalled.
The default is 8193.
@type cipherNames: list
@ivar cipherNames: The allowed ciphers, in order of preference.
The allowed values in this list are 'aes256', 'aes128', '3des', and
'rc4'. If these settings are used with a client handshake, they
determine the order of the ciphersuites offered in the ClientHello
message.
If these settings are used with a server handshake, the server will
choose whichever ciphersuite matches the earliest entry in this
list.
NOTE: If '3des' is used in this list, but TLS Lite can't find an
add-on library that supports 3DES, then '3des' will be silently
removed.
The default value is ['aes256', 'aes128', '3des', 'rc4'].
@type certificateTypes: list
@ivar certificateTypes: The allowed certificate types, in order of
preference.
The allowed values in this list are 'x509' and 'cryptoID'. This
list is only used with a client handshake. The client will
advertise to the server which certificate types are supported, and
will check that the server uses one of the appropriate types.
NOTE: If 'cryptoID' is used in this list, but cryptoIDlib is not
installed, then 'cryptoID' will be silently removed.
@type minVersion: tuple
@ivar minVersion: The minimum allowed SSL/TLS version.
This variable can be set to (3,0) for SSL 3.0, (3,1) for
TLS 1.0, or (3,2) for TLS 1.1. If the other party wishes to
use a lower version, a protocol_version alert will be signalled.
The default is (3,0).
@type maxVersion: tuple
@ivar maxVersion: The maximum allowed SSL/TLS version.
This variable can be set to (3,0) for SSL 3.0, (3,1) for
TLS 1.0, or (3,2) for TLS 1.1. If the other party wishes to
use a higher version, a protocol_version alert will be signalled.
The default is (3,2). (WARNING: Some servers may (improperly)
reject clients which offer support for TLS 1.1. In this case,
try lowering maxVersion to (3,1)).
"""
def __init__(self):
self.minKeySize = 1023
self.maxKeySize = 8193
self.cipherNames = ["aes256", "aes128", "3des", "rc4"]
self.cipherImplementations = ["cryptlib", "openssl", "pycrypto",
"python"]
self.certificateTypes = ["x509", "cryptoID"]
self.minVersion = (3,0)
self.maxVersion = (3,2)
#Filters out options that are not supported
def _filter(self):
other = HandshakeSettings()
other.minKeySize = self.minKeySize
other.maxKeySize = self.maxKeySize
other.cipherNames = self.cipherNames
other.cipherImplementations = self.cipherImplementations
other.certificateTypes = self.certificateTypes
other.minVersion = self.minVersion
other.maxVersion = self.maxVersion
if not cipherfactory.tripleDESPresent:
other.cipherNames = [e for e in self.cipherNames if e != "3des"]
if len(other.cipherNames)==0:
raise ValueError("No supported ciphers")
try:
import cryptoIDlib
except ImportError:
other.certificateTypes = [e for e in self.certificateTypes \
if e != "cryptoID"]
if len(other.certificateTypes)==0:
raise ValueError("No supported certificate types")
if not cryptomath.cryptlibpyLoaded:
other.cipherImplementations = [e for e in \
self.cipherImplementations if e != "cryptlib"]
if not cryptomath.m2cryptoLoaded:
other.cipherImplementations = [e for e in \
other.cipherImplementations if e != "openssl"]
if not cryptomath.pycryptoLoaded:
other.cipherImplementations = [e for e in \
other.cipherImplementations if e != "pycrypto"]
if len(other.cipherImplementations)==0:
raise ValueError("No supported cipher implementations")
if other.minKeySize<512:
raise ValueError("minKeySize too small")
if other.minKeySize>16384:
raise ValueError("minKeySize too large")
if other.maxKeySize<512:
raise ValueError("maxKeySize too small")
if other.maxKeySize>16384:
raise ValueError("maxKeySize too large")
for s in other.cipherNames:
if s not in ("aes256", "aes128", "rc4", "3des"):
raise ValueError("Unknown cipher name: '%s'" % s)
for s in other.cipherImplementations:
if s not in ("cryptlib", "openssl", "python", "pycrypto"):
raise ValueError("Unknown cipher implementation: '%s'" % s)
for s in other.certificateTypes:
if s not in ("x509", "cryptoID"):
raise ValueError("Unknown certificate type: '%s'" % s)
if other.minVersion > other.maxVersion:
raise ValueError("Versions set incorrectly")
if not other.minVersion in ((3,0), (3,1), (3,2)):
raise ValueError("minVersion set incorrectly")
if not other.maxVersion in ((3,0), (3,1), (3,2)):
raise ValueError("maxVersion set incorrectly")
return other
def _getCertificateTypes(self):
l = []
for ct in self.certificateTypes:
if ct == "x509":
l.append(CertificateType.x509)
elif ct == "cryptoID":
l.append(CertificateType.cryptoID)
else:
raise AssertionError()
return l
tlslite-0.3.8/tlslite/messages.py 0000700 0001750 0001750 00000043775 10130676044 016061 0 ustar clint clint """Classes representing TLS messages."""
from utils.compat import *
from utils.cryptomath import *
from errors import *
from utils.codec import *
from constants import *
from X509 import X509
from X509CertChain import X509CertChain
import sha
import md5
class RecordHeader3:
def __init__(self):
self.type = 0
self.version = (0,0)
self.length = 0
self.ssl2 = False
def create(self, version, type, length):
self.type = type
self.version = version
self.length = length
return self
def write(self):
w = Writer(5)
w.add(self.type, 1)
w.add(self.version[0], 1)
w.add(self.version[1], 1)
w.add(self.length, 2)
return w.bytes
def parse(self, p):
self.type = p.get(1)
self.version = (p.get(1), p.get(1))
self.length = p.get(2)
self.ssl2 = False
return self
class RecordHeader2:
def __init__(self):
self.type = 0
self.version = (0,0)
self.length = 0
self.ssl2 = True
def parse(self, p):
if p.get(1)!=128:
raise SyntaxError()
self.type = ContentType.handshake
self.version = (2,0)
#We don't support 2-byte-length-headers; could be a problem
self.length = p.get(1)
return self
class Msg:
def preWrite(self, trial):
if trial:
w = Writer()
else:
length = self.write(True)
w = Writer(length)
return w
def postWrite(self, w, trial):
if trial:
return w.index
else:
return w.bytes
class Alert(Msg):
def __init__(self):
self.contentType = ContentType.alert
self.level = 0
self.description = 0
def create(self, description, level=AlertLevel.fatal):
self.level = level
self.description = description
return self
def parse(self, p):
p.setLengthCheck(2)
self.level = p.get(1)
self.description = p.get(1)
p.stopLengthCheck()
return self
def write(self):
w = Writer(2)
w.add(self.level, 1)
w.add(self.description, 1)
return w.bytes
class HandshakeMsg(Msg):
def preWrite(self, handshakeType, trial):
if trial:
w = Writer()
w.add(handshakeType, 1)
w.add(0, 3)
else:
length = self.write(True)
w = Writer(length)
w.add(handshakeType, 1)
w.add(length-4, 3)
return w
class ClientHello(HandshakeMsg):
def __init__(self, ssl2=False):
self.contentType = ContentType.handshake
self.ssl2 = ssl2
self.client_version = (0,0)
self.random = createByteArrayZeros(32)
self.session_id = createByteArraySequence([])
self.cipher_suites = [] # a list of 16-bit values
self.certificate_types = [CertificateType.x509]
self.compression_methods = [] # a list of 8-bit values
self.srp_username = None # a string
def create(self, version, random, session_id, cipher_suites,
certificate_types=None, srp_username=None):
self.client_version = version
self.random = random
self.session_id = session_id
self.cipher_suites = cipher_suites
self.certificate_types = certificate_types
self.compression_methods = [0]
self.srp_username = srp_username
return self
def parse(self, p):
if self.ssl2:
self.client_version = (p.get(1), p.get(1))
cipherSpecsLength = p.get(2)
sessionIDLength = p.get(2)
randomLength = p.get(2)
self.cipher_suites = p.getFixList(3, int(cipherSpecsLength/3))
self.session_id = p.getFixBytes(sessionIDLength)
self.random = p.getFixBytes(randomLength)
if len(self.random) < 32:
zeroBytes = 32-len(self.random)
self.random = createByteArrayZeros(zeroBytes) + self.random
self.compression_methods = [0]#Fake this value
#We're not doing a stopLengthCheck() for SSLv2, oh well..
else:
p.startLengthCheck(3)
self.client_version = (p.get(1), p.get(1))
self.random = p.getFixBytes(32)
self.session_id = p.getVarBytes(1)
self.cipher_suites = p.getVarList(2, 2)
self.compression_methods = p.getVarList(1, 1)
if not p.atLengthCheck():
totalExtLength = p.get(2)
soFar = 0
while soFar != totalExtLength:
extType = p.get(2)
extLength = p.get(2)
if extType == 6:
self.srp_username = bytesToString(p.getVarBytes(1))
elif extType == 7:
self.certificate_types = p.getVarList(1, 1)
else:
p.getFixBytes(extLength)
soFar += 4 + extLength
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.client_hello, trial)
w.add(self.client_version[0], 1)
w.add(self.client_version[1], 1)
w.addFixSeq(self.random, 1)
w.addVarSeq(self.session_id, 1, 1)
w.addVarSeq(self.cipher_suites, 2, 2)
w.addVarSeq(self.compression_methods, 1, 1)
extLength = 0
if self.certificate_types and self.certificate_types != \
[CertificateType.x509]:
extLength += 5 + len(self.certificate_types)
if self.srp_username:
extLength += 5 + len(self.srp_username)
if extLength > 0:
w.add(extLength, 2)
if self.certificate_types and self.certificate_types != \
[CertificateType.x509]:
w.add(7, 2)
w.add(len(self.certificate_types)+1, 2)
w.addVarSeq(self.certificate_types, 1, 1)
if self.srp_username:
w.add(6, 2)
w.add(len(self.srp_username)+1, 2)
w.addVarSeq(stringToBytes(self.srp_username), 1, 1)
return HandshakeMsg.postWrite(self, w, trial)
class ServerHello(HandshakeMsg):
def __init__(self):
self.contentType = ContentType.handshake
self.server_version = (0,0)
self.random = createByteArrayZeros(32)
self.session_id = createByteArraySequence([])
self.cipher_suite = 0
self.certificate_type = CertificateType.x509
self.compression_method = 0
def create(self, version, random, session_id, cipher_suite,
certificate_type):
self.server_version = version
self.random = random
self.session_id = session_id
self.cipher_suite = cipher_suite
self.certificate_type = certificate_type
self.compression_method = 0
return self
def parse(self, p):
p.startLengthCheck(3)
self.server_version = (p.get(1), p.get(1))
self.random = p.getFixBytes(32)
self.session_id = p.getVarBytes(1)
self.cipher_suite = p.get(2)
self.compression_method = p.get(1)
if not p.atLengthCheck():
totalExtLength = p.get(2)
soFar = 0
while soFar != totalExtLength:
extType = p.get(2)
extLength = p.get(2)
if extType == 7:
self.certificate_type = p.get(1)
else:
p.getFixBytes(extLength)
soFar += 4 + extLength
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.server_hello, trial)
w.add(self.server_version[0], 1)
w.add(self.server_version[1], 1)
w.addFixSeq(self.random, 1)
w.addVarSeq(self.session_id, 1, 1)
w.add(self.cipher_suite, 2)
w.add(self.compression_method, 1)
extLength = 0
if self.certificate_type and self.certificate_type != \
CertificateType.x509:
extLength += 5
if extLength != 0:
w.add(extLength, 2)
if self.certificate_type and self.certificate_type != \
CertificateType.x509:
w.add(7, 2)
w.add(1, 2)
w.add(self.certificate_type, 1)
return HandshakeMsg.postWrite(self, w, trial)
class Certificate(HandshakeMsg):
def __init__(self, certificateType):
self.certificateType = certificateType
self.contentType = ContentType.handshake
self.certChain = None
def create(self, certChain):
self.certChain = certChain
return self
def parse(self, p):
p.startLengthCheck(3)
if self.certificateType == CertificateType.x509:
chainLength = p.get(3)
index = 0
certificate_list = []
while index != chainLength:
certBytes = p.getVarBytes(3)
x509 = X509()
x509.parseBinary(certBytes)
certificate_list.append(x509)
index += len(certBytes)+3
if certificate_list:
self.certChain = X509CertChain(certificate_list)
elif self.certificateType == CertificateType.cryptoID:
s = bytesToString(p.getVarBytes(2))
if s:
try:
import cryptoIDlib.CertChain
except ImportError:
raise SyntaxError(\
"cryptoID cert chain received, cryptoIDlib not present")
self.certChain = cryptoIDlib.CertChain.CertChain().parse(s)
else:
raise AssertionError()
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.certificate, trial)
if self.certificateType == CertificateType.x509:
chainLength = 0
if self.certChain:
certificate_list = self.certChain.x509List
else:
certificate_list = []
#determine length
for cert in certificate_list:
bytes = cert.writeBytes()
chainLength += len(bytes)+3
#add bytes
w.add(chainLength, 3)
for cert in certificate_list:
bytes = cert.writeBytes()
w.addVarSeq(bytes, 1, 3)
elif self.certificateType == CertificateType.cryptoID:
if self.certChain:
bytes = stringToBytes(self.certChain.write())
else:
bytes = createByteArraySequence([])
w.addVarSeq(bytes, 1, 2)
else:
raise AssertionError()
return HandshakeMsg.postWrite(self, w, trial)
class CertificateRequest(HandshakeMsg):
def __init__(self):
self.contentType = ContentType.handshake
self.certificate_types = []
#treat as opaque bytes for now
self.certificate_authorities = createByteArraySequence([])
def create(self, certificate_types, certificate_authorities):
self.certificate_types = certificate_types
self.certificate_authorities = certificate_authorities
return self
def parse(self, p):
p.startLengthCheck(3)
self.certificate_types = p.getVarList(1, 1)
self.certificate_authorities = p.getVarBytes(2)
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.certificate_request,
trial)
w.addVarSeq(self.certificate_types, 1, 1)
w.addVarSeq(self.certificate_authorities, 1, 2)
return HandshakeMsg.postWrite(self, w, trial)
class ServerKeyExchange(HandshakeMsg):
def __init__(self, cipherSuite):
self.cipherSuite = cipherSuite
self.contentType = ContentType.handshake
self.srp_N = 0L
self.srp_g = 0L
self.srp_s = createByteArraySequence([])
self.srp_B = 0L
self.signature = createByteArraySequence([])
def createSRP(self, srp_N, srp_g, srp_s, srp_B):
self.srp_N = srp_N
self.srp_g = srp_g
self.srp_s = srp_s
self.srp_B = srp_B
return self
def parse(self, p):
p.startLengthCheck(3)
self.srp_N = bytesToNumber(p.getVarBytes(2))
self.srp_g = bytesToNumber(p.getVarBytes(2))
self.srp_s = p.getVarBytes(1)
self.srp_B = bytesToNumber(p.getVarBytes(2))
if self.cipherSuite in CipherSuite.srpRsaSuites:
self.signature = p.getVarBytes(2)
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.server_key_exchange,
trial)
w.addVarSeq(numberToBytes(self.srp_N), 1, 2)
w.addVarSeq(numberToBytes(self.srp_g), 1, 2)
w.addVarSeq(self.srp_s, 1, 1)
w.addVarSeq(numberToBytes(self.srp_B), 1, 2)
if self.cipherSuite in CipherSuite.srpRsaSuites:
w.addVarSeq(self.signature, 1, 2)
return HandshakeMsg.postWrite(self, w, trial)
def hash(self, clientRandom, serverRandom):
oldCipherSuite = self.cipherSuite
self.cipherSuite = None
try:
bytes = clientRandom + serverRandom + self.write()[4:]
s = bytesToString(bytes)
return stringToBytes(md5.md5(s).digest() + sha.sha(s).digest())
finally:
self.cipherSuite = oldCipherSuite
class ServerHelloDone(HandshakeMsg):
def __init__(self):
self.contentType = ContentType.handshake
def create(self):
return self
def parse(self, p):
p.startLengthCheck(3)
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.server_hello_done, trial)
return HandshakeMsg.postWrite(self, w, trial)
class ClientKeyExchange(HandshakeMsg):
def __init__(self, cipherSuite, version=None):
self.cipherSuite = cipherSuite
self.version = version
self.contentType = ContentType.handshake
self.srp_A = 0
self.encryptedPreMasterSecret = createByteArraySequence([])
def createSRP(self, srp_A):
self.srp_A = srp_A
return self
def createRSA(self, encryptedPreMasterSecret):
self.encryptedPreMasterSecret = encryptedPreMasterSecret
return self
def parse(self, p):
p.startLengthCheck(3)
if self.cipherSuite in CipherSuite.srpSuites + \
CipherSuite.srpRsaSuites:
self.srp_A = bytesToNumber(p.getVarBytes(2))
elif self.cipherSuite in CipherSuite.rsaSuites:
if self.version in ((3,1), (3,2)):
self.encryptedPreMasterSecret = p.getVarBytes(2)
elif self.version == (3,0):
self.encryptedPreMasterSecret = \
p.getFixBytes(len(p.bytes)-p.index)
else:
raise AssertionError()
else:
raise AssertionError()
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.client_key_exchange,
trial)
if self.cipherSuite in CipherSuite.srpSuites + \
CipherSuite.srpRsaSuites:
w.addVarSeq(numberToBytes(self.srp_A), 1, 2)
elif self.cipherSuite in CipherSuite.rsaSuites:
if self.version in ((3,1), (3,2)):
w.addVarSeq(self.encryptedPreMasterSecret, 1, 2)
elif self.version == (3,0):
w.addFixSeq(self.encryptedPreMasterSecret, 1)
else:
raise AssertionError()
else:
raise AssertionError()
return HandshakeMsg.postWrite(self, w, trial)
class CertificateVerify(HandshakeMsg):
def __init__(self):
self.contentType = ContentType.handshake
self.signature = createByteArraySequence([])
def create(self, signature):
self.signature = signature
return self
def parse(self, p):
p.startLengthCheck(3)
self.signature = p.getVarBytes(2)
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.certificate_verify,
trial)
w.addVarSeq(self.signature, 1, 2)
return HandshakeMsg.postWrite(self, w, trial)
class ChangeCipherSpec(Msg):
def __init__(self):
self.contentType = ContentType.change_cipher_spec
self.type = 1
def create(self):
self.type = 1
return self
def parse(self, p):
p.setLengthCheck(1)
self.type = p.get(1)
p.stopLengthCheck()
return self
def write(self, trial=False):
w = Msg.preWrite(self, trial)
w.add(self.type,1)
return Msg.postWrite(self, w, trial)
class Finished(HandshakeMsg):
def __init__(self, version):
self.contentType = ContentType.handshake
self.version = version
self.verify_data = createByteArraySequence([])
def create(self, verify_data):
self.verify_data = verify_data
return self
def parse(self, p):
p.startLengthCheck(3)
if self.version == (3,0):
self.verify_data = p.getFixBytes(36)
elif self.version in ((3,1), (3,2)):
self.verify_data = p.getFixBytes(12)
else:
raise AssertionError()
p.stopLengthCheck()
return self
def write(self, trial=False):
w = HandshakeMsg.preWrite(self, HandshakeType.finished, trial)
w.addFixSeq(self.verify_data, 1)
return HandshakeMsg.postWrite(self, w, trial)
class ApplicationData(Msg):
def __init__(self):
self.contentType = ContentType.application_data
self.bytes = createByteArraySequence([])
def create(self, bytes):
self.bytes = bytes
return self
def parse(self, p):
self.bytes = p.bytes
return self
def write(self):
return self.bytes tlslite-0.3.8/tlslite/errors.py 0000700 0001750 0001750 00000013243 10025523106 015542 0 ustar clint clint """Exception classes.
@sort: TLSError, TLSAbruptCloseError, TLSAlert, TLSLocalAlert, TLSRemoteAlert,
TLSAuthenticationError, TLSNoAuthenticationError, TLSAuthenticationTypeError,
TLSFingerprintError, TLSAuthorizationError, TLSValidationError, TLSFaultError
"""
from constants import AlertDescription, AlertLevel
class TLSError(Exception):
"""Base class for all TLS Lite exceptions."""
pass
class TLSAbruptCloseError(TLSError):
"""The socket was closed without a proper TLS shutdown.
The TLS specification mandates that an alert of some sort
must be sent before the underlying socket is closed. If the socket
is closed without this, it could signify that an attacker is trying
to truncate the connection. It could also signify a misbehaving
TLS implementation, or a random network failure.
"""
pass
class TLSAlert(TLSError):
"""A TLS alert has been signalled."""
pass
_descriptionStr = {\
AlertDescription.close_notify: "close_notify",\
AlertDescription.unexpected_message: "unexpected_message",\
AlertDescription.bad_record_mac: "bad_record_mac",\
AlertDescription.decryption_failed: "decryption_failed",\
AlertDescription.record_overflow: "record_overflow",\
AlertDescription.decompression_failure: "decompression_failure",\
AlertDescription.handshake_failure: "handshake_failure",\
AlertDescription.no_certificate: "no certificate",\
AlertDescription.bad_certificate: "bad_certificate",\
AlertDescription.unsupported_certificate: "unsupported_certificate",\
AlertDescription.certificate_revoked: "certificate_revoked",\
AlertDescription.certificate_expired: "certificate_expired",\
AlertDescription.certificate_unknown: "certificate_unknown",\
AlertDescription.illegal_parameter: "illegal_parameter",\
AlertDescription.unknown_ca: "unknown_ca",\
AlertDescription.access_denied: "access_denied",\
AlertDescription.decode_error: "decode_error",\
AlertDescription.decrypt_error: "decrypt_error",\
AlertDescription.export_restriction: "export_restriction",\
AlertDescription.protocol_version: "protocol_version",\
AlertDescription.insufficient_security: "insufficient_security",\
AlertDescription.internal_error: "internal_error",\
AlertDescription.user_canceled: "user_canceled",\
AlertDescription.no_renegotiation: "no_renegotiation",\
AlertDescription.unknown_srp_username: "unknown_srp_username",\
AlertDescription.missing_srp_username: "missing_srp_username"}
class TLSLocalAlert(TLSAlert):
"""A TLS alert has been signalled by the local implementation.
@type description: int
@ivar description: Set to one of the constants in
L{tlslite.constants.AlertDescription}
@type level: int
@ivar level: Set to one of the constants in
L{tlslite.constants.AlertLevel}
@type message: str
@ivar message: Description of what went wrong.
"""
def __init__(self, alert, message=None):
self.description = alert.description
self.level = alert.level
self.message = message
def __str__(self):
alertStr = TLSAlert._descriptionStr.get(self.description)
if alertStr == None:
alertStr = str(self.description)
if self.message:
return alertStr + ": " + self.message
else:
return alertStr
class TLSRemoteAlert(TLSAlert):
"""A TLS alert has been signalled by the remote implementation.
@type description: int
@ivar description: Set to one of the constants in
L{tlslite.constants.AlertDescription}
@type level: int
@ivar level: Set to one of the constants in
L{tlslite.constants.AlertLevel}
"""
def __init__(self, alert):
self.description = alert.description
self.level = alert.level
def __str__(self):
alertStr = TLSAlert._descriptionStr.get(self.description)
if alertStr == None:
alertStr = str(self.description)
return alertStr
class TLSAuthenticationError(TLSError):
"""The handshake succeeded, but the other party's authentication
was inadequate.
This exception will only be raised when a
L{tlslite.Checker.Checker} has been passed to a handshake function.
The Checker will be invoked once the handshake completes, and if
the Checker objects to how the other party authenticated, a
subclass of this exception will be raised.
"""
pass
class TLSNoAuthenticationError(TLSAuthenticationError):
"""The Checker was expecting the other party to authenticate with a
certificate chain, but this did not occur."""
pass
class TLSAuthenticationTypeError(TLSAuthenticationError):
"""The Checker was expecting the other party to authenticate with a
different type of certificate chain."""
pass
class TLSFingerprintError(TLSAuthenticationError):
"""The Checker was expecting the other party to authenticate with a
certificate chain that matches a different fingerprint."""
pass
class TLSAuthorizationError(TLSAuthenticationError):
"""The Checker was expecting the other party to authenticate with a
certificate chain that has a different authorization."""
pass
class TLSValidationError(TLSAuthenticationError):
"""The Checker has determined that the other party's certificate
chain is invalid."""
pass
class TLSFaultError(TLSError):
"""The other party responded incorrectly to an induced fault.
This exception will only occur during fault testing, when a
TLSConnection's fault variable is set to induce some sort of
faulty behavior, and the other party doesn't respond appropriately.
"""
pass
tlslite-0.3.8/tlslite/VerifierDB.py 0000700 0001750 0001750 00000006040 10130676116 016213 0 ustar clint clint """Class for storing SRP password verifiers."""
from utils.cryptomath import *
from utils.compat import *
import mathtls
from BaseDB import BaseDB
class VerifierDB(BaseDB):
"""This class represent an in-memory or on-disk database of SRP
password verifiers.
A VerifierDB can be passed to a server handshake to authenticate
a client based on one of the verifiers.
This class is thread-safe.
"""
def __init__(self, filename=None):
"""Create a new VerifierDB instance.
@type filename: str
@param filename: Filename for an on-disk database, or None for
an in-memory database. If the filename already exists, follow
this with a call to open(). To create a new on-disk database,
follow this with a call to create().
"""
BaseDB.__init__(self, filename, "verifier")
def _getItem(self, username, valueStr):
(N, g, salt, verifier) = valueStr.split(" ")
N = base64ToNumber(N)
g = base64ToNumber(g)
salt = base64ToString(salt)
verifier = base64ToNumber(verifier)
return (N, g, salt, verifier)
def __setitem__(self, username, verifierEntry):
"""Add a verifier entry to the database.
@type username: str
@param username: The username to associate the verifier with.
Must be less than 256 characters in length. Must not already
be in the database.
@type verifierEntry: tuple
@param verifierEntry: The verifier entry to add. Use
L{tlslite.VerifierDB.VerifierDB.makeVerifier} to create a
verifier entry.
"""
BaseDB.__setitem__(self, username, verifierEntry)
def _setItem(self, username, value):
if len(username)>=256:
raise ValueError("username too long")
N, g, salt, verifier = value
N = numberToBase64(N)
g = numberToBase64(g)
salt = stringToBase64(salt)
verifier = numberToBase64(verifier)
valueStr = " ".join( (N, g, salt, verifier) )
return valueStr
def _checkItem(self, value, username, param):
(N, g, salt, verifier) = value
x = mathtls.makeX(salt, username, param)
v = powMod(g, x, N)
return (verifier == v)
def makeVerifier(username, password, bits):
"""Create a verifier entry which can be stored in a VerifierDB.
@type username: str
@param username: The username for this verifier. Must be less
than 256 characters in length.
@type password: str
@param password: The password for this verifier.
@type bits: int
@param bits: This values specifies which SRP group parameters
to use. It must be one of (1024, 1536, 2048, 3072, 4096, 6144,
8192). Larger values are more secure but slower. 2048 is a
good compromise between safety and speed.
@rtype: tuple
@return: A tuple which may be stored in a VerifierDB.
"""
return mathtls.makeVerifier(username, password, bits)
makeVerifier = staticmethod(makeVerifier) tlslite-0.3.8/tlslite/BaseDB.py 0000700 0001750 0001750 00000006664 10027143547 015330 0 ustar clint clint """Base class for SharedKeyDB and VerifierDB."""
import anydbm
import thread
class BaseDB:
def __init__(self, filename, type):
self.type = type
self.filename = filename
if self.filename:
self.db = None
else:
self.db = {}
self.lock = thread.allocate_lock()
def create(self):
"""Create a new on-disk database.
@raise anydbm.error: If there's a problem creating the database.
"""
if self.filename:
self.db = anydbm.open(self.filename, "n") #raises anydbm.error
self.db["--Reserved--type"] = self.type
self.db.sync()
else:
self.db = {}
def open(self):
"""Open a pre-existing on-disk database.
@raise anydbm.error: If there's a problem opening the database.
@raise ValueError: If the database is not of the right type.
"""
if not self.filename:
raise ValueError("Can only open on-disk databases")
self.db = anydbm.open(self.filename, "w") #raises anydbm.error
try:
if self.db["--Reserved--type"] != self.type:
raise ValueError("Not a %s database" % self.type)
except KeyError:
raise ValueError("Not a recognized database")
def __getitem__(self, username):
if self.db == None:
raise AssertionError("DB not open")
self.lock.acquire()
try:
valueStr = self.db[username]
finally:
self.lock.release()
return self._getItem(username, valueStr)
def __setitem__(self, username, value):
if self.db == None:
raise AssertionError("DB not open")
valueStr = self._setItem(username, value)
self.lock.acquire()
try:
self.db[username] = valueStr
if self.filename:
self.db.sync()
finally:
self.lock.release()
def __delitem__(self, username):
if self.db == None:
raise AssertionError("DB not open")
self.lock.acquire()
try:
del(self.db[username])
if self.filename:
self.db.sync()
finally:
self.lock.release()
def __contains__(self, username):
"""Check if the database contains the specified username.
@type username: str
@param username: The username to check for.
@rtype: bool
@return: True if the database contains the username, False
otherwise.
"""
if self.db == None:
raise AssertionError("DB not open")
self.lock.acquire()
try:
return self.db.has_key(username)
finally:
self.lock.release()
def check(self, username, param):
value = self.__getitem__(username)
return self._checkItem(value, username, param)
def keys(self):
"""Return a list of usernames in the database.
@rtype: list
@return: The usernames in the database.
"""
if self.db == None:
raise AssertionError("DB not open")
self.lock.acquire()
try:
usernames = self.db.keys()
finally:
self.lock.release()
usernames = [u for u in usernames if not u.startswith("--Reserved--")]
return usernames tlslite-0.3.8/tlslite/TLSRecordLayer.py 0000700 0001750 0001750 00000125764 10206541675 017054 0 ustar clint clint """Helper class for TLSConnection."""
from __future__ import generators
from utils.compat import *
from utils.cryptomath import *
from utils.cipherfactory import createAES, createRC4, createTripleDES
from utils.codec import *
from errors import *
from messages import *
from mathtls import *
from constants import *
from utils.cryptomath import getRandomBytes
from utils import hmac
from FileObject import FileObject
import sha
import md5
import socket
import errno
import traceback
class _ConnectionState:
def __init__(self):
self.macContext = None
self.encContext = None
self.seqnum = 0
def getSeqNumStr(self):
w = Writer(8)
w.add(self.seqnum, 8)
seqnumStr = bytesToString(w.bytes)
self.seqnum += 1
return seqnumStr
class TLSRecordLayer:
"""
This class handles data transmission for a TLS connection.
Its only subclass is L{tlslite.TLSConnection.TLSConnection}. We've
separated the code in this class from TLSConnection to make things
more readable.
@type sock: socket.socket
@ivar sock: The underlying socket object.
@type session: L{tlslite.Session.Session}
@ivar session: The session corresponding to this connection.
Due to TLS session resumption, multiple connections can correspond
to the same underlying session.
@type version: tuple
@ivar version: The TLS version being used for this connection.
(3,0) means SSL 3.0, and (3,1) means TLS 1.0.
@type closed: bool
@ivar closed: If this connection is closed.
@type resumed: bool
@ivar resumed: If this connection is based on a resumed session.
@type allegedSharedKeyUsername: str or None
@ivar allegedSharedKeyUsername: This is set to the shared-key
username asserted by the client, whether the handshake succeeded or
not. If the handshake fails, this can be inspected to
determine if a guessing attack is in progress against a particular
user account.
@type allegedSrpUsername: str or None
@ivar allegedSrpUsername: This is set to the SRP username
asserted by the client, whether the handshake succeeded or not.
If the handshake fails, this can be inspected to determine
if a guessing attack is in progress against a particular user
account.
@type closeSocket: bool
@ivar closeSocket: If the socket should be closed when the
connection is closed (writable).
If you set this to True, TLS Lite will assume the responsibility of
closing the socket when the TLS Connection is shutdown (either
through an error or through the user calling close()). The default
is False.
@type ignoreAbruptClose: bool
@ivar ignoreAbruptClose: If an abrupt close of the socket should
raise an error (writable).
If you set this to True, TLS Lite will not raise a
L{tlslite.errors.TLSAbruptCloseError} exception if the underlying
socket is unexpectedly closed. Such an unexpected closure could be
caused by an attacker. However, it also occurs with some incorrect
TLS implementations.
You should set this to True only if you're not worried about an
attacker truncating the connection, and only if necessary to avoid
spurious errors. The default is False.
@sort: __init__, read, readAsync, write, writeAsync, close, closeAsync,
getCipherImplementation, getCipherName
"""
def __init__(self, sock):
self.sock = sock
#My session object (Session instance; read-only)
self.session = None
#Am I a client or server?
self._client = None
#Buffers for processing messages
self._handshakeBuffer = []
self._readBuffer = ""
#Handshake digests
self._handshake_md5 = md5.md5()
self._handshake_sha = sha.sha()
#TLS Protocol Version
self.version = (0,0) #read-only
self._versionCheck = False #Once we choose a version, this is True
#Current and Pending connection states
self._writeState = _ConnectionState()
self._readState = _ConnectionState()
self._pendingWriteState = _ConnectionState()
self._pendingReadState = _ConnectionState()
#Is the connection open?
self.closed = True #read-only
self._refCount = 0 #Used to trigger closure
#Is this a resumed (or shared-key) session?
self.resumed = False #read-only
#What username did the client claim in his handshake?
self.allegedSharedKeyUsername = None
self.allegedSrpUsername = None
#On a call to close(), do we close the socket? (writeable)
self.closeSocket = False
#If the socket is abruptly closed, do we ignore it
#and pretend the connection was shut down properly? (writeable)
self.ignoreAbruptClose = False
#Fault we will induce, for testing purposes
self.fault = None
#*********************************************************
# Public Functions START
#*********************************************************
def read(self, max=None, min=1):
"""Read some data from the TLS connection.
This function will block until at least 'min' bytes are
available (or the connection is closed).
If an exception is raised, the connection will have been
automatically closed.
@type max: int
@param max: The maximum number of bytes to return.
@type min: int
@param min: The minimum number of bytes to return
@rtype: str
@return: A string of no more than 'max' bytes, and no fewer
than 'min' (unless the connection has been closed, in which
case fewer than 'min' bytes may be returned).
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
"""
for result in self.readAsync(max, min):
pass
return result
def readAsync(self, max=None, min=1):
"""Start a read operation on the TLS connection.
This function returns a generator which behaves similarly to
read(). Successive invocations of the generator will return 0
if it is waiting to read from the socket, 1 if it is waiting
to write to the socket, or a string if the read operation has
completed.
@rtype: iterable
@return: A generator; see above for details.
"""
try:
while len(self._readBuffer)= len(s):
break
if endIndex > len(s):
endIndex = len(s)
block = stringToBytes(s[startIndex : endIndex])
applicationData = ApplicationData().create(block)
for result in self._sendMsg(applicationData, skipEmptyFrag):
yield result
skipEmptyFrag = True #only send an empy fragment on 1st message
index += 1
except:
self._shutdown(False)
raise
def close(self):
"""Close the TLS connection.
This function will block until it has exchanged close_notify
alerts with the other party. After doing so, it will shut down the
TLS connection. Further attempts to read through this connection
will return "". Further attempts to write through this connection
will raise ValueError.
If makefile() has been called on this connection, the connection
will be not be closed until the connection object and all file
objects have been closed.
Even if an exception is raised, the connection will have been
closed.
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
"""
if not self.closed:
for result in self._decrefAsync():
pass
def closeAsync(self):
"""Start a close operation on the TLS connection.
This function returns a generator which behaves similarly to
close(). Successive invocations of the generator will return 0
if it is waiting to read from the socket, 1 if it is waiting
to write to the socket, or will raise StopIteration if the
close operation has completed.
@rtype: iterable
@return: A generator; see above for details.
"""
if not self.closed:
for result in self._decrefAsync():
yield result
def _decrefAsync(self):
self._refCount -= 1
if self._refCount == 0 and not self.closed:
try:
for result in self._sendMsg(Alert().create(\
AlertDescription.close_notify, AlertLevel.warning)):
yield result
alert = None
while not alert:
for result in self._getMsg((ContentType.alert, \
ContentType.application_data)):
if result in (0,1):
yield result
if result.contentType == ContentType.alert:
alert = result
if alert.description == AlertDescription.close_notify:
self._shutdown(True)
else:
raise TLSRemoteAlert(alert)
except (socket.error, TLSAbruptCloseError):
#If the other side closes the socket, that's okay
self._shutdown(True)
except:
self._shutdown(False)
raise
def getCipherName(self):
"""Get the name of the cipher used with this connection.
@rtype: str
@return: The name of the cipher used with this connection.
Either 'aes128', 'aes256', 'rc4', or '3des'.
"""
if not self._writeState.encContext:
return None
return self._writeState.encContext.name
def getCipherImplementation(self):
"""Get the name of the cipher implementation used with
this connection.
@rtype: str
@return: The name of the cipher implementation used with
this connection. Either 'python', 'cryptlib', 'openssl',
or 'pycrypto'.
"""
if not self._writeState.encContext:
return None
return self._writeState.encContext.implementation
#Emulate a socket, somewhat -
def send(self, s):
"""Send data to the TLS connection (socket emulation).
@raise socket.error: If a socket error occurs.
"""
self.write(s)
return len(s)
def sendall(self, s):
"""Send data to the TLS connection (socket emulation).
@raise socket.error: If a socket error occurs.
"""
self.write(s)
def recv(self, bufsize):
"""Get some data from the TLS connection (socket emulation).
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
"""
return self.read(bufsize)
def makefile(self, mode='r', bufsize=-1):
"""Create a file object for the TLS connection (socket emulation).
@rtype: L{tlslite.FileObject.FileObject}
"""
self._refCount += 1
return FileObject(self, mode, bufsize)
def getsockname(self):
"""Return the socket's own address (socket emulation)."""
return self.sock.getsockname()
def getpeername(self):
"""Return the remote address to which the socket is connected
(socket emulation)."""
return self.sock.getpeername()
def settimeout(self, value):
"""Set a timeout on blocking socket operations (socket emulation)."""
return self.sock.settimeout(value)
def gettimeout(self):
"""Return the timeout associated with socket operations (socket
emulation)."""
return self.sock.gettimeout()
def setsockopt(self, level, optname, value):
"""Set the value of the given socket option (socket emulation)."""
return self.sock.setsockopt(level, optname, value)
#*********************************************************
# Public Functions END
#*********************************************************
def _shutdown(self, resumable):
self._writeState = _ConnectionState()
self._readState = _ConnectionState()
#Don't do this: self._readBuffer = ""
self.version = (0,0)
self._versionCheck = False
self.closed = True
if self.closeSocket:
self.sock.close()
#Even if resumable is False, we'll never toggle this on
if not resumable and self.session:
self.session.resumable = False
def _sendError(self, alertDescription, errorStr=None):
alert = Alert().create(alertDescription, AlertLevel.fatal)
for result in self._sendMsg(alert):
yield result
self._shutdown(False)
raise TLSLocalAlert(alert, errorStr)
def _sendMsgs(self, msgs):
skipEmptyFrag = False
for msg in msgs:
for result in self._sendMsg(msg, skipEmptyFrag):
yield result
skipEmptyFrag = True
def _sendMsg(self, msg, skipEmptyFrag=False):
bytes = msg.write()
contentType = msg.contentType
#Whenever we're connected and asked to send a message,
#we first send an empty Application Data message. This prevents
#an attacker from launching a chosen-plaintext attack based on
#knowing the next IV.
if not self.closed and not skipEmptyFrag and self.version == (3,1):
if self._writeState.encContext:
if self._writeState.encContext.isBlockCipher:
for result in self._sendMsg(ApplicationData(),
skipEmptyFrag=True):
yield result
#Update handshake hashes
if contentType == ContentType.handshake:
bytesStr = bytesToString(bytes)
self._handshake_md5.update(bytesStr)
self._handshake_sha.update(bytesStr)
#Calculate MAC
if self._writeState.macContext:
seqnumStr = self._writeState.getSeqNumStr()
bytesStr = bytesToString(bytes)
mac = self._writeState.macContext.copy()
mac.update(seqnumStr)
mac.update(chr(contentType))
if self.version == (3,0):
mac.update( chr( int(len(bytes)/256) ) )
mac.update( chr( int(len(bytes)%256) ) )
elif self.version in ((3,1), (3,2)):
mac.update(chr(self.version[0]))
mac.update(chr(self.version[1]))
mac.update( chr( int(len(bytes)/256) ) )
mac.update( chr( int(len(bytes)%256) ) )
else:
raise AssertionError()
mac.update(bytesStr)
macString = mac.digest()
macBytes = stringToBytes(macString)
if self.fault == Fault.badMAC:
macBytes[0] = (macBytes[0]+1) % 256
#Encrypt for Block or Stream Cipher
if self._writeState.encContext:
#Add padding and encrypt (for Block Cipher):
if self._writeState.encContext.isBlockCipher:
#Add TLS 1.1 fixed block
if self.version == (3,2):
bytes = self.fixedIVBlock + bytes
#Add padding: bytes = bytes + (macBytes + paddingBytes)
currentLength = len(bytes) + len(macBytes) + 1
blockLength = self._writeState.encContext.block_size
paddingLength = blockLength-(currentLength % blockLength)
paddingBytes = createByteArraySequence([paddingLength] * \
(paddingLength+1))
if self.fault == Fault.badPadding:
paddingBytes[0] = (paddingBytes[0]+1) % 256
endBytes = concatArrays(macBytes, paddingBytes)
bytes = concatArrays(bytes, endBytes)
#Encrypt
plaintext = stringToBytes(bytes)
ciphertext = self._writeState.encContext.encrypt(plaintext)
bytes = stringToBytes(ciphertext)
#Encrypt (for Stream Cipher)
else:
bytes = concatArrays(bytes, macBytes)
plaintext = bytesToString(bytes)
ciphertext = self._writeState.encContext.encrypt(plaintext)
bytes = stringToBytes(ciphertext)
#Add record header and send
r = RecordHeader3().create(self.version, contentType, len(bytes))
s = bytesToString(concatArrays(r.write(), bytes))
while 1:
try:
bytesSent = self.sock.send(s) #Might raise socket.error
except socket.error, why:
if why[0] == errno.EWOULDBLOCK:
yield 1
continue
else:
raise
if bytesSent == len(s):
return
s = s[bytesSent:]
yield 1
def _getMsg(self, expectedType, secondaryType=None, constructorType=None):
try:
if not isinstance(expectedType, tuple):
expectedType = (expectedType,)
#Spin in a loop, until we've got a non-empty record of a type we
#expect. The loop will be repeated if:
# - we receive a renegotiation attempt; we send no_renegotiation,
# then try again
# - we receive an empty application-data fragment; we try again
while 1:
for result in self._getNextRecord():
if result in (0,1):
yield result
recordHeader, p = result
#If this is an empty application-data fragment, try again
if recordHeader.type == ContentType.application_data:
if p.index == len(p.bytes):
continue
#If we received an unexpected record type...
if recordHeader.type not in expectedType:
#If we received an alert...
if recordHeader.type == ContentType.alert:
alert = Alert().parse(p)
#We either received a fatal error, a warning, or a
#close_notify. In any case, we're going to close the
#connection. In the latter two cases we respond with
#a close_notify, but ignore any socket errors, since
#the other side might have already closed the socket.
if alert.level == AlertLevel.warning or \
alert.description == AlertDescription.close_notify:
#If the sendMsg() call fails because the socket has
#already been closed, we will be forgiving and not
#report the error nor invalidate the "resumability"
#of the session.
try:
alertMsg = Alert()
alertMsg.create(AlertDescription.close_notify,
AlertLevel.warning)
for result in self._sendMsg(alertMsg):
yield result
except socket.error:
pass
if alert.description == \
AlertDescription.close_notify:
self._shutdown(True)
elif alert.level == AlertLevel.warning:
self._shutdown(False)
else: #Fatal alert:
self._shutdown(False)
#Raise the alert as an exception
raise TLSRemoteAlert(alert)
#If we received a renegotiation attempt...
if recordHeader.type == ContentType.handshake:
subType = p.get(1)
reneg = False
if self._client:
if subType == HandshakeType.hello_request:
reneg = True
else:
if subType == HandshakeType.client_hello:
reneg = True
#Send no_renegotiation, then try again
if reneg:
alertMsg = Alert()
alertMsg.create(AlertDescription.no_renegotiation,
AlertLevel.warning)
for result in self._sendMsg(alertMsg):
yield result
continue
#Otherwise: this is an unexpected record, but neither an
#alert nor renegotiation
for result in self._sendError(\
AlertDescription.unexpected_message,
"received type=%d" % recordHeader.type):
yield result
break
#Parse based on content_type
if recordHeader.type == ContentType.change_cipher_spec:
yield ChangeCipherSpec().parse(p)
elif recordHeader.type == ContentType.alert:
yield Alert().parse(p)
elif recordHeader.type == ContentType.application_data:
yield ApplicationData().parse(p)
elif recordHeader.type == ContentType.handshake:
#Convert secondaryType to tuple, if it isn't already
if not isinstance(secondaryType, tuple):
secondaryType = (secondaryType,)
#If it's a handshake message, check handshake header
if recordHeader.ssl2:
subType = p.get(1)
if subType != HandshakeType.client_hello:
for result in self._sendError(\
AlertDescription.unexpected_message,
"Can only handle SSLv2 ClientHello messages"):
yield result
if HandshakeType.client_hello not in secondaryType:
for result in self._sendError(\
AlertDescription.unexpected_message):
yield result
subType = HandshakeType.client_hello
else:
subType = p.get(1)
if subType not in secondaryType:
for result in self._sendError(\
AlertDescription.unexpected_message,
"Expecting %s, got %s" % (str(secondaryType), subType)):
yield result
#Update handshake hashes
sToHash = bytesToString(p.bytes)
self._handshake_md5.update(sToHash)
self._handshake_sha.update(sToHash)
#Parse based on handshake type
if subType == HandshakeType.client_hello:
yield ClientHello(recordHeader.ssl2).parse(p)
elif subType == HandshakeType.server_hello:
yield ServerHello().parse(p)
elif subType == HandshakeType.certificate:
yield Certificate(constructorType).parse(p)
elif subType == HandshakeType.certificate_request:
yield CertificateRequest().parse(p)
elif subType == HandshakeType.certificate_verify:
yield CertificateVerify().parse(p)
elif subType == HandshakeType.server_key_exchange:
yield ServerKeyExchange(constructorType).parse(p)
elif subType == HandshakeType.server_hello_done:
yield ServerHelloDone().parse(p)
elif subType == HandshakeType.client_key_exchange:
yield ClientKeyExchange(constructorType, \
self.version).parse(p)
elif subType == HandshakeType.finished:
yield Finished(self.version).parse(p)
else:
raise AssertionError()
#If an exception was raised by a Parser or Message instance:
except SyntaxError, e:
for result in self._sendError(AlertDescription.decode_error,
formatExceptionTrace(e)):
yield result
#Returns next record or next handshake message
def _getNextRecord(self):
#If there's a handshake message waiting, return it
if self._handshakeBuffer:
recordHeader, bytes = self._handshakeBuffer[0]
self._handshakeBuffer = self._handshakeBuffer[1:]
yield (recordHeader, Parser(bytes))
return
#Otherwise...
#Read the next record header
bytes = createByteArraySequence([])
recordHeaderLength = 1
ssl2 = False
while 1:
try:
s = self.sock.recv(recordHeaderLength-len(bytes))
except socket.error, why:
if why[0] == errno.EWOULDBLOCK:
yield 0
continue
else:
raise
#If the connection was abruptly closed, raise an error
if len(s)==0:
raise TLSAbruptCloseError()
bytes += stringToBytes(s)
if len(bytes)==1:
if bytes[0] in ContentType.all:
ssl2 = False
recordHeaderLength = 5
elif bytes[0] == 128:
ssl2 = True
recordHeaderLength = 2
else:
raise SyntaxError()
if len(bytes) == recordHeaderLength:
break
#Parse the record header
if ssl2:
r = RecordHeader2().parse(Parser(bytes))
else:
r = RecordHeader3().parse(Parser(bytes))
#Check the record header fields
if r.length > 18432:
for result in self._sendError(AlertDescription.record_overflow):
yield result
#Read the record contents
bytes = createByteArraySequence([])
while 1:
try:
s = self.sock.recv(r.length - len(bytes))
except socket.error, why:
if why[0] == errno.EWOULDBLOCK:
yield 0
continue
else:
raise
#If the connection is closed, raise a socket error
if len(s)==0:
raise TLSAbruptCloseError()
bytes += stringToBytes(s)
if len(bytes) == r.length:
break
#Check the record header fields (2)
#We do this after reading the contents from the socket, so that
#if there's an error, we at least don't leave extra bytes in the
#socket..
#
# THIS CHECK HAS NO SECURITY RELEVANCE (?), BUT COULD HURT INTEROP.
# SO WE LEAVE IT OUT FOR NOW.
#
#if self._versionCheck and r.version != self.version:
# for result in self._sendError(AlertDescription.protocol_version,
# "Version in header field: %s, should be %s" % (str(r.version),
# str(self.version))):
# yield result
#Decrypt the record
for result in self._decryptRecord(r.type, bytes):
if result in (0,1):
yield result
else:
break
bytes = result
p = Parser(bytes)
#If it doesn't contain handshake messages, we can just return it
if r.type != ContentType.handshake:
yield (r, p)
#If it's an SSLv2 ClientHello, we can return it as well
elif r.ssl2:
yield (r, p)
else:
#Otherwise, we loop through and add the handshake messages to the
#handshake buffer
while 1:
if p.index == len(bytes): #If we're at the end
if not self._handshakeBuffer:
for result in self._sendError(\
AlertDescription.decode_error, \
"Received empty handshake record"):
yield result
break
#There needs to be at least 4 bytes to get a header
if p.index+4 > len(bytes):
for result in self._sendError(\
AlertDescription.decode_error,
"A record has a partial handshake message (1)"):
yield result
p.get(1) # skip handshake type
msgLength = p.get(3)
if p.index+msgLength > len(bytes):
for result in self._sendError(\
AlertDescription.decode_error,
"A record has a partial handshake message (2)"):
yield result
handshakePair = (r, bytes[p.index-4 : p.index+msgLength])
self._handshakeBuffer.append(handshakePair)
p.index += msgLength
#We've moved at least one handshake message into the
#handshakeBuffer, return the first one
recordHeader, bytes = self._handshakeBuffer[0]
self._handshakeBuffer = self._handshakeBuffer[1:]
yield (recordHeader, Parser(bytes))
def _decryptRecord(self, recordType, bytes):
if self._readState.encContext:
#Decrypt if it's a block cipher
if self._readState.encContext.isBlockCipher:
blockLength = self._readState.encContext.block_size
if len(bytes) % blockLength != 0:
for result in self._sendError(\
AlertDescription.decryption_failed,
"Encrypted data not a multiple of blocksize"):
yield result
ciphertext = bytesToString(bytes)
plaintext = self._readState.encContext.decrypt(ciphertext)
if self.version == (3,2): #For TLS 1.1, remove explicit IV
plaintext = plaintext[self._readState.encContext.block_size : ]
bytes = stringToBytes(plaintext)
#Check padding
paddingGood = True
paddingLength = bytes[-1]
if (paddingLength+1) > len(bytes):
paddingGood=False
totalPaddingLength = 0
else:
if self.version == (3,0):
totalPaddingLength = paddingLength+1
elif self.version in ((3,1), (3,2)):
totalPaddingLength = paddingLength+1
paddingBytes = bytes[-totalPaddingLength:-1]
for byte in paddingBytes:
if byte != paddingLength:
paddingGood = False
totalPaddingLength = 0
else:
raise AssertionError()
#Decrypt if it's a stream cipher
else:
paddingGood = True
ciphertext = bytesToString(bytes)
plaintext = self._readState.encContext.decrypt(ciphertext)
bytes = stringToBytes(plaintext)
totalPaddingLength = 0
#Check MAC
macGood = True
macLength = self._readState.macContext.digest_size
endLength = macLength + totalPaddingLength
if endLength > len(bytes):
macGood = False
else:
#Read MAC
startIndex = len(bytes) - endLength
endIndex = startIndex + macLength
checkBytes = bytes[startIndex : endIndex]
#Calculate MAC
seqnumStr = self._readState.getSeqNumStr()
bytes = bytes[:-endLength]
bytesStr = bytesToString(bytes)
mac = self._readState.macContext.copy()
mac.update(seqnumStr)
mac.update(chr(recordType))
if self.version == (3,0):
mac.update( chr( int(len(bytes)/256) ) )
mac.update( chr( int(len(bytes)%256) ) )
elif self.version in ((3,1), (3,2)):
mac.update(chr(self.version[0]))
mac.update(chr(self.version[1]))
mac.update( chr( int(len(bytes)/256) ) )
mac.update( chr( int(len(bytes)%256) ) )
else:
raise AssertionError()
mac.update(bytesStr)
macString = mac.digest()
macBytes = stringToBytes(macString)
#Compare MACs
if macBytes != checkBytes:
macGood = False
if not (paddingGood and macGood):
for result in self._sendError(AlertDescription.bad_record_mac,
"MAC failure (or padding failure)"):
yield result
yield bytes
def _handshakeStart(self, client):
self._client = client
self._handshake_md5 = md5.md5()
self._handshake_sha = sha.sha()
self._handshakeBuffer = []
self.allegedSharedKeyUsername = None
self.allegedSrpUsername = None
self._refCount = 1
def _handshakeDone(self, resumed):
self.resumed = resumed
self.closed = False
def _calcPendingStates(self, clientRandom, serverRandom, implementations):
if self.session.cipherSuite in CipherSuite.aes128Suites:
macLength = 20
keyLength = 16
ivLength = 16
createCipherFunc = createAES
elif self.session.cipherSuite in CipherSuite.aes256Suites:
macLength = 20
keyLength = 32
ivLength = 16
createCipherFunc = createAES
elif self.session.cipherSuite in CipherSuite.rc4Suites:
macLength = 20
keyLength = 16
ivLength = 0
createCipherFunc = createRC4
elif self.session.cipherSuite in CipherSuite.tripleDESSuites:
macLength = 20
keyLength = 24
ivLength = 8
createCipherFunc = createTripleDES
else:
raise AssertionError()
if self.version == (3,0):
createMACFunc = MAC_SSL
elif self.version in ((3,1), (3,2)):
createMACFunc = hmac.HMAC
outputLength = (macLength*2) + (keyLength*2) + (ivLength*2)
#Calculate Keying Material from Master Secret
if self.version == (3,0):
keyBlock = PRF_SSL(self.session.masterSecret,
concatArrays(serverRandom, clientRandom),
outputLength)
elif self.version in ((3,1), (3,2)):
keyBlock = PRF(self.session.masterSecret,
"key expansion",
concatArrays(serverRandom,clientRandom),
outputLength)
else:
raise AssertionError()
#Slice up Keying Material
clientPendingState = _ConnectionState()
serverPendingState = _ConnectionState()
p = Parser(keyBlock)
clientMACBlock = bytesToString(p.getFixBytes(macLength))
serverMACBlock = bytesToString(p.getFixBytes(macLength))
clientKeyBlock = bytesToString(p.getFixBytes(keyLength))
serverKeyBlock = bytesToString(p.getFixBytes(keyLength))
clientIVBlock = bytesToString(p.getFixBytes(ivLength))
serverIVBlock = bytesToString(p.getFixBytes(ivLength))
clientPendingState.macContext = createMACFunc(clientMACBlock,
digestmod=sha)
serverPendingState.macContext = createMACFunc(serverMACBlock,
digestmod=sha)
clientPendingState.encContext = createCipherFunc(clientKeyBlock,
clientIVBlock,
implementations)
serverPendingState.encContext = createCipherFunc(serverKeyBlock,
serverIVBlock,
implementations)
#Assign new connection states to pending states
if self._client:
self._pendingWriteState = clientPendingState
self._pendingReadState = serverPendingState
else:
self._pendingWriteState = serverPendingState
self._pendingReadState = clientPendingState
if self.version == (3,2) and ivLength:
#Choose fixedIVBlock for TLS 1.1 (this is encrypted with the CBC
#residue to create the IV for each sent block)
self.fixedIVBlock = getRandomBytes(ivLength)
def _changeWriteState(self):
self._writeState = self._pendingWriteState
self._pendingWriteState = _ConnectionState()
def _changeReadState(self):
self._readState = self._pendingReadState
self._pendingReadState = _ConnectionState()
def _sendFinished(self):
#Send ChangeCipherSpec
for result in self._sendMsg(ChangeCipherSpec()):
yield result
#Switch to pending write state
self._changeWriteState()
#Calculate verification data
verifyData = self._calcFinished(True)
if self.fault == Fault.badFinished:
verifyData[0] = (verifyData[0]+1)%256
#Send Finished message under new state
finished = Finished(self.version).create(verifyData)
for result in self._sendMsg(finished):
yield result
def _getFinished(self):
#Get and check ChangeCipherSpec
for result in self._getMsg(ContentType.change_cipher_spec):
if result in (0,1):
yield result
changeCipherSpec = result
if changeCipherSpec.type != 1:
for result in self._sendError(AlertDescription.illegal_parameter,
"ChangeCipherSpec type incorrect"):
yield result
#Switch to pending read state
self._changeReadState()
#Calculate verification data
verifyData = self._calcFinished(False)
#Get and check Finished message under new state
for result in self._getMsg(ContentType.handshake,
HandshakeType.finished):
if result in (0,1):
yield result
finished = result
if finished.verify_data != verifyData:
for result in self._sendError(AlertDescription.decrypt_error,
"Finished message is incorrect"):
yield result
def _calcFinished(self, send=True):
if self.version == (3,0):
if (self._client and send) or (not self._client and not send):
senderStr = "\x43\x4C\x4E\x54"
else:
senderStr = "\x53\x52\x56\x52"
verifyData = self._calcSSLHandshakeHash(self.session.masterSecret,
senderStr)
return verifyData
elif self.version in ((3,1), (3,2)):
if (self._client and send) or (not self._client and not send):
label = "client finished"
else:
label = "server finished"
handshakeHashes = stringToBytes(self._handshake_md5.digest() + \
self._handshake_sha.digest())
verifyData = PRF(self.session.masterSecret, label, handshakeHashes,
12)
return verifyData
else:
raise AssertionError()
#Used for Finished messages and CertificateVerify messages in SSL v3
def _calcSSLHandshakeHash(self, masterSecret, label):
masterSecretStr = bytesToString(masterSecret)
imac_md5 = self._handshake_md5.copy()
imac_sha = self._handshake_sha.copy()
imac_md5.update(label + masterSecretStr + '\x36'*48)
imac_sha.update(label + masterSecretStr + '\x36'*40)
md5Str = md5.md5(masterSecretStr + ('\x5c'*48) + \
imac_md5.digest()).digest()
shaStr = sha.sha(masterSecretStr + ('\x5c'*40) + \
imac_sha.digest()).digest()
return stringToBytes(md5Str + shaStr)
tlslite-0.3.8/tlslite/utils/ 0000700 0001750 0001750 00000000000 10206544771 015022 5 ustar clint clint tlslite-0.3.8/tlslite/utils/OpenSSL_AES.py 0000700 0001750 0001750 00000003436 10025510520 017340 0 ustar clint clint """OpenSSL/M2Crypto AES implementation."""
from cryptomath import *
from AES import *
if m2cryptoLoaded:
def new(key, mode, IV):
return OpenSSL_AES(key, mode, IV)
class OpenSSL_AES(AES):
def __init__(self, key, mode, IV):
AES.__init__(self, key, mode, IV, "openssl")
self.key = key
self.IV = IV
def _createContext(self, encrypt):
context = m2.cipher_ctx_new()
if len(self.key)==16:
cipherType = m2.aes_128_cbc()
if len(self.key)==24:
cipherType = m2.aes_192_cbc()
if len(self.key)==32:
cipherType = m2.aes_256_cbc()
m2.cipher_init(context, cipherType, self.key, self.IV, encrypt)
return context
def encrypt(self, plaintext):
AES.encrypt(self, plaintext)
context = self._createContext(1)
ciphertext = m2.cipher_update(context, plaintext)
m2.cipher_ctx_free(context)
self.IV = ciphertext[-self.block_size:]
return ciphertext
def decrypt(self, ciphertext):
AES.decrypt(self, ciphertext)
context = self._createContext(0)
#I think M2Crypto has a bug - it fails to decrypt and return the last block passed in.
#To work around this, we append sixteen zeros to the string, below:
plaintext = m2.cipher_update(context, ciphertext+('\0'*16))
#If this bug is ever fixed, then plaintext will end up having a garbage
#plaintext block on the end. That's okay - the below code will discard it.
plaintext = plaintext[:len(ciphertext)]
m2.cipher_ctx_free(context)
self.IV = ciphertext[-self.block_size:]
return plaintext
tlslite-0.3.8/tlslite/utils/keyfactory.py 0000700 0001750 0001750 00000021127 10130676203 017552 0 ustar clint clint """Factory functions for asymmetric cryptography.
@sort: generateRSAKey, parseXMLKey, parsePEMKey, parseAsPublicKey,
parseAsPrivateKey
"""
from compat import *
from RSAKey import RSAKey
from Python_RSAKey import Python_RSAKey
import cryptomath
if cryptomath.m2cryptoLoaded:
from OpenSSL_RSAKey import OpenSSL_RSAKey
if cryptomath.pycryptoLoaded:
from PyCrypto_RSAKey import PyCrypto_RSAKey
# **************************************************************************
# Factory Functions for RSA Keys
# **************************************************************************
def generateRSAKey(bits, implementations=["openssl", "python"]):
"""Generate an RSA key with the specified bit length.
@type bits: int
@param bits: Desired bit length of the new key's modulus.
@rtype: L{tlslite.utils.RSAKey.RSAKey}
@return: A new RSA private key.
"""
for implementation in implementations:
if implementation == "openssl" and cryptomath.m2cryptoLoaded:
return OpenSSL_RSAKey.generate(bits)
elif implementation == "python":
return Python_RSAKey.generate(bits)
raise ValueError("No acceptable implementations")
def parseXMLKey(s, private=False, public=False, implementations=["python"]):
"""Parse an XML-format key.
The XML format used here is specific to tlslite and cryptoIDlib. The
format can store the public component of a key, or the public and
private components. For example::
4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
Aw==4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou...
Aw==JZ0TIgUxWXmL8KJ0VqyG1V0J3ern9pqIoB0xmy...
@type s: str
@param s: A string containing an XML public or private key.
@type private: bool
@param private: If True, a L{SyntaxError} will be raised if the private
key component is not present.
@type public: bool
@param public: If True, the private key component (if present) will be
discarded, so this function will always return a public key.
@rtype: L{tlslite.utils.RSAKey.RSAKey}
@return: An RSA key.
@raise SyntaxError: If the key is not properly formatted.
"""
for implementation in implementations:
if implementation == "python":
key = Python_RSAKey.parseXML(s)
break
else:
raise ValueError("No acceptable implementations")
return _parseKeyHelper(key, private, public)
#Parse as an OpenSSL or Python key
def parsePEMKey(s, private=False, public=False, passwordCallback=None,
implementations=["openssl", "python"]):
"""Parse a PEM-format key.
The PEM format is used by OpenSSL and other tools. The
format is typically used to store both the public and private
components of a key. For example::
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+
dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH
dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB
AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc
esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO
gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl
aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV
VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV
CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv
i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP
wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG
6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH
h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe
-----END RSA PRIVATE KEY-----
To generate a key like this with OpenSSL, run::
openssl genrsa 2048 > key.pem
This format also supports password-encrypted private keys. TLS
Lite can only handle password-encrypted private keys when OpenSSL
and M2Crypto are installed. In this case, passwordCallback will be
invoked to query the user for the password.
@type s: str
@param s: A string containing a PEM-encoded public or private key.
@type private: bool
@param private: If True, a L{SyntaxError} will be raised if the
private key component is not present.
@type public: bool
@param public: If True, the private key component (if present) will
be discarded, so this function will always return a public key.
@type passwordCallback: callable
@param passwordCallback: This function will be called, with no
arguments, if the PEM-encoded private key is password-encrypted.
The callback should return the password string. If the password is
incorrect, SyntaxError will be raised. If no callback is passed
and the key is password-encrypted, a prompt will be displayed at
the console.
@rtype: L{tlslite.utils.RSAKey.RSAKey}
@return: An RSA key.
@raise SyntaxError: If the key is not properly formatted.
"""
for implementation in implementations:
if implementation == "openssl" and cryptomath.m2cryptoLoaded:
key = OpenSSL_RSAKey.parse(s, passwordCallback)
break
elif implementation == "python":
key = Python_RSAKey.parsePEM(s)
break
else:
raise ValueError("No acceptable implementations")
return _parseKeyHelper(key, private, public)
def _parseKeyHelper(key, private, public):
if private:
if not key.hasPrivateKey():
raise SyntaxError("Not a private key!")
if public:
return _createPublicKey(key)
if private:
if hasattr(key, "d"):
return _createPrivateKey(key)
else:
return key
return key
def parseAsPublicKey(s):
"""Parse an XML or PEM-formatted public key.
@type s: str
@param s: A string containing an XML or PEM-encoded public or private key.
@rtype: L{tlslite.utils.RSAKey.RSAKey}
@return: An RSA public key.
@raise SyntaxError: If the key is not properly formatted.
"""
try:
return parsePEMKey(s, public=True)
except:
return parseXMLKey(s, public=True)
def parsePrivateKey(s):
"""Parse an XML or PEM-formatted private key.
@type s: str
@param s: A string containing an XML or PEM-encoded private key.
@rtype: L{tlslite.utils.RSAKey.RSAKey}
@return: An RSA private key.
@raise SyntaxError: If the key is not properly formatted.
"""
try:
return parsePEMKey(s, private=True)
except:
return parseXMLKey(s, private=True)
def _createPublicKey(key):
"""
Create a new public key. Discard any private component,
and return the most efficient key possible.
"""
if not isinstance(key, RSAKey):
raise AssertionError()
return _createPublicRSAKey(key.n, key.e)
def _createPrivateKey(key):
"""
Create a new private key. Return the most efficient key possible.
"""
if not isinstance(key, RSAKey):
raise AssertionError()
if not key.hasPrivateKey():
raise AssertionError()
return _createPrivateRSAKey(key.n, key.e, key.d, key.p, key.q, key.dP,
key.dQ, key.qInv)
def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto",
"python"]):
for implementation in implementations:
if implementation == "openssl" and cryptomath.m2cryptoLoaded:
return OpenSSL_RSAKey(n, e)
elif implementation == "pycrypto" and cryptomath.pycryptoLoaded:
return PyCrypto_RSAKey(n, e)
elif implementation == "python":
return Python_RSAKey(n, e)
raise ValueError("No acceptable implementations")
def _createPrivateRSAKey(n, e, d, p, q, dP, dQ, qInv,
implementations = ["pycrypto", "python"]):
for implementation in implementations:
if implementation == "pycrypto" and cryptomath.pycryptoLoaded:
return PyCrypto_RSAKey(n, e, d, p, q, dP, dQ, qInv)
elif implementation == "python":
return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
raise ValueError("No acceptable implementations")
tlslite-0.3.8/tlslite/utils/compat.py 0000700 0001750 0001750 00000007734 10130701741 016661 0 ustar clint clint """Miscellaneous functions to mask Python version differences."""
import sys
import os
if sys.version_info < (2,2):
raise AssertionError("Python 2.2 or later required")
if sys.version_info < (2,3):
def enumerate(collection):
return zip(range(len(collection)), collection)
class Set:
def __init__(self, seq=None):
self.values = {}
if seq:
for e in seq:
self.values[e] = None
def add(self, e):
self.values[e] = None
def discard(self, e):
if e in self.values.keys():
del(self.values[e])
def union(self, s):
ret = Set()
for e in self.values.keys():
ret.values[e] = None
for e in s.values.keys():
ret.values[e] = None
return ret
def issubset(self, other):
for e in self.values.keys():
if e not in other.values.keys():
return False
return True
def __nonzero__( self):
return len(self.values.keys())
def __contains__(self, e):
return e in self.values.keys()
def __iter__(self):
return iter(set.values.keys())
if os.name != "java":
import array
def createByteArraySequence(seq):
return array.array('B', seq)
def createByteArrayZeros(howMany):
return array.array('B', [0] * howMany)
def concatArrays(a1, a2):
return a1+a2
def bytesToString(bytes):
return bytes.tostring()
def stringToBytes(s):
bytes = createByteArrayZeros(0)
bytes.fromstring(s)
return bytes
import math
def numBits(n):
if n==0:
return 0
s = "%x" % n
return ((len(s)-1)*4) + \
{'0':0, '1':1, '2':2, '3':2,
'4':3, '5':3, '6':3, '7':3,
'8':4, '9':4, 'a':4, 'b':4,
'c':4, 'd':4, 'e':4, 'f':4,
}[s[0]]
return int(math.floor(math.log(n, 2))+1)
BaseException = Exception
import sys
import traceback
def formatExceptionTrace(e):
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
return newStr
else:
#Jython 2.1 is missing lots of python 2.3 stuff,
#which we have to emulate here:
#NOTE: JYTHON SUPPORT NO LONGER WORKS, DUE TO USE OF GENERATORS.
#THIS CODE IS LEFT IN SO THAT ONE JYTHON UPDATES TO 2.2, IT HAS A
#CHANCE OF WORKING AGAIN.
import java
import jarray
def createByteArraySequence(seq):
if isinstance(seq, type("")): #If it's a string, convert
seq = [ord(c) for c in seq]
return jarray.array(seq, 'h') #use short instead of bytes, cause bytes are signed
def createByteArrayZeros(howMany):
return jarray.zeros(howMany, 'h') #use short instead of bytes, cause bytes are signed
def concatArrays(a1, a2):
l = list(a1)+list(a2)
return createByteArraySequence(l)
#WAY TOO SLOW - MUST BE REPLACED------------
def bytesToString(bytes):
return "".join([chr(b) for b in bytes])
def stringToBytes(s):
bytes = createByteArrayZeros(len(s))
for count, c in enumerate(s):
bytes[count] = ord(c)
return bytes
#WAY TOO SLOW - MUST BE REPLACED------------
def numBits(n):
if n==0:
return 0
n= 1L * n; #convert to long, if it isn't already
return n.__tojava__(java.math.BigInteger).bitLength()
#Adjust the string to an array of bytes
def stringToJavaByteArray(s):
bytes = jarray.zeros(len(s), 'b')
for count, c in enumerate(s):
x = ord(c)
if x >= 128: x -= 256
bytes[count] = x
return bytes
BaseException = java.lang.Exception
import sys
import traceback
def formatExceptionTrace(e):
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
return newStr tlslite-0.3.8/tlslite/utils/PyCrypto_RC4.py 0000700 0001750 0001750 00000001021 10025510264 017617 0 ustar clint clint """PyCrypto RC4 implementation."""
from cryptomath import *
from RC4 import *
if pycryptoLoaded:
import Crypto.Cipher.ARC4
def new(key):
return PyCrypto_RC4(key)
class PyCrypto_RC4(RC4):
def __init__(self, key):
RC4.__init__(self, key, "pycrypto")
self.context = Crypto.Cipher.ARC4.new(key)
def encrypt(self, plaintext):
return self.context.encrypt(plaintext)
def decrypt(self, ciphertext):
return self.context.decrypt(ciphertext) tlslite-0.3.8/tlslite/utils/win32prng.c 0000700 0001750 0001750 00000002256 10130673244 017021 0 ustar clint clint
#include "Python.h"
#define _WIN32_WINNT 0x0400 /* Needed for CryptoAPI on some systems */
#include
static PyObject* getRandomBytes(PyObject *self, PyObject *args)
{
int howMany;
HCRYPTPROV hCryptProv;
unsigned char* bytes = NULL;
PyObject* returnVal = NULL;
/* Read Arguments */
if (!PyArg_ParseTuple(args, "i", &howMany))
return(NULL);
/* Get Context */
if(CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT) == 0)
return Py_BuildValue("s#", NULL, 0);
/* Allocate bytes */
bytes = malloc(howMany);
/* Get random data */
if(CryptGenRandom(
hCryptProv,
howMany,
bytes) == 0)
returnVal = Py_BuildValue("s#", NULL, 0);
else
returnVal = Py_BuildValue("s#", bytes, howMany);
free(bytes);
CryptReleaseContext(hCryptProv, 0);
return returnVal;
}
/* List of functions exported by this module */
static struct PyMethodDef win32prng_functions[] = {
{"getRandomBytes", (PyCFunction)getRandomBytes, METH_VARARGS},
{NULL, NULL} /* Sentinel */
};
/* Initialize this module. */
DL_EXPORT(void) initwin32prng(void)
{
Py_InitModule("win32prng", win32prng_functions);
}
tlslite-0.3.8/tlslite/utils/RSAKey.py 0000700 0001750 0001750 00000020577 10027164144 016501 0 ustar clint clint """Abstract class for RSA."""
from cryptomath import *
class RSAKey:
"""This is an abstract base class for RSA keys.
Particular implementations of RSA keys, such as
L{OpenSSL_RSAKey.OpenSSL_RSAKey},
L{Python_RSAKey.Python_RSAKey}, and
L{PyCrypto_RSAKey.PyCrypto_RSAKey},
inherit from this.
To create or parse an RSA key, don't use one of these classes
directly. Instead, use the factory functions in
L{tlslite.utils.keyfactory}.
"""
def __init__(self, n=0, e=0):
"""Create a new RSA key.
If n and e are passed in, the new key will be initialized.
@type n: int
@param n: RSA modulus.
@type e: int
@param e: RSA public exponent.
"""
raise NotImplementedError()
def __len__(self):
"""Return the length of this key in bits.
@rtype: int
"""
return numBits(self.n)
def hasPrivateKey(self):
"""Return whether or not this key has a private component.
@rtype: bool
"""
raise NotImplementedError()
def hash(self):
"""Return the cryptoID value corresponding to this
key.
@rtype: str
"""
raise NotImplementedError()
def getSigningAlgorithm(self):
"""Return the cryptoID sigAlgo value corresponding to this key.
@rtype: str
"""
return "pkcs1-sha1"
def hashAndSign(self, bytes):
"""Hash and sign the passed-in bytes.
This requires the key to have a private component. It performs
a PKCS1-SHA1 signature on the passed-in data.
@type bytes: str or L{array.array} of unsigned bytes
@param bytes: The value which will be hashed and signed.
@rtype: L{array.array} of unsigned bytes.
@return: A PKCS1-SHA1 signature on the passed-in data.
"""
if not isinstance(bytes, type("")):
bytes = bytesToString(bytes)
hashBytes = stringToBytes(sha.sha(bytes).digest())
prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes)
sigBytes = self.sign(prefixedHashBytes)
return sigBytes
def hashAndVerify(self, sigBytes, bytes):
"""Hash and verify the passed-in bytes with the signature.
This verifies a PKCS1-SHA1 signature on the passed-in data.
@type sigBytes: L{array.array} of unsigned bytes
@param sigBytes: A PKCS1-SHA1 signature.
@type bytes: str or L{array.array} of unsigned bytes
@param bytes: The value which will be hashed and verified.
@rtype: bool
@return: Whether the signature matches the passed-in data.
"""
if not isinstance(bytes, type("")):
bytes = bytesToString(bytes)
hashBytes = stringToBytes(sha.sha(bytes).digest())
prefixedHashBytes = self._addPKCS1SHA1Prefix(hashBytes)
return self.verify(sigBytes, prefixedHashBytes)
def sign(self, bytes):
"""Sign the passed-in bytes.
This requires the key to have a private component. It performs
a PKCS1 signature on the passed-in data.
@type bytes: L{array.array} of unsigned bytes
@param bytes: The value which will be signed.
@rtype: L{array.array} of unsigned bytes.
@return: A PKCS1 signature on the passed-in data.
"""
if not self.hasPrivateKey():
raise AssertionError()
paddedBytes = self._addPKCS1Padding(bytes, 1)
m = bytesToNumber(paddedBytes)
if m >= self.n:
raise ValueError()
c = self._rawPrivateKeyOp(m)
sigBytes = numberToBytes(c)
return sigBytes
def verify(self, sigBytes, bytes):
"""Verify the passed-in bytes with the signature.
This verifies a PKCS1 signature on the passed-in data.
@type sigBytes: L{array.array} of unsigned bytes
@param sigBytes: A PKCS1 signature.
@type bytes: L{array.array} of unsigned bytes
@param bytes: The value which will be verified.
@rtype: bool
@return: Whether the signature matches the passed-in data.
"""
paddedBytes = self._addPKCS1Padding(bytes, 1)
c = bytesToNumber(sigBytes)
if c >= self.n:
return False
m = self._rawPublicKeyOp(c)
checkBytes = numberToBytes(m)
return checkBytes == paddedBytes
def encrypt(self, bytes):
"""Encrypt the passed-in bytes.
This performs PKCS1 encryption of the passed-in data.
@type bytes: L{array.array} of unsigned bytes
@param bytes: The value which will be encrypted.
@rtype: L{array.array} of unsigned bytes.
@return: A PKCS1 encryption of the passed-in data.
"""
paddedBytes = self._addPKCS1Padding(bytes, 2)
m = bytesToNumber(paddedBytes)
if m >= self.n:
raise ValueError()
c = self._rawPublicKeyOp(m)
encBytes = numberToBytes(c)
return encBytes
def decrypt(self, encBytes):
"""Decrypt the passed-in bytes.
This requires the key to have a private component. It performs
PKCS1 decryption of the passed-in data.
@type encBytes: L{array.array} of unsigned bytes
@param encBytes: The value which will be decrypted.
@rtype: L{array.array} of unsigned bytes or None.
@return: A PKCS1 decryption of the passed-in data or None if
the data is not properly formatted.
"""
if not self.hasPrivateKey():
raise AssertionError()
c = bytesToNumber(encBytes)
if c >= self.n:
return None
m = self._rawPrivateKeyOp(c)
decBytes = numberToBytes(m)
if (len(decBytes) != numBytes(self.n)-1): #Check first byte
return None
if decBytes[0] != 2: #Check second byte
return None
for x in range(len(decBytes)-1): #Scan through for zero separator
if decBytes[x]== 0:
break
else:
return None
return decBytes[x+1:] #Return everything after the separator
def _rawPrivateKeyOp(self, m):
raise NotImplementedError()
def _rawPublicKeyOp(self, c):
raise NotImplementedError()
def acceptsPassword(self):
"""Return True if the write() method accepts a password for use
in encrypting the private key.
@rtype: bool
"""
raise NotImplementedError()
def write(self, password=None):
"""Return a string containing the key.
@rtype: str
@return: A string describing the key, in whichever format (PEM
or XML) is native to the implementation.
"""
raise NotImplementedError()
def writeXMLPublicKey(self, indent=''):
"""Return a string containing the key.
@rtype: str
@return: A string describing the public key, in XML format.
"""
return Python_RSAKey(self.n, self.e).write(indent)
def generate(bits):
"""Generate a new key with the specified bit length.
@rtype: L{tlslite.utils.RSAKey.RSAKey}
"""
raise NotImplementedError()
generate = staticmethod(generate)
# **************************************************************************
# Helper Functions for RSA Keys
# **************************************************************************
def _addPKCS1SHA1Prefix(self, bytes):
prefixBytes = createByteArraySequence(\
[48,33,48,9,6,5,43,14,3,2,26,5,0,4,20])
prefixedBytes = prefixBytes + bytes
return prefixedBytes
def _addPKCS1Padding(self, bytes, blockType):
padLength = (numBytes(self.n) - (len(bytes)+3))
if blockType == 1: #Signature padding
pad = [0xFF] * padLength
elif blockType == 2: #Encryption padding
pad = createByteArraySequence([])
while len(pad) < padLength:
padBytes = getRandomBytes(padLength * 2)
pad = [b for b in padBytes if b != 0]
pad = pad[:padLength]
else:
raise AssertionError()
#NOTE: To be proper, we should add [0,blockType]. However,
#the zero is lost when the returned padding is converted
#to a number, so we don't even bother with it. Also,
#adding it would cause a misalignment in verify()
padding = createByteArraySequence([blockType] + pad + [0])
paddedBytes = padding + bytes
return paddedBytes
tlslite-0.3.8/tlslite/utils/hmac.py 0000700 0001750 0001750 00000006326 10025511254 016303 0 ustar clint clint """HMAC (Keyed-Hashing for Message Authentication) Python module.
Implements the HMAC algorithm as described by RFC 2104.
(This file is modified from the standard library version to do faster
copying)
"""
def _strxor(s1, s2):
"""Utility method. XOR the two strings s1 and s2 (must have same length).
"""
return "".join(map(lambda x, y: chr(ord(x) ^ ord(y)), s1, s2))
# The size of the digests returned by HMAC depends on the underlying
# hashing module used.
digest_size = None
class HMAC:
"""RFC2104 HMAC class.
This supports the API for Cryptographic Hash Functions (PEP 247).
"""
def __init__(self, key, msg = None, digestmod = None):
"""Create a new HMAC object.
key: key for the keyed hash object.
msg: Initial input for the hash, if provided.
digestmod: A module supporting PEP 247. Defaults to the md5 module.
"""
if digestmod is None:
import md5
digestmod = md5
if key == None: #TREVNEW - for faster copying
return #TREVNEW
self.digestmod = digestmod
self.outer = digestmod.new()
self.inner = digestmod.new()
self.digest_size = digestmod.digest_size
blocksize = 64
ipad = "\x36" * blocksize
opad = "\x5C" * blocksize
if len(key) > blocksize:
key = digestmod.new(key).digest()
key = key + chr(0) * (blocksize - len(key))
self.outer.update(_strxor(key, opad))
self.inner.update(_strxor(key, ipad))
if msg is not None:
self.update(msg)
## def clear(self):
## raise NotImplementedError, "clear() method not available in HMAC."
def update(self, msg):
"""Update this hashing object with the string msg.
"""
self.inner.update(msg)
def copy(self):
"""Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
"""
other = HMAC(None) #TREVNEW - for faster copying
other.digest_size = self.digest_size #TREVNEW
other.digestmod = self.digestmod
other.inner = self.inner.copy()
other.outer = self.outer.copy()
return other
def digest(self):
"""Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is
not altered in any way by this function; you can continue
updating the object after calling this function.
"""
h = self.outer.copy()
h.update(self.inner.digest())
return h.digest()
def hexdigest(self):
"""Like digest(), but returns a string of hexadecimal digits instead.
"""
return "".join([hex(ord(x))[2:].zfill(2)
for x in tuple(self.digest())])
def new(key, msg = None, digestmod = None):
"""Create a new hashing object and return it.
key: The starting key for the hash.
msg: if available, will immediately be hashed into the object's starting
state.
You can now feed arbitrary strings into the object using its update()
method, and can ask for the hash value at any time by calling its digest()
method.
"""
return HMAC(key, msg, digestmod)
tlslite-0.3.8/tlslite/utils/dateFuncs.py 0000700 0001750 0001750 00000004205 10016012501 017270 0 ustar clint clint
import os
#Functions for manipulating datetime objects
#CCYY-MM-DDThh:mm:ssZ
def parseDateClass(s):
year, month, day = s.split("-")
day, tail = day[:2], day[2:]
hour, minute, second = tail[1:].split(":")
second = second[:2]
year, month, day = int(year), int(month), int(day)
hour, minute, second = int(hour), int(minute), int(second)
return createDateClass(year, month, day, hour, minute, second)
if os.name != "java":
from datetime import datetime, timedelta
#Helper functions for working with a date/time class
def createDateClass(year, month, day, hour, minute, second):
return datetime(year, month, day, hour, minute, second)
def printDateClass(d):
#Split off fractional seconds, append 'Z'
return d.isoformat().split(".")[0]+"Z"
def getNow():
return datetime.utcnow()
def getHoursFromNow(hours):
return datetime.utcnow() + timedelta(hours=hours)
def getMinutesFromNow(minutes):
return datetime.utcnow() + timedelta(minutes=minutes)
def isDateClassExpired(d):
return d < datetime.utcnow()
def isDateClassBefore(d1, d2):
return d1 < d2
else:
#Jython 2.1 is missing lots of python 2.3 stuff,
#which we have to emulate here:
import java
import jarray
def createDateClass(year, month, day, hour, minute, second):
c = java.util.Calendar.getInstance()
c.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
c.set(year, month-1, day, hour, minute, second)
return c
def printDateClass(d):
return "%04d-%02d-%02dT%02d:%02d:%02dZ" % \
(d.get(d.YEAR), d.get(d.MONTH)+1, d.get(d.DATE), \
d.get(d.HOUR_OF_DAY), d.get(d.MINUTE), d.get(d.SECOND))
def getNow():
c = java.util.Calendar.getInstance()
c.setTimeZone(java.util.TimeZone.getTimeZone("UTC"))
c.get(c.HOUR) #force refresh?
return c
def getHoursFromNow(hours):
d = getNow()
d.add(d.HOUR, hours)
return d
def isDateClassExpired(d):
n = getNow()
return d.before(n)
def isDateClassBefore(d1, d2):
return d1.before(d2)
tlslite-0.3.8/tlslite/utils/__init__.py 0000700 0001750 0001750 00000001434 10130676125 017133 0 ustar clint clint """Toolkit for crypto and other stuff."""
__all__ = ["AES",
"ASN1Parser",
"cipherfactory",
"codec",
"Cryptlib_AES",
"Cryptlib_RC4",
"Cryptlib_TripleDES",
"cryptomath: cryptomath module",
"dateFuncs",
"hmac",
"JCE_RSAKey",
"compat",
"keyfactory",
"OpenSSL_AES",
"OpenSSL_RC4",
"OpenSSL_RSAKey",
"OpenSSL_TripleDES",
"PyCrypto_AES",
"PyCrypto_RC4",
"PyCrypto_RSAKey",
"PyCrypto_TripleDES",
"Python_AES",
"Python_RC4",
"Python_RSAKey",
"RC4",
"rijndael",
"RSAKey",
"TripleDES",
"xmltools"]
tlslite-0.3.8/tlslite/utils/Cryptlib_AES.py 0000700 0001750 0001750 00000002524 10025507713 017654 0 ustar clint clint """Cryptlib AES implementation."""
from cryptomath import *
from AES import *
if cryptlibpyLoaded:
def new(key, mode, IV):
return Cryptlib_AES(key, mode, IV)
class Cryptlib_AES(AES):
def __init__(self, key, mode, IV):
AES.__init__(self, key, mode, IV, "cryptlib")
self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_AES)
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_MODE, cryptlib_py.CRYPT_MODE_CBC)
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key))
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key)
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_IV, IV)
def __del__(self):
cryptlib_py.cryptDestroyContext(self.context)
def encrypt(self, plaintext):
AES.encrypt(self, plaintext)
bytes = stringToBytes(plaintext)
cryptlib_py.cryptEncrypt(self.context, bytes)
return bytesToString(bytes)
def decrypt(self, ciphertext):
AES.decrypt(self, ciphertext)
bytes = stringToBytes(ciphertext)
cryptlib_py.cryptDecrypt(self.context, bytes)
return bytesToString(bytes)
tlslite-0.3.8/tlslite/utils/PyCrypto_AES.py 0000700 0001750 0001750 00000001101 10025510254 017635 0 ustar clint clint """PyCrypto AES implementation."""
from cryptomath import *
from AES import *
if pycryptoLoaded:
import Crypto.Cipher.AES
def new(key, mode, IV):
return PyCrypto_AES(key, mode, IV)
class PyCrypto_AES(AES):
def __init__(self, key, mode, IV):
AES.__init__(self, key, mode, IV, "pycrypto")
self.context = Crypto.Cipher.AES.new(key, mode, IV)
def encrypt(self, plaintext):
return self.context.encrypt(plaintext)
def decrypt(self, ciphertext):
return self.context.decrypt(ciphertext) tlslite-0.3.8/tlslite/utils/cryptomath.py 0000700 0001750 0001750 00000026447 10130676175 017606 0 ustar clint clint """cryptomath module
This module has basic math/crypto code."""
import os
import math
import base64
import binascii
import sha
from compat import *
# **************************************************************************
# Load Optional Modules
# **************************************************************************
# Try to load M2Crypto/OpenSSL
try:
from M2Crypto import m2
m2cryptoLoaded = True
except ImportError:
m2cryptoLoaded = False
# Try to load cryptlib
try:
import cryptlib_py
try:
cryptlib_py.cryptInit()
except cryptlib_py.CryptException, e:
#If tlslite and cryptoIDlib are both present,
#they might each try to re-initialize this,
#so we're tolerant of that.
if e[0] != cryptlib_py.CRYPT_ERROR_INITED:
raise
cryptlibpyLoaded = True
except ImportError:
cryptlibpyLoaded = False
#Try to load GMPY
try:
import gmpy
gmpyLoaded = True
except ImportError:
gmpyLoaded = False
#Try to load pycrypto
try:
import Crypto.Cipher.AES
pycryptoLoaded = True
except ImportError:
pycryptoLoaded = False
# **************************************************************************
# PRNG Functions
# **************************************************************************
# Get os.urandom PRNG
try:
os.urandom(1)
def getRandomBytes(howMany):
return stringToBytes(os.urandom(howMany))
prngName = "os.urandom"
except:
# Else get cryptlib PRNG
if cryptlibpyLoaded:
def getRandomBytes(howMany):
randomKey = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED,
cryptlib_py.CRYPT_ALGO_AES)
cryptlib_py.cryptSetAttribute(randomKey,
cryptlib_py.CRYPT_CTXINFO_MODE,
cryptlib_py.CRYPT_MODE_OFB)
cryptlib_py.cryptGenerateKey(randomKey)
bytes = createByteArrayZeros(howMany)
cryptlib_py.cryptEncrypt(randomKey, bytes)
return bytes
prngName = "cryptlib"
else:
#Else get UNIX /dev/urandom PRNG
try:
devRandomFile = open("/dev/urandom", "rb")
def getRandomBytes(howMany):
return stringToBytes(devRandomFile.read(howMany))
prngName = "/dev/urandom"
except IOError:
#Else get Win32 CryptoAPI PRNG
try:
import win32prng
def getRandomBytes(howMany):
s = win32prng.getRandomBytes(howMany)
if len(s) != howMany:
raise AssertionError()
return stringToBytes(s)
prngName ="CryptoAPI"
except ImportError:
#Else no PRNG :-(
def getRandomBytes(howMany):
raise NotImplementedError("No Random Number Generator "\
"available.")
prngName = "None"
# **************************************************************************
# Converter Functions
# **************************************************************************
def bytesToNumber(bytes):
total = 0L
multiplier = 1L
for count in range(len(bytes)-1, -1, -1):
byte = bytes[count]
total += multiplier * byte
multiplier *= 256
return total
def numberToBytes(n):
howManyBytes = numBytes(n)
bytes = createByteArrayZeros(howManyBytes)
for count in range(howManyBytes-1, -1, -1):
bytes[count] = int(n % 256)
n >>= 8
return bytes
def bytesToBase64(bytes):
s = bytesToString(bytes)
return stringToBase64(s)
def base64ToBytes(s):
s = base64ToString(s)
return stringToBytes(s)
def numberToBase64(n):
bytes = numberToBytes(n)
return bytesToBase64(bytes)
def base64ToNumber(s):
bytes = base64ToBytes(s)
return bytesToNumber(bytes)
def stringToNumber(s):
bytes = stringToBytes(s)
return bytesToNumber(bytes)
def numberToString(s):
bytes = numberToBytes(s)
return bytesToString(bytes)
def base64ToString(s):
try:
return base64.decodestring(s)
except binascii.Error, e:
raise SyntaxError(e)
except binascii.Incomplete, e:
raise SyntaxError(e)
def stringToBase64(s):
return base64.encodestring(s).replace("\n", "")
def mpiToNumber(mpi): #mpi is an openssl-format bignum string
if (ord(mpi[4]) & 0x80) !=0: #Make sure this is a positive number
raise AssertionError()
bytes = stringToBytes(mpi[4:])
return bytesToNumber(bytes)
def numberToMPI(n):
bytes = numberToBytes(n)
ext = 0
#If the high-order bit is going to be set,
#add an extra byte of zeros
if (numBits(n) & 0x7)==0:
ext = 1
length = numBytes(n) + ext
bytes = concatArrays(createByteArrayZeros(4+ext), bytes)
bytes[0] = (length >> 24) & 0xFF
bytes[1] = (length >> 16) & 0xFF
bytes[2] = (length >> 8) & 0xFF
bytes[3] = length & 0xFF
return bytesToString(bytes)
# **************************************************************************
# Misc. Utility Functions
# **************************************************************************
def numBytes(n):
if n==0:
return 0
bits = numBits(n)
return int(math.ceil(bits / 8.0))
def hashAndBase64(s):
return stringToBase64(sha.sha(s).digest())
def getBase64Nonce(numChars=22): #defaults to an 132 bit nonce
bytes = getRandomBytes(numChars)
bytesStr = "".join([chr(b) for b in bytes])
return stringToBase64(bytesStr)[:numChars]
# **************************************************************************
# Big Number Math
# **************************************************************************
def getRandomNumber(low, high):
if low >= high:
raise AssertionError()
howManyBits = numBits(high)
howManyBytes = numBytes(high)
lastBits = howManyBits % 8
while 1:
bytes = getRandomBytes(howManyBytes)
if lastBits:
bytes[0] = bytes[0] % (1 << lastBits)
n = bytesToNumber(bytes)
if n >= low and n < high:
return n
def gcd(a,b):
a, b = max(a,b), min(a,b)
while b:
a, b = b, a % b
return a
def lcm(a, b):
#This will break when python division changes, but we can't use // cause
#of Jython
return (a * b) / gcd(a, b)
#Returns inverse of a mod b, zero if none
#Uses Extended Euclidean Algorithm
def invMod(a, b):
c, d = a, b
uc, ud = 1, 0
while c != 0:
#This will break when python division changes, but we can't use //
#cause of Jython
q = d / c
c, d = d-(q*c), c
uc, ud = ud - (q * uc), uc
if d == 1:
return ud % b
return 0
if gmpyLoaded:
def powMod(base, power, modulus):
base = gmpy.mpz(base)
power = gmpy.mpz(power)
modulus = gmpy.mpz(modulus)
result = pow(base, power, modulus)
return long(result)
else:
#Copied from Bryan G. Olson's post to comp.lang.python
#Does left-to-right instead of pow()'s right-to-left,
#thus about 30% faster than the python built-in with small bases
def powMod(base, power, modulus):
nBitScan = 5
""" Return base**power mod modulus, using multi bit scanning
with nBitScan bits at a time."""
#TREV - Added support for negative exponents
negativeResult = False
if (power < 0):
power *= -1
negativeResult = True
exp2 = 2**nBitScan
mask = exp2 - 1
# Break power into a list of digits of nBitScan bits.
# The list is recursive so easy to read in reverse direction.
nibbles = None
while power:
nibbles = int(power & mask), nibbles
power = power >> nBitScan
# Make a table of powers of base up to 2**nBitScan - 1
lowPowers = [1]
for i in xrange(1, exp2):
lowPowers.append((lowPowers[i-1] * base) % modulus)
# To exponentiate by the first nibble, look it up in the table
nib, nibbles = nibbles
prod = lowPowers[nib]
# For the rest, square nBitScan times, then multiply by
# base^nibble
while nibbles:
nib, nibbles = nibbles
for i in xrange(nBitScan):
prod = (prod * prod) % modulus
if nib: prod = (prod * lowPowers[nib]) % modulus
#TREV - Added support for negative exponents
if negativeResult:
prodInv = invMod(prod, modulus)
#Check to make sure the inverse is correct
if (prod * prodInv) % modulus != 1:
raise AssertionError()
return prodInv
return prod
#Pre-calculate a sieve of the ~100 primes < 1000:
def makeSieve(n):
sieve = range(n)
for count in range(2, int(math.sqrt(n))):
if sieve[count] == 0:
continue
x = sieve[count] * 2
while x < len(sieve):
sieve[x] = 0
x += sieve[count]
sieve = [x for x in sieve[2:] if x]
return sieve
sieve = makeSieve(1000)
def isPrime(n, iterations=5, display=False):
#Trial division with sieve
for x in sieve:
if x >= n: return True
if n % x == 0: return False
#Passed trial division, proceed to Rabin-Miller
#Rabin-Miller implemented per Ferguson & Schneier
#Compute s, t for Rabin-Miller
if display: print "*",
s, t = n-1, 0
while s % 2 == 0:
s, t = s/2, t+1
#Repeat Rabin-Miller x times
a = 2 #Use 2 as a base for first iteration speedup, per HAC
for count in range(iterations):
v = powMod(a, s, n)
if v==1:
continue
i = 0
while v != n-1:
if i == t-1:
return False
else:
v, i = powMod(v, 2, n), i+1
a = getRandomNumber(2, n)
return True
def getRandomPrime(bits, display=False):
if bits < 10:
raise AssertionError()
#The 1.5 ensures the 2 MSBs are set
#Thus, when used for p,q in RSA, n will have its MSB set
#
#Since 30 is lcm(2,3,5), we'll set our test numbers to
#29 % 30 and keep them there
low = (2L ** (bits-1)) * 3/2
high = 2L ** bits - 30
p = getRandomNumber(low, high)
p += 29 - (p % 30)
while 1:
if display: print ".",
p += 30
if p >= high:
p = getRandomNumber(low, high)
p += 29 - (p % 30)
if isPrime(p, display=display):
return p
#Unused at the moment...
def getRandomSafePrime(bits, display=False):
if bits < 10:
raise AssertionError()
#The 1.5 ensures the 2 MSBs are set
#Thus, when used for p,q in RSA, n will have its MSB set
#
#Since 30 is lcm(2,3,5), we'll set our test numbers to
#29 % 30 and keep them there
low = (2 ** (bits-2)) * 3/2
high = (2 ** (bits-1)) - 30
q = getRandomNumber(low, high)
q += 29 - (q % 30)
while 1:
if display: print ".",
q += 30
if (q >= high):
q = getRandomNumber(low, high)
q += 29 - (q % 30)
#Ideas from Tom Wu's SRP code
#Do trial division on p and q before Rabin-Miller
if isPrime(q, 0, display=display):
p = (2 * q) + 1
if isPrime(p, display=display):
if isPrime(q, display=display):
return p
tlslite-0.3.8/tlslite/utils/PyCrypto_RSAKey.py 0000700 0001750 0001750 00000003426 10026002742 020336 0 ustar clint clint """PyCrypto RSA implementation."""
from cryptomath import *
from RSAKey import *
from Python_RSAKey import Python_RSAKey
if pycryptoLoaded:
from Crypto.PublicKey import RSA
class PyCrypto_RSAKey(RSAKey):
def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0):
if not d:
self.rsa = RSA.construct( (n, e) )
else:
self.rsa = RSA.construct( (n, e, d, p, q) )
def __getattr__(self, name):
return getattr(self.rsa, name)
def hasPrivateKey(self):
return self.rsa.has_private()
def hash(self):
return Python_RSAKey(self.n, self.e).hash()
def _rawPrivateKeyOp(self, m):
s = numberToString(m)
byteLength = numBytes(self.n)
if len(s)== byteLength:
pass
elif len(s) == byteLength-1:
s = '\0' + s
else:
raise AssertionError()
c = stringToNumber(self.rsa.decrypt((s,)))
return c
def _rawPublicKeyOp(self, c):
s = numberToString(c)
byteLength = numBytes(self.n)
if len(s)== byteLength:
pass
elif len(s) == byteLength-1:
s = '\0' + s
else:
raise AssertionError()
m = stringToNumber(self.rsa.encrypt(s, None)[0])
return m
def writeXMLPublicKey(self, indent=''):
return Python_RSAKey(self.n, self.e).write(indent)
def generate(bits):
key = PyCrypto_RSAKey()
def f(numBytes):
return bytesToString(getRandomBytes(numBytes))
key.rsa = RSA.generate(bits, f)
return key
generate = staticmethod(generate)
tlslite-0.3.8/tlslite/utils/TripleDES.py 0000700 0001750 0001750 00000001400 10130676221 017155 0 ustar clint clint """Abstract class for 3DES."""
from compat import * #For True
class TripleDES:
def __init__(self, key, mode, IV, implementation):
if len(key) != 24:
raise ValueError()
if mode != 2:
raise ValueError()
if len(IV) != 8:
raise ValueError()
self.isBlockCipher = True
self.block_size = 8
self.implementation = implementation
self.name = "3des"
#CBC-Mode encryption, returns ciphertext
#WARNING: *MAY* modify the input as well
def encrypt(self, plaintext):
assert(len(plaintext) % 8 == 0)
#CBC-Mode decryption, returns plaintext
#WARNING: *MAY* modify the input as well
def decrypt(self, ciphertext):
assert(len(ciphertext) % 8 == 0)
tlslite-0.3.8/tlslite/utils/entropy.c 0000700 0001750 0001750 00000011275 10043077535 016675 0 ustar clint clint
#include "Python.h"
#ifdef MS_WINDOWS
/* The following #define is not needed on VC6 with the Platform SDK, and it
may not be needed on VC7, I'm not sure. I don't think it hurts anything.*/
#define _WIN32_WINNT 0x0400
#include
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
DWORD dwFlags );
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
BYTE *pbBuffer );
typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv,\
DWORD dwFlags);
static PyObject* entropy(PyObject *self, PyObject *args)
{
int howMany = 0;
HINSTANCE hAdvAPI32 = NULL;
CRYPTACQUIRECONTEXTA pCryptAcquireContextA = NULL;
CRYPTGENRANDOM pCryptGenRandom = NULL;
CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
HCRYPTPROV hCryptProv = 0;
unsigned char* bytes = NULL;
PyObject* returnVal = NULL;
/* Read arguments */
if (!PyArg_ParseTuple(args, "i", &howMany))
return(NULL);
/* Obtain handle to the DLL containing CryptoAPI
This should not fail */
if( (hAdvAPI32 = GetModuleHandle("advapi32.dll")) == NULL) {
PyErr_Format(PyExc_SystemError,
"Advapi32.dll not found");
return NULL;
}
/* Obtain pointers to the CryptoAPI functions
This will fail on some early version of Win95 */
pCryptAcquireContextA = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32,\
"CryptAcquireContextA");
pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32,\
"CryptGenRandom");
pCryptReleaseContext = (CRYPTRELEASECONTEXT) GetProcAddress(hAdvAPI32,\
"CryptReleaseContext");
if (pCryptAcquireContextA == NULL || pCryptGenRandom == NULL ||
pCryptReleaseContext == NULL) {
PyErr_Format(PyExc_NotImplementedError,
"CryptoAPI not available on this version of Windows");
return NULL;
}
/* Allocate bytes */
if ((bytes = (unsigned char*)PyMem_Malloc(howMany)) == NULL)
return PyErr_NoMemory();
/* Acquire context */
if(!pCryptAcquireContextA(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
PyErr_Format(PyExc_SystemError,
"CryptAcquireContext failed, error %d", GetLastError());
PyMem_Free(bytes);
return NULL;
}
/* Get random data */
if(!pCryptGenRandom(hCryptProv, howMany, bytes)) {
PyErr_Format(PyExc_SystemError,
"CryptGenRandom failed, error %d", GetLastError());
PyMem_Free(bytes);
CryptReleaseContext(hCryptProv, 0);
return NULL;
}
/* Build return value */
returnVal = Py_BuildValue("s#", bytes, howMany);
PyMem_Free(bytes);
/* Release context */
if (!pCryptReleaseContext(hCryptProv, 0)) {
PyErr_Format(PyExc_SystemError,
"CryptReleaseContext failed, error %d", GetLastError());
return NULL;
}
return returnVal;
}
#elif defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL_H)
#include
#include
static PyObject* entropy(PyObject *self, PyObject *args)
{
int howMany;
int fd;
unsigned char* bytes = NULL;
PyObject* returnVal = NULL;
/* Read arguments */
if (!PyArg_ParseTuple(args, "i", &howMany))
return(NULL);
/* Allocate bytes */
if ((bytes = (unsigned char*)PyMem_Malloc(howMany)) == NULL)
return PyErr_NoMemory();
/* Open device */
if ((fd = open("/dev/urandom", O_RDONLY, 0)) == -1) {
PyErr_Format(PyExc_NotImplementedError,
"No entropy source found");
PyMem_Free(bytes);
return NULL;
}
/* Get random data */
if (read(fd, bytes, howMany) < howMany) {
PyErr_Format(PyExc_SystemError,
"Reading from /dev/urandom failed");
PyMem_Free(bytes);
close(fd);
return NULL;
}
/* Build return value */
returnVal = Py_BuildValue("s#", bytes, howMany);
PyMem_Free(bytes);
/* Close device */
close(fd);
return returnVal;
}
#else
static PyObject* entropy(PyObject *self, PyObject *args)
{
PyErr_Format(PyExc_NotImplementedError,
"Function not supported");
return NULL;
}
#endif
/* List of functions exported by this module */
static struct PyMethodDef entropy_functions[] = {
{"entropy", (PyCFunction)entropy, METH_VARARGS, "Return a string of random bytes produced by a platform-specific\nentropy source."},
{NULL, NULL} /* Sentinel */
};
/* Initialize this module. */
PyMODINIT_FUNC initentropy(void)
{
Py_InitModule("entropy", entropy_functions);
} tlslite-0.3.8/tlslite/utils/OpenSSL_TripleDES.py 0000700 0001750 0001750 00000003202 10025510541 020515 0 ustar clint clint """OpenSSL/M2Crypto 3DES implementation."""
from cryptomath import *
from TripleDES import *
if m2cryptoLoaded:
def new(key, mode, IV):
return OpenSSL_TripleDES(key, mode, IV)
class OpenSSL_TripleDES(TripleDES):
def __init__(self, key, mode, IV):
TripleDES.__init__(self, key, mode, IV, "openssl")
self.key = key
self.IV = IV
def _createContext(self, encrypt):
context = m2.cipher_ctx_new()
cipherType = m2.des_ede3_cbc()
m2.cipher_init(context, cipherType, self.key, self.IV, encrypt)
return context
def encrypt(self, plaintext):
TripleDES.encrypt(self, plaintext)
context = self._createContext(1)
ciphertext = m2.cipher_update(context, plaintext)
m2.cipher_ctx_free(context)
self.IV = ciphertext[-self.block_size:]
return ciphertext
def decrypt(self, ciphertext):
TripleDES.decrypt(self, ciphertext)
context = self._createContext(0)
#I think M2Crypto has a bug - it fails to decrypt and return the last block passed in.
#To work around this, we append sixteen zeros to the string, below:
plaintext = m2.cipher_update(context, ciphertext+('\0'*16))
#If this bug is ever fixed, then plaintext will end up having a garbage
#plaintext block on the end. That's okay - the below code will ignore it.
plaintext = plaintext[:len(ciphertext)]
m2.cipher_ctx_free(context)
self.IV = ciphertext[-self.block_size:]
return plaintext tlslite-0.3.8/tlslite/utils/rijndael.py 0000700 0001750 0001750 00000026115 10016012503 017152 0 ustar clint clint """
A pure python (slow) implementation of rijndael with a decent interface
To include -
from rijndael import rijndael
To do a key setup -
r = rijndael(key, block_size = 16)
key must be a string of length 16, 24, or 32
blocksize must be 16, 24, or 32. Default is 16
To use -
ciphertext = r.encrypt(plaintext)
plaintext = r.decrypt(ciphertext)
If any strings are of the wrong length a ValueError is thrown
"""
# ported from the Java reference code by Bram Cohen, bram@gawth.com, April 2001
# this code is public domain, unless someone makes
# an intellectual property claim against the reference
# code, in which case it can be made public domain by
# deleting all the comments and renaming all the variables
import copy
import string
#-----------------------
#TREV - ADDED BECAUSE THERE'S WARNINGS ABOUT INT OVERFLOW BEHAVIOR CHANGING IN
#2.4.....
import os
if os.name != "java":
import exceptions
if hasattr(exceptions, "FutureWarning"):
import warnings
warnings.filterwarnings("ignore", category=FutureWarning, append=1)
#-----------------------
shifts = [[[0, 0], [1, 3], [2, 2], [3, 1]],
[[0, 0], [1, 5], [2, 4], [3, 3]],
[[0, 0], [1, 7], [3, 5], [4, 4]]]
# [keysize][block_size]
num_rounds = {16: {16: 10, 24: 12, 32: 14}, 24: {16: 12, 24: 12, 32: 14}, 32: {16: 14, 24: 14, 32: 14}}
A = [[1, 1, 1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 1],
[1, 1, 0, 0, 0, 1, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 1],
[1, 1, 1, 1, 0, 0, 0, 1]]
# produce log and alog tables, needed for multiplying in the
# field GF(2^m) (generator = 3)
alog = [1]
for i in xrange(255):
j = (alog[-1] << 1) ^ alog[-1]
if j & 0x100 != 0:
j ^= 0x11B
alog.append(j)
log = [0] * 256
for i in xrange(1, 255):
log[alog[i]] = i
# multiply two elements of GF(2^m)
def mul(a, b):
if a == 0 or b == 0:
return 0
return alog[(log[a & 0xFF] + log[b & 0xFF]) % 255]
# substitution box based on F^{-1}(x)
box = [[0] * 8 for i in xrange(256)]
box[1][7] = 1
for i in xrange(2, 256):
j = alog[255 - log[i]]
for t in xrange(8):
box[i][t] = (j >> (7 - t)) & 0x01
B = [0, 1, 1, 0, 0, 0, 1, 1]
# affine transform: box[i] <- B + A*box[i]
cox = [[0] * 8 for i in xrange(256)]
for i in xrange(256):
for t in xrange(8):
cox[i][t] = B[t]
for j in xrange(8):
cox[i][t] ^= A[t][j] * box[i][j]
# S-boxes and inverse S-boxes
S = [0] * 256
Si = [0] * 256
for i in xrange(256):
S[i] = cox[i][0] << 7
for t in xrange(1, 8):
S[i] ^= cox[i][t] << (7-t)
Si[S[i] & 0xFF] = i
# T-boxes
G = [[2, 1, 1, 3],
[3, 2, 1, 1],
[1, 3, 2, 1],
[1, 1, 3, 2]]
AA = [[0] * 8 for i in xrange(4)]
for i in xrange(4):
for j in xrange(4):
AA[i][j] = G[i][j]
AA[i][i+4] = 1
for i in xrange(4):
pivot = AA[i][i]
if pivot == 0:
t = i + 1
while AA[t][i] == 0 and t < 4:
t += 1
assert t != 4, 'G matrix must be invertible'
for j in xrange(8):
AA[i][j], AA[t][j] = AA[t][j], AA[i][j]
pivot = AA[i][i]
for j in xrange(8):
if AA[i][j] != 0:
AA[i][j] = alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]
for t in xrange(4):
if i != t:
for j in xrange(i+1, 8):
AA[t][j] ^= mul(AA[i][j], AA[t][i])
AA[t][i] = 0
iG = [[0] * 4 for i in xrange(4)]
for i in xrange(4):
for j in xrange(4):
iG[i][j] = AA[i][j + 4]
def mul4(a, bs):
if a == 0:
return 0
r = 0
for b in bs:
r <<= 8
if b != 0:
r = r | mul(a, b)
return r
T1 = []
T2 = []
T3 = []
T4 = []
T5 = []
T6 = []
T7 = []
T8 = []
U1 = []
U2 = []
U3 = []
U4 = []
for t in xrange(256):
s = S[t]
T1.append(mul4(s, G[0]))
T2.append(mul4(s, G[1]))
T3.append(mul4(s, G[2]))
T4.append(mul4(s, G[3]))
s = Si[t]
T5.append(mul4(s, iG[0]))
T6.append(mul4(s, iG[1]))
T7.append(mul4(s, iG[2]))
T8.append(mul4(s, iG[3]))
U1.append(mul4(t, iG[0]))
U2.append(mul4(t, iG[1]))
U3.append(mul4(t, iG[2]))
U4.append(mul4(t, iG[3]))
# round constants
rcon = [1]
r = 1
for t in xrange(1, 30):
r = mul(2, r)
rcon.append(r)
del A
del AA
del pivot
del B
del G
del box
del log
del alog
del i
del j
del r
del s
del t
del mul
del mul4
del cox
del iG
class rijndael:
def __init__(self, key, block_size = 16):
if block_size != 16 and block_size != 24 and block_size != 32:
raise ValueError('Invalid block size: ' + str(block_size))
if len(key) != 16 and len(key) != 24 and len(key) != 32:
raise ValueError('Invalid key size: ' + str(len(key)))
self.block_size = block_size
ROUNDS = num_rounds[len(key)][block_size]
BC = block_size / 4
# encryption round keys
Ke = [[0] * BC for i in xrange(ROUNDS + 1)]
# decryption round keys
Kd = [[0] * BC for i in xrange(ROUNDS + 1)]
ROUND_KEY_COUNT = (ROUNDS + 1) * BC
KC = len(key) / 4
# copy user material bytes into temporary ints
tk = []
for i in xrange(0, KC):
tk.append((ord(key[i * 4]) << 24) | (ord(key[i * 4 + 1]) << 16) |
(ord(key[i * 4 + 2]) << 8) | ord(key[i * 4 + 3]))
# copy values into round key arrays
t = 0
j = 0
while j < KC and t < ROUND_KEY_COUNT:
Ke[t / BC][t % BC] = tk[j]
Kd[ROUNDS - (t / BC)][t % BC] = tk[j]
j += 1
t += 1
tt = 0
rconpointer = 0
while t < ROUND_KEY_COUNT:
# extrapolate using phi (the round key evolution function)
tt = tk[KC - 1]
tk[0] ^= (S[(tt >> 16) & 0xFF] & 0xFF) << 24 ^ \
(S[(tt >> 8) & 0xFF] & 0xFF) << 16 ^ \
(S[ tt & 0xFF] & 0xFF) << 8 ^ \
(S[(tt >> 24) & 0xFF] & 0xFF) ^ \
(rcon[rconpointer] & 0xFF) << 24
rconpointer += 1
if KC != 8:
for i in xrange(1, KC):
tk[i] ^= tk[i-1]
else:
for i in xrange(1, KC / 2):
tk[i] ^= tk[i-1]
tt = tk[KC / 2 - 1]
tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) ^ \
(S[(tt >> 8) & 0xFF] & 0xFF) << 8 ^ \
(S[(tt >> 16) & 0xFF] & 0xFF) << 16 ^ \
(S[(tt >> 24) & 0xFF] & 0xFF) << 24
for i in xrange(KC / 2 + 1, KC):
tk[i] ^= tk[i-1]
# copy values into round key arrays
j = 0
while j < KC and t < ROUND_KEY_COUNT:
Ke[t / BC][t % BC] = tk[j]
Kd[ROUNDS - (t / BC)][t % BC] = tk[j]
j += 1
t += 1
# inverse MixColumn where needed
for r in xrange(1, ROUNDS):
for j in xrange(BC):
tt = Kd[r][j]
Kd[r][j] = U1[(tt >> 24) & 0xFF] ^ \
U2[(tt >> 16) & 0xFF] ^ \
U3[(tt >> 8) & 0xFF] ^ \
U4[ tt & 0xFF]
self.Ke = Ke
self.Kd = Kd
def encrypt(self, plaintext):
if len(plaintext) != self.block_size:
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
Ke = self.Ke
BC = self.block_size / 4
ROUNDS = len(Ke) - 1
if BC == 4:
SC = 0
elif BC == 6:
SC = 1
else:
SC = 2
s1 = shifts[SC][1][0]
s2 = shifts[SC][2][0]
s3 = shifts[SC][3][0]
a = [0] * BC
# temporary work array
t = []
# plaintext to ints + key
for i in xrange(BC):
t.append((ord(plaintext[i * 4 ]) << 24 |
ord(plaintext[i * 4 + 1]) << 16 |
ord(plaintext[i * 4 + 2]) << 8 |
ord(plaintext[i * 4 + 3]) ) ^ Ke[0][i])
# apply round transforms
for r in xrange(1, ROUNDS):
for i in xrange(BC):
a[i] = (T1[(t[ i ] >> 24) & 0xFF] ^
T2[(t[(i + s1) % BC] >> 16) & 0xFF] ^
T3[(t[(i + s2) % BC] >> 8) & 0xFF] ^
T4[ t[(i + s3) % BC] & 0xFF] ) ^ Ke[r][i]
t = copy.copy(a)
# last round is special
result = []
for i in xrange(BC):
tt = Ke[ROUNDS][i]
result.append((S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
result.append((S[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
result.append((S[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
result.append((S[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
return string.join(map(chr, result), '')
def decrypt(self, ciphertext):
if len(ciphertext) != self.block_size:
raise ValueError('wrong block length, expected ' + str(self.block_size) + ' got ' + str(len(plaintext)))
Kd = self.Kd
BC = self.block_size / 4
ROUNDS = len(Kd) - 1
if BC == 4:
SC = 0
elif BC == 6:
SC = 1
else:
SC = 2
s1 = shifts[SC][1][1]
s2 = shifts[SC][2][1]
s3 = shifts[SC][3][1]
a = [0] * BC
# temporary work array
t = [0] * BC
# ciphertext to ints + key
for i in xrange(BC):
t[i] = (ord(ciphertext[i * 4 ]) << 24 |
ord(ciphertext[i * 4 + 1]) << 16 |
ord(ciphertext[i * 4 + 2]) << 8 |
ord(ciphertext[i * 4 + 3]) ) ^ Kd[0][i]
# apply round transforms
for r in xrange(1, ROUNDS):
for i in xrange(BC):
a[i] = (T5[(t[ i ] >> 24) & 0xFF] ^
T6[(t[(i + s1) % BC] >> 16) & 0xFF] ^
T7[(t[(i + s2) % BC] >> 8) & 0xFF] ^
T8[ t[(i + s3) % BC] & 0xFF] ) ^ Kd[r][i]
t = copy.copy(a)
# last round is special
result = []
for i in xrange(BC):
tt = Kd[ROUNDS][i]
result.append((Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF)
result.append((Si[(t[(i + s1) % BC] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF)
result.append((Si[(t[(i + s2) % BC] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF)
result.append((Si[ t[(i + s3) % BC] & 0xFF] ^ tt ) & 0xFF)
return string.join(map(chr, result), '')
def encrypt(key, block):
return rijndael(key, len(block)).encrypt(block)
def decrypt(key, block):
return rijndael(key, len(block)).decrypt(block)
def test():
def t(kl, bl):
b = 'b' * bl
r = rijndael('a' * kl, bl)
assert r.decrypt(r.encrypt(b)) == b
t(16, 16)
t(16, 24)
t(16, 32)
t(24, 16)
t(24, 24)
t(24, 32)
t(32, 16)
t(32, 24)
t(32, 32)
tlslite-0.3.8/tlslite/utils/jython_compat.py 0000700 0001750 0001750 00000012226 10206534007 020247 0 ustar clint clint """Miscellaneous functions to mask Python/Jython differences."""
import os
import sha
if os.name != "java":
BaseException = Exception
from sets import Set
import array
import math
def createByteArraySequence(seq):
return array.array('B', seq)
def createByteArrayZeros(howMany):
return array.array('B', [0] * howMany)
def concatArrays(a1, a2):
return a1+a2
def bytesToString(bytes):
return bytes.tostring()
def stringToBytes(s):
bytes = createByteArrayZeros(0)
bytes.fromstring(s)
return bytes
def numBits(n):
if n==0:
return 0
return int(math.floor(math.log(n, 2))+1)
class CertChainBase: pass
class SelfTestBase: pass
class ReportFuncBase: pass
#Helper functions for working with sets (from Python 2.3)
def iterSet(set):
return iter(set)
def getListFromSet(set):
return list(set)
#Factory function for getting a SHA1 object
def getSHA1(s):
return sha.sha(s)
import sys
import traceback
def formatExceptionTrace(e):
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
return newStr
else:
#Jython 2.1 is missing lots of python 2.3 stuff,
#which we have to emulate here:
import java
import jarray
BaseException = java.lang.Exception
def createByteArraySequence(seq):
if isinstance(seq, type("")): #If it's a string, convert
seq = [ord(c) for c in seq]
return jarray.array(seq, 'h') #use short instead of bytes, cause bytes are signed
def createByteArrayZeros(howMany):
return jarray.zeros(howMany, 'h') #use short instead of bytes, cause bytes are signed
def concatArrays(a1, a2):
l = list(a1)+list(a2)
return createByteArraySequence(l)
#WAY TOO SLOW - MUST BE REPLACED------------
def bytesToString(bytes):
return "".join([chr(b) for b in bytes])
def stringToBytes(s):
bytes = createByteArrayZeros(len(s))
for count, c in enumerate(s):
bytes[count] = ord(c)
return bytes
#WAY TOO SLOW - MUST BE REPLACED------------
def numBits(n):
if n==0:
return 0
n= 1L * n; #convert to long, if it isn't already
return n.__tojava__(java.math.BigInteger).bitLength()
#This properly creates static methods for Jython
class staticmethod:
def __init__(self, anycallable): self.__call__ = anycallable
#Properties are not supported for Jython
class property:
def __init__(self, anycallable): pass
#True and False have to be specially defined
False = 0
True = 1
class StopIteration(Exception): pass
def enumerate(collection):
return zip(range(len(collection)), collection)
class Set:
def __init__(self, seq=None):
self.values = {}
if seq:
for e in seq:
self.values[e] = None
def add(self, e):
self.values[e] = None
def discard(self, e):
if e in self.values.keys():
del(self.values[e])
def union(self, s):
ret = Set()
for e in self.values.keys():
ret.values[e] = None
for e in s.values.keys():
ret.values[e] = None
return ret
def issubset(self, other):
for e in self.values.keys():
if e not in other.values.keys():
return False
return True
def __nonzero__( self):
return len(self.values.keys())
def __contains__(self, e):
return e in self.values.keys()
def iterSet(set):
return set.values.keys()
def getListFromSet(set):
return set.values.keys()
"""
class JCE_SHA1:
def __init__(self, s=None):
self.md = java.security.MessageDigest.getInstance("SHA1")
if s:
self.update(s)
def update(self, s):
self.md.update(s)
def copy(self):
sha1 = JCE_SHA1()
sha1.md = self.md.clone()
return sha1
def digest(self):
digest = self.md.digest()
bytes = jarray.zeros(20, 'h')
for count in xrange(20):
x = digest[count]
if x < 0: x += 256
bytes[count] = x
return bytes
"""
#Factory function for getting a SHA1 object
#The JCE_SHA1 class is way too slow...
#the sha.sha object we use instead is broken in the jython 2.1
#release, and needs to be patched
def getSHA1(s):
#return JCE_SHA1(s)
return sha.sha(s)
#Adjust the string to an array of bytes
def stringToJavaByteArray(s):
bytes = jarray.zeros(len(s), 'b')
for count, c in enumerate(s):
x = ord(c)
if x >= 128: x -= 256
bytes[count] = x
return bytes
import sys
import traceback
def formatExceptionTrace(e):
newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
return newStr
tlslite-0.3.8/tlslite/utils/OpenSSL_RSAKey.py 0000700 0001750 0001750 00000011626 10027165661 020044 0 ustar clint clint """OpenSSL/M2Crypto RSA implementation."""
from cryptomath import *
from RSAKey import *
from Python_RSAKey import Python_RSAKey
#copied from M2Crypto.util.py, so when we load the local copy of m2
#we can still use it
def password_callback(v, prompt1='Enter private key passphrase:',
prompt2='Verify passphrase:'):
from getpass import getpass
while 1:
try:
p1=getpass(prompt1)
if v:
p2=getpass(prompt2)
if p1==p2:
break
else:
break
except KeyboardInterrupt:
return None
return p1
if m2cryptoLoaded:
class OpenSSL_RSAKey(RSAKey):
def __init__(self, n=0, e=0):
self.rsa = None
self._hasPrivateKey = False
if (n and not e) or (e and not n):
raise AssertionError()
if n and e:
self.rsa = m2.rsa_new()
m2.rsa_set_n(self.rsa, numberToMPI(n))
m2.rsa_set_e(self.rsa, numberToMPI(e))
def __del__(self):
if self.rsa:
m2.rsa_free(self.rsa)
def __getattr__(self, name):
if name == 'e':
if not self.rsa:
return 0
return mpiToNumber(m2.rsa_get_e(self.rsa))
elif name == 'n':
if not self.rsa:
return 0
return mpiToNumber(m2.rsa_get_n(self.rsa))
else:
raise AttributeError
def hasPrivateKey(self):
return self._hasPrivateKey
def hash(self):
return Python_RSAKey(self.n, self.e).hash()
def _rawPrivateKeyOp(self, m):
s = numberToString(m)
byteLength = numBytes(self.n)
if len(s)== byteLength:
pass
elif len(s) == byteLength-1:
s = '\0' + s
else:
raise AssertionError()
c = stringToNumber(m2.rsa_private_encrypt(self.rsa, s,
m2.no_padding))
return c
def _rawPublicKeyOp(self, c):
s = numberToString(c)
byteLength = numBytes(self.n)
if len(s)== byteLength:
pass
elif len(s) == byteLength-1:
s = '\0' + s
else:
raise AssertionError()
m = stringToNumber(m2.rsa_public_decrypt(self.rsa, s,
m2.no_padding))
return m
def acceptsPassword(self): return True
def write(self, password=None):
bio = m2.bio_new(m2.bio_s_mem())
if self._hasPrivateKey:
if password:
def f(v): return password
m2.rsa_write_key(self.rsa, bio, m2.des_ede_cbc(), f)
else:
def f(): pass
m2.rsa_write_key_no_cipher(self.rsa, bio, f)
else:
if password:
raise AssertionError()
m2.rsa_write_pub_key(self.rsa, bio)
s = m2.bio_read(bio, m2.bio_ctrl_pending(bio))
m2.bio_free(bio)
return s
def writeXMLPublicKey(self, indent=''):
return Python_RSAKey(self.n, self.e).write(indent)
def generate(bits):
key = OpenSSL_RSAKey()
def f():pass
key.rsa = m2.rsa_generate_key(bits, 3, f)
key._hasPrivateKey = True
return key
generate = staticmethod(generate)
def parse(s, passwordCallback=None):
if s.startswith("-----BEGIN "):
if passwordCallback==None:
callback = password_callback
else:
def f(v, prompt1=None, prompt2=None):
return passwordCallback()
callback = f
bio = m2.bio_new(m2.bio_s_mem())
try:
m2.bio_write(bio, s)
key = OpenSSL_RSAKey()
if s.startswith("-----BEGIN RSA PRIVATE KEY-----"):
def f():pass
key.rsa = m2.rsa_read_key(bio, callback)
if key.rsa == None:
raise SyntaxError()
key._hasPrivateKey = True
elif s.startswith("-----BEGIN PUBLIC KEY-----"):
key.rsa = m2.rsa_read_pub_key(bio)
if key.rsa == None:
raise SyntaxError()
key._hasPrivateKey = False
else:
raise SyntaxError()
return key
finally:
m2.bio_free(bio)
else:
raise SyntaxError()
parse = staticmethod(parse)
tlslite-0.3.8/tlslite/utils/RC4.py 0000700 0001750 0001750 00000000712 10130676211 015756 0 ustar clint clint """Abstract class for RC4."""
from compat import * #For False
class RC4:
def __init__(self, keyBytes, implementation):
if len(keyBytes) < 16 or len(keyBytes) > 256:
raise ValueError()
self.isBlockCipher = False
self.name = "rc4"
self.implementation = implementation
def encrypt(self, plaintext):
raise NotImplementedError()
def decrypt(self, ciphertext):
raise NotImplementedError() tlslite-0.3.8/tlslite/utils/Cryptlib_RC4.py 0000700 0001750 0001750 00000001642 10025507724 017636 0 ustar clint clint """Cryptlib RC4 implementation."""
from cryptomath import *
from RC4 import RC4
if cryptlibpyLoaded:
def new(key):
return Cryptlib_RC4(key)
class Cryptlib_RC4(RC4):
def __init__(self, key):
RC4.__init__(self, key, "cryptlib")
self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_RC4)
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key))
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key)
def __del__(self):
cryptlib_py.cryptDestroyContext(self.context)
def encrypt(self, plaintext):
bytes = stringToBytes(plaintext)
cryptlib_py.cryptEncrypt(self.context, bytes)
return bytesToString(bytes)
def decrypt(self, ciphertext):
return self.encrypt(ciphertext) tlslite-0.3.8/tlslite/utils/Python_RSAKey.py 0000700 0001750 0001750 00000017033 10026003077 020027 0 ustar clint clint """Pure-Python RSA implementation."""
from cryptomath import *
import xmltools
from ASN1Parser import ASN1Parser
from RSAKey import *
class Python_RSAKey(RSAKey):
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):
raise AssertionError()
self.n = n
self.e = e
self.d = d
self.p = p
self.q = q
self.dP = dP
self.dQ = dQ
self.qInv = qInv
self.blinder = 0
self.unblinder = 0
def hasPrivateKey(self):
return self.d != 0
def hash(self):
s = self.writeXMLPublicKey('\t\t')
return hashAndBase64(s.strip())
def _rawPrivateKeyOp(self, m):
#Create blinding values, on the first pass:
if not self.blinder:
self.unblinder = getRandomNumber(2, self.n)
self.blinder = powMod(invMod(self.unblinder, self.n), self.e,
self.n)
#Blind the input
m = (m * self.blinder) % self.n
#Perform the RSA operation
c = self._rawPrivateKeyOpHelper(m)
#Unblind the output
c = (c * self.unblinder) % self.n
#Update blinding values
self.blinder = (self.blinder * self.blinder) % self.n
self.unblinder = (self.unblinder * self.unblinder) % self.n
#Return the output
return c
def _rawPrivateKeyOpHelper(self, m):
#Non-CRT version
#c = powMod(m, self.d, self.n)
#CRT version (~3x faster)
s1 = powMod(m, self.dP, self.p)
s2 = powMod(m, self.dQ, self.q)
h = ((s1 - s2) * self.qInv) % self.p
c = s2 + self.q * h
return c
def _rawPublicKeyOp(self, c):
m = powMod(c, self.e, self.n)
return m
def acceptsPassword(self): return False
def write(self, indent=''):
if self.d:
s = indent+'\n'
else:
s = indent+'\n'
s += indent+'\t%s\n' % numberToBase64(self.n)
s += indent+'\t%s\n' % numberToBase64(self.e)
if self.d:
s += indent+'\t%s\n' % numberToBase64(self.d)
s += indent+'\t
%s
\n' % numberToBase64(self.p)
s += indent+'\t%s\n' % numberToBase64(self.q)
s += indent+'\t%s\n' % numberToBase64(self.dP)
s += indent+'\t%s\n' % numberToBase64(self.dQ)
s += indent+'\t%s\n' % numberToBase64(self.qInv)
s += indent+''
else:
s += indent+''
#Only add \n if part of a larger structure
if indent != '':
s += '\n'
return s
def writeXMLPublicKey(self, indent=''):
return Python_RSAKey(self.n, self.e).write(indent)
def generate(bits):
key = Python_RSAKey()
p = getRandomPrime(bits/2, False)
q = getRandomPrime(bits/2, False)
t = lcm(p-1, q-1)
key.n = p * q
key.e = 3L #Needed to be long, for Java
key.d = invMod(key.e, t)
key.p = p
key.q = q
key.dP = key.d % (p-1)
key.dQ = key.d % (q-1)
key.qInv = invMod(q, p)
return key
generate = staticmethod(generate)
def parsePEM(s, passwordCallback=None):
"""Parse a string containing a or , or
PEM-encoded key."""
start = s.find("-----BEGIN PRIVATE KEY-----")
if start != -1:
end = s.find("-----END PRIVATE KEY-----")
if end == -1:
raise SyntaxError("Missing PEM Postfix")
s = s[start+len("-----BEGIN PRIVATE KEY -----") : end]
bytes = base64ToBytes(s)
return Python_RSAKey._parsePKCS8(bytes)
else:
start = s.find("-----BEGIN RSA PRIVATE KEY-----")
if start != -1:
end = s.find("-----END RSA PRIVATE KEY-----")
if end == -1:
raise SyntaxError("Missing PEM Postfix")
s = s[start+len("-----BEGIN RSA PRIVATE KEY -----") : end]
bytes = base64ToBytes(s)
return Python_RSAKey._parseSSLeay(bytes)
raise SyntaxError("Missing PEM Prefix")
parsePEM = staticmethod(parsePEM)
def parseXML(s):
element = xmltools.parseAndStripWhitespace(s)
return Python_RSAKey._parseXML(element)
parseXML = staticmethod(parseXML)
def _parsePKCS8(bytes):
p = ASN1Parser(bytes)
version = p.getChild(0).value[0]
if version != 0:
raise SyntaxError("Unrecognized PKCS8 version")
rsaOID = p.getChild(1).value
if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]:
raise SyntaxError("Unrecognized AlgorithmIdentifier")
#Get the privateKey
privateKeyP = p.getChild(2)
#Adjust for OCTET STRING encapsulation
privateKeyP = ASN1Parser(privateKeyP.value)
return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
_parsePKCS8 = staticmethod(_parsePKCS8)
def _parseSSLeay(bytes):
privateKeyP = ASN1Parser(bytes)
return Python_RSAKey._parseASN1PrivateKey(privateKeyP)
_parseSSLeay = staticmethod(_parseSSLeay)
def _parseASN1PrivateKey(privateKeyP):
version = privateKeyP.getChild(0).value[0]
if version != 0:
raise SyntaxError("Unrecognized RSAPrivateKey version")
n = bytesToNumber(privateKeyP.getChild(1).value)
e = bytesToNumber(privateKeyP.getChild(2).value)
d = bytesToNumber(privateKeyP.getChild(3).value)
p = bytesToNumber(privateKeyP.getChild(4).value)
q = bytesToNumber(privateKeyP.getChild(5).value)
dP = bytesToNumber(privateKeyP.getChild(6).value)
dQ = bytesToNumber(privateKeyP.getChild(7).value)
qInv = bytesToNumber(privateKeyP.getChild(8).value)
return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
_parseASN1PrivateKey = staticmethod(_parseASN1PrivateKey)
def _parseXML(element):
try:
xmltools.checkName(element, "privateKey")
except SyntaxError:
xmltools.checkName(element, "publicKey")
#Parse attributes
xmltools.getReqAttribute(element, "xmlns", "http://trevp.net/rsa\Z")
xmltools.checkNoMoreAttributes(element)
#Parse public values ( and )
n = base64ToNumber(xmltools.getText(xmltools.getChild(element, 0, "n"), xmltools.base64RegEx))
e = base64ToNumber(xmltools.getText(xmltools.getChild(element, 1, "e"), xmltools.base64RegEx))
d = 0
p = 0
q = 0
dP = 0
dQ = 0
qInv = 0
#Parse private values, if present
if element.childNodes.length>=3:
d = base64ToNumber(xmltools.getText(xmltools.getChild(element, 2, "d"), xmltools.base64RegEx))
p = base64ToNumber(xmltools.getText(xmltools.getChild(element, 3, "p"), xmltools.base64RegEx))
q = base64ToNumber(xmltools.getText(xmltools.getChild(element, 4, "q"), xmltools.base64RegEx))
dP = base64ToNumber(xmltools.getText(xmltools.getChild(element, 5, "dP"), xmltools.base64RegEx))
dQ = base64ToNumber(xmltools.getText(xmltools.getChild(element, 6, "dQ"), xmltools.base64RegEx))
qInv = base64ToNumber(xmltools.getText(xmltools.getLastChild(element, 7, "qInv"), xmltools.base64RegEx))
return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv)
_parseXML = staticmethod(_parseXML)
tlslite-0.3.8/tlslite/utils/cipherfactory.py 0000700 0001750 0001750 00000006151 10025512501 020225 0 ustar clint clint """Factory functions for symmetric cryptography."""
import os
import Python_AES
import Python_RC4
import cryptomath
tripleDESPresent = False
if cryptomath.m2cryptoLoaded:
import OpenSSL_AES
import OpenSSL_RC4
import OpenSSL_TripleDES
tripleDESPresent = True
if cryptomath.cryptlibpyLoaded:
import Cryptlib_AES
import Cryptlib_RC4
import Cryptlib_TripleDES
tripleDESPresent = True
if cryptomath.pycryptoLoaded:
import PyCrypto_AES
import PyCrypto_RC4
import PyCrypto_TripleDES
tripleDESPresent = True
# **************************************************************************
# Factory Functions for AES
# **************************************************************************
def createAES(key, IV, implList=None):
"""Create a new AES object.
@type key: str
@param key: A 16, 24, or 32 byte string.
@type IV: str
@param IV: A 16 byte string
@rtype: L{tlslite.utils.AES}
@return: An AES object.
"""
if implList == None:
implList = ["cryptlib", "openssl", "pycrypto", "python"]
for impl in implList:
if impl == "cryptlib" and cryptomath.cryptlibpyLoaded:
return Cryptlib_AES.new(key, 2, IV)
elif impl == "openssl" and cryptomath.m2cryptoLoaded:
return OpenSSL_AES.new(key, 2, IV)
elif impl == "pycrypto" and cryptomath.pycryptoLoaded:
return PyCrypto_AES.new(key, 2, IV)
elif impl == "python":
return Python_AES.new(key, 2, IV)
raise NotImplementedError()
def createRC4(key, IV, implList=None):
"""Create a new RC4 object.
@type key: str
@param key: A 16 to 32 byte string.
@type IV: object
@param IV: Ignored, whatever it is.
@rtype: L{tlslite.utils.RC4}
@return: An RC4 object.
"""
if implList == None:
implList = ["cryptlib", "openssl", "pycrypto", "python"]
if len(IV) != 0:
raise AssertionError()
for impl in implList:
if impl == "cryptlib" and cryptomath.cryptlibpyLoaded:
return Cryptlib_RC4.new(key)
elif impl == "openssl" and cryptomath.m2cryptoLoaded:
return OpenSSL_RC4.new(key)
elif impl == "pycrypto" and cryptomath.pycryptoLoaded:
return PyCrypto_RC4.new(key)
elif impl == "python":
return Python_RC4.new(key)
raise NotImplementedError()
#Create a new TripleDES instance
def createTripleDES(key, IV, implList=None):
"""Create a new 3DES object.
@type key: str
@param key: A 24 byte string.
@type IV: str
@param IV: An 8 byte string
@rtype: L{tlslite.utils.TripleDES}
@return: A 3DES object.
"""
if implList == None:
implList = ["cryptlib", "openssl", "pycrypto"]
for impl in implList:
if impl == "cryptlib" and cryptomath.cryptlibpyLoaded:
return Cryptlib_TripleDES.new(key, 2, IV)
elif impl == "openssl" and cryptomath.m2cryptoLoaded:
return OpenSSL_TripleDES.new(key, 2, IV)
elif impl == "pycrypto" and cryptomath.pycryptoLoaded:
return PyCrypto_TripleDES.new(key, 2, IV)
raise NotImplementedError() tlslite-0.3.8/tlslite/utils/AES.py 0000700 0001750 0001750 00000001676 10130676147 016020 0 ustar clint clint """Abstract class for AES."""
class AES:
def __init__(self, key, mode, IV, implementation):
if len(key) not in (16, 24, 32):
raise AssertionError()
if mode != 2:
raise AssertionError()
if len(IV) != 16:
raise AssertionError()
self.isBlockCipher = True
self.block_size = 16
self.implementation = implementation
if len(key)==16:
self.name = "aes128"
elif len(key)==24:
self.name = "aes192"
elif len(key)==32:
self.name = "aes256"
else:
raise AssertionError()
#CBC-Mode encryption, returns ciphertext
#WARNING: *MAY* modify the input as well
def encrypt(self, plaintext):
assert(len(plaintext) % 16 == 0)
#CBC-Mode decryption, returns plaintext
#WARNING: *MAY* modify the input as well
def decrypt(self, ciphertext):
assert(len(ciphertext) % 16 == 0) tlslite-0.3.8/tlslite/utils/PyCrypto_TripleDES.py 0000700 0001750 0001750 00000001142 10025510304 021021 0 ustar clint clint """PyCrypto 3DES implementation."""
from cryptomath import *
from TripleDES import *
if pycryptoLoaded:
import Crypto.Cipher.DES3
def new(key, mode, IV):
return PyCrypto_TripleDES(key, mode, IV)
class PyCrypto_TripleDES(TripleDES):
def __init__(self, key, mode, IV):
TripleDES.__init__(self, key, mode, IV, "pycrypto")
self.context = Crypto.Cipher.DES3.new(key, mode, IV)
def encrypt(self, plaintext):
return self.context.encrypt(plaintext)
def decrypt(self, ciphertext):
return self.context.decrypt(ciphertext) tlslite-0.3.8/tlslite/utils/xmltools.py 0000700 0001750 0001750 00000016276 10130676227 017272 0 ustar clint clint """Helper functions for XML.
This module has misc. helper functions for working with XML DOM nodes."""
import re
from compat import *
import os
if os.name != "java":
from xml.dom import minidom
from xml.sax import saxutils
def parseDocument(s):
return minidom.parseString(s)
else:
from javax.xml.parsers import *
import java
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
def parseDocument(s):
stream = java.io.ByteArrayInputStream(java.lang.String(s).getBytes())
return builder.parse(stream)
def parseAndStripWhitespace(s):
try:
element = parseDocument(s).documentElement
except BaseException, e:
raise SyntaxError(str(e))
stripWhitespace(element)
return element
#Goes through a DOM tree and removes whitespace besides child elements,
#as long as this whitespace is correctly tab-ified
def stripWhitespace(element, tab=0):
element.normalize()
lastSpacer = "\n" + ("\t"*tab)
spacer = lastSpacer + "\t"
#Zero children aren't allowed (i.e. )
#This makes writing output simpler, and matches Canonical XML
if element.childNodes.length==0: #DON'T DO len(element.childNodes) - doesn't work in Jython
raise SyntaxError("Empty XML elements not allowed")
#If there's a single child, it must be text context
if element.childNodes.length==1:
if element.firstChild.nodeType == element.firstChild.TEXT_NODE:
#If it's an empty element, remove
if element.firstChild.data == lastSpacer:
element.removeChild(element.firstChild)
return
#If not text content, give an error
elif element.firstChild.nodeType == element.firstChild.ELEMENT_NODE:
raise SyntaxError("Bad whitespace under '%s'" % element.tagName)
else:
raise SyntaxError("Unexpected node type in XML document")
#Otherwise there's multiple child element
child = element.firstChild
while child:
if child.nodeType == child.ELEMENT_NODE:
stripWhitespace(child, tab+1)
child = child.nextSibling
elif child.nodeType == child.TEXT_NODE:
if child == element.lastChild:
if child.data != lastSpacer:
raise SyntaxError("Bad whitespace under '%s'" % element.tagName)
elif child.data != spacer:
raise SyntaxError("Bad whitespace under '%s'" % element.tagName)
next = child.nextSibling
element.removeChild(child)
child = next
else:
raise SyntaxError("Unexpected node type in XML document")
def checkName(element, name):
if element.nodeType != element.ELEMENT_NODE:
raise SyntaxError("Missing element: '%s'" % name)
if name == None:
return
if element.tagName != name:
raise SyntaxError("Wrong element name: should be '%s', is '%s'" % (name, element.tagName))
def getChild(element, index, name=None):
if element.nodeType != element.ELEMENT_NODE:
raise SyntaxError("Wrong node type in getChild()")
child = element.childNodes.item(index)
if child == None:
raise SyntaxError("Missing child: '%s'" % name)
checkName(child, name)
return child
def getChildIter(element, index):
class ChildIter:
def __init__(self, element, index):
self.element = element
self.index = index
def next(self):
if self.index < len(self.element.childNodes):
retVal = self.element.childNodes.item(self.index)
self.index += 1
else:
retVal = None
return retVal
def checkEnd(self):
if self.index != len(self.element.childNodes):
raise SyntaxError("Too many elements under: '%s'" % self.element.tagName)
return ChildIter(element, index)
def getChildOrNone(element, index):
if element.nodeType != element.ELEMENT_NODE:
raise SyntaxError("Wrong node type in getChild()")
child = element.childNodes.item(index)
return child
def getLastChild(element, index, name=None):
if element.nodeType != element.ELEMENT_NODE:
raise SyntaxError("Wrong node type in getLastChild()")
child = element.childNodes.item(index)
if child == None:
raise SyntaxError("Missing child: '%s'" % name)
if child != element.lastChild:
raise SyntaxError("Too many elements under: '%s'" % element.tagName)
checkName(child, name)
return child
#Regular expressions for syntax-checking attribute and element content
nsRegEx = "http://trevp.net/cryptoID\Z"
cryptoIDRegEx = "([a-km-z3-9]{5}\.){3}[a-km-z3-9]{5}\Z"
urlRegEx = "http(s)?://.{1,100}\Z"
sha1Base64RegEx = "[A-Za-z0-9+/]{27}=\Z"
base64RegEx = "[A-Za-z0-9+/]+={0,4}\Z"
certsListRegEx = "(0)?(1)?(2)?(3)?(4)?(5)?(6)?(7)?(8)?(9)?\Z"
keyRegEx = "[A-Z]\Z"
keysListRegEx = "(A)?(B)?(C)?(D)?(E)?(F)?(G)?(H)?(I)?(J)?(K)?(L)?(M)?(N)?(O)?(P)?(Q)?(R)?(S)?(T)?(U)?(V)?(W)?(X)?(Y)?(Z)?\Z"
dateTimeRegEx = "\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\Z"
shortStringRegEx = ".{1,100}\Z"
exprRegEx = "[a-zA-Z0-9 ,()]{1,200}\Z"
notAfterDeltaRegEx = "0|([1-9][0-9]{0,8})\Z" #A number from 0 to (1 billion)-1
booleanRegEx = "(true)|(false)"
def getReqAttribute(element, attrName, regEx=""):
if element.nodeType != element.ELEMENT_NODE:
raise SyntaxError("Wrong node type in getReqAttribute()")
value = element.getAttribute(attrName)
if not value:
raise SyntaxError("Missing Attribute: " + attrName)
if not re.match(regEx, value):
raise SyntaxError("Bad Attribute Value for '%s': '%s' " % (attrName, value))
element.removeAttribute(attrName)
return str(value) #de-unicode it; this is needed for bsddb, for example
def getAttribute(element, attrName, regEx=""):
if element.nodeType != element.ELEMENT_NODE:
raise SyntaxError("Wrong node type in getAttribute()")
value = element.getAttribute(attrName)
if value:
if not re.match(regEx, value):
raise SyntaxError("Bad Attribute Value for '%s': '%s' " % (attrName, value))
element.removeAttribute(attrName)
return str(value) #de-unicode it; this is needed for bsddb, for example
def checkNoMoreAttributes(element):
if element.nodeType != element.ELEMENT_NODE:
raise SyntaxError("Wrong node type in checkNoMoreAttributes()")
if element.attributes.length!=0:
raise SyntaxError("Extra attributes on '%s'" % element.tagName)
def getText(element, regEx=""):
textNode = element.firstChild
if textNode == None:
raise SyntaxError("Empty element '%s'" % element.tagName)
if textNode.nodeType != textNode.TEXT_NODE:
raise SyntaxError("Non-text node: '%s'" % element.tagName)
if not re.match(regEx, textNode.data):
raise SyntaxError("Bad Text Value for '%s': '%s' " % (element.tagName, textNode.data))
return str(textNode.data) #de-unicode it; this is needed for bsddb, for example
#Function for adding tabs to a string
def indent(s, steps, ch="\t"):
tabs = ch*steps
if s[-1] != "\n":
s = tabs + s.replace("\n", "\n"+tabs)
else:
s = tabs + s.replace("\n", "\n"+tabs)
s = s[ : -len(tabs)]
return s
def escape(s):
return saxutils.escape(s)
tlslite-0.3.8/tlslite/utils/Cryptlib_TripleDES.py 0000700 0001750 0001750 00000002600 10025507703 021031 0 ustar clint clint """Cryptlib 3DES implementation."""
from cryptomath import *
from TripleDES import *
if cryptlibpyLoaded:
def new(key, mode, IV):
return Cryptlib_TripleDES(key, mode, IV)
class Cryptlib_TripleDES(TripleDES):
def __init__(self, key, mode, IV):
TripleDES.__init__(self, key, mode, IV, "cryptlib")
self.context = cryptlib_py.cryptCreateContext(cryptlib_py.CRYPT_UNUSED, cryptlib_py.CRYPT_ALGO_3DES)
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_MODE, cryptlib_py.CRYPT_MODE_CBC)
cryptlib_py.cryptSetAttribute(self.context, cryptlib_py.CRYPT_CTXINFO_KEYSIZE, len(key))
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_KEY, key)
cryptlib_py.cryptSetAttributeString(self.context, cryptlib_py.CRYPT_CTXINFO_IV, IV)
def __del__(self):
cryptlib_py.cryptDestroyContext(self.context)
def encrypt(self, plaintext):
TripleDES.encrypt(self, plaintext)
bytes = stringToBytes(plaintext)
cryptlib_py.cryptEncrypt(self.context, bytes)
return bytesToString(bytes)
def decrypt(self, ciphertext):
TripleDES.decrypt(self, ciphertext)
bytes = stringToBytes(ciphertext)
cryptlib_py.cryptDecrypt(self.context, bytes)
return bytesToString(bytes) tlslite-0.3.8/tlslite/utils/Python_RC4.py 0000700 0001750 0001750 00000001766 10025510402 017321 0 ustar clint clint """Pure-Python RC4 implementation."""
from RC4 import RC4
from cryptomath import *
def new(key):
return Python_RC4(key)
class Python_RC4(RC4):
def __init__(self, key):
RC4.__init__(self, key, "python")
keyBytes = stringToBytes(key)
S = [i for i in range(256)]
j = 0
for i in range(256):
j = (j + S[i] + keyBytes[i % len(keyBytes)]) % 256
S[i], S[j] = S[j], S[i]
self.S = S
self.i = 0
self.j = 0
def encrypt(self, plaintext):
plaintextBytes = stringToBytes(plaintext)
S = self.S
i = self.i
j = self.j
for x in range(len(plaintextBytes)):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
t = (S[i] + S[j]) % 256
plaintextBytes[x] ^= S[t]
self.i = i
self.j = j
return bytesToString(plaintextBytes)
def decrypt(self, ciphertext):
return self.encrypt(ciphertext)
tlslite-0.3.8/tlslite/utils/ASN1Parser.py 0000700 0001750 0001750 00000001700 10130676160 017246 0 ustar clint clint """Class for parsing ASN.1"""
from compat import *
from codec import *
#Takes a byte array which has a DER TLV field at its head
class ASN1Parser:
def __init__(self, bytes):
p = Parser(bytes)
p.get(1) #skip Type
#Get Length
self.length = self._getASN1Length(p)
#Get Value
self.value = p.getFixBytes(self.length)
#Assuming this is a sequence...
def getChild(self, which):
p = Parser(self.value)
for x in range(which+1):
markIndex = p.index
p.get(1) #skip Type
length = self._getASN1Length(p)
p.getFixBytes(length)
return ASN1Parser(p.bytes[markIndex : p.index])
#Decode the ASN.1 DER length field
def _getASN1Length(self, p):
firstLength = p.get(1)
if firstLength<=127:
return firstLength
else:
lengthLength = firstLength & 0x7F
return p.get(lengthLength)
tlslite-0.3.8/tlslite/utils/Python_AES.py 0000700 0001750 0001750 00000004111 10025510371 017331 0 ustar clint clint """Pure-Python AES implementation."""
from cryptomath import *
from AES import *
from rijndael import rijndael
def new(key, mode, IV):
return Python_AES(key, mode, IV)
class Python_AES(AES):
def __init__(self, key, mode, IV):
AES.__init__(self, key, mode, IV, "python")
self.rijndael = rijndael(key, 16)
self.IV = IV
def encrypt(self, plaintext):
AES.encrypt(self, plaintext)
plaintextBytes = stringToBytes(plaintext)
chainBytes = stringToBytes(self.IV)
#CBC Mode: For each block...
for x in range(len(plaintextBytes)/16):
#XOR with the chaining block
blockBytes = plaintextBytes[x*16 : (x*16)+16]
for y in range(16):
blockBytes[y] ^= chainBytes[y]
blockString = bytesToString(blockBytes)
#Encrypt it
encryptedBytes = stringToBytes(self.rijndael.encrypt(blockString))
#Overwrite the input with the output
for y in range(16):
plaintextBytes[(x*16)+y] = encryptedBytes[y]
#Set the next chaining block
chainBytes = encryptedBytes
self.IV = bytesToString(chainBytes)
return bytesToString(plaintextBytes)
def decrypt(self, ciphertext):
AES.decrypt(self, ciphertext)
ciphertextBytes = stringToBytes(ciphertext)
chainBytes = stringToBytes(self.IV)
#CBC Mode: For each block...
for x in range(len(ciphertextBytes)/16):
#Decrypt it
blockBytes = ciphertextBytes[x*16 : (x*16)+16]
blockString = bytesToString(blockBytes)
decryptedBytes = stringToBytes(self.rijndael.decrypt(blockString))
#XOR with the chaining block and overwrite the input with output
for y in range(16):
decryptedBytes[y] ^= chainBytes[y]
ciphertextBytes[(x*16)+y] = decryptedBytes[y]
#Set the next chaining block
chainBytes = blockBytes
self.IV = bytesToString(chainBytes)
return bytesToString(ciphertextBytes)
tlslite-0.3.8/tlslite/utils/OpenSSL_RC4.py 0000700 0001750 0001750 00000001113 10025510111 017302 0 ustar clint clint """OpenSSL/M2Crypto RC4 implementation."""
from cryptomath import *
from RC4 import RC4
if m2cryptoLoaded:
def new(key):
return OpenSSL_RC4(key)
class OpenSSL_RC4(RC4):
def __init__(self, key):
RC4.__init__(self, key, "openssl")
self.rc4 = m2.rc4_new()
m2.rc4_set_key(self.rc4, key)
def __del__(self):
m2.rc4_free(self.rc4)
def encrypt(self, plaintext):
return m2.rc4_update(self.rc4, plaintext)
def decrypt(self, ciphertext):
return self.encrypt(ciphertext)
tlslite-0.3.8/tlslite/utils/codec.py 0000700 0001750 0001750 00000005323 10130676166 016457 0 ustar clint clint """Classes for reading/writing binary data (such as TLS records)."""
from compat import *
class Writer:
def __init__(self, length=0):
#If length is zero, then this is just a "trial run" to determine length
self.index = 0
self.bytes = createByteArrayZeros(length)
def add(self, x, length):
if self.bytes:
newIndex = self.index+length-1
while newIndex >= self.index:
self.bytes[newIndex] = x & 0xFF
x >>= 8
newIndex -= 1
self.index += length
def addFixSeq(self, seq, length):
if self.bytes:
for e in seq:
self.add(e, length)
else:
self.index += len(seq)*length
def addVarSeq(self, seq, length, lengthLength):
if self.bytes:
self.add(len(seq)*length, lengthLength)
for e in seq:
self.add(e, length)
else:
self.index += lengthLength + (len(seq)*length)
class Parser:
def __init__(self, bytes):
self.bytes = bytes
self.index = 0
def get(self, length):
if self.index + length > len(self.bytes):
raise SyntaxError()
x = 0
for count in range(length):
x <<= 8
x |= self.bytes[self.index]
self.index += 1
return x
def getFixBytes(self, lengthBytes):
bytes = self.bytes[self.index : self.index+lengthBytes]
self.index += lengthBytes
return bytes
def getVarBytes(self, lengthLength):
lengthBytes = self.get(lengthLength)
return self.getFixBytes(lengthBytes)
def getFixList(self, length, lengthList):
l = [0] * lengthList
for x in range(lengthList):
l[x] = self.get(length)
return l
def getVarList(self, length, lengthLength):
lengthList = self.get(lengthLength)
if lengthList % length != 0:
raise SyntaxError()
lengthList = int(lengthList/length)
l = [0] * lengthList
for x in range(lengthList):
l[x] = self.get(length)
return l
def startLengthCheck(self, lengthLength):
self.lengthCheck = self.get(lengthLength)
self.indexCheck = self.index
def setLengthCheck(self, length):
self.lengthCheck = length
self.indexCheck = self.index
def stopLengthCheck(self):
if (self.index - self.indexCheck) != self.lengthCheck:
raise SyntaxError()
def atLengthCheck(self):
if (self.index - self.indexCheck) < self.lengthCheck:
return False
elif (self.index - self.indexCheck) == self.lengthCheck:
return True
else:
raise SyntaxError() tlslite-0.3.8/tlslite/TLSConnection.py 0000700 0001750 0001750 00000211313 10130704331 016704 0 ustar clint clint """
MAIN CLASS FOR TLS LITE (START HERE!).
"""
from __future__ import generators
import socket
from utils.compat import formatExceptionTrace
from TLSRecordLayer import TLSRecordLayer
from Session import Session
from constants import *
from utils.cryptomath import getRandomBytes
from errors import *
from messages import *
from mathtls import *
from HandshakeSettings import HandshakeSettings
class TLSConnection(TLSRecordLayer):
"""
This class wraps a socket and provides TLS handshaking and data
transfer.
To use this class, create a new instance, passing a connected
socket into the constructor. Then call some handshake function.
If the handshake completes without raising an exception, then a TLS
connection has been negotiated. You can transfer data over this
connection as if it were a socket.
This class provides both synchronous and asynchronous versions of
its key functions. The synchronous versions should be used when
writing single-or multi-threaded code using blocking sockets. The
asynchronous versions should be used when performing asynchronous,
event-based I/O with non-blocking sockets.
Asynchronous I/O is a complicated subject; typically, you should
not use the asynchronous functions directly, but should use some
framework like asyncore or Twisted which TLS Lite integrates with
(see
L{tlslite.integration.TLSAsyncDispatcherMixIn.TLSAsyncDispatcherMixIn} or
L{tlslite.integration.TLSTwistedProtocolWrapper.TLSTwistedProtocolWrapper}).
"""
def __init__(self, sock):
"""Create a new TLSConnection instance.
@param sock: The socket data will be transmitted on. The
socket should already be connected. It may be in blocking or
non-blocking mode.
@type sock: L{socket.socket}
"""
TLSRecordLayer.__init__(self, sock)
def handshakeClientSRP(self, username, password, session=None,
settings=None, checker=None, async=False):
"""Perform an SRP handshake in the role of client.
This function performs a TLS/SRP handshake. SRP mutually
authenticates both parties to each other using only a
username and password. This function may also perform a
combined SRP and server-certificate handshake, if the server
chooses to authenticate itself with a certificate chain in
addition to doing SRP.
TLS/SRP is non-standard. Most TLS implementations don't
support it. See
U{http://www.ietf.org/html.charters/tls-charter.html} or
U{http://trevp.net/tlssrp/} for the latest information on
TLS/SRP.
Like any handshake function, this can be called on a closed
TLS connection, or on a TLS connection that is already open.
If called on an open connection it performs a re-handshake.
If the function completes without raising an exception, the
TLS connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
@type username: str
@param username: The SRP username.
@type password: str
@param password: The SRP password.
@type session: L{tlslite.Session.Session}
@param session: A TLS session to attempt to resume. This
session must be an SRP session performed with the same username
and password as were passed in. If the resumption does not
succeed, a full SRP handshake will be performed.
@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.
@type checker: L{tlslite.Checker.Checker}
@param checker: A Checker instance. This instance will be
invoked to examine the other party's authentication
credentials, if the handshake completes succesfully.
@type async: bool
@param async: If False, this function will block until the
handshake is completed. If True, this function will return a
generator. Successive invocations of the generator will
return 0 if it is waiting to read from the socket, 1 if it is
waiting to write to the socket, or will raise StopIteration if
the handshake operation is completed.
@rtype: None or an iterable
@return: If 'async' is True, a generator object will be
returned.
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
@raise tlslite.errors.TLSAuthenticationError: If the checker
doesn't like the other party's authentication credentials.
"""
handshaker = self._handshakeClientAsync(srpParams=(username, password),
session=session, settings=settings, checker=checker)
if async:
return handshaker
for result in handshaker:
pass
def handshakeClientCert(self, certChain=None, privateKey=None,
session=None, settings=None, checker=None,
async=False):
"""Perform a certificate-based handshake in the role of client.
This function performs an SSL or TLS handshake. The server
will authenticate itself using an X.509 or cryptoID certificate
chain. If the handshake succeeds, the server's certificate
chain will be stored in the session's serverCertChain attribute.
Unless a checker object is passed in, this function does no
validation or checking of the server's certificate chain.
If the server requests client authentication, the
client will send the passed-in certificate chain, and use the
passed-in private key to authenticate itself. If no
certificate chain and private key were passed in, the client
will attempt to proceed without client authentication. The
server may or may not allow this.
Like any handshake function, this can be called on a closed
TLS connection, or on a TLS connection that is already open.
If called on an open connection it performs a re-handshake.
If the function completes without raising an exception, the
TLS connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
@type certChain: L{tlslite.X509CertChain.X509CertChain} or
L{cryptoIDlib.CertChain.CertChain}
@param certChain: The certificate chain to be used if the
server requests client authentication.
@type privateKey: L{tlslite.utils.RSAKey.RSAKey}
@param privateKey: The private key to be used if the server
requests client authentication.
@type session: L{tlslite.Session.Session}
@param session: A TLS session to attempt to resume. If the
resumption does not succeed, a full handshake will be
performed.
@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.
@type checker: L{tlslite.Checker.Checker}
@param checker: A Checker instance. This instance will be
invoked to examine the other party's authentication
credentials, if the handshake completes succesfully.
@type async: bool
@param async: If False, this function will block until the
handshake is completed. If True, this function will return a
generator. Successive invocations of the generator will
return 0 if it is waiting to read from the socket, 1 if it is
waiting to write to the socket, or will raise StopIteration if
the handshake operation is completed.
@rtype: None or an iterable
@return: If 'async' is True, a generator object will be
returned.
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
@raise tlslite.errors.TLSAuthenticationError: If the checker
doesn't like the other party's authentication credentials.
"""
handshaker = self._handshakeClientAsync(certParams=(certChain,
privateKey), session=session, settings=settings,
checker=checker)
if async:
return handshaker
for result in handshaker:
pass
def handshakeClientUnknown(self, srpCallback=None, certCallback=None,
session=None, settings=None, checker=None,
async=False):
"""Perform a to-be-determined type of handshake in the role of client.
This function performs an SSL or TLS handshake. If the server
requests client certificate authentication, the
certCallback will be invoked and should return a (certChain,
privateKey) pair. If the callback returns None, the library
will attempt to proceed without client authentication. The
server may or may not allow this.
If the server requests SRP authentication, the srpCallback
will be invoked and should return a (username, password) pair.
If the callback returns None, the local implementation will
signal a user_canceled error alert.
After the handshake completes, the client can inspect the
connection's session attribute to determine what type of
authentication was performed.
Like any handshake function, this can be called on a closed
TLS connection, or on a TLS connection that is already open.
If called on an open connection it performs a re-handshake.
If the function completes without raising an exception, the
TLS connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
@type srpCallback: callable
@param srpCallback: The callback to be used if the server
requests SRP authentication. If None, the client will not
offer support for SRP ciphersuites.
@type certCallback: callable
@param certCallback: The callback to be used if the server
requests client certificate authentication.
@type session: L{tlslite.Session.Session}
@param session: A TLS session to attempt to resume. If the
resumption does not succeed, a full handshake will be
performed.
@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.
@type checker: L{tlslite.Checker.Checker}
@param checker: A Checker instance. This instance will be
invoked to examine the other party's authentication
credentials, if the handshake completes succesfully.
@type async: bool
@param async: If False, this function will block until the
handshake is completed. If True, this function will return a
generator. Successive invocations of the generator will
return 0 if it is waiting to read from the socket, 1 if it is
waiting to write to the socket, or will raise StopIteration if
the handshake operation is completed.
@rtype: None or an iterable
@return: If 'async' is True, a generator object will be
returned.
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
@raise tlslite.errors.TLSAuthenticationError: If the checker
doesn't like the other party's authentication credentials.
"""
handshaker = self._handshakeClientAsync(unknownParams=(srpCallback,
certCallback), session=session, settings=settings,
checker=checker)
if async:
return handshaker
for result in handshaker:
pass
def handshakeClientSharedKey(self, username, sharedKey, settings=None,
checker=None, async=False):
"""Perform a shared-key handshake in the role of client.
This function performs a shared-key handshake. Using shared
symmetric keys of high entropy (128 bits or greater) mutually
authenticates both parties to each other.
TLS with shared-keys is non-standard. Most TLS
implementations don't support it. See
U{http://www.ietf.org/html.charters/tls-charter.html} for the
latest information on TLS with shared-keys. If the shared-keys
Internet-Draft changes or is superceded, TLS Lite will track
those changes, so the shared-key support in later versions of
TLS Lite may become incompatible with this version.
Like any handshake function, this can be called on a closed
TLS connection, or on a TLS connection that is already open.
If called on an open connection it performs a re-handshake.
If the function completes without raising an exception, the
TLS connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
@type username: str
@param username: The shared-key username.
@type sharedKey: str
@param sharedKey: The shared key.
@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.
@type checker: L{tlslite.Checker.Checker}
@param checker: A Checker instance. This instance will be
invoked to examine the other party's authentication
credentials, if the handshake completes succesfully.
@type async: bool
@param async: If False, this function will block until the
handshake is completed. If True, this function will return a
generator. Successive invocations of the generator will
return 0 if it is waiting to read from the socket, 1 if it is
waiting to write to the socket, or will raise StopIteration if
the handshake operation is completed.
@rtype: None or an iterable
@return: If 'async' is True, a generator object will be
returned.
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
@raise tlslite.errors.TLSAuthenticationError: If the checker
doesn't like the other party's authentication credentials.
"""
handshaker = self._handshakeClientAsync(sharedKeyParams=(username,
sharedKey), settings=settings, checker=checker)
if async:
return handshaker
for result in handshaker:
pass
def _handshakeClientAsync(self, srpParams=(), certParams=(),
unknownParams=(), sharedKeyParams=(),
session=None, settings=None, checker=None,
recursive=False):
handshaker = self._handshakeClientAsyncHelper(srpParams=srpParams,
certParams=certParams, unknownParams=unknownParams,
sharedKeyParams=sharedKeyParams, session=session,
settings=settings, recursive=recursive)
for result in self._handshakeWrapperAsync(handshaker, checker):
yield result
def _handshakeClientAsyncHelper(self, srpParams, certParams, unknownParams,
sharedKeyParams, session, settings, recursive):
if not recursive:
self._handshakeStart(client=True)
#Unpack parameters
srpUsername = None # srpParams
password = None # srpParams
clientCertChain = None # certParams
privateKey = None # certParams
srpCallback = None # unknownParams
certCallback = None # unknownParams
#session # sharedKeyParams (or session)
#settings # settings
if srpParams:
srpUsername, password = srpParams
elif certParams:
clientCertChain, privateKey = certParams
elif unknownParams:
srpCallback, certCallback = unknownParams
elif sharedKeyParams:
session = Session()._createSharedKey(*sharedKeyParams)
if not settings:
settings = HandshakeSettings()
settings = settings._filter()
#Validate parameters
if srpUsername and not password:
raise ValueError("Caller passed a username but no password")
if password and not srpUsername:
raise ValueError("Caller passed a password but no username")
if clientCertChain and not privateKey:
raise ValueError("Caller passed a certChain but no privateKey")
if privateKey and not clientCertChain:
raise ValueError("Caller passed a privateKey but no certChain")
if clientCertChain:
foundType = False
try:
import cryptoIDlib.CertChain
if isinstance(clientCertChain, cryptoIDlib.CertChain.CertChain):
if "cryptoID" not in settings.certificateTypes:
raise ValueError("Client certificate doesn't "\
"match Handshake Settings")
settings.certificateTypes = ["cryptoID"]
foundType = True
except ImportError:
pass
if not foundType and isinstance(clientCertChain,
X509CertChain):
if "x509" not in settings.certificateTypes:
raise ValueError("Client certificate doesn't match "\
"Handshake Settings")
settings.certificateTypes = ["x509"]
foundType = True
if not foundType:
raise ValueError("Unrecognized certificate type")
if session:
if not session.valid():
session = None #ignore non-resumable sessions...
elif session.resumable and \
(session.srpUsername != srpUsername):
raise ValueError("Session username doesn't match")
#Add Faults to parameters
if srpUsername and self.fault == Fault.badUsername:
srpUsername += "GARBAGE"
if password and self.fault == Fault.badPassword:
password += "GARBAGE"
if sharedKeyParams:
identifier = sharedKeyParams[0]
sharedKey = sharedKeyParams[1]
if self.fault == Fault.badIdentifier:
identifier += "GARBAGE"
session = Session()._createSharedKey(identifier, sharedKey)
elif self.fault == Fault.badSharedKey:
sharedKey += "GARBAGE"
session = Session()._createSharedKey(identifier, sharedKey)
#Initialize locals
serverCertChain = None
cipherSuite = 0
certificateType = CertificateType.x509
premasterSecret = None
#Get client nonce
clientRandom = getRandomBytes(32)
#Initialize acceptable ciphersuites
cipherSuites = []
if srpParams:
cipherSuites += CipherSuite.getSrpRsaSuites(settings.cipherNames)
cipherSuites += CipherSuite.getSrpSuites(settings.cipherNames)
elif certParams:
cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames)
elif unknownParams:
if srpCallback:
cipherSuites += \
CipherSuite.getSrpRsaSuites(settings.cipherNames)
cipherSuites += \
CipherSuite.getSrpSuites(settings.cipherNames)
cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames)
elif sharedKeyParams:
cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames)
else:
cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames)
#Initialize acceptable certificate types
certificateTypes = settings._getCertificateTypes()
#Tentatively set the version to the client's minimum version.
#We'll use this for the ClientHello, and if an error occurs
#parsing the Server Hello, we'll use this version for the response
self.version = settings.maxVersion
#Either send ClientHello (with a resumable session)...
if session:
#If it's a resumable (i.e. not a shared-key session), then its
#ciphersuite must be one of the acceptable ciphersuites
if (not sharedKeyParams) and \
session.cipherSuite not in cipherSuites:
raise ValueError("Session's cipher suite not consistent "\
"with parameters")
else:
clientHello = ClientHello()
clientHello.create(settings.maxVersion, clientRandom,
session.sessionID, cipherSuites,
certificateTypes, session.srpUsername)
#Or send ClientHello (without)
else:
clientHello = ClientHello()
clientHello.create(settings.maxVersion, clientRandom,
createByteArraySequence([]), cipherSuites,
certificateTypes, srpUsername)
for result in self._sendMsg(clientHello):
yield result
#Get ServerHello (or missing_srp_username)
for result in self._getMsg((ContentType.handshake,
ContentType.alert),
HandshakeType.server_hello):
if result in (0,1):
yield result
else:
break
msg = result
if isinstance(msg, ServerHello):
serverHello = msg
elif isinstance(msg, Alert):
alert = msg
#If it's not a missing_srp_username, re-raise
if alert.description != AlertDescription.missing_srp_username:
self._shutdown(False)
raise TLSRemoteAlert(alert)
#If we're not in SRP callback mode, we won't have offered SRP
#without a username, so we shouldn't get this alert
if not srpCallback:
for result in self._sendError(\
AlertDescription.unexpected_message):
yield result
srpParams = srpCallback()
#If the callback returns None, cancel the handshake
if srpParams == None:
for result in self._sendError(AlertDescription.user_canceled):
yield result
#Recursively perform handshake
for result in self._handshakeClientAsyncHelper(srpParams,
None, None, None, None, settings, True):
yield result
return
#Get the server version. Do this before anything else, so any
#error alerts will use the server's version
self.version = serverHello.server_version
#Future responses from server must use this version
self._versionCheck = True
#Check ServerHello
if serverHello.server_version < settings.minVersion:
for result in self._sendError(\
AlertDescription.protocol_version,
"Too old version: %s" % str(serverHello.server_version)):
yield result
if serverHello.server_version > settings.maxVersion:
for result in self._sendError(\
AlertDescription.protocol_version,
"Too new version: %s" % str(serverHello.server_version)):
yield result
if serverHello.cipher_suite not in cipherSuites:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Server responded with incorrect ciphersuite"):
yield result
if serverHello.certificate_type not in certificateTypes:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Server responded with incorrect certificate type"):
yield result
if serverHello.compression_method != 0:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Server responded with incorrect compression method"):
yield result
#Get the server nonce
serverRandom = serverHello.random
#If the server agrees to resume
if session and session.sessionID and \
serverHello.session_id == session.sessionID:
#If a shared-key, we're flexible about suites; otherwise the
#server-chosen suite has to match the session's suite
if sharedKeyParams:
session.cipherSuite = serverHello.cipher_suite
elif serverHello.cipher_suite != session.cipherSuite:
for result in self._sendError(\
AlertDescription.illegal_parameter,\
"Server's ciphersuite doesn't match session"):
yield result
#Set the session for this connection
self.session = session
#Calculate pending connection states
self._calcPendingStates(clientRandom, serverRandom,
settings.cipherImplementations)
#Exchange ChangeCipherSpec and Finished messages
for result in self._getFinished():
yield result
for result in self._sendFinished():
yield result
#Mark the connection as open
self._handshakeDone(resumed=True)
#If server DOES NOT agree to resume
else:
if sharedKeyParams:
for result in self._sendError(\
AlertDescription.user_canceled,
"Was expecting a shared-key resumption"):
yield result
#We've already validated these
cipherSuite = serverHello.cipher_suite
certificateType = serverHello.certificate_type
#If the server chose an SRP suite...
if cipherSuite in CipherSuite.srpSuites:
#Get ServerKeyExchange, ServerHelloDone
for result in self._getMsg(ContentType.handshake,
HandshakeType.server_key_exchange, cipherSuite):
if result in (0,1):
yield result
else:
break
serverKeyExchange = result
for result in self._getMsg(ContentType.handshake,
HandshakeType.server_hello_done):
if result in (0,1):
yield result
else:
break
serverHelloDone = result
#If the server chose an SRP+RSA suite...
elif cipherSuite in CipherSuite.srpRsaSuites:
#Get Certificate, ServerKeyExchange, ServerHelloDone
for result in self._getMsg(ContentType.handshake,
HandshakeType.certificate, certificateType):
if result in (0,1):
yield result
else:
break
serverCertificate = result
for result in self._getMsg(ContentType.handshake,
HandshakeType.server_key_exchange, cipherSuite):
if result in (0,1):
yield result
else:
break
serverKeyExchange = result
for result in self._getMsg(ContentType.handshake,
HandshakeType.server_hello_done):
if result in (0,1):
yield result
else:
break
serverHelloDone = result
#If the server chose an RSA suite...
elif cipherSuite in CipherSuite.rsaSuites:
#Get Certificate[, CertificateRequest], ServerHelloDone
for result in self._getMsg(ContentType.handshake,
HandshakeType.certificate, certificateType):
if result in (0,1):
yield result
else:
break
serverCertificate = result
for result in self._getMsg(ContentType.handshake,
(HandshakeType.server_hello_done,
HandshakeType.certificate_request)):
if result in (0,1):
yield result
else:
break
msg = result
certificateRequest = None
if isinstance(msg, CertificateRequest):
certificateRequest = msg
for result in self._getMsg(ContentType.handshake,
HandshakeType.server_hello_done):
if result in (0,1):
yield result
else:
break
serverHelloDone = result
elif isinstance(msg, ServerHelloDone):
serverHelloDone = msg
else:
raise AssertionError()
#Calculate SRP premaster secret, if server chose an SRP or
#SRP+RSA suite
if cipherSuite in CipherSuite.srpSuites + \
CipherSuite.srpRsaSuites:
#Get and check the server's group parameters and B value
N = serverKeyExchange.srp_N
g = serverKeyExchange.srp_g
s = serverKeyExchange.srp_s
B = serverKeyExchange.srp_B
if (g,N) not in goodGroupParameters:
for result in self._sendError(\
AlertDescription.untrusted_srp_parameters,
"Unknown group parameters"):
yield result
if numBits(N) < settings.minKeySize:
for result in self._sendError(\
AlertDescription.untrusted_srp_parameters,
"N value is too small: %d" % numBits(N)):
yield result
if numBits(N) > settings.maxKeySize:
for result in self._sendError(\
AlertDescription.untrusted_srp_parameters,
"N value is too large: %d" % numBits(N)):
yield result
if B % N == 0:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Suspicious B value"):
yield result
#Check the server's signature, if server chose an
#SRP+RSA suite
if cipherSuite in CipherSuite.srpRsaSuites:
#Hash ServerKeyExchange/ServerSRPParams
hashBytes = serverKeyExchange.hash(clientRandom,
serverRandom)
#Extract signature bytes from ServerKeyExchange
sigBytes = serverKeyExchange.signature
if len(sigBytes) == 0:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Server sent an SRP ServerKeyExchange "\
"message without a signature"):
yield result
#Get server's public key from the Certificate message
for result in self._getKeyFromChain(serverCertificate,
settings):
if result in (0,1):
yield result
else:
break
publicKey, serverCertChain = result
#Verify signature
if not publicKey.verify(sigBytes, hashBytes):
for result in self._sendError(\
AlertDescription.decrypt_error,
"Signature failed to verify"):
yield result
#Calculate client's ephemeral DH values (a, A)
a = bytesToNumber(getRandomBytes(32))
A = powMod(g, a, N)
#Calculate client's static DH values (x, v)
x = makeX(bytesToString(s), srpUsername, password)
v = powMod(g, x, N)
#Calculate u
u = makeU(N, A, B)
#Calculate premaster secret
k = makeK(N, g)
S = powMod((B - (k*v)) % N, a+(u*x), N)
if self.fault == Fault.badA:
A = N
S = 0
premasterSecret = numberToBytes(S)
#Send ClientKeyExchange
for result in self._sendMsg(\
ClientKeyExchange(cipherSuite).createSRP(A)):
yield result
#Calculate RSA premaster secret, if server chose an RSA suite
elif cipherSuite in CipherSuite.rsaSuites:
#Handle the presence of a CertificateRequest
if certificateRequest:
if unknownParams and certCallback:
certParamsNew = certCallback()
if certParamsNew:
clientCertChain, privateKey = certParamsNew
#Get server's public key from the Certificate message
for result in self._getKeyFromChain(serverCertificate,
settings):
if result in (0,1):
yield result
else:
break
publicKey, serverCertChain = result
#Calculate premaster secret
premasterSecret = getRandomBytes(48)
premasterSecret[0] = settings.maxVersion[0]
premasterSecret[1] = settings.maxVersion[1]
if self.fault == Fault.badPremasterPadding:
premasterSecret[0] = 5
if self.fault == Fault.shortPremasterSecret:
premasterSecret = premasterSecret[:-1]
#Encrypt premaster secret to server's public key
encryptedPreMasterSecret = publicKey.encrypt(premasterSecret)
#If client authentication was requested, send Certificate
#message, either with certificates or empty
if certificateRequest:
clientCertificate = Certificate(certificateType)
if clientCertChain:
#Check to make sure we have the same type of
#certificates the server requested
wrongType = False
if certificateType == CertificateType.x509:
if not isinstance(clientCertChain, X509CertChain):
wrongType = True
elif certificateType == CertificateType.cryptoID:
if not isinstance(clientCertChain,
cryptoIDlib.CertChain.CertChain):
wrongType = True
if wrongType:
for result in self._sendError(\
AlertDescription.handshake_failure,
"Client certificate is of wrong type"):
yield result
clientCertificate.create(clientCertChain)
for result in self._sendMsg(clientCertificate):
yield result
else:
#The server didn't request client auth, so we
#zeroize these so the clientCertChain won't be
#stored in the session.
privateKey = None
clientCertChain = None
#Send ClientKeyExchange
clientKeyExchange = ClientKeyExchange(cipherSuite,
self.version)
clientKeyExchange.createRSA(encryptedPreMasterSecret)
for result in self._sendMsg(clientKeyExchange):
yield result
#If client authentication was requested and we have a
#private key, send CertificateVerify
if certificateRequest and privateKey:
if self.version == (3,0):
#Create a temporary session object, just for the
#purpose of creating the CertificateVerify
session = Session()
session._calcMasterSecret(self.version,
premasterSecret,
clientRandom,
serverRandom)
verifyBytes = self._calcSSLHandshakeHash(\
session.masterSecret, "")
elif self.version in ((3,1), (3,2)):
verifyBytes = stringToBytes(\
self._handshake_md5.digest() + \
self._handshake_sha.digest())
if self.fault == Fault.badVerifyMessage:
verifyBytes[0] = ((verifyBytes[0]+1) % 256)
signedBytes = privateKey.sign(verifyBytes)
certificateVerify = CertificateVerify()
certificateVerify.create(signedBytes)
for result in self._sendMsg(certificateVerify):
yield result
#Create the session object
self.session = Session()
self.session._calcMasterSecret(self.version, premasterSecret,
clientRandom, serverRandom)
self.session.sessionID = serverHello.session_id
self.session.cipherSuite = cipherSuite
self.session.srpUsername = srpUsername
self.session.clientCertChain = clientCertChain
self.session.serverCertChain = serverCertChain
#Calculate pending connection states
self._calcPendingStates(clientRandom, serverRandom,
settings.cipherImplementations)
#Exchange ChangeCipherSpec and Finished messages
for result in self._sendFinished():
yield result
for result in self._getFinished():
yield result
#Mark the connection as open
self.session._setResumable(True)
self._handshakeDone(resumed=False)
def handshakeServer(self, sharedKeyDB=None, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None):
"""Perform a handshake in the role of server.
This function performs an SSL or TLS handshake. Depending on
the arguments and the behavior of the client, this function can
perform a shared-key, SRP, or certificate-based handshake. It
can also perform a combined SRP and server-certificate
handshake.
Like any handshake function, this can be called on a closed
TLS connection, or on a TLS connection that is already open.
If called on an open connection it performs a re-handshake.
This function does not send a Hello Request message before
performing the handshake, so if re-handshaking is required,
the server must signal the client to begin the re-handshake
through some other means.
If the function completes without raising an exception, the
TLS connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
@type sharedKeyDB: L{tlslite.SharedKeyDB.SharedKeyDB}
@param sharedKeyDB: A database of shared symmetric keys
associated with usernames. If the client performs a
shared-key handshake, the session's sharedKeyUsername
attribute will be set.
@type verifierDB: L{tlslite.VerifierDB.VerifierDB}
@param verifierDB: A database of SRP password verifiers
associated with usernames. If the client performs an SRP
handshake, the session's srpUsername attribute will be set.
@type certChain: L{tlslite.X509CertChain.X509CertChain} or
L{cryptoIDlib.CertChain.CertChain}
@param certChain: The certificate chain to be used if the
client requests server certificate authentication.
@type privateKey: L{tlslite.utils.RSAKey.RSAKey}
@param privateKey: The private key to be used if the client
requests server certificate authentication.
@type reqCert: bool
@param reqCert: Whether to request client certificate
authentication. This only applies if the client chooses server
certificate authentication; if the client chooses SRP or
shared-key authentication, this will be ignored. If the client
performs a client certificate authentication, the sessions's
clientCertChain attribute will be set.
@type sessionCache: L{tlslite.SessionCache.SessionCache}
@param sessionCache: An in-memory cache of resumable sessions.
The client can resume sessions from this cache. Alternatively,
if the client performs a full handshake, a new session will be
added to the cache.
@type settings: L{tlslite.HandshakeSettings.HandshakeSettings}
@param settings: Various settings which can be used to control
the ciphersuites and SSL/TLS version chosen by the server.
@type checker: L{tlslite.Checker.Checker}
@param checker: A Checker instance. This instance will be
invoked to examine the other party's authentication
credentials, if the handshake completes succesfully.
@raise socket.error: If a socket error occurs.
@raise tlslite.errors.TLSAbruptCloseError: If the socket is closed
without a preceding alert.
@raise tlslite.errors.TLSAlert: If a TLS alert is signalled.
@raise tlslite.errors.TLSAuthenticationError: If the checker
doesn't like the other party's authentication credentials.
"""
for result in self.handshakeServerAsync(sharedKeyDB, verifierDB,
certChain, privateKey, reqCert, sessionCache, settings,
checker):
pass
def handshakeServerAsync(self, sharedKeyDB=None, verifierDB=None,
certChain=None, privateKey=None, reqCert=False,
sessionCache=None, settings=None, checker=None):
"""Start a server handshake operation on the TLS connection.
This function returns a generator which behaves similarly to
handshakeServer(). Successive invocations of the generator
will return 0 if it is waiting to read from the socket, 1 if it is
waiting to write to the socket, or it will raise StopIteration
if the handshake operation is complete.
@rtype: iterable
@return: A generator; see above for details.
"""
handshaker = self._handshakeServerAsyncHelper(\
sharedKeyDB=sharedKeyDB,
verifierDB=verifierDB, certChain=certChain,
privateKey=privateKey, reqCert=reqCert,
sessionCache=sessionCache, settings=settings)
for result in self._handshakeWrapperAsync(handshaker, checker):
yield result
def _handshakeServerAsyncHelper(self, sharedKeyDB, verifierDB,
certChain, privateKey, reqCert, sessionCache,
settings):
self._handshakeStart(client=False)
if (not sharedKeyDB) and (not verifierDB) and (not certChain):
raise ValueError("Caller passed no authentication credentials")
if certChain and not privateKey:
raise ValueError("Caller passed a certChain but no privateKey")
if privateKey and not certChain:
raise ValueError("Caller passed a privateKey but no certChain")
if not settings:
settings = HandshakeSettings()
settings = settings._filter()
#Initialize acceptable cipher suites
cipherSuites = []
if verifierDB:
if certChain:
cipherSuites += \
CipherSuite.getSrpRsaSuites(settings.cipherNames)
cipherSuites += CipherSuite.getSrpSuites(settings.cipherNames)
if sharedKeyDB or certChain:
cipherSuites += CipherSuite.getRsaSuites(settings.cipherNames)
#Initialize acceptable certificate type
certificateType = None
if certChain:
try:
import cryptoIDlib.CertChain
if isinstance(certChain, cryptoIDlib.CertChain.CertChain):
certificateType = CertificateType.cryptoID
except ImportError:
pass
if isinstance(certChain, X509CertChain):
certificateType = CertificateType.x509
if certificateType == None:
raise ValueError("Unrecognized certificate type")
#Initialize locals
clientCertChain = None
serverCertChain = None #We may set certChain to this later
postFinishedError = None
#Tentatively set version to most-desirable version, so if an error
#occurs parsing the ClientHello, this is what we'll use for the
#error alert
self.version = settings.maxVersion
#Get ClientHello
for result in self._getMsg(ContentType.handshake,
HandshakeType.client_hello):
if result in (0,1):
yield result
else:
break
clientHello = result
#If client's version is too low, reject it
if clientHello.client_version < settings.minVersion:
self.version = settings.minVersion
for result in self._sendError(\
AlertDescription.protocol_version,
"Too old version: %s" % str(clientHello.client_version)):
yield result
#If client's version is too high, propose my highest version
elif clientHello.client_version > settings.maxVersion:
self.version = settings.maxVersion
else:
#Set the version to the client's version
self.version = clientHello.client_version
#Get the client nonce; create server nonce
clientRandom = clientHello.random
serverRandom = getRandomBytes(32)
#Calculate the first cipher suite intersection.
#This is the 'privileged' ciphersuite. We'll use it if we're
#doing a shared-key resumption or a new negotiation. In fact,
#the only time we won't use it is if we're resuming a non-sharedkey
#session, in which case we use the ciphersuite from the session.
#
#Given the current ciphersuite ordering, this means we prefer SRP
#over non-SRP.
for cipherSuite in cipherSuites:
if cipherSuite in clientHello.cipher_suites:
break
else:
for result in self._sendError(\
AlertDescription.handshake_failure):
yield result
#If resumption was requested...
if clientHello.session_id and (sharedKeyDB or sessionCache):
session = None
#Check in the sharedKeys container
if sharedKeyDB and len(clientHello.session_id)==16:
try:
#Trim off zero padding, if any
for x in range(16):
if clientHello.session_id[x]==0:
break
self.allegedSharedKeyUsername = bytesToString(\
clientHello.session_id[:x])
session = sharedKeyDB[self.allegedSharedKeyUsername]
if not session.sharedKey:
raise AssertionError()
#use privileged ciphersuite
session.cipherSuite = cipherSuite
except KeyError:
pass
#Then check in the session cache
if sessionCache and not session:
try:
session = sessionCache[bytesToString(\
clientHello.session_id)]
if session.sharedKey:
raise AssertionError()
if not session.resumable:
raise AssertionError()
#Check for consistency with ClientHello
if session.cipherSuite not in cipherSuites:
for result in self._sendError(\
AlertDescription.handshake_failure):
yield result
if session.cipherSuite not in clientHello.cipher_suites:
for result in self._sendError(\
AlertDescription.handshake_failure):
yield result
if clientHello.srp_username:
if clientHello.srp_username != session.srpUsername:
for result in self._sendError(\
AlertDescription.handshake_failure):
yield result
except KeyError:
pass
#If a session is found..
if session:
#Set the session
self.session = session
#Send ServerHello
serverHello = ServerHello()
serverHello.create(self.version, serverRandom,
session.sessionID, session.cipherSuite,
certificateType)
for result in self._sendMsg(serverHello):
yield result
#From here on, the client's messages must have the right version
self._versionCheck = True
#Calculate pending connection states
self._calcPendingStates(clientRandom, serverRandom,
settings.cipherImplementations)
#Exchange ChangeCipherSpec and Finished messages
for result in self._sendFinished():
yield result
for result in self._getFinished():
yield result
#Mark the connection as open
self._handshakeDone(resumed=True)
return
#If not a resumption...
#TRICKY: we might have chosen an RSA suite that was only deemed
#acceptable because of the shared-key resumption. If the shared-
#key resumption failed, because the identifier wasn't recognized,
#we might fall through to here, where we have an RSA suite
#chosen, but no certificate.
if cipherSuite in CipherSuite.rsaSuites and not certChain:
for result in self._sendError(\
AlertDescription.handshake_failure):
yield result
#If an RSA suite is chosen, check for certificate type intersection
#(We do this check down here because if the mismatch occurs but the
# client is using a shared-key session, it's okay)
if cipherSuite in CipherSuite.rsaSuites + \
CipherSuite.srpRsaSuites:
if certificateType not in clientHello.certificate_types:
for result in self._sendError(\
AlertDescription.handshake_failure,
"the client doesn't support my certificate type"):
yield result
#Move certChain -> serverCertChain, now that we're using it
serverCertChain = certChain
#Create sessionID
if sessionCache:
sessionID = getRandomBytes(32)
else:
sessionID = createByteArraySequence([])
#If we've selected an SRP suite, exchange keys and calculate
#premaster secret:
if cipherSuite in CipherSuite.srpSuites + CipherSuite.srpRsaSuites:
#If there's no SRP username...
if not clientHello.srp_username:
#Ask the client to re-send ClientHello with one
for result in self._sendMsg(Alert().create(\
AlertDescription.missing_srp_username,
AlertLevel.warning)):
yield result
#Get ClientHello
for result in self._getMsg(ContentType.handshake,
HandshakeType.client_hello):
if result in (0,1):
yield result
else:
break
clientHello = result
#Check ClientHello
#If client's version is too low, reject it (COPIED CODE; BAD!)
if clientHello.client_version < settings.minVersion:
self.version = settings.minVersion
for result in self._sendError(\
AlertDescription.protocol_version,
"Too old version: %s" % str(clientHello.client_version)):
yield result
#If client's version is too high, propose my highest version
elif clientHello.client_version > settings.maxVersion:
self.version = settings.maxVersion
else:
#Set the version to the client's version
self.version = clientHello.client_version
#Recalculate the privileged cipher suite, making sure to
#pick an SRP suite
cipherSuites = [c for c in cipherSuites if c in \
CipherSuite.srpSuites + \
CipherSuite.srpRsaSuites]
for cipherSuite in cipherSuites:
if cipherSuite in clientHello.cipher_suites:
break
else:
for result in self._sendError(\
AlertDescription.handshake_failure):
yield result
#Get the client nonce; create server nonce
clientRandom = clientHello.random
serverRandom = getRandomBytes(32)
#The username better be there, this time
if not clientHello.srp_username:
for result in self._sendError(\
AlertDescription.illegal_parameter,
"Client resent a hello, but without the SRP"\
" username"):
yield result
#Get username
self.allegedSrpUsername = clientHello.srp_username
#Get parameters from username
try:
entry = verifierDB[self.allegedSrpUsername]
except KeyError:
for result in self._sendError(\
AlertDescription.unknown_srp_username):
yield result
(N, g, s, v) = entry
#Calculate server's ephemeral DH values (b, B)
b = bytesToNumber(getRandomBytes(32))
k = makeK(N, g)
B = (powMod(g, b, N) + (k*v)) % N
#Create ServerKeyExchange, signing it if necessary
serverKeyExchange = ServerKeyExchange(cipherSuite)
serverKeyExchange.createSRP(N, g, stringToBytes(s), B)
if cipherSuite in CipherSuite.srpRsaSuites:
hashBytes = serverKeyExchange.hash(clientRandom,
serverRandom)
serverKeyExchange.signature = privateKey.sign(hashBytes)
#Send ServerHello[, Certificate], ServerKeyExchange,
#ServerHelloDone
msgs = []
serverHello = ServerHello()
serverHello.create(self.version, serverRandom, sessionID,
cipherSuite, certificateType)
msgs.append(serverHello)
if cipherSuite in CipherSuite.srpRsaSuites:
certificateMsg = Certificate(certificateType)
certificateMsg.create(serverCertChain)
msgs.append(certificateMsg)
msgs.append(serverKeyExchange)
msgs.append(ServerHelloDone())
for result in self._sendMsgs(msgs):
yield result
#From here on, the client's messages must have the right version
self._versionCheck = True
#Get and check ClientKeyExchange
for result in self._getMsg(ContentType.handshake,
HandshakeType.client_key_exchange,
cipherSuite):
if result in (0,1):
yield result
else:
break
clientKeyExchange = result
A = clientKeyExchange.srp_A
if A % N == 0:
postFinishedError = (AlertDescription.illegal_parameter,
"Suspicious A value")
#Calculate u
u = makeU(N, A, B)
#Calculate premaster secret
S = powMod((A * powMod(v,u,N)) % N, b, N)
premasterSecret = numberToBytes(S)
#If we've selected an RSA suite, exchange keys and calculate
#premaster secret:
elif cipherSuite in CipherSuite.rsaSuites:
#Send ServerHello, Certificate[, CertificateRequest],
#ServerHelloDone
msgs = []
msgs.append(ServerHello().create(self.version, serverRandom,
sessionID, cipherSuite, certificateType))
msgs.append(Certificate(certificateType).create(serverCertChain))
if reqCert:
msgs.append(CertificateRequest())
msgs.append(ServerHelloDone())
for result in self._sendMsgs(msgs):
yield result
#From here on, the client's messages must have the right version
self._versionCheck = True
#Get [Certificate,] (if was requested)
if reqCert:
if self.version == (3,0):
for result in self._getMsg((ContentType.handshake,
ContentType.alert),
HandshakeType.certificate,
certificateType):
if result in (0,1):
yield result
else:
break
msg = result
if isinstance(msg, Alert):
#If it's not a no_certificate alert, re-raise
alert = msg
if alert.description != \
AlertDescription.no_certificate:
self._shutdown(False)
raise TLSRemoteAlert(alert)
elif isinstance(msg, Certificate):
clientCertificate = msg
if clientCertificate.certChain and \
clientCertificate.certChain.getNumCerts()!=0:
clientCertChain = clientCertificate.certChain
else:
raise AssertionError()
elif self.version in ((3,1), (3,2)):
for result in self._getMsg(ContentType.handshake,
HandshakeType.certificate,
certificateType):
if result in (0,1):
yield result
else:
break
clientCertificate = result
if clientCertificate.certChain and \
clientCertificate.certChain.getNumCerts()!=0:
clientCertChain = clientCertificate.certChain
else:
raise AssertionError()
#Get ClientKeyExchange
for result in self._getMsg(ContentType.handshake,
HandshakeType.client_key_exchange,
cipherSuite):
if result in (0,1):
yield result
else:
break
clientKeyExchange = result
#Decrypt ClientKeyExchange
premasterSecret = privateKey.decrypt(\
clientKeyExchange.encryptedPreMasterSecret)
randomPreMasterSecret = getRandomBytes(48)
versionCheck = (premasterSecret[0], premasterSecret[1])
if not premasterSecret:
premasterSecret = randomPreMasterSecret
elif len(premasterSecret)!=48:
premasterSecret = randomPreMasterSecret
elif versionCheck != clientHello.client_version:
if versionCheck != self.version: #Tolerate buggy IE clients
premasterSecret = randomPreMasterSecret
#Get and check CertificateVerify, if relevant
if clientCertChain:
if self.version == (3,0):
#Create a temporary session object, just for the purpose
#of checking the CertificateVerify
session = Session()
session._calcMasterSecret(self.version, premasterSecret,
clientRandom, serverRandom)
verifyBytes = self._calcSSLHandshakeHash(\
session.masterSecret, "")
elif self.version in ((3,1), (3,2)):
verifyBytes = stringToBytes(self._handshake_md5.digest() +\
self._handshake_sha.digest())
for result in self._getMsg(ContentType.handshake,
HandshakeType.certificate_verify):
if result in (0,1):
yield result
else:
break
certificateVerify = result
publicKey = clientCertChain.getEndEntityPublicKey()
if len(publicKey) < settings.minKeySize:
postFinishedError = (AlertDescription.handshake_failure,
"Client's public key too small: %d" % len(publicKey))
if len(publicKey) > settings.maxKeySize:
postFinishedError = (AlertDescription.handshake_failure,
"Client's public key too large: %d" % len(publicKey))
if not publicKey.verify(certificateVerify.signature,
verifyBytes):
postFinishedError = (AlertDescription.decrypt_error,
"Signature failed to verify")
#Create the session object
self.session = Session()
self.session._calcMasterSecret(self.version, premasterSecret,
clientRandom, serverRandom)
self.session.sessionID = sessionID
self.session.cipherSuite = cipherSuite
self.session.srpUsername = self.allegedSrpUsername
self.session.clientCertChain = clientCertChain
self.session.serverCertChain = serverCertChain
#Calculate pending connection states
self._calcPendingStates(clientRandom, serverRandom,
settings.cipherImplementations)
#Exchange ChangeCipherSpec and Finished messages
for result in self._getFinished():
yield result
#If we were holding a post-finished error until receiving the client
#finished message, send it now. We delay the call until this point
#because calling sendError() throws an exception, and our caller might
#shut down the socket upon receiving the exception. If he did, and the
#client was still sending its ChangeCipherSpec or Finished messages, it
#would cause a socket error on the client side. This is a lot of
#consideration to show to misbehaving clients, but this would also
#cause problems with fault-testing.
if postFinishedError:
for result in self._sendError(*postFinishedError):
yield result
for result in self._sendFinished():
yield result
#Add the session object to the session cache
if sessionCache and sessionID:
sessionCache[bytesToString(sessionID)] = self.session
#Mark the connection as open
self.session._setResumable(True)
self._handshakeDone(resumed=False)
def _handshakeWrapperAsync(self, handshaker, checker):
if not self.fault:
try:
for result in handshaker:
yield result
if checker:
try:
checker(self)
except TLSAuthenticationError:
alert = Alert().create(AlertDescription.close_notify,
AlertLevel.fatal)
for result in self._sendMsg(alert):
yield result
raise
except:
self._shutdown(False)
raise
else:
try:
for result in handshaker:
yield result
if checker:
try:
checker(self)
except TLSAuthenticationError:
alert = Alert().create(AlertDescription.close_notify,
AlertLevel.fatal)
for result in self._sendMsg(alert):
yield result
raise
except socket.error, e:
raise TLSFaultError("socket error!")
except TLSAbruptCloseError, e:
raise TLSFaultError("abrupt close error!")
except TLSAlert, alert:
if alert.description not in Fault.faultAlerts[self.fault]:
raise TLSFaultError(str(alert))
else:
pass
except:
self._shutdown(False)
raise
else:
raise TLSFaultError("No error!")
def _getKeyFromChain(self, certificate, settings):
#Get and check cert chain from the Certificate message
certChain = certificate.certChain
if not certChain or certChain.getNumCerts() == 0:
for result in self._sendError(AlertDescription.illegal_parameter,
"Other party sent a Certificate message without "\
"certificates"):
yield result
#Get and check public key from the cert chain
publicKey = certChain.getEndEntityPublicKey()
if len(publicKey) < settings.minKeySize:
for result in self._sendError(AlertDescription.handshake_failure,
"Other party's public key too small: %d" % len(publicKey)):
yield result
if len(publicKey) > settings.maxKeySize:
for result in self._sendError(AlertDescription.handshake_failure,
"Other party's public key too large: %d" % len(publicKey)):
yield result
yield publicKey, certChain
tlslite-0.3.8/tlslite/constants.py 0000700 0001750 0001750 00000016464 10062004507 016252 0 ustar clint clint """Constants used in various places."""
class CertificateType:
x509 = 0
openpgp = 1
cryptoID = 2
class HandshakeType:
hello_request = 0
client_hello = 1
server_hello = 2
certificate = 11
server_key_exchange = 12
certificate_request = 13
server_hello_done = 14
certificate_verify = 15
client_key_exchange = 16
finished = 20
class ContentType:
change_cipher_spec = 20
alert = 21
handshake = 22
application_data = 23
all = (20,21,22,23)
class AlertLevel:
warning = 1
fatal = 2
class AlertDescription:
"""
@cvar bad_record_mac: A TLS record failed to decrypt properly.
If this occurs during a shared-key or SRP handshake it most likely
indicates a bad password. It may also indicate an implementation
error, or some tampering with the data in transit.
This alert will be signalled by the server if the SRP password is bad. It
may also be signalled by the server if the SRP username is unknown to the
server, but it doesn't wish to reveal that fact.
This alert will be signalled by the client if the shared-key username is
bad.
@cvar handshake_failure: A problem occurred while handshaking.
This typically indicates a lack of common ciphersuites between client and
server, or some other disagreement (about SRP parameters or key sizes,
for example).
@cvar protocol_version: The other party's SSL/TLS version was unacceptable.
This indicates that the client and server couldn't agree on which version
of SSL or TLS to use.
@cvar user_canceled: The handshake is being cancelled for some reason.
"""
close_notify = 0
unexpected_message = 10
bad_record_mac = 20
decryption_failed = 21
record_overflow = 22
decompression_failure = 30
handshake_failure = 40
no_certificate = 41 #SSLv3
bad_certificate = 42
unsupported_certificate = 43
certificate_revoked = 44
certificate_expired = 45
certificate_unknown = 46
illegal_parameter = 47
unknown_ca = 48
access_denied = 49
decode_error = 50
decrypt_error = 51
export_restriction = 60
protocol_version = 70
insufficient_security = 71
internal_error = 80
user_canceled = 90
no_renegotiation = 100
unknown_srp_username = 120
missing_srp_username = 121
untrusted_srp_parameters = 122
class CipherSuite:
TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0x0050
TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0x0053
TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0x0056
TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0x0051
TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0x0054
TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0x0057
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A
TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F
TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035
TLS_RSA_WITH_RC4_128_SHA = 0x0005
srpSuites = []
srpSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
srpSuites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
srpSuites.append(TLS_SRP_SHA_WITH_AES_256_CBC_SHA)
def getSrpSuites(ciphers):
suites = []
for cipher in ciphers:
if cipher == "aes128":
suites.append(CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
elif cipher == "aes256":
suites.append(CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA)
elif cipher == "3des":
suites.append(CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
return suites
getSrpSuites = staticmethod(getSrpSuites)
srpRsaSuites = []
srpRsaSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
srpRsaSuites.append(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA)
srpRsaSuites.append(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA)
def getSrpRsaSuites(ciphers):
suites = []
for cipher in ciphers:
if cipher == "aes128":
suites.append(CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA)
elif cipher == "aes256":
suites.append(CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA)
elif cipher == "3des":
suites.append(CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
return suites
getSrpRsaSuites = staticmethod(getSrpRsaSuites)
rsaSuites = []
rsaSuites.append(TLS_RSA_WITH_3DES_EDE_CBC_SHA)
rsaSuites.append(TLS_RSA_WITH_AES_128_CBC_SHA)
rsaSuites.append(TLS_RSA_WITH_AES_256_CBC_SHA)
rsaSuites.append(TLS_RSA_WITH_RC4_128_SHA)
def getRsaSuites(ciphers):
suites = []
for cipher in ciphers:
if cipher == "aes128":
suites.append(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA)
elif cipher == "aes256":
suites.append(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA)
elif cipher == "rc4":
suites.append(CipherSuite.TLS_RSA_WITH_RC4_128_SHA)
elif cipher == "3des":
suites.append(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
return suites
getRsaSuites = staticmethod(getRsaSuites)
tripleDESSuites = []
tripleDESSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
tripleDESSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
tripleDESSuites.append(TLS_RSA_WITH_3DES_EDE_CBC_SHA)
aes128Suites = []
aes128Suites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
aes128Suites.append(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA)
aes128Suites.append(TLS_RSA_WITH_AES_128_CBC_SHA)
aes256Suites = []
aes256Suites.append(TLS_SRP_SHA_WITH_AES_256_CBC_SHA)
aes256Suites.append(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA)
aes256Suites.append(TLS_RSA_WITH_AES_256_CBC_SHA)
rc4Suites = []
rc4Suites.append(TLS_RSA_WITH_RC4_128_SHA)
class Fault:
badUsername = 101
badPassword = 102
badA = 103
clientSrpFaults = range(101,104)
badVerifyMessage = 601
clientCertFaults = range(601,602)
badPremasterPadding = 501
shortPremasterSecret = 502
clientNoAuthFaults = range(501,503)
badIdentifier = 401
badSharedKey = 402
clientSharedKeyFaults = range(401,403)
badB = 201
serverFaults = range(201,202)
badFinished = 300
badMAC = 301
badPadding = 302
genericFaults = range(300,303)
faultAlerts = {\
badUsername: (AlertDescription.unknown_srp_username, \
AlertDescription.bad_record_mac),\
badPassword: (AlertDescription.bad_record_mac,),\
badA: (AlertDescription.illegal_parameter,),\
badIdentifier: (AlertDescription.handshake_failure,),\
badSharedKey: (AlertDescription.bad_record_mac,),\
badPremasterPadding: (AlertDescription.bad_record_mac,),\
shortPremasterSecret: (AlertDescription.bad_record_mac,),\
badVerifyMessage: (AlertDescription.decrypt_error,),\
badFinished: (AlertDescription.decrypt_error,),\
badMAC: (AlertDescription.bad_record_mac,),\
badPadding: (AlertDescription.bad_record_mac,)
}
faultNames = {\
badUsername: "bad username",\
badPassword: "bad password",\
badA: "bad A",\
badIdentifier: "bad identifier",\
badSharedKey: "bad sharedkey",\
badPremasterPadding: "bad premaster padding",\
shortPremasterSecret: "short premaster secret",\
badVerifyMessage: "bad verify message",\
badFinished: "bad finished message",\
badMAC: "bad MAC",\
badPadding: "bad padding"
}
tlslite-0.3.8/docs/ 0000700 0001750 0001750 00000000000 10206516226 013124 5 ustar clint clint tlslite-0.3.8/docs/private/ 0000700 0001750 0001750 00000000000 10206544755 014606 5 ustar clint clint tlslite-0.3.8/docs/private/tlslite.messages.ServerKeyExchange-class.html 0000700 0001750 0001750 00000014522 10206544645 025453 0 ustar clint clint
tlslite.messages.ServerKeyExchange
This class is passed to a handshake function to check the other
party's certificate chain.
If a handshake function completes successfully, but the Checker judges
the other party's certificate chain to be missing or inadequate, a
subclass of tlslite.errors.TLSAuthenticationError will
be raised.
Currently, the Checker can check either an X.509 or a cryptoID chain
(for the latter, cryptoIDlib must be installed).
Method Summary
__init__(self,
cryptoID,
protocol,
x509Fingerprint,
x509TrustList,
x509CommonName,
checkResumedSession)
Create a new Checker instance.
cryptoID -
A cryptoID which the other party's certificate chain must
match. The cryptoIDlib module must be installed. Mutually
exclusive with all of the 'x509...' arguments.
(type=str)
protocol -
A cryptoID protocol URI which the other party's certificate
chain must match. Requires the 'cryptoID' argument.
(type=str)
x509Fingerprint -
A hex-encoded X.509 end-entity fingerprint which the other
party's end-entity certificate must match. Mutually exclusive
with the 'cryptoID' and 'x509TrustList' arguments.
(type=str)
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. Mutually
exclusive with the 'cryptoID' and 'x509Fingerprint'
arguments.
(type=list of tlslite.X509.X509)
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=str)
checkResumedSession -
If resumed sessions should be checked. This defaults to False,
on the theory that if the session was checked once, we don't need
to bother re-checking it.
(type=bool)
__call__(self,
connection) (Call operator)
Check a TLSConnection.
When a Checker is passed to a handshake function, this will be
called at the end of the function.
If the other party tries to use SRP, RSA, or Diffie-Hellman parameters
smaller than this length, an alert will be signalled. The default is
1023.
Type:
int
maxKeySize
The maximum bit length for asymmetric keys.
If the other party tries to use SRP, RSA, or Diffie-Hellman parameters
larger than this length, an alert will be signalled. The default is
8193.
Type:
int
cipherNames
The allowed ciphers, in order of preference.
The allowed values in this list are 'aes256', 'aes128', '3des', and
'rc4'. If these settings are used with a client handshake, they determine
the order of the ciphersuites offered in the ClientHello message.
If these settings are used with a server handshake, the server will
choose whichever ciphersuite matches the earliest entry in this list.
NOTE: If '3des' is used in this list, but TLS Lite can't find an
add-on library that supports 3DES, then '3des' will be silently
removed.
The default value is ['aes256', 'aes128', '3des', 'rc4'].
Type:
list
certificateTypes
The allowed certificate types, in order of preference.
The allowed values in this list are 'x509' and 'cryptoID'. This list
is only used with a client handshake. The client will advertise to the
server which certificate types are supported, and will check that the
server uses one of the appropriate types.
NOTE: If 'cryptoID' is used in this list, but cryptoIDlib is not
installed, then 'cryptoID' will be silently removed.
Type:
list
minVersion
The minimum allowed SSL/TLS version.
This variable can be set to (3,0) for SSL 3.0, (3,1) for TLS 1.0, or
(3,2) for TLS 1.1. If the other party wishes to use a lower version, a
protocol_version alert will be signalled. The default is (3,0).
Type:
tuple
maxVersion
The maximum allowed SSL/TLS version.
This variable can be set to (3,0) for SSL 3.0, (3,1) for TLS 1.0, or
(3,2) for TLS 1.1. If the other party wishes to use a higher version, a
protocol_version alert will be signalled. The default is (3,2). (WARNING:
Some servers may (improperly) reject clients which offer support for TLS
1.1. In this case, try lowering maxVersion to (3,1)).
key: The starting key for the hash. msg: if available, will
immediately be hashed into the object's starting state.
You can now feed arbitrary strings into the object using its
update() method, and can ask for the hash value at any time by calling
its digest() method.
_strxor(s1,
s2)
Utility method. XOR the two strings s1 and s2 (must have same
length).
IMAP4 client class.
Instantiate with: IMAP4([host[, port]])
host - host's name (default: localhost);
port - port number (default: standard IMAP4 port).
All IMAP4rev1 commands are supported by methods of the same
name (in lower-case).
All arguments to commands are converted to strings, except for
AUTHENTICATE, and the last argument to APPEND which is passed as
an IMAP4 literal. If necessary (the string contains any
non-printing characters or white-space and isn't enclosed with
either parentheses or double quotes) each string is quoted.
However, the 'password' argument to the LOGIN command is always
quoted. If you want to avoid having an argument string quoted
(eg: the 'flags' argument to STORE) then enclose the string in
parentheses (eg: "(\Deleted)").
Each command returns a tuple: (type, [data, ...]) where 'type'
is usually 'OK' or 'NO', and 'data' is either the text from the
tagged response, or untagged results from command. Each 'data'
is either a string, or a tuple. If a tuple, then the first part
is the header of the response, and the second part contains
the data (ie: 'literal' value).
Errors raise the exception class <instance>.error("<reason>").
IMAP4 server errors raise <instance>.abort("<reason>"),
which is a sub-class of 'error'. Mailbox status changes
from READ-WRITE to READ-ONLY raise the exception class
<instance>.readonly("<reason>"), which is a sub-class of 'abort'.
"error" exceptions imply a program error.
"abort" exceptions imply the connection should be reset, and
the command re-tried.
"readonly" exceptions imply the command should be re-tried.
Note: to use this module, you must read the RFCs pertaining
to the IMAP4 protocol, as the semantics of the arguments to
each IMAP4 command are left to the invoker, not to mention
the results.
Method Summary
__init__(self,
host,
port)
__getattr__(self,
attr)
append(self,
mailbox,
flags,
date_time,
message)
Append message to named mailbox.
Append message to named mailbox.
(typ, [data]) = <instance>.append(mailbox, flags, date_time, message)
All args except `message' can be None.
authenticate(self,
mechanism,
authobject)
Authenticate command - requires response processing.
'mechanism' specifies which authentication mechanism is to
be used - it must appear in <instance>.capabilities in the
form AUTH=<mechanism>.
'authobject' must be a callable object:
data = authobject(response)
It will be called to process server continuation responses.
It should return data that will be encoded and sent to server.
It should return None if the client abort response '*' should
be sent instead.
check(self)
Checkpoint mailbox on server.
(typ, [data]) = <instance>.check()
close(self)
Close currently selected mailbox.
Deleted messages are removed from writable mailbox. This is the
recommended command before 'LOGOUT'.
(typ, [data]) = <instance>.close()
copy(self,
message_set,
new_mailbox)
Copy 'message_set' messages onto end of 'new_mailbox'.
'data' are tuples of message part envelope and data.
namespace(self)
Returns IMAP namespaces ala rfc2342
(typ, [data, ...]) = <instance>.namespace()
noop(self)
Send NOOP command.
(typ, [data]) = <instance>.noop()
open(self,
host='',
port=143)
Setup connection to remote server on "host:port"
(default: localhost:standard IMAP4 port).
This connection will be used by the routines:
read, readline, send, shutdown.
Execute "command arg ..." with messages identified by UID,
rather than message number.
(typ, [data]) = <instance>.uid(command, arg1, arg2, ...)
Returns response appropriate to 'command'.
unsubscribe(self,
mailbox)
Unsubscribe from old mailbox.
(typ, [data]) = <instance>.unsubscribe(mailbox)
xatom(self,
name,
*args)
Allow simple extension commands
notified by server in CAPABILITY response.
Assumes command is legal in current state.
(typ, [data]) = <instance>.xatom(name, arg, ...)
Returns response appropriate to extension command `name'.
This class manages a connection to an SMTP or ESMTP server.
SMTP Objects:
SMTP objects have the following attributes:
helo_resp
This is the message given by the server in response to the
most recent HELO command.
ehlo_resp
This is the message given by the server in response to the
most recent EHLO command. This is usually multiline.
does_esmtp
This is a True value _after you do an EHLO command_, if the
server supports ESMTP.
esmtp_features
This is a dictionary, which, if the server supports ESMTP,
will _after you do an EHLO command_, contain the names of the
SMTP service extensions this server supports, and their
parameters (if any).
Note, all extension names are mapped to lower case in the
dictionary.
See each method's docstrings for details. In general, there is a
method of the same name to perform each SMTP command. There is also a
method called 'sendmail' that will do an entire mail transaction.
Method Summary
__init__(self,
host,
port,
local_hostname)
Initialize a new instance.
close(self)
Close the connection to the SMTP server.
connect(self,
host,
port)
Connect to a host on a given port.
data(self,
msg)
SMTP 'DATA' command -- sends message data to server.
docmd(self,
cmd,
args)
Send a command, and return its response code.
If specified, `host' is the name of the remote host to which to
connect. If specified, `port' specifies the port to which to connect.
By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised if
the specified `host' doesn't respond correctly. If specified,
`local_hostname` is used as the FQDN of the local host. By default, the
local hostname is found using socket.getfqdn().
close(self)
Close the connection to the SMTP server.
connect(self,
host='localhost',
port=0)
Connect to a host on a given port.
If the hostname ends with a colon (`:') followed by a number, and
there is no port specified, that suffix will be stripped off and the
number interpreted as the port number to use.
Note: This method is automatically invoked by __init__, if a host is
specified during instantiation.
data(self,
msg)
SMTP 'DATA' command -- sends message data to server.
Automatically quotes lines beginning with a period per rfc821.
Raises SMTPDataError if there is an unexpected reply to the DATA
command; the return value from this method is the final response code
received when the all data is sent.
docmd(self,
cmd,
args='')
Send a command, and return its response code.
ehlo(self,
name='')
SMTP 'ehlo' command. Hostname to send for this command defaults to
the FQDN of the local host.
expn(self,
address)
SMTP 'verify' command -- checks for address validity.
getreply(self)
Get a reply from the server.
Returns a tuple consisting of:
server response code (e.g. '250', or such, if all goes well)
Note: returns -1 if it can't read response code.
server response string corresponding to response code (multiline
responses are converted to a single, multiline string).
Raises SMTPServerDisconnected if end-of-file is reached.
has_extn(self,
opt)
Does the server support a given SMTP service extension?
helo(self,
name='')
SMTP 'helo' command. Hostname to send for this command defaults to
the FQDN of the local host.
help(self,
args='')
SMTP 'help' command. Returns help text from server.
login(self,
user,
password)
Log in on an SMTP server that requires authentication.
The arguments are:
- user: The user name to authenticate with.
- password: The password for the authentication.
If there has been no previous EHLO or HELO command this session, this
method tries ESMTP EHLO first.
This method will return normally if the authentication was successful.
This method may raise the following exceptions:
SMTPHeloError The server didn't reply properly to
the helo greeting.
SMTPAuthenticationError The server didn't accept the username/
password combination.
SMTPException No suitable authentication method was
found.
mail(self,
sender,
options=[])
SMTP 'mail' command -- begins mail xfer session.
noop(self)
SMTP 'noop' command -- doesn't do anything :>
putcmd(self,
cmd,
args='')
Send a command to the server.
quit(self)
Terminate the SMTP session.
rcpt(self,
recip,
options=[])
SMTP 'rcpt' command -- indicates 1 recipient for this mail.
This command performs an entire mail transaction.
The arguments are:
- from_addr : The address sending this mail.
- to_addrs : A list of addresses to send this mail to. A bare
string will be treated as a list with 1 address.
- msg : The message to send.
- mail_options : List of ESMTP options (such as 8bitmime) for the
mail command.
- rcpt_options : List of ESMTP options (such as DSN commands) for
all the rcpt commands.
If there has been no previous EHLO or HELO command this session, this
method tries ESMTP EHLO first. If the server does ESMTP, message size
and each of the specified options will be passed to it. If EHLO
fails, HELO will be tried and ESMTP options suppressed.
This method will return normally if the mail is accepted for at least
one recipient. It returns a dictionary, with one entry for each
recipient that was refused. Each entry contains a tuple of the SMTP
error code and the accompanying error message sent by the server.
This method may raise the following exceptions:
SMTPHeloError The server didn't reply properly to
the helo greeting.
SMTPRecipientsRefused The server rejected ALL recipients
(no mail was sent).
SMTPSenderRefused The server didn't accept the from_addr.
SMTPDataError The server replied with an unexpected
error code (other than a refusal of
a recipient).
Note: the connection will be open even after an exception is raised.
Example:
>>> import smtplib
>>> s=smtplib.SMTP("localhost")
>>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
>>> msg = '''\
... From: Me@my.org
... Subject: testin'...
...
... This is a test '''
>>> s.sendmail("me@my.org",tolist,msg)
{ "three@three.org" : ( 550 ,"User unknown" ) }
>>> s.quit()
In the above example, the message was accepted for delivery to three
of the four addresses, and one was rejected, with the error code
550. If all addresses are accepted, then the method will return an
empty dictionary.
set_debuglevel(self,
debuglevel)
Set the debug output level.
A non-false value results in debug messages for connection and for
all messages sent to and received from the server.
starttls(self,
keyfile=None,
certfile=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. If you provide the keyfile and certfile parameters, the
identity of the SMTP server and client can be checked. This, however,
depends on whether the socket module really checks the
certificates.
verify(self,
address)
SMTP 'verify' command -- checks for address validity.
vrfy(self,
address)
SMTP 'verify' command -- checks for address validity.
key: key for the keyed hash object. msg: Initial input for the hash,
if provided. digestmod: A module supporting PEP 247. Defaults to the
md5 module.
copy(self)
Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
digest(self)
Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is not
altered in any way by this function; you can continue updating the
object after calling this function.
hexdigest(self)
Like digest(), but returns a string of hexadecimal digits
instead.
The other party responded incorrectly to an induced fault.
This exception will only occur during fault testing, when a
TLSConnection's fault variable is set to induce some sort of faulty
behavior, and the other party doesn't respond appropriately.
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.
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:
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 httplib.HTTPConnection such as request(),
connect(), and send(). See the client handshake functions in tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
host -
Server to connect to.
(type=str)
port -
Port to connect to.
(type=int)
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
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.
filename -
Filename for an on-disk database, or None for an in-memory
database. If the filename already exists, follow this with a call
to open(). To create a new on-disk database, follow this with a
call to create().
(type=str)
Create a verifier entry which can be stored in a VerifierDB.
Parameters:
username -
The username for this verifier. Must be less than 256
characters in length.
(type=str)
password -
The password for this verifier.
(type=str)
bits -
This values specifies which SRP group parameters to use. It
must be one of (1024, 1536, 2048, 3072, 4096, 6144, 8192). Larger
values are more secure but slower. 2048 is a good compromise
between safety and speed.
(type=int)
Returns:
A tuple which may be stored in a VerifierDB.
(type=tuple)
The socket was closed without a proper TLS shutdown.
The TLS specification mandates that an alert of some sort must be sent
before the underlying socket is closed. If the socket is closed without
this, it could signify that an attacker is trying to truncate the
connection. It could also signify a misbehaving TLS implementation, or a
random network failure.
starttls(self,
username,
password,
sharedKey,
certChain,
privateKey,
cryptoID,
protocol,
x509Fingerprint,
x509TrustList,
x509CommonName,
settings)
Puts the connection to the SMTP server into TLS mode.
Inherited from SMTP
__init__(self,
host,
port,
local_hostname)
Initialize a new instance.
close(self)
Close the connection to the SMTP server.
connect(self,
host,
port)
Connect to a host on a given port.
data(self,
msg)
SMTP 'DATA' command -- sends message data to server.
docmd(self,
cmd,
args)
Send a command, and return its response code.
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:
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 tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
version: The TLS version being used for this connection.
Method Details
read(self,
max=None,
min=1)
Read some data from the TLS connection.
This function will block until at least 'min' bytes are available
(or the connection is closed).
If an exception is raised, the connection will have been
automatically closed.
Parameters:
max -
The maximum number of bytes to return.
(type=int)
min -
The minimum number of bytes to return
(type=int)
Returns:
A string of no more than 'max' bytes, and no fewer than 'min'
(unless the connection has been closed, in which case fewer than
'min' bytes may be returned).
(type=str)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
readAsync(self,
max=None,
min=1)
Start a read operation on the TLS connection.
This function returns a generator which behaves similarly to read().
Successive invocations of the generator will return 0 if it is waiting
to read from the socket, 1 if it is waiting to write to the socket, or
a string if the read operation has completed.
Returns:
A generator; see above for details.
(type=iterable)
write(self,
s)
Write some data to the TLS connection.
This function will block until all the data has been sent.
If an exception is raised, the connection will have been
automatically closed.
Parameters:
s -
The data to transmit to the other party.
(type=str)
Raises:
socket.error -
If a socket error occurs.
writeAsync(self,
s)
Start a write operation on the TLS connection.
This function returns a generator which behaves similarly to
write(). Successive invocations of the generator will return 1 if it is
waiting to write to the socket, or will raise StopIteration if the
write operation has completed.
Returns:
A generator; see above for details.
(type=iterable)
close(self)
Close the TLS connection.
This function will block until it has exchanged close_notify alerts
with the other party. After doing so, it will shut down the TLS
connection. Further attempts to read through this connection will
return "". Further attempts to write through this connection
will raise ValueError.
If makefile() has been called on this connection, the connection
will be not be closed until the connection object and all file objects
have been closed.
Even if an exception is raised, the connection will have been
closed.
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
closeAsync(self)
Start a close operation on the TLS connection.
This function returns a generator which behaves similarly to
close(). Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to the
socket, or will raise StopIteration if the close operation has
completed.
Returns:
A generator; see above for details.
(type=iterable)
getCipherImplementation(self)
Get the name of the cipher implementation used with this
connection.
Returns:
The name of the cipher implementation used with this
connection. Either 'python', 'cryptlib', 'openssl', or
'pycrypto'.
(type=str)
getCipherName(self)
Get the name of the cipher used with this connection.
Returns:
The name of the cipher used with this connection. Either
'aes128', 'aes256', 'rc4', or '3des'.
(type=str)
getpeername(self)
Return the remote address to which the socket is connected (socket
emulation).
getsockname(self)
Return the socket's own address (socket emulation).
gettimeout(self)
Return the timeout associated with socket operations (socket
emulation).
makefile(self,
mode='r',
bufsize=-1)
Create a file object for the TLS connection (socket emulation).
Get some data from the TLS connection (socket emulation).
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
send(self,
s)
Send data to the TLS connection (socket emulation).
Raises:
socket.error -
If a socket error occurs.
sendall(self,
s)
Send data to the TLS connection (socket emulation).
Raises:
socket.error -
If a socket error occurs.
setsockopt(self,
level,
optname,
value)
Set the value of the given socket option (socket emulation).
settimeout(self,
value)
Set a timeout on blocking socket operations (socket emulation).
Instance Variable Details
allegedSharedKeyUsername
This is set to the shared-key username asserted by the client, whether
the handshake succeeded or not. If the handshake fails, this can be
inspected to determine if a guessing attack is in progress against a
particular user account.
Type:
str or None
allegedSrpUsername
This is set to the SRP username asserted by the client, whether the
handshake succeeded or not. If the handshake fails, this can be inspected
to determine if a guessing attack is in progress against a particular
user account.
Type:
str or None
closed
If this connection is closed.
Type:
bool
closeSocket
If the socket should be closed when the connection is closed
(writable).
If you set this to True, TLS Lite will assume the responsibility of
closing the socket when the TLS Connection is shutdown (either through an
error or through the user calling close()). The default is False.
Type:
bool
ignoreAbruptClose
If an abrupt close of the socket should raise an error (writable).
If you set this to True, TLS Lite will not raise a tlslite.errors.TLSAbruptCloseError
exception if the underlying socket is unexpectedly closed. Such an
unexpected closure could be caused by an attacker. However, it also
occurs with some incorrect TLS implementations.
You should set this to True only if you're not worried about an
attacker truncating the connection, and only if necessary to avoid
spurious errors. The default is False.
Type:
bool
resumed
If this connection is based on a resumed session.
Type:
bool
session
The session corresponding to this connection.
Due to TLS session resumption, multiple connections can correspond to
the same underlying 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:
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 tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
host -
Server to connect to.
(type=str)
port -
Port to connect to.
(type=int)
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
This class is used by the server to cache TLS sessions.
Caching sessions allows the client to use TLS session resumption and
avoid the expense of a full handshake. To use this class, simply pass a
SessionCache instance into the server handshake function.
This class is thread-safe.
Method Summary
__init__(self,
maxEntries,
maxAge)
Create a new SessionCache.
maxEntries -
The maximum size of the cache. When this limit is reached, the
oldest sessions will be deleted as necessary to make room for new
ones. The default is 10000.
(type=int)
maxAge -
The number of seconds before a session expires from the cache.
The default is 14400 (i.e. 4 hours).
(type=int)
This document contains the API (Application Programming Interface)
documentation for this project. Documentation for the Python
objects defined by the project is divided into separate pages for each
package, module, and class. The API documentation also includes two
pages containing information about the project as a whole: a trees
page, and an index page.
Object Documentation
Each Package Documentation page contains:
A description of the package.
A list of the modules and sub-packages contained by the
package.
A summary of the classes defined by the package.
A summary of the functions defined by the package.
A summary of the variables defined by the package.
A detailed description of each function defined by the
package.
A detailed description of each variable defined by the
package.
Each Module Documentation page contains:
A description of the module.
A summary of the classes defined by the module.
A summary of the functions defined by the module.
A summary of the variables defined by the module.
A detailed description of each function defined by the
module.
A detailed description of each variable defined by the
module.
Each Class Documentation page contains:
A class inheritance diagram.
A list of known subclasses.
A description of the class.
A summary of the methods defined by the class.
A summary of the instance variables defined by the class.
A summary of the class (static) variables defined by the
class.
A detailed description of each method defined by the
class.
A detailed description of each instance variable defined by the
class.
A detailed description of each class (static) variable defined
by the class.
Project Documentation
The Trees page contains the module and class hierarchies:
The module hierarchy lists every package and module, with
modules grouped into packages. At the top level, and within each
package, modules and sub-packages are listed alphabetically.
The class hierarchy lists every class, grouped by base
class. If a class has more than one base class, then it will be
listed under each base class. At the top level, and under each base
class, classes are listed alphabetically.
The Index page contains indices of terms and
identifiers:
The term index lists every term indexed by any object's
documentation. For each term, the index provides links to each
place where the term is indexed.
The identifier index lists the (short) name of every package,
module, class, method, function, variable, and parameter. For each
identifier, the index provides a short description, and a link to
its documentation.
The Table of Contents
The table of contents occupies the two frames on the left side of
the window. The upper-left frame displays the project
contents, and the lower-left frame displays the module
contents:
Project Contents...
API Documentation Frame
Module Contents ...
The project contents frame contains a list of all packages
and modules that are defined by the project. Clicking on an entry
will display its contents in the module contents frame. Clicking on a
special entry, labeled "Everything," will display the contents of
the entire project.
The module contents frame contains a list of every
submodule, class, type, exception, function, and variable defined by a
module or package. Clicking on an entry will display its
documentation in the API documentation frame. Clicking on the name of
the module, at the top of the frame, will display the documentation
for the module itself.
The "frames" and "no frames" buttons below the top
navigation bar can be used to control whether the table of contents is
displayed or not.
The Navigation Bar
A navigation bar is located at the top and bottom of every page.
It indicates what type of page you are currently viewing, and allows
you to go to related pages. The following table describes the labels
on the navigation bar. Note that not some labels (such as
[Parent]) are not displayed on all pages.
Label
Highlighted when...
Links to...
[Parent]
(never highlighted)
the parent of the current package
[Package]
viewing a package
the package containing the current object
[Module]
viewing a module
the module containing the current object
[Class]
viewing a class
the class containing the current object
[Trees]
viewing the trees page
the trees page
[Index]
viewing the index page
the index page
[Help]
viewing the help page
the help page
The "show private" and "hide private" buttons below
the top navigation bar can be used to control whether documentation
for private objects is displayed. Private objects are usually defined
as objects whose (short) names begin with a single underscore, but do
not end with an underscore. For example, "_x",
"__pprint", and "epydoc.epytext._tokenize"
are private objects; but "re.sub",
"__init__", and "type_" are not. However,
if a module defines the "__all__" variable, then its
contents are used to decide which objects are private.
A timestamp below the bottom navigation bar indicates when each
page was last updated.
Import this module for easy access to TLS Lite objects.
The TLS Lite API consists of classes, functions, and variables spread
throughout this package. Instead of importing them individually with:
from tlslite.TLSConnection import TLSConnection
from tlslite.HandshakeSettings import HandshakeSettings
from tlslite.errors import *
.
.
It's easier to do:
from tlslite.api import *
This imports all the important objects (TLSConnection, Checker,
HandshakeSettings, etc.) into the global namespace. In particular, it
imports:
from constants import AlertLevel, AlertDescription, Fault
from errors import *
from Checker import Checker
from HandshakeSettings import HandshakeSettings
from Session import Session
from SessionCache import SessionCache
from SharedKeyDB import SharedKeyDB
from TLSConnection import TLSConnection
from VerifierDB import VerifierDB
from X509 import X509
from X509CertChain import X509CertChain
from integration.HTTPTLSConnection import HTTPTLSConnection
from integration.POP3_TLS import POP3_TLS
from integration.IMAP4_TLS import IMAP4_TLS
from integration.SMTP_TLS import SMTP_TLS
from integration.XMLRPCTransport import XMLRPCTransport
from integration.TLSSocketServerMixIn import TLSSocketServerMixIn
from integration.TLSAsyncDispatcherMixIn import TLSAsyncDispatcherMixIn
from integration.TLSTwistedProtocolWrapper import TLSTwistedProtocolWrapper
from utils.cryptomath import cryptlibpyLoaded, m2cryptoLoaded,
gmpyLoaded, pycryptoLoaded, prngName
from utils.keyfactory import generateRSAKey, parsePEMKey, parseXMLKey,
parseAsPublicKey, parsePrivateKey
publicKey: The subject public key from the certificate.
Method Details
getCommonName(self)
Get the Subject's Common Name from the certificate.
The cryptlib_py module must be installed in order to use this
function.
Returns:
The CN component of the certificate's subject DN, if
present.
(type=str or None)
getFingerprint(self)
Get the hex-encoded fingerprint of this certificate.
Returns:
A hex-encoded fingerprint.
(type=str)
parse(self,
s)
Parse a PEM-encoded X.509 certificate.
Parameters:
s -
A PEM-encoded X.509 certificate (i.e. a base64-encoded
certificate wrapped with "-----BEGIN CERTIFICATE-----"
and "-----END CERTIFICATE-----" tags).
(type=str)
parseBinary(self,
bytes)
Parse a DER-encoded X.509 certificate.
Parameters:
bytes -
A DER-encoded X.509 certificate.
(type=str or array.array of unsigned bytes)
This class supports both the minimal and optional command sets.
Arguments can be strings or integers (where appropriate)
(e.g.: retr(1) and retr('1') both work equally well.
Minimal Command Set:
USER name user(name)
PASS string pass_(string)
STAT stat()
LIST [msg] list(msg = None)
RETR msg retr(msg)
DELE msg dele(msg)
NOOP noop()
RSET rset()
QUIT quit()
Optional Commands (some servers support these):
RPOP name rpop(name)
APOP name digest apop(name, digest)
TOP msg n top(msg, n)
UIDL [msg] uidl(msg = None)
Raises one exception: 'error_proto'.
Instantiate with:
POP3(hostname, port=110)
NB: the POP protocol locks the mailbox from user
authorization until QUIT, so be sure to get in, suck
the messages, and quit, each time you access the
mailbox.
POP is a line-based protocol, which means large mail
messages consume lots of python cycles reading them
line-by-line.
If it's available on your mail server, use IMAP4
instead, it doesn't suffer from the two problems
above.
Method Summary
__init__(self,
host,
port)
apop(self,
user,
secret)
Authorisation
- only possible if server has supplied a timestamp in initial greeting.
Authorisation
- only possible if server has supplied a timestamp in initial greeting.
Args:
user - mailbox user;
secret - secret shared between client and server.
NB: mailbox is locked by server from here to 'quit()'
dele(self,
which)
Delete message number 'which'.
Result is 'response'.
list(self,
which=None)
Request listing, return result.
Result without a message number argument is in form ['response',
['mesg_num octets', ...]].
Result when a message number argument is given is a single response:
the "scan listing" for that message.
noop(self)
Does nothing.
One supposes the response indicates the server is alive.
pass_(self,
pswd)
Send password, return response
(response includes message count, mailbox size).
NB: mailbox is locked by server from here to 'quit()'
quit(self)
Signoff: commit changes on server, unlock mailbox, close
connection.
retr(self,
which)
Retrieve whole message number 'which'.
Result is in form ['response', ['line', ...], octets].
rpop(self,
user)
Not sure what this does.
rset(self)
Not sure what this does.
stat(self)
Get mailbox status.
Result is tuple of 2 ints (message count, mailbox size)
top(self,
which,
howmuch)
Retrieve message header of message number 'which' and first
'howmuch' lines of message body.
Result is in form ['response', ['line', ...], octets].
uidl(self,
which=None)
Return message digest (unique id) list.
If 'which', result contains unique id for that message in the form
'response mesgnum uid', otherwise result is the list ['response',
['mesgnum uid', ...], octets]
user_canceled: The handshake is being cancelled for some reason.
Class Variable Details
access_denied
Type:
int
Value:
49
bad_certificate
Type:
int
Value:
42
bad_record_mac
A TLS record failed to decrypt properly.
If this occurs during a shared-key or SRP handshake it most likely
indicates a bad password. It may also indicate an implementation error,
or some tampering with the data in transit.
This alert will be signalled by the server if the SRP password is bad.
It may also be signalled by the server if the SRP username is unknown to
the server, but it doesn't wish to reveal that fact.
This alert will be signalled by the client if the shared-key username
is bad.
Type:
int
Value:
20
certificate_expired
Type:
int
Value:
45
certificate_revoked
Type:
int
Value:
44
certificate_unknown
Type:
int
Value:
46
close_notify
Type:
int
Value:
0
decode_error
Type:
int
Value:
50
decompression_failure
Type:
int
Value:
30
decrypt_error
Type:
int
Value:
51
decryption_failed
Type:
int
Value:
21
export_restriction
Type:
int
Value:
60
handshake_failure
A problem occurred while handshaking.
This typically indicates a lack of common ciphersuites between client
and server, or some other disagreement (about SRP parameters or key
sizes, for example).
Type:
int
Value:
40
illegal_parameter
Type:
int
Value:
47
insufficient_security
Type:
int
Value:
71
internal_error
Type:
int
Value:
80
missing_srp_username
Type:
int
Value:
121
no_certificate
Type:
int
Value:
41
no_renegotiation
Type:
int
Value:
100
protocol_version
The other party's SSL/TLS version was unacceptable.
This indicates that the client and server couldn't agree on which
version of SSL or TLS to use.
This class wraps a socket and provides TLS handshaking and data
transfer.
To use this class, create a new instance, passing a connected socket
into the constructor. Then call some handshake function. If the handshake
completes without raising an exception, then a TLS connection has been
negotiated. You can transfer data over this connection as if it were a
socket.
This class provides both synchronous and asynchronous versions of its
key functions. The synchronous versions should be used when writing
single-or multi-threaded code using blocking sockets. The asynchronous
versions should be used when performing asynchronous, event-based I/O
with non-blocking sockets.
__init__(self,
sock)
Create a new TLSConnection instance.
None or an iterable
handshakeClientCert(self,
certChain,
privateKey,
session,
settings,
checker,
async)
Perform a certificate-based handshake in the role of client.
None or an iterable
handshakeClientSharedKey(self,
username,
sharedKey,
settings,
checker,
async)
Perform a shared-key handshake in the role of client.
None or an iterable
handshakeClientSRP(self,
username,
password,
session,
settings,
checker,
async)
Perform an SRP handshake in the role of client.
None or an iterable
handshakeClientUnknown(self,
srpCallback,
certCallback,
session,
settings,
checker,
async)
Perform a to-be-determined type of handshake in the role of
client.
handshakeServer(self,
sharedKeyDB,
verifierDB,
certChain,
privateKey,
reqCert,
sessionCache,
settings,
checker)
Perform a handshake in the role of server.
iterable
handshakeServerAsync(self,
sharedKeyDB,
verifierDB,
certChain,
privateKey,
reqCert,
sessionCache,
settings,
checker)
Start a server handshake operation on the TLS connection.
version: The TLS version being used for this connection.
Method Details
__init__(self,
sock) (Constructor)
Create a new TLSConnection instance.
Parameters:
sock -
The socket data will be transmitted on. The socket should
already be connected. It may be in blocking or non-blocking
mode.
(type=socket.socket)
Perform a certificate-based handshake in the role of client.
This function performs an SSL or TLS handshake. The server will
authenticate itself using an X.509 or cryptoID certificate chain. If
the handshake succeeds, the server's certificate chain will be stored
in the session's serverCertChain attribute. Unless a checker object is
passed in, this function does no validation or checking of the server's
certificate chain.
If the server requests client authentication, the client will send
the passed-in certificate chain, and use the passed-in private key to
authenticate itself. If no certificate chain and private key were
passed in, the client will attempt to proceed without client
authentication. The server may or may not allow this.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
certChain -
The certificate chain to be used if the server requests client
authentication.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
The private key to be used if the server requests client
authentication.
(type=tlslite.utils.RSAKey.RSAKey)
session -
A TLS session to attempt to resume. If the resumption does not
succeed, a full handshake will be performed.
(type=tlslite.Session.Session)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
Perform a shared-key handshake in the role of client.
This function performs a shared-key handshake. Using shared
symmetric keys of high entropy (128 bits or greater) mutually
authenticates both parties to each other.
TLS with shared-keys is non-standard. Most TLS implementations don't
support it. See http://www.ietf.org/html.charters/tls-charter.html
for the latest information on TLS with shared-keys. If the shared-keys
Internet-Draft changes or is superceded, TLS Lite will track those
changes, so the shared-key support in later versions of TLS Lite may
become incompatible with this version.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
username -
The shared-key username.
(type=str)
sharedKey -
The shared key.
(type=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
This function performs a TLS/SRP handshake. SRP mutually
authenticates both parties to each other using only a username and
password. This function may also perform a combined SRP and
server-certificate handshake, if the server chooses to authenticate
itself with a certificate chain in addition to doing SRP.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
username -
The SRP username.
(type=str)
password -
The SRP password.
(type=str)
session -
A TLS session to attempt to resume. This session must be an
SRP session performed with the same username and password as were
passed in. If the resumption does not succeed, a full SRP
handshake will be performed.
(type=tlslite.Session.Session)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
Perform a to-be-determined type of handshake in the role of
client.
This function performs an SSL or TLS handshake. If the server
requests client certificate authentication, the certCallback will be
invoked and should return a (certChain, privateKey) pair. If the
callback returns None, the library will attempt to proceed without
client authentication. The server may or may not allow this.
If the server requests SRP authentication, the srpCallback will be
invoked and should return a (username, password) pair. If the callback
returns None, the local implementation will signal a user_canceled
error alert.
After the handshake completes, the client can inspect the
connection's session attribute to determine what type of authentication
was performed.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
srpCallback -
The callback to be used if the server requests SRP
authentication. If None, the client will not offer support for
SRP ciphersuites.
(type=callable)
certCallback -
The callback to be used if the server requests client
certificate authentication.
(type=callable)
session -
A TLS session to attempt to resume. If the resumption does not
succeed, a full handshake will be performed.
(type=tlslite.Session.Session)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
This function performs an SSL or TLS handshake. Depending on the
arguments and the behavior of the client, this function can perform a
shared-key, SRP, or certificate-based handshake. It can also perform a
combined SRP and server-certificate handshake.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake. This function does not
send a Hello Request message before performing the handshake, so if
re-handshaking is required, the server must signal the client to begin
the re-handshake through some other means.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
sharedKeyDB -
A database of shared symmetric keys associated with usernames.
If the client performs a shared-key handshake, the session's
sharedKeyUsername attribute will be set.
(type=tlslite.SharedKeyDB.SharedKeyDB)
verifierDB -
A database of SRP password verifiers associated with
usernames. If the client performs an SRP handshake, the session's
srpUsername attribute will be set.
(type=tlslite.VerifierDB.VerifierDB)
certChain -
The certificate chain to be used if the client requests server
certificate authentication.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
The private key to be used if the client requests server
certificate authentication.
(type=tlslite.utils.RSAKey.RSAKey)
reqCert -
Whether to request client certificate authentication. This
only applies if the client chooses server certificate
authentication; if the client chooses SRP or shared-key
authentication, this will be ignored. If the client performs a
client certificate authentication, the sessions's clientCertChain
attribute will be set.
(type=bool)
sessionCache -
An in-memory cache of resumable sessions. The client can
resume sessions from this cache. Alternatively, if the client
performs a full handshake, a new session will be added to the
cache.
(type=tlslite.SessionCache.SessionCache)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
Start a server handshake operation on the TLS connection.
This function returns a generator which behaves similarly to
handshakeServer(). Successive invocations of the generator will return
0 if it is waiting to read from the socket, 1 if it is waiting to write
to the socket, or it will raise StopIteration if the handshake
operation is complete.
Returns:
A generator; see above for details.
(type=iterable)
tlslite.errors.TLSAuthorizationError:
The Checker was expecting the other party to authenticate with a
certificate chain that has a different authorization.
tlslite.errors.TLSFingerprintError:
The Checker was expecting the other party to authenticate with a
certificate chain that matches a different fingerprint.
TLS Lite is a free python library that implements SSL v3, TLS v1, and
TLS v1.1. TLS Lite supports non-traditional authentication methods such
as SRP, shared keys, and cryptoIDs, in addition to X.509 certificates.
TLS Lite is pure python, however it can access OpenSSL, cryptlib,
pycrypto, and GMPY for faster crypto operations. TLS Lite integrates with
httplib, xmlrpclib, poplib, imaplib, smtplib, SocketServer, asyncore, and
Twisted.
This class can be "mixed in" with an
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:
the mix-in is listed first in the inheritance list
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.
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:
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.
Method Summary
__init__(self,
sock)
close(self)
handle_read(self)
handle_write(self)
outCloseEvent(self)
Called when a close operation completes.
outConnectEvent(self)
Called when a handshake operation completes.
outReadEvent(self,
readBuffer)
Called when a read operation completes.
outWriteEvent(self)
Called when a write operation completes.
readable(self)
recv(self,
bufferSize)
send(self,
writeBuffer)
writable(self)
Inherited from AsyncStateMachine
inReadEvent(self)
Tell the state machine it can read from the socket.
inWriteEvent(self)
Tell the state machine it can write to the socket.
The XML format used here is specific to tlslite and cryptoIDlib. The
format can store the public component of a key, or the public and
private components. For example:
This format also supports password-encrypted private keys. TLS Lite
can only handle password-encrypted private keys when OpenSSL and
M2Crypto are installed. In this case, passwordCallback will be invoked
to query the user for the password.
Parameters:
s -
A string containing a PEM-encoded public or private key.
(type=str)
private -
If True, a SyntaxError will be raised if the
private key component is not present.
(type=bool)
public -
If True, the private key component (if present) will be
discarded, so this function will always return a public key.
(type=bool)
passwordCallback -
This function will be called, with no arguments, if the
PEM-encoded private key is password-encrypted. The callback
should return the password string. If the password is incorrect,
SyntaxError will be raised. If no callback is passed and the key
is password-encrypted, a prompt will be displayed at the
console.
(type=callable)
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.
Method Summary
__init__(self)
inReadEvent(self)
Tell the state machine it can read from the socket.
inWriteEvent(self)
Tell the state machine it can write to the socket.
outCloseEvent(self)
Called when a close operation completes.
outConnectEvent(self)
Called when a handshake operation completes.
outReadEvent(self,
readBuffer)
Called when a read operation completes.
outWriteEvent(self)
Called when a write operation completes.
Tell the state machine it can read from the socket.
inWriteEvent(self)
Tell the state machine it can write to the socket.
outCloseEvent(self)
Called when a close operation completes.
May be overridden in subclass.
outConnectEvent(self)
Called when a handshake operation completes.
May be overridden in subclass.
outReadEvent(self,
readBuffer)
Called when a read operation completes.
May be overridden in subclass.
outWriteEvent(self)
Called when a write operation completes.
May be overridden in subclass.
setCloseOp(self)
Start a close operation.
setHandshakeOp(self,
handshaker)
Start a handshake operation.
Parameters:
handshaker -
A generator created by using one of the asynchronous handshake
functions (i.e. handshakeServerAsync, or handshakeClientxxx(...,
async=True).
(type=generator)
The handshake succeeded, but the other party's authentication was
inadequate.
This exception will only be raised when a tlslite.Checker.Checker has been passed to
a handshake function. The Checker will be invoked once the handshake
completes, and if the Checker objects to how the other party
authenticated, a subclass of this exception will be raised.
This is a helper class used to integrate TLS Lite with various TLS
clients (e.g. poplib, smtplib, httplib, etc.)
Method Summary
__init__(self,
username,
password,
sharedKey,
certChain,
privateKey,
cryptoID,
protocol,
x509Fingerprint,
x509TrustList,
x509CommonName,
settings)
For client authentication, use one of these argument combinations:
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:
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 tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
getFingerprint(self)
Get the hex-encoded fingerprint of the end-entity certificate.
int
getNumCerts(self)
Get the number of certificates in this chain.
validate(self,
x509TrustList)
Check the validity of the certificate chain.
_checkChaining(self,
lastC,
rootC)
Instance Variable Summary
list
x509List: A list of tlslite.X509.X509 instances, starting with
the end-entity certificate and with every subsequent certificate
certifying the previous.
Method Details
__init__(self,
x509List=None) (Constructor)
Create a new X509CertChain.
Parameters:
x509List -
A list of tlslite.X509.X509 instances,
starting with the end-entity certificate and with every
subsequent certificate certifying the previous.
(type=list)
getCommonName(self)
Get the Subject's Common Name from the end-entity certificate.
The cryptlib_py module must be installed in order to use this
function.
Returns:
The CN component of the certificate's subject DN, if
present.
(type=str or None)
getEndEntityPublicKey(self)
Get the public key from the end-entity certificate.
Get the hex-encoded fingerprint of the end-entity certificate.
Returns:
A hex-encoded fingerprint.
(type=str)
getNumCerts(self)
Get the number of certificates in this chain.
Returns:
int
validate(self,
x509TrustList)
Check the validity of the certificate chain.
This checks that every certificate in the chain validates with the
subsequent one, until some certificate validates with (or is identical
to) one of the passed-in root certificates.
The cryptlib_py module must be installed in order to use this
function.
Parameters:
x509TrustList -
A list of trusted root certificates. The certificate chain
must extend to one of these certificates to be considered
valid.
(type=list of tlslite.X509.X509)
Instance Variable Details
x509List
A list of tlslite.X509.X509 instances, starting with
the end-entity certificate and with every subsequent certificate
certifying the previous.
If you are going to write a new protocol for Twisted, start here. The
docstrings of this class explain how you can get started. Any protocol
implementation, either client or server, should be a subclass of me.
My API is quite simple. Implement dataReceived(data) to handle both
event-based and synchronous input; output can be sent through the
'transport' attribute, which is to be an instance that implements
twisted.internet.interfaces.ITransport.
Some subclasses exist already to help you write common types of
protocols: see the twisted.protocols.basic module for a few
of them.
This may be considered the initializer of the protocol, because it
is called when the connection is completed. For clients, this is called
once the connection to the server has been established; for servers,
this is called after an accept() call stops blocking and a socket has
been received. If you need to send any greeting or initial message, do
it here.
makeConnection(self,
transport)
Make a connection to a transport and a server.
This sets the 'transport' attribute of this Protocol, and calls the
connectionMade() callback.
filename -
Filename for an on-disk database, or None for an in-memory
database. If the filename already exists, follow this with a call
to open(). To create a new on-disk database, follow this with a
call to create().
(type=str)
username -
The username to associate the shared key with. Must be less
than or equal to 16 characters in length, and must not already be
in the database.
(type=str)
sharedKey -
The shared key to add. Must be less than 48 characters in
length.
(type=str)
TLS distinguishes between connections and sessions. A new handshake
creates both a connection and a session. Data is transmitted over the
connection.
The session contains a more permanent record of the handshake. The
session can be inspected to determine handshake results. The session can
also be used to create a new connection through "session
resumption". If the client and server both support this, they can
create a new connection based on an old session without the overhead of a
full handshake.
_safe_read(self,
amt)
Read the number of bytes requested, compensating for partial
reads.
Method Details
_safe_read(self,
amt)
Read the number of bytes requested, compensating for partial
reads.
Normally, we have a blocking socket, but a read() can be interrupted
by a signal (resulting in a partial read).
Note that we cannot distinguish between EOF and an interrupt when
zero bytes have been read. IncompleteRead() will be raised in this
situation.
This function should be used when <amt> bytes
"should" be present for reading. If the bytes are truly not
available (due to EOF), then the IncompleteRead exception can be used
to detect the problem.
This class can be mixed in with any
SocketServer.TCPServer to add TLS support.
To use this class, define a new class that inherits from it and some
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()
This may be considered the initializer of the protocol, because it
is called when the connection is completed. For clients, this is called
once the connection to the server has been established; for servers,
this is called after an accept() call stops blocking and a socket has
been received. If you need to send any greeting or initial message, do
it here.
Use this method to translate to a higher-level message. Usually,
some callback will be made upon the receipt of each complete protocol
message.
Parameters:
data -
a string of indeterminate length. Please keep in mind that you
will probably need to buffer some data, as partial (or multiple)
protocol messages may be received! I recommend that unit tests
for protocols call through to this method with differing chunk
sizes, down to one byte at a time.
An instance of this class can be passed to
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:
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
xmlrpclib.ServerProxy. See the client handshake functions
in tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
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.
This may be considered the initializer of the protocol, because it
is called when the connection is completed. For clients, this is called
once the connection to the server has been established; for servers,
this is called after an accept() call stops blocking and a socket has
been received. If you need to send any greeting or initial message, do
it here.
Use this method to translate to a higher-level message. Usually,
some callback will be made upon the receipt of each complete protocol
message.
Parameters:
data -
a string of indeterminate length. Please keep in mind that you
will probably need to buffer some data, as partial (or multiple)
protocol messages may be received! I recommend that unit tests
for protocols call through to this method with differing chunk
sizes, down to one byte at a time.
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:
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 tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
host -
Server to connect to.
(type=str)
port -
Port to connect to.
(type=int)
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
key: key for the keyed hash object. msg: Initial input for the hash,
if provided. digestmod: A module supporting PEP 247. Defaults to the
md5 module.
copy(self)
Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
digest(self)
Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is not
altered in any way by this function; you can continue updating the
object after calling this function.
hexdigest(self)
Like digest(), but returns a string of hexadecimal digits
instead.
Clear any circular references here, and any external references to
this Protocol. The connection has been closed.
Parameters:
reason
(type=twisted.python.failure.Failure)
dataReceived(self,
data)
Called whenever data is received.
Use this method to translate to a higher-level message. Usually,
some callback will be made upon the receipt of each complete protocol
message.
Parameters:
data -
a string of indeterminate length. Please keep in mind that you
will probably need to buffer some data, as partial (or multiple)
protocol messages may be received! I recommend that unit tests
for protocols call through to this method with differing chunk
sizes, down to one byte at a time.
This class is passed to a handshake function to check the other
party's certificate chain.
If a handshake function completes successfully, but the Checker judges
the other party's certificate chain to be missing or inadequate, a
subclass of tlslite.errors.TLSAuthenticationError will
be raised.
Currently, the Checker can check either an X.509 or a cryptoID chain
(for the latter, cryptoIDlib must be installed).
Method Summary
__init__(self,
cryptoID,
protocol,
x509Fingerprint,
x509TrustList,
x509CommonName,
checkResumedSession)
Create a new Checker instance.
cryptoID -
A cryptoID which the other party's certificate chain must
match. The cryptoIDlib module must be installed. Mutually
exclusive with all of the 'x509...' arguments.
(type=str)
protocol -
A cryptoID protocol URI which the other party's certificate
chain must match. Requires the 'cryptoID' argument.
(type=str)
x509Fingerprint -
A hex-encoded X.509 end-entity fingerprint which the other
party's end-entity certificate must match. Mutually exclusive
with the 'cryptoID' and 'x509TrustList' arguments.
(type=str)
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. Mutually
exclusive with the 'cryptoID' and 'x509Fingerprint'
arguments.
(type=list of tlslite.X509.X509)
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=str)
checkResumedSession -
If resumed sessions should be checked. This defaults to False,
on the theory that if the session was checked once, we don't need
to bother re-checking it.
(type=bool)
__call__(self,
connection) (Call operator)
Check a TLSConnection.
When a Checker is passed to a handshake function, this will be
called at the end of the function.
If the other party tries to use SRP, RSA, or Diffie-Hellman parameters
smaller than this length, an alert will be signalled. The default is
1023.
Type:
int
maxKeySize
The maximum bit length for asymmetric keys.
If the other party tries to use SRP, RSA, or Diffie-Hellman parameters
larger than this length, an alert will be signalled. The default is
8193.
Type:
int
cipherNames
The allowed ciphers, in order of preference.
The allowed values in this list are 'aes256', 'aes128', '3des', and
'rc4'. If these settings are used with a client handshake, they determine
the order of the ciphersuites offered in the ClientHello message.
If these settings are used with a server handshake, the server will
choose whichever ciphersuite matches the earliest entry in this list.
NOTE: If '3des' is used in this list, but TLS Lite can't find an
add-on library that supports 3DES, then '3des' will be silently
removed.
The default value is ['aes256', 'aes128', '3des', 'rc4'].
Type:
list
certificateTypes
The allowed certificate types, in order of preference.
The allowed values in this list are 'x509' and 'cryptoID'. This list
is only used with a client handshake. The client will advertise to the
server which certificate types are supported, and will check that the
server uses one of the appropriate types.
NOTE: If 'cryptoID' is used in this list, but cryptoIDlib is not
installed, then 'cryptoID' will be silently removed.
Type:
list
minVersion
The minimum allowed SSL/TLS version.
This variable can be set to (3,0) for SSL 3.0, (3,1) for TLS 1.0, or
(3,2) for TLS 1.1. If the other party wishes to use a lower version, a
protocol_version alert will be signalled. The default is (3,0).
Type:
tuple
maxVersion
The maximum allowed SSL/TLS version.
This variable can be set to (3,0) for SSL 3.0, (3,1) for TLS 1.0, or
(3,2) for TLS 1.1. If the other party wishes to use a higher version, a
protocol_version alert will be signalled. The default is (3,2). (WARNING:
Some servers may (improperly) reject clients which offer support for TLS
1.1. In this case, try lowering maxVersion to (3,1)).
key: The starting key for the hash. msg: if available, will
immediately be hashed into the object's starting state.
You can now feed arbitrary strings into the object using its
update() method, and can ask for the hash value at any time by calling
its digest() method.
IMAP4 client class.
Instantiate with: IMAP4([host[, port]])
host - host's name (default: localhost);
port - port number (default: standard IMAP4 port).
All IMAP4rev1 commands are supported by methods of the same
name (in lower-case).
All arguments to commands are converted to strings, except for
AUTHENTICATE, and the last argument to APPEND which is passed as
an IMAP4 literal. If necessary (the string contains any
non-printing characters or white-space and isn't enclosed with
either parentheses or double quotes) each string is quoted.
However, the 'password' argument to the LOGIN command is always
quoted. If you want to avoid having an argument string quoted
(eg: the 'flags' argument to STORE) then enclose the string in
parentheses (eg: "(\Deleted)").
Each command returns a tuple: (type, [data, ...]) where 'type'
is usually 'OK' or 'NO', and 'data' is either the text from the
tagged response, or untagged results from command. Each 'data'
is either a string, or a tuple. If a tuple, then the first part
is the header of the response, and the second part contains
the data (ie: 'literal' value).
Errors raise the exception class <instance>.error("<reason>").
IMAP4 server errors raise <instance>.abort("<reason>"),
which is a sub-class of 'error'. Mailbox status changes
from READ-WRITE to READ-ONLY raise the exception class
<instance>.readonly("<reason>"), which is a sub-class of 'abort'.
"error" exceptions imply a program error.
"abort" exceptions imply the connection should be reset, and
the command re-tried.
"readonly" exceptions imply the command should be re-tried.
Note: to use this module, you must read the RFCs pertaining
to the IMAP4 protocol, as the semantics of the arguments to
each IMAP4 command are left to the invoker, not to mention
the results.
Method Summary
__init__(self,
host,
port)
__getattr__(self,
attr)
append(self,
mailbox,
flags,
date_time,
message)
Append message to named mailbox.
Append message to named mailbox.
(typ, [data]) = <instance>.append(mailbox, flags, date_time, message)
All args except `message' can be None.
authenticate(self,
mechanism,
authobject)
Authenticate command - requires response processing.
'mechanism' specifies which authentication mechanism is to
be used - it must appear in <instance>.capabilities in the
form AUTH=<mechanism>.
'authobject' must be a callable object:
data = authobject(response)
It will be called to process server continuation responses.
It should return data that will be encoded and sent to server.
It should return None if the client abort response '*' should
be sent instead.
check(self)
Checkpoint mailbox on server.
(typ, [data]) = <instance>.check()
close(self)
Close currently selected mailbox.
Deleted messages are removed from writable mailbox. This is the
recommended command before 'LOGOUT'.
(typ, [data]) = <instance>.close()
copy(self,
message_set,
new_mailbox)
Copy 'message_set' messages onto end of 'new_mailbox'.
'data' are tuples of message part envelope and data.
namespace(self)
Returns IMAP namespaces ala rfc2342
(typ, [data, ...]) = <instance>.namespace()
noop(self)
Send NOOP command.
(typ, [data]) = <instance>.noop()
open(self,
host='',
port=143)
Setup connection to remote server on "host:port"
(default: localhost:standard IMAP4 port).
This connection will be used by the routines:
read, readline, send, shutdown.
Execute "command arg ..." with messages identified by UID,
rather than message number.
(typ, [data]) = <instance>.uid(command, arg1, arg2, ...)
Returns response appropriate to 'command'.
unsubscribe(self,
mailbox)
Unsubscribe from old mailbox.
(typ, [data]) = <instance>.unsubscribe(mailbox)
xatom(self,
name,
*args)
Allow simple extension commands
notified by server in CAPABILITY response.
Assumes command is legal in current state.
(typ, [data]) = <instance>.xatom(name, arg, ...)
Returns response appropriate to extension command `name'.
This class manages a connection to an SMTP or ESMTP server.
SMTP Objects:
SMTP objects have the following attributes:
helo_resp
This is the message given by the server in response to the
most recent HELO command.
ehlo_resp
This is the message given by the server in response to the
most recent EHLO command. This is usually multiline.
does_esmtp
This is a True value _after you do an EHLO command_, if the
server supports ESMTP.
esmtp_features
This is a dictionary, which, if the server supports ESMTP,
will _after you do an EHLO command_, contain the names of the
SMTP service extensions this server supports, and their
parameters (if any).
Note, all extension names are mapped to lower case in the
dictionary.
See each method's docstrings for details. In general, there is a
method of the same name to perform each SMTP command. There is also a
method called 'sendmail' that will do an entire mail transaction.
Method Summary
__init__(self,
host,
port,
local_hostname)
Initialize a new instance.
close(self)
Close the connection to the SMTP server.
connect(self,
host,
port)
Connect to a host on a given port.
data(self,
msg)
SMTP 'DATA' command -- sends message data to server.
docmd(self,
cmd,
args)
Send a command, and return its response code.
If specified, `host' is the name of the remote host to which to
connect. If specified, `port' specifies the port to which to connect.
By default, smtplib.SMTP_PORT is used. An SMTPConnectError is raised if
the specified `host' doesn't respond correctly. If specified,
`local_hostname` is used as the FQDN of the local host. By default, the
local hostname is found using socket.getfqdn().
close(self)
Close the connection to the SMTP server.
connect(self,
host='localhost',
port=0)
Connect to a host on a given port.
If the hostname ends with a colon (`:') followed by a number, and
there is no port specified, that suffix will be stripped off and the
number interpreted as the port number to use.
Note: This method is automatically invoked by __init__, if a host is
specified during instantiation.
data(self,
msg)
SMTP 'DATA' command -- sends message data to server.
Automatically quotes lines beginning with a period per rfc821.
Raises SMTPDataError if there is an unexpected reply to the DATA
command; the return value from this method is the final response code
received when the all data is sent.
docmd(self,
cmd,
args='')
Send a command, and return its response code.
ehlo(self,
name='')
SMTP 'ehlo' command. Hostname to send for this command defaults to
the FQDN of the local host.
expn(self,
address)
SMTP 'verify' command -- checks for address validity.
getreply(self)
Get a reply from the server.
Returns a tuple consisting of:
server response code (e.g. '250', or such, if all goes well)
Note: returns -1 if it can't read response code.
server response string corresponding to response code (multiline
responses are converted to a single, multiline string).
Raises SMTPServerDisconnected if end-of-file is reached.
has_extn(self,
opt)
Does the server support a given SMTP service extension?
helo(self,
name='')
SMTP 'helo' command. Hostname to send for this command defaults to
the FQDN of the local host.
help(self,
args='')
SMTP 'help' command. Returns help text from server.
login(self,
user,
password)
Log in on an SMTP server that requires authentication.
The arguments are:
- user: The user name to authenticate with.
- password: The password for the authentication.
If there has been no previous EHLO or HELO command this session, this
method tries ESMTP EHLO first.
This method will return normally if the authentication was successful.
This method may raise the following exceptions:
SMTPHeloError The server didn't reply properly to
the helo greeting.
SMTPAuthenticationError The server didn't accept the username/
password combination.
SMTPException No suitable authentication method was
found.
mail(self,
sender,
options=[])
SMTP 'mail' command -- begins mail xfer session.
noop(self)
SMTP 'noop' command -- doesn't do anything :>
putcmd(self,
cmd,
args='')
Send a command to the server.
quit(self)
Terminate the SMTP session.
rcpt(self,
recip,
options=[])
SMTP 'rcpt' command -- indicates 1 recipient for this mail.
This command performs an entire mail transaction.
The arguments are:
- from_addr : The address sending this mail.
- to_addrs : A list of addresses to send this mail to. A bare
string will be treated as a list with 1 address.
- msg : The message to send.
- mail_options : List of ESMTP options (such as 8bitmime) for the
mail command.
- rcpt_options : List of ESMTP options (such as DSN commands) for
all the rcpt commands.
If there has been no previous EHLO or HELO command this session, this
method tries ESMTP EHLO first. If the server does ESMTP, message size
and each of the specified options will be passed to it. If EHLO
fails, HELO will be tried and ESMTP options suppressed.
This method will return normally if the mail is accepted for at least
one recipient. It returns a dictionary, with one entry for each
recipient that was refused. Each entry contains a tuple of the SMTP
error code and the accompanying error message sent by the server.
This method may raise the following exceptions:
SMTPHeloError The server didn't reply properly to
the helo greeting.
SMTPRecipientsRefused The server rejected ALL recipients
(no mail was sent).
SMTPSenderRefused The server didn't accept the from_addr.
SMTPDataError The server replied with an unexpected
error code (other than a refusal of
a recipient).
Note: the connection will be open even after an exception is raised.
Example:
>>> import smtplib
>>> s=smtplib.SMTP("localhost")
>>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
>>> msg = '''\
... From: Me@my.org
... Subject: testin'...
...
... This is a test '''
>>> s.sendmail("me@my.org",tolist,msg)
{ "three@three.org" : ( 550 ,"User unknown" ) }
>>> s.quit()
In the above example, the message was accepted for delivery to three
of the four addresses, and one was rejected, with the error code
550. If all addresses are accepted, then the method will return an
empty dictionary.
set_debuglevel(self,
debuglevel)
Set the debug output level.
A non-false value results in debug messages for connection and for
all messages sent to and received from the server.
starttls(self,
keyfile=None,
certfile=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. If you provide the keyfile and certfile parameters, the
identity of the SMTP server and client can be checked. This, however,
depends on whether the socket module really checks the
certificates.
verify(self,
address)
SMTP 'verify' command -- checks for address validity.
vrfy(self,
address)
SMTP 'verify' command -- checks for address validity.
key: key for the keyed hash object. msg: Initial input for the hash,
if provided. digestmod: A module supporting PEP 247. Defaults to the
md5 module.
copy(self)
Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
digest(self)
Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is not
altered in any way by this function; you can continue updating the
object after calling this function.
hexdigest(self)
Like digest(), but returns a string of hexadecimal digits
instead.
The other party responded incorrectly to an induced fault.
This exception will only occur during fault testing, when a
TLSConnection's fault variable is set to induce some sort of faulty
behavior, and the other party doesn't respond appropriately.
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:
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 httplib.HTTPConnection such as request(),
connect(), and send(). See the client handshake functions in tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
host -
Server to connect to.
(type=str)
port -
Port to connect to.
(type=int)
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
filename -
Filename for an on-disk database, or None for an in-memory
database. If the filename already exists, follow this with a call
to open(). To create a new on-disk database, follow this with a
call to create().
(type=str)
Create a verifier entry which can be stored in a VerifierDB.
Parameters:
username -
The username for this verifier. Must be less than 256
characters in length.
(type=str)
password -
The password for this verifier.
(type=str)
bits -
This values specifies which SRP group parameters to use. It
must be one of (1024, 1536, 2048, 3072, 4096, 6144, 8192). Larger
values are more secure but slower. 2048 is a good compromise
between safety and speed.
(type=int)
Returns:
A tuple which may be stored in a VerifierDB.
(type=tuple)
The socket was closed without a proper TLS shutdown.
The TLS specification mandates that an alert of some sort must be sent
before the underlying socket is closed. If the socket is closed without
this, it could signify that an attacker is trying to truncate the
connection. It could also signify a misbehaving TLS implementation, or a
random network failure.
starttls(self,
username,
password,
sharedKey,
certChain,
privateKey,
cryptoID,
protocol,
x509Fingerprint,
x509TrustList,
x509CommonName,
settings)
Puts the connection to the SMTP server into TLS mode.
Inherited from SMTP
__init__(self,
host,
port,
local_hostname)
Initialize a new instance.
close(self)
Close the connection to the SMTP server.
connect(self,
host,
port)
Connect to a host on a given port.
data(self,
msg)
SMTP 'DATA' command -- sends message data to server.
docmd(self,
cmd,
args)
Send a command, and return its response code.
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:
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 tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
version: The TLS version being used for this connection.
Method Details
read(self,
max=None,
min=1)
Read some data from the TLS connection.
This function will block until at least 'min' bytes are available
(or the connection is closed).
If an exception is raised, the connection will have been
automatically closed.
Parameters:
max -
The maximum number of bytes to return.
(type=int)
min -
The minimum number of bytes to return
(type=int)
Returns:
A string of no more than 'max' bytes, and no fewer than 'min'
(unless the connection has been closed, in which case fewer than
'min' bytes may be returned).
(type=str)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
readAsync(self,
max=None,
min=1)
Start a read operation on the TLS connection.
This function returns a generator which behaves similarly to read().
Successive invocations of the generator will return 0 if it is waiting
to read from the socket, 1 if it is waiting to write to the socket, or
a string if the read operation has completed.
Returns:
A generator; see above for details.
(type=iterable)
write(self,
s)
Write some data to the TLS connection.
This function will block until all the data has been sent.
If an exception is raised, the connection will have been
automatically closed.
Parameters:
s -
The data to transmit to the other party.
(type=str)
Raises:
socket.error -
If a socket error occurs.
writeAsync(self,
s)
Start a write operation on the TLS connection.
This function returns a generator which behaves similarly to
write(). Successive invocations of the generator will return 1 if it is
waiting to write to the socket, or will raise StopIteration if the
write operation has completed.
Returns:
A generator; see above for details.
(type=iterable)
close(self)
Close the TLS connection.
This function will block until it has exchanged close_notify alerts
with the other party. After doing so, it will shut down the TLS
connection. Further attempts to read through this connection will
return "". Further attempts to write through this connection
will raise ValueError.
If makefile() has been called on this connection, the connection
will be not be closed until the connection object and all file objects
have been closed.
Even if an exception is raised, the connection will have been
closed.
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
closeAsync(self)
Start a close operation on the TLS connection.
This function returns a generator which behaves similarly to
close(). Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to the
socket, or will raise StopIteration if the close operation has
completed.
Returns:
A generator; see above for details.
(type=iterable)
getCipherImplementation(self)
Get the name of the cipher implementation used with this
connection.
Returns:
The name of the cipher implementation used with this
connection. Either 'python', 'cryptlib', 'openssl', or
'pycrypto'.
(type=str)
getCipherName(self)
Get the name of the cipher used with this connection.
Returns:
The name of the cipher used with this connection. Either
'aes128', 'aes256', 'rc4', or '3des'.
(type=str)
getpeername(self)
Return the remote address to which the socket is connected (socket
emulation).
getsockname(self)
Return the socket's own address (socket emulation).
gettimeout(self)
Return the timeout associated with socket operations (socket
emulation).
makefile(self,
mode='r',
bufsize=-1)
Create a file object for the TLS connection (socket emulation).
Get some data from the TLS connection (socket emulation).
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
send(self,
s)
Send data to the TLS connection (socket emulation).
Raises:
socket.error -
If a socket error occurs.
sendall(self,
s)
Send data to the TLS connection (socket emulation).
Raises:
socket.error -
If a socket error occurs.
setsockopt(self,
level,
optname,
value)
Set the value of the given socket option (socket emulation).
settimeout(self,
value)
Set a timeout on blocking socket operations (socket emulation).
Instance Variable Details
allegedSharedKeyUsername
This is set to the shared-key username asserted by the client, whether
the handshake succeeded or not. If the handshake fails, this can be
inspected to determine if a guessing attack is in progress against a
particular user account.
Type:
str or None
allegedSrpUsername
This is set to the SRP username asserted by the client, whether the
handshake succeeded or not. If the handshake fails, this can be inspected
to determine if a guessing attack is in progress against a particular
user account.
Type:
str or None
closed
If this connection is closed.
Type:
bool
closeSocket
If the socket should be closed when the connection is closed
(writable).
If you set this to True, TLS Lite will assume the responsibility of
closing the socket when the TLS Connection is shutdown (either through an
error or through the user calling close()). The default is False.
Type:
bool
ignoreAbruptClose
If an abrupt close of the socket should raise an error (writable).
If you set this to True, TLS Lite will not raise a tlslite.errors.TLSAbruptCloseError
exception if the underlying socket is unexpectedly closed. Such an
unexpected closure could be caused by an attacker. However, it also
occurs with some incorrect TLS implementations.
You should set this to True only if you're not worried about an
attacker truncating the connection, and only if necessary to avoid
spurious errors. The default is False.
Type:
bool
resumed
If this connection is based on a resumed session.
Type:
bool
session
The session corresponding to this connection.
Due to TLS session resumption, multiple connections can correspond to
the same underlying 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:
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 tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
host -
Server to connect to.
(type=str)
port -
Port to connect to.
(type=int)
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
This class is used by the server to cache TLS sessions.
Caching sessions allows the client to use TLS session resumption and
avoid the expense of a full handshake. To use this class, simply pass a
SessionCache instance into the server handshake function.
This class is thread-safe.
Method Summary
__init__(self,
maxEntries,
maxAge)
Create a new SessionCache.
maxEntries -
The maximum size of the cache. When this limit is reached, the
oldest sessions will be deleted as necessary to make room for new
ones. The default is 10000.
(type=int)
maxAge -
The number of seconds before a session expires from the cache.
The default is 14400 (i.e. 4 hours).
(type=int)
This document contains the API (Application Programming Interface)
documentation for this project. Documentation for the Python
objects defined by the project is divided into separate pages for each
package, module, and class. The API documentation also includes two
pages containing information about the project as a whole: a trees
page, and an index page.
Object Documentation
Each Package Documentation page contains:
A description of the package.
A list of the modules and sub-packages contained by the
package.
A summary of the classes defined by the package.
A summary of the functions defined by the package.
A summary of the variables defined by the package.
A detailed description of each function defined by the
package.
A detailed description of each variable defined by the
package.
Each Module Documentation page contains:
A description of the module.
A summary of the classes defined by the module.
A summary of the functions defined by the module.
A summary of the variables defined by the module.
A detailed description of each function defined by the
module.
A detailed description of each variable defined by the
module.
Each Class Documentation page contains:
A class inheritance diagram.
A list of known subclasses.
A description of the class.
A summary of the methods defined by the class.
A summary of the instance variables defined by the class.
A summary of the class (static) variables defined by the
class.
A detailed description of each method defined by the
class.
A detailed description of each instance variable defined by the
class.
A detailed description of each class (static) variable defined
by the class.
Project Documentation
The Trees page contains the module and class hierarchies:
The module hierarchy lists every package and module, with
modules grouped into packages. At the top level, and within each
package, modules and sub-packages are listed alphabetically.
The class hierarchy lists every class, grouped by base
class. If a class has more than one base class, then it will be
listed under each base class. At the top level, and under each base
class, classes are listed alphabetically.
The Index page contains indices of terms and
identifiers:
The term index lists every term indexed by any object's
documentation. For each term, the index provides links to each
place where the term is indexed.
The identifier index lists the (short) name of every package,
module, class, method, function, variable, and parameter. For each
identifier, the index provides a short description, and a link to
its documentation.
The Table of Contents
The table of contents occupies the two frames on the left side of
the window. The upper-left frame displays the project
contents, and the lower-left frame displays the module
contents:
Project Contents...
API Documentation Frame
Module Contents ...
The project contents frame contains a list of all packages
and modules that are defined by the project. Clicking on an entry
will display its contents in the module contents frame. Clicking on a
special entry, labeled "Everything," will display the contents of
the entire project.
The module contents frame contains a list of every
submodule, class, type, exception, function, and variable defined by a
module or package. Clicking on an entry will display its
documentation in the API documentation frame. Clicking on the name of
the module, at the top of the frame, will display the documentation
for the module itself.
The "frames" and "no frames" buttons below the top
navigation bar can be used to control whether the table of contents is
displayed or not.
The Navigation Bar
A navigation bar is located at the top and bottom of every page.
It indicates what type of page you are currently viewing, and allows
you to go to related pages. The following table describes the labels
on the navigation bar. Note that not some labels (such as
[Parent]) are not displayed on all pages.
Label
Highlighted when...
Links to...
[Parent]
(never highlighted)
the parent of the current package
[Package]
viewing a package
the package containing the current object
[Module]
viewing a module
the module containing the current object
[Class]
viewing a class
the class containing the current object
[Trees]
viewing the trees page
the trees page
[Index]
viewing the index page
the index page
[Help]
viewing the help page
the help page
The "show private" and "hide private" buttons below
the top navigation bar can be used to control whether documentation
for private objects is displayed. Private objects are usually defined
as objects whose (short) names begin with a single underscore, but do
not end with an underscore. For example, "_x",
"__pprint", and "epydoc.epytext._tokenize"
are private objects; but "re.sub",
"__init__", and "type_" are not. However,
if a module defines the "__all__" variable, then its
contents are used to decide which objects are private.
A timestamp below the bottom navigation bar indicates when each
page was last updated.
Import this module for easy access to TLS Lite objects.
The TLS Lite API consists of classes, functions, and variables spread
throughout this package. Instead of importing them individually with:
from tlslite.TLSConnection import TLSConnection
from tlslite.HandshakeSettings import HandshakeSettings
from tlslite.errors import *
.
.
It's easier to do:
from tlslite.api import *
This imports all the important objects (TLSConnection, Checker,
HandshakeSettings, etc.) into the global namespace. In particular, it
imports:
from constants import AlertLevel, AlertDescription, Fault
from errors import *
from Checker import Checker
from HandshakeSettings import HandshakeSettings
from Session import Session
from SessionCache import SessionCache
from SharedKeyDB import SharedKeyDB
from TLSConnection import TLSConnection
from VerifierDB import VerifierDB
from X509 import X509
from X509CertChain import X509CertChain
from integration.HTTPTLSConnection import HTTPTLSConnection
from integration.POP3_TLS import POP3_TLS
from integration.IMAP4_TLS import IMAP4_TLS
from integration.SMTP_TLS import SMTP_TLS
from integration.XMLRPCTransport import XMLRPCTransport
from integration.TLSSocketServerMixIn import TLSSocketServerMixIn
from integration.TLSAsyncDispatcherMixIn import TLSAsyncDispatcherMixIn
from integration.TLSTwistedProtocolWrapper import TLSTwistedProtocolWrapper
from utils.cryptomath import cryptlibpyLoaded, m2cryptoLoaded,
gmpyLoaded, pycryptoLoaded, prngName
from utils.keyfactory import generateRSAKey, parsePEMKey, parseXMLKey,
parseAsPublicKey, parsePrivateKey
publicKey: The subject public key from the certificate.
Method Details
getCommonName(self)
Get the Subject's Common Name from the certificate.
The cryptlib_py module must be installed in order to use this
function.
Returns:
The CN component of the certificate's subject DN, if
present.
(type=str or None)
getFingerprint(self)
Get the hex-encoded fingerprint of this certificate.
Returns:
A hex-encoded fingerprint.
(type=str)
parse(self,
s)
Parse a PEM-encoded X.509 certificate.
Parameters:
s -
A PEM-encoded X.509 certificate (i.e. a base64-encoded
certificate wrapped with "-----BEGIN CERTIFICATE-----"
and "-----END CERTIFICATE-----" tags).
(type=str)
parseBinary(self,
bytes)
Parse a DER-encoded X.509 certificate.
Parameters:
bytes -
A DER-encoded X.509 certificate.
(type=str or array.array of unsigned bytes)
This class supports both the minimal and optional command sets.
Arguments can be strings or integers (where appropriate)
(e.g.: retr(1) and retr('1') both work equally well.
Minimal Command Set:
USER name user(name)
PASS string pass_(string)
STAT stat()
LIST [msg] list(msg = None)
RETR msg retr(msg)
DELE msg dele(msg)
NOOP noop()
RSET rset()
QUIT quit()
Optional Commands (some servers support these):
RPOP name rpop(name)
APOP name digest apop(name, digest)
TOP msg n top(msg, n)
UIDL [msg] uidl(msg = None)
Raises one exception: 'error_proto'.
Instantiate with:
POP3(hostname, port=110)
NB: the POP protocol locks the mailbox from user
authorization until QUIT, so be sure to get in, suck
the messages, and quit, each time you access the
mailbox.
POP is a line-based protocol, which means large mail
messages consume lots of python cycles reading them
line-by-line.
If it's available on your mail server, use IMAP4
instead, it doesn't suffer from the two problems
above.
Method Summary
__init__(self,
host,
port)
apop(self,
user,
secret)
Authorisation
- only possible if server has supplied a timestamp in initial greeting.
Authorisation
- only possible if server has supplied a timestamp in initial greeting.
Args:
user - mailbox user;
secret - secret shared between client and server.
NB: mailbox is locked by server from here to 'quit()'
dele(self,
which)
Delete message number 'which'.
Result is 'response'.
list(self,
which=None)
Request listing, return result.
Result without a message number argument is in form ['response',
['mesg_num octets', ...]].
Result when a message number argument is given is a single response:
the "scan listing" for that message.
noop(self)
Does nothing.
One supposes the response indicates the server is alive.
pass_(self,
pswd)
Send password, return response
(response includes message count, mailbox size).
NB: mailbox is locked by server from here to 'quit()'
quit(self)
Signoff: commit changes on server, unlock mailbox, close
connection.
retr(self,
which)
Retrieve whole message number 'which'.
Result is in form ['response', ['line', ...], octets].
rpop(self,
user)
Not sure what this does.
rset(self)
Not sure what this does.
stat(self)
Get mailbox status.
Result is tuple of 2 ints (message count, mailbox size)
top(self,
which,
howmuch)
Retrieve message header of message number 'which' and first
'howmuch' lines of message body.
Result is in form ['response', ['line', ...], octets].
uidl(self,
which=None)
Return message digest (unique id) list.
If 'which', result contains unique id for that message in the form
'response mesgnum uid', otherwise result is the list ['response',
['mesgnum uid', ...], octets]
user_canceled: The handshake is being cancelled for some reason.
Class Variable Details
access_denied
Type:
int
Value:
49
bad_certificate
Type:
int
Value:
42
bad_record_mac
A TLS record failed to decrypt properly.
If this occurs during a shared-key or SRP handshake it most likely
indicates a bad password. It may also indicate an implementation error,
or some tampering with the data in transit.
This alert will be signalled by the server if the SRP password is bad.
It may also be signalled by the server if the SRP username is unknown to
the server, but it doesn't wish to reveal that fact.
This alert will be signalled by the client if the shared-key username
is bad.
Type:
int
Value:
20
certificate_expired
Type:
int
Value:
45
certificate_revoked
Type:
int
Value:
44
certificate_unknown
Type:
int
Value:
46
close_notify
Type:
int
Value:
0
decode_error
Type:
int
Value:
50
decompression_failure
Type:
int
Value:
30
decrypt_error
Type:
int
Value:
51
decryption_failed
Type:
int
Value:
21
export_restriction
Type:
int
Value:
60
handshake_failure
A problem occurred while handshaking.
This typically indicates a lack of common ciphersuites between client
and server, or some other disagreement (about SRP parameters or key
sizes, for example).
Type:
int
Value:
40
illegal_parameter
Type:
int
Value:
47
insufficient_security
Type:
int
Value:
71
internal_error
Type:
int
Value:
80
missing_srp_username
Type:
int
Value:
121
no_certificate
Type:
int
Value:
41
no_renegotiation
Type:
int
Value:
100
protocol_version
The other party's SSL/TLS version was unacceptable.
This indicates that the client and server couldn't agree on which
version of SSL or TLS to use.
This class wraps a socket and provides TLS handshaking and data
transfer.
To use this class, create a new instance, passing a connected socket
into the constructor. Then call some handshake function. If the handshake
completes without raising an exception, then a TLS connection has been
negotiated. You can transfer data over this connection as if it were a
socket.
This class provides both synchronous and asynchronous versions of its
key functions. The synchronous versions should be used when writing
single-or multi-threaded code using blocking sockets. The asynchronous
versions should be used when performing asynchronous, event-based I/O
with non-blocking sockets.
__init__(self,
sock)
Create a new TLSConnection instance.
None or an iterable
handshakeClientCert(self,
certChain,
privateKey,
session,
settings,
checker,
async)
Perform a certificate-based handshake in the role of client.
None or an iterable
handshakeClientSharedKey(self,
username,
sharedKey,
settings,
checker,
async)
Perform a shared-key handshake in the role of client.
None or an iterable
handshakeClientSRP(self,
username,
password,
session,
settings,
checker,
async)
Perform an SRP handshake in the role of client.
None or an iterable
handshakeClientUnknown(self,
srpCallback,
certCallback,
session,
settings,
checker,
async)
Perform a to-be-determined type of handshake in the role of
client.
handshakeServer(self,
sharedKeyDB,
verifierDB,
certChain,
privateKey,
reqCert,
sessionCache,
settings,
checker)
Perform a handshake in the role of server.
iterable
handshakeServerAsync(self,
sharedKeyDB,
verifierDB,
certChain,
privateKey,
reqCert,
sessionCache,
settings,
checker)
Start a server handshake operation on the TLS connection.
version: The TLS version being used for this connection.
Method Details
__init__(self,
sock) (Constructor)
Create a new TLSConnection instance.
Parameters:
sock -
The socket data will be transmitted on. The socket should
already be connected. It may be in blocking or non-blocking
mode.
(type=socket.socket)
Perform a certificate-based handshake in the role of client.
This function performs an SSL or TLS handshake. The server will
authenticate itself using an X.509 or cryptoID certificate chain. If
the handshake succeeds, the server's certificate chain will be stored
in the session's serverCertChain attribute. Unless a checker object is
passed in, this function does no validation or checking of the server's
certificate chain.
If the server requests client authentication, the client will send
the passed-in certificate chain, and use the passed-in private key to
authenticate itself. If no certificate chain and private key were
passed in, the client will attempt to proceed without client
authentication. The server may or may not allow this.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
certChain -
The certificate chain to be used if the server requests client
authentication.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
The private key to be used if the server requests client
authentication.
(type=tlslite.utils.RSAKey.RSAKey)
session -
A TLS session to attempt to resume. If the resumption does not
succeed, a full handshake will be performed.
(type=tlslite.Session.Session)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
Perform a shared-key handshake in the role of client.
This function performs a shared-key handshake. Using shared
symmetric keys of high entropy (128 bits or greater) mutually
authenticates both parties to each other.
TLS with shared-keys is non-standard. Most TLS implementations don't
support it. See http://www.ietf.org/html.charters/tls-charter.html
for the latest information on TLS with shared-keys. If the shared-keys
Internet-Draft changes or is superceded, TLS Lite will track those
changes, so the shared-key support in later versions of TLS Lite may
become incompatible with this version.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
username -
The shared-key username.
(type=str)
sharedKey -
The shared key.
(type=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
This function performs a TLS/SRP handshake. SRP mutually
authenticates both parties to each other using only a username and
password. This function may also perform a combined SRP and
server-certificate handshake, if the server chooses to authenticate
itself with a certificate chain in addition to doing SRP.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
username -
The SRP username.
(type=str)
password -
The SRP password.
(type=str)
session -
A TLS session to attempt to resume. This session must be an
SRP session performed with the same username and password as were
passed in. If the resumption does not succeed, a full SRP
handshake will be performed.
(type=tlslite.Session.Session)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
Perform a to-be-determined type of handshake in the role of
client.
This function performs an SSL or TLS handshake. If the server
requests client certificate authentication, the certCallback will be
invoked and should return a (certChain, privateKey) pair. If the
callback returns None, the library will attempt to proceed without
client authentication. The server may or may not allow this.
If the server requests SRP authentication, the srpCallback will be
invoked and should return a (username, password) pair. If the callback
returns None, the local implementation will signal a user_canceled
error alert.
After the handshake completes, the client can inspect the
connection's session attribute to determine what type of authentication
was performed.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
srpCallback -
The callback to be used if the server requests SRP
authentication. If None, the client will not offer support for
SRP ciphersuites.
(type=callable)
certCallback -
The callback to be used if the server requests client
certificate authentication.
(type=callable)
session -
A TLS session to attempt to resume. If the resumption does not
succeed, a full handshake will be performed.
(type=tlslite.Session.Session)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
async -
If False, this function will block until the handshake is
completed. If True, this function will return a generator.
Successive invocations of the generator will return 0 if it is
waiting to read from the socket, 1 if it is waiting to write to
the socket, or will raise StopIteration if the handshake
operation is completed.
(type=bool)
Returns:
If 'async' is True, a generator object will be returned.
(type=None or an iterable)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
This function performs an SSL or TLS handshake. Depending on the
arguments and the behavior of the client, this function can perform a
shared-key, SRP, or certificate-based handshake. It can also perform a
combined SRP and server-certificate handshake.
Like any handshake function, this can be called on a closed TLS
connection, or on a TLS connection that is already open. If called on
an open connection it performs a re-handshake. This function does not
send a Hello Request message before performing the handshake, so if
re-handshaking is required, the server must signal the client to begin
the re-handshake through some other means.
If the function completes without raising an exception, the TLS
connection will be open and available for data transfer.
If an exception is raised, the connection will have been
automatically closed (if it was ever open).
Parameters:
sharedKeyDB -
A database of shared symmetric keys associated with usernames.
If the client performs a shared-key handshake, the session's
sharedKeyUsername attribute will be set.
(type=tlslite.SharedKeyDB.SharedKeyDB)
verifierDB -
A database of SRP password verifiers associated with
usernames. If the client performs an SRP handshake, the session's
srpUsername attribute will be set.
(type=tlslite.VerifierDB.VerifierDB)
certChain -
The certificate chain to be used if the client requests server
certificate authentication.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
The private key to be used if the client requests server
certificate authentication.
(type=tlslite.utils.RSAKey.RSAKey)
reqCert -
Whether to request client certificate authentication. This
only applies if the client chooses server certificate
authentication; if the client chooses SRP or shared-key
authentication, this will be ignored. If the client performs a
client certificate authentication, the sessions's clientCertChain
attribute will be set.
(type=bool)
sessionCache -
An in-memory cache of resumable sessions. The client can
resume sessions from this cache. Alternatively, if the client
performs a full handshake, a new session will be added to the
cache.
(type=tlslite.SessionCache.SessionCache)
checker -
A Checker instance. This instance will be invoked to examine
the other party's authentication credentials, if the handshake
completes succesfully.
(type=tlslite.Checker.Checker)
Raises:
socket.error -
If a socket error occurs.
tlslite.errors.TLSAbruptCloseError -
If the socket is closed without a preceding alert.
tlslite.errors.TLSAlert -
If a TLS alert is signalled.
tlslite.errors.TLSAuthenticationError -
If the checker doesn't like the other party's authentication
credentials.
Start a server handshake operation on the TLS connection.
This function returns a generator which behaves similarly to
handshakeServer(). Successive invocations of the generator will return
0 if it is waiting to read from the socket, 1 if it is waiting to write
to the socket, or it will raise StopIteration if the handshake
operation is complete.
Returns:
A generator; see above for details.
(type=iterable)
tlslite.errors.TLSAuthorizationError:
The Checker was expecting the other party to authenticate with a
certificate chain that has a different authorization.
tlslite.errors.TLSFingerprintError:
The Checker was expecting the other party to authenticate with a
certificate chain that matches a different fingerprint.
TLS Lite is a free python library that implements SSL v3, TLS v1, and
TLS v1.1. TLS Lite supports non-traditional authentication methods such
as SRP, shared keys, and cryptoIDs, in addition to X.509 certificates.
TLS Lite is pure python, however it can access OpenSSL, cryptlib,
pycrypto, and GMPY for faster crypto operations. TLS Lite integrates with
httplib, xmlrpclib, poplib, imaplib, smtplib, SocketServer, asyncore, and
Twisted.
This class can be "mixed in" with an
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:
the mix-in is listed first in the inheritance list
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.
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:
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.
Method Summary
__init__(self,
sock)
close(self)
handle_read(self)
handle_write(self)
outCloseEvent(self)
Called when a close operation completes.
outConnectEvent(self)
Called when a handshake operation completes.
outReadEvent(self,
readBuffer)
Called when a read operation completes.
outWriteEvent(self)
Called when a write operation completes.
readable(self)
recv(self,
bufferSize)
send(self,
writeBuffer)
writable(self)
Inherited from AsyncStateMachine
inReadEvent(self)
Tell the state machine it can read from the socket.
inWriteEvent(self)
Tell the state machine it can write to the socket.
The XML format used here is specific to tlslite and cryptoIDlib. The
format can store the public component of a key, or the public and
private components. For example:
This format also supports password-encrypted private keys. TLS Lite
can only handle password-encrypted private keys when OpenSSL and
M2Crypto are installed. In this case, passwordCallback will be invoked
to query the user for the password.
Parameters:
s -
A string containing a PEM-encoded public or private key.
(type=str)
private -
If True, a SyntaxError will be raised if the
private key component is not present.
(type=bool)
public -
If True, the private key component (if present) will be
discarded, so this function will always return a public key.
(type=bool)
passwordCallback -
This function will be called, with no arguments, if the
PEM-encoded private key is password-encrypted. The callback
should return the password string. If the password is incorrect,
SyntaxError will be raised. If no callback is passed and the key
is password-encrypted, a prompt will be displayed at the
console.
(type=callable)
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.
Method Summary
__init__(self)
inReadEvent(self)
Tell the state machine it can read from the socket.
inWriteEvent(self)
Tell the state machine it can write to the socket.
outCloseEvent(self)
Called when a close operation completes.
outConnectEvent(self)
Called when a handshake operation completes.
outReadEvent(self,
readBuffer)
Called when a read operation completes.
outWriteEvent(self)
Called when a write operation completes.
Tell the state machine it can read from the socket.
inWriteEvent(self)
Tell the state machine it can write to the socket.
outCloseEvent(self)
Called when a close operation completes.
May be overridden in subclass.
outConnectEvent(self)
Called when a handshake operation completes.
May be overridden in subclass.
outReadEvent(self,
readBuffer)
Called when a read operation completes.
May be overridden in subclass.
outWriteEvent(self)
Called when a write operation completes.
May be overridden in subclass.
setCloseOp(self)
Start a close operation.
setHandshakeOp(self,
handshaker)
Start a handshake operation.
Parameters:
handshaker -
A generator created by using one of the asynchronous handshake
functions (i.e. handshakeServerAsync, or handshakeClientxxx(...,
async=True).
(type=generator)
The handshake succeeded, but the other party's authentication was
inadequate.
This exception will only be raised when a tlslite.Checker.Checker has been passed to
a handshake function. The Checker will be invoked once the handshake
completes, and if the Checker objects to how the other party
authenticated, a subclass of this exception will be raised.
getFingerprint(self)
Get the hex-encoded fingerprint of the end-entity certificate.
int
getNumCerts(self)
Get the number of certificates in this chain.
validate(self,
x509TrustList)
Check the validity of the certificate chain.
Instance Variable Summary
list
x509List: A list of tlslite.X509.X509 instances, starting with
the end-entity certificate and with every subsequent certificate
certifying the previous.
Method Details
__init__(self,
x509List=None) (Constructor)
Create a new X509CertChain.
Parameters:
x509List -
A list of tlslite.X509.X509 instances,
starting with the end-entity certificate and with every
subsequent certificate certifying the previous.
(type=list)
getCommonName(self)
Get the Subject's Common Name from the end-entity certificate.
The cryptlib_py module must be installed in order to use this
function.
Returns:
The CN component of the certificate's subject DN, if
present.
(type=str or None)
getEndEntityPublicKey(self)
Get the public key from the end-entity certificate.
Get the hex-encoded fingerprint of the end-entity certificate.
Returns:
A hex-encoded fingerprint.
(type=str)
getNumCerts(self)
Get the number of certificates in this chain.
Returns:
int
validate(self,
x509TrustList)
Check the validity of the certificate chain.
This checks that every certificate in the chain validates with the
subsequent one, until some certificate validates with (or is identical
to) one of the passed-in root certificates.
The cryptlib_py module must be installed in order to use this
function.
Parameters:
x509TrustList -
A list of trusted root certificates. The certificate chain
must extend to one of these certificates to be considered
valid.
(type=list of tlslite.X509.X509)
Instance Variable Details
x509List
A list of tlslite.X509.X509 instances, starting with
the end-entity certificate and with every subsequent certificate
certifying the previous.
filename -
Filename for an on-disk database, or None for an in-memory
database. If the filename already exists, follow this with a call
to open(). To create a new on-disk database, follow this with a
call to create().
(type=str)
username -
The username to associate the shared key with. Must be less
than or equal to 16 characters in length, and must not already be
in the database.
(type=str)
sharedKey -
The shared key to add. Must be less than 48 characters in
length.
(type=str)
TLS distinguishes between connections and sessions. A new handshake
creates both a connection and a session. Data is transmitted over the
connection.
The session contains a more permanent record of the handshake. The
session can be inspected to determine handshake results. The session can
also be used to create a new connection through "session
resumption". If the client and server both support this, they can
create a new connection based on an old session without the overhead of a
full handshake.
This class can be mixed in with any
SocketServer.TCPServer to add TLS support.
To use this class, define a new class that inherits from it and some
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()
This may be considered the initializer of the protocol, because it
is called when the connection is completed. For clients, this is called
once the connection to the server has been established; for servers,
this is called after an accept() call stops blocking and a socket has
been received. If you need to send any greeting or initial message, do
it here.
Use this method to translate to a higher-level message. Usually,
some callback will be made upon the receipt of each complete protocol
message.
Parameters:
data -
a string of indeterminate length. Please keep in mind that you
will probably need to buffer some data, as partial (or multiple)
protocol messages may be received! I recommend that unit tests
for protocols call through to this method with differing chunk
sizes, down to one byte at a time.
An instance of this class can be passed to
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:
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
xmlrpclib.ServerProxy. See the client handshake functions
in tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
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.
This may be considered the initializer of the protocol, because it
is called when the connection is completed. For clients, this is called
once the connection to the server has been established; for servers,
this is called after an accept() call stops blocking and a socket has
been received. If you need to send any greeting or initial message, do
it here.
Use this method to translate to a higher-level message. Usually,
some callback will be made upon the receipt of each complete protocol
message.
Parameters:
data -
a string of indeterminate length. Please keep in mind that you
will probably need to buffer some data, as partial (or multiple)
protocol messages may be received! I recommend that unit tests
for protocols call through to this method with differing chunk
sizes, down to one byte at a time.
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:
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 tlslite.TLSConnection.TLSConnection for
details on which exceptions might be raised.
Parameters:
host -
Server to connect to.
(type=str)
port -
Port to connect to.
(type=int)
username -
SRP or shared-key username. Requires the 'password' or
'sharedKey' argument.
(type=str)
password -
SRP password for mutual authentication. Requires the
'username' argument.
(type=str)
sharedKey -
Shared key for mutual authentication. Requires the 'username'
argument.
(type=str)
certChain -
Certificate chain for client authentication. Requires the
'privateKey' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.X509CertChain.X509CertChain
or cryptoIDlib.CertChain.CertChain)
privateKey -
Private key for client authentication. Requires the
'certChain' argument. Excludes the SRP or shared-key related
arguments.
(type=tlslite.utils.RSAKey.RSAKey)
cryptoID -
cryptoID for server authentication. Mutually exclusive with
the 'x509...' arguments.
(type=str)
protocol -
cryptoID protocol URI for server authentication. Requires the
'cryptoID' argument.
(type=str)
x509Fingerprint -
Hex-encoded X.509 fingerprint for server authentication.
Mutually exclusive with the 'cryptoID' and 'x509TrustList'
arguments.
(type=str)
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=list of tlslite.X509.X509)
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=str)
settings -
Various settings which can be used to control the
ciphersuites, certificate types, and SSL/TLS versions offered by
the client.
(type=tlslite.HandshakeSettings.HandshakeSettings)
key: key for the keyed hash object. msg: Initial input for the hash,
if provided. digestmod: A module supporting PEP 247. Defaults to the
md5 module.
copy(self)
Return a separate copy of this hashing object.
An update to this copy won't affect the original object.
digest(self)
Return the hash value of this hashing object.
This returns a string containing 8-bit data. The object is not
altered in any way by this function; you can continue updating the
object after calling this function.
hexdigest(self)
Like digest(), but returns a string of hexadecimal digits
instead.
Clear any circular references here, and any external references to
this Protocol. The connection has been closed.
Parameters:
reason
(type=twisted.python.failure.Failure)
dataReceived(self,
data)
Called whenever data is received.
Use this method to translate to a higher-level message. Usually,
some callback will be made upon the receipt of each complete protocol
message.
Parameters:
data -
a string of indeterminate length. Please keep in mind that you
will probably need to buffer some data, as partial (or multiple)
protocol messages may be received! I recommend that unit tests
for protocols call through to this method with differing chunk
sizes, down to one byte at a time.