diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:38:33 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:38:33 +0000 |
commit | 584cd5cbd7be997400ccb8db24ae5410b0b88117 (patch) | |
tree | 083e5f1f48d019e0f07b96fef7179483df53c823 /third_party/tlslite | |
parent | f5b16fed647e941aa66933178da85db2860d639b (diff) | |
download | chromium_src-584cd5cbd7be997400ccb8db24ae5410b0b88117.zip chromium_src-584cd5cbd7be997400ccb8db24ae5410b0b88117.tar.gz chromium_src-584cd5cbd7be997400ccb8db24ae5410b0b88117.tar.bz2 |
Add third_party to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/tlslite')
85 files changed, 13337 insertions, 0 deletions
diff --git a/third_party/tlslite/README.google b/third_party/tlslite/README.google new file mode 100644 index 0000000..e5cf9bc --- /dev/null +++ b/third_party/tlslite/README.google @@ -0,0 +1,7 @@ +This library was downloaded from http://trevp.net/tlslite/. + +The code is public domain. + +tlslite/TLSRecordLayer.py was changed to force the socket to be closed when the +SSL connection is closed. This is is necessary at this point since WinHTTP does +not seem to react to the SSL close notify. diff --git a/third_party/tlslite/google.patch b/third_party/tlslite/google.patch new file mode 100644 index 0000000..f5a7401 --- /dev/null +++ b/third_party/tlslite/google.patch @@ -0,0 +1,18 @@ +--- tlslite/TLSRecordLayer.py 2008-02-27 15:45:16.159680300 -0800 ++++ tlslite_google/TLSRecordLayer.py 2008-02-29 14:54:36.515625000 -0800 +@@ -324,8 +324,10 @@ + alert = None + # Forcing a shutdown as WinHTTP does not seem to be + # responsive to the close notify. ++ prevCloseSocket = self.closeSocket + self.closeSocket = True + self._shutdown(True) ++ self.closeSocket = prevCloseSocket + while not alert: + for result in self._getMsg((ContentType.alert, \ + ContentType.application_data)): +@@ -1124,4 +1126,3 @@ + imac_sha.digest()).digest() + + return stringToBytes(md5Str + shaStr) +- diff --git a/third_party/tlslite/installers/tlslite-0.3.8.win32-py2.3.exe b/third_party/tlslite/installers/tlslite-0.3.8.win32-py2.3.exe Binary files differnew file mode 100644 index 0000000..30320fd --- /dev/null +++ b/third_party/tlslite/installers/tlslite-0.3.8.win32-py2.3.exe diff --git a/third_party/tlslite/installers/tlslite-0.3.8.win32-py2.4.exe b/third_party/tlslite/installers/tlslite-0.3.8.win32-py2.4.exe Binary files differnew file mode 100644 index 0000000..fcc1968 --- /dev/null +++ b/third_party/tlslite/installers/tlslite-0.3.8.win32-py2.4.exe diff --git a/third_party/tlslite/make_release.py b/third_party/tlslite/make_release.py new file mode 100644 index 0000000..d289879 --- /dev/null +++ b/third_party/tlslite/make_release.py @@ -0,0 +1,61 @@ + +#When run on (my) windows box, this builds and cleans everything in +#preparation for a release. + +import os +import sys + +#Replace version strings +if len(sys.argv)>1: + oldVersion = sys.argv[1] + newVersion = sys.argv[2] + query = raw_input("Replace %s with %s?: " % (oldVersion, newVersion)) + if query == "y": + #First, scan through and make sure the replacement is possible + for filename in ("setup.py", "tlslite\\__init__.py", "scripts\\tls.py", "scripts\\tlsdb.py"): + s = open(filename, "rU").read() + x = s.count(oldVersion) + if filename.endswith("__init__.py"): + if x != 2: + print "Error, old version appears in %s %s times" % (filename, x) + sys.exit() + else: + if x != 1: + print "Error, old version appears in %s %s times" % (filename, x) + sys.exit() + + #Then perform it + for filename in ("setup.py", "tlslite\\__init__.py", "scripts\\tls.py", "scripts\\tlsdb.py"): + os.system("copy %s .." % filename) #save a backup copy in case something goes awry + s = open(filename, "r").read() + f = open(filename, "w") + f.write(s.replace(oldVersion, newVersion)) + f.close() + + +#Make windows installers +os.system("del installers\*.exe") + +#Python 2.3 +os.system("rmdir build /s /q") +os.system("python23 setup.py bdist_wininst -o") +os.system("copy dist\* installers") + +#Python 2.4 +os.system("rmdir build /s /q") +os.system("python24 setup.py bdist_wininst -o") +os.system("copy dist\* installers") + + +#Make documentation +os.system("python23 c:\\devtools\\python23\\scripts\\epydoc.py --html -o docs tlslite") + +#Delete excess files +os.system("del tlslite\\*.pyc") +os.system("del tlslite\\utils\\*.pyc") +os.system("del tlslite\\integration\\*.pyc") +os.system("rmdir build /s /q") +os.system("rmdir dist /s /q") + + + diff --git a/third_party/tlslite/readme.txt b/third_party/tlslite/readme.txt new file mode 100644 index 0000000..c1f1b38 --- /dev/null +++ b/third_party/tlslite/readme.txt @@ -0,0 +1,815 @@ + +tlslite version 0.3.8 February 21, 2005 +Trevor Perrin <trevp at trevp.net> +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/ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third_party/tlslite/scripts/tls.py b/third_party/tlslite/scripts/tls.py new file mode 100644 index 0000000..fa2c663 --- /dev/null +++ b/third_party/tlslite/scripts/tls.py @@ -0,0 +1,1074 @@ +#! python + +import sys +import os +import os.path +import socket +import thread +import time +import httplib +import BaseHTTPServer +import SimpleHTTPServer + + +try: + from cryptoIDlib.api import * + cryptoIDlibLoaded = True +except: + cryptoIDlibLoaded = False + +if __name__ != "__main__": + raise "This must be run as a command, not used as a module!" + +#import tlslite +#from tlslite.constants import AlertDescription, Fault + +#from tlslite.utils.jython_compat import formatExceptionTrace +#from tlslite.X509 import X509, X509CertChain + +from tlslite.api import * + +def parsePrivateKey(s): + try: + return parsePEMKey(s, private=True) + except Exception, e: + print e + return parseXMLKey(s, private=True) + + +def clientTest(address, dir): + + #Split address into hostname/port tuple + address = address.split(":") + if len(address)==1: + address.append("4443") + address = ( address[0], int(address[1]) ) + + def connect(): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if hasattr(sock, 'settimeout'): #It's a python 2.3 feature + sock.settimeout(5) + sock.connect(address) + c = TLSConnection(sock) + return c + + test = 0 + + badFault = False + + print "Test 1 - good shared key" + connection = connect() + connection.handshakeClientSharedKey("shared", "key") + connection.close() + connection.sock.close() + + print "Test 2 - shared key faults" + for fault in Fault.clientSharedKeyFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientSharedKey("shared", "key") + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + print "Test 3 - good SRP" + connection = connect() + connection.handshakeClientSRP("test", "password") + connection.close() + + print "Test 4 - SRP faults" + for fault in Fault.clientSrpFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientSRP("test", "password") + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + print "Test 5 - good SRP: unknown_srp_username idiom" + def srpCallback(): + return ("test", "password") + connection = connect() + connection.handshakeClientUnknown(srpCallback=srpCallback) + connection.close() + connection.sock.close() + + print "Test 6 - good SRP: with X.509 certificate" + connection = connect() + connection.handshakeClientSRP("test", "password") + assert(isinstance(connection.session.serverCertChain, X509CertChain)) + connection.close() + connection.sock.close() + + print "Test 7 - X.509 with SRP faults" + for fault in Fault.clientSrpFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientSRP("test", "password") + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + if cryptoIDlibLoaded: + print "Test 8 - good SRP: with cryptoID certificate chain" + connection = connect() + connection.handshakeClientSRP("test", "password") + assert(isinstance(connection.session.serverCertChain, CertChain)) + if not (connection.session.serverCertChain.validate()): + print connection.session.serverCertChain.validate(listProblems=True) + + connection.close() + connection.sock.close() + + print "Test 9 - CryptoID with SRP faults" + for fault in Fault.clientSrpFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientSRP("test", "password") + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + print "Test 10 - good X509" + connection = connect() + connection.handshakeClientCert() + assert(isinstance(connection.session.serverCertChain, X509CertChain)) + connection.close() + connection.sock.close() + + print "Test 10.a - good X509, SSLv3" + connection = connect() + settings = HandshakeSettings() + settings.minVersion = (3,0) + settings.maxVersion = (3,0) + connection.handshakeClientCert(settings=settings) + assert(isinstance(connection.session.serverCertChain, X509CertChain)) + connection.close() + connection.sock.close() + + print "Test 11 - X.509 faults" + for fault in Fault.clientNoAuthFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientCert() + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + if cryptoIDlibLoaded: + print "Test 12 - good cryptoID" + connection = connect() + connection.handshakeClientCert() + assert(isinstance(connection.session.serverCertChain, CertChain)) + assert(connection.session.serverCertChain.validate()) + connection.close() + connection.sock.close() + + print "Test 13 - cryptoID faults" + for fault in Fault.clientNoAuthFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientCert() + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + print "Test 14 - good mutual X509" + x509Cert = X509().parse(open(os.path.join(dir, "clientX509Cert.pem")).read()) + x509Chain = X509CertChain([x509Cert]) + s = open(os.path.join(dir, "clientX509Key.pem")).read() + x509Key = parsePEMKey(s, private=True) + + connection = connect() + connection.handshakeClientCert(x509Chain, x509Key) + assert(isinstance(connection.session.serverCertChain, X509CertChain)) + connection.close() + connection.sock.close() + + print "Test 14.a - good mutual X509, SSLv3" + connection = connect() + settings = HandshakeSettings() + settings.minVersion = (3,0) + settings.maxVersion = (3,0) + connection.handshakeClientCert(x509Chain, x509Key, settings=settings) + assert(isinstance(connection.session.serverCertChain, X509CertChain)) + connection.close() + connection.sock.close() + + print "Test 15 - mutual X.509 faults" + for fault in Fault.clientCertFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientCert(x509Chain, x509Key) + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + if cryptoIDlibLoaded: + print "Test 16 - good mutual cryptoID" + cryptoIDChain = CertChain().parse(open(os.path.join(dir, "serverCryptoIDChain.xml"), "r").read()) + cryptoIDKey = parseXMLKey(open(os.path.join(dir, "serverCryptoIDKey.xml"), "r").read(), private=True) + + connection = connect() + connection.handshakeClientCert(cryptoIDChain, cryptoIDKey) + assert(isinstance(connection.session.serverCertChain, CertChain)) + assert(connection.session.serverCertChain.validate()) + connection.close() + connection.sock.close() + + print "Test 17 - mutual cryptoID faults" + for fault in Fault.clientCertFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeClientCert(cryptoIDChain, cryptoIDKey) + print " Good Fault %s" % (Fault.faultNames[fault]) + except TLSFaultError, e: + print " BAD FAULT %s: %s" % (Fault.faultNames[fault], str(e)) + badFault = True + connection.sock.close() + + print "Test 18 - good SRP, prepare to resume..." + connection = connect() + connection.handshakeClientSRP("test", "password") + connection.close() + connection.sock.close() + session = connection.session + + print "Test 19 - resumption" + connection = connect() + connection.handshakeClientSRP("test", "garbage", session=session) + #Don't close! -- see below + + print "Test 20 - invalidated resumption" + connection.sock.close() #Close the socket without a close_notify! + connection = connect() + try: + connection.handshakeClientSRP("test", "garbage", session=session) + assert() + except TLSRemoteAlert, alert: + if alert.description != AlertDescription.bad_record_mac: + raise + connection.sock.close() + + print "Test 21 - HTTPS test X.509" + address = address[0], address[1]+1 + if hasattr(socket, "timeout"): + timeoutEx = socket.timeout + else: + timeoutEx = socket.error + while 1: + try: + time.sleep(2) + htmlBody = open(os.path.join(dir, "index.html")).read() + fingerprint = None + for y in range(2): + h = HTTPTLSConnection(\ + address[0], address[1], x509Fingerprint=fingerprint) + for x in range(3): + h.request("GET", "/index.html") + r = h.getresponse() + assert(r.status == 200) + s = r.read() + assert(s == htmlBody) + fingerprint = h.tlsSession.serverCertChain.getFingerprint() + assert(fingerprint) + time.sleep(2) + break + except timeoutEx: + print "timeout, retrying..." + pass + + if cryptoIDlibLoaded: + print "Test 21a - HTTPS test SRP+cryptoID" + address = address[0], address[1]+1 + if hasattr(socket, "timeout"): + timeoutEx = socket.timeout + else: + timeoutEx = socket.error + while 1: + try: + time.sleep(2) #Time to generate key and cryptoID + htmlBody = open(os.path.join(dir, "index.html")).read() + fingerprint = None + protocol = None + for y in range(2): + h = HTTPTLSConnection(\ + address[0], address[1], + username="test", password="password", + cryptoID=fingerprint, protocol=protocol) + for x in range(3): + h.request("GET", "/index.html") + r = h.getresponse() + assert(r.status == 200) + s = r.read() + assert(s == htmlBody) + fingerprint = h.tlsSession.serverCertChain.cryptoID + assert(fingerprint) + protocol = "urn:whatever" + time.sleep(2) + break + except timeoutEx: + print "timeout, retrying..." + pass + + address = address[0], address[1]+1 + + implementations = [] + if cryptlibpyLoaded: + implementations.append("cryptlib") + if m2cryptoLoaded: + implementations.append("openssl") + if pycryptoLoaded: + implementations.append("pycrypto") + implementations.append("python") + + print "Test 22 - different ciphers" + for implementation in implementations: + for cipher in ["aes128", "aes256", "rc4"]: + + print "Test 22:", + connection = connect() + + settings = HandshakeSettings() + settings.cipherNames = [cipher] + settings.cipherImplementations = [implementation, "python"] + connection.handshakeClientSharedKey("shared", "key", settings=settings) + print ("%s %s" % (connection.getCipherName(), connection.getCipherImplementation())) + + connection.write("hello") + h = connection.read(min=5, max=5) + assert(h == "hello") + connection.close() + connection.sock.close() + + print "Test 23 - throughput test" + for implementation in implementations: + for cipher in ["aes128", "aes256", "3des", "rc4"]: + if cipher == "3des" and implementation not in ("openssl", "cryptlib", "pycrypto"): + continue + + print "Test 23:", + connection = connect() + + settings = HandshakeSettings() + settings.cipherNames = [cipher] + settings.cipherImplementations = [implementation, "python"] + connection.handshakeClientSharedKey("shared", "key", settings=settings) + print ("%s %s:" % (connection.getCipherName(), connection.getCipherImplementation())), + + startTime = time.clock() + connection.write("hello"*10000) + h = connection.read(min=50000, max=50000) + stopTime = time.clock() + print "100K exchanged at rate of %d bytes/sec" % int(100000/(stopTime-startTime)) + + assert(h == "hello"*10000) + connection.close() + connection.sock.close() + + print "Test 24 - Internet servers test" + try: + i = IMAP4_TLS("cyrus.andrew.cmu.edu") + i.login("anonymous", "anonymous@anonymous.net") + i.logout() + print "Test 24: IMAP4 good" + p = POP3_TLS("pop.gmail.com") + p.quit() + print "Test 24: POP3 good" + except socket.error, e: + print "Non-critical error: socket error trying to reach internet server: ", e + + if not badFault: + print "Test succeeded" + else: + print "Test failed" + + +def serverTest(address, dir): + #Split address into hostname/port tuple + address = address.split(":") + if len(address)==1: + address.append("4443") + address = ( address[0], int(address[1]) ) + + #Connect to server + lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + lsock.bind(address) + lsock.listen(5) + + def connect(): + return TLSConnection(lsock.accept()[0]) + + print "Test 1 - good shared key" + sharedKeyDB = SharedKeyDB() + sharedKeyDB["shared"] = "key" + sharedKeyDB["shared2"] = "key2" + connection = connect() + connection.handshakeServer(sharedKeyDB=sharedKeyDB) + connection.close() + connection.sock.close() + + print "Test 2 - shared key faults" + for fault in Fault.clientSharedKeyFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(sharedKeyDB=sharedKeyDB) + assert() + except: + pass + connection.sock.close() + + print "Test 3 - good SRP" + #verifierDB = tlslite.VerifierDB(os.path.join(dir, "verifierDB")) + #verifierDB.open() + verifierDB = VerifierDB() + verifierDB.create() + entry = VerifierDB.makeVerifier("test", "password", 1536) + verifierDB["test"] = entry + + connection = connect() + connection.handshakeServer(verifierDB=verifierDB) + connection.close() + connection.sock.close() + + print "Test 4 - SRP faults" + for fault in Fault.clientSrpFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(verifierDB=verifierDB) + assert() + except: + pass + connection.sock.close() + + print "Test 5 - good SRP: unknown_srp_username idiom" + connection = connect() + connection.handshakeServer(verifierDB=verifierDB) + connection.close() + connection.sock.close() + + print "Test 6 - good SRP: with X.509 cert" + x509Cert = X509().parse(open(os.path.join(dir, "serverX509Cert.pem")).read()) + x509Chain = X509CertChain([x509Cert]) + s = open(os.path.join(dir, "serverX509Key.pem")).read() + x509Key = parsePEMKey(s, private=True) + + connection = connect() + connection.handshakeServer(verifierDB=verifierDB, \ + certChain=x509Chain, privateKey=x509Key) + connection.close() + connection.sock.close() + + print "Test 7 - X.509 with SRP faults" + for fault in Fault.clientSrpFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(verifierDB=verifierDB, \ + certChain=x509Chain, privateKey=x509Key) + assert() + except: + pass + connection.sock.close() + + if cryptoIDlibLoaded: + print "Test 8 - good SRP: with cryptoID certs" + cryptoIDChain = CertChain().parse(open(os.path.join(dir, "serverCryptoIDChain.xml"), "r").read()) + cryptoIDKey = parseXMLKey(open(os.path.join(dir, "serverCryptoIDKey.xml"), "r").read(), private=True) + connection = connect() + connection.handshakeServer(verifierDB=verifierDB, \ + certChain=cryptoIDChain, privateKey=cryptoIDKey) + connection.close() + connection.sock.close() + + print "Test 9 - cryptoID with SRP faults" + for fault in Fault.clientSrpFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(verifierDB=verifierDB, \ + certChain=cryptoIDChain, privateKey=cryptoIDKey) + assert() + except: + pass + connection.sock.close() + + print "Test 10 - good X.509" + connection = connect() + connection.handshakeServer(certChain=x509Chain, privateKey=x509Key) + connection.close() + connection.sock.close() + + print "Test 10.a - good X.509, SSL v3" + connection = connect() + settings = HandshakeSettings() + settings.minVersion = (3,0) + settings.maxVersion = (3,0) + connection.handshakeServer(certChain=x509Chain, privateKey=x509Key, settings=settings) + connection.close() + connection.sock.close() + + print "Test 11 - X.509 faults" + for fault in Fault.clientNoAuthFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(certChain=x509Chain, privateKey=x509Key) + assert() + except: + pass + connection.sock.close() + + if cryptoIDlibLoaded: + print "Test 12 - good cryptoID" + connection = connect() + connection.handshakeServer(certChain=cryptoIDChain, privateKey=cryptoIDKey) + connection.close() + connection.sock.close() + + print "Test 13 - cryptoID faults" + for fault in Fault.clientNoAuthFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(certChain=cryptoIDChain, privateKey=cryptoIDKey) + assert() + except: + pass + connection.sock.close() + + print "Test 14 - good mutual X.509" + connection = connect() + connection.handshakeServer(certChain=x509Chain, privateKey=x509Key, reqCert=True) + assert(isinstance(connection.session.serverCertChain, X509CertChain)) + connection.close() + connection.sock.close() + + print "Test 14a - good mutual X.509, SSLv3" + connection = connect() + settings = HandshakeSettings() + settings.minVersion = (3,0) + settings.maxVersion = (3,0) + connection.handshakeServer(certChain=x509Chain, privateKey=x509Key, reqCert=True, settings=settings) + assert(isinstance(connection.session.serverCertChain, X509CertChain)) + connection.close() + connection.sock.close() + + print "Test 15 - mutual X.509 faults" + for fault in Fault.clientCertFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(certChain=x509Chain, privateKey=x509Key, reqCert=True) + assert() + except: + pass + connection.sock.close() + + if cryptoIDlibLoaded: + print "Test 16 - good mutual cryptoID" + connection = connect() + connection.handshakeServer(certChain=cryptoIDChain, privateKey=cryptoIDKey, reqCert=True) + assert(isinstance(connection.session.serverCertChain, CertChain)) + assert(connection.session.serverCertChain.validate()) + connection.close() + connection.sock.close() + + print "Test 17 - mutual cryptoID faults" + for fault in Fault.clientCertFaults + Fault.genericFaults: + connection = connect() + connection.fault = fault + try: + connection.handshakeServer(certChain=cryptoIDChain, privateKey=cryptoIDKey, reqCert=True) + assert() + except: + pass + connection.sock.close() + + print "Test 18 - good SRP, prepare to resume" + sessionCache = SessionCache() + connection = connect() + connection.handshakeServer(verifierDB=verifierDB, sessionCache=sessionCache) + connection.close() + connection.sock.close() + + print "Test 19 - resumption" + connection = connect() + connection.handshakeServer(verifierDB=verifierDB, sessionCache=sessionCache) + #Don't close! -- see next test + + print "Test 20 - invalidated resumption" + try: + connection.read(min=1, max=1) + assert() #Client is going to close the socket without a close_notify + except TLSAbruptCloseError, e: + pass + connection = connect() + try: + connection.handshakeServer(verifierDB=verifierDB, sessionCache=sessionCache) + except TLSLocalAlert, alert: + if alert.description != AlertDescription.bad_record_mac: + raise + connection.sock.close() + + print "Test 21 - HTTPS test X.509" + + #Close the current listening socket + lsock.close() + + #Create and run an HTTP Server using TLSSocketServerMixIn + class MyHTTPServer(TLSSocketServerMixIn, + BaseHTTPServer.HTTPServer): + def handshake(self, tlsConnection): + tlsConnection.handshakeServer(certChain=x509Chain, privateKey=x509Key) + return True + cd = os.getcwd() + os.chdir(dir) + address = address[0], address[1]+1 + httpd = MyHTTPServer(address, SimpleHTTPServer.SimpleHTTPRequestHandler) + for x in range(6): + httpd.handle_request() + httpd.server_close() + cd = os.chdir(cd) + + if cryptoIDlibLoaded: + print "Test 21a - HTTPS test SRP+cryptoID" + + #Create and run an HTTP Server using TLSSocketServerMixIn + class MyHTTPServer(TLSSocketServerMixIn, + BaseHTTPServer.HTTPServer): + def handshake(self, tlsConnection): + tlsConnection.handshakeServer(certChain=cryptoIDChain, privateKey=cryptoIDKey, + verifierDB=verifierDB) + return True + cd = os.getcwd() + os.chdir(dir) + address = address[0], address[1]+1 + httpd = MyHTTPServer(address, SimpleHTTPServer.SimpleHTTPRequestHandler) + for x in range(6): + httpd.handle_request() + httpd.server_close() + cd = os.chdir(cd) + + #Re-connect the listening socket + lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + address = address[0], address[1]+1 + lsock.bind(address) + lsock.listen(5) + + def connect(): + return TLSConnection(lsock.accept()[0]) + + implementations = [] + if cryptlibpyLoaded: + implementations.append("cryptlib") + if m2cryptoLoaded: + implementations.append("openssl") + if pycryptoLoaded: + implementations.append("pycrypto") + implementations.append("python") + + print "Test 22 - different ciphers" + for implementation in ["python"] * len(implementations): + for cipher in ["aes128", "aes256", "rc4"]: + + print "Test 22:", + connection = connect() + + settings = HandshakeSettings() + settings.cipherNames = [cipher] + settings.cipherImplementations = [implementation, "python"] + + connection.handshakeServer(sharedKeyDB=sharedKeyDB, settings=settings) + print connection.getCipherName(), connection.getCipherImplementation() + h = connection.read(min=5, max=5) + assert(h == "hello") + connection.write(h) + connection.close() + connection.sock.close() + + print "Test 23 - throughput test" + for implementation in implementations: + for cipher in ["aes128", "aes256", "3des", "rc4"]: + if cipher == "3des" and implementation not in ("openssl", "cryptlib", "pycrypto"): + continue + + print "Test 23:", + connection = connect() + + settings = HandshakeSettings() + settings.cipherNames = [cipher] + settings.cipherImplementations = [implementation, "python"] + + connection.handshakeServer(sharedKeyDB=sharedKeyDB, settings=settings) + print connection.getCipherName(), connection.getCipherImplementation() + h = connection.read(min=50000, max=50000) + assert(h == "hello"*10000) + connection.write(h) + connection.close() + connection.sock.close() + + print "Test succeeded" + + + + + + + + + + + + +if len(sys.argv) == 1 or (len(sys.argv)==2 and sys.argv[1].lower().endswith("help")): + print "" + print "Version: 0.3.8" + print "" + print "RNG: %s" % prngName + print "" + print "Modules:" + if cryptlibpyLoaded: + print " cryptlib_py : Loaded" + else: + print " cryptlib_py : Not Loaded" + if m2cryptoLoaded: + print " M2Crypto : Loaded" + else: + print " M2Crypto : Not Loaded" + if pycryptoLoaded: + print " pycrypto : Loaded" + else: + print " pycrypto : Not Loaded" + if gmpyLoaded: + print " GMPY : Loaded" + else: + print " GMPY : Not Loaded" + if cryptoIDlibLoaded: + print " cryptoIDlib : Loaded" + else: + print " cryptoIDlib : Not Loaded" + print "" + print "Commands:" + print "" + print " clientcert <server> [<chain> <key>]" + print " clientsharedkey <server> <user> <pass>" + print " clientsrp <server> <user> <pass>" + print " clienttest <server> <dir>" + print "" + print " serversrp <server> <verifierDB>" + print " servercert <server> <chain> <key> [req]" + print " serversrpcert <server> <verifierDB> <chain> <key>" + print " serversharedkey <server> <sharedkeyDB>" + print " servertest <server> <dir>" + sys.exit() + +cmd = sys.argv[1].lower() + +class Args: + def __init__(self, argv): + self.argv = argv + def get(self, index): + if len(self.argv)<=index: + raise SyntaxError("Not enough arguments") + return self.argv[index] + def getLast(self, index): + if len(self.argv)>index+1: + raise SyntaxError("Too many arguments") + return self.get(index) + +args = Args(sys.argv) + +def reformatDocString(s): + lines = s.splitlines() + newLines = [] + for line in lines: + newLines.append(" " + line.strip()) + return "\n".join(newLines) + +try: + if cmd == "clienttest": + address = args.get(2) + dir = args.getLast(3) + clientTest(address, dir) + sys.exit() + + elif cmd.startswith("client"): + address = args.get(2) + + #Split address into hostname/port tuple + address = address.split(":") + if len(address)==1: + address.append("4443") + address = ( address[0], int(address[1]) ) + + def connect(): + #Connect to server + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if hasattr(sock, "settimeout"): + sock.settimeout(5) + sock.connect(address) + + #Instantiate TLSConnections + return TLSConnection(sock) + + try: + if cmd == "clientsrp": + username = args.get(3) + password = args.getLast(4) + connection = connect() + start = time.clock() + connection.handshakeClientSRP(username, password) + elif cmd == "clientsharedkey": + username = args.get(3) + password = args.getLast(4) + connection = connect() + start = time.clock() + connection.handshakeClientSharedKey(username, password) + elif cmd == "clientcert": + certChain = None + privateKey = None + if len(sys.argv) > 3: + certFilename = args.get(3) + keyFilename = args.getLast(4) + + s1 = open(certFilename, "rb").read() + s2 = open(keyFilename, "rb").read() + + #Try to create cryptoID cert chain + if cryptoIDlibLoaded: + try: + certChain = CertChain().parse(s1) + privateKey = parsePrivateKey(s2) + except: + certChain = None + privateKey = None + + #Try to create X.509 cert chain + if not certChain: + x509 = X509() + x509.parse(s1) + certChain = X509CertChain([x509]) + privateKey = parsePrivateKey(s2) + + connection = connect() + start = time.clock() + connection.handshakeClientCert(certChain, privateKey) + else: + raise SyntaxError("Unknown command") + + except TLSLocalAlert, a: + if a.description == AlertDescription.bad_record_mac: + if cmd == "clientsharedkey": + print "Bad sharedkey password" + else: + raise + elif a.description == AlertDescription.user_canceled: + print str(a) + else: + raise + sys.exit() + except TLSRemoteAlert, a: + if a.description == AlertDescription.unknown_srp_username: + if cmd == "clientsrp": + print "Unknown username" + else: + raise + elif a.description == AlertDescription.bad_record_mac: + if cmd == "clientsrp": + print "Bad username or password" + else: + raise + elif a.description == AlertDescription.handshake_failure: + print "Unable to negotiate mutually acceptable parameters" + else: + raise + sys.exit() + + stop = time.clock() + print "Handshake success" + print " Handshake time: %.4f seconds" % (stop - start) + print " Version: %s.%s" % connection.version + print " Cipher: %s %s" % (connection.getCipherName(), connection.getCipherImplementation()) + if connection.session.srpUsername: + print " Client SRP username: %s" % connection.session.srpUsername + if connection.session.sharedKeyUsername: + print " Client shared key username: %s" % connection.session.sharedKeyUsername + if connection.session.clientCertChain: + print " Client fingerprint: %s" % connection.session.clientCertChain.getFingerprint() + if connection.session.serverCertChain: + print " Server fingerprint: %s" % connection.session.serverCertChain.getFingerprint() + connection.close() + connection.sock.close() + + elif cmd.startswith("server"): + address = args.get(2) + + #Split address into hostname/port tuple + address = address.split(":") + if len(address)==1: + address.append("4443") + address = ( address[0], int(address[1]) ) + + verifierDBFilename = None + sharedKeyDBFilename = None + certFilename = None + keyFilename = None + sharedKeyDB = None + reqCert = False + + if cmd == "serversrp": + verifierDBFilename = args.getLast(3) + elif cmd == "servercert": + certFilename = args.get(3) + keyFilename = args.get(4) + if len(sys.argv)>=6: + req = args.getLast(5) + if req.lower() != "req": + raise SyntaxError() + reqCert = True + elif cmd == "serversrpcert": + verifierDBFilename = args.get(3) + certFilename = args.get(4) + keyFilename = args.getLast(5) + elif cmd == "serversharedkey": + sharedKeyDBFilename = args.getLast(3) + elif cmd == "servertest": + address = args.get(2) + dir = args.getLast(3) + serverTest(address, dir) + sys.exit() + + verifierDB = None + if verifierDBFilename: + verifierDB = VerifierDB(verifierDBFilename) + verifierDB.open() + + sharedKeyDB = None + if sharedKeyDBFilename: + sharedKeyDB = SharedKeyDB(sharedKeyDBFilename) + sharedKeyDB.open() + + certChain = None + privateKey = None + if certFilename: + s1 = open(certFilename, "rb").read() + s2 = open(keyFilename, "rb").read() + + #Try to create cryptoID cert chain + if cryptoIDlibLoaded: + try: + certChain = CertChain().parse(s1) + privateKey = parsePrivateKey(s2) + except: + certChain = None + privateKey = None + + #Try to create X.509 cert chain + if not certChain: + x509 = X509() + x509.parse(s1) + certChain = X509CertChain([x509]) + privateKey = parsePrivateKey(s2) + + + + #Create handler function - performs handshake, then echos all bytes received + def handler(sock): + try: + connection = TLSConnection(sock) + settings = HandshakeSettings() + connection.handshakeServer(sharedKeyDB=sharedKeyDB, verifierDB=verifierDB, \ + certChain=certChain, privateKey=privateKey, \ + reqCert=reqCert, settings=settings) + print "Handshake success" + print " Version: %s.%s" % connection.version + print " Cipher: %s %s" % (connection.getCipherName(), connection.getCipherImplementation()) + if connection.session.srpUsername: + print " Client SRP username: %s" % connection.session.srpUsername + if connection.session.sharedKeyUsername: + print " Client shared key username: %s" % connection.session.sharedKeyUsername + if connection.session.clientCertChain: + print " Client fingerprint: %s" % connection.session.clientCertChain.getFingerprint() + if connection.session.serverCertChain: + print " Server fingerprint: %s" % connection.session.serverCertChain.getFingerprint() + + s = "" + while 1: + newS = connection.read() + if not newS: + break + s += newS + if s[-1]=='\n': + connection.write(s) + s = "" + except TLSLocalAlert, a: + if a.description == AlertDescription.unknown_srp_username: + print "Unknown SRP username" + elif a.description == AlertDescription.bad_record_mac: + if cmd == "serversrp" or cmd == "serversrpcert": + print "Bad SRP password for:", connection.allegedSrpUsername + else: + raise + elif a.description == AlertDescription.handshake_failure: + print "Unable to negotiate mutually acceptable parameters" + else: + raise + except TLSRemoteAlert, a: + if a.description == AlertDescription.bad_record_mac: + if cmd == "serversharedkey": + print "Bad sharedkey password for:", connection.allegedSharedKeyUsername + else: + raise + elif a.description == AlertDescription.user_canceled: + print "Handshake cancelled" + elif a.description == AlertDescription.handshake_failure: + print "Unable to negotiate mutually acceptable parameters" + elif a.description == AlertDescription.close_notify: + pass + else: + raise + + #Run multi-threaded server + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(address) + sock.listen(5) + while 1: + (newsock, cliAddress) = sock.accept() + thread.start_new_thread(handler, (newsock,)) + + + else: + print "Bad command: '%s'" % cmd +except TLSRemoteAlert, a: + print str(a) + raise + + + + + diff --git a/third_party/tlslite/scripts/tlsdb.py b/third_party/tlslite/scripts/tlsdb.py new file mode 100644 index 0000000..bdd524e --- /dev/null +++ b/third_party/tlslite/scripts/tlsdb.py @@ -0,0 +1,194 @@ +#! python + +import sys +import os +import socket +import thread +import math + +try: + import cryptoIDlib + cryptoIDlibLoaded = True +except: + cryptoIDlibLoaded = False + + +if __name__ != "__main__": + raise "This must be run as a command, not used as a module!" + + +from tlslite.api import * + +if len(sys.argv) == 1 or (len(sys.argv)==2 and sys.argv[1].lower().endswith("help")): + print "" + print "Version: 0.3.8" + print "" + print "RNG: %s" % prngName + print "" + print "Modules:" + if cryptlibpyLoaded: + print " cryptlib_py : Loaded" + else: + print " cryptlib_py : Not Loaded" + if m2cryptoLoaded: + print " M2Crypto : Loaded" + else: + print " M2Crypto : Not Loaded" + if pycryptoLoaded: + print " pycrypto : Loaded" + else: + print " pycrypto : Not Loaded" + if gmpyLoaded: + print " GMPY : Loaded" + else: + print " GMPY : Not Loaded" + if cryptoIDlibLoaded: + print " cryptoIDlib : Loaded" + else: + print " cryptoIDlib : Not Loaded" + print "" + print "Commands:" + print "" + print " createsrp <db>" + print " createsharedkey <db>" + print "" + print " add <db> <user> <pass> [<bits>]" + print " del <db> <user>" + print " check <db> <user> [<pass>]" + print " list <db>" + sys.exit() + +cmd = sys.argv[1].lower() + +class Args: + def __init__(self, argv): + self.argv = argv + def get(self, index): + if len(self.argv)<=index: + raise SyntaxError("Not enough arguments") + return self.argv[index] + def getLast(self, index): + if len(self.argv)>index+1: + raise SyntaxError("Too many arguments") + return self.get(index) + +args = Args(sys.argv) + +def reformatDocString(s): + lines = s.splitlines() + newLines = [] + for line in lines: + newLines.append(" " + line.strip()) + return "\n".join(newLines) + +try: + if cmd == "help": + command = args.getLast(2).lower() + if command == "valid": + print "" + else: + print "Bad command: '%s'" % command + + elif cmd == "createsrp": + dbName = args.get(2) + + db = VerifierDB(dbName) + db.create() + + elif cmd == "createsharedkey": + dbName = args.getLast(2) + + db = SharedKeyDB(dbName) + db.create() + + elif cmd == "add": + dbName = args.get(2) + username = args.get(3) + password = args.get(4) + + try: + db = VerifierDB(dbName) + db.open() + if username in db: + print "User already in database!" + sys.exit() + bits = int(args.getLast(5)) + N, g, salt, verifier = VerifierDB.makeVerifier(username, password, bits) + db[username] = N, g, salt, verifier + except ValueError: + db = SharedKeyDB(dbName) + db.open() + if username in db: + print "User already in database!" + sys.exit() + args.getLast(4) + db[username] = password + + elif cmd == "del": + dbName = args.get(2) + username = args.getLast(3) + + try: + db = VerifierDB(dbName) + db.open() + except ValueError: + db = SharedKeyDB(dbName) + db.open() + + del(db[username]) + + elif cmd == "check": + dbName = args.get(2) + username = args.get(3) + if len(sys.argv)>=5: + password = args.getLast(4) + else: + password = None + + try: + db = VerifierDB(dbName) + db.open() + except ValueError: + db = SharedKeyDB(dbName) + db.open() + + try: + db[username] + print "Username exists" + + if password: + if db.check(username, password): + print "Password is correct" + else: + print "Password is wrong" + except KeyError: + print "Username does not exist" + sys.exit() + + elif cmd == "list": + dbName = args.get(2) + + try: + db = VerifierDB(dbName) + db.open() + except ValueError: + db = SharedKeyDB(dbName) + db.open() + + if isinstance(db, VerifierDB): + print "Verifier Database" + def numBits(n): + if n==0: + return 0 + return int(math.floor(math.log(n, 2))+1) + for username in db.keys(): + N, g, s, v = db[username] + print numBits(N), username + else: + print "Shared Key Database" + for username in db.keys(): + print username + else: + print "Bad command: '%s'" % cmd +except: + raise diff --git a/third_party/tlslite/setup.py b/third_party/tlslite/setup.py new file mode 100644 index 0000000..e3417c4 --- /dev/null +++ b/third_party/tlslite/setup.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +import sys +from distutils.core import setup, Extension + +if sys.version_info < (2, 2): + raise AssertionError("Python 2.2 or later required") + +if sys.platform == "win32": + ext = Extension("tlslite.utils.win32prng", + sources=["tlslite/utils/win32prng.c"], + libraries=["advapi32"]) + exts = [ext] +else: + exts = None + +setup(name="tlslite", + version="0.3.8", + author="Trevor Perrin", + author_email="trevp@trevp.net", + url="http://trevp.net/tlslite/", + description="tlslite implements SSL and TLS with SRP, shared-keys, cryptoID, or X.509 authentication.", + license="public domain", + scripts=["scripts/tls.py", "scripts/tlsdb.py"], + packages=["tlslite", "tlslite.utils", "tlslite.integration"], + ext_modules=exts) diff --git a/third_party/tlslite/test/clientCryptoIDChain.xml b/third_party/tlslite/test/clientCryptoIDChain.xml new file mode 100644 index 0000000..aea9e19 --- /dev/null +++ b/third_party/tlslite/test/clientCryptoIDChain.xml @@ -0,0 +1,16 @@ +<certChain chainID="zUuTTlYaoCcQt7olivgLTwi4Dcc=" cryptoID="fpxef.4kvyi.v98yh.fmpnb" xmlns="http://trevp.net/cryptoID"> + <certs> + <cert certID="Z8S1svS6uDF2ALgDM/IQ3dLBMjM="> + <keyExpression expr="A"> + <keyHash>I3xggvcPVOmIBsOzO87lCPNA4Rg=</keyHash> + </keyExpression> + <modifier zeroCount="2">19155</modifier> + </cert> + </certs> + <publicKeys keys="A"> + <publicKey xmlns="http://trevp.net/rsa"> + <n>0P1JB0+Rp+h+wjzyox1RsZtarpaFWCyLYy3SXhTrIOpebu3Ojx2A1iFzzblaUsjVhgRxNmEpBRe31QKKsIhmRCHJwhPkHkf6JsLCTVnM6LpZnvlsSRs0SW/8Rk4xVotESs5jz7dA0nHJi5WcqA2SffgEJ3KPPVNAFsCv4NYMQzU=</n> + <e>Aw==</e> + </publicKey> + </publicKeys> +</certChain> diff --git a/third_party/tlslite/test/clientCryptoIDKey.xml b/third_party/tlslite/test/clientCryptoIDKey.xml new file mode 100644 index 0000000..437b3d8 --- /dev/null +++ b/third_party/tlslite/test/clientCryptoIDKey.xml @@ -0,0 +1,10 @@ +<privateKey xmlns="http://trevp.net/rsa"> + <n>0P1JB0+Rp+h+wjzyox1RsZtarpaFWCyLYy3SXhTrIOpebu3Ojx2A1iFzzblaUsjVhgRxNmEpBRe31QKKsIhmRCHJwhPkHkf6JsLCTVnM6LpZnvlsSRs0SW/8Rk4xVotESs5jz7dA0nHJi5WcqA2SffgEJ3KPPVNAFsCv4NYMQzU=</n> + <e>Aw==</e> + <d>ItThgTftm/wVIF99xdo4SESPHRkWOVzB5dz4ZQN8hXxlEnz3woTqzlrookmPDcwjllYS3mWG1i6eo4BscsFmYGMxFH7uBNOWAnxkE+tPRTcRbihDFBAnrR4nZxD/W9+pa/yaiaBhbZVUzuldlAPR4xr0UdD3AyuUuxahRpqBiV0=</d> + <p>5KUm5qeX3XtAPtZP2xbuaiEpggt3YXaYR+RMi1/18TDcIKXPtqTshUkSzo2uipkgayQGOVnfy/XIaEIgExMLGw==</p> + <q>6f4gM6hpdPrXmZOF+tpbBc/ghc5ZWM+icyuPXNU5XBrmwh7GPlNUbIOfTt2BbA4K6yY2U2tKgc3r0KYZI+//7w==</q> + <dP>mG4Z7xplPlIq1I7f52Se8WtxAVz6QPm62pgzB5VOoMs9axk1JG3zA4YMibPJsbtq8hgEJjvqh/kwRYFqt2IHZw==</dP> + <dQ>m/7AInBGTfyPu7eupzw8roqVromQ5d/Boh0KPeN7kryZ1r8u1DeNna0U3z5WSAlcnMQkN5zcVolH4G67bUqqnw==</dQ> + <qInv>laETO0Mg9RXvXaJLhTO4ZGQbBIQO+6a0rd9lP/cXscmh34s8QpxAbQoRviV9migvVyuCNd8aQcTSMwmJO59AWQ==</qInv> +</privateKey> diff --git a/third_party/tlslite/test/clientX509Cert.pem b/third_party/tlslite/test/clientX509Cert.pem new file mode 100644 index 0000000..fe8c995 --- /dev/null +++ b/third_party/tlslite/test/clientX509Cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICoDCCAgmgAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMB4XDTA0MDIwNjA2NDkxM1oXDTA0MDMwNzA2NDkxM1owRTELMAkGA1UE +BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2LHLqDM7 +BpltKQGLJsh5bcQdk3cB0tHSJn4wjH2kg5Hy3WWOfnTljkVZ7PXrVp69feJkhgNR +dD5bP1SVvPnF/ft77SVfM0nQDT2FKEH9Ez+1ZScZB3UkZFGxKM+WwALP/ve9LqLO +5+4l0CJ4vt3q1E3WBJNolpzAY05Y34Gyv3UCAwEAAaOBnzCBnDAdBgNVHQ4EFgQU +zir4m5L6TMX16qGLDzzTSSEsMwQwbQYDVR0jBGYwZIAUzir4m5L6TMX16qGLDzzT +SSEsMwShSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw +HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCAQAwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQQFAAOBgQBWiYArf5Z0hMDB7TeHONS6NYFktMndJnctOTGV +lmBV4I9Eg+TeYGIGfGkkZMm/zS2gfPRY12KyXVEL7+aBzguF/vPV+8nb5ByHlMu+ +K+4j3YnbkwMQ8QLZwwHOjc2quyMnm1hVKPPTpEWhXGK86lbbinidHgSe8cNKqjjg +xor7mA== +-----END CERTIFICATE----- diff --git a/third_party/tlslite/test/clientX509Key.pem b/third_party/tlslite/test/clientX509Key.pem new file mode 100644 index 0000000..3c506f8 --- /dev/null +++ b/third_party/tlslite/test/clientX509Key.pem @@ -0,0 +1,15 @@ +-----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----- diff --git a/third_party/tlslite/test/httpsserver.py b/third_party/tlslite/test/httpsserver.py new file mode 100644 index 0000000..087a979 --- /dev/null +++ b/third_party/tlslite/test/httpsserver.py @@ -0,0 +1,29 @@ +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()
\ No newline at end of file diff --git a/third_party/tlslite/test/index.html b/third_party/tlslite/test/index.html new file mode 100644 index 0000000..e7f02cc --- /dev/null +++ b/third_party/tlslite/test/index.html @@ -0,0 +1,649 @@ +<html> +<head> +<title>Trevor Perrin</title> +</head> +<body> +<H1>Trevor Perrin</H1> +<b>Email:</b> trevp at trevp.net<br> +<b>PGP Key:</b> <a href="pgp/key.asc">8035 47B9 D1F9 C148 619A 7948 D8C0 0F11 2F2F F9E3</a> +<p>I'm a programmer, here are some projects I'm involved in. + +<p>My current interest is cryptographic key management and alternatives to PKI. +<p> + +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<a name="tls_lite"> +<H2><a href="tls_lite/">TLS Lite</a></H2> +<b>Code:</b> tls_lite python library v0.1.8 (<a href="tls_lite/tls_lite-0.1.8.zip">.zip</a>, <a href="tls_lite/readme.txt">readme.txt</a>)<br> +<p> +TLS Lite is a free python library that implements SSL 3.0 and <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0</a>. +TLS Lite supports non-traditional authentication methods such as <a href="http://trevp.net/tls_srp/index.html">SRP</a>, +<a href="http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt">shared keys</a>, +and <a href="http://trevp.net/cryptoID/index.html">cryptoIDs</a>, in addition to X.509 certificates. TLS Lite is pure +<a href="http://www.python.org">Python</a>, however it can access <a href="http://www.openssl.org/">OpenSSL</a> or +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a> for faster crypto operations. + +<a name="tlssrp"> +<H2><a href="tls_srp/">TLS/SRP</a></H2> +<b>Internet-Draft:</b> Using SRP for TLS Authentication (<a href="tls_srp/draft-ietf-tls-srp-06.txt">.txt</a>, <a href="tls_srp/draft-ietf-tls-srp-06.html">.html</a>) +<p><a href="http://srp.stanford.edu">SRP</a> is the best way to do password authentication +across a network. <a href="http://www.ietf.org/html.charters/tls-charter.html">TLS</a> (aka SSL v3.1) +is the best way to do channel security. What could go better together? +<p>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. + +<a name="dss"> +<H2>DSS</H2> +<b>Requirements:</b> DSS Use Case Requirements Analysis (<a href="dss/oasis-dss-1.0-requirements-wd-12.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-requirements-wd-12.doc">.doc</a>)<br> +<b>Specification Working Draft:</b> Digital Signature Service Core Protocol and Elements (<a href="dss/oasis-dss-1.0-core-spec-wd-10.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-core-spec-wd-10.doc">.doc</a>)<br> +<b>Schema Working Draft:</b> oasis-dss-1.0-core-schema-wd-10 (<a href="dss/oasis-dss-1.0-core-schema-wd-10.xsd">.xsd</a>)<br> +<b>Somewhat Related Paper:</b> Delegated Cryptography, Online Trusted Third Parties, and PKI +(<a href="delegatedCrypto/delegatedCrypto.pdf">.pdf</a>, <a href="delegatedCrypto/delegatedCrypto.html">.html</a>)<br> +<i>(presented at the <a href="http://www.cs.dartmouth.edu/~pki02/">1st Annual PKI Research Workshop</a>)</i> +<p>The <a href="http://www.oasis-open.org/">OASIS</a> <a href="http://www.oasis-open.org/committees/dss/">Digital Signature Service Technical Committee</a> +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. +<p>Also listed is a paper arguing for the server-based approach vs. client-side PKI. + +<a name="cryptoURL"> +<H2>CryptoURLs</H2> +<b>Draft of potential Internet-Draft:</b> The "crypto" URL scheme (<a href="cryptoURL/draft-ietf-cryptoURL-01.txt">.txt</a>, <a href="cryptoURL/draft-ietf-cryptoURL-01.html">.html</a>)<br> +<p> +CryptoURLs add "crypto metadata" like content hashes and key fingerprints to normal URLs. +The resulting URLs are <a href="http://zooko.com/distnames.html">self-authenticating</a>, +like <a href="http://citeseer.nj.nec.com/mazieres99separating.html">SFS file names</a> or +<a href="http://research.microsoft.com/users/tuomaura/CGA/">Cryptographically Generated Addresses</a>. +These could be useful in: +<dir> +<LI>web pages: + <dir> + <LI>a page could link to software binaries and include their hash + <LI>a portal could provide secure introductions to a community of sites + </dir> +<LI>XML documents (e.g. extending an <a href="http://www.w3.org/TR/xmldsig-core/">XML-DSIG</a> over external references) +<LI>protocols (e.g. HTTP Redirects or LDAP Referrals) +<LI>software configuration (you could configure a client with the address and fingerprint of a server in one step) +</dir> +<a href="http://www.waterken.com/dev/YURL/">YURLs</a> are another approach to self-authenticating URLs. + +<a name="cryptlibConverter"> +<H2><a href="cryptlibConverter/">CryptlibConverter</a></H2> +<b>Code:</b> Version 5 for cryptlib 3.1 (<a href="cryptlibConverter/cryptlibConverter5_cl31.zip">.zip</a>, <a href="cryptlibConverter/readme.txt">readme.txt</a>) +<p>This is a python script that generates java, python, and C# wrappers for +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a>. 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. +<br> +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<a name="tls_lite"> +<H2><a href="tls_lite/">TLS Lite</a></H2> +<b>Code:</b> tls_lite python library v0.1.8 (<a href="tls_lite/tls_lite-0.1.8.zip">.zip</a>, <a href="tls_lite/readme.txt">readme.txt</a>)<br> +<p> +TLS Lite is a free python library that implements SSL 3.0 and <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0</a>. +TLS Lite supports non-traditional authentication methods such as <a href="http://trevp.net/tls_srp/index.html">SRP</a>, +<a href="http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt">shared keys</a>, +and <a href="http://trevp.net/cryptoID/index.html">cryptoIDs</a>, in addition to X.509 certificates. TLS Lite is pure +<a href="http://www.python.org">Python</a>, however it can access <a href="http://www.openssl.org/">OpenSSL</a> or +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a> for faster crypto operations. + +<a name="tlssrp"> +<H2><a href="tls_srp/">TLS/SRP</a></H2> +<b>Internet-Draft:</b> Using SRP for TLS Authentication (<a href="tls_srp/draft-ietf-tls-srp-06.txt">.txt</a>, <a href="tls_srp/draft-ietf-tls-srp-06.html">.html</a>) +<p><a href="http://srp.stanford.edu">SRP</a> is the best way to do password authentication +across a network. <a href="http://www.ietf.org/html.charters/tls-charter.html">TLS</a> (aka SSL v3.1) +is the best way to do channel security. What could go better together? +<p>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. + +<a name="dss"> +<H2>DSS</H2> +<b>Requirements:</b> DSS Use Case Requirements Analysis (<a href="dss/oasis-dss-1.0-requirements-wd-12.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-requirements-wd-12.doc">.doc</a>)<br> +<b>Specification Working Draft:</b> Digital Signature Service Core Protocol and Elements (<a href="dss/oasis-dss-1.0-core-spec-wd-10.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-core-spec-wd-10.doc">.doc</a>)<br> +<b>Schema Working Draft:</b> oasis-dss-1.0-core-schema-wd-10 (<a href="dss/oasis-dss-1.0-core-schema-wd-10.xsd">.xsd</a>)<br> +<b>Somewhat Related Paper:</b> Delegated Cryptography, Online Trusted Third Parties, and PKI +(<a href="delegatedCrypto/delegatedCrypto.pdf">.pdf</a>, <a href="delegatedCrypto/delegatedCrypto.html">.html</a>)<br> +<i>(presented at the <a href="http://www.cs.dartmouth.edu/~pki02/">1st Annual PKI Research Workshop</a>)</i> +<p>The <a href="http://www.oasis-open.org/">OASIS</a> <a href="http://www.oasis-open.org/committees/dss/">Digital Signature Service Technical Committee</a> +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. +<p>Also listed is a paper arguing for the server-based approach vs. client-side PKI. + +<a name="cryptoURL"> +<H2>CryptoURLs</H2> +<b>Draft of potential Internet-Draft:</b> The "crypto" URL scheme (<a href="cryptoURL/draft-ietf-cryptoURL-01.txt">.txt</a>, <a href="cryptoURL/draft-ietf-cryptoURL-01.html">.html</a>)<br> +<p> +CryptoURLs add "crypto metadata" like content hashes and key fingerprints to normal URLs. +The resulting URLs are <a href="http://zooko.com/distnames.html">self-authenticating</a>, +like <a href="http://citeseer.nj.nec.com/mazieres99separating.html">SFS file names</a> or +<a href="http://research.microsoft.com/users/tuomaura/CGA/">Cryptographically Generated Addresses</a>. +These could be useful in: +<dir> +<LI>web pages: + <dir> + <LI>a page could link to software binaries and include their hash + <LI>a portal could provide secure introductions to a community of sites + </dir> +<LI>XML documents (e.g. extending an <a href="http://www.w3.org/TR/xmldsig-core/">XML-DSIG</a> over external references) +<LI>protocols (e.g. HTTP Redirects or LDAP Referrals) +<LI>software configuration (you could configure a client with the address and fingerprint of a server in one step) +</dir> +<a href="http://www.waterken.com/dev/YURL/">YURLs</a> are another approach to self-authenticating URLs. + +<a name="cryptlibConverter"> +<H2><a href="cryptlibConverter/">CryptlibConverter</a></H2> +<b>Code:</b> Version 5 for cryptlib 3.1 (<a href="cryptlibConverter/cryptlibConverter5_cl31.zip">.zip</a>, <a href="cryptlibConverter/readme.txt">readme.txt</a>) +<p>This is a python script that generates java, python, and C# wrappers for +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a>. 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. +<br> +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<a name="tls_lite"> +<H2><a href="tls_lite/">TLS Lite</a></H2> +<b>Code:</b> tls_lite python library v0.1.8 (<a href="tls_lite/tls_lite-0.1.8.zip">.zip</a>, <a href="tls_lite/readme.txt">readme.txt</a>)<br> +<p> +TLS Lite is a free python library that implements SSL 3.0 and <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0</a>. +TLS Lite supports non-traditional authentication methods such as <a href="http://trevp.net/tls_srp/index.html">SRP</a>, +<a href="http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt">shared keys</a>, +and <a href="http://trevp.net/cryptoID/index.html">cryptoIDs</a>, in addition to X.509 certificates. TLS Lite is pure +<a href="http://www.python.org">Python</a>, however it can access <a href="http://www.openssl.org/">OpenSSL</a> or +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a> for faster crypto operations. + +<a name="tlssrp"> +<H2><a href="tls_srp/">TLS/SRP</a></H2> +<b>Internet-Draft:</b> Using SRP for TLS Authentication (<a href="tls_srp/draft-ietf-tls-srp-06.txt">.txt</a>, <a href="tls_srp/draft-ietf-tls-srp-06.html">.html</a>) +<p><a href="http://srp.stanford.edu">SRP</a> is the best way to do password authentication +across a network. <a href="http://www.ietf.org/html.charters/tls-charter.html">TLS</a> (aka SSL v3.1) +is the best way to do channel security. What could go better together? +<p>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. + +<a name="dss"> +<H2>DSS</H2> +<b>Requirements:</b> DSS Use Case Requirements Analysis (<a href="dss/oasis-dss-1.0-requirements-wd-12.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-requirements-wd-12.doc">.doc</a>)<br> +<b>Specification Working Draft:</b> Digital Signature Service Core Protocol and Elements (<a href="dss/oasis-dss-1.0-core-spec-wd-10.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-core-spec-wd-10.doc">.doc</a>)<br> +<b>Schema Working Draft:</b> oasis-dss-1.0-core-schema-wd-10 (<a href="dss/oasis-dss-1.0-core-schema-wd-10.xsd">.xsd</a>)<br> +<b>Somewhat Related Paper:</b> Delegated Cryptography, Online Trusted Third Parties, and PKI +(<a href="delegatedCrypto/delegatedCrypto.pdf">.pdf</a>, <a href="delegatedCrypto/delegatedCrypto.html">.html</a>)<br> +<i>(presented at the <a href="http://www.cs.dartmouth.edu/~pki02/">1st Annual PKI Research Workshop</a>)</i> +<p>The <a href="http://www.oasis-open.org/">OASIS</a> <a href="http://www.oasis-open.org/committees/dss/">Digital Signature Service Technical Committee</a> +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. +<p>Also listed is a paper arguing for the server-based approach vs. client-side PKI. + +<a name="cryptoURL"> +<H2>CryptoURLs</H2> +<b>Draft of potential Internet-Draft:</b> The "crypto" URL scheme (<a href="cryptoURL/draft-ietf-cryptoURL-01.txt">.txt</a>, <a href="cryptoURL/draft-ietf-cryptoURL-01.html">.html</a>)<br> +<p> +CryptoURLs add "crypto metadata" like content hashes and key fingerprints to normal URLs. +The resulting URLs are <a href="http://zooko.com/distnames.html">self-authenticating</a>, +like <a href="http://citeseer.nj.nec.com/mazieres99separating.html">SFS file names</a> or +<a href="http://research.microsoft.com/users/tuomaura/CGA/">Cryptographically Generated Addresses</a>. +These could be useful in: +<dir> +<LI>web pages: + <dir> + <LI>a page could link to software binaries and include their hash + <LI>a portal could provide secure introductions to a community of sites + </dir> +<LI>XML documents (e.g. extending an <a href="http://www.w3.org/TR/xmldsig-core/">XML-DSIG</a> over external references) +<LI>protocols (e.g. HTTP Redirects or LDAP Referrals) +<LI>software configuration (you could configure a client with the address and fingerprint of a server in one step) +</dir> +<a href="http://www.waterken.com/dev/YURL/">YURLs</a> are another approach to self-authenticating URLs. + +<a name="cryptlibConverter"> +<H2><a href="cryptlibConverter/">CryptlibConverter</a></H2> +<b>Code:</b> Version 5 for cryptlib 3.1 (<a href="cryptlibConverter/cryptlibConverter5_cl31.zip">.zip</a>, <a href="cryptlibConverter/readme.txt">readme.txt</a>) +<p>This is a python script that generates java, python, and C# wrappers for +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a>. 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. +<br> +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<a name="tls_lite"> +<H2><a href="tls_lite/">TLS Lite</a></H2> +<b>Code:</b> tls_lite python library v0.1.8 (<a href="tls_lite/tls_lite-0.1.8.zip">.zip</a>, <a href="tls_lite/readme.txt">readme.txt</a>)<br> +<p> +TLS Lite is a free python library that implements SSL 3.0 and <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0</a>. +TLS Lite supports non-traditional authentication methods such as <a href="http://trevp.net/tls_srp/index.html">SRP</a>, +<a href="http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt">shared keys</a>, +and <a href="http://trevp.net/cryptoID/index.html">cryptoIDs</a>, in addition to X.509 certificates. TLS Lite is pure +<a href="http://www.python.org">Python</a>, however it can access <a href="http://www.openssl.org/">OpenSSL</a> or +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a> for faster crypto operations. + +<a name="tlssrp"> +<H2><a href="tls_srp/">TLS/SRP</a></H2> +<b>Internet-Draft:</b> Using SRP for TLS Authentication (<a href="tls_srp/draft-ietf-tls-srp-06.txt">.txt</a>, <a href="tls_srp/draft-ietf-tls-srp-06.html">.html</a>) +<p><a href="http://srp.stanford.edu">SRP</a> is the best way to do password authentication +across a network. <a href="http://www.ietf.org/html.charters/tls-charter.html">TLS</a> (aka SSL v3.1) +is the best way to do channel security. What could go better together? +<p>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. + +<a name="dss"> +<H2>DSS</H2> +<b>Requirements:</b> DSS Use Case Requirements Analysis (<a href="dss/oasis-dss-1.0-requirements-wd-12.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-requirements-wd-12.doc">.doc</a>)<br> +<b>Specification Working Draft:</b> Digital Signature Service Core Protocol and Elements (<a href="dss/oasis-dss-1.0-core-spec-wd-10.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-core-spec-wd-10.doc">.doc</a>)<br> +<b>Schema Working Draft:</b> oasis-dss-1.0-core-schema-wd-10 (<a href="dss/oasis-dss-1.0-core-schema-wd-10.xsd">.xsd</a>)<br> +<b>Somewhat Related Paper:</b> Delegated Cryptography, Online Trusted Third Parties, and PKI +(<a href="delegatedCrypto/delegatedCrypto.pdf">.pdf</a>, <a href="delegatedCrypto/delegatedCrypto.html">.html</a>)<br> +<i>(presented at the <a href="http://www.cs.dartmouth.edu/~pki02/">1st Annual PKI Research Workshop</a>)</i> +<p>The <a href="http://www.oasis-open.org/">OASIS</a> <a href="http://www.oasis-open.org/committees/dss/">Digital Signature Service Technical Committee</a> +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. +<p>Also listed is a paper arguing for the server-based approach vs. client-side PKI. + +<a name="cryptoURL"> +<H2>CryptoURLs</H2> +<b>Draft of potential Internet-Draft:</b> The "crypto" URL scheme (<a href="cryptoURL/draft-ietf-cryptoURL-01.txt">.txt</a>, <a href="cryptoURL/draft-ietf-cryptoURL-01.html">.html</a>)<br> +<p> +CryptoURLs add "crypto metadata" like content hashes and key fingerprints to normal URLs. +The resulting URLs are <a href="http://zooko.com/distnames.html">self-authenticating</a>, +like <a href="http://citeseer.nj.nec.com/mazieres99separating.html">SFS file names</a> or +<a href="http://research.microsoft.com/users/tuomaura/CGA/">Cryptographically Generated Addresses</a>. +These could be useful in: +<dir> +<LI>web pages: + <dir> + <LI>a page could link to software binaries and include their hash + <LI>a portal could provide secure introductions to a community of sites + </dir> +<LI>XML documents (e.g. extending an <a href="http://www.w3.org/TR/xmldsig-core/">XML-DSIG</a> over external references) +<LI>protocols (e.g. HTTP Redirects or LDAP Referrals) +<LI>software configuration (you could configure a client with the address and fingerprint of a server in one step) +</dir> +<a href="http://www.waterken.com/dev/YURL/">YURLs</a> are another approach to self-authenticating URLs. + +<a name="cryptlibConverter"> +<H2><a href="cryptlibConverter/">CryptlibConverter</a></H2> +<b>Code:</b> Version 5 for cryptlib 3.1 (<a href="cryptlibConverter/cryptlibConverter5_cl31.zip">.zip</a>, <a href="cryptlibConverter/readme.txt">readme.txt</a>) +<p>This is a python script that generates java, python, and C# wrappers for +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a>. 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. +<br> +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<a name="tls_lite"> +<H2><a href="tls_lite/">TLS Lite</a></H2> +<b>Code:</b> tls_lite python library v0.1.8 (<a href="tls_lite/tls_lite-0.1.8.zip">.zip</a>, <a href="tls_lite/readme.txt">readme.txt</a>)<br> +<p> +TLS Lite is a free python library that implements SSL 3.0 and <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0</a>. +TLS Lite supports non-traditional authentication methods such as <a href="http://trevp.net/tls_srp/index.html">SRP</a>, +<a href="http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt">shared keys</a>, +and <a href="http://trevp.net/cryptoID/index.html">cryptoIDs</a>, in addition to X.509 certificates. TLS Lite is pure +<a href="http://www.python.org">Python</a>, however it can access <a href="http://www.openssl.org/">OpenSSL</a> or +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a> for faster crypto operations. + +<a name="tlssrp"> +<H2><a href="tls_srp/">TLS/SRP</a></H2> +<b>Internet-Draft:</b> Using SRP for TLS Authentication (<a href="tls_srp/draft-ietf-tls-srp-06.txt">.txt</a>, <a href="tls_srp/draft-ietf-tls-srp-06.html">.html</a>) +<p><a href="http://srp.stanford.edu">SRP</a> is the best way to do password authentication +across a network. <a href="http://www.ietf.org/html.charters/tls-charter.html">TLS</a> (aka SSL v3.1) +is the best way to do channel security. What could go better together? +<p>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. + +<a name="dss"> +<H2>DSS</H2> +<b>Requirements:</b> DSS Use Case Requirements Analysis (<a href="dss/oasis-dss-1.0-requirements-wd-12.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-requirements-wd-12.doc">.doc</a>)<br> +<b>Specification Working Draft:</b> Digital Signature Service Core Protocol and Elements (<a href="dss/oasis-dss-1.0-core-spec-wd-10.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-core-spec-wd-10.doc">.doc</a>)<br> +<b>Schema Working Draft:</b> oasis-dss-1.0-core-schema-wd-10 (<a href="dss/oasis-dss-1.0-core-schema-wd-10.xsd">.xsd</a>)<br> +<b>Somewhat Related Paper:</b> Delegated Cryptography, Online Trusted Third Parties, and PKI +(<a href="delegatedCrypto/delegatedCrypto.pdf">.pdf</a>, <a href="delegatedCrypto/delegatedCrypto.html">.html</a>)<br> +<i>(presented at the <a href="http://www.cs.dartmouth.edu/~pki02/">1st Annual PKI Research Workshop</a>)</i> +<p>The <a href="http://www.oasis-open.org/">OASIS</a> <a href="http://www.oasis-open.org/committees/dss/">Digital Signature Service Technical Committee</a> +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. +<p>Also listed is a paper arguing for the server-based approach vs. client-side PKI. + +<a name="cryptoURL"> +<H2>CryptoURLs</H2> +<b>Draft of potential Internet-Draft:</b> The "crypto" URL scheme (<a href="cryptoURL/draft-ietf-cryptoURL-01.txt">.txt</a>, <a href="cryptoURL/draft-ietf-cryptoURL-01.html">.html</a>)<br> +<p> +CryptoURLs add "crypto metadata" like content hashes and key fingerprints to normal URLs. +The resulting URLs are <a href="http://zooko.com/distnames.html">self-authenticating</a>, +like <a href="http://citeseer.nj.nec.com/mazieres99separating.html">SFS file names</a> or +<a href="http://research.microsoft.com/users/tuomaura/CGA/">Cryptographically Generated Addresses</a>. +These could be useful in: +<dir> +<LI>web pages: + <dir> + <LI>a page could link to software binaries and include their hash + <LI>a portal could provide secure introductions to a community of sites + </dir> +<LI>XML documents (e.g. extending an <a href="http://www.w3.org/TR/xmldsig-core/">XML-DSIG</a> over external references) +<LI>protocols (e.g. HTTP Redirects or LDAP Referrals) +<LI>software configuration (you could configure a client with the address and fingerprint of a server in one step) +</dir> +<a href="http://www.waterken.com/dev/YURL/">YURLs</a> are another approach to self-authenticating URLs. + +<a name="cryptlibConverter"> +<H2><a href="cryptlibConverter/">CryptlibConverter</a></H2> +<b>Code:</b> Version 5 for cryptlib 3.1 (<a href="cryptlibConverter/cryptlibConverter5_cl31.zip">.zip</a>, <a href="cryptlibConverter/readme.txt">readme.txt</a>) +<p>This is a python script that generates java, python, and C# wrappers for +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a>. 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. +<br> +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<a name="tls_lite"> +<H2><a href="tls_lite/">TLS Lite</a></H2> +<b>Code:</b> tls_lite python library v0.1.8 (<a href="tls_lite/tls_lite-0.1.8.zip">.zip</a>, <a href="tls_lite/readme.txt">readme.txt</a>)<br> +<p> +TLS Lite is a free python library that implements SSL 3.0 and <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0</a>. +TLS Lite supports non-traditional authentication methods such as <a href="http://trevp.net/tls_srp/index.html">SRP</a>, +<a href="http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt">shared keys</a>, +and <a href="http://trevp.net/cryptoID/index.html">cryptoIDs</a>, in addition to X.509 certificates. TLS Lite is pure +<a href="http://www.python.org">Python</a>, however it can access <a href="http://www.openssl.org/">OpenSSL</a> or +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a> for faster crypto operations. + +<a name="tlssrp"> +<H2><a href="tls_srp/">TLS/SRP</a></H2> +<b>Internet-Draft:</b> Using SRP for TLS Authentication (<a href="tls_srp/draft-ietf-tls-srp-06.txt">.txt</a>, <a href="tls_srp/draft-ietf-tls-srp-06.html">.html</a>) +<p><a href="http://srp.stanford.edu">SRP</a> is the best way to do password authentication +across a network. <a href="http://www.ietf.org/html.charters/tls-charter.html">TLS</a> (aka SSL v3.1) +is the best way to do channel security. What could go better together? +<p>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. + +<a name="dss"> +<H2>DSS</H2> +<b>Requirements:</b> DSS Use Case Requirements Analysis (<a href="dss/oasis-dss-1.0-requirements-wd-12.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-requirements-wd-12.doc">.doc</a>)<br> +<b>Specification Working Draft:</b> Digital Signature Service Core Protocol and Elements (<a href="dss/oasis-dss-1.0-core-spec-wd-10.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-core-spec-wd-10.doc">.doc</a>)<br> +<b>Schema Working Draft:</b> oasis-dss-1.0-core-schema-wd-10 (<a href="dss/oasis-dss-1.0-core-schema-wd-10.xsd">.xsd</a>)<br> +<b>Somewhat Related Paper:</b> Delegated Cryptography, Online Trusted Third Parties, and PKI +(<a href="delegatedCrypto/delegatedCrypto.pdf">.pdf</a>, <a href="delegatedCrypto/delegatedCrypto.html">.html</a>)<br> +<i>(presented at the <a href="http://www.cs.dartmouth.edu/~pki02/">1st Annual PKI Research Workshop</a>)</i> +<p>The <a href="http://www.oasis-open.org/">OASIS</a> <a href="http://www.oasis-open.org/committees/dss/">Digital Signature Service Technical Committee</a> +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. +<p>Also listed is a paper arguing for the server-based approach vs. client-side PKI. + +<a name="cryptoURL"> +<H2>CryptoURLs</H2> +<b>Draft of potential Internet-Draft:</b> The "crypto" URL scheme (<a href="cryptoURL/draft-ietf-cryptoURL-01.txt">.txt</a>, <a href="cryptoURL/draft-ietf-cryptoURL-01.html">.html</a>)<br> +<p> +CryptoURLs add "crypto metadata" like content hashes and key fingerprints to normal URLs. +The resulting URLs are <a href="http://zooko.com/distnames.html">self-authenticating</a>, +like <a href="http://citeseer.nj.nec.com/mazieres99separating.html">SFS file names</a> or +<a href="http://research.microsoft.com/users/tuomaura/CGA/">Cryptographically Generated Addresses</a>. +These could be useful in: +<dir> +<LI>web pages: + <dir> + <LI>a page could link to software binaries and include their hash + <LI>a portal could provide secure introductions to a community of sites + </dir> +<LI>XML documents (e.g. extending an <a href="http://www.w3.org/TR/xmldsig-core/">XML-DSIG</a> over external references) +<LI>protocols (e.g. HTTP Redirects or LDAP Referrals) +<LI>software configuration (you could configure a client with the address and fingerprint of a server in one step) +</dir> +<a href="http://www.waterken.com/dev/YURL/">YURLs</a> are another approach to self-authenticating URLs. + +<a name="cryptlibConverter"> +<H2><a href="cryptlibConverter/">CryptlibConverter</a></H2> +<b>Code:</b> Version 5 for cryptlib 3.1 (<a href="cryptlibConverter/cryptlibConverter5_cl31.zip">.zip</a>, <a href="cryptlibConverter/readme.txt">readme.txt</a>) +<p>This is a python script that generates java, python, and C# wrappers for +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a>. 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. +<br> +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<a name="tls_lite"> +<H2><a href="tls_lite/">TLS Lite</a></H2> +<b>Code:</b> tls_lite python library v0.1.8 (<a href="tls_lite/tls_lite-0.1.8.zip">.zip</a>, <a href="tls_lite/readme.txt">readme.txt</a>)<br> +<p> +TLS Lite is a free python library that implements SSL 3.0 and <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0</a>. +TLS Lite supports non-traditional authentication methods such as <a href="http://trevp.net/tls_srp/index.html">SRP</a>, +<a href="http://www.ietf.org/internet-drafts/draft-ietf-tls-sharedkeys-02.txt">shared keys</a>, +and <a href="http://trevp.net/cryptoID/index.html">cryptoIDs</a>, in addition to X.509 certificates. TLS Lite is pure +<a href="http://www.python.org">Python</a>, however it can access <a href="http://www.openssl.org/">OpenSSL</a> or +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a> for faster crypto operations. + +<a name="tlssrp"> +<H2><a href="tls_srp/">TLS/SRP</a></H2> +<b>Internet-Draft:</b> Using SRP for TLS Authentication (<a href="tls_srp/draft-ietf-tls-srp-06.txt">.txt</a>, <a href="tls_srp/draft-ietf-tls-srp-06.html">.html</a>) +<p><a href="http://srp.stanford.edu">SRP</a> is the best way to do password authentication +across a network. <a href="http://www.ietf.org/html.charters/tls-charter.html">TLS</a> (aka SSL v3.1) +is the best way to do channel security. What could go better together? +<p>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. + +<a name="dss"> +<H2>DSS</H2> +<b>Requirements:</b> DSS Use Case Requirements Analysis (<a href="dss/oasis-dss-1.0-requirements-wd-12.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-requirements-wd-12.doc">.doc</a>)<br> +<b>Specification Working Draft:</b> Digital Signature Service Core Protocol and Elements (<a href="dss/oasis-dss-1.0-core-spec-wd-10.pdf">.pdf</a>, <a href="dss/oasis-dss-1.0-core-spec-wd-10.doc">.doc</a>)<br> +<b>Schema Working Draft:</b> oasis-dss-1.0-core-schema-wd-10 (<a href="dss/oasis-dss-1.0-core-schema-wd-10.xsd">.xsd</a>)<br> +<b>Somewhat Related Paper:</b> Delegated Cryptography, Online Trusted Third Parties, and PKI +(<a href="delegatedCrypto/delegatedCrypto.pdf">.pdf</a>, <a href="delegatedCrypto/delegatedCrypto.html">.html</a>)<br> +<i>(presented at the <a href="http://www.cs.dartmouth.edu/~pki02/">1st Annual PKI Research Workshop</a>)</i> +<p>The <a href="http://www.oasis-open.org/">OASIS</a> <a href="http://www.oasis-open.org/committees/dss/">Digital Signature Service Technical Committee</a> +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. +<p>Also listed is a paper arguing for the server-based approach vs. client-side PKI. + +<a name="cryptoURL"> +<H2>CryptoURLs</H2> +<b>Draft of potential Internet-Draft:</b> The "crypto" URL scheme (<a href="cryptoURL/draft-ietf-cryptoURL-01.txt">.txt</a>, <a href="cryptoURL/draft-ietf-cryptoURL-01.html">.html</a>)<br> +<p> +CryptoURLs add "crypto metadata" like content hashes and key fingerprints to normal URLs. +The resulting URLs are <a href="http://zooko.com/distnames.html">self-authenticating</a>, +like <a href="http://citeseer.nj.nec.com/mazieres99separating.html">SFS file names</a> or +<a href="http://research.microsoft.com/users/tuomaura/CGA/">Cryptographically Generated Addresses</a>. +These could be useful in: +<dir> +<LI>web pages: + <dir> + <LI>a page could link to software binaries and include their hash + <LI>a portal could provide secure introductions to a community of sites + </dir> +<LI>XML documents (e.g. extending an <a href="http://www.w3.org/TR/xmldsig-core/">XML-DSIG</a> over external references) +<LI>protocols (e.g. HTTP Redirects or LDAP Referrals) +<LI>software configuration (you could configure a client with the address and fingerprint of a server in one step) +</dir> +<a href="http://www.waterken.com/dev/YURL/">YURLs</a> are another approach to self-authenticating URLs. + +<a name="cryptlibConverter"> +<H2><a href="cryptlibConverter/">CryptlibConverter</a></H2> +<b>Code:</b> Version 5 for cryptlib 3.1 (<a href="cryptlibConverter/cryptlibConverter5_cl31.zip">.zip</a>, <a href="cryptlibConverter/readme.txt">readme.txt</a>) +<p>This is a python script that generates java, python, and C# wrappers for +<a href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">cryptlib</a>. 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. +<br> +<a name="cryptoID"> +<H2><a href="cryptoID/">CryptoIDs</a></H2> +<b>Paper 1:</b> Public Key Distribution through "cryptoIDs" (<a href="cryptoID/cryptoID.pdf">.pdf</a>, <a href="cryptoID/cryptoID.html">.html</a>) <i>(presented at <a href="http://www.nspw.org/2003/">NSPW 2003</a>)</i><br> +<b>Paper 2:</b> The CryptoID Key Management Protocols (<a href="cryptoID/cryptoID2.pdf">.pdf</a>) <i>(the best introduction)</i><br> +<b>Schema:</b> XML Schema for <certChain> (<a href="cryptoID/cryptoID.xsd">.xsd</a>)<br> +<b>Code:</b> CryptoIDlib Python and Java library and command-line tool v0.1.8 (<a href="cryptoID/cryptoIDlib-0.1.8.zip">.zip</a>, <a href="cryptoID/readme.txt">readme.txt</a>) +<p>PKI isn't working for person-to-person communications. Few people use +secure email, voice, instant-messaging, or anything else. +<p>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. +<p>The cryptoID for each user would correspond to that user's <i>root key</i>. +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 <i>subkey certificates</i> or <i>validation signatures</i> to the user. +<p>CryptoIDs, then, are about combining <i>fingerprint-based public-key distribution</i> with +<i>certificate-based private-key management</i>. The first paper above presents the +cryptoID fingerprint and certificate formats, which are designed specifically for +this. CryptoIDlib lets you test-drive these formats. +<p>The second paper presents private-key management protocols for use with online servers. +Support for these is being added to cryptoIDlib. + +<br> +<br> +</body> +</html> diff --git a/third_party/tlslite/test/serverCryptoIDChain.xml b/third_party/tlslite/test/serverCryptoIDChain.xml new file mode 100644 index 0000000..7490d6b --- /dev/null +++ b/third_party/tlslite/test/serverCryptoIDChain.xml @@ -0,0 +1,16 @@ +<certChain chainID="+YzLTjs06lZvpdErm4XvLrdDIm0=" cryptoID="fcqnh.x9ipq.7htkd.36ciw" xmlns="http://trevp.net/cryptoID"> + <certs> + <cert certID="MIowYZzWGkDQnHc4Givt2SO8QY8="> + <keyExpression expr="A"> + <keyHash>8PABXXCcJCBGo9Yy8rGJg01md+Y=</keyHash> + </keyExpression> + <modifier zeroCount="2">18531525</modifier> + </cert> + </certs> + <publicKeys keys="A"> + <publicKey xmlns="http://trevp.net/rsa"> + <n>uJRX5oHWOjaQEvoGmshObJSWEVotPAvIfdtNWc4cI56sNhNcKMSLSEvZF/294hpvDl8SQB6Y/DyGcCFv5ShYOL7mfje+7Iq64ck604jeea9rE848NMfwq9MgHDpXq1Cx9NtbcOLilrb2z0rCvNihI4Qb/wrI/tYLlU5fXwOoUGM=</n> + <e>Aw==</e> + </publicKey> + </publicKeys> +</certChain> diff --git a/third_party/tlslite/test/serverCryptoIDKey.xml b/third_party/tlslite/test/serverCryptoIDKey.xml new file mode 100644 index 0000000..69bf9a2 --- /dev/null +++ b/third_party/tlslite/test/serverCryptoIDKey.xml @@ -0,0 +1,10 @@ +<privateKey xmlns="http://trevp.net/rsa"> + <n>uJRX5oHWOjaQEvoGmshObJSWEVotPAvIfdtNWc4cI56sNhNcKMSLSEvZF/294hpvDl8SQB6Y/DyGcCFv5ShYOL7mfje+7Iq64ck604jeea9rE848NMfwq9MgHDpXq1Cx9NtbcOLilrb2z0rCvNihI4Qb/wrI/tYLlU5fXwOoUGM=</n> + <e>Aw==</e> + <d>HsNj+8BOXwkYAymrxHa3vMNuWDmyNKyhak83jvevW0Ucs63ksXYXNrdO2VT0+wRn17qDCq/EKgoWaAWSpjFkCSwsTV9UTOLNmxd+OZ1KePURiZo9EPTlzcufbyAW6t01gx6MFuKfBo9Ayuk/Na3dVt6s2vOVYvaJvjqnWpuv/Oc=</d> + <p>wOJPKhX4RqJLyHBJ7JMnM1hwWixWE0Bn1KFDiFyjmIFU8mNkLKvGBkrTvegkcwwiRvOf3H5fyWiUHeO3YJopLQ==</p> + <q>9Ppe0a8m80bzc9Uv7Ix8valp1qF4901xOMI98XGGiO+NMa+DZnypVSc6FV9WUmT4BRs9eMpNRWiL0I+H/O45zw==</q> + <dP>gJbfcWP62cGH2vWGnbdvd5BK5sg5Yirv4xYtBZMXuwDjTEJCyHKEBDHifprC911sL00VPamVMPBivpfPlbwbcw==</dP> + <dQ>o1GUi8oZ94SiTTjKnbL908ZGjxZQpN5LeywpS6EEW0peIR+s7v3GOMTRY5TkNu36rhIo+zGI2PBdNbUFU0l73w==</dQ> + <qInv>XJ1sKQDEzji46Xfg08m2y66COjLNguW5DW7SNVKEbsS9f6C4Wpt2bA806pqn/6lTiv4h2DSGTKh/RzH6Ztdmdg==</qInv> +</privateKey> diff --git a/third_party/tlslite/test/serverX509Cert.pem b/third_party/tlslite/test/serverX509Cert.pem new file mode 100644 index 0000000..9c8d849 --- /dev/null +++ b/third_party/tlslite/test/serverX509Cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICoDCCAgmgAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMB4XDTA0MDIwNjA2NDUyN1oXDTA0MDMwNzA2NDUyN1owRTELMAkGA1UE +BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3+xiHTIR +hvdr58p4A6oBC6xMlPZ19hSNf58s4A3f8ORV4IOXR3BvScgOI3WqM47WkkQ1/S5O +gKiDMKmmomEEgntjl9AAqH6/UztE6zoKlyz200wC6yNayfpcJiyBkr5xDMnCzPz0 +e2tScODhGx+r6uy3AontC5tyUAqkeeWsrk0CAwEAAaOBnzCBnDAdBgNVHQ4EFgQU +1HnCXw1pdREsK8PJSHN2zS2YTfgwbQYDVR0jBGYwZIAU1HnCXw1pdREsK8PJSHN2 +zS2YTfihSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw +HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCAQAwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQQFAAOBgQAgu4Su/NpL1ZQt6HUbi0deyx2yiPO9x2s2EHPz +r8Gu7M/JORKi9vtLiYfjfjTGKLTXTCpRvqL8rRc13QRGi4cTsAFxwQjDKukoidOx +BWl4mMvw+pLJoAIcacdJAgSrFQeVUy8eVdvxqktDq+KdxZIn4z+vah+ZLuyozdsv +idQlIQ== +-----END CERTIFICATE----- diff --git a/third_party/tlslite/test/serverX509Key.pem b/third_party/tlslite/test/serverX509Key.pem new file mode 100644 index 0000000..e558e8e --- /dev/null +++ b/third_party/tlslite/test/serverX509Key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDf7GIdMhGG92vnyngDqgELrEyU9nX2FI1/nyzgDd/w5FXgg5dH +cG9JyA4jdaozjtaSRDX9Lk6AqIMwqaaiYQSCe2OX0ACofr9TO0TrOgqXLPbTTALr +I1rJ+lwmLIGSvnEMycLM/PR7a1Jw4OEbH6vq7LcCie0Lm3JQCqR55ayuTQIDAQAB +AoGAE8QQ8RTPWUOT4dUMfP5Ps1EVPXz38q3jw6UwV+LBpsjxD61t+B9jo3amUNj9 +Gin8pNKilWO2CENXuT7wd5rqw9OHpk5R1BHeSMzCCiqHkrVHzlOnchMnlYvFhA3K +8z4pSdljAQLoW1Az4uVwepS625wdv7ZPOSW0+ozwftL5fsECQQD3fKf64Vx1qTZT +F+w7+q49+JztEQMef3Lu1wcDwcFZ1+wvvFbSky+7OU1URu10jXujLDXowfIkm5jF +S8fuefG9AkEA56A6k31y5wpmldRF/geJIjbqxHhQEvGzYkvSlsKxWWxMmldtAlwQ +aMEpJ6Vfk2yoaxHSKJVfm3lgUY7e3GlP0QJAckRQ/sncucq19WmfPhZBKwXF1sM7 +EHLB6zrG11o3XrcOKwAnijRBHo2Xgaj57A2DH1TDU0Nw/KwGvll950LQdQJAZf/N +S73mp4+Q9VHxMJio7wQ4BiTlPjJpyFOTfQhniPWEFkOBoZRhNYA6W1cb65Ph5qSG +Y5DD9XdRzxiXU4CcwQJBAOu91/L0ujuh3j/V824bEdGpENoB923qsGa0BOA9PAWk +s7wW6mKStbzcBIBExX91tdSxtYvAUXikA2J6D7Xmge0= +-----END RSA PRIVATE KEY----- diff --git a/third_party/tlslite/test/test.txt b/third_party/tlslite/test/test.txt new file mode 100644 index 0000000..96153c1 --- /dev/null +++ b/third_party/tlslite/test/test.txt @@ -0,0 +1,10 @@ +<privateKey xmlns="http://trevp.net/rsa"> + <n>mwvyukly7i05mdtoml8s2Kesk1Kozv4Yh8Kq2QPiWkDFX/EM7sx9Y3cr6FJnpeTTka1gzwUGifBUGIuTytD4vrI44K5Y+0VZbD77cKQgIzh3g6WvPV/PNRDZ3NdWh/nCfE3L0fgYuOPqlyLT1L+bZH+JPdZubizzrP7JZxk6cf0=</n> + <e>Aw==</e> + <d>GddTHww90lze7vnmxGUyJBvyGI3GzSpZa/XHJCtQZGAg5VLXfSIU5ekx/A278Pt4mEeQIoDWbFK4rsHt9yLUH4XvjdSdbTjMSUOF7MNraW+BbrqH3OCA/T91HbdOijYyAvakyob5uwf3wwFlFUZ20WC3jXDybNjimImHHeXb2ys=</d> + <p>wdIkgfQQ+HldVlNmwVjNotSuYOYoUy7mnIVz0yf+Y3Sgg8rD9/5tQSgsBD4poxTxWUm0kegah9ZK8hjtpDeLvQ==</p> + <q>zMlpMLRa+BZXU4R9TkLc+Jo85ZnnyZpe95W2uFdMUSHKAiRO1j/pcvPZFjcrdb2K4fI4ntfGj83O04XGEdvDQQ==</q> + <dP>gTbDAU1gpaY+OYzvK5CJFzh0QJlwN3SZva5NN2/+7PhrAoctT/7zgMVyrX7GbLig5jEjC/ARr+Qx9rtJGCUH0w==</dP> + <dQ>iIZGIHg8pWQ6N62o3tc9+xF97maahmbp+mPPJY+INhaGrBg0jtVGTKKQuXoc+SkHQUwlvzqEX96J4lkutpKCKw==</dQ> + <qInv>XmTSYkIsPdz7ZhfySnPDSGTMd+gb39neAPrI8WoE981h89hJYXS0EVFiWRRs1kduFw7g21oM+WfGLNABlbyCbA==</qInv> +</privateKey> diff --git a/third_party/tlslite/test/twistedclient.py b/third_party/tlslite/test/twistedclient.py new file mode 100644 index 0000000..4f6c86a --- /dev/null +++ b/third_party/tlslite/test/twistedclient.py @@ -0,0 +1,33 @@ + +from tlslite.api import * +import socket + +s = socket.socket() + +s.connect( ("localhost", 1079) ) + +""" +#Only use this for Echo2 +s.send("000\r\n") +while 1: + val= s.recv(100) + print val, + if val.endswith("000\r\n"): + break + +s.send("STARTTLS\r\n") +""" + +connection = TLSConnection(s) +#connection.handshakeClientNoAuth() +connection.handshakeClientSRP("test", "password") + +connection.send("abc\r\n") +print connection.recv(100), +print connection.recv(100), + +connection.send("def\r\n") +print connection.recv(100), + +connection.close() +connection.sock.close()
\ No newline at end of file diff --git a/third_party/tlslite/test/twistedserver.py b/third_party/tlslite/test/twistedserver.py new file mode 100644 index 0000000..9946e42 --- /dev/null +++ b/third_party/tlslite/test/twistedserver.py @@ -0,0 +1,62 @@ + +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() diff --git a/third_party/tlslite/test/verifierDB b/third_party/tlslite/test/verifierDB Binary files differnew file mode 100644 index 0000000..8e23c9d --- /dev/null +++ b/third_party/tlslite/test/verifierDB diff --git a/third_party/tlslite/tlslite/BaseDB.py b/third_party/tlslite/tlslite/BaseDB.py new file mode 100644 index 0000000..4988c15 --- /dev/null +++ b/third_party/tlslite/tlslite/BaseDB.py @@ -0,0 +1,120 @@ +"""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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/Checker.py b/third_party/tlslite/tlslite/Checker.py new file mode 100644 index 0000000..f978697 --- /dev/null +++ b/third_party/tlslite/tlslite/Checker.py @@ -0,0 +1,146 @@ +"""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() + diff --git a/third_party/tlslite/tlslite/FileObject.py b/third_party/tlslite/tlslite/FileObject.py new file mode 100644 index 0000000..6ee02b2 --- /dev/null +++ b/third_party/tlslite/tlslite/FileObject.py @@ -0,0 +1,220 @@ +"""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 diff --git a/third_party/tlslite/tlslite/HandshakeSettings.py b/third_party/tlslite/tlslite/HandshakeSettings.py new file mode 100644 index 0000000..c7c3223 --- /dev/null +++ b/third_party/tlslite/tlslite/HandshakeSettings.py @@ -0,0 +1,159 @@ +"""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 diff --git a/third_party/tlslite/tlslite/Session.py b/third_party/tlslite/tlslite/Session.py new file mode 100644 index 0000000..a951f45 --- /dev/null +++ b/third_party/tlslite/tlslite/Session.py @@ -0,0 +1,131 @@ +"""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 + + diff --git a/third_party/tlslite/tlslite/SessionCache.py b/third_party/tlslite/tlslite/SessionCache.py new file mode 100644 index 0000000..34cf0b0 --- /dev/null +++ b/third_party/tlslite/tlslite/SessionCache.py @@ -0,0 +1,103 @@ +"""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() diff --git a/third_party/tlslite/tlslite/SharedKeyDB.py b/third_party/tlslite/tlslite/SharedKeyDB.py new file mode 100644 index 0000000..3246ec7 --- /dev/null +++ b/third_party/tlslite/tlslite/SharedKeyDB.py @@ -0,0 +1,58 @@ +"""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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/TLSConnection.py b/third_party/tlslite/tlslite/TLSConnection.py new file mode 100644 index 0000000..d125f8f --- /dev/null +++ b/third_party/tlslite/tlslite/TLSConnection.py @@ -0,0 +1,1600 @@ +""" +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 diff --git a/third_party/tlslite/tlslite/TLSRecordLayer.py b/third_party/tlslite/tlslite/TLSRecordLayer.py new file mode 100644 index 0000000..4a9042c --- /dev/null +++ b/third_party/tlslite/tlslite/TLSRecordLayer.py @@ -0,0 +1,1128 @@ +"""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)<min and not self.closed: + try: + for result in self._getMsg(ContentType.application_data): + if result in (0,1): + yield result + applicationData = result + self._readBuffer += bytesToString(applicationData.write()) + except TLSRemoteAlert, alert: + if alert.description != AlertDescription.close_notify: + raise + except TLSAbruptCloseError: + if not self.ignoreAbruptClose: + raise + else: + self._shutdown(True) + + if max == None: + max = len(self._readBuffer) + + returnStr = self._readBuffer[:max] + self._readBuffer = self._readBuffer[max:] + yield returnStr + except: + self._shutdown(False) + raise + + def 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. + + @type s: str + @param s: The data to transmit to the other party. + + @raise socket.error: If a socket error occurs. + """ + for result in self.writeAsync(s): + pass + + def 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. + + @rtype: iterable + @return: A generator; see above for details. + """ + try: + if self.closed: + raise ValueError() + + index = 0 + blockSize = 16384 + skipEmptyFrag = False + while 1: + startIndex = index * blockSize + endIndex = startIndex + blockSize + if startIndex >= 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 + # Forcing a shutdown as WinHTTP does not seem to be + # responsive to the close notify. + prevCloseSocket = self.closeSocket + self.closeSocket = True + self._shutdown(True) + self.closeSocket = prevCloseSocket + 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) diff --git a/third_party/tlslite/tlslite/VerifierDB.py b/third_party/tlslite/tlslite/VerifierDB.py new file mode 100644 index 0000000..f706b17 --- /dev/null +++ b/third_party/tlslite/tlslite/VerifierDB.py @@ -0,0 +1,90 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/X509.py b/third_party/tlslite/tlslite/X509.py new file mode 100644 index 0000000..a47ddcf --- /dev/null +++ b/third_party/tlslite/tlslite/X509.py @@ -0,0 +1,133 @@ +"""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 + + diff --git a/third_party/tlslite/tlslite/X509CertChain.py b/third_party/tlslite/tlslite/X509CertChain.py new file mode 100644 index 0000000..6bb503e --- /dev/null +++ b/third_party/tlslite/tlslite/X509CertChain.py @@ -0,0 +1,181 @@ +"""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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/__init__.py b/third_party/tlslite/tlslite/__init__.py new file mode 100644 index 0000000..47cfd1c --- /dev/null +++ b/third_party/tlslite/tlslite/__init__.py @@ -0,0 +1,39 @@ +""" +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"] diff --git a/third_party/tlslite/tlslite/api.py b/third_party/tlslite/tlslite/api.py new file mode 100644 index 0000000..eebfbc6 --- /dev/null +++ b/third_party/tlslite/tlslite/api.py @@ -0,0 +1,75 @@ +"""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 diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py new file mode 100644 index 0000000..8f2d559 --- /dev/null +++ b/third_party/tlslite/tlslite/constants.py @@ -0,0 +1,225 @@ +"""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" + } diff --git a/third_party/tlslite/tlslite/errors.py b/third_party/tlslite/tlslite/errors.py new file mode 100644 index 0000000..c7f7ba8 --- /dev/null +++ b/third_party/tlslite/tlslite/errors.py @@ -0,0 +1,149 @@ +"""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 diff --git a/third_party/tlslite/tlslite/integration/AsyncStateMachine.py b/third_party/tlslite/tlslite/integration/AsyncStateMachine.py new file mode 100644 index 0000000..01c7efe --- /dev/null +++ b/third_party/tlslite/tlslite/integration/AsyncStateMachine.py @@ -0,0 +1,235 @@ +""" +A state machine for using TLS Lite with asynchronous I/O. +""" + +class AsyncStateMachine: + """ + This is an abstract class that's used to integrate TLS Lite with + asyncore and Twisted. + + This class signals wantsReadsEvent() and wantsWriteEvent(). When + the underlying socket has become readable or writeable, the event + should be passed to this class by calling inReadEvent() or + inWriteEvent(). This class will then try to read or write through + the socket, and will update its state appropriately. + + This class will forward higher-level events to its subclass. For + example, when a complete TLS record has been received, + outReadEvent() will be called with the decrypted data. + """ + + def __init__(self): + self._clear() + + def _clear(self): + #These store the various asynchronous operations (i.e. + #generators). Only one of them, at most, is ever active at a + #time. + self.handshaker = None + self.closer = None + self.reader = None + self.writer = None + + #This stores the result from the last call to the + #currently active operation. If 0 it indicates that the + #operation wants to read, if 1 it indicates that the + #operation wants to write. If None, there is no active + #operation. + self.result = None + + def _checkAssert(self, maxActive=1): + #This checks that only one operation, at most, is + #active, and that self.result is set appropriately. + activeOps = 0 + if self.handshaker: + activeOps += 1 + if self.closer: + activeOps += 1 + if self.reader: + activeOps += 1 + if self.writer: + activeOps += 1 + + if self.result == None: + if activeOps != 0: + raise AssertionError() + elif self.result in (0,1): + if activeOps != 1: + raise AssertionError() + else: + raise AssertionError() + if activeOps > maxActive: + raise AssertionError() + + def wantsReadEvent(self): + """If the state machine wants to read. + + If an operation is active, this returns whether or not the + operation wants to read from the socket. If an operation is + not active, this returns None. + + @rtype: bool or None + @return: If the state machine wants to read. + """ + if self.result != None: + return self.result == 0 + return None + + def wantsWriteEvent(self): + """If the state machine wants to write. + + If an operation is active, this returns whether or not the + operation wants to write to the socket. If an operation is + not active, this returns None. + + @rtype: bool or None + @return: If the state machine wants to write. + """ + if self.result != None: + return self.result == 1 + return None + + def outConnectEvent(self): + """Called when a handshake operation completes. + + May be overridden in subclass. + """ + pass + + def outCloseEvent(self): + """Called when a close operation completes. + + May be overridden in subclass. + """ + pass + + def outReadEvent(self, readBuffer): + """Called when a read operation completes. + + May be overridden in subclass.""" + pass + + def outWriteEvent(self): + """Called when a write operation completes. + + May be overridden in subclass.""" + pass + + def inReadEvent(self): + """Tell the state machine it can read from the socket.""" + try: + self._checkAssert() + if self.handshaker: + self._doHandshakeOp() + elif self.closer: + self._doCloseOp() + elif self.reader: + self._doReadOp() + elif self.writer: + self._doWriteOp() + else: + self.reader = self.tlsConnection.readAsync(16384) + self._doReadOp() + except: + self._clear() + raise + + def inWriteEvent(self): + """Tell the state machine it can write to the socket.""" + try: + self._checkAssert() + if self.handshaker: + self._doHandshakeOp() + elif self.closer: + self._doCloseOp() + elif self.reader: + self._doReadOp() + elif self.writer: + self._doWriteOp() + else: + self.outWriteEvent() + except: + self._clear() + raise + + def _doHandshakeOp(self): + try: + self.result = self.handshaker.next() + except StopIteration: + self.handshaker = None + self.result = None + self.outConnectEvent() + + def _doCloseOp(self): + try: + self.result = self.closer.next() + except StopIteration: + self.closer = None + self.result = None + self.outCloseEvent() + + def _doReadOp(self): + self.result = self.reader.next() + if not self.result in (0,1): + readBuffer = self.result + self.reader = None + self.result = None + self.outReadEvent(readBuffer) + + def _doWriteOp(self): + try: + self.result = self.writer.next() + except StopIteration: + self.writer = None + self.result = None + + def setHandshakeOp(self, handshaker): + """Start a handshake operation. + + @type handshaker: generator + @param handshaker: A generator created by using one of the + asynchronous handshake functions (i.e. handshakeServerAsync, or + handshakeClientxxx(..., async=True). + """ + try: + self._checkAssert(0) + self.handshaker = handshaker + self._doHandshakeOp() + except: + self._clear() + raise + + def setServerHandshakeOp(self, **args): + """Start a handshake operation. + + The arguments passed to this function will be forwarded to + L{tlslite.TLSConnection.TLSConnection.handshakeServerAsync}. + """ + handshaker = self.tlsConnection.handshakeServerAsync(**args) + self.setHandshakeOp(handshaker) + + def setCloseOp(self): + """Start a close operation. + """ + try: + self._checkAssert(0) + self.closer = self.tlsConnection.closeAsync() + self._doCloseOp() + except: + self._clear() + raise + + def setWriteOp(self, writeBuffer): + """Start a write operation. + + @type writeBuffer: str + @param writeBuffer: The string to transmit. + """ + try: + self._checkAssert(0) + self.writer = self.tlsConnection.writeAsync(writeBuffer) + self._doWriteOp() + except: + self._clear() + raise + diff --git a/third_party/tlslite/tlslite/integration/ClientHelper.py b/third_party/tlslite/tlslite/integration/ClientHelper.py new file mode 100644 index 0000000..7918e4a --- /dev/null +++ b/third_party/tlslite/tlslite/integration/ClientHelper.py @@ -0,0 +1,163 @@ +""" +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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/HTTPTLSConnection.py b/third_party/tlslite/tlslite/integration/HTTPTLSConnection.py new file mode 100644 index 0000000..051d8e6 --- /dev/null +++ b/third_party/tlslite/tlslite/integration/HTTPTLSConnection.py @@ -0,0 +1,169 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/IMAP4_TLS.py b/third_party/tlslite/tlslite/integration/IMAP4_TLS.py new file mode 100644 index 0000000..0535801 --- /dev/null +++ b/third_party/tlslite/tlslite/integration/IMAP4_TLS.py @@ -0,0 +1,132 @@ +"""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')
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/IntegrationHelper.py b/third_party/tlslite/tlslite/integration/IntegrationHelper.py new file mode 100644 index 0000000..ca81a48 --- /dev/null +++ b/third_party/tlslite/tlslite/integration/IntegrationHelper.py @@ -0,0 +1,52 @@ + +class IntegrationHelper: + + def __init__(self, + username=None, password=None, sharedKey=None, + certChain=None, privateKey=None, + cryptoID=None, protocol=None, + x509Fingerprint=None, + x509TrustList=None, x509CommonName=None, + settings = None): + + self.username = None + self.password = None + self.sharedKey = None + self.certChain = None + self.privateKey = None + self.checker = None + + #SRP Authentication + if username and password and not \ + (sharedKey or certChain or privateKey): + self.username = username + self.password = password + + #Shared Key Authentication + elif username and sharedKey and not \ + (password or certChain or privateKey): + self.username = username + self.sharedKey = sharedKey + + #Certificate Chain Authentication + elif certChain and privateKey and not \ + (username or password or sharedKey): + self.certChain = certChain + self.privateKey = privateKey + + #No Authentication + elif not password and not username and not \ + sharedKey and not certChain and not privateKey: + pass + + else: + raise ValueError("Bad parameters") + + #Authenticate the server based on its cryptoID or fingerprint + if sharedKey and (cryptoID or protocol or x509Fingerprint): + raise ValueError("Can't use shared keys with other forms of"\ + "authentication") + + self.checker = Checker(cryptoID, protocol, x509Fingerprint, + x509TrustList, x509CommonName) + self.settings = settings
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/POP3_TLS.py b/third_party/tlslite/tlslite/integration/POP3_TLS.py new file mode 100644 index 0000000..71530cc --- /dev/null +++ b/third_party/tlslite/tlslite/integration/POP3_TLS.py @@ -0,0 +1,142 @@ +"""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()
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/SMTP_TLS.py b/third_party/tlslite/tlslite/integration/SMTP_TLS.py new file mode 100644 index 0000000..8421523 --- /dev/null +++ b/third_party/tlslite/tlslite/integration/SMTP_TLS.py @@ -0,0 +1,114 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/TLSAsyncDispatcherMixIn.py b/third_party/tlslite/tlslite/integration/TLSAsyncDispatcherMixIn.py new file mode 100644 index 0000000..fd9868f --- /dev/null +++ b/third_party/tlslite/tlslite/integration/TLSAsyncDispatcherMixIn.py @@ -0,0 +1,139 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/TLSSocketServerMixIn.py b/third_party/tlslite/tlslite/integration/TLSSocketServerMixIn.py new file mode 100644 index 0000000..dd4f945 --- /dev/null +++ b/third_party/tlslite/tlslite/integration/TLSSocketServerMixIn.py @@ -0,0 +1,59 @@ +"""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()
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/TLSTwistedProtocolWrapper.py b/third_party/tlslite/tlslite/integration/TLSTwistedProtocolWrapper.py new file mode 100644 index 0000000..6e1b5ca --- /dev/null +++ b/third_party/tlslite/tlslite/integration/TLSTwistedProtocolWrapper.py @@ -0,0 +1,196 @@ +"""TLS Lite + Twisted.""" + +from twisted.protocols.policies import ProtocolWrapper, WrappingFactory +from twisted.python.failure import Failure + +from AsyncStateMachine import AsyncStateMachine +from 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))
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/XMLRPCTransport.py b/third_party/tlslite/tlslite/integration/XMLRPCTransport.py new file mode 100644 index 0000000..87a035d --- /dev/null +++ b/third_party/tlslite/tlslite/integration/XMLRPCTransport.py @@ -0,0 +1,137 @@ +"""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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/integration/__init__.py b/third_party/tlslite/tlslite/integration/__init__.py new file mode 100644 index 0000000..960f406 --- /dev/null +++ b/third_party/tlslite/tlslite/integration/__init__.py @@ -0,0 +1,17 @@ +"""Classes for integrating TLS Lite with other packages.""" + +__all__ = ["AsyncStateMachine", + "HTTPTLSConnection", + "POP3_TLS", + "IMAP4_TLS", + "SMTP_TLS", + "XMLRPCTransport", + "TLSSocketServerMixIn", + "TLSAsyncDispatcherMixIn", + "TLSTwistedProtocolWrapper"] + +try: + import twisted + del twisted +except ImportError: + del __all__[__all__.index("TLSTwistedProtocolWrapper")] diff --git a/third_party/tlslite/tlslite/mathtls.py b/third_party/tlslite/tlslite/mathtls.py new file mode 100644 index 0000000..3b8ede6 --- /dev/null +++ b/third_party/tlslite/tlslite/mathtls.py @@ -0,0 +1,170 @@ +"""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())]) diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py new file mode 100644 index 0000000..afccc79 --- /dev/null +++ b/third_party/tlslite/tlslite/messages.py @@ -0,0 +1,561 @@ +"""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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/AES.py b/third_party/tlslite/tlslite/utils/AES.py new file mode 100644 index 0000000..8413f4c --- /dev/null +++ b/third_party/tlslite/tlslite/utils/AES.py @@ -0,0 +1,31 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/ASN1Parser.py b/third_party/tlslite/tlslite/utils/ASN1Parser.py new file mode 100644 index 0000000..16b50f2 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/ASN1Parser.py @@ -0,0 +1,34 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/Cryptlib_AES.py b/third_party/tlslite/tlslite/utils/Cryptlib_AES.py new file mode 100644 index 0000000..9e101fc --- /dev/null +++ b/third_party/tlslite/tlslite/utils/Cryptlib_AES.py @@ -0,0 +1,34 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/Cryptlib_RC4.py b/third_party/tlslite/tlslite/utils/Cryptlib_RC4.py new file mode 100644 index 0000000..7c6d087 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/Cryptlib_RC4.py @@ -0,0 +1,28 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/Cryptlib_TripleDES.py b/third_party/tlslite/tlslite/utils/Cryptlib_TripleDES.py new file mode 100644 index 0000000..a4f8155 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/Cryptlib_TripleDES.py @@ -0,0 +1,35 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/OpenSSL_AES.py b/third_party/tlslite/tlslite/utils/OpenSSL_AES.py new file mode 100644 index 0000000..e60679b --- /dev/null +++ b/third_party/tlslite/tlslite/utils/OpenSSL_AES.py @@ -0,0 +1,49 @@ +"""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 diff --git a/third_party/tlslite/tlslite/utils/OpenSSL_RC4.py b/third_party/tlslite/tlslite/utils/OpenSSL_RC4.py new file mode 100644 index 0000000..ac433aa --- /dev/null +++ b/third_party/tlslite/tlslite/utils/OpenSSL_RC4.py @@ -0,0 +1,25 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/OpenSSL_RSAKey.py b/third_party/tlslite/tlslite/utils/OpenSSL_RSAKey.py new file mode 100644 index 0000000..fe1a3cd --- /dev/null +++ b/third_party/tlslite/tlslite/utils/OpenSSL_RSAKey.py @@ -0,0 +1,148 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/OpenSSL_TripleDES.py b/third_party/tlslite/tlslite/utils/OpenSSL_TripleDES.py new file mode 100644 index 0000000..f5ba165 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/OpenSSL_TripleDES.py @@ -0,0 +1,44 @@ +"""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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/PyCrypto_AES.py b/third_party/tlslite/tlslite/utils/PyCrypto_AES.py new file mode 100644 index 0000000..e38b19d --- /dev/null +++ b/third_party/tlslite/tlslite/utils/PyCrypto_AES.py @@ -0,0 +1,22 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/PyCrypto_RC4.py b/third_party/tlslite/tlslite/utils/PyCrypto_RC4.py new file mode 100644 index 0000000..6c6d86a --- /dev/null +++ b/third_party/tlslite/tlslite/utils/PyCrypto_RC4.py @@ -0,0 +1,22 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/PyCrypto_RSAKey.py b/third_party/tlslite/tlslite/utils/PyCrypto_RSAKey.py new file mode 100644 index 0000000..48b5cef --- /dev/null +++ b/third_party/tlslite/tlslite/utils/PyCrypto_RSAKey.py @@ -0,0 +1,61 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/PyCrypto_TripleDES.py b/third_party/tlslite/tlslite/utils/PyCrypto_TripleDES.py new file mode 100644 index 0000000..8c22bb8 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/PyCrypto_TripleDES.py @@ -0,0 +1,22 @@ +"""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)
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/Python_AES.py b/third_party/tlslite/tlslite/utils/Python_AES.py new file mode 100644 index 0000000..657152f --- /dev/null +++ b/third_party/tlslite/tlslite/utils/Python_AES.py @@ -0,0 +1,68 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/Python_RC4.py b/third_party/tlslite/tlslite/utils/Python_RC4.py new file mode 100644 index 0000000..56ce5fb --- /dev/null +++ b/third_party/tlslite/tlslite/utils/Python_RC4.py @@ -0,0 +1,39 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/Python_RSAKey.py b/third_party/tlslite/tlslite/utils/Python_RSAKey.py new file mode 100644 index 0000000..b57553a --- /dev/null +++ b/third_party/tlslite/tlslite/utils/Python_RSAKey.py @@ -0,0 +1,209 @@ +"""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+'<privateKey xmlns="http://trevp.net/rsa">\n' + else: + s = indent+'<publicKey xmlns="http://trevp.net/rsa">\n' + s += indent+'\t<n>%s</n>\n' % numberToBase64(self.n) + s += indent+'\t<e>%s</e>\n' % numberToBase64(self.e) + if self.d: + s += indent+'\t<d>%s</d>\n' % numberToBase64(self.d) + s += indent+'\t<p>%s</p>\n' % numberToBase64(self.p) + s += indent+'\t<q>%s</q>\n' % numberToBase64(self.q) + s += indent+'\t<dP>%s</dP>\n' % numberToBase64(self.dP) + s += indent+'\t<dQ>%s</dQ>\n' % numberToBase64(self.dQ) + s += indent+'\t<qInv>%s</qInv>\n' % numberToBase64(self.qInv) + s += indent+'</privateKey>' + else: + s += indent+'</publicKey>' + #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 <privateKey> or <publicKey>, 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 (<n> and <e>) + 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) diff --git a/third_party/tlslite/tlslite/utils/RC4.py b/third_party/tlslite/tlslite/utils/RC4.py new file mode 100644 index 0000000..5506923 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/RC4.py @@ -0,0 +1,17 @@ +"""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()
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/RSAKey.py b/third_party/tlslite/tlslite/utils/RSAKey.py new file mode 100644 index 0000000..37c292d --- /dev/null +++ b/third_party/tlslite/tlslite/utils/RSAKey.py @@ -0,0 +1,264 @@ +"""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 <keyHash> 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 diff --git a/third_party/tlslite/tlslite/utils/TripleDES.py b/third_party/tlslite/tlslite/utils/TripleDES.py new file mode 100644 index 0000000..2db4588 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/TripleDES.py @@ -0,0 +1,26 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/__init__.py b/third_party/tlslite/tlslite/utils/__init__.py new file mode 100644 index 0000000..e96b4be --- /dev/null +++ b/third_party/tlslite/tlslite/utils/__init__.py @@ -0,0 +1,31 @@ +"""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"] diff --git a/third_party/tlslite/tlslite/utils/cipherfactory.py b/third_party/tlslite/tlslite/utils/cipherfactory.py new file mode 100644 index 0000000..ccbb6b5 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/cipherfactory.py @@ -0,0 +1,111 @@ +"""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()
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/codec.py b/third_party/tlslite/tlslite/utils/codec.py new file mode 100644 index 0000000..13022a0 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/codec.py @@ -0,0 +1,94 @@ +"""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()
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/compat.py b/third_party/tlslite/tlslite/utils/compat.py new file mode 100644 index 0000000..7d2d925 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/compat.py @@ -0,0 +1,140 @@ +"""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
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/cryptomath.py b/third_party/tlslite/tlslite/utils/cryptomath.py new file mode 100644 index 0000000..51d6dff --- /dev/null +++ b/third_party/tlslite/tlslite/utils/cryptomath.py @@ -0,0 +1,400 @@ +"""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 diff --git a/third_party/tlslite/tlslite/utils/dateFuncs.py b/third_party/tlslite/tlslite/utils/dateFuncs.py new file mode 100644 index 0000000..38812eb --- /dev/null +++ b/third_party/tlslite/tlslite/utils/dateFuncs.py @@ -0,0 +1,75 @@ + +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) diff --git a/third_party/tlslite/tlslite/utils/entropy.c b/third_party/tlslite/tlslite/utils/entropy.c new file mode 100644 index 0000000..c627794 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/entropy.c @@ -0,0 +1,173 @@ + +#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 <windows.h> + + +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 <unistd.h> +#include <fcntl.h> + +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); +}
\ No newline at end of file diff --git a/third_party/tlslite/tlslite/utils/hmac.py b/third_party/tlslite/tlslite/utils/hmac.py new file mode 100644 index 0000000..fe8feec --- /dev/null +++ b/third_party/tlslite/tlslite/utils/hmac.py @@ -0,0 +1,104 @@ +"""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) diff --git a/third_party/tlslite/tlslite/utils/jython_compat.py b/third_party/tlslite/tlslite/utils/jython_compat.py new file mode 100644 index 0000000..1245183 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/jython_compat.py @@ -0,0 +1,195 @@ +"""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 diff --git a/third_party/tlslite/tlslite/utils/keyfactory.py b/third_party/tlslite/tlslite/utils/keyfactory.py new file mode 100644 index 0000000..5005af7 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/keyfactory.py @@ -0,0 +1,243 @@ +"""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:: + + <publicKey xmlns="http://trevp.net/rsa"> + <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou... + <e>Aw==</e> + </publicKey> + + <privateKey xmlns="http://trevp.net/rsa"> + <n>4a5yzB8oGNlHo866CAspAC47M4Fvx58zwK8pou... + <e>Aw==</e> + <d>JZ0TIgUxWXmL8KJ0VqyG1V0J3ern9pqIoB0xmy... + <p>5PreIj6z6ldIGL1V4+1C36dQFHNCQHJvW52GXc... + <q>/E/wDit8YXPCxx126zTq2ilQ3IcW54NJYyNjiZ... + <dP>mKc+wX8inDowEH45Qp4slRo1YveBgExKPROu6... + <dQ>qDVKtBz9lk0shL5PR3ickXDgkwS576zbl2ztB... + <qInv>j6E8EA7dNsTImaXexAmLA1DoeArsYeFAInr... + </privateKey> + + @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") diff --git a/third_party/tlslite/tlslite/utils/rijndael.py b/third_party/tlslite/tlslite/utils/rijndael.py new file mode 100644 index 0000000..cb2f547 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/rijndael.py @@ -0,0 +1,392 @@ +""" +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) + diff --git a/third_party/tlslite/tlslite/utils/win32prng.c b/third_party/tlslite/tlslite/utils/win32prng.c new file mode 100644 index 0000000..de08b3b --- /dev/null +++ b/third_party/tlslite/tlslite/utils/win32prng.c @@ -0,0 +1,63 @@ + +#include "Python.h" +#define _WIN32_WINNT 0x0400 /* Needed for CryptoAPI on some systems */ +#include <windows.h> + + +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); +} diff --git a/third_party/tlslite/tlslite/utils/xmltools.py b/third_party/tlslite/tlslite/utils/xmltools.py new file mode 100644 index 0000000..06f2e430 --- /dev/null +++ b/third_party/tlslite/tlslite/utils/xmltools.py @@ -0,0 +1,201 @@ +"""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. <empty/>) + #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) |