├── .gitignore ├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README ├── build-requirements.txt ├── pylintrc ├── scripts ├── tls.py └── tlsdb.py ├── setup.py ├── tests ├── TACK1.pem ├── TACK2.pem ├── TACK_Key1.pem ├── TACK_Key2.pem ├── TACKs.pem ├── TACKunrelated.pem ├── clientX509Cert.pem ├── clientX509Key.pem ├── httpsclient.py ├── httpsserver.sh ├── index.html ├── serverX509Cert.pem ├── serverX509Key.pem ├── tlstest.py └── verifierDB ├── tlslite ├── __init__.py ├── api.py ├── basedb.py ├── checker.py ├── constants.py ├── errors.py ├── extensions.py ├── handshakesettings.py ├── integration │ ├── __init__.py │ ├── asyncstatemachine.py │ ├── clienthelper.py │ ├── httptlsconnection.py │ ├── imap4_tls.py │ ├── pop3_tls.py │ ├── smtp_tls.py │ ├── tlsasyncdispatchermixin.py │ ├── tlssocketservermixin.py │ ├── xmlrpcserver.py │ └── xmlrpctransport.py ├── mathtls.py ├── messages.py ├── session.py ├── sessioncache.py ├── tlsconnection.py ├── tlsrecordlayer.py ├── utils │ ├── __init__.py │ ├── aes.py │ ├── asn1parser.py │ ├── cipherfactory.py │ ├── codec.py │ ├── compat.py │ ├── cryptomath.py │ ├── datefuncs.py │ ├── keyfactory.py │ ├── openssl_aes.py │ ├── openssl_rc4.py │ ├── openssl_rsakey.py │ ├── openssl_tripledes.py │ ├── pem.py │ ├── pycrypto_aes.py │ ├── pycrypto_rc4.py │ ├── pycrypto_rsakey.py │ ├── pycrypto_tripledes.py │ ├── python_aes.py │ ├── python_rc4.py │ ├── python_rsakey.py │ ├── rc4.py │ ├── rijndael.py │ ├── rsakey.py │ ├── tackwrapper.py │ └── tripledes.py ├── verifierdb.py ├── x509.py └── x509certchain.py └── unit_tests ├── __init__.py ├── test_tlslite_extensions.py ├── test_tlslite_handshakesettings.py ├── test_tlslite_messages.py ├── test_tlslite_sessioncache.py ├── test_tlslite_utils_codec.py ├── test_tlslite_utils_cryptomath.py └── test_tlslite_utils_keyfactory.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .project 3 | .pydevproject 4 | .settings 5 | .coverage 6 | coverage.xml 7 | pylint_report.txt 8 | build/ 9 | docs/ 10 | htmlcov/ 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | addons: 4 | apt_packages: 5 | # needed for M2Crypto 6 | - swig 7 | # needed for GMPY 8 | - libgmp-dev 9 | 10 | python: 11 | - 2.6 12 | - 2.7 13 | - 3.2 14 | - 3.3 15 | - 3.4 16 | 17 | env: 18 | - TACKPY=true 19 | - TACKPY=false 20 | 21 | matrix: 22 | exclude: 23 | - env: TACKPY=true 24 | include: 25 | - python: 2.7 26 | env: TACKPY=true 27 | - python: 3.4 28 | env: TACKPY=true 29 | - python: 2.7 30 | env: M2CRYPTO=true 31 | # no M2crypto on Python 3 32 | - python: 2.7 33 | env: PYCRYPTO=true 34 | - python: 3.4 35 | env: PYCRYPTO=true 36 | - python: 2.7 37 | env: GMPY=true 38 | - python: 3.4 39 | env: GMPY=true 40 | - python: 2.7 41 | env: M2CRYPTO=true PYCRYPTO=true GMPY=true 42 | - python: 3.4 43 | env: PYCRYPTO=true GMPY=true 44 | 45 | before_install: 46 | - | 47 | echo -e "TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST\n" \ 48 | "TRAVIS_REPO_SLUG=$TRAVIS_REPO_SLUG\n" \ 49 | "TRAVIS_PULL_REQUEST=$TRAVIS_PULL_REQUEST\n" \ 50 | "TRAVIS_COMMIT=$TRAVIS_COMMIT\n" \ 51 | "TRAVIS_PYTHON_VERSION=$TRAVIS_PYTHON_VERSION" 52 | - | 53 | # workaround https://github.com/travis-ci/travis-ci/issues/2666 54 | if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then 55 | URL="https://github.com/${TRAVIS_REPO_SLUG}/pull/${TRAVIS_PULL_REQUEST}.patch" 56 | # `--location` makes curl follow redirects 57 | PR_FIRST=$(curl --silent --show-error --location $URL | head -1 | grep -o -E '\b[0-9a-f]{40}\b' | tr -d '\n') 58 | TRAVIS_COMMIT_RANGE=$PR_FIRST^..$TRAVIS_COMMIT 59 | fi 60 | - echo "TRAVIS_COMMIT_RANGE=$TRAVIS_COMMIT_RANGE" 61 | - git fetch origin master:refs/remotes/origin/master 62 | 63 | install: 64 | - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then travis_retry pip install unittest2; fi 65 | - if [[ $TACKPY == 'true' ]]; then travis_retry pip install tackpy; fi 66 | - if [[ $M2CRYPTO == 'true' ]]; then travis_retry pip install M2Crypto; fi 67 | - if [[ $PYCRYPTO == 'true' ]]; then travis_retry pip install pycrypto; fi 68 | - if [[ $GMPY == 'true' ]]; then travis_retry pip install gmpy; fi 69 | - travis_retry pip install -r build-requirements.txt 70 | 71 | script: 72 | - | 73 | if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then 74 | coverage run --branch --source tlslite -m unittest2 discover; 75 | else 76 | coverage run --branch --source tlslite -m unittest discover; 77 | fi 78 | - coverage report -m 79 | - ./setup.py install && make test 80 | # pylint doesn't work on 2.6: https://bitbucket.org/logilab/pylint/issue/390/py26-compatiblity-broken 81 | # diff-quality doesn't work on 3.2: https://github.com/edx/diff-cover/issues/94 82 | - | 83 | if [[ $TRAVIS_PYTHON_VERSION != '2.6' ]] && [[ $TRAVIS_PYTHON_VERSION != '3.2' ]]; then 84 | pylint --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" tlslite > pylint_report.txt || : 85 | diff-quality --violations=pylint --fail-under=90 pylint_report.txt 86 | fi 87 | - echo "Will test commits between $TRAVIS_COMMIT_RANGE:" 88 | - git log --oneline --reverse $TRAVIS_COMMIT_RANGE 89 | - | 90 | for i in $(git log --pretty=format:%H --reverse $TRAVIS_COMMIT_RANGE); do 91 | git checkout $i 92 | make clean 93 | if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then 94 | unit2 discover || exit 1 95 | else 96 | python -m unittest discover || exit 1 97 | fi 98 | make test-local || exit 1 99 | cd $TRAVIS_BUILD_DIR 100 | done 101 | 102 | sudo: false 103 | 104 | after_success: 105 | - coveralls 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | TLS Lite includes code from different sources. All code is either dedicated to 3 | the public domain by its authors, or available under a BSD-style license. In 4 | particular: 5 | 6 | - 7 | 8 | Code written by Trevor Perrin, Kees Bos, Sam Rushing, Dimitris Moraitis, 9 | Marcelo Fernandez, Martin von Loewis, Dave Baggett, Yngve Pettersen, and 10 | Mirko Dziadzka is available under the following terms: 11 | 12 | This is free and unencumbered software released into the public domain. 13 | 14 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute 15 | this software, either in source code form or as a compiled binary, for any 16 | purpose, commercial or non-commercial, and by any means. 17 | 18 | In jurisdictions that recognize copyright laws, the author or authors of this 19 | software dedicate any and all copyright interest in the software to the public 20 | domain. We make this dedication for the benefit of the public at large and to 21 | the detriment of our heirs and successors. We intend this dedication to be an 22 | overt act of relinquishment in perpetuity of all present and future rights to 23 | this software under copyright law. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | 32 | - 33 | 34 | Code written by Bram Cohen (rijndael.py) was dedicated to the public domain by 35 | its author. See rijndael.py for details. 36 | 37 | - 38 | 39 | Code written by Google is available under the following terms: 40 | 41 | Copyright (c) 2008, The Chromium Authors 42 | All rights reserved. 43 | 44 | Redistribution and use in source and binary forms, with or without 45 | modification, are permitted provided that the following conditions are met: 46 | 47 | * Redistributions of source code must retain the above copyright notice, this 48 | list of conditions and the following disclaimer. 49 | 50 | * Redistributions in binary form must reproduce the above copyright notice, 51 | this list of conditions and the following disclaimer in the documentation 52 | and/or other materials provided with the distribution. 53 | 54 | * Neither the name of the Google Inc. nor the names of its contributors may 55 | be used to endorse or promote products derived from this software without 56 | specific prior written permission. 57 | 58 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 59 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 61 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 62 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 64 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 65 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 66 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 67 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 68 | 69 | - 70 | 71 | Code written by Hubert Kario is available under the following terms: 72 | 73 | Copyright (c) 2014, Hubert Kario, Red Hat Inc. 74 | All rights reserved. 75 | 76 | Redistribution and use in source and binary forms, with or without modification, 77 | are permitted provided that the following conditions are met: 78 | 79 | 1. Redistributions of source code must retain the above copyright notice, this 80 | list of conditions and the following disclaimer. 81 | 82 | 2. Redistributions in binary form must reproduce the above copyright notice, 83 | this list of conditions and the following disclaimer in the documentation 84 | and/or other materials provided with the distribution. 85 | 86 | 3. Neither the name of the copyright holder nor the names of its contributors 87 | may be used to endorse or promote products derived from this software without 88 | specific prior written permission. 89 | 90 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 91 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 92 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 93 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 94 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 95 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 96 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 97 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 98 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 99 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 100 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include tests * 2 | recursive-include docs * 3 | include LICENSE 4 | include README 5 | include Makefile 6 | include MANIFEST.in -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Hubert Kario - test and test-dev 4 | # 5 | PYTHON2 := $(shell which python2 2>/dev/null) 6 | PYTHON3 := $(shell which python3 2>/dev/null) 7 | COVERAGE := $(shell which coverage 2>/dev/null) 8 | COVERAGE2 := $(shell which coverage2 2>/dev/null) 9 | COVERAGE3 := $(shell which coverage3 2>/dev/null) 10 | 11 | .PHONY : default 12 | default: 13 | @echo To install tlslite run \"./setup.py install\" or \"make install\" 14 | 15 | .PHONY: install 16 | install: 17 | ./setup.py install 18 | 19 | .PHONY : clean 20 | clean: 21 | rm -rf tlslite/*.pyc 22 | rm -rf tlslite/utils/*.pyc 23 | rm -rf tlslite/integration/*.pyc 24 | rm -rf unit_tests/*.pyc 25 | rm -rf dist 26 | rm -rf docs 27 | rm -rf build 28 | rm -f MANIFEST 29 | 30 | docs: 31 | epydoc --html -v --introspect-only -o docs --graph all tlslite 32 | 33 | dist: docs 34 | ./setup.py sdist 35 | 36 | test: 37 | cd tests/ && python ./tlstest.py server localhost:4433 . & sleep 1 38 | cd tests/ && python ./tlstest.py client localhost:4433 . 39 | 40 | test-local: 41 | cd tests/ && PYTHONPATH=.. python ./tlstest.py server localhost:4433 . & sleep 1 42 | cd tests/ && PYTHONPATH=.. python ./tlstest.py client localhost:4433 . 43 | 44 | test-dev: 45 | ifdef PYTHON2 46 | @echo "Running test suite with Python 2" 47 | python2 -m unittest discover -v 48 | cd tests/ && PYTHONPATH=.. python2 ./tlstest.py server localhost:4433 . & sleep 1 49 | cd tests/ && PYTHONPATH=.. python2 ./tlstest.py client localhost:4433 . 50 | endif 51 | ifdef PYTHON3 52 | @echo "Running test suite with Python 3" 53 | python3 -m unittest discover -v 54 | cd tests/ && PYTHONPATH=.. python3 ./tlstest.py server localhost:4433 . & sleep 1 55 | cd tests/ && PYTHONPATH=.. python3 ./tlstest.py client localhost:4433 . 56 | endif 57 | ifndef PYTHON2 58 | ifndef PYTHON3 59 | @echo "Running test suite with default Python" 60 | python -m unittest discover -v 61 | cd tests/ && PYTHONPATH=.. python ./tlstest.py server localhost:4433 . & sleep 1 62 | cd tests/ && PYTHONPATH=.. python ./tlstest.py client localhost:4433 . 63 | endif 64 | endif 65 | epydoc --check --fail-on-error -v tlslite 66 | pylint --msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" tlslite > pylint_report.txt || : 67 | diff-quality --violations=pylint --fail-under=90 pylint_report.txt 68 | ifdef COVERAGE2 69 | coverage2 run --branch --source tlslite -m unittest discover 70 | coverage2 report -m 71 | coverage2 xml 72 | diff-cover --fail-under=90 coverage.xml 73 | endif 74 | ifdef COVERAGE3 75 | coverage3 run --branch --source tlslite -m unittest discover 76 | coverage3 report -m 77 | coverage3 xml 78 | diff-cover --fail-under=90 coverage.xml 79 | endif 80 | ifndef COVERAGE2 81 | ifndef COVERAGE3 82 | ifdef COVERAGE 83 | coverage run --branch --source tlslite -m unittest discover 84 | coverage report -m 85 | coverage xml 86 | diff-cover --fail-under=90 coverage.xml 87 | endif 88 | endif 89 | endif 90 | 91 | tests/TACK_Key1.pem: 92 | tack genkey -x -p test -o tests/TACK_Key1.pem 93 | 94 | tests/TACK_Key2.pem: 95 | tack genkey -x -p test -o tests/TACK_Key2.pem 96 | 97 | # the following needs to be used only when the server certificate gets recreated 98 | gen-tacks: tests/TACK_Key1.pem tests/TACK_Key2.pem 99 | tack sign -x -k tests/TACK_Key1.pem -p test -c tests/serverX509Cert.pem -o tests/TACK1.pem 100 | tack sign -x -k tests/TACK_Key2.pem -p test -c tests/serverX509Cert.pem -o tests/TACK2.pem 101 | -------------------------------------------------------------------------------- /build-requirements.txt: -------------------------------------------------------------------------------- 1 | pylint 2 | diff_cover 3 | coverage 4 | coveralls 5 | -------------------------------------------------------------------------------- /scripts/tlsdb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Authors: 4 | # Trevor Perrin 5 | # Martin von Loewis - python 3 port 6 | # 7 | # See the LICENSE file for legal information regarding use of this file. 8 | 9 | from __future__ import print_function 10 | import sys 11 | import os 12 | import socket 13 | import math 14 | 15 | if __name__ != "__main__": 16 | raise "This must be run as a command, not used as a module!" 17 | 18 | 19 | from tlslite import * 20 | from tlslite import __version__ 21 | 22 | if len(sys.argv) == 1 or (len(sys.argv)==2 and sys.argv[1].lower().endswith("help")): 23 | print("") 24 | print("Version: %s" % __version__) 25 | print("") 26 | print("RNG: %s" % prngName) 27 | print("") 28 | print("Modules:") 29 | if m2cryptoLoaded: 30 | print(" M2Crypto : Loaded") 31 | else: 32 | print(" M2Crypto : Not Loaded") 33 | if pycryptoLoaded: 34 | print(" pycrypto : Loaded") 35 | else: 36 | print(" pycrypto : Not Loaded") 37 | if gmpyLoaded: 38 | print(" GMPY : Loaded") 39 | else: 40 | print(" GMPY : Not Loaded") 41 | print("") 42 | print("Commands:") 43 | print("") 44 | print(" createsrp ") 45 | print("") 46 | print(" add []") 47 | print(" del ") 48 | print(" check []") 49 | print(" list ") 50 | sys.exit() 51 | 52 | cmd = sys.argv[1].lower() 53 | 54 | class Args: 55 | def __init__(self, argv): 56 | self.argv = argv 57 | def get(self, index): 58 | if len(self.argv)<=index: 59 | raise SyntaxError("Not enough arguments") 60 | return self.argv[index] 61 | def getLast(self, index): 62 | if len(self.argv)>index+1: 63 | raise SyntaxError("Too many arguments") 64 | return self.get(index) 65 | 66 | args = Args(sys.argv) 67 | 68 | def reformatDocString(s): 69 | lines = s.splitlines() 70 | newLines = [] 71 | for line in lines: 72 | newLines.append(" " + line.strip()) 73 | return "\n".join(newLines) 74 | 75 | try: 76 | if cmd == "help": 77 | command = args.getLast(2).lower() 78 | if command == "valid": 79 | print("") 80 | else: 81 | print("Bad command: '%s'" % command) 82 | 83 | elif cmd == "createsrp": 84 | dbName = args.get(2) 85 | 86 | db = VerifierDB(dbName) 87 | db.create() 88 | 89 | elif cmd == "add": 90 | dbName = args.get(2) 91 | username = args.get(3) 92 | password = args.get(4) 93 | 94 | db = VerifierDB(dbName) 95 | db.open() 96 | if username in db: 97 | print("User already in database!") 98 | sys.exit() 99 | bits = int(args.getLast(5)) 100 | N, g, salt, verifier = VerifierDB.makeVerifier(username, password, bits) 101 | db[username] = N, g, salt, verifier 102 | 103 | elif cmd == "del": 104 | dbName = args.get(2) 105 | username = args.getLast(3) 106 | db = VerifierDB(dbName) 107 | db.open() 108 | del(db[username]) 109 | 110 | elif cmd == "check": 111 | dbName = args.get(2) 112 | username = args.get(3) 113 | if len(sys.argv)>=5: 114 | password = args.getLast(4) 115 | else: 116 | password = None 117 | 118 | db = VerifierDB(dbName) 119 | db.open() 120 | 121 | try: 122 | db[username] 123 | print("Username exists") 124 | 125 | if password: 126 | if db.check(username, password): 127 | print("Password is correct") 128 | else: 129 | print("Password is wrong") 130 | except KeyError: 131 | print("Username does not exist") 132 | sys.exit() 133 | 134 | elif cmd == "list": 135 | dbName = args.get(2) 136 | db = VerifierDB(dbName) 137 | db.open() 138 | 139 | print("Verifier Database") 140 | def numBits(n): 141 | if n==0: 142 | return 0 143 | return int(math.floor(math.log(n, 2))+1) 144 | for username in db.keys(): 145 | N, g, s, v = db[username] 146 | print(numBits(N), username) 147 | else: 148 | print("Bad command: '%s'" % cmd) 149 | except: 150 | raise 151 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Author: Trevor Perrin 4 | # See the LICENSE file for legal information regarding use of this file. 5 | 6 | from distutils.core import setup 7 | 8 | setup(name="tlslite", 9 | version="0.4.9", 10 | author="Trevor Perrin", 11 | author_email="tlslite@trevp.net", 12 | url="http://trevp.net/tlslite/", 13 | description="tlslite implements SSL and TLS.", 14 | license="public domain and BSD", 15 | scripts=["scripts/tls.py", "scripts/tlsdb.py"], 16 | packages=["tlslite", "tlslite.utils", "tlslite.integration"],) 17 | -------------------------------------------------------------------------------- /tests/TACK1.pem: -------------------------------------------------------------------------------- 1 | Created by tack.py 0.9.9 2 | Created at 2015-03-03T21:10:40Z 3 | -----BEGIN TACK----- 4 | QjeXykNtxc22jUSQHO32Uq0HVfg9jKEUHNlqfxtpPAaiJ3mA1O+lI2ZDs8uS+Zdb 5 | /uxswqubymN2Fg5ujrQr2QAAAbtbWsbjtgd+sy84p8w/aiD1a08WGz1A6IsN36Hs 6 | Z5wb70F54Y8N6jZxJp9PZcT4MnFiv58MxrmJAQnIlqx6y8TEzHMS7zj2uu6d+m1N 7 | HhZK/UtLpncs2wwqw8PI5Ea9kcYQXw== 8 | -----END TACK----- 9 | -------------------------------------------------------------------------------- /tests/TACK2.pem: -------------------------------------------------------------------------------- 1 | Created by tack.py 0.9.9 2 | Created at 2015-03-03T21:10:41Z 3 | -----BEGIN TACK----- 4 | 9C+V4IbqF3l/GsK4y1X2wWhis+f2Jw4pX2bCpB22NFDdUV+QiI5Ztpvd1jQFtIH+ 5 | ayr7ycK52KsU7/rRYjX7JwAAAbtbWsbjtgd+sy84p8w/aiD1a08WGz1A6IsN36Hs 6 | Z5wb70F5bmWSnoZ8rqEHkLbqmqjiM+XCDZW+57MUqzT5sid4mkS00g7hMZCFw1q+ 7 | pmv6B7SqyKd5IumU/bdmqt3g/g6xzw== 8 | -----END TACK----- 9 | -------------------------------------------------------------------------------- /tests/TACK_Key1.pem: -------------------------------------------------------------------------------- 1 | Created by tack.py 0.9.9 2 | Created at 2015-03-03T21:09:21Z 3 | -----BEGIN TACK PRIVATE KEY----- 4 | AQAAIABwzwuq6r+poACwbpVJ/DI9GWMdPNh2r5C+khOxccgvTtnb36Rz+YRvdWM5 5 | uFwZKh5CN5fKQ23FzbaNRJAc7fZSrQdV+D2MoRQc2Wp/G2k8BqIneYDU76UjZkOz 6 | y5L5l1v+7GzCq5vKY3YWDm6OtCvZCEvqRIl7bOvhNKa608Xj+49YlJeVzFxlX8Sb 7 | HN1BlEU= 8 | -----END TACK PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /tests/TACK_Key2.pem: -------------------------------------------------------------------------------- 1 | Created by tack.py 0.9.9 2 | Created at 2015-03-03T21:09:21Z 3 | -----BEGIN TACK PRIVATE KEY----- 4 | AQAAIABrNu+M/CwjNVTJe4gD7vow75Bws7ggXZNKl33QAAh81VS+tKgOiCPuLwYS 5 | ft6djk70L5XghuoXeX8awrjLVfbBaGKz5/YnDilfZsKkHbY0UN1RX5CIjlm2m93W 6 | NAW0gf5rKvvJwrnYqxTv+tFiNfsnllxaTH/Pi0hoCjdGNxqFnTGu53H6TYzpU7aK 7 | 3U4t/nA= 8 | -----END TACK PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /tests/TACKs.pem: -------------------------------------------------------------------------------- 1 | Created by TACK.py 0.9.6 2 | Created at 2012-05-08T15:53:56Z 3 | -----BEGIN TACK----- 4 | lJ7JcxIC9y6i/jTkTh+MXf0aO23J58PjUQCAI4vCMINlcMGSC8Vyq9On51hk5zAz 5 | DlIdXzC7zcUC7AN7/alXYwAAAkJ0Bb8+RaM9YEywaJEGViKJJmpYG/gJHgfGaefI 6 | 9kKbXSDmXHI2tbZPnCxzR4ZXz21HxFm1SPYijTKm4zm5dAzXzvneOTRf/SFbY0dZ 7 | s7UpHKK4yOhREoGH8z8kxxD5/BXb5A== 8 | -----END TACK----- 9 | Created by tack.py 0.9.7 10 | Created at 2012-08-31T19:15:38Z 11 | -----BEGIN TACK----- 12 | x7MspJSqsflA4qZ6qG8r8Hd5AB0+BB09n96vuF5Z1ayBeGzrny90WeCu3E3G2d8Y 13 | 620TVYfnALIaMg//MZ8ovQAAAkMcxb8+RaM9YEywaJEGViKJJmpYG/gJHgfGaefI 14 | 9kKbXSDmq3tmkncGftPeMAUh3T2vcXNiRnRqyFArnCKr2gCSj2vsCiS3F+qVhaUv 15 | OyxAcIhminamGruajdPSXMtlCCwWag== 16 | -----END TACK----- 17 | -------------------------------------------------------------------------------- /tests/TACKunrelated.pem: -------------------------------------------------------------------------------- 1 | Created by TACK.py 0.9.6 2 | Created at 2012-05-08T17:12:57Z 3 | -----BEGIN TACK----- 4 | lJ7JcxIC9y6i/jTkTh+MXf0aO23J58PjUQCAI4vCMINlcMGSC8Vyq9On51hk5zAz 5 | DlIdXzC7zcUC7AN7/alXYwMFAchwkzK2S2ZyeiBj5AZvO5WMsKruV2pezv2VM5m7 6 | iHRzHZWHnUVusrs/d04QnVS2Btmt5hECAKdcWK0qZHnMxhZhom9DExiqLQW0A05E 7 | xHvWKhN8y6J9UATLvGjjm3U7oyNxzQ== 8 | -----END TACK----- 9 | -------------------------------------------------------------------------------- /tests/clientX509Cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICfjCCAecCCQDgdeCLz7d92jANBgkqhkiG9w0BAQUFADCBgDELMAkGA1UEBhMC 3 | VVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQHEwdPYWtsYW5kMQ8wDQYDVQQKEwZUcmV2 4 | Q28xCzAJBgNVBAsTAkNBMRIwEAYDVQQDEwlUcmV2Q28gQ0ExIDAeBgkqhkiG9w0B 5 | CQEWEXRsc2xpdGVAdHJldnAubmV0MB4XDTEyMDIwNjAxMDMxMVoXDTQyMDEyOTAx 6 | MDMxMVowgYUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEBxMHT2Fr 7 | bGFuZDEPMA0GA1UEChMGVHJldkNvMQwwCgYDVQQLFANSJkQxFjAUBgNVBAMTDVRy 8 | ZXZvciBQZXJyaW4xIDAeBgkqhkiG9w0BCQEWEXRsc2xpdGVAdHJldnAubmV0MIGf 9 | MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrncYzz0HWlT3ELBTZ1Jt/ZDFWlHW9 10 | SrhlwR5Pd8bEonXCxhomAssz4SkJMaByGFyAUAT4bqf41PV50y5lkYVfgUIy8qQS 11 | Gd/qJrNuFa6odWt3MExQdVCXKTOdjYQmhwvXo6zlf7u/Sj5NICAWmXRHZFBljqG8 12 | QasxPrLSbWUtWQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAJRqUTQ6pZ71rm46+qXo 13 | Sqc5tnj42uIn1eIfnm5pbPxXFvuP3RbuHVO140+LQL844c2JCOKeu9dQPKxoRNU7 14 | sQLdo8+o+KboiYif6m9Ial4ss0I5MhPPVi9heguRbcFHx+87q8xdN7vd6Wn2gw/l 15 | IV+b9EUQMWYFBCokR8o7o+IV 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /tests/clientX509Key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXwIBAAKBgQCrncYzz0HWlT3ELBTZ1Jt/ZDFWlHW9SrhlwR5Pd8bEonXCxhom 3 | Assz4SkJMaByGFyAUAT4bqf41PV50y5lkYVfgUIy8qQSGd/qJrNuFa6odWt3MExQ 4 | dVCXKTOdjYQmhwvXo6zlf7u/Sj5NICAWmXRHZFBljqG8QasxPrLSbWUtWQIDAQAB 5 | AoGBAIo99cMWWTq5zZ+QwtsV4Iyl8PiFbrKk1hVhk0EAgyUymRnk6ntkFLwdzCiT 6 | yWMfLKRP0TEuMjDHm1YfP2ih6ITMh83SLF4og0dDzU+tn3PX/XWaoYZr8HsFTDMi 7 | FhrWXXBX8ST3F2aEyOxXZj8SGFu5YIJ8iemztANzZVSvYkWBAkEA2EbI6rnpXc5t 8 | fKhdkXa0c8l+Uyn/8JadHJ8sobzNhZ/CeC0a9PwhZLQvsRgNXXjYUFJ7N2igoIrk 9 | y0e8f+iD/QJBAMsjFrsrhmXcksf4RX6ZAg1rcJS115JjH2EnbbWd2nBLHUBwywGh 10 | VJhNyQRWBNlVGMrYWCQwHcZNOdUsvmLX140CQQC5v2GDpxQ0irwh2gAylH67CwzB 11 | pEq6eMCK+nI8nojtAJ7m0+ZZDcooUVC8imnAI6+0nIJSvjtmZqPFquDMAgiJAkEA 12 | ox/mXR+yqZHbfSHuDJ+qekRQ/9qW5kMbK9WR0EqW454uO1VYcFKxsCymxAiflDc1 13 | 1Y6uGUFaZ6gUTQ/FQ3K48QJBAIlPKkD8VfNg/3B6wq7gmqRIy9MblLLZo2Qh4nZA 14 | 4icCv/vpHH+o6Ccxad03LQKsTNJl3z52G4sKgASudWiBbLs= 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /tests/httpsclient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | from tlslite import HTTPTLSConnection, HandshakeSettings 4 | 5 | settings = HandshakeSettings() 6 | settings.useExperimentalTackExtension = True 7 | 8 | h = HTTPTLSConnection("localhost", 4443, settings=settings) 9 | h.request("GET", "/index.html") 10 | r = h.getresponse() 11 | print(r.read()) 12 | -------------------------------------------------------------------------------- /tests/httpsserver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | python ../scripts/tls.py server -k serverX509Key.pem -c serverX509Cert.pem -t TACK1.pem localhost:4443 3 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | TLS Lite test server 4 | 5 | 6 |

TLS Lite test server

7 | I am a TLS Lite HTTPS test server
8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/serverX509Cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC+zCCAeOgAwIBAgIJALEP97+mvF6wMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV 3 | BAMMCWxvY2FsaG9zdDAeFw0xNTAzMDMxNTUzNDhaFw0yNTAyMjgxNTUzNDhaMBQx 4 | EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC 5 | ggEBAOYz+2ar/b83RjKoFvYG7Zff7N0BT7qWdSzP6k03r2czbRo0+L1Afh6TLGz/ 6 | H66PftmXDaEPADmmJ8DjiQW05eTDV7HiVLXHG1YK4a7VhdMODFLUjV1w1rip1i/C 7 | WAEbLHZPQZ0gN4bexY1Y7HY5cF5brCbRFHGpSHIj1Jdo3zJBawJpqM9nHDz04nVd 8 | pJKFat8PbGrrGZBhXpg/opwg5GVAbbVroG8Nt7ATeIzY4YCaUS/9rs7J0qV6tatz 9 | egUEGg6aCdsu4FrGQFA2/RRCtEF8H5A6gPdwTex4COR+RVXbaWUnlwyfTRjAVF2x 10 | FiWA0WShLeTblixMxv42qUZidHUCAwEAAaNQME4wHQYDVR0OBBYEFFpCTwDYmMcu 11 | zo+fxFRZJTIChcHqMB8GA1UdIwQYMBaAFFpCTwDYmMcuzo+fxFRZJTIChcHqMAwG 12 | A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBABF66SE6d9Px5nTjuwvq3112 13 | Vw3l1ejJFwauYY36ctPnuNgG0V0A7Hs5ksAvsSe+SGedzASr9vRDy/aZ007Voo4a 14 | tmP3vVtyjT2EHSXWFxLRNVr+vPnFCEBjPVpbmRNeB5odGjFh9oG6UmcdvlS/4rAI 15 | pVOeGw0kx/yXpGRkVB6kc+XcsEi45ERIEYBBdE1RU04y/Q0YfPi6jXF6hTV7bIoH 16 | LEKV/td6Edje2ihjlz33amR8qOv6wH1vUiRj3VRp+aegnigTq3S+FO9mmh7tP/Wg 17 | DOOM6qxItHCcnphOYzY2gaQM5YnsLVmr3HUn/IEUT4uf2VjDNz/a7JWebscQsZI= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /tests/serverX509Key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDmM/tmq/2/N0Yy 3 | qBb2Bu2X3+zdAU+6lnUsz+pNN69nM20aNPi9QH4ekyxs/x+uj37Zlw2hDwA5pifA 4 | 44kFtOXkw1ex4lS1xxtWCuGu1YXTDgxS1I1dcNa4qdYvwlgBGyx2T0GdIDeG3sWN 5 | WOx2OXBeW6wm0RRxqUhyI9SXaN8yQWsCaajPZxw89OJ1XaSShWrfD2xq6xmQYV6Y 6 | P6KcIORlQG21a6BvDbewE3iM2OGAmlEv/a7OydKlerWrc3oFBBoOmgnbLuBaxkBQ 7 | Nv0UQrRBfB+QOoD3cE3seAjkfkVV22llJ5cMn00YwFRdsRYlgNFkoS3k25YsTMb+ 8 | NqlGYnR1AgMBAAECggEAUCu6Wj9716RAZlPz6yrug/4QV8elJK5RkJG4X7wM8jwO 9 | uxnHpuFXCv7mce9H8Vs4Kj9ZF8ZJpcof/iVACyS9C7acS+8u4T++XXDcuC7UtHQo 10 | BpDPysMJhLZhSbC9RWVZTrq7dyVJMUdUNa3KbEIEyFfU1I/sNsll2Zpw52o2kSFe 11 | Ip1TGcnVmFu0uKxPrlNLSSNOVQqz2fOYWBJLk98gk54HAkHpFk92FVorn17seAfS 12 | ksF70B9X6MBUa6PDSgQfKCwGd27KBpTivx6d8QVtMNqrFq/cqZ7TwWDIq1atZ0aF 13 | 3mYXfXR0toRyYZEXaa14Ao7iCUt5D8d2IG9u3q88AQKBgQD5x6kiqO+ApY7V0S0g 14 | SyaIdTBjYc9Rbb0qvgy0Mhq68Ekc2fBIdTLc+G9ajkVFIe5blZc0nvwgSLdRfWrJ 15 | bFpX8SS9Aelgp0mcfXgfIpJmLrPijtgEipTCh/73GTJM3ZnHI1z6xrRP0hi1ww2Q 16 | Z8oqF34H6glXfYHfMqy9VaGQ4QKBgQDr74T4BxiXK4dIQ0T4oRE/881dScrVz9Ok 17 | 3wPINa5bIvfqHPl3eAJgRYBkxjKRyxt29wvGtWBQvCTHvFgF9F+3v3mfXJPRHaZZ 18 | e1VJn9Eqjz1KuArIOwSrmnCFrd9jim10Qo36AFU0myridllN/NQn4l7yYgnw2a1/ 19 | WbLYq2nSFQKBgAkJWyog2IFb+/3qUmqfrWY0byq5SCnXAYgBVi5SvbrTpKGBlPra 20 | Gpv59PVevkzQ/HGdyNmjgtWcK92r3ugonmAeHkkkP5A6nSQnOehOdONzfxiMOG55 21 | oQYkq2m/JJ25Sq30rpF4DN/yZuh0hRIbXyoErY+VvP7IUKGFkNBMv8qhAoGBANDV 22 | pLPJzClanRcIfA86ukMKMPfm7kQM/gAMapOXeGow7JHr7aCiuC+wtTH+ARrtVbUa 23 | fPD48HTl5ARroNo8cVD6idPWJPzPKsQ/l8FgVcs/GHh/qQOMwdiHDhw1R+sax0FF 24 | +9eS3dh/lBj5uph+NufKxlHzF2t5sclsgxKnvzX1AoGAZlNZt2xn3q/kusUXLovS 25 | WN8C3ty06qLbD99kiWqEC2gSXc94rk7K7R/1XgfxXV8uOA9eUPDBpchd9PUnhwBE 26 | tnkuQZ0fZ1P6EpNTumeL/UvIaA2UFtqrzxxJPJQExPRqX5foT6FhXVtGrNGKw78C 27 | Ft7IqSkjX742rx0ephmvZgE= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/verifierDB: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trevp/tlslite/cd82fadb6bb958522b7457c5ed95890283437a4f/tests/verifierDB -------------------------------------------------------------------------------- /tlslite/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """TLS Lite is a free python library that implements SSL and TLS. TLS Lite 5 | supports RSA and SRP ciphersuites. TLS Lite is pure python, however it can use 6 | other libraries for faster crypto operations. TLS Lite integrates with several 7 | stdlib neworking libraries. 8 | 9 | API documentation is available in the 'docs' directory. 10 | 11 | If you have questions or feedback, feel free to contact me. 12 | 13 | To use, do:: 14 | 15 | from tlslite import TLSConnection, ... 16 | 17 | If you want to import the most useful objects, the cleanest way is:: 18 | 19 | from tlslite.api import * 20 | 21 | Then use the L{tlslite.TLSConnection.TLSConnection} class with a socket. 22 | (Or, use one of the integration classes in L{tlslite.integration}). 23 | 24 | @version: 0.4.9 25 | """ 26 | 27 | from tlslite.api import * 28 | from tlslite.api import __version__ # Unsure why this is needed, but it is 29 | -------------------------------------------------------------------------------- /tlslite/api.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | __version__ = "0.4.9" 5 | from .constants import AlertLevel, AlertDescription, Fault 6 | from .errors import * 7 | from .checker import Checker 8 | from .handshakesettings import HandshakeSettings 9 | from .session import Session 10 | from .sessioncache import SessionCache 11 | from .tlsconnection import TLSConnection 12 | from .verifierdb import VerifierDB 13 | from .x509 import X509 14 | from .x509certchain import X509CertChain 15 | 16 | from .integration.httptlsconnection import HTTPTLSConnection 17 | from .integration.tlssocketservermixin import TLSSocketServerMixIn 18 | from .integration.tlsasyncdispatchermixin import TLSAsyncDispatcherMixIn 19 | from .integration.pop3_tls import POP3_TLS 20 | from .integration.imap4_tls import IMAP4_TLS 21 | from .integration.smtp_tls import SMTP_TLS 22 | from .integration.xmlrpctransport import XMLRPCTransport 23 | from .integration.xmlrpcserver import TLSXMLRPCRequestHandler, \ 24 | TLSXMLRPCServer, \ 25 | MultiPathTLSXMLRPCServer 26 | 27 | from .utils.cryptomath import m2cryptoLoaded, gmpyLoaded, \ 28 | pycryptoLoaded, prngName 29 | from .utils.keyfactory import generateRSAKey, parsePEMKey, \ 30 | parseAsPublicKey, parsePrivateKey 31 | from .utils.tackwrapper import tackpyLoaded 32 | -------------------------------------------------------------------------------- /tlslite/basedb.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Martin von Loewis - python 3 port 4 | # 5 | # See the LICENSE file for legal information regarding use of this file. 6 | 7 | """Base class for SharedKeyDB and VerifierDB.""" 8 | 9 | try: 10 | import anydbm 11 | except ImportError: 12 | # Python 3 13 | import dbm as anydbm 14 | import threading 15 | 16 | class BaseDB(object): 17 | def __init__(self, filename, type): 18 | self.type = type 19 | self.filename = filename 20 | if self.filename: 21 | self.db = None 22 | else: 23 | self.db = {} 24 | self.lock = threading.Lock() 25 | 26 | def create(self): 27 | """Create a new on-disk database. 28 | 29 | @raise anydbm.error: If there's a problem creating the database. 30 | """ 31 | if self.filename: 32 | self.db = anydbm.open(self.filename, "n") #raises anydbm.error 33 | self.db["--Reserved--type"] = self.type 34 | self.db.sync() 35 | else: 36 | self.db = {} 37 | 38 | def open(self): 39 | """Open a pre-existing on-disk database. 40 | 41 | @raise anydbm.error: If there's a problem opening the database. 42 | @raise ValueError: If the database is not of the right type. 43 | """ 44 | if not self.filename: 45 | raise ValueError("Can only open on-disk databases") 46 | self.db = anydbm.open(self.filename, "w") #raises anydbm.error 47 | try: 48 | if self.db["--Reserved--type"] != self.type: 49 | raise ValueError("Not a %s database" % self.type) 50 | except KeyError: 51 | raise ValueError("Not a recognized database") 52 | 53 | def __getitem__(self, username): 54 | if self.db == None: 55 | raise AssertionError("DB not open") 56 | 57 | self.lock.acquire() 58 | try: 59 | valueStr = self.db[username] 60 | finally: 61 | self.lock.release() 62 | 63 | return self._getItem(username, valueStr) 64 | 65 | def __setitem__(self, username, value): 66 | if self.db == None: 67 | raise AssertionError("DB not open") 68 | 69 | valueStr = self._setItem(username, value) 70 | 71 | self.lock.acquire() 72 | try: 73 | self.db[username] = valueStr 74 | if self.filename: 75 | self.db.sync() 76 | finally: 77 | self.lock.release() 78 | 79 | def __delitem__(self, username): 80 | if self.db == None: 81 | raise AssertionError("DB not open") 82 | 83 | self.lock.acquire() 84 | try: 85 | del(self.db[username]) 86 | if self.filename: 87 | self.db.sync() 88 | finally: 89 | self.lock.release() 90 | 91 | def __contains__(self, username): 92 | """Check if the database contains the specified username. 93 | 94 | @type username: str 95 | @param username: The username to check for. 96 | 97 | @rtype: bool 98 | @return: True if the database contains the username, False 99 | otherwise. 100 | 101 | """ 102 | if self.db == None: 103 | raise AssertionError("DB not open") 104 | 105 | self.lock.acquire() 106 | try: 107 | return self.db.has_key(username) 108 | finally: 109 | self.lock.release() 110 | 111 | def check(self, username, param): 112 | value = self.__getitem__(username) 113 | return self._checkItem(value, username, param) 114 | 115 | def keys(self): 116 | """Return a list of usernames in the database. 117 | 118 | @rtype: list 119 | @return: The usernames in the database. 120 | """ 121 | if self.db == None: 122 | raise AssertionError("DB not open") 123 | 124 | self.lock.acquire() 125 | try: 126 | usernames = self.db.keys() 127 | finally: 128 | self.lock.release() 129 | usernames = [u for u in usernames if not u.startswith("--Reserved--")] 130 | return usernames 131 | -------------------------------------------------------------------------------- /tlslite/checker.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Class for post-handshake certificate checking.""" 5 | 6 | from .x509 import X509 7 | from .x509certchain import X509CertChain 8 | from .errors import * 9 | 10 | 11 | class Checker(object): 12 | """This class is passed to a handshake function to check the other 13 | party's certificate chain. 14 | 15 | If a handshake function completes successfully, but the Checker 16 | judges the other party's certificate chain to be missing or 17 | inadequate, a subclass of 18 | L{tlslite.errors.TLSAuthenticationError} will be raised. 19 | 20 | Currently, the Checker can check an X.509 chain. 21 | """ 22 | 23 | def __init__(self, 24 | x509Fingerprint=None, 25 | checkResumedSession=False): 26 | """Create a new Checker instance. 27 | 28 | You must pass in one of these argument combinations: 29 | - x509Fingerprint 30 | 31 | @type x509Fingerprint: str 32 | @param x509Fingerprint: A hex-encoded X.509 end-entity 33 | fingerprint which the other party's end-entity certificate must 34 | match. 35 | 36 | @type checkResumedSession: bool 37 | @param checkResumedSession: If resumed sessions should be 38 | checked. This defaults to False, on the theory that if the 39 | session was checked once, we don't need to bother 40 | re-checking it. 41 | """ 42 | 43 | self.x509Fingerprint = x509Fingerprint 44 | self.checkResumedSession = checkResumedSession 45 | 46 | def __call__(self, connection): 47 | """Check a TLSConnection. 48 | 49 | When a Checker is passed to a handshake function, this will 50 | be called at the end of the function. 51 | 52 | @type connection: L{tlslite.tlsconnection.TLSConnection} 53 | @param connection: The TLSConnection to examine. 54 | 55 | @raise tlslite.errors.TLSAuthenticationError: If the other 56 | party's certificate chain is missing or bad. 57 | """ 58 | if not self.checkResumedSession and connection.resumed: 59 | return 60 | 61 | if self.x509Fingerprint: 62 | if connection._client: 63 | chain = connection.session.serverCertChain 64 | else: 65 | chain = connection.session.clientCertChain 66 | 67 | if self.x509Fingerprint: 68 | if isinstance(chain, X509CertChain): 69 | if self.x509Fingerprint: 70 | if chain.getFingerprint() != self.x509Fingerprint: 71 | raise TLSFingerprintError(\ 72 | "X.509 fingerprint mismatch: %s, %s" % \ 73 | (chain.getFingerprint(), self.x509Fingerprint)) 74 | elif chain: 75 | raise TLSAuthenticationTypeError() 76 | else: 77 | raise TLSNoAuthenticationError() -------------------------------------------------------------------------------- /tlslite/errors.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Dave Baggett (Arcode Corporation) - Added TLSUnsupportedError. 4 | # 5 | # See the LICENSE file for legal information regarding use of this file. 6 | 7 | """Exception classes. 8 | @sort: TLSError, TLSAbruptCloseError, TLSAlert, TLSLocalAlert, TLSRemoteAlert, 9 | TLSAuthenticationError, TLSNoAuthenticationError, TLSAuthenticationTypeError, 10 | TLSFingerprintError, TLSAuthorizationError, TLSValidationError, TLSFaultError, 11 | TLSUnsupportedError 12 | """ 13 | import socket 14 | 15 | from .constants import AlertDescription, AlertLevel 16 | 17 | class TLSError(Exception): 18 | """Base class for all TLS Lite exceptions.""" 19 | 20 | def __str__(self): 21 | """"At least print out the Exception time for str(...).""" 22 | return repr(self) 23 | 24 | class TLSClosedConnectionError(TLSError, socket.error): 25 | """An attempt was made to use the connection after it was closed.""" 26 | pass 27 | 28 | class TLSAbruptCloseError(TLSError): 29 | """The socket was closed without a proper TLS shutdown. 30 | 31 | The TLS specification mandates that an alert of some sort 32 | must be sent before the underlying socket is closed. If the socket 33 | is closed without this, it could signify that an attacker is trying 34 | to truncate the connection. It could also signify a misbehaving 35 | TLS implementation, or a random network failure. 36 | """ 37 | pass 38 | 39 | class TLSAlert(TLSError): 40 | """A TLS alert has been signalled.""" 41 | pass 42 | 43 | _descriptionStr = {\ 44 | AlertDescription.close_notify: "close_notify",\ 45 | AlertDescription.unexpected_message: "unexpected_message",\ 46 | AlertDescription.bad_record_mac: "bad_record_mac",\ 47 | AlertDescription.decryption_failed: "decryption_failed",\ 48 | AlertDescription.record_overflow: "record_overflow",\ 49 | AlertDescription.decompression_failure: "decompression_failure",\ 50 | AlertDescription.handshake_failure: "handshake_failure",\ 51 | AlertDescription.no_certificate: "no certificate",\ 52 | AlertDescription.bad_certificate: "bad_certificate",\ 53 | AlertDescription.unsupported_certificate: "unsupported_certificate",\ 54 | AlertDescription.certificate_revoked: "certificate_revoked",\ 55 | AlertDescription.certificate_expired: "certificate_expired",\ 56 | AlertDescription.certificate_unknown: "certificate_unknown",\ 57 | AlertDescription.illegal_parameter: "illegal_parameter",\ 58 | AlertDescription.unknown_ca: "unknown_ca",\ 59 | AlertDescription.access_denied: "access_denied",\ 60 | AlertDescription.decode_error: "decode_error",\ 61 | AlertDescription.decrypt_error: "decrypt_error",\ 62 | AlertDescription.export_restriction: "export_restriction",\ 63 | AlertDescription.protocol_version: "protocol_version",\ 64 | AlertDescription.insufficient_security: "insufficient_security",\ 65 | AlertDescription.internal_error: "internal_error",\ 66 | AlertDescription.inappropriate_fallback: "inappropriate_fallback",\ 67 | AlertDescription.user_canceled: "user_canceled",\ 68 | AlertDescription.no_renegotiation: "no_renegotiation",\ 69 | AlertDescription.unknown_psk_identity: "unknown_psk_identity"} 70 | 71 | class TLSLocalAlert(TLSAlert): 72 | """A TLS alert has been signalled by the local implementation. 73 | 74 | @type description: int 75 | @ivar description: Set to one of the constants in 76 | L{tlslite.constants.AlertDescription} 77 | 78 | @type level: int 79 | @ivar level: Set to one of the constants in 80 | L{tlslite.constants.AlertLevel} 81 | 82 | @type message: str 83 | @ivar message: Description of what went wrong. 84 | """ 85 | def __init__(self, alert, message=None): 86 | self.description = alert.description 87 | self.level = alert.level 88 | self.message = message 89 | 90 | def __str__(self): 91 | alertStr = TLSAlert._descriptionStr.get(self.description) 92 | if alertStr == None: 93 | alertStr = str(self.description) 94 | if self.message: 95 | return alertStr + ": " + self.message 96 | else: 97 | return alertStr 98 | 99 | class TLSRemoteAlert(TLSAlert): 100 | """A TLS alert has been signalled by the remote implementation. 101 | 102 | @type description: int 103 | @ivar description: Set to one of the constants in 104 | L{tlslite.constants.AlertDescription} 105 | 106 | @type level: int 107 | @ivar level: Set to one of the constants in 108 | L{tlslite.constants.AlertLevel} 109 | """ 110 | def __init__(self, alert): 111 | self.description = alert.description 112 | self.level = alert.level 113 | 114 | def __str__(self): 115 | alertStr = TLSAlert._descriptionStr.get(self.description) 116 | if alertStr == None: 117 | alertStr = str(self.description) 118 | return alertStr 119 | 120 | class TLSAuthenticationError(TLSError): 121 | """The handshake succeeded, but the other party's authentication 122 | was inadequate. 123 | 124 | This exception will only be raised when a 125 | L{tlslite.Checker.Checker} has been passed to a handshake function. 126 | The Checker will be invoked once the handshake completes, and if 127 | the Checker objects to how the other party authenticated, a 128 | subclass of this exception will be raised. 129 | """ 130 | pass 131 | 132 | class TLSNoAuthenticationError(TLSAuthenticationError): 133 | """The Checker was expecting the other party to authenticate with a 134 | certificate chain, but this did not occur.""" 135 | pass 136 | 137 | class TLSAuthenticationTypeError(TLSAuthenticationError): 138 | """The Checker was expecting the other party to authenticate with a 139 | different type of certificate chain.""" 140 | pass 141 | 142 | class TLSFingerprintError(TLSAuthenticationError): 143 | """The Checker was expecting the other party to authenticate with a 144 | certificate chain that matches a different fingerprint.""" 145 | pass 146 | 147 | class TLSAuthorizationError(TLSAuthenticationError): 148 | """The Checker was expecting the other party to authenticate with a 149 | certificate chain that has a different authorization.""" 150 | pass 151 | 152 | class TLSValidationError(TLSAuthenticationError): 153 | """The Checker has determined that the other party's certificate 154 | chain is invalid.""" 155 | def __init__(self, msg, info=None): 156 | # Include a dict containing info about this validation failure 157 | TLSAuthenticationError.__init__(self, msg) 158 | self.info = info 159 | 160 | class TLSFaultError(TLSError): 161 | """The other party responded incorrectly to an induced fault. 162 | 163 | This exception will only occur during fault testing, when a 164 | TLSConnection's fault variable is set to induce some sort of 165 | faulty behavior, and the other party doesn't respond appropriately. 166 | """ 167 | pass 168 | 169 | 170 | class TLSUnsupportedError(TLSError): 171 | """The implementation doesn't support the requested (or required) 172 | capabilities.""" 173 | pass 174 | 175 | class TLSInternalError(TLSError): 176 | """The internal state of object is unexpected or invalid""" 177 | pass 178 | -------------------------------------------------------------------------------- /tlslite/handshakesettings.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Dave Baggett (Arcode Corporation) - cleanup handling of constants 4 | # Yngve Pettersen (ported by Paul Sokolovsky) - TLS 1.2 5 | # 6 | # See the LICENSE file for legal information regarding use of this file. 7 | 8 | """Class for setting handshake parameters.""" 9 | 10 | from .constants import CertificateType 11 | from .utils import cryptomath 12 | from .utils import cipherfactory 13 | 14 | # RC4 is preferred as faster in Python, works in SSL3, and immune to CBC 15 | # issues such as timing attacks 16 | CIPHER_NAMES = ["rc4", "aes256", "aes128", "3des"] 17 | MAC_NAMES = ["sha", "sha256"] # "md5" is allowed 18 | CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"] 19 | CERTIFICATE_TYPES = ["x509"] 20 | 21 | class HandshakeSettings(object): 22 | """This class encapsulates various parameters that can be used with 23 | a TLS handshake. 24 | @sort: minKeySize, maxKeySize, cipherNames, macNames, certificateTypes, 25 | minVersion, maxVersion 26 | 27 | @type minKeySize: int 28 | @ivar minKeySize: The minimum bit length for asymmetric keys. 29 | 30 | If the other party tries to use SRP, RSA, or Diffie-Hellman 31 | parameters smaller than this length, an alert will be 32 | signalled. The default is 1023. 33 | 34 | @type maxKeySize: int 35 | @ivar maxKeySize: The maximum bit length for asymmetric keys. 36 | 37 | If the other party tries to use SRP, RSA, or Diffie-Hellman 38 | parameters larger than this length, an alert will be signalled. 39 | The default is 8193. 40 | 41 | @type cipherNames: list 42 | @ivar cipherNames: The allowed ciphers, in order of preference. 43 | 44 | The allowed values in this list are 'aes256', 'aes128', '3des', and 45 | 'rc4'. If these settings are used with a client handshake, they 46 | determine the order of the ciphersuites offered in the ClientHello 47 | message. 48 | 49 | If these settings are used with a server handshake, the server will 50 | choose whichever ciphersuite matches the earliest entry in this 51 | list. 52 | 53 | NOTE: If '3des' is used in this list, but TLS Lite can't find an 54 | add-on library that supports 3DES, then '3des' will be silently 55 | removed. 56 | 57 | The default value is ['rc4', 'aes256', 'aes128', '3des']. 58 | 59 | @type macNames: list 60 | @ivar macNames: The allowed MAC algorithms. 61 | 62 | The allowed values in this list are 'sha' and 'md5'. 63 | 64 | The default value is ['sha']. 65 | 66 | 67 | @type certificateTypes: list 68 | @ivar certificateTypes: The allowed certificate types, in order of 69 | preference. 70 | 71 | The only allowed certificate type is 'x509'. This list is only used with a 72 | client handshake. The client will advertise to the server which certificate 73 | types are supported, and will check that the server uses one of the 74 | appropriate types. 75 | 76 | 77 | @type minVersion: tuple 78 | @ivar minVersion: The minimum allowed SSL/TLS version. 79 | 80 | This variable can be set to (3,0) for SSL 3.0, (3,1) for TLS 1.0, (3,2) for 81 | TLS 1.1, or (3,3) for TLS 1.2. If the other party wishes to use a lower 82 | version, a protocol_version alert will be signalled. The default is (3,1). 83 | 84 | @type maxVersion: tuple 85 | @ivar maxVersion: The maximum allowed SSL/TLS version. 86 | 87 | This variable can be set to (3,0) for SSL 3.0, (3,1) for TLS 1.0, (3,2) for 88 | TLS 1.1, or (3,3) for TLS 1.2. If the other party wishes to use a higher 89 | version, a protocol_version alert will be signalled. The default is (3,3). 90 | (WARNING: Some servers may (improperly) reject clients which offer support 91 | for TLS 1.1. In this case, try lowering maxVersion to (3,1)). 92 | 93 | @type useExperimentalTackExtension: bool 94 | @ivar useExperimentalTackExtension: Whether to enabled TACK support. 95 | 96 | Note that TACK support is not standardized by IETF and uses a temporary 97 | TLS Extension number, so should NOT be used in production software. 98 | 99 | @type sendFallbackSCSV: bool 100 | @ivar sendFallbackSCSV: Whether to, as a client, send FALLBACK_SCSV. 101 | """ 102 | def __init__(self): 103 | self.minKeySize = 1023 104 | self.maxKeySize = 8193 105 | self.cipherNames = CIPHER_NAMES 106 | self.macNames = MAC_NAMES 107 | self.cipherImplementations = CIPHER_IMPLEMENTATIONS 108 | self.certificateTypes = CERTIFICATE_TYPES 109 | self.minVersion = (3,1) 110 | self.maxVersion = (3,3) 111 | self.useExperimentalTackExtension = False 112 | self.sendFallbackSCSV = False 113 | 114 | def validate(self): 115 | """ 116 | Validate the settings, filter out unsupported ciphersuites and return 117 | a copy of object. Does not modify the original object. 118 | 119 | @rtype: HandshakeSettings 120 | @return: a self-consistent copy of settings 121 | @raise ValueError: when settings are invalid, insecure or unsupported. 122 | """ 123 | other = HandshakeSettings() 124 | other.minKeySize = self.minKeySize 125 | other.maxKeySize = self.maxKeySize 126 | other.cipherNames = self.cipherNames 127 | other.macNames = self.macNames 128 | other.cipherImplementations = self.cipherImplementations 129 | other.certificateTypes = self.certificateTypes 130 | other.minVersion = self.minVersion 131 | other.maxVersion = self.maxVersion 132 | other.sendFallbackSCSV = self.sendFallbackSCSV 133 | 134 | if other.maxVersion < (3,3): 135 | other.macNames = [e for e in self.macNames if e != "sha256"] 136 | 137 | if not cipherfactory.tripleDESPresent: 138 | other.cipherNames = [e for e in self.cipherNames if e != "3des"] 139 | if len(other.cipherNames)==0: 140 | raise ValueError("No supported ciphers") 141 | if len(other.certificateTypes)==0: 142 | raise ValueError("No supported certificate types") 143 | 144 | if not cryptomath.m2cryptoLoaded: 145 | other.cipherImplementations = \ 146 | [e for e in other.cipherImplementations if e != "openssl"] 147 | if not cryptomath.pycryptoLoaded: 148 | other.cipherImplementations = \ 149 | [e for e in other.cipherImplementations if e != "pycrypto"] 150 | if len(other.cipherImplementations)==0: 151 | raise ValueError("No supported cipher implementations") 152 | 153 | if other.minKeySize<512: 154 | raise ValueError("minKeySize too small") 155 | if other.minKeySize>16384: 156 | raise ValueError("minKeySize too large") 157 | if other.maxKeySize<512: 158 | raise ValueError("maxKeySize too small") 159 | if other.maxKeySize>16384: 160 | raise ValueError("maxKeySize too large") 161 | if other.maxKeySize < other.minKeySize: 162 | raise ValueError("maxKeySize smaller than minKeySize") 163 | for s in other.cipherNames: 164 | if s not in CIPHER_NAMES: 165 | raise ValueError("Unknown cipher name: '%s'" % s) 166 | for s in other.cipherImplementations: 167 | if s not in CIPHER_IMPLEMENTATIONS: 168 | raise ValueError("Unknown cipher implementation: '%s'" % s) 169 | for s in other.certificateTypes: 170 | if s not in CERTIFICATE_TYPES: 171 | raise ValueError("Unknown certificate type: '%s'" % s) 172 | 173 | if other.minVersion > other.maxVersion: 174 | raise ValueError("Versions set incorrectly") 175 | 176 | if not other.minVersion in ((3,0), (3,1), (3,2), (3,3)): 177 | raise ValueError("minVersion set incorrectly") 178 | 179 | if not other.maxVersion in ((3,0), (3,1), (3,2), (3,3)): 180 | raise ValueError("maxVersion set incorrectly") 181 | 182 | return other 183 | 184 | def getCertificateTypes(self): 185 | """Get list of certificate types as IDs""" 186 | ret = [] 187 | for ct in self.certificateTypes: 188 | if ct == "x509": 189 | ret.append(CertificateType.x509) 190 | else: 191 | raise AssertionError() 192 | return ret 193 | -------------------------------------------------------------------------------- /tlslite/integration/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Classes for integrating TLS Lite with other packages.""" 5 | 6 | __all__ = ["asyncstatemachine", 7 | "httptlsconnection", 8 | "pop3_tls", 9 | "imap4_tls", 10 | "smtp_tls", 11 | "xmlrpctransport", 12 | "tlssocketservermixin", 13 | "tlsasyncdispatchermixin"] 14 | -------------------------------------------------------------------------------- /tlslite/integration/asyncstatemachine.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """ 5 | A state machine for using TLS Lite with asynchronous I/O. 6 | """ 7 | 8 | class AsyncStateMachine: 9 | """ 10 | This is an abstract class that's used to integrate TLS Lite with 11 | asyncore and Twisted. 12 | 13 | This class signals wantsReadsEvent() and wantsWriteEvent(). When 14 | the underlying socket has become readable or writeable, the event 15 | should be passed to this class by calling inReadEvent() or 16 | inWriteEvent(). This class will then try to read or write through 17 | the socket, and will update its state appropriately. 18 | 19 | This class will forward higher-level events to its subclass. For 20 | example, when a complete TLS record has been received, 21 | outReadEvent() will be called with the decrypted data. 22 | """ 23 | 24 | def __init__(self): 25 | self._clear() 26 | 27 | def _clear(self): 28 | #These store the various asynchronous operations (i.e. 29 | #generators). Only one of them, at most, is ever active at a 30 | #time. 31 | self.handshaker = None 32 | self.closer = None 33 | self.reader = None 34 | self.writer = None 35 | 36 | #This stores the result from the last call to the 37 | #currently active operation. If 0 it indicates that the 38 | #operation wants to read, if 1 it indicates that the 39 | #operation wants to write. If None, there is no active 40 | #operation. 41 | self.result = None 42 | 43 | def _checkAssert(self, maxActive=1): 44 | #This checks that only one operation, at most, is 45 | #active, and that self.result is set appropriately. 46 | activeOps = 0 47 | if self.handshaker: 48 | activeOps += 1 49 | if self.closer: 50 | activeOps += 1 51 | if self.reader: 52 | activeOps += 1 53 | if self.writer: 54 | activeOps += 1 55 | 56 | if self.result == None: 57 | if activeOps != 0: 58 | raise AssertionError() 59 | elif self.result in (0,1): 60 | if activeOps != 1: 61 | raise AssertionError() 62 | else: 63 | raise AssertionError() 64 | if activeOps > maxActive: 65 | raise AssertionError() 66 | 67 | def wantsReadEvent(self): 68 | """If the state machine wants to read. 69 | 70 | If an operation is active, this returns whether or not the 71 | operation wants to read from the socket. If an operation is 72 | not active, this returns None. 73 | 74 | @rtype: bool or None 75 | @return: If the state machine wants to read. 76 | """ 77 | if self.result != None: 78 | return self.result == 0 79 | return None 80 | 81 | def wantsWriteEvent(self): 82 | """If the state machine wants to write. 83 | 84 | If an operation is active, this returns whether or not the 85 | operation wants to write to the socket. If an operation is 86 | not active, this returns None. 87 | 88 | @rtype: bool or None 89 | @return: If the state machine wants to write. 90 | """ 91 | if self.result != None: 92 | return self.result == 1 93 | return None 94 | 95 | def outConnectEvent(self): 96 | """Called when a handshake operation completes. 97 | 98 | May be overridden in subclass. 99 | """ 100 | pass 101 | 102 | def outCloseEvent(self): 103 | """Called when a close operation completes. 104 | 105 | May be overridden in subclass. 106 | """ 107 | pass 108 | 109 | def outReadEvent(self, readBuffer): 110 | """Called when a read operation completes. 111 | 112 | May be overridden in subclass.""" 113 | pass 114 | 115 | def outWriteEvent(self): 116 | """Called when a write operation completes. 117 | 118 | May be overridden in subclass.""" 119 | pass 120 | 121 | def inReadEvent(self): 122 | """Tell the state machine it can read from the socket.""" 123 | try: 124 | self._checkAssert() 125 | if self.handshaker: 126 | self._doHandshakeOp() 127 | elif self.closer: 128 | self._doCloseOp() 129 | elif self.reader: 130 | self._doReadOp() 131 | elif self.writer: 132 | self._doWriteOp() 133 | else: 134 | self.reader = self.tlsConnection.readAsync(16384) 135 | self._doReadOp() 136 | except: 137 | self._clear() 138 | raise 139 | 140 | def inWriteEvent(self): 141 | """Tell the state machine it can write to the socket.""" 142 | try: 143 | self._checkAssert() 144 | if self.handshaker: 145 | self._doHandshakeOp() 146 | elif self.closer: 147 | self._doCloseOp() 148 | elif self.reader: 149 | self._doReadOp() 150 | elif self.writer: 151 | self._doWriteOp() 152 | else: 153 | self.outWriteEvent() 154 | except: 155 | self._clear() 156 | raise 157 | 158 | def _doHandshakeOp(self): 159 | try: 160 | self.result = self.handshaker.next() 161 | except StopIteration: 162 | self.handshaker = None 163 | self.result = None 164 | self.outConnectEvent() 165 | 166 | def _doCloseOp(self): 167 | try: 168 | self.result = self.closer.next() 169 | except StopIteration: 170 | self.closer = None 171 | self.result = None 172 | self.outCloseEvent() 173 | 174 | def _doReadOp(self): 175 | self.result = self.reader.next() 176 | if not self.result in (0,1): 177 | readBuffer = self.result 178 | self.reader = None 179 | self.result = None 180 | self.outReadEvent(readBuffer) 181 | 182 | def _doWriteOp(self): 183 | try: 184 | self.result = self.writer.next() 185 | except StopIteration: 186 | self.writer = None 187 | self.result = None 188 | 189 | def setHandshakeOp(self, handshaker): 190 | """Start a handshake operation. 191 | 192 | @type handshaker: generator 193 | @param handshaker: A generator created by using one of the 194 | asynchronous handshake functions (i.e. handshakeServerAsync, or 195 | handshakeClientxxx(..., async=True). 196 | """ 197 | try: 198 | self._checkAssert(0) 199 | self.handshaker = handshaker 200 | self._doHandshakeOp() 201 | except: 202 | self._clear() 203 | raise 204 | 205 | def setServerHandshakeOp(self, **args): 206 | """Start a handshake operation. 207 | 208 | The arguments passed to this function will be forwarded to 209 | L{tlslite.tlsconnection.TLSConnection.handshakeServerAsync}. 210 | """ 211 | handshaker = self.tlsConnection.handshakeServerAsync(**args) 212 | self.setHandshakeOp(handshaker) 213 | 214 | def setCloseOp(self): 215 | """Start a close operation. 216 | """ 217 | try: 218 | self._checkAssert(0) 219 | self.closer = self.tlsConnection.closeAsync() 220 | self._doCloseOp() 221 | except: 222 | self._clear() 223 | raise 224 | 225 | def setWriteOp(self, writeBuffer): 226 | """Start a write operation. 227 | 228 | @type writeBuffer: str 229 | @param writeBuffer: The string to transmit. 230 | """ 231 | try: 232 | self._checkAssert(0) 233 | self.writer = self.tlsConnection.writeAsync(writeBuffer) 234 | self._doWriteOp() 235 | except: 236 | self._clear() 237 | raise 238 | 239 | -------------------------------------------------------------------------------- /tlslite/integration/clienthelper.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Dimitris Moraitis - Anon ciphersuites 4 | # 5 | # See the LICENSE file for legal information regarding use of this file. 6 | 7 | """ 8 | A helper class for using TLS Lite with stdlib clients 9 | (httplib, xmlrpclib, imaplib, poplib). 10 | """ 11 | 12 | from tlslite.checker import Checker 13 | 14 | class ClientHelper(object): 15 | """This is a helper class used to integrate TLS Lite with various 16 | TLS clients (e.g. poplib, smtplib, httplib, etc.)""" 17 | 18 | def __init__(self, 19 | username=None, password=None, 20 | certChain=None, privateKey=None, 21 | checker=None, 22 | settings = None, 23 | anon = False): 24 | """ 25 | For client authentication, use one of these argument 26 | combinations: 27 | - username, password (SRP) 28 | - certChain, privateKey (certificate) 29 | 30 | For server authentication, you can either rely on the 31 | implicit mutual authentication performed by SRP, 32 | or you can do certificate-based server 33 | authentication with one of these argument combinations: 34 | - x509Fingerprint 35 | 36 | Certificate-based server authentication is compatible with 37 | SRP or certificate-based client authentication. 38 | 39 | The constructor does not perform the TLS handshake itself, but 40 | simply stores these arguments for later. The handshake is 41 | performed only when this class needs to connect with the 42 | server. Then you should be prepared to handle TLS-specific 43 | exceptions. See the client handshake functions in 44 | L{tlslite.TLSConnection.TLSConnection} for details on which 45 | exceptions might be raised. 46 | 47 | @type username: str 48 | @param username: SRP username. Requires the 49 | 'password' argument. 50 | 51 | @type password: str 52 | @param password: SRP password for mutual authentication. 53 | Requires the 'username' argument. 54 | 55 | @type certChain: L{tlslite.x509certchain.X509CertChain} 56 | @param certChain: Certificate chain for client authentication. 57 | Requires the 'privateKey' argument. Excludes the SRP arguments. 58 | 59 | @type privateKey: L{tlslite.utils.rsakey.RSAKey} 60 | @param privateKey: Private key for client authentication. 61 | Requires the 'certChain' argument. Excludes the SRP arguments. 62 | 63 | @type checker: L{tlslite.checker.Checker} 64 | @param checker: Callable object called after handshaking to 65 | evaluate the connection and raise an Exception if necessary. 66 | 67 | @type settings: L{tlslite.handshakesettings.HandshakeSettings} 68 | @param settings: Various settings which can be used to control 69 | the ciphersuites, certificate types, and SSL/TLS versions 70 | offered by the client. 71 | """ 72 | 73 | self.username = None 74 | self.password = None 75 | self.certChain = None 76 | self.privateKey = None 77 | self.checker = None 78 | self.anon = anon 79 | 80 | #SRP Authentication 81 | if username and password and not \ 82 | (certChain or privateKey): 83 | self.username = username 84 | self.password = password 85 | 86 | #Certificate Chain Authentication 87 | elif certChain and privateKey and not \ 88 | (username or password): 89 | self.certChain = certChain 90 | self.privateKey = privateKey 91 | 92 | #No Authentication 93 | elif not password and not username and not \ 94 | certChain and not privateKey: 95 | pass 96 | 97 | else: 98 | raise ValueError("Bad parameters") 99 | 100 | self.checker = checker 101 | self.settings = settings 102 | 103 | self.tlsSession = None 104 | 105 | def _handshake(self, tlsConnection): 106 | if self.username and self.password: 107 | tlsConnection.handshakeClientSRP(username=self.username, 108 | password=self.password, 109 | checker=self.checker, 110 | settings=self.settings, 111 | session=self.tlsSession) 112 | elif self.anon: 113 | tlsConnection.handshakeClientAnonymous(session=self.tlsSession, 114 | settings=self.settings, 115 | checker=self.checker) 116 | else: 117 | tlsConnection.handshakeClientCert(certChain=self.certChain, 118 | privateKey=self.privateKey, 119 | checker=self.checker, 120 | settings=self.settings, 121 | session=self.tlsSession) 122 | self.tlsSession = tlsConnection.session -------------------------------------------------------------------------------- /tlslite/integration/httptlsconnection.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Kees Bos - Added ignoreAbruptClose parameter 4 | # Dimitris Moraitis - Anon ciphersuites 5 | # Martin von Loewis - python 3 port 6 | # 7 | # See the LICENSE file for legal information regarding use of this file. 8 | 9 | """TLS Lite + httplib.""" 10 | 11 | import socket 12 | try: 13 | import httplib 14 | except ImportError: 15 | # Python 3 16 | from http import client as httplib 17 | from tlslite.tlsconnection import TLSConnection 18 | from tlslite.integration.clienthelper import ClientHelper 19 | 20 | 21 | class HTTPTLSConnection(httplib.HTTPConnection, ClientHelper): 22 | """This class extends L{httplib.HTTPConnection} to support TLS.""" 23 | 24 | def __init__(self, host, port=None, strict=None, 25 | timeout=socket._GLOBAL_DEFAULT_TIMEOUT, 26 | source_address=None, 27 | username=None, password=None, 28 | certChain=None, privateKey=None, 29 | checker=None, 30 | settings=None, 31 | ignoreAbruptClose=False, 32 | anon=False): 33 | """Create a new HTTPTLSConnection. 34 | 35 | For client authentication, use one of these argument 36 | combinations: 37 | - username, password (SRP) 38 | - certChain, privateKey (certificate) 39 | 40 | For server authentication, you can either rely on the 41 | implicit mutual authentication performed by SRP 42 | or you can do certificate-based server 43 | authentication with one of these argument combinations: 44 | - x509Fingerprint 45 | 46 | Certificate-based server authentication is compatible with 47 | SRP or certificate-based client authentication. 48 | 49 | The constructor does not perform the TLS handshake itself, but 50 | simply stores these arguments for later. The handshake is 51 | performed only when this class needs to connect with the 52 | server. Thus you should be prepared to handle TLS-specific 53 | exceptions when calling methods inherited from 54 | L{httplib.HTTPConnection} such as request(), connect(), and 55 | send(). See the client handshake functions in 56 | L{tlslite.TLSConnection.TLSConnection} for details on which 57 | exceptions might be raised. 58 | 59 | @type host: str 60 | @param host: Server to connect to. 61 | 62 | @type port: int 63 | @param port: Port to connect to. 64 | 65 | @type username: str 66 | @param username: SRP username. Requires the 67 | 'password' argument. 68 | 69 | @type password: str 70 | @param password: SRP password for mutual authentication. 71 | Requires the 'username' argument. 72 | 73 | @type certChain: L{tlslite.x509certchain.X509CertChain} or 74 | @param certChain: Certificate chain for client authentication. 75 | Requires the 'privateKey' argument. Excludes the SRP arguments. 76 | 77 | @type privateKey: L{tlslite.utils.rsakey.RSAKey} 78 | @param privateKey: Private key for client authentication. 79 | Requires the 'certChain' argument. Excludes the SRP arguments. 80 | 81 | @type checker: L{tlslite.checker.Checker} 82 | @param checker: Callable object called after handshaking to 83 | evaluate the connection and raise an Exception if necessary. 84 | 85 | @type settings: L{tlslite.handshakesettings.HandshakeSettings} 86 | @param settings: Various settings which can be used to control 87 | the ciphersuites, certificate types, and SSL/TLS versions 88 | offered by the client. 89 | 90 | @type ignoreAbruptClose: bool 91 | @param ignoreAbruptClose: ignore the TLSAbruptCloseError on 92 | unexpected hangup. 93 | """ 94 | if source_address: 95 | httplib.HTTPConnection.__init__(self, 96 | host=host, 97 | port=port, 98 | timeout=timeout, 99 | source_address=source_address) 100 | if not source_address: 101 | httplib.HTTPConnection.__init__(self, 102 | host=host, 103 | port=port, 104 | timeout=timeout) 105 | self.ignoreAbruptClose = ignoreAbruptClose 106 | ClientHelper.__init__(self, 107 | username, password, 108 | certChain, privateKey, 109 | checker, 110 | settings, 111 | anon) 112 | 113 | def connect(self): 114 | httplib.HTTPConnection.connect(self) 115 | self.sock = TLSConnection(self.sock) 116 | self.sock.ignoreAbruptClose = self.ignoreAbruptClose 117 | ClientHelper._handshake(self, self.sock) 118 | -------------------------------------------------------------------------------- /tlslite/integration/imap4_tls.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """TLS Lite + imaplib.""" 5 | 6 | import socket 7 | from imaplib import IMAP4 8 | from tlslite.tlsconnection import TLSConnection 9 | from tlslite.integration.clienthelper import ClientHelper 10 | 11 | # IMAP TLS PORT 12 | IMAP4_TLS_PORT = 993 13 | 14 | class IMAP4_TLS(IMAP4, ClientHelper): 15 | """This class extends L{imaplib.IMAP4} with TLS support.""" 16 | 17 | def __init__(self, host = '', port = IMAP4_TLS_PORT, 18 | username=None, password=None, 19 | certChain=None, privateKey=None, 20 | checker=None, 21 | settings=None): 22 | """Create a new IMAP4_TLS. 23 | 24 | For client authentication, use one of these argument 25 | combinations: 26 | - username, password (SRP) 27 | - certChain, privateKey (certificate) 28 | 29 | For server authentication, you can either rely on the 30 | implicit mutual authentication performed by SRP 31 | or you can do certificate-based server 32 | authentication with one of these argument combinations: 33 | - x509Fingerprint 34 | 35 | Certificate-based server authentication is compatible with 36 | SRP or certificate-based client authentication. 37 | 38 | The caller should be prepared to handle TLS-specific 39 | exceptions. See the client handshake functions in 40 | L{tlslite.TLSConnection.TLSConnection} for details on which 41 | exceptions might be raised. 42 | 43 | @type host: str 44 | @param host: Server to connect to. 45 | 46 | @type port: int 47 | @param port: Port to connect to. 48 | 49 | @type username: str 50 | @param username: SRP username. Requires the 51 | 'password' argument. 52 | 53 | @type password: str 54 | @param password: SRP password for mutual authentication. 55 | Requires the 'username' argument. 56 | 57 | @type certChain: L{tlslite.x509certchain.X509CertChain} 58 | @param certChain: Certificate chain for client authentication. 59 | Requires the 'privateKey' argument. Excludes the SRP arguments. 60 | 61 | @type privateKey: L{tlslite.utils.rsakey.RSAKey} 62 | @param privateKey: Private key for client authentication. 63 | Requires the 'certChain' argument. Excludes the SRP arguments. 64 | 65 | @type checker: L{tlslite.checker.Checker} 66 | @param checker: Callable object called after handshaking to 67 | evaluate the connection and raise an Exception if necessary. 68 | 69 | @type settings: L{tlslite.handshakesettings.HandshakeSettings} 70 | @param settings: Various settings which can be used to control 71 | the ciphersuites, certificate types, and SSL/TLS versions 72 | offered by the client. 73 | """ 74 | 75 | ClientHelper.__init__(self, 76 | username, password, 77 | certChain, privateKey, 78 | checker, 79 | settings) 80 | 81 | IMAP4.__init__(self, host, port) 82 | 83 | 84 | def open(self, host = '', port = IMAP4_TLS_PORT): 85 | """Setup connection to remote server on "host:port". 86 | 87 | This connection will be used by the routines: 88 | read, readline, send, shutdown. 89 | """ 90 | self.host = host 91 | self.port = port 92 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 93 | self.sock.connect((host, port)) 94 | self.sock = TLSConnection(self.sock) 95 | ClientHelper._handshake(self, self.sock) 96 | self.file = self.sock.makefile('rb') -------------------------------------------------------------------------------- /tlslite/integration/pop3_tls.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """TLS Lite + poplib.""" 5 | 6 | import socket 7 | from poplib import POP3, POP3_SSL_PORT 8 | from tlslite.tlsconnection import TLSConnection 9 | from tlslite.integration.clienthelper import ClientHelper 10 | 11 | class POP3_TLS(POP3, ClientHelper): 12 | """This class extends L{poplib.POP3} with TLS support.""" 13 | 14 | def __init__(self, host, port = POP3_SSL_PORT, 15 | timeout=socket._GLOBAL_DEFAULT_TIMEOUT, 16 | username=None, password=None, 17 | certChain=None, privateKey=None, 18 | checker=None, 19 | settings=None): 20 | """Create a new POP3_TLS. 21 | 22 | For client authentication, use one of these argument 23 | combinations: 24 | - username, password (SRP) 25 | - certChain, privateKey (certificate) 26 | 27 | For server authentication, you can either rely on the 28 | implicit mutual authentication performed by SRP or 29 | you can do certificate-based server 30 | authentication with one of these argument combinations: 31 | - x509Fingerprint 32 | 33 | Certificate-based server authentication is compatible with 34 | SRP or certificate-based client authentication. 35 | 36 | The caller should be prepared to handle TLS-specific 37 | exceptions. See the client handshake functions in 38 | L{tlslite.TLSConnection.TLSConnection} for details on which 39 | exceptions might be raised. 40 | 41 | @type host: str 42 | @param host: Server to connect to. 43 | 44 | @type port: int 45 | @param port: Port to connect to. 46 | 47 | @type username: str 48 | @param username: SRP username. 49 | 50 | @type password: str 51 | @param password: SRP password for mutual authentication. 52 | Requires the 'username' argument. 53 | 54 | @type certChain: L{tlslite.x509certchain.X509CertChain} 55 | @param certChain: Certificate chain for client authentication. 56 | Requires the 'privateKey' argument. Excludes the SRP argument. 57 | 58 | @type privateKey: L{tlslite.utils.rsakey.RSAKey} 59 | @param privateKey: Private key for client authentication. 60 | Requires the 'certChain' argument. Excludes the SRP argument. 61 | 62 | @type checker: L{tlslite.checker.Checker} 63 | @param checker: Callable object called after handshaking to 64 | evaluate the connection and raise an Exception if necessary. 65 | 66 | @type settings: L{tlslite.handshakesettings.HandshakeSettings} 67 | @param settings: Various settings which can be used to control 68 | the ciphersuites, certificate types, and SSL/TLS versions 69 | offered by the client. 70 | """ 71 | self.host = host 72 | self.port = port 73 | sock = socket.create_connection((host, port), timeout) 74 | ClientHelper.__init__(self, 75 | username, password, 76 | certChain, privateKey, 77 | checker, 78 | settings) 79 | connection = TLSConnection(sock) 80 | ClientHelper._handshake(self, connection) 81 | self.sock = connection 82 | self.file = self.sock.makefile('rb') 83 | self._debugging = 0 84 | self.welcome = self._getresp() -------------------------------------------------------------------------------- /tlslite/integration/smtp_tls.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """TLS Lite + smtplib.""" 5 | 6 | from smtplib import SMTP 7 | from tlslite.tlsconnection import TLSConnection 8 | from tlslite.integration.clienthelper import ClientHelper 9 | 10 | class SMTP_TLS(SMTP): 11 | """This class extends L{smtplib.SMTP} with TLS support.""" 12 | 13 | def starttls(self, 14 | username=None, password=None, 15 | certChain=None, privateKey=None, 16 | checker=None, 17 | settings=None): 18 | """Puts the connection to the SMTP server into TLS mode. 19 | 20 | If the server supports TLS, this will encrypt the rest of the SMTP 21 | session. 22 | 23 | For client authentication, use one of these argument 24 | combinations: 25 | - username, password (SRP) 26 | - certChain, privateKey (certificate) 27 | 28 | For server authentication, you can either rely on the 29 | implicit mutual authentication performed by SRP or 30 | you can do certificate-based server 31 | authentication with one of these argument combinations: 32 | - x509Fingerprint 33 | 34 | Certificate-based server authentication is compatible with 35 | SRP or certificate-based client authentication. 36 | 37 | The caller should be prepared to handle TLS-specific 38 | exceptions. See the client handshake functions in 39 | L{tlslite.TLSConnection.TLSConnection} for details on which 40 | exceptions might be raised. 41 | 42 | @type username: str 43 | @param username: SRP username. Requires the 44 | 'password' argument. 45 | 46 | @type password: str 47 | @param password: SRP password for mutual authentication. 48 | Requires the 'username' argument. 49 | 50 | @type certChain: L{tlslite.x509certchain.X509CertChain} 51 | @param certChain: Certificate chain for client authentication. 52 | Requires the 'privateKey' argument. Excludes the SRP arguments. 53 | 54 | @type privateKey: L{tlslite.utils.rsakey.RSAKey} 55 | @param privateKey: Private key for client authentication. 56 | Requires the 'certChain' argument. Excludes the SRP arguments. 57 | 58 | @type checker: L{tlslite.checker.Checker} 59 | @param checker: Callable object called after handshaking to 60 | evaluate the connection and raise an Exception if necessary. 61 | 62 | @type settings: L{tlslite.handshakesettings.HandshakeSettings} 63 | @param settings: Various settings which can be used to control 64 | the ciphersuites, certificate types, and SSL/TLS versions 65 | offered by the client. 66 | """ 67 | (resp, reply) = self.docmd("STARTTLS") 68 | if resp == 220: 69 | helper = ClientHelper( 70 | username, password, 71 | certChain, privateKey, 72 | checker, 73 | settings) 74 | conn = TLSConnection(self.sock) 75 | helper._handshake(conn) 76 | self.sock = conn 77 | self.file = conn.makefile('rb') 78 | return (resp, reply) -------------------------------------------------------------------------------- /tlslite/integration/tlsasyncdispatchermixin.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Martin von Loewis - python 3 port 4 | # 5 | # See the LICENSE file for legal information regarding use of this file. 6 | 7 | """TLS Lite + asyncore.""" 8 | 9 | 10 | import asyncore 11 | from tlslite.tlsconnection import TLSConnection 12 | from .asyncstatemachine import AsyncStateMachine 13 | 14 | 15 | class TLSAsyncDispatcherMixIn(AsyncStateMachine): 16 | """This class can be "mixed in" with an 17 | L{asyncore.dispatcher} to add TLS support. 18 | 19 | This class essentially sits between the dispatcher and the select 20 | loop, intercepting events and only calling the dispatcher when 21 | applicable. 22 | 23 | In the case of handle_read(), a read operation will be activated, 24 | and when it completes, the bytes will be placed in a buffer where 25 | the dispatcher can retrieve them by calling recv(), and the 26 | dispatcher's handle_read() will be called. 27 | 28 | In the case of handle_write(), the dispatcher's handle_write() will 29 | be called, and when it calls send(), a write operation will be 30 | activated. 31 | 32 | To use this class, you must combine it with an asyncore.dispatcher, 33 | and pass in a handshake operation with setServerHandshakeOp(). 34 | 35 | Below is an example of using this class with medusa. This class is 36 | mixed in with http_channel to create http_tls_channel. Note: 37 | 1. the mix-in is listed first in the inheritance list 38 | 39 | 2. the input buffer size must be at least 16K, otherwise the 40 | dispatcher might not read all the bytes from the TLS layer, 41 | leaving some bytes in limbo. 42 | 43 | 3. IE seems to have a problem receiving a whole HTTP response in a 44 | single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't 45 | be displayed on IE. 46 | 47 | Add the following text into 'start_medusa.py', in the 'HTTP Server' 48 | section:: 49 | 50 | from tlslite import * 51 | s = open("./serverX509Cert.pem").read() 52 | x509 = X509() 53 | x509.parse(s) 54 | certChain = X509CertChain([x509]) 55 | 56 | s = open("./serverX509Key.pem").read() 57 | privateKey = parsePEMKey(s, private=True) 58 | 59 | class http_tls_channel(TLSAsyncDispatcherMixIn, 60 | http_server.http_channel): 61 | ac_in_buffer_size = 16384 62 | 63 | def __init__ (self, server, conn, addr): 64 | http_server.http_channel.__init__(self, server, conn, addr) 65 | TLSAsyncDispatcherMixIn.__init__(self, conn) 66 | self.tlsConnection.ignoreAbruptClose = True 67 | self.setServerHandshakeOp(certChain=certChain, 68 | privateKey=privateKey) 69 | 70 | hs.channel_class = http_tls_channel 71 | 72 | If the TLS layer raises an exception, the exception will be caught 73 | in asyncore.dispatcher, which will call close() on this class. The 74 | TLS layer always closes the TLS connection before raising an 75 | exception, so the close operation will complete right away, causing 76 | asyncore.dispatcher.close() to be called, which closes the socket 77 | and removes this instance from the asyncore loop. 78 | 79 | """ 80 | 81 | 82 | def __init__(self, sock=None): 83 | AsyncStateMachine.__init__(self) 84 | 85 | if sock: 86 | self.tlsConnection = TLSConnection(sock) 87 | 88 | #Calculate the sibling I'm being mixed in with. 89 | #This is necessary since we override functions 90 | #like readable(), handle_read(), etc., but we 91 | #also want to call the sibling's versions. 92 | for cl in self.__class__.__bases__: 93 | if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine: 94 | self.siblingClass = cl 95 | break 96 | else: 97 | raise AssertionError() 98 | 99 | def readable(self): 100 | result = self.wantsReadEvent() 101 | if result != None: 102 | return result 103 | return self.siblingClass.readable(self) 104 | 105 | def writable(self): 106 | result = self.wantsWriteEvent() 107 | if result != None: 108 | return result 109 | return self.siblingClass.writable(self) 110 | 111 | def handle_read(self): 112 | self.inReadEvent() 113 | 114 | def handle_write(self): 115 | self.inWriteEvent() 116 | 117 | def outConnectEvent(self): 118 | self.siblingClass.handle_connect(self) 119 | 120 | def outCloseEvent(self): 121 | asyncore.dispatcher.close(self) 122 | 123 | def outReadEvent(self, readBuffer): 124 | self.readBuffer = readBuffer 125 | self.siblingClass.handle_read(self) 126 | 127 | def outWriteEvent(self): 128 | self.siblingClass.handle_write(self) 129 | 130 | def recv(self, bufferSize=16384): 131 | if bufferSize < 16384 or self.readBuffer == None: 132 | raise AssertionError() 133 | returnValue = self.readBuffer 134 | self.readBuffer = None 135 | return returnValue 136 | 137 | def send(self, writeBuffer): 138 | self.setWriteOp(writeBuffer) 139 | return len(writeBuffer) 140 | 141 | def close(self): 142 | if hasattr(self, "tlsConnection"): 143 | self.setCloseOp() 144 | else: 145 | asyncore.dispatcher.close(self) 146 | -------------------------------------------------------------------------------- /tlslite/integration/tlssocketservermixin.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """TLS Lite + SocketServer.""" 5 | 6 | from tlslite.tlsconnection import TLSConnection 7 | 8 | class TLSSocketServerMixIn: 9 | """ 10 | This class can be mixed in with any L{SocketServer.TCPServer} to 11 | add TLS support. 12 | 13 | To use this class, define a new class that inherits from it and 14 | some L{SocketServer.TCPServer} (with the mix-in first). Then 15 | implement the handshake() method, doing some sort of server 16 | handshake on the connection argument. If the handshake method 17 | returns True, the RequestHandler will be triggered. Below is a 18 | complete example of a threaded HTTPS server:: 19 | 20 | from SocketServer import * 21 | from BaseHTTPServer import * 22 | from SimpleHTTPServer import * 23 | from tlslite import * 24 | 25 | s = open("./serverX509Cert.pem").read() 26 | x509 = X509() 27 | x509.parse(s) 28 | certChain = X509CertChain([x509]) 29 | 30 | s = open("./serverX509Key.pem").read() 31 | privateKey = parsePEMKey(s, private=True) 32 | 33 | sessionCache = SessionCache() 34 | 35 | class MyHTTPServer(ThreadingMixIn, TLSSocketServerMixIn, 36 | HTTPServer): 37 | def handshake(self, tlsConnection): 38 | try: 39 | tlsConnection.handshakeServer(certChain=certChain, 40 | privateKey=privateKey, 41 | sessionCache=sessionCache) 42 | tlsConnection.ignoreAbruptClose = True 43 | return True 44 | except TLSError, error: 45 | print "Handshake failure:", str(error) 46 | return False 47 | 48 | httpd = MyHTTPServer(('localhost', 443), SimpleHTTPRequestHandler) 49 | httpd.serve_forever() 50 | """ 51 | 52 | 53 | def finish_request(self, sock, client_address): 54 | tlsConnection = TLSConnection(sock) 55 | if self.handshake(tlsConnection) == True: 56 | self.RequestHandlerClass(tlsConnection, client_address, self) 57 | tlsConnection.close() 58 | 59 | #Implement this method to do some form of handshaking. Return True 60 | #if the handshake finishes properly and the request is authorized. 61 | def handshake(self, tlsConnection): 62 | raise NotImplementedError() -------------------------------------------------------------------------------- /tlslite/integration/xmlrpcserver.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Kees Bos 3 | # Martin von Loewis - python 3 port 4 | # 5 | # See the LICENSE file for legal information regarding use of this file. 6 | 7 | """xmlrpcserver.py - simple XML RPC server supporting TLS""" 8 | try: 9 | from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler 10 | except ImportError: 11 | # Python 3 12 | from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler 13 | from .tlssocketservermixin import TLSSocketServerMixIn 14 | 15 | 16 | class TLSXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 17 | """XMLRPCRequestHandler using TLS""" 18 | 19 | # Redefine the setup method (see SocketServer.StreamRequestHandler) 20 | def setup(self): 21 | self.connection = self.request 22 | if getattr(self, 'timeout', None) is not None: 23 | # Python 2.7 24 | self.connection.settimeout(self.timeout) 25 | self.rfile = self.connection.makefile('rb', self.rbufsize) 26 | self.wfile = self.connection.makefile('wb', self.wbufsize) 27 | 28 | def do_POST(self): 29 | """Handles the HTTPS POST request.""" 30 | SimpleXMLRPCRequestHandler.do_POST(self) 31 | try: 32 | # shut down the connection 33 | self.connection.shutdown() 34 | except: 35 | pass 36 | 37 | 38 | class TLSXMLRPCServer(TLSSocketServerMixIn, 39 | SimpleXMLRPCServer): 40 | """Simple XML-RPC server using TLS""" 41 | 42 | def __init__(self, addr, *args, **kwargs): 43 | if not args and not 'requestHandler' in kwargs: 44 | kwargs['requestHandler'] = TLSXMLRPCRequestHandler 45 | SimpleXMLRPCServer.__init__(self, addr, *args, **kwargs) 46 | 47 | 48 | class MultiPathTLSXMLRPCServer(TLSXMLRPCServer): 49 | """Multipath XML-RPC Server using TLS""" 50 | 51 | def __init__(self, addr, *args, **kwargs): 52 | TLSXMLRPCServer.__init__(addr, *args, **kwargs) 53 | self.dispatchers = {} 54 | self.allow_none = allow_none 55 | self.encoding = encoding 56 | -------------------------------------------------------------------------------- /tlslite/integration/xmlrpctransport.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Kees Bos - Fixes for compatibility with different Python versions 4 | # Martin von Loewis - python 3 port 5 | # 6 | # See the LICENSE file for legal information regarding use of this file. 7 | 8 | 9 | """TLS Lite + xmlrpclib.""" 10 | 11 | try: 12 | import xmlrpclib 13 | import httplib 14 | except ImportError: 15 | # Python 3 16 | from xmlrpc import client as xmlrpclib 17 | from http import client as httplib 18 | from tlslite.integration.httptlsconnection import HTTPTLSConnection 19 | from tlslite.integration.clienthelper import ClientHelper 20 | import tlslite.errors 21 | 22 | 23 | class XMLRPCTransport(xmlrpclib.Transport, ClientHelper): 24 | """Handles an HTTPS transaction to an XML-RPC server.""" 25 | 26 | # Pre python 2.7, the make_connection returns a HTTP class 27 | transport = xmlrpclib.Transport() 28 | conn_class_is_http = not hasattr(transport, '_connection') 29 | del(transport) 30 | 31 | def __init__(self, use_datetime=0, 32 | username=None, password=None, 33 | certChain=None, privateKey=None, 34 | checker=None, 35 | settings=None, 36 | ignoreAbruptClose=False): 37 | """Create a new XMLRPCTransport. 38 | 39 | An instance of this class can be passed to L{xmlrpclib.ServerProxy} 40 | to use TLS with XML-RPC calls:: 41 | 42 | from tlslite import XMLRPCTransport 43 | from xmlrpclib import ServerProxy 44 | 45 | transport = XMLRPCTransport(user="alice", password="abra123") 46 | server = ServerProxy("https://localhost", transport) 47 | 48 | For client authentication, use one of these argument 49 | combinations: 50 | - username, password (SRP) 51 | - certChain, privateKey (certificate) 52 | 53 | For server authentication, you can either rely on the 54 | implicit mutual authentication performed by SRP or 55 | you can do certificate-based server 56 | authentication with one of these argument combinations: 57 | - x509Fingerprint 58 | 59 | Certificate-based server authentication is compatible with 60 | SRP or certificate-based client authentication. 61 | 62 | The constructor does not perform the TLS handshake itself, but 63 | simply stores these arguments for later. The handshake is 64 | performed only when this class needs to connect with the 65 | server. Thus you should be prepared to handle TLS-specific 66 | exceptions when calling methods of L{xmlrpclib.ServerProxy}. See the 67 | client handshake functions in 68 | L{tlslite.TLSConnection.TLSConnection} for details on which 69 | exceptions might be raised. 70 | 71 | @type username: str 72 | @param username: SRP username. Requires the 73 | 'password' argument. 74 | 75 | @type password: str 76 | @param password: SRP password for mutual authentication. 77 | Requires the 'username' argument. 78 | 79 | @type certChain: L{tlslite.x509certchain.X509CertChain} 80 | @param certChain: Certificate chain for client authentication. 81 | Requires the 'privateKey' argument. Excludes the SRP arguments. 82 | 83 | @type privateKey: L{tlslite.utils.rsakey.RSAKey} 84 | @param privateKey: Private key for client authentication. 85 | Requires the 'certChain' argument. Excludes the SRP arguments. 86 | 87 | @type checker: L{tlslite.checker.Checker} 88 | @param checker: Callable object called after handshaking to 89 | evaluate the connection and raise an Exception if necessary. 90 | 91 | @type settings: L{tlslite.handshakesettings.HandshakeSettings} 92 | @param settings: Various settings which can be used to control 93 | the ciphersuites, certificate types, and SSL/TLS versions 94 | offered by the client. 95 | 96 | @type ignoreAbruptClose: bool 97 | @param ignoreAbruptClose: ignore the TLSAbruptCloseError on 98 | unexpected hangup. 99 | """ 100 | 101 | # self._connection is new in python 2.7, since we're using it here, 102 | # we'll add this ourselves too, just in case we're pre-2.7 103 | self._connection = (None, None) 104 | xmlrpclib.Transport.__init__(self, use_datetime) 105 | self.ignoreAbruptClose = ignoreAbruptClose 106 | ClientHelper.__init__(self, 107 | username, password, 108 | certChain, privateKey, 109 | checker, 110 | settings) 111 | 112 | def make_connection(self, host): 113 | # return an existing connection if possible. This allows 114 | # HTTP/1.1 keep-alive. 115 | if self._connection and host == self._connection[0]: 116 | http = self._connection[1] 117 | else: 118 | # create a HTTPS connection object from a host descriptor 119 | chost, extra_headers, x509 = self.get_host_info(host) 120 | 121 | http = HTTPTLSConnection(chost, None, 122 | username=self.username, password=self.password, 123 | certChain=self.certChain, privateKey=self.privateKey, 124 | checker=self.checker, 125 | settings=self.settings, 126 | ignoreAbruptClose=self.ignoreAbruptClose) 127 | # store the host argument along with the connection object 128 | self._connection = host, http 129 | if not self.conn_class_is_http: 130 | return http 131 | http2 = httplib.HTTP() 132 | http2._setup(http) 133 | return http2 134 | -------------------------------------------------------------------------------- /tlslite/session.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Dave Baggett (Arcode Corporation) - canonicalCipherName 4 | # 5 | # See the LICENSE file for legal information regarding use of this file. 6 | 7 | """Class representing a TLS session.""" 8 | 9 | from .utils.compat import * 10 | from .mathtls import * 11 | from .constants import * 12 | 13 | class Session(object): 14 | """ 15 | This class represents a TLS session. 16 | 17 | TLS distinguishes between connections and sessions. A new 18 | handshake creates both a connection and a session. Data is 19 | transmitted over the connection. 20 | 21 | The session contains a more permanent record of the handshake. The 22 | session can be inspected to determine handshake results. The 23 | session can also be used to create a new connection through 24 | "session resumption". If the client and server both support this, 25 | they can create a new connection based on an old session without 26 | the overhead of a full handshake. 27 | 28 | The session for a L{tlslite.TLSConnection.TLSConnection} can be 29 | retrieved from the connection's 'session' attribute. 30 | 31 | @type srpUsername: str 32 | @ivar srpUsername: The client's SRP username (or None). 33 | 34 | @type clientCertChain: L{tlslite.x509certchain.X509CertChain} 35 | @ivar clientCertChain: The client's certificate chain (or None). 36 | 37 | @type serverCertChain: L{tlslite.x509certchain.X509CertChain} 38 | @ivar serverCertChain: The server's certificate chain (or None). 39 | 40 | @type tackExt: L{tack.structures.TackExtension.TackExtension} 41 | @ivar tackExt: The server's TackExtension (or None). 42 | 43 | @type tackInHelloExt: L{bool} 44 | @ivar tackInHelloExt: True if a TACK was presented via TLS Extension. 45 | """ 46 | 47 | def __init__(self): 48 | self.masterSecret = bytearray(0) 49 | self.sessionID = bytearray(0) 50 | self.cipherSuite = 0 51 | self.srpUsername = "" 52 | self.clientCertChain = None 53 | self.serverCertChain = None 54 | self.tackExt = None 55 | self.tackInHelloExt = False 56 | self.serverName = "" 57 | self.resumable = False 58 | 59 | def create(self, masterSecret, sessionID, cipherSuite, 60 | srpUsername, clientCertChain, serverCertChain, 61 | tackExt, tackInHelloExt, serverName, resumable=True): 62 | self.masterSecret = masterSecret 63 | self.sessionID = sessionID 64 | self.cipherSuite = cipherSuite 65 | self.srpUsername = srpUsername 66 | self.clientCertChain = clientCertChain 67 | self.serverCertChain = serverCertChain 68 | self.tackExt = tackExt 69 | self.tackInHelloExt = tackInHelloExt 70 | self.serverName = serverName 71 | self.resumable = resumable 72 | 73 | def _clone(self): 74 | other = Session() 75 | other.masterSecret = self.masterSecret 76 | other.sessionID = self.sessionID 77 | other.cipherSuite = self.cipherSuite 78 | other.srpUsername = self.srpUsername 79 | other.clientCertChain = self.clientCertChain 80 | other.serverCertChain = self.serverCertChain 81 | other.tackExt = self.tackExt 82 | other.tackInHelloExt = self.tackInHelloExt 83 | other.serverName = self.serverName 84 | other.resumable = self.resumable 85 | return other 86 | 87 | def valid(self): 88 | """If this session can be used for session resumption. 89 | 90 | @rtype: bool 91 | @return: If this session can be used for session resumption. 92 | """ 93 | return self.resumable and self.sessionID 94 | 95 | def _setResumable(self, boolean): 96 | #Only let it be set to True if the sessionID is non-null 97 | if (not boolean) or (boolean and self.sessionID): 98 | self.resumable = boolean 99 | 100 | def getTackId(self): 101 | if self.tackExt and self.tackExt.tack: 102 | return self.tackExt.tack.getTackId() 103 | else: 104 | return None 105 | 106 | def getBreakSigs(self): 107 | if self.tackExt and self.tackExt.break_sigs: 108 | return self.tackExt.break_sigs 109 | else: 110 | return None 111 | 112 | def getCipherName(self): 113 | """Get the name of the cipher used with this connection. 114 | 115 | @rtype: str 116 | @return: The name of the cipher used with this connection. 117 | """ 118 | return CipherSuite.canonicalCipherName(self.cipherSuite) 119 | 120 | def getMacName(self): 121 | """Get the name of the HMAC hash algo used with this connection. 122 | 123 | @rtype: str 124 | @return: The name of the HMAC hash algo used with this connection. 125 | """ 126 | return CipherSuite.canonicalMacName(self.cipherSuite) 127 | -------------------------------------------------------------------------------- /tlslite/sessioncache.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Martin von Loewis - python 3 port 4 | # Mirko Dziadzka - bugfix 5 | # 6 | # See the LICENSE file for legal information regarding use of this file. 7 | 8 | """Class for caching TLS sessions.""" 9 | 10 | import threading 11 | import time 12 | 13 | class SessionCache(object): 14 | """This class is used by the server to cache TLS sessions. 15 | 16 | Caching sessions allows the client to use TLS session resumption 17 | and avoid the expense of a full handshake. To use this class, 18 | simply pass a SessionCache instance into the server handshake 19 | function. 20 | 21 | This class is thread-safe. 22 | """ 23 | 24 | #References to these instances 25 | #are also held by the caller, who may change the 'resumable' 26 | #flag, so the SessionCache must return the same instances 27 | #it was passed in. 28 | 29 | def __init__(self, maxEntries=10000, maxAge=14400): 30 | """Create a new SessionCache. 31 | 32 | @type maxEntries: int 33 | @param maxEntries: The maximum size of the cache. When this 34 | limit is reached, the oldest sessions will be deleted as 35 | necessary to make room for new ones. The default is 10000. 36 | 37 | @type maxAge: int 38 | @param maxAge: The number of seconds before a session expires 39 | from the cache. The default is 14400 (i.e. 4 hours).""" 40 | 41 | self.lock = threading.Lock() 42 | 43 | # Maps sessionIDs to sessions 44 | self.entriesDict = {} 45 | 46 | #Circular list of (sessionID, timestamp) pairs 47 | self.entriesList = [(None,None)] * maxEntries 48 | 49 | self.firstIndex = 0 50 | self.lastIndex = 0 51 | self.maxAge = maxAge 52 | 53 | def __getitem__(self, sessionID): 54 | self.lock.acquire() 55 | try: 56 | self._purge() #Delete old items, so we're assured of a new one 57 | session = self.entriesDict[bytes(sessionID)] 58 | 59 | #When we add sessions they're resumable, but it's possible 60 | #for the session to be invalidated later on (if a fatal alert 61 | #is returned), so we have to check for resumability before 62 | #returning the session. 63 | 64 | if session.valid(): 65 | return session 66 | else: 67 | raise KeyError() 68 | finally: 69 | self.lock.release() 70 | 71 | 72 | def __setitem__(self, sessionID, session): 73 | self.lock.acquire() 74 | try: 75 | #Add the new element 76 | self.entriesDict[bytes(sessionID)] = session 77 | self.entriesList[self.lastIndex] = (bytes(sessionID), time.time()) 78 | self.lastIndex = (self.lastIndex+1) % len(self.entriesList) 79 | 80 | #If the cache is full, we delete the oldest element to make an 81 | #empty space 82 | if self.lastIndex == self.firstIndex: 83 | del(self.entriesDict[self.entriesList[self.firstIndex][0]]) 84 | self.firstIndex = (self.firstIndex+1) % len(self.entriesList) 85 | finally: 86 | self.lock.release() 87 | 88 | #Delete expired items 89 | def _purge(self): 90 | currentTime = time.time() 91 | 92 | #Search through the circular list, deleting expired elements until 93 | #we reach a non-expired element. Since elements in list are 94 | #ordered in time, we can break once we reach the first non-expired 95 | #element 96 | index = self.firstIndex 97 | while index != self.lastIndex: 98 | if currentTime - self.entriesList[index][1] > self.maxAge: 99 | del(self.entriesDict[self.entriesList[index][0]]) 100 | index = (index+1) % len(self.entriesList) 101 | else: 102 | break 103 | self.firstIndex = index 104 | -------------------------------------------------------------------------------- /tlslite/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Toolkit for crypto and other stuff.""" 5 | 6 | __all__ = ["aes", 7 | "asn1parser", 8 | "cipherfactory", 9 | "codec", 10 | "cryptomath", 11 | "datefuncs", 12 | "compat", 13 | "keyfactory", 14 | "openssl_aes", 15 | "openssl_rc4", 16 | "openssl_rsakey", 17 | "openssl_tripledes", 18 | "pycrypto_aes", 19 | "pycrypto_rc4", 20 | "pycrypto_rsakey", 21 | "pycrypto_tripledes", 22 | "python_aes", 23 | "python_rc4", 24 | "python_rsakey", 25 | "rc4", 26 | "rijndael", 27 | "rsakey", 28 | "tackpywrapper", 29 | "tripledes"] 30 | -------------------------------------------------------------------------------- /tlslite/utils/aes.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Abstract class for AES.""" 5 | 6 | class AES(object): 7 | def __init__(self, key, mode, IV, implementation): 8 | if len(key) not in (16, 24, 32): 9 | raise AssertionError() 10 | if mode != 2: 11 | raise AssertionError() 12 | if len(IV) != 16: 13 | raise AssertionError() 14 | self.isBlockCipher = True 15 | self.block_size = 16 16 | self.implementation = implementation 17 | if len(key)==16: 18 | self.name = "aes128" 19 | elif len(key)==24: 20 | self.name = "aes192" 21 | elif len(key)==32: 22 | self.name = "aes256" 23 | else: 24 | raise AssertionError() 25 | 26 | #CBC-Mode encryption, returns ciphertext 27 | #WARNING: *MAY* modify the input as well 28 | def encrypt(self, plaintext): 29 | assert(len(plaintext) % 16 == 0) 30 | 31 | #CBC-Mode decryption, returns plaintext 32 | #WARNING: *MAY* modify the input as well 33 | def decrypt(self, ciphertext): 34 | assert(len(ciphertext) % 16 == 0) -------------------------------------------------------------------------------- /tlslite/utils/asn1parser.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # Patch from Google adding getChildBytes() 3 | # 4 | # See the LICENSE file for legal information regarding use of this file. 5 | 6 | """Class for parsing ASN.1""" 7 | from .compat import * 8 | from .codec import * 9 | 10 | #Takes a byte array which has a DER TLV field at its head 11 | class ASN1Parser(object): 12 | def __init__(self, bytes): 13 | p = Parser(bytes) 14 | p.get(1) #skip Type 15 | 16 | #Get Length 17 | self.length = self._getASN1Length(p) 18 | 19 | #Get Value 20 | self.value = p.getFixBytes(self.length) 21 | 22 | #Assuming this is a sequence... 23 | def getChild(self, which): 24 | return ASN1Parser(self.getChildBytes(which)) 25 | 26 | def getChildBytes(self, which): 27 | p = Parser(self.value) 28 | for x in range(which+1): 29 | markIndex = p.index 30 | p.get(1) #skip Type 31 | length = self._getASN1Length(p) 32 | p.getFixBytes(length) 33 | return p.bytes[markIndex : p.index] 34 | 35 | #Decode the ASN.1 DER length field 36 | def _getASN1Length(self, p): 37 | firstLength = p.get(1) 38 | if firstLength<=127: 39 | return firstLength 40 | else: 41 | lengthLength = firstLength & 0x7F 42 | return p.get(lengthLength) 43 | -------------------------------------------------------------------------------- /tlslite/utils/cipherfactory.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Factory functions for symmetric cryptography.""" 5 | 6 | import os 7 | 8 | from tlslite.utils import python_aes 9 | from tlslite.utils import python_rc4 10 | 11 | from tlslite.utils import cryptomath 12 | 13 | tripleDESPresent = False 14 | 15 | if cryptomath.m2cryptoLoaded: 16 | from tlslite.utils import openssl_aes 17 | from tlslite.utils import openssl_rc4 18 | from tlslite.utils import openssl_tripledes 19 | tripleDESPresent = True 20 | 21 | if cryptomath.pycryptoLoaded: 22 | from tlslite.utils import pycrypto_aes 23 | from tlslite.utils import pycrypto_rc4 24 | from tlslite.utils import pycrypto_tripledes 25 | tripleDESPresent = True 26 | 27 | # ************************************************************************** 28 | # Factory Functions for AES 29 | # ************************************************************************** 30 | 31 | def createAES(key, IV, implList=None): 32 | """Create a new AES object. 33 | 34 | @type key: str 35 | @param key: A 16, 24, or 32 byte string. 36 | 37 | @type IV: str 38 | @param IV: A 16 byte string 39 | 40 | @rtype: L{tlslite.utils.AES} 41 | @return: An AES object. 42 | """ 43 | if implList == None: 44 | implList = ["openssl", "pycrypto", "python"] 45 | 46 | for impl in implList: 47 | if impl == "openssl" and cryptomath.m2cryptoLoaded: 48 | return openssl_aes.new(key, 2, IV) 49 | elif impl == "pycrypto" and cryptomath.pycryptoLoaded: 50 | return pycrypto_aes.new(key, 2, IV) 51 | elif impl == "python": 52 | return python_aes.new(key, 2, IV) 53 | raise NotImplementedError() 54 | 55 | def createRC4(key, IV, implList=None): 56 | """Create a new RC4 object. 57 | 58 | @type key: str 59 | @param key: A 16 to 32 byte string. 60 | 61 | @type IV: object 62 | @param IV: Ignored, whatever it is. 63 | 64 | @rtype: L{tlslite.utils.RC4} 65 | @return: An RC4 object. 66 | """ 67 | if implList == None: 68 | implList = ["openssl", "pycrypto", "python"] 69 | 70 | if len(IV) != 0: 71 | raise AssertionError() 72 | for impl in implList: 73 | if impl == "openssl" and cryptomath.m2cryptoLoaded: 74 | return openssl_rc4.new(key) 75 | elif impl == "pycrypto" and cryptomath.pycryptoLoaded: 76 | return pycrypto_rc4.new(key) 77 | elif impl == "python": 78 | return python_rc4.new(key) 79 | raise NotImplementedError() 80 | 81 | #Create a new TripleDES instance 82 | def createTripleDES(key, IV, implList=None): 83 | """Create a new 3DES object. 84 | 85 | @type key: str 86 | @param key: A 24 byte string. 87 | 88 | @type IV: str 89 | @param IV: An 8 byte string 90 | 91 | @rtype: L{tlslite.utils.TripleDES} 92 | @return: A 3DES object. 93 | """ 94 | if implList == None: 95 | implList = ["openssl", "pycrypto"] 96 | 97 | for impl in implList: 98 | if impl == "openssl" and cryptomath.m2cryptoLoaded: 99 | return openssl_tripledes.new(key, 2, IV) 100 | elif impl == "pycrypto" and cryptomath.pycryptoLoaded: 101 | return pycrypto_tripledes.new(key, 2, IV) 102 | raise NotImplementedError() -------------------------------------------------------------------------------- /tlslite/utils/codec.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Classes for reading/writing binary data (such as TLS records).""" 5 | 6 | from .compat import * 7 | 8 | class Writer(object): 9 | def __init__(self): 10 | self.bytes = bytearray(0) 11 | 12 | def add(self, x, length): 13 | self.bytes += bytearray(length) 14 | newIndex = len(self.bytes) - 1 15 | for count in range(length): 16 | self.bytes[newIndex] = x & 0xFF 17 | x >>= 8 18 | newIndex -= 1 19 | if x != 0: 20 | raise ValueError("Can't represent value in specified length") 21 | 22 | def addFixSeq(self, seq, length): 23 | for e in seq: 24 | self.add(e, length) 25 | 26 | def addVarSeq(self, seq, length, lengthLength): 27 | self.add(len(seq)*length, lengthLength) 28 | for e in seq: 29 | self.add(e, length) 30 | 31 | class Parser(object): 32 | def __init__(self, bytes): 33 | self.bytes = bytes 34 | self.index = 0 35 | 36 | def get(self, length): 37 | if self.index + length > len(self.bytes): 38 | raise SyntaxError() 39 | x = 0 40 | for count in range(length): 41 | x <<= 8 42 | x |= self.bytes[self.index] 43 | self.index += 1 44 | return x 45 | 46 | def getFixBytes(self, lengthBytes): 47 | if self.index + lengthBytes > len(self.bytes): 48 | raise SyntaxError() 49 | bytes = self.bytes[self.index : self.index+lengthBytes] 50 | self.index += lengthBytes 51 | return bytes 52 | 53 | def getVarBytes(self, lengthLength): 54 | lengthBytes = self.get(lengthLength) 55 | return self.getFixBytes(lengthBytes) 56 | 57 | def getFixList(self, length, lengthList): 58 | l = [0] * lengthList 59 | for x in range(lengthList): 60 | l[x] = self.get(length) 61 | return l 62 | 63 | def getVarList(self, length, lengthLength): 64 | lengthList = self.get(lengthLength) 65 | if lengthList % length != 0: 66 | raise SyntaxError() 67 | lengthList = lengthList // length 68 | l = [0] * lengthList 69 | for x in range(lengthList): 70 | l[x] = self.get(length) 71 | return l 72 | 73 | def startLengthCheck(self, lengthLength): 74 | self.lengthCheck = self.get(lengthLength) 75 | self.indexCheck = self.index 76 | 77 | def setLengthCheck(self, length): 78 | self.lengthCheck = length 79 | self.indexCheck = self.index 80 | 81 | def stopLengthCheck(self): 82 | if (self.index - self.indexCheck) != self.lengthCheck: 83 | raise SyntaxError() 84 | 85 | def atLengthCheck(self): 86 | if (self.index - self.indexCheck) < self.lengthCheck: 87 | return False 88 | elif (self.index - self.indexCheck) == self.lengthCheck: 89 | return True 90 | else: 91 | raise SyntaxError() 92 | 93 | def getRemainingLength(self): 94 | return len(self.bytes) - self.index 95 | -------------------------------------------------------------------------------- /tlslite/utils/compat.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Miscellaneous functions to mask Python version differences.""" 5 | 6 | import sys 7 | import os 8 | import math 9 | import binascii 10 | 11 | if sys.version_info >= (3,0): 12 | 13 | def compat26Str(x): return x 14 | 15 | # Python 3 requires bytes instead of bytearrays for HMAC 16 | 17 | # So, python 2.6 requires strings, python 3 requires 'bytes', 18 | # and python 2.7 can handle bytearrays... 19 | def compatHMAC(x): return bytes(x) 20 | 21 | def raw_input(s): 22 | return input(s) 23 | 24 | # So, the python3 binascii module deals with bytearrays, and python2 25 | # deals with strings... I would rather deal with the "a" part as 26 | # strings, and the "b" part as bytearrays, regardless of python version, 27 | # so... 28 | def a2b_hex(s): 29 | try: 30 | b = bytearray(binascii.a2b_hex(bytearray(s, "ascii"))) 31 | except Exception as e: 32 | raise SyntaxError("base16 error: %s" % e) 33 | return b 34 | 35 | def a2b_base64(s): 36 | try: 37 | b = bytearray(binascii.a2b_base64(bytearray(s, "ascii"))) 38 | except Exception as e: 39 | raise SyntaxError("base64 error: %s" % e) 40 | return b 41 | 42 | def b2a_hex(b): 43 | return binascii.b2a_hex(b).decode("ascii") 44 | 45 | def b2a_base64(b): 46 | return binascii.b2a_base64(b).decode("ascii") 47 | 48 | def readStdinBinary(): 49 | return sys.stdin.buffer.read() 50 | 51 | def compatLong(num): 52 | return int(num) 53 | 54 | else: 55 | # Python 2.6 requires strings instead of bytearrays in a couple places, 56 | # so we define this function so it does the conversion if needed. 57 | if sys.version_info < (2,7): 58 | def compat26Str(x): return str(x) 59 | else: 60 | def compat26Str(x): return x 61 | 62 | # So, python 2.6 requires strings, python 3 requires 'bytes', 63 | # and python 2.7 can handle bytearrays... 64 | def compatHMAC(x): return compat26Str(x) 65 | 66 | def a2b_hex(s): 67 | try: 68 | b = bytearray(binascii.a2b_hex(s)) 69 | except Exception as e: 70 | raise SyntaxError("base16 error: %s" % e) 71 | return b 72 | 73 | def a2b_base64(s): 74 | try: 75 | b = bytearray(binascii.a2b_base64(s)) 76 | except Exception as e: 77 | raise SyntaxError("base64 error: %s" % e) 78 | return b 79 | 80 | def b2a_hex(b): 81 | return binascii.b2a_hex(compat26Str(b)) 82 | 83 | def b2a_base64(b): 84 | return binascii.b2a_base64(compat26Str(b)) 85 | 86 | def compatLong(num): 87 | return long(num) 88 | 89 | import traceback 90 | def formatExceptionTrace(e): 91 | newStr = "".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)) 92 | return newStr 93 | 94 | -------------------------------------------------------------------------------- /tlslite/utils/cryptomath.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Martin von Loewis - python 3 port 4 | # Yngve Pettersen (ported by Paul Sokolovsky) - TLS 1.2 5 | # 6 | # See the LICENSE file for legal information regarding use of this file. 7 | 8 | """cryptomath module 9 | 10 | This module has basic math/crypto code.""" 11 | from __future__ import print_function 12 | import os 13 | import math 14 | import base64 15 | import binascii 16 | 17 | from .compat import * 18 | 19 | 20 | # ************************************************************************** 21 | # Load Optional Modules 22 | # ************************************************************************** 23 | 24 | # Try to load M2Crypto/OpenSSL 25 | try: 26 | from M2Crypto import m2 27 | m2cryptoLoaded = True 28 | 29 | except ImportError: 30 | m2cryptoLoaded = False 31 | 32 | #Try to load GMPY 33 | try: 34 | import gmpy 35 | gmpyLoaded = True 36 | except ImportError: 37 | gmpyLoaded = False 38 | 39 | #Try to load pycrypto 40 | try: 41 | import Crypto.Cipher.AES 42 | pycryptoLoaded = True 43 | except ImportError: 44 | pycryptoLoaded = False 45 | 46 | 47 | # ************************************************************************** 48 | # PRNG Functions 49 | # ************************************************************************** 50 | 51 | # Check that os.urandom works 52 | import zlib 53 | length = len(zlib.compress(os.urandom(1000))) 54 | assert(length > 900) 55 | del length 56 | 57 | def getRandomBytes(howMany): 58 | b = bytearray(os.urandom(howMany)) 59 | assert(len(b) == howMany) 60 | return b 61 | 62 | prngName = "os.urandom" 63 | 64 | # ************************************************************************** 65 | # Simple hash functions 66 | # ************************************************************************** 67 | 68 | import hmac 69 | import hashlib 70 | 71 | def MD5(b): 72 | return bytearray(hashlib.md5(compat26Str(b)).digest()) 73 | 74 | def SHA1(b): 75 | return bytearray(hashlib.sha1(compat26Str(b)).digest()) 76 | 77 | def HMAC_MD5(k, b): 78 | k = compatHMAC(k) 79 | b = compatHMAC(b) 80 | return bytearray(hmac.new(k, b, hashlib.md5).digest()) 81 | 82 | def HMAC_SHA1(k, b): 83 | k = compatHMAC(k) 84 | b = compatHMAC(b) 85 | return bytearray(hmac.new(k, b, hashlib.sha1).digest()) 86 | 87 | def HMAC_SHA256(k, b): 88 | k = compatHMAC(k) 89 | b = compatHMAC(b) 90 | return bytearray(hmac.new(k, b, hashlib.sha256).digest()) 91 | 92 | # ************************************************************************** 93 | # Converter Functions 94 | # ************************************************************************** 95 | 96 | def bytesToNumber(b): 97 | total = 0 98 | multiplier = 1 99 | for count in range(len(b)-1, -1, -1): 100 | byte = b[count] 101 | total += multiplier * byte 102 | multiplier *= 256 103 | return total 104 | 105 | def numberToByteArray(n, howManyBytes=None): 106 | """Convert an integer into a bytearray, zero-pad to howManyBytes. 107 | 108 | The returned bytearray may be smaller than howManyBytes, but will 109 | not be larger. The returned bytearray will contain a big-endian 110 | encoding of the input integer (n). 111 | """ 112 | if howManyBytes == None: 113 | howManyBytes = numBytes(n) 114 | b = bytearray(howManyBytes) 115 | for count in range(howManyBytes-1, -1, -1): 116 | b[count] = int(n % 256) 117 | n >>= 8 118 | return b 119 | 120 | def mpiToNumber(mpi): #mpi is an openssl-format bignum string 121 | if (ord(mpi[4]) & 0x80) !=0: #Make sure this is a positive number 122 | raise AssertionError() 123 | b = bytearray(mpi[4:]) 124 | return bytesToNumber(b) 125 | 126 | def numberToMPI(n): 127 | b = numberToByteArray(n) 128 | ext = 0 129 | #If the high-order bit is going to be set, 130 | #add an extra byte of zeros 131 | if (numBits(n) & 0x7)==0: 132 | ext = 1 133 | length = numBytes(n) + ext 134 | b = bytearray(4+ext) + b 135 | b[0] = (length >> 24) & 0xFF 136 | b[1] = (length >> 16) & 0xFF 137 | b[2] = (length >> 8) & 0xFF 138 | b[3] = length & 0xFF 139 | return bytes(b) 140 | 141 | 142 | # ************************************************************************** 143 | # Misc. Utility Functions 144 | # ************************************************************************** 145 | 146 | def numBits(n): 147 | if n==0: 148 | return 0 149 | s = "%x" % n 150 | return ((len(s)-1)*4) + \ 151 | {'0':0, '1':1, '2':2, '3':2, 152 | '4':3, '5':3, '6':3, '7':3, 153 | '8':4, '9':4, 'a':4, 'b':4, 154 | 'c':4, 'd':4, 'e':4, 'f':4, 155 | }[s[0]] 156 | return int(math.floor(math.log(n, 2))+1) 157 | 158 | def numBytes(n): 159 | if n==0: 160 | return 0 161 | bits = numBits(n) 162 | return int(math.ceil(bits / 8.0)) 163 | 164 | # ************************************************************************** 165 | # Big Number Math 166 | # ************************************************************************** 167 | 168 | def getRandomNumber(low, high): 169 | if low >= high: 170 | raise AssertionError() 171 | howManyBits = numBits(high) 172 | howManyBytes = numBytes(high) 173 | lastBits = howManyBits % 8 174 | while 1: 175 | bytes = getRandomBytes(howManyBytes) 176 | if lastBits: 177 | bytes[0] = bytes[0] % (1 << lastBits) 178 | n = bytesToNumber(bytes) 179 | if n >= low and n < high: 180 | return n 181 | 182 | def gcd(a,b): 183 | a, b = max(a,b), min(a,b) 184 | while b: 185 | a, b = b, a % b 186 | return a 187 | 188 | def lcm(a, b): 189 | return (a * b) // gcd(a, b) 190 | 191 | #Returns inverse of a mod b, zero if none 192 | #Uses Extended Euclidean Algorithm 193 | def invMod(a, b): 194 | c, d = a, b 195 | uc, ud = 1, 0 196 | while c != 0: 197 | q = d // c 198 | c, d = d-(q*c), c 199 | uc, ud = ud - (q * uc), uc 200 | if d == 1: 201 | return ud % b 202 | return 0 203 | 204 | 205 | if gmpyLoaded: 206 | def powMod(base, power, modulus): 207 | base = gmpy.mpz(base) 208 | power = gmpy.mpz(power) 209 | modulus = gmpy.mpz(modulus) 210 | result = pow(base, power, modulus) 211 | return compatLong(result) 212 | 213 | else: 214 | def powMod(base, power, modulus): 215 | if power < 0: 216 | result = pow(base, power*-1, modulus) 217 | result = invMod(result, modulus) 218 | return result 219 | else: 220 | return pow(base, power, modulus) 221 | 222 | #Pre-calculate a sieve of the ~100 primes < 1000: 223 | def makeSieve(n): 224 | sieve = list(range(n)) 225 | for count in range(2, int(math.sqrt(n))+1): 226 | if sieve[count] == 0: 227 | continue 228 | x = sieve[count] * 2 229 | while x < len(sieve): 230 | sieve[x] = 0 231 | x += sieve[count] 232 | sieve = [x for x in sieve[2:] if x] 233 | return sieve 234 | 235 | def isPrime(n, iterations=5, display=False, sieve=makeSieve(1000)): 236 | #Trial division with sieve 237 | for x in sieve: 238 | if x >= n: return True 239 | if n % x == 0: return False 240 | #Passed trial division, proceed to Rabin-Miller 241 | #Rabin-Miller implemented per Ferguson & Schneier 242 | #Compute s, t for Rabin-Miller 243 | if display: print("*", end=' ') 244 | s, t = n-1, 0 245 | while s % 2 == 0: 246 | s, t = s//2, t+1 247 | #Repeat Rabin-Miller x times 248 | a = 2 #Use 2 as a base for first iteration speedup, per HAC 249 | for count in range(iterations): 250 | v = powMod(a, s, n) 251 | if v==1: 252 | continue 253 | i = 0 254 | while v != n-1: 255 | if i == t-1: 256 | return False 257 | else: 258 | v, i = powMod(v, 2, n), i+1 259 | a = getRandomNumber(2, n) 260 | return True 261 | 262 | def getRandomPrime(bits, display=False): 263 | if bits < 10: 264 | raise AssertionError() 265 | #The 1.5 ensures the 2 MSBs are set 266 | #Thus, when used for p,q in RSA, n will have its MSB set 267 | # 268 | #Since 30 is lcm(2,3,5), we'll set our test numbers to 269 | #29 % 30 and keep them there 270 | low = ((2 ** (bits-1)) * 3) // 2 271 | high = 2 ** bits - 30 272 | p = getRandomNumber(low, high) 273 | p += 29 - (p % 30) 274 | while 1: 275 | if display: print(".", end=' ') 276 | p += 30 277 | if p >= high: 278 | p = getRandomNumber(low, high) 279 | p += 29 - (p % 30) 280 | if isPrime(p, display=display): 281 | return p 282 | 283 | #Unused at the moment... 284 | def getRandomSafePrime(bits, display=False): 285 | if bits < 10: 286 | raise AssertionError() 287 | #The 1.5 ensures the 2 MSBs are set 288 | #Thus, when used for p,q in RSA, n will have its MSB set 289 | # 290 | #Since 30 is lcm(2,3,5), we'll set our test numbers to 291 | #29 % 30 and keep them there 292 | low = (2 ** (bits-2)) * 3//2 293 | high = (2 ** (bits-1)) - 30 294 | q = getRandomNumber(low, high) 295 | q += 29 - (q % 30) 296 | while 1: 297 | if display: print(".", end=' ') 298 | q += 30 299 | if (q >= high): 300 | q = getRandomNumber(low, high) 301 | q += 29 - (q % 30) 302 | #Ideas from Tom Wu's SRP code 303 | #Do trial division on p and q before Rabin-Miller 304 | if isPrime(q, 0, display=display): 305 | p = (2 * q) + 1 306 | if isPrime(p, display=display): 307 | if isPrime(q, display=display): 308 | return p 309 | -------------------------------------------------------------------------------- /tlslite/utils/datefuncs.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | import os 5 | 6 | #Functions for manipulating datetime objects 7 | #CCYY-MM-DDThh:mm:ssZ 8 | def parseDateClass(s): 9 | year, month, day = s.split("-") 10 | day, tail = day[:2], day[2:] 11 | hour, minute, second = tail[1:].split(":") 12 | second = second[:2] 13 | year, month, day = int(year), int(month), int(day) 14 | hour, minute, second = int(hour), int(minute), int(second) 15 | return createDateClass(year, month, day, hour, minute, second) 16 | 17 | 18 | if os.name != "java": 19 | from datetime import datetime, timedelta 20 | 21 | #Helper functions for working with a date/time class 22 | def createDateClass(year, month, day, hour, minute, second): 23 | return datetime(year, month, day, hour, minute, second) 24 | 25 | def printDateClass(d): 26 | #Split off fractional seconds, append 'Z' 27 | return d.isoformat().split(".")[0]+"Z" 28 | 29 | def getNow(): 30 | return datetime.utcnow() 31 | 32 | def getHoursFromNow(hours): 33 | return datetime.utcnow() + timedelta(hours=hours) 34 | 35 | def getMinutesFromNow(minutes): 36 | return datetime.utcnow() + timedelta(minutes=minutes) 37 | 38 | def isDateClassExpired(d): 39 | return d < datetime.utcnow() 40 | 41 | def isDateClassBefore(d1, d2): 42 | return d1 < d2 43 | 44 | else: 45 | #Jython 2.1 is missing lots of python 2.3 stuff, 46 | #which we have to emulate here: 47 | import java 48 | import jarray 49 | 50 | def createDateClass(year, month, day, hour, minute, second): 51 | c = java.util.Calendar.getInstance() 52 | c.setTimeZone(java.util.TimeZone.getTimeZone("UTC")) 53 | c.set(year, month-1, day, hour, minute, second) 54 | return c 55 | 56 | def printDateClass(d): 57 | return "%04d-%02d-%02dT%02d:%02d:%02dZ" % \ 58 | (d.get(d.YEAR), d.get(d.MONTH)+1, d.get(d.DATE), \ 59 | d.get(d.HOUR_OF_DAY), d.get(d.MINUTE), d.get(d.SECOND)) 60 | 61 | def getNow(): 62 | c = java.util.Calendar.getInstance() 63 | c.setTimeZone(java.util.TimeZone.getTimeZone("UTC")) 64 | c.get(c.HOUR) #force refresh? 65 | return c 66 | 67 | def getHoursFromNow(hours): 68 | d = getNow() 69 | d.add(d.HOUR, hours) 70 | return d 71 | 72 | def isDateClassExpired(d): 73 | n = getNow() 74 | return d.before(n) 75 | 76 | def isDateClassBefore(d1, d2): 77 | return d1.before(d2) 78 | -------------------------------------------------------------------------------- /tlslite/utils/keyfactory.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Factory functions for asymmetric cryptography. 5 | @sort: generateRSAKey, parsePEMKey, parseAsPublicKey 6 | """ 7 | 8 | from .compat import * 9 | 10 | from .rsakey import RSAKey 11 | from .python_rsakey import Python_RSAKey 12 | from tlslite.utils import cryptomath 13 | 14 | if cryptomath.m2cryptoLoaded: 15 | from .openssl_rsakey import OpenSSL_RSAKey 16 | 17 | if cryptomath.pycryptoLoaded: 18 | from .pycrypto_rsakey import PyCrypto_RSAKey 19 | 20 | # ************************************************************************** 21 | # Factory Functions for RSA Keys 22 | # ************************************************************************** 23 | 24 | def generateRSAKey(bits, implementations=["openssl", "python"]): 25 | """Generate an RSA key with the specified bit length. 26 | 27 | @type bits: int 28 | @param bits: Desired bit length of the new key's modulus. 29 | 30 | @rtype: L{tlslite.utils.rsakey.RSAKey} 31 | @return: A new RSA private key. 32 | """ 33 | for implementation in implementations: 34 | if implementation == "openssl" and cryptomath.m2cryptoLoaded: 35 | return OpenSSL_RSAKey.generate(bits) 36 | elif implementation == "python": 37 | return Python_RSAKey.generate(bits) 38 | raise ValueError("No acceptable implementations") 39 | 40 | #Parse as an OpenSSL or Python key 41 | def parsePEMKey(s, private=False, public=False, passwordCallback=None, 42 | implementations=["openssl", "python"]): 43 | """Parse a PEM-format key. 44 | 45 | The PEM format is used by OpenSSL and other tools. The 46 | format is typically used to store both the public and private 47 | components of a key. For example:: 48 | 49 | -----BEGIN RSA PRIVATE KEY----- 50 | MIICXQIBAAKBgQDYscuoMzsGmW0pAYsmyHltxB2TdwHS0dImfjCMfaSDkfLdZY5+ 51 | dOWORVns9etWnr194mSGA1F0Pls/VJW8+cX9+3vtJV8zSdANPYUoQf0TP7VlJxkH 52 | dSRkUbEoz5bAAs/+970uos7n7iXQIni+3erUTdYEk2iWnMBjTljfgbK/dQIDAQAB 53 | AoGAJHoJZk75aKr7DSQNYIHuruOMdv5ZeDuJvKERWxTrVJqE32/xBKh42/IgqRrc 54 | esBN9ZregRCd7YtxoL+EVUNWaJNVx2mNmezEznrc9zhcYUrgeaVdFO2yBF1889zO 55 | gCOVwrO8uDgeyj6IKa25H6c1N13ih/o7ZzEgWbGG+ylU1yECQQDv4ZSJ4EjSh/Fl 56 | aHdz3wbBa/HKGTjC8iRy476Cyg2Fm8MZUe9Yy3udOrb5ZnS2MTpIXt5AF3h2TfYV 57 | VoFXIorjAkEA50FcJmzT8sNMrPaV8vn+9W2Lu4U7C+K/O2g1iXMaZms5PC5zV5aV 58 | CKXZWUX1fq2RaOzlbQrpgiolhXpeh8FjxwJBAOFHzSQfSsTNfttp3KUpU0LbiVvv 59 | i+spVSnA0O4rq79KpVNmK44Mq67hsW1P11QzrzTAQ6GVaUBRv0YS061td1kCQHnP 60 | wtN2tboFR6lABkJDjxoGRvlSt4SOPr7zKGgrWjeiuTZLHXSAnCY+/hr5L9Q3ZwXG 61 | 6x6iBdgLjVIe4BZQNtcCQQDXGv/gWinCNTN3MPWfTW/RGzuMYVmyBFais0/VrgdH 62 | h1dLpztmpQqfyH/zrBXQ9qL/zR4ojS6XYneO/U18WpEe 63 | -----END RSA PRIVATE KEY----- 64 | 65 | To generate a key like this with OpenSSL, run:: 66 | 67 | openssl genrsa 2048 > key.pem 68 | 69 | This format also supports password-encrypted private keys. TLS 70 | Lite can only handle password-encrypted private keys when OpenSSL 71 | and M2Crypto are installed. In this case, passwordCallback will be 72 | invoked to query the user for the password. 73 | 74 | @type s: str 75 | @param s: A string containing a PEM-encoded public or private key. 76 | 77 | @type private: bool 78 | @param private: If True, a L{SyntaxError} will be raised if the 79 | private key component is not present. 80 | 81 | @type public: bool 82 | @param public: If True, the private key component (if present) will 83 | be discarded, so this function will always return a public key. 84 | 85 | @type passwordCallback: callable 86 | @param passwordCallback: This function will be called, with no 87 | arguments, if the PEM-encoded private key is password-encrypted. 88 | The callback should return the password string. If the password is 89 | incorrect, SyntaxError will be raised. If no callback is passed 90 | and the key is password-encrypted, a prompt will be displayed at 91 | the console. 92 | 93 | @rtype: L{tlslite.utils.RSAKey.RSAKey} 94 | @return: An RSA key. 95 | 96 | @raise SyntaxError: If the key is not properly formatted. 97 | """ 98 | for implementation in implementations: 99 | if implementation == "openssl" and cryptomath.m2cryptoLoaded: 100 | key = OpenSSL_RSAKey.parse(s, passwordCallback) 101 | break 102 | elif implementation == "python": 103 | key = Python_RSAKey.parsePEM(s) 104 | break 105 | else: 106 | raise ValueError("No acceptable implementations") 107 | 108 | return _parseKeyHelper(key, private, public) 109 | 110 | 111 | def _parseKeyHelper(key, private, public): 112 | if private: 113 | if not key.hasPrivateKey(): 114 | raise SyntaxError("Not a private key!") 115 | 116 | if public: 117 | return _createPublicKey(key) 118 | 119 | if private: 120 | if hasattr(key, "d"): 121 | return _createPrivateKey(key) 122 | else: 123 | return key 124 | 125 | return key 126 | 127 | def parseAsPublicKey(s): 128 | """Parse a PEM-formatted public key. 129 | 130 | @type s: str 131 | @param s: A string containing a PEM-encoded public or private key. 132 | 133 | @rtype: L{tlslite.utils.rsakey.RSAKey} 134 | @return: An RSA public key. 135 | 136 | @raise SyntaxError: If the key is not properly formatted. 137 | """ 138 | return parsePEMKey(s, public=True) 139 | 140 | def parsePrivateKey(s): 141 | """Parse a PEM-formatted private key. 142 | 143 | @type s: str 144 | @param s: A string containing a PEM-encoded private key. 145 | 146 | @rtype: L{tlslite.utils.rsakey.RSAKey} 147 | @return: An RSA private key. 148 | 149 | @raise SyntaxError: If the key is not properly formatted. 150 | """ 151 | return parsePEMKey(s, private=True) 152 | 153 | def _createPublicKey(key): 154 | """ 155 | Create a new public key. Discard any private component, 156 | and return the most efficient key possible. 157 | """ 158 | if not isinstance(key, RSAKey): 159 | raise AssertionError() 160 | return _createPublicRSAKey(key.n, key.e) 161 | 162 | def _createPrivateKey(key): 163 | """ 164 | Create a new private key. Return the most efficient key possible. 165 | """ 166 | if not isinstance(key, RSAKey): 167 | raise AssertionError() 168 | if not key.hasPrivateKey(): 169 | raise AssertionError() 170 | return _createPrivateRSAKey(key.n, key.e, key.d, key.p, key.q, key.dP, 171 | key.dQ, key.qInv) 172 | 173 | def _createPublicRSAKey(n, e, implementations = ["openssl", "pycrypto", 174 | "python"]): 175 | for implementation in implementations: 176 | if implementation == "openssl" and cryptomath.m2cryptoLoaded: 177 | return OpenSSL_RSAKey(n, e) 178 | elif implementation == "pycrypto" and cryptomath.pycryptoLoaded: 179 | return PyCrypto_RSAKey(n, e) 180 | elif implementation == "python": 181 | return Python_RSAKey(n, e) 182 | raise ValueError("No acceptable implementations") 183 | 184 | def _createPrivateRSAKey(n, e, d, p, q, dP, dQ, qInv, 185 | implementations = ["pycrypto", "python"]): 186 | for implementation in implementations: 187 | if implementation == "pycrypto" and cryptomath.pycryptoLoaded: 188 | return PyCrypto_RSAKey(n, e, d, p, q, dP, dQ, qInv) 189 | elif implementation == "python": 190 | return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv) 191 | raise ValueError("No acceptable implementations") 192 | -------------------------------------------------------------------------------- /tlslite/utils/openssl_aes.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """OpenSSL/M2Crypto AES implementation.""" 5 | 6 | from .cryptomath import * 7 | from .aes import * 8 | 9 | if m2cryptoLoaded: 10 | 11 | def new(key, mode, IV): 12 | return OpenSSL_AES(key, mode, IV) 13 | 14 | class OpenSSL_AES(AES): 15 | 16 | def __init__(self, key, mode, IV): 17 | AES.__init__(self, key, mode, IV, "openssl") 18 | self.key = key 19 | self.IV = IV 20 | 21 | def _createContext(self, encrypt): 22 | context = m2.cipher_ctx_new() 23 | if len(self.key)==16: 24 | cipherType = m2.aes_128_cbc() 25 | if len(self.key)==24: 26 | cipherType = m2.aes_192_cbc() 27 | if len(self.key)==32: 28 | cipherType = m2.aes_256_cbc() 29 | m2.cipher_init(context, cipherType, self.key, self.IV, encrypt) 30 | return context 31 | 32 | def encrypt(self, plaintext): 33 | AES.encrypt(self, plaintext) 34 | context = self._createContext(1) 35 | ciphertext = m2.cipher_update(context, plaintext) 36 | m2.cipher_ctx_free(context) 37 | self.IV = ciphertext[-self.block_size:] 38 | return bytearray(ciphertext) 39 | 40 | def decrypt(self, ciphertext): 41 | AES.decrypt(self, ciphertext) 42 | context = self._createContext(0) 43 | #I think M2Crypto has a bug - it fails to decrypt and return the last block passed in. 44 | #To work around this, we append sixteen zeros to the string, below: 45 | plaintext = m2.cipher_update(context, ciphertext+('\0'*16)) 46 | 47 | #If this bug is ever fixed, then plaintext will end up having a garbage 48 | #plaintext block on the end. That's okay - the below code will discard it. 49 | plaintext = plaintext[:len(ciphertext)] 50 | m2.cipher_ctx_free(context) 51 | self.IV = ciphertext[-self.block_size:] 52 | return bytearray(plaintext) 53 | -------------------------------------------------------------------------------- /tlslite/utils/openssl_rc4.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """OpenSSL/M2Crypto RC4 implementation.""" 5 | 6 | from .cryptomath import * 7 | from .rc4 import RC4 8 | 9 | if m2cryptoLoaded: 10 | 11 | def new(key): 12 | return OpenSSL_RC4(key) 13 | 14 | class OpenSSL_RC4(RC4): 15 | 16 | def __init__(self, key): 17 | RC4.__init__(self, key, "openssl") 18 | self.rc4 = m2.rc4_new() 19 | m2.rc4_set_key(self.rc4, key) 20 | 21 | def __del__(self): 22 | m2.rc4_free(self.rc4) 23 | 24 | def encrypt(self, plaintext): 25 | return bytearray(m2.rc4_update(self.rc4, plaintext)) 26 | 27 | def decrypt(self, ciphertext): 28 | return bytearray(self.encrypt(ciphertext)) 29 | -------------------------------------------------------------------------------- /tlslite/utils/openssl_rsakey.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """OpenSSL/M2Crypto RSA implementation.""" 5 | 6 | from .cryptomath import * 7 | 8 | from .rsakey import * 9 | from .python_rsakey import Python_RSAKey 10 | 11 | #copied from M2Crypto.util.py, so when we load the local copy of m2 12 | #we can still use it 13 | def password_callback(v, prompt1='Enter private key passphrase:', 14 | prompt2='Verify passphrase:'): 15 | from getpass import getpass 16 | while 1: 17 | try: 18 | p1=getpass(prompt1) 19 | if v: 20 | p2=getpass(prompt2) 21 | if p1==p2: 22 | break 23 | else: 24 | break 25 | except KeyboardInterrupt: 26 | return None 27 | return p1 28 | 29 | 30 | if m2cryptoLoaded: 31 | class OpenSSL_RSAKey(RSAKey): 32 | def __init__(self, n=0, e=0): 33 | self.rsa = None 34 | self._hasPrivateKey = False 35 | if (n and not e) or (e and not n): 36 | raise AssertionError() 37 | if n and e: 38 | self.rsa = m2.rsa_new() 39 | m2.rsa_set_n(self.rsa, numberToMPI(n)) 40 | m2.rsa_set_e(self.rsa, numberToMPI(e)) 41 | 42 | def __del__(self): 43 | if self.rsa: 44 | m2.rsa_free(self.rsa) 45 | 46 | def __getattr__(self, name): 47 | if name == 'e': 48 | if not self.rsa: 49 | return 0 50 | return mpiToNumber(m2.rsa_get_e(self.rsa)) 51 | elif name == 'n': 52 | if not self.rsa: 53 | return 0 54 | return mpiToNumber(m2.rsa_get_n(self.rsa)) 55 | else: 56 | raise AttributeError 57 | 58 | def hasPrivateKey(self): 59 | return self._hasPrivateKey 60 | 61 | def _rawPrivateKeyOp(self, m): 62 | b = numberToByteArray(m, numBytes(self.n)) 63 | s = m2.rsa_private_encrypt(self.rsa, bytes(b), m2.no_padding) 64 | c = bytesToNumber(bytearray(s)) 65 | return c 66 | 67 | def _rawPublicKeyOp(self, c): 68 | b = numberToByteArray(c, numBytes(self.n)) 69 | s = m2.rsa_public_decrypt(self.rsa, bytes(b), m2.no_padding) 70 | m = bytesToNumber(bytearray(s)) 71 | return m 72 | 73 | def acceptsPassword(self): return True 74 | 75 | def write(self, password=None): 76 | bio = m2.bio_new(m2.bio_s_mem()) 77 | if self._hasPrivateKey: 78 | if password: 79 | def f(v): return password 80 | m2.rsa_write_key(self.rsa, bio, m2.des_ede_cbc(), f) 81 | else: 82 | def f(): pass 83 | m2.rsa_write_key_no_cipher(self.rsa, bio, f) 84 | else: 85 | if password: 86 | raise AssertionError() 87 | m2.rsa_write_pub_key(self.rsa, bio) 88 | s = m2.bio_read(bio, m2.bio_ctrl_pending(bio)) 89 | m2.bio_free(bio) 90 | return s 91 | 92 | def generate(bits): 93 | key = OpenSSL_RSAKey() 94 | def f():pass 95 | key.rsa = m2.rsa_generate_key(bits, 3, f) 96 | key._hasPrivateKey = True 97 | return key 98 | generate = staticmethod(generate) 99 | 100 | def parse(s, passwordCallback=None): 101 | # Skip forward to the first PEM header 102 | start = s.find("-----BEGIN ") 103 | if start == -1: 104 | raise SyntaxError() 105 | s = s[start:] 106 | if s.startswith("-----BEGIN "): 107 | if passwordCallback==None: 108 | callback = password_callback 109 | else: 110 | def f(v, prompt1=None, prompt2=None): 111 | return passwordCallback() 112 | callback = f 113 | bio = m2.bio_new(m2.bio_s_mem()) 114 | try: 115 | m2.bio_write(bio, s) 116 | key = OpenSSL_RSAKey() 117 | # parse SSLay format PEM file 118 | if s.startswith("-----BEGIN RSA PRIVATE KEY-----"): 119 | def f():pass 120 | key.rsa = m2.rsa_read_key(bio, callback) 121 | if key.rsa == None: 122 | raise SyntaxError() 123 | key._hasPrivateKey = True 124 | # parse a standard PKCS#8 PEM file 125 | elif s.startswith("-----BEGIN PRIVATE KEY-----"): 126 | def f():pass 127 | key.rsa = m2.pkey_read_pem(bio, callback) 128 | # the below code assumes RSA key while PKCS#8 files 129 | # (and by extension the EVP_PKEY structure) can be 130 | # also DSA or EC, thus the double check against None 131 | # (first if the file was properly loaded and second 132 | # if the file actually has a RSA key in it) 133 | # tlslite doesn't support DSA or EC so it's useless 134 | # to handle them in a different way 135 | if key.rsa == None: 136 | raise SyntaxError() 137 | key.rsa = m2.pkey_get1_rsa(key.rsa) 138 | if key.rsa == None: 139 | raise SyntaxError() 140 | key._hasPrivateKey = True 141 | elif s.startswith("-----BEGIN PUBLIC KEY-----"): 142 | key.rsa = m2.rsa_read_pub_key(bio) 143 | if key.rsa == None: 144 | raise SyntaxError() 145 | key._hasPrivateKey = False 146 | else: 147 | raise SyntaxError() 148 | return key 149 | finally: 150 | m2.bio_free(bio) 151 | else: 152 | raise SyntaxError() 153 | 154 | parse = staticmethod(parse) 155 | -------------------------------------------------------------------------------- /tlslite/utils/openssl_tripledes.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """OpenSSL/M2Crypto 3DES implementation.""" 5 | 6 | from .cryptomath import * 7 | from .tripledes import * 8 | 9 | if m2cryptoLoaded: 10 | 11 | def new(key, mode, IV): 12 | return OpenSSL_TripleDES(key, mode, IV) 13 | 14 | class OpenSSL_TripleDES(TripleDES): 15 | 16 | def __init__(self, key, mode, IV): 17 | TripleDES.__init__(self, key, mode, IV, "openssl") 18 | self.key = key 19 | self.IV = IV 20 | 21 | def _createContext(self, encrypt): 22 | context = m2.cipher_ctx_new() 23 | cipherType = m2.des_ede3_cbc() 24 | m2.cipher_init(context, cipherType, self.key, self.IV, encrypt) 25 | return context 26 | 27 | def encrypt(self, plaintext): 28 | TripleDES.encrypt(self, plaintext) 29 | context = self._createContext(1) 30 | ciphertext = m2.cipher_update(context, plaintext) 31 | m2.cipher_ctx_free(context) 32 | self.IV = ciphertext[-self.block_size:] 33 | return bytearray(ciphertext) 34 | 35 | def decrypt(self, ciphertext): 36 | TripleDES.decrypt(self, ciphertext) 37 | context = self._createContext(0) 38 | #I think M2Crypto has a bug - it fails to decrypt and return the last block passed in. 39 | #To work around this, we append sixteen zeros to the string, below: 40 | plaintext = m2.cipher_update(context, ciphertext+('\0'*16)) 41 | 42 | #If this bug is ever fixed, then plaintext will end up having a garbage 43 | #plaintext block on the end. That's okay - the below code will ignore it. 44 | plaintext = plaintext[:len(ciphertext)] 45 | m2.cipher_ctx_free(context) 46 | self.IV = ciphertext[-self.block_size:] 47 | return bytearray(plaintext) -------------------------------------------------------------------------------- /tlslite/utils/pem.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | from .compat import * 5 | import binascii 6 | 7 | #This code is shared with tackpy (somewhat), so I'd rather make minimal 8 | #changes, and preserve the use of a2b_base64 throughout. 9 | 10 | def dePem(s, name): 11 | """Decode a PEM string into a bytearray of its payload. 12 | 13 | The input must contain an appropriate PEM prefix and postfix 14 | based on the input name string, e.g. for name="CERTIFICATE":: 15 | 16 | -----BEGIN CERTIFICATE----- 17 | MIIBXDCCAUSgAwIBAgIBADANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDEwRUQUNL 18 | ... 19 | KoZIhvcNAQEFBQADAwA5kw== 20 | -----END CERTIFICATE----- 21 | 22 | The first such PEM block in the input will be found, and its 23 | payload will be base64 decoded and returned. 24 | """ 25 | prefix = "-----BEGIN %s-----" % name 26 | postfix = "-----END %s-----" % name 27 | start = s.find(prefix) 28 | if start == -1: 29 | raise SyntaxError("Missing PEM prefix") 30 | end = s.find(postfix, start+len(prefix)) 31 | if end == -1: 32 | raise SyntaxError("Missing PEM postfix") 33 | s = s[start+len("-----BEGIN %s-----" % name) : end] 34 | retBytes = a2b_base64(s) # May raise SyntaxError 35 | return retBytes 36 | 37 | def dePemList(s, name): 38 | """Decode a sequence of PEM blocks into a list of bytearrays. 39 | 40 | The input must contain any number of PEM blocks, each with the appropriate 41 | PEM prefix and postfix based on the input name string, e.g. for 42 | name="TACK BREAK SIG". Arbitrary text can appear between and before and 43 | after the PEM blocks. For example:: 44 | 45 | Created by TACK.py 0.9.3 Created at 2012-02-01T00:30:10Z 46 | -----BEGIN TACK BREAK SIG----- 47 | ATKhrz5C6JHJW8BF5fLVrnQss6JnWVyEaC0p89LNhKPswvcC9/s6+vWLd9snYTUv 48 | YMEBdw69PUP8JB4AdqA3K6Ap0Fgd9SSTOECeAKOUAym8zcYaXUwpk0+WuPYa7Zmm 49 | SkbOlK4ywqt+amhWbg9txSGUwFO5tWUHT3QrnRlE/e3PeNFXLx5Bckg= 50 | -----END TACK BREAK SIG----- 51 | Created by TACK.py 0.9.3 Created at 2012-02-01T00:30:11Z 52 | -----BEGIN TACK BREAK SIG----- 53 | ATKhrz5C6JHJW8BF5fLVrnQss6JnWVyEaC0p89LNhKPswvcC9/s6+vWLd9snYTUv 54 | YMEBdw69PUP8JB4AdqA3K6BVCWfcjN36lx6JwxmZQncS6sww7DecFO/qjSePCxwM 55 | +kdDqX/9/183nmjx6bf0ewhPXkA0nVXsDYZaydN8rJU1GaMlnjcIYxY= 56 | -----END TACK BREAK SIG----- 57 | 58 | All such PEM blocks will be found, decoded, and return in an ordered list 59 | of bytearrays, which may have zero elements if not PEM blocks are found. 60 | """ 61 | bList = [] 62 | prefix = "-----BEGIN %s-----" % name 63 | postfix = "-----END %s-----" % name 64 | while 1: 65 | start = s.find(prefix) 66 | if start == -1: 67 | return bList 68 | end = s.find(postfix, start+len(prefix)) 69 | if end == -1: 70 | raise SyntaxError("Missing PEM postfix") 71 | s2 = s[start+len(prefix) : end] 72 | retBytes = a2b_base64(s2) # May raise SyntaxError 73 | bList.append(retBytes) 74 | s = s[end+len(postfix) : ] 75 | 76 | def pem(b, name): 77 | """Encode a payload bytearray into a PEM string. 78 | 79 | The input will be base64 encoded, then wrapped in a PEM prefix/postfix 80 | based on the name string, e.g. for name="CERTIFICATE":: 81 | 82 | -----BEGIN CERTIFICATE----- 83 | MIIBXDCCAUSgAwIBAgIBADANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDEwRUQUNL 84 | ... 85 | KoZIhvcNAQEFBQADAwA5kw== 86 | -----END CERTIFICATE----- 87 | """ 88 | s1 = b2a_base64(b)[:-1] # remove terminating \n 89 | s2 = "" 90 | while s1: 91 | s2 += s1[:64] + "\n" 92 | s1 = s1[64:] 93 | s = ("-----BEGIN %s-----\n" % name) + s2 + \ 94 | ("-----END %s-----\n" % name) 95 | return s 96 | 97 | def pemSniff(inStr, name): 98 | searchStr = "-----BEGIN %s-----" % name 99 | return searchStr in inStr 100 | -------------------------------------------------------------------------------- /tlslite/utils/pycrypto_aes.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """PyCrypto AES implementation.""" 5 | 6 | from .cryptomath import * 7 | from .aes import * 8 | 9 | if pycryptoLoaded: 10 | import Crypto.Cipher.AES 11 | 12 | def new(key, mode, IV): 13 | return PyCrypto_AES(key, mode, IV) 14 | 15 | class PyCrypto_AES(AES): 16 | 17 | def __init__(self, key, mode, IV): 18 | AES.__init__(self, key, mode, IV, "pycrypto") 19 | key = bytes(key) 20 | IV = bytes(IV) 21 | self.context = Crypto.Cipher.AES.new(key, mode, IV) 22 | 23 | def encrypt(self, plaintext): 24 | plaintext = bytes(plaintext) 25 | return bytearray(self.context.encrypt(plaintext)) 26 | 27 | def decrypt(self, ciphertext): 28 | ciphertext = bytes(ciphertext) 29 | return bytearray(self.context.decrypt(ciphertext)) 30 | -------------------------------------------------------------------------------- /tlslite/utils/pycrypto_rc4.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """PyCrypto RC4 implementation.""" 5 | 6 | from .cryptomath import * 7 | from .rc4 import * 8 | 9 | if pycryptoLoaded: 10 | import Crypto.Cipher.ARC4 11 | 12 | def new(key): 13 | return PyCrypto_RC4(key) 14 | 15 | class PyCrypto_RC4(RC4): 16 | 17 | def __init__(self, key): 18 | RC4.__init__(self, key, "pycrypto") 19 | key = bytes(key) 20 | self.context = Crypto.Cipher.ARC4.new(key) 21 | 22 | def encrypt(self, plaintext): 23 | plaintext = bytes(plaintext) 24 | return bytearray(self.context.encrypt(plaintext)) 25 | 26 | def decrypt(self, ciphertext): 27 | ciphertext = bytes(ciphertext) 28 | return bytearray(self.context.decrypt(ciphertext)) -------------------------------------------------------------------------------- /tlslite/utils/pycrypto_rsakey.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """PyCrypto RSA implementation.""" 5 | 6 | from .cryptomath import * 7 | 8 | from .rsakey import * 9 | from .python_rsakey import Python_RSAKey 10 | from .compat import compatLong 11 | 12 | if pycryptoLoaded: 13 | 14 | from Crypto.PublicKey import RSA 15 | 16 | class PyCrypto_RSAKey(RSAKey): 17 | def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0): 18 | if not d: 19 | self.rsa = RSA.construct((compatLong(n), compatLong(e))) 20 | else: 21 | self.rsa = RSA.construct((compatLong(n), compatLong(e), 22 | compatLong(d), compatLong(p), 23 | compatLong(q))) 24 | 25 | def __getattr__(self, name): 26 | return getattr(self.rsa, name) 27 | 28 | def hasPrivateKey(self): 29 | return self.rsa.has_private() 30 | 31 | def _rawPrivateKeyOp(self, m): 32 | c = self.rsa.decrypt((m,)) 33 | return c 34 | 35 | def _rawPublicKeyOp(self, c): 36 | m = self.rsa.encrypt(c, None)[0] 37 | return m 38 | 39 | def generate(bits): 40 | key = PyCrypto_RSAKey() 41 | def f(numBytes): 42 | return bytes(getRandomBytes(numBytes)) 43 | key.rsa = RSA.generate(bits, f) 44 | return key 45 | generate = staticmethod(generate) 46 | -------------------------------------------------------------------------------- /tlslite/utils/pycrypto_tripledes.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """PyCrypto 3DES implementation.""" 5 | 6 | from .cryptomath import * 7 | from .tripledes import * 8 | 9 | if pycryptoLoaded: 10 | import Crypto.Cipher.DES3 11 | 12 | def new(key, mode, IV): 13 | return PyCrypto_TripleDES(key, mode, IV) 14 | 15 | class PyCrypto_TripleDES(TripleDES): 16 | 17 | def __init__(self, key, mode, IV): 18 | TripleDES.__init__(self, key, mode, IV, "pycrypto") 19 | key = bytes(key) 20 | IV = bytes(IV) 21 | self.context = Crypto.Cipher.DES3.new(key, mode, IV) 22 | 23 | def encrypt(self, plaintext): 24 | plaintext = bytes(plaintext) 25 | return bytearray(self.context.encrypt(plaintext)) 26 | 27 | def decrypt(self, ciphertext): 28 | ciphertext = bytes(ciphertext) 29 | return bytearray(self.context.decrypt(ciphertext)) -------------------------------------------------------------------------------- /tlslite/utils/python_aes.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Pure-Python AES implementation.""" 5 | 6 | from .cryptomath import * 7 | 8 | from .aes import * 9 | from .rijndael import rijndael 10 | 11 | def new(key, mode, IV): 12 | return Python_AES(key, mode, IV) 13 | 14 | class Python_AES(AES): 15 | def __init__(self, key, mode, IV): 16 | AES.__init__(self, key, mode, IV, "python") 17 | self.rijndael = rijndael(key, 16) 18 | self.IV = IV 19 | 20 | def encrypt(self, plaintext): 21 | AES.encrypt(self, plaintext) 22 | 23 | plaintextBytes = plaintext[:] 24 | chainBytes = self.IV[:] 25 | 26 | #CBC Mode: For each block... 27 | for x in range(len(plaintextBytes)//16): 28 | 29 | #XOR with the chaining block 30 | blockBytes = plaintextBytes[x*16 : (x*16)+16] 31 | for y in range(16): 32 | blockBytes[y] ^= chainBytes[y] 33 | 34 | #Encrypt it 35 | encryptedBytes = self.rijndael.encrypt(blockBytes) 36 | 37 | #Overwrite the input with the output 38 | for y in range(16): 39 | plaintextBytes[(x*16)+y] = encryptedBytes[y] 40 | 41 | #Set the next chaining block 42 | chainBytes = encryptedBytes 43 | 44 | self.IV = chainBytes[:] 45 | return plaintextBytes 46 | 47 | def decrypt(self, ciphertext): 48 | AES.decrypt(self, ciphertext) 49 | 50 | ciphertextBytes = ciphertext[:] 51 | chainBytes = self.IV[:] 52 | 53 | #CBC Mode: For each block... 54 | for x in range(len(ciphertextBytes)//16): 55 | 56 | #Decrypt it 57 | blockBytes = ciphertextBytes[x*16 : (x*16)+16] 58 | decryptedBytes = self.rijndael.decrypt(blockBytes) 59 | 60 | #XOR with the chaining block and overwrite the input with output 61 | for y in range(16): 62 | decryptedBytes[y] ^= chainBytes[y] 63 | ciphertextBytes[(x*16)+y] = decryptedBytes[y] 64 | 65 | #Set the next chaining block 66 | chainBytes = blockBytes 67 | 68 | self.IV = chainBytes[:] 69 | return ciphertextBytes 70 | -------------------------------------------------------------------------------- /tlslite/utils/python_rc4.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Pure-Python RC4 implementation.""" 5 | 6 | from .rc4 import RC4 7 | from .cryptomath import * 8 | 9 | def new(key): 10 | return Python_RC4(key) 11 | 12 | class Python_RC4(RC4): 13 | def __init__(self, keyBytes): 14 | RC4.__init__(self, keyBytes, "python") 15 | S = [i for i in range(256)] 16 | j = 0 17 | for i in range(256): 18 | j = (j + S[i] + keyBytes[i % len(keyBytes)]) % 256 19 | S[i], S[j] = S[j], S[i] 20 | 21 | self.S = S 22 | self.i = 0 23 | self.j = 0 24 | 25 | def encrypt(self, plaintextBytes): 26 | ciphertextBytes = plaintextBytes[:] 27 | S = self.S 28 | i = self.i 29 | j = self.j 30 | for x in range(len(ciphertextBytes)): 31 | i = (i + 1) % 256 32 | j = (j + S[i]) % 256 33 | S[i], S[j] = S[j], S[i] 34 | t = (S[i] + S[j]) % 256 35 | ciphertextBytes[x] ^= S[t] 36 | self.i = i 37 | self.j = j 38 | return ciphertextBytes 39 | 40 | def decrypt(self, ciphertext): 41 | return self.encrypt(ciphertext) 42 | -------------------------------------------------------------------------------- /tlslite/utils/python_rsakey.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Pure-Python RSA implementation.""" 5 | 6 | from .cryptomath import * 7 | from .asn1parser import ASN1Parser 8 | from .rsakey import * 9 | from .pem import * 10 | 11 | class Python_RSAKey(RSAKey): 12 | def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0): 13 | if (n and not e) or (e and not n): 14 | raise AssertionError() 15 | self.n = n 16 | self.e = e 17 | self.d = d 18 | self.p = p 19 | self.q = q 20 | self.dP = dP 21 | self.dQ = dQ 22 | self.qInv = qInv 23 | self.blinder = 0 24 | self.unblinder = 0 25 | 26 | def hasPrivateKey(self): 27 | return self.d != 0 28 | 29 | def _rawPrivateKeyOp(self, m): 30 | #Create blinding values, on the first pass: 31 | if not self.blinder: 32 | self.unblinder = getRandomNumber(2, self.n) 33 | self.blinder = powMod(invMod(self.unblinder, self.n), self.e, 34 | self.n) 35 | 36 | #Blind the input 37 | m = (m * self.blinder) % self.n 38 | 39 | #Perform the RSA operation 40 | c = self._rawPrivateKeyOpHelper(m) 41 | 42 | #Unblind the output 43 | c = (c * self.unblinder) % self.n 44 | 45 | #Update blinding values 46 | self.blinder = (self.blinder * self.blinder) % self.n 47 | self.unblinder = (self.unblinder * self.unblinder) % self.n 48 | 49 | #Return the output 50 | return c 51 | 52 | 53 | def _rawPrivateKeyOpHelper(self, m): 54 | #Non-CRT version 55 | #c = powMod(m, self.d, self.n) 56 | 57 | #CRT version (~3x faster) 58 | s1 = powMod(m, self.dP, self.p) 59 | s2 = powMod(m, self.dQ, self.q) 60 | h = ((s1 - s2) * self.qInv) % self.p 61 | c = s2 + self.q * h 62 | return c 63 | 64 | def _rawPublicKeyOp(self, c): 65 | m = powMod(c, self.e, self.n) 66 | return m 67 | 68 | def acceptsPassword(self): return False 69 | 70 | def generate(bits): 71 | key = Python_RSAKey() 72 | p = getRandomPrime(bits//2, False) 73 | q = getRandomPrime(bits//2, False) 74 | t = lcm(p-1, q-1) 75 | key.n = p * q 76 | key.e = 65537 77 | key.d = invMod(key.e, t) 78 | key.p = p 79 | key.q = q 80 | key.dP = key.d % (p-1) 81 | key.dQ = key.d % (q-1) 82 | key.qInv = invMod(q, p) 83 | return key 84 | generate = staticmethod(generate) 85 | 86 | def parsePEM(s, passwordCallback=None): 87 | """Parse a string containing a PEM-encoded .""" 88 | 89 | if pemSniff(s, "PRIVATE KEY"): 90 | bytes = dePem(s, "PRIVATE KEY") 91 | return Python_RSAKey._parsePKCS8(bytes) 92 | elif pemSniff(s, "RSA PRIVATE KEY"): 93 | bytes = dePem(s, "RSA PRIVATE KEY") 94 | return Python_RSAKey._parseSSLeay(bytes) 95 | else: 96 | raise SyntaxError("Not a PEM private key file") 97 | parsePEM = staticmethod(parsePEM) 98 | 99 | def _parsePKCS8(bytes): 100 | p = ASN1Parser(bytes) 101 | 102 | version = p.getChild(0).value[0] 103 | if version != 0: 104 | raise SyntaxError("Unrecognized PKCS8 version") 105 | 106 | rsaOID = p.getChild(1).value 107 | if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]: 108 | raise SyntaxError("Unrecognized AlgorithmIdentifier") 109 | 110 | #Get the privateKey 111 | privateKeyP = p.getChild(2) 112 | 113 | #Adjust for OCTET STRING encapsulation 114 | privateKeyP = ASN1Parser(privateKeyP.value) 115 | 116 | return Python_RSAKey._parseASN1PrivateKey(privateKeyP) 117 | _parsePKCS8 = staticmethod(_parsePKCS8) 118 | 119 | def _parseSSLeay(bytes): 120 | privateKeyP = ASN1Parser(bytes) 121 | return Python_RSAKey._parseASN1PrivateKey(privateKeyP) 122 | _parseSSLeay = staticmethod(_parseSSLeay) 123 | 124 | def _parseASN1PrivateKey(privateKeyP): 125 | version = privateKeyP.getChild(0).value[0] 126 | if version != 0: 127 | raise SyntaxError("Unrecognized RSAPrivateKey version") 128 | n = bytesToNumber(privateKeyP.getChild(1).value) 129 | e = bytesToNumber(privateKeyP.getChild(2).value) 130 | d = bytesToNumber(privateKeyP.getChild(3).value) 131 | p = bytesToNumber(privateKeyP.getChild(4).value) 132 | q = bytesToNumber(privateKeyP.getChild(5).value) 133 | dP = bytesToNumber(privateKeyP.getChild(6).value) 134 | dQ = bytesToNumber(privateKeyP.getChild(7).value) 135 | qInv = bytesToNumber(privateKeyP.getChild(8).value) 136 | return Python_RSAKey(n, e, d, p, q, dP, dQ, qInv) 137 | _parseASN1PrivateKey = staticmethod(_parseASN1PrivateKey) 138 | -------------------------------------------------------------------------------- /tlslite/utils/rc4.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Abstract class for RC4.""" 5 | 6 | 7 | class RC4(object): 8 | def __init__(self, keyBytes, implementation): 9 | if len(keyBytes) < 16 or len(keyBytes) > 256: 10 | raise ValueError() 11 | self.isBlockCipher = False 12 | self.name = "rc4" 13 | self.implementation = implementation 14 | 15 | def encrypt(self, plaintext): 16 | raise NotImplementedError() 17 | 18 | def decrypt(self, ciphertext): 19 | raise NotImplementedError() -------------------------------------------------------------------------------- /tlslite/utils/rsakey.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Abstract class for RSA.""" 5 | 6 | from .cryptomath import * 7 | 8 | 9 | class RSAKey(object): 10 | """This is an abstract base class for RSA keys. 11 | 12 | Particular implementations of RSA keys, such as 13 | L{openssl_rsakey.OpenSSL_RSAKey}, 14 | L{python_rsakey.Python_RSAKey}, and 15 | L{pycrypto_rsakey.PyCrypto_RSAKey}, 16 | inherit from this. 17 | 18 | To create or parse an RSA key, don't use one of these classes 19 | directly. Instead, use the factory functions in 20 | L{tlslite.utils.keyfactory}. 21 | """ 22 | 23 | def __init__(self, n=0, e=0): 24 | """Create a new RSA key. 25 | 26 | If n and e are passed in, the new key will be initialized. 27 | 28 | @type n: int 29 | @param n: RSA modulus. 30 | 31 | @type e: int 32 | @param e: RSA public exponent. 33 | """ 34 | raise NotImplementedError() 35 | 36 | def __len__(self): 37 | """Return the length of this key in bits. 38 | 39 | @rtype: int 40 | """ 41 | return numBits(self.n) 42 | 43 | def hasPrivateKey(self): 44 | """Return whether or not this key has a private component. 45 | 46 | @rtype: bool 47 | """ 48 | raise NotImplementedError() 49 | 50 | def hashAndSign(self, bytes): 51 | """Hash and sign the passed-in bytes. 52 | 53 | This requires the key to have a private component. It performs 54 | a PKCS1-SHA1 signature on the passed-in data. 55 | 56 | @type bytes: str or L{bytearray} of unsigned bytes 57 | @param bytes: The value which will be hashed and signed. 58 | 59 | @rtype: L{bytearray} of unsigned bytes. 60 | @return: A PKCS1-SHA1 signature on the passed-in data. 61 | """ 62 | hashBytes = SHA1(bytearray(bytes)) 63 | prefixedHashBytes = self.addPKCS1SHA1Prefix(hashBytes) 64 | sigBytes = self.sign(prefixedHashBytes) 65 | return sigBytes 66 | 67 | def hashAndVerify(self, sigBytes, bytes): 68 | """Hash and verify the passed-in bytes with the signature. 69 | 70 | This verifies a PKCS1-SHA1 signature on the passed-in data. 71 | 72 | @type sigBytes: L{bytearray} of unsigned bytes 73 | @param sigBytes: A PKCS1-SHA1 signature. 74 | 75 | @type bytes: str or L{bytearray} of unsigned bytes 76 | @param bytes: The value which will be hashed and verified. 77 | 78 | @rtype: bool 79 | @return: Whether the signature matches the passed-in data. 80 | """ 81 | hashBytes = SHA1(bytearray(bytes)) 82 | 83 | # Try it with/without the embedded NULL 84 | prefixedHashBytes1 = self.addPKCS1SHA1Prefix(hashBytes, False) 85 | prefixedHashBytes2 = self.addPKCS1SHA1Prefix(hashBytes, True) 86 | result1 = self.verify(sigBytes, prefixedHashBytes1) 87 | result2 = self.verify(sigBytes, prefixedHashBytes2) 88 | return (result1 or result2) 89 | 90 | def sign(self, bytes): 91 | """Sign the passed-in bytes. 92 | 93 | This requires the key to have a private component. It performs 94 | a PKCS1 signature on the passed-in data. 95 | 96 | @type bytes: L{bytearray} of unsigned bytes 97 | @param bytes: The value which will be signed. 98 | 99 | @rtype: L{bytearray} of unsigned bytes. 100 | @return: A PKCS1 signature on the passed-in data. 101 | """ 102 | if not self.hasPrivateKey(): 103 | raise AssertionError() 104 | paddedBytes = self._addPKCS1Padding(bytes, 1) 105 | m = bytesToNumber(paddedBytes) 106 | if m >= self.n: 107 | raise ValueError() 108 | c = self._rawPrivateKeyOp(m) 109 | sigBytes = numberToByteArray(c, numBytes(self.n)) 110 | return sigBytes 111 | 112 | def verify(self, sigBytes, bytes): 113 | """Verify the passed-in bytes with the signature. 114 | 115 | This verifies a PKCS1 signature on the passed-in data. 116 | 117 | @type sigBytes: L{bytearray} of unsigned bytes 118 | @param sigBytes: A PKCS1 signature. 119 | 120 | @type bytes: L{bytearray} of unsigned bytes 121 | @param bytes: The value which will be verified. 122 | 123 | @rtype: bool 124 | @return: Whether the signature matches the passed-in data. 125 | """ 126 | if len(sigBytes) != numBytes(self.n): 127 | return False 128 | paddedBytes = self._addPKCS1Padding(bytes, 1) 129 | c = bytesToNumber(sigBytes) 130 | if c >= self.n: 131 | return False 132 | m = self._rawPublicKeyOp(c) 133 | checkBytes = numberToByteArray(m, numBytes(self.n)) 134 | return checkBytes == paddedBytes 135 | 136 | def encrypt(self, bytes): 137 | """Encrypt the passed-in bytes. 138 | 139 | This performs PKCS1 encryption of the passed-in data. 140 | 141 | @type bytes: L{bytearray} of unsigned bytes 142 | @param bytes: The value which will be encrypted. 143 | 144 | @rtype: L{bytearray} of unsigned bytes. 145 | @return: A PKCS1 encryption of the passed-in data. 146 | """ 147 | paddedBytes = self._addPKCS1Padding(bytes, 2) 148 | m = bytesToNumber(paddedBytes) 149 | if m >= self.n: 150 | raise ValueError() 151 | c = self._rawPublicKeyOp(m) 152 | encBytes = numberToByteArray(c, numBytes(self.n)) 153 | return encBytes 154 | 155 | def decrypt(self, encBytes): 156 | """Decrypt the passed-in bytes. 157 | 158 | This requires the key to have a private component. It performs 159 | PKCS1 decryption of the passed-in data. 160 | 161 | @type encBytes: L{bytearray} of unsigned bytes 162 | @param encBytes: The value which will be decrypted. 163 | 164 | @rtype: L{bytearray} of unsigned bytes or None. 165 | @return: A PKCS1 decryption of the passed-in data or None if 166 | the data is not properly formatted. 167 | """ 168 | if not self.hasPrivateKey(): 169 | raise AssertionError() 170 | if len(encBytes) != numBytes(self.n): 171 | return None 172 | c = bytesToNumber(encBytes) 173 | if c >= self.n: 174 | return None 175 | m = self._rawPrivateKeyOp(c) 176 | decBytes = numberToByteArray(m, numBytes(self.n)) 177 | #Check first two bytes 178 | if decBytes[0] != 0 or decBytes[1] != 2: 179 | return None 180 | #Scan through for zero separator 181 | for x in range(1, len(decBytes)-1): 182 | if decBytes[x]== 0: 183 | break 184 | else: 185 | return None 186 | return decBytes[x+1:] #Return everything after the separator 187 | 188 | def _rawPrivateKeyOp(self, m): 189 | raise NotImplementedError() 190 | 191 | def _rawPublicKeyOp(self, c): 192 | raise NotImplementedError() 193 | 194 | def acceptsPassword(self): 195 | """Return True if the write() method accepts a password for use 196 | in encrypting the private key. 197 | 198 | @rtype: bool 199 | """ 200 | raise NotImplementedError() 201 | 202 | def write(self, password=None): 203 | """Return a string containing the key. 204 | 205 | @rtype: str 206 | @return: A string describing the key, in whichever format (PEM) 207 | is native to the implementation. 208 | """ 209 | raise NotImplementedError() 210 | 211 | def generate(bits): 212 | """Generate a new key with the specified bit length. 213 | 214 | @rtype: L{tlslite.utils.RSAKey.RSAKey} 215 | """ 216 | raise NotImplementedError() 217 | generate = staticmethod(generate) 218 | 219 | 220 | # ************************************************************************** 221 | # Helper Functions for RSA Keys 222 | # ************************************************************************** 223 | 224 | @staticmethod 225 | def addPKCS1SHA1Prefix(bytes, withNULL=True): 226 | # There is a long history of confusion over whether the SHA1 227 | # algorithmIdentifier should be encoded with a NULL parameter or 228 | # with the parameter omitted. While the original intention was 229 | # apparently to omit it, many toolkits went the other way. TLS 1.2 230 | # specifies the NULL should be included, and this behavior is also 231 | # mandated in recent versions of PKCS #1, and is what tlslite has 232 | # always implemented. Anyways, verification code should probably 233 | # accept both. 234 | if not withNULL: 235 | prefixBytes = bytearray(\ 236 | [0x30,0x1f,0x30,0x07,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x04,0x14]) 237 | else: 238 | prefixBytes = bytearray(\ 239 | [0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14]) 240 | prefixedBytes = prefixBytes + bytes 241 | return prefixedBytes 242 | 243 | def _addPKCS1Padding(self, bytes, blockType): 244 | padLength = (numBytes(self.n) - (len(bytes)+3)) 245 | if blockType == 1: #Signature padding 246 | pad = [0xFF] * padLength 247 | elif blockType == 2: #Encryption padding 248 | pad = bytearray(0) 249 | while len(pad) < padLength: 250 | padBytes = getRandomBytes(padLength * 2) 251 | pad = [b for b in padBytes if b != 0] 252 | pad = pad[:padLength] 253 | else: 254 | raise AssertionError() 255 | 256 | padding = bytearray([0,blockType] + pad + [0]) 257 | paddedBytes = padding + bytes 258 | return paddedBytes 259 | -------------------------------------------------------------------------------- /tlslite/utils/tackwrapper.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | try: 5 | from tack.structures.Tack import Tack 6 | from tack.structures.TackExtension import TackExtension 7 | from tack.tls.TlsCertificate import TlsCertificate 8 | 9 | tackpyLoaded = True 10 | except ImportError: 11 | tackpyLoaded = False 12 | -------------------------------------------------------------------------------- /tlslite/utils/tripledes.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Abstract class for 3DES.""" 5 | 6 | class TripleDES(object): 7 | def __init__(self, key, mode, IV, implementation): 8 | if len(key) != 24: 9 | raise ValueError() 10 | if mode != 2: 11 | raise ValueError() 12 | if len(IV) != 8: 13 | raise ValueError() 14 | self.isBlockCipher = True 15 | self.block_size = 8 16 | self.implementation = implementation 17 | self.name = "3des" 18 | 19 | #CBC-Mode encryption, returns ciphertext 20 | #WARNING: *MAY* modify the input as well 21 | def encrypt(self, plaintext): 22 | assert(len(plaintext) % 8 == 0) 23 | 24 | #CBC-Mode decryption, returns plaintext 25 | #WARNING: *MAY* modify the input as well 26 | def decrypt(self, ciphertext): 27 | assert(len(ciphertext) % 8 == 0) 28 | -------------------------------------------------------------------------------- /tlslite/verifierdb.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Class for storing SRP password verifiers.""" 5 | 6 | from .utils.cryptomath import * 7 | from .utils.compat import * 8 | from tlslite import mathtls 9 | from .basedb import BaseDB 10 | 11 | class VerifierDB(BaseDB): 12 | """This class represent an in-memory or on-disk database of SRP 13 | password verifiers. 14 | 15 | A VerifierDB can be passed to a server handshake to authenticate 16 | a client based on one of the verifiers. 17 | 18 | This class is thread-safe. 19 | """ 20 | def __init__(self, filename=None): 21 | """Create a new VerifierDB instance. 22 | 23 | @type filename: str 24 | @param filename: Filename for an on-disk database, or None for 25 | an in-memory database. If the filename already exists, follow 26 | this with a call to open(). To create a new on-disk database, 27 | follow this with a call to create(). 28 | """ 29 | BaseDB.__init__(self, filename, "verifier") 30 | 31 | def _getItem(self, username, valueStr): 32 | (N, g, salt, verifier) = valueStr.split(" ") 33 | N = bytesToNumber(a2b_base64(N)) 34 | g = bytesToNumber(a2b_base64(g)) 35 | salt = a2b_base64(salt) 36 | verifier = bytesToNumber(a2b_base64(verifier)) 37 | return (N, g, salt, verifier) 38 | 39 | def __setitem__(self, username, verifierEntry): 40 | """Add a verifier entry to the database. 41 | 42 | @type username: str 43 | @param username: The username to associate the verifier with. 44 | Must be less than 256 characters in length. Must not already 45 | be in the database. 46 | 47 | @type verifierEntry: tuple 48 | @param verifierEntry: The verifier entry to add. Use 49 | L{tlslite.verifierdb.VerifierDB.makeVerifier} to create a 50 | verifier entry. 51 | """ 52 | BaseDB.__setitem__(self, username, verifierEntry) 53 | 54 | 55 | def _setItem(self, username, value): 56 | if len(username)>=256: 57 | raise ValueError("username too long") 58 | N, g, salt, verifier = value 59 | N = b2a_base64(numberToByteArray(N)) 60 | g = b2a_base64(numberToByteArray(g)) 61 | salt = b2a_base64(salt) 62 | verifier = b2a_base64(numberToByteArray(verifier)) 63 | valueStr = " ".join( (N, g, salt, verifier) ) 64 | return valueStr 65 | 66 | def _checkItem(self, value, username, param): 67 | (N, g, salt, verifier) = value 68 | x = mathtls.makeX(salt, username, param) 69 | v = powMod(g, x, N) 70 | return (verifier == v) 71 | 72 | 73 | def makeVerifier(username, password, bits): 74 | """Create a verifier entry which can be stored in a VerifierDB. 75 | 76 | @type username: str 77 | @param username: The username for this verifier. Must be less 78 | than 256 characters in length. 79 | 80 | @type password: str 81 | @param password: The password for this verifier. 82 | 83 | @type bits: int 84 | @param bits: This values specifies which SRP group parameters 85 | to use. It must be one of (1024, 1536, 2048, 3072, 4096, 6144, 86 | 8192). Larger values are more secure but slower. 2048 is a 87 | good compromise between safety and speed. 88 | 89 | @rtype: tuple 90 | @return: A tuple which may be stored in a VerifierDB. 91 | """ 92 | usernameBytes = bytearray(username, "utf-8") 93 | passwordBytes = bytearray(password, "utf-8") 94 | return mathtls.makeVerifier(usernameBytes, passwordBytes, bits) 95 | makeVerifier = staticmethod(makeVerifier) 96 | -------------------------------------------------------------------------------- /tlslite/x509.py: -------------------------------------------------------------------------------- 1 | # Authors: 2 | # Trevor Perrin 3 | # Google - parsing subject field 4 | # 5 | # See the LICENSE file for legal information regarding use of this file. 6 | 7 | """Class representing an X.509 certificate.""" 8 | 9 | from .utils.asn1parser import ASN1Parser 10 | from .utils.cryptomath import * 11 | from .utils.keyfactory import _createPublicRSAKey 12 | from .utils.pem import * 13 | 14 | 15 | class X509(object): 16 | """This class represents an X.509 certificate. 17 | 18 | @type bytes: L{bytearray} of unsigned bytes 19 | @ivar bytes: The DER-encoded ASN.1 certificate 20 | 21 | @type publicKey: L{tlslite.utils.rsakey.RSAKey} 22 | @ivar publicKey: The subject public key from the certificate. 23 | 24 | @type subject: L{bytearray} of unsigned bytes 25 | @ivar subject: The DER-encoded ASN.1 subject distinguished name. 26 | """ 27 | 28 | def __init__(self): 29 | self.bytes = bytearray(0) 30 | self.publicKey = None 31 | self.subject = None 32 | 33 | def parse(self, s): 34 | """Parse a PEM-encoded X.509 certificate. 35 | 36 | @type s: str 37 | @param s: A PEM-encoded X.509 certificate (i.e. a base64-encoded 38 | certificate wrapped with "-----BEGIN CERTIFICATE-----" and 39 | "-----END CERTIFICATE-----" tags). 40 | """ 41 | 42 | bytes = dePem(s, "CERTIFICATE") 43 | self.parseBinary(bytes) 44 | return self 45 | 46 | def parseBinary(self, bytes): 47 | """Parse a DER-encoded X.509 certificate. 48 | 49 | @type bytes: str or L{bytearray} of unsigned bytes 50 | @param bytes: A DER-encoded X.509 certificate. 51 | """ 52 | 53 | self.bytes = bytearray(bytes) 54 | p = ASN1Parser(bytes) 55 | 56 | #Get the tbsCertificate 57 | tbsCertificateP = p.getChild(0) 58 | 59 | #Is the optional version field present? 60 | #This determines which index the key is at. 61 | if tbsCertificateP.value[0]==0xA0: 62 | subjectPublicKeyInfoIndex = 6 63 | else: 64 | subjectPublicKeyInfoIndex = 5 65 | 66 | #Get the subject 67 | self.subject = tbsCertificateP.getChildBytes(\ 68 | subjectPublicKeyInfoIndex - 1) 69 | 70 | #Get the subjectPublicKeyInfo 71 | subjectPublicKeyInfoP = tbsCertificateP.getChild(\ 72 | subjectPublicKeyInfoIndex) 73 | 74 | #Get the algorithm 75 | algorithmP = subjectPublicKeyInfoP.getChild(0) 76 | rsaOID = algorithmP.value 77 | if list(rsaOID) != [6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0]: 78 | raise SyntaxError("Unrecognized AlgorithmIdentifier") 79 | 80 | #Get the subjectPublicKey 81 | subjectPublicKeyP = subjectPublicKeyInfoP.getChild(1) 82 | 83 | #Adjust for BIT STRING encapsulation 84 | if (subjectPublicKeyP.value[0] !=0): 85 | raise SyntaxError() 86 | subjectPublicKeyP = ASN1Parser(subjectPublicKeyP.value[1:]) 87 | 88 | #Get the modulus and exponent 89 | modulusP = subjectPublicKeyP.getChild(0) 90 | publicExponentP = subjectPublicKeyP.getChild(1) 91 | 92 | #Decode them into numbers 93 | n = bytesToNumber(modulusP.value) 94 | e = bytesToNumber(publicExponentP.value) 95 | 96 | #Create a public key instance 97 | self.publicKey = _createPublicRSAKey(n, e) 98 | 99 | def getFingerprint(self): 100 | """Get the hex-encoded fingerprint of this certificate. 101 | 102 | @rtype: str 103 | @return: A hex-encoded fingerprint. 104 | """ 105 | return b2a_hex(SHA1(self.bytes)) 106 | 107 | def writeBytes(self): 108 | return self.bytes 109 | 110 | 111 | -------------------------------------------------------------------------------- /tlslite/x509certchain.py: -------------------------------------------------------------------------------- 1 | # Author: Trevor Perrin 2 | # See the LICENSE file for legal information regarding use of this file. 3 | 4 | """Class representing an X.509 certificate chain.""" 5 | 6 | from .utils import cryptomath 7 | from .utils.tackwrapper import * 8 | from .utils.pem import * 9 | from .x509 import X509 10 | 11 | class X509CertChain(object): 12 | """This class represents a chain of X.509 certificates. 13 | 14 | @type x509List: list 15 | @ivar x509List: A list of L{tlslite.x509.X509} instances, 16 | starting with the end-entity certificate and with every 17 | subsequent certificate certifying the previous. 18 | """ 19 | 20 | def __init__(self, x509List=None): 21 | """Create a new X509CertChain. 22 | 23 | @type x509List: list 24 | @param x509List: A list of L{tlslite.x509.X509} instances, 25 | starting with the end-entity certificate and with every 26 | subsequent certificate certifying the previous. 27 | """ 28 | if x509List: 29 | self.x509List = x509List 30 | else: 31 | self.x509List = [] 32 | 33 | def parsePemList(self, s): 34 | """Parse a string containing a sequence of PEM certs. 35 | 36 | Raise a SyntaxError if input is malformed. 37 | """ 38 | x509List = [] 39 | bList = dePemList(s, "CERTIFICATE") 40 | for b in bList: 41 | x509 = X509() 42 | x509.parseBinary(b) 43 | x509List.append(x509) 44 | self.x509List = x509List 45 | 46 | def getNumCerts(self): 47 | """Get the number of certificates in this chain. 48 | 49 | @rtype: int 50 | """ 51 | return len(self.x509List) 52 | 53 | def getEndEntityPublicKey(self): 54 | """Get the public key from the end-entity certificate. 55 | 56 | @rtype: L{tlslite.utils.rsakey.RSAKey} 57 | """ 58 | if self.getNumCerts() == 0: 59 | raise AssertionError() 60 | return self.x509List[0].publicKey 61 | 62 | def getFingerprint(self): 63 | """Get the hex-encoded fingerprint of the end-entity certificate. 64 | 65 | @rtype: str 66 | @return: A hex-encoded fingerprint. 67 | """ 68 | if self.getNumCerts() == 0: 69 | raise AssertionError() 70 | return self.x509List[0].getFingerprint() 71 | 72 | def checkTack(self, tack): 73 | if self.x509List: 74 | tlsCert = TlsCertificate(self.x509List[0].bytes) 75 | if tlsCert.matches(tack): 76 | return True 77 | return False 78 | 79 | def getTackExt(self): 80 | """Get the TACK and/or Break Sigs from a TACK Cert in the chain.""" 81 | tackExt = None 82 | # Search list in backwards order 83 | for x509 in self.x509List[::-1]: 84 | tlsCert = TlsCertificate(x509.bytes) 85 | if tlsCert.tackExt: 86 | if tackExt: 87 | raise SyntaxError("Multiple TACK Extensions") 88 | else: 89 | tackExt = tlsCert.tackExt 90 | return tackExt 91 | 92 | -------------------------------------------------------------------------------- /unit_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trevp/tlslite/cd82fadb6bb958522b7457c5ed95890283437a4f/unit_tests/__init__.py -------------------------------------------------------------------------------- /unit_tests/test_tlslite_handshakesettings.py: -------------------------------------------------------------------------------- 1 | # Author: Hubert Kario (c) 2014 2 | # see LICENCE file for legal information regarding use of this file 3 | 4 | # compatibility with Python 2.6, for that we need unittest2 package, 5 | # which is not available on 3.3 or 3.4 6 | try: 7 | import unittest2 as unittest 8 | except ImportError: 9 | import unittest 10 | 11 | from tlslite.handshakesettings import HandshakeSettings 12 | 13 | class TestHandshakeSettings(unittest.TestCase): 14 | def test___init__(self): 15 | hs = HandshakeSettings() 16 | 17 | self.assertIsNotNone(hs) 18 | 19 | def test_validate(self): 20 | hs = HandshakeSettings() 21 | newHS = hs.validate() 22 | 23 | self.assertIsNotNone(newHS) 24 | self.assertIsNot(hs, newHS) 25 | 26 | def test_minKeySize_too_small(self): 27 | hs = HandshakeSettings() 28 | hs.minKeySize = 511 29 | 30 | with self.assertRaises(ValueError): 31 | hs.validate() 32 | 33 | def test_minKeySize_too_large(self): 34 | hs = HandshakeSettings() 35 | hs.minKeySize = 16385 36 | 37 | with self.assertRaises(ValueError): 38 | hs.validate() 39 | 40 | def test_maxKeySize_too_small(self): 41 | hs = HandshakeSettings() 42 | hs.maxKeySize = 511 43 | 44 | with self.assertRaises(ValueError): 45 | hs.validate() 46 | 47 | def test_maxKeySize_too_large(self): 48 | hs = HandshakeSettings() 49 | hs.maxKeySize = 16385 50 | 51 | with self.assertRaises(ValueError): 52 | hs.validate() 53 | 54 | def test_maxKeySize_smaller_than_minKeySize(self): 55 | hs = HandshakeSettings() 56 | hs.maxKeySize = 1024 57 | hs.minKeySize = 2048 58 | 59 | with self.assertRaises(ValueError): 60 | hs.validate() 61 | 62 | def test_cipherNames_with_unknown_name(self): 63 | hs = HandshakeSettings() 64 | hs.cipherNames = ["aes256"] 65 | 66 | newHs = hs.validate() 67 | 68 | self.assertEqual(["aes256"], newHs.cipherNames) 69 | 70 | def test_cipherNames_with_unknown_name(self): 71 | hs = HandshakeSettings() 72 | hs.cipherNames = ["aes256gcm", "aes256"] 73 | 74 | with self.assertRaises(ValueError): 75 | hs.validate() 76 | 77 | def test_cipherNames_empty(self): 78 | hs = HandshakeSettings() 79 | hs.cipherNames = [] 80 | 81 | with self.assertRaises(ValueError): 82 | hs.validate() 83 | 84 | def test_certificateTypes_empty(self): 85 | hs = HandshakeSettings() 86 | hs.certificateTypes = [] 87 | 88 | with self.assertRaises(ValueError): 89 | hs.validate() 90 | 91 | def test_certificateTypes_with_unknown_type(self): 92 | hs = HandshakeSettings() 93 | hs.certificateTypes = [0, 42] 94 | 95 | with self.assertRaises(ValueError): 96 | hs.validate() 97 | 98 | def test_cipherImplementations_empty(self): 99 | hs = HandshakeSettings() 100 | hs.cipherImplementations = [] 101 | 102 | with self.assertRaises(ValueError): 103 | hs.validate() 104 | 105 | def test_cipherImplementations_with_unknown_implementations(self): 106 | hs = HandshakeSettings() 107 | hs.cipherImplementations = ["openssl", "NSS"] 108 | 109 | with self.assertRaises(ValueError): 110 | hs.validate() 111 | 112 | def test_minVersion_higher_than_maxVersion(self): 113 | hs = HandshakeSettings() 114 | hs.minVersion = (3, 3) 115 | hs.maxVersion = (3, 0) 116 | 117 | with self.assertRaises(ValueError): 118 | hs.validate() 119 | 120 | def test_minVersion_with_unknown_version(self): 121 | hs = HandshakeSettings() 122 | hs.minVersion = (2, 0) 123 | 124 | with self.assertRaises(ValueError): 125 | hs.validate() 126 | 127 | def test_maxVersion_with_unknown_version(self): 128 | hs = HandshakeSettings() 129 | hs.maxVersion = (3, 4) 130 | 131 | with self.assertRaises(ValueError): 132 | hs.validate() 133 | 134 | def test_maxVersion_without_TLSv1_2(self): 135 | hs = HandshakeSettings() 136 | hs.maxVersion = (3, 2) 137 | 138 | self.assertTrue('sha256' in hs.macNames) 139 | 140 | new_hs = hs.validate() 141 | 142 | self.assertFalse("sha256" in new_hs.macNames) 143 | 144 | def test_getCertificateTypes(self): 145 | hs = HandshakeSettings() 146 | 147 | self.assertEqual([0], hs.getCertificateTypes()) 148 | 149 | def test_getCertificateTypes_with_unsupported_type(self): 150 | hs = HandshakeSettings() 151 | hs.certificateTypes = ["x509", "openpgp"] 152 | 153 | with self.assertRaises(AssertionError): 154 | hs.getCertificateTypes() 155 | -------------------------------------------------------------------------------- /unit_tests/test_tlslite_sessioncache.py: -------------------------------------------------------------------------------- 1 | # compatibility with Python 2.6, for that we need unittest2 package, 2 | # which is not available on 3.3 or 3.4 3 | try: 4 | import unittest2 as unittest 5 | except ImportError: 6 | import unittest 7 | 8 | from tlslite.sessioncache import SessionCache 9 | 10 | class TestGetAttributeAfterPurge(unittest.TestCase): 11 | """ 12 | This tests the following scenario 13 | 14 | Add an entry to the session cache 15 | wait until the cache should have expired 16 | fetch the entry for the session cache. 17 | 18 | """ 19 | 20 | def setUp(self): 21 | # set maxAge to 0 to have an immediate expire 22 | self.session_cache = SessionCache(maxAge=0) 23 | 24 | def test_fetch_after_expire(self): 25 | key = bytearray(b'hello world') 26 | self.session_cache[key] = "42" 27 | with self.assertRaises(KeyError): 28 | self.session_cache[key] 29 | 30 | class TestFillLinkedList(unittest.TestCase): 31 | """ check what happens if the linked list gets full 32 | """ 33 | 34 | def setUp(self): 35 | self.session_cache = SessionCache(maxEntries = 10) 36 | 37 | def test_fill_linked_list(self): 38 | """this test should not throw an exception""" 39 | for i in range(20): 40 | key = bytearray(b'prefill-') + bytearray(str(i), "ascii") 41 | self.session_cache[key] = "forty-two" 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /unit_tests/test_tlslite_utils_codec.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Hubert Kario 2 | # 3 | # See the LICENSE file for legal information regarding use of this file. 4 | 5 | # compatibility with Python 2.6, for that we need unittest2 package, 6 | # which is not available on 3.3 or 3.4 7 | try: 8 | import unittest2 as unittest 9 | except ImportError: 10 | import unittest 11 | from tlslite.utils.codec import Parser, Writer 12 | 13 | class TestParser(unittest.TestCase): 14 | def test___init__(self): 15 | p = Parser(bytearray(0)) 16 | 17 | self.assertEqual(bytearray(0), p.bytes) 18 | self.assertEqual(0, p.index) 19 | 20 | def test_get(self): 21 | p = Parser(bytearray(b'\x02\x01\x00')) 22 | 23 | self.assertEqual(2, p.get(1)) 24 | self.assertEqual(256, p.get(2)) 25 | self.assertEqual(3, p.index) 26 | 27 | def test_get_with_too_few_bytes_left(self): 28 | p = Parser(bytearray(b'\x02\x01')) 29 | 30 | p.get(1) 31 | 32 | with self.assertRaises(SyntaxError): 33 | p.get(2) 34 | 35 | def test_getFixBytes(self): 36 | p = Parser(bytearray(b'\x02\x01\x00')) 37 | 38 | self.assertEqual(bytearray(b'\x02\x01'), p.getFixBytes(2)) 39 | self.assertEqual(2, p.index) 40 | 41 | def test_getVarBytes(self): 42 | p = Parser(bytearray(b'\x02\x01\x00')) 43 | 44 | self.assertEqual(bytearray(b'\x01\x00'), p.getVarBytes(1)) 45 | self.assertEqual(3, p.index) 46 | 47 | def test_getFixList(self): 48 | p = Parser(bytearray( 49 | b'\x00\x01' + 50 | b'\x00\x02' + 51 | b'\x00\x03')) 52 | 53 | self.assertEqual([1,2,3], p.getFixList(2, 3)) 54 | self.assertEqual(6, p.index) 55 | 56 | def test_getVarList(self): 57 | p = Parser(bytearray( 58 | b'\x06' + 59 | b'\x00\x01\x00' + 60 | b'\x00\x00\xff')) 61 | 62 | self.assertEqual([256, 255], p.getVarList(3, 1)) 63 | self.assertEqual(7, p.index) 64 | 65 | def test_getVarList_with_incorrect_length(self): 66 | p = Parser(bytearray( 67 | b'\x07' + 68 | b'\x00\x01\x00' 69 | b'\x00\x00\xff' 70 | b'\x00')) 71 | 72 | with self.assertRaises(SyntaxError): 73 | p.getVarList(3,1) 74 | 75 | def test_lengthCheck(self): 76 | p = Parser(bytearray( 77 | b'\x06' + 78 | b'\x00\x00' + 79 | b'\x03' + 80 | b'\x01\x02\x03' 81 | )) 82 | 83 | p.startLengthCheck(1) 84 | 85 | self.assertEqual([0,0], p.getFixList(1,2)) 86 | self.assertEqual([1,2,3], p.getVarList(1,1)) 87 | # should not raise exception 88 | p.stopLengthCheck() 89 | 90 | def test_lengthCheck_with_incorrect_parsing(self): 91 | p = Parser(bytearray( 92 | b'\x06' + 93 | b'\x00\x00' + 94 | b'\x02' + 95 | b'\x01\x02' + 96 | b'\x03' 97 | )) 98 | 99 | p.startLengthCheck(1) 100 | self.assertEqual([0,0], p.getFixList(1,2)) 101 | self.assertEqual([1,2], p.getVarList(1,1)) 102 | with self.assertRaises(SyntaxError): 103 | p.stopLengthCheck() 104 | 105 | def test_setLengthCheck(self): 106 | p = Parser(bytearray( 107 | b'\x06' + 108 | b'\x00\x01' + 109 | b'\x00\x02' + 110 | b'\x00\x03' 111 | )) 112 | 113 | p.setLengthCheck(7) 114 | self.assertEqual([1,2,3], p.getVarList(2,1)) 115 | p.stopLengthCheck() 116 | 117 | def test_setLengthCheck_with_bad_data(self): 118 | p = Parser(bytearray( 119 | b'\x04' + 120 | b'\x00\x01' + 121 | b'\x00\x02' 122 | )) 123 | 124 | p.setLengthCheck(7) 125 | self.assertEqual([1,2], p.getVarList(2,1)) 126 | 127 | with self.assertRaises(SyntaxError): 128 | p.stopLengthCheck() 129 | 130 | def test_atLengthCheck(self): 131 | p = Parser(bytearray( 132 | b'\x00\x06' + 133 | b'\x05' + 134 | b'\x01\xff' + 135 | b'\x07' + 136 | b'\x01\xf0' 137 | )) 138 | 139 | p.startLengthCheck(2) 140 | while not p.atLengthCheck(): 141 | p.get(1) 142 | p.getVarBytes(1) 143 | p.stopLengthCheck() 144 | 145 | def test_getVarBytes_with_incorrect_data(self): 146 | p = Parser(bytearray( 147 | b'\x00\x04' + 148 | b'\x00\x00\x00' 149 | )) 150 | 151 | with self.assertRaises(SyntaxError): 152 | p.getVarBytes(2) 153 | 154 | def test_getFixBytes_with_incorrect_data(self): 155 | p = Parser(bytearray( 156 | b'\x00\x04' 157 | )) 158 | 159 | with self.assertRaises(SyntaxError): 160 | p.getFixBytes(10) 161 | 162 | def test_getRemainingLength(self): 163 | p = Parser(bytearray( 164 | b'\x00\x01\x05' 165 | )) 166 | 167 | self.assertEqual(1, p.get(2)) 168 | self.assertEqual(1, p.getRemainingLength()) 169 | self.assertEqual(5, p.get(1)) 170 | self.assertEqual(0, p.getRemainingLength()) 171 | 172 | class TestWriter(unittest.TestCase): 173 | def test___init__(self): 174 | w = Writer() 175 | 176 | self.assertEqual(bytearray(0), w.bytes) 177 | 178 | def test_add(self): 179 | w = Writer() 180 | w.add(255, 1) 181 | 182 | self.assertEqual(bytearray(b'\xff'), w.bytes) 183 | 184 | def test_add_with_multibyte_field(self): 185 | w = Writer() 186 | w.add(32, 2) 187 | 188 | self.assertEqual(bytearray(b'\x00\x20'), w.bytes) 189 | 190 | def test_add_with_multibyte_data(self): 191 | w = Writer() 192 | w.add(512, 2) 193 | 194 | self.assertEqual(bytearray(b'\x02\x00'), w.bytes) 195 | 196 | def test_add_with_overflowing_data(self): 197 | w = Writer() 198 | 199 | with self.assertRaises(ValueError): 200 | w.add(256, 1) 201 | 202 | def test_addFixSeq(self): 203 | w = Writer() 204 | w.addFixSeq([16,17,18], 2) 205 | 206 | self.assertEqual(bytearray(b'\x00\x10\x00\x11\x00\x12'), w.bytes) 207 | 208 | def test_addVarSeq(self): 209 | w = Writer() 210 | w.addVarSeq([16, 17, 18], 2, 2) 211 | 212 | self.assertEqual(bytearray( 213 | b'\x00\x06' + 214 | b'\x00\x10' + 215 | b'\x00\x11' + 216 | b'\x00\x12'), w.bytes) 217 | 218 | def test_bytes(self): 219 | w = Writer() 220 | w.bytes += bytearray(b'\xbe\xef') 221 | w.add(15, 1) 222 | 223 | self.assertEqual(bytearray(b'\xbe\xef\x0f'), w.bytes) 224 | 225 | if __name__ == '__main__': 226 | unittest.main() 227 | -------------------------------------------------------------------------------- /unit_tests/test_tlslite_utils_cryptomath.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014, Hubert Kario 2 | # 3 | # See the LICENSE file for legal information regarding use of this file. 4 | 5 | # compatibility with Python 2.6, for that we need unittest2 package, 6 | # which is not available on 3.3 or 3.4 7 | try: 8 | import unittest2 as unittest 9 | except ImportError: 10 | import unittest 11 | 12 | from tlslite.utils.cryptomath import isPrime 13 | 14 | class TestIsPrime(unittest.TestCase): 15 | def test_with_small_primes(self): 16 | self.assertTrue(isPrime(3)) 17 | self.assertTrue(isPrime(5)) 18 | self.assertTrue(isPrime(7)) 19 | self.assertTrue(isPrime(11)) 20 | 21 | def test_with_small_composites(self): 22 | self.assertFalse(isPrime(4)) 23 | self.assertFalse(isPrime(6)) 24 | self.assertFalse(isPrime(9)) 25 | self.assertFalse(isPrime(10)) 26 | 27 | def test_with_hard_primes_to_test(self): 28 | 29 | # XXX Rabin-Miller fails to properly detect following composites 30 | with self.assertRaises(AssertionError): 31 | for i in range(100): 32 | # OEIS A014233 33 | self.assertFalse(isPrime(2047)) 34 | self.assertFalse(isPrime(1373653)) 35 | self.assertFalse(isPrime(25326001)) 36 | self.assertFalse(isPrime(3215031751)) 37 | self.assertFalse(isPrime(2152302898747)) 38 | self.assertFalse(isPrime(3474749660383)) 39 | self.assertFalse(isPrime(341550071728321)) 40 | self.assertFalse(isPrime(341550071728321)) 41 | self.assertFalse(isPrime(3825123056546413051)) 42 | self.assertFalse(isPrime(3825123056546413051)) 43 | self.assertFalse(isPrime(3825123056546413051)) 44 | 45 | def test_with_big_primes(self): 46 | # NextPrime[2^256] 47 | self.assertTrue(isPrime(115792089237316195423570985008687907853269984665640564039457584007913129640233)) 48 | # NextPrime[2^1024] 49 | self.assertTrue(isPrime(179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137859)) 50 | 51 | def test_with_big_composites(self): 52 | # NextPrime[2^256]-2 (factors: 71, 1559, 4801, 7703, 28286...8993) 53 | self.assertFalse(isPrime(115792089237316195423570985008687907853269984665640564039457584007913129640233-2)) 54 | # NextPrime[2^256]+2 (factors: 3^2, 5, 7, 11, 1753, 19063..7643) 55 | self.assertFalse(isPrime(115792089237316195423570985008687907853269984665640564039457584007913129640233+2)) 56 | # NextPrime[2^1024]-2 57 | self.assertFalse(isPrime(179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137859-2)) 58 | # NextPrime[2^1024]+2 59 | self.assertFalse(isPrime(179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137859+2)) 60 | # NextPrime[NextPrime[2^512]]*NextPrime[2^512] 61 | self.assertFalse(isPrime(179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639477074095512480796227391561801824887394139579933613278628104952355769470429079061808809522886423955917442317693387325171135071792698344550223571732405562649211)) 62 | 63 | -------------------------------------------------------------------------------- /unit_tests/test_tlslite_utils_keyfactory.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2015, Hubert Kario 2 | # 3 | # See the LICENSE file for legal information regarding use of this file. 4 | 5 | # compatibility with Python 2.6, for that we need unittest2 package, 6 | # which is not available on 3.3 or 3.4 7 | try: 8 | import unittest2 as unittest 9 | except ImportError: 10 | import unittest 11 | 12 | from tlslite.utils.keyfactory import parsePEMKey 13 | from tlslite.utils.rsakey import RSAKey 14 | from tlslite.utils import cryptomath 15 | 16 | class TestParsePEMKey(unittest.TestCase): 17 | 18 | # generated with: 19 | # openssl req -x509 -newkey rsa:1024 -keyout localhost.key \ 20 | # -out localhost.crt -subj /CN=localhost -nodes -batch -sha256 21 | privKey_str = str( 22 | "-----BEGIN PRIVATE KEY-----"\ 23 | "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANEJBHmpEslfyzLU"\ 24 | "3gEXUbV+aXW81blLqjiHc95YO2DskSf6Mi0z81l6Ssa//7eBT0L2LEiYlTpT5PPe"\ 25 | "RTburDRf7iUMkBnxVmCpBOn8xYn0OrPZLLLJBZS9Q1SP3Q/2Z+7IM7mtj9UsiyR0"\ 26 | "E07NTLTG9e9P319hAT5A8/tpGCjdAgMBAAECgYBVItsTwezI358fANu6jgjVZrsF"\ 27 | "HPffFBYsF971O/JTM4abRaeSCYqfctNpx2EbGCt0FldK6fo9W1XwjSKbkPHJVo12"\ 28 | "Lfeyn48iRlTfzp/VVSpydieaCyexRAQElC59RmaA0z5t9H5F+WLgx7DyVDSyitn5"\ 29 | "3b/l+wzSDzRCGLkzcQJBAO9d4LKtzLS78dkU2MiWjJdoAi9q9notzqB/OcJJ8dzl"\ 30 | "jCmU5jt0hanwVFElzJeQDfvSXl0nQRePkbG51X1BDjcCQQDfj5HGNGTgNPtmj61s"\ 31 | "z8WSiLuOHX/SEWRTk0MfB4l4f+Ymx6Ie2wco5w8a0QYEGpPYo09ZXPgWPX0uJSaa"\ 32 | "NZeLAkEAgGzj07n/7LAx0ACpVuW/RLSfB4Xh/Cd7hwz7lkxKIfRewSiMZjXcSRMS"\ 33 | "if83x9GYTxXNXzliaRu0VaCY9Hzk/QJBAKx6VZs3XQRlm/f6rXAftGxjNWBlffIS"\ 34 | "HPclzEkqRXNEKcqNhpSLozB5Y3vq+9s6rgobpOJrCbQO6H8rhma/JhUCQGmkTlFF"\ 35 | "CpeK/UoX1sCtwAke8ubS+cc+l/XIhCvltbqeMG4vipzGVoolUZFdPvIW2PZ+PSC/"\ 36 | "f3XiNjay5aqnxck="\ 37 | "-----END PRIVATE KEY-----") 38 | cert_str = str( 39 | "-----BEGIN CERTIFICATE-----"\ 40 | "MIIB9jCCAV+gAwIBAgIJAMyn9DpsTG55MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV"\ 41 | "BAMMCWxvY2FsaG9zdDAeFw0xNTAxMjExNDQzMDFaFw0xNTAyMjAxNDQzMDFaMBQx"\ 42 | "EjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA"\ 43 | "0QkEeakSyV/LMtTeARdRtX5pdbzVuUuqOIdz3lg7YOyRJ/oyLTPzWXpKxr//t4FP"\ 44 | "QvYsSJiVOlPk895FNu6sNF/uJQyQGfFWYKkE6fzFifQ6s9kssskFlL1DVI/dD/Zn"\ 45 | "7sgzua2P1SyLJHQTTs1MtMb170/fX2EBPkDz+2kYKN0CAwEAAaNQME4wHQYDVR0O"\ 46 | "BBYEFJtvXbRmxRFXYVMOPH/29pXCpGmLMB8GA1UdIwQYMBaAFJtvXbRmxRFXYVMO"\ 47 | "PH/29pXCpGmLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEAkOgC7LP/"\ 48 | "Rd6uJXY28HlD2K+/hMh1C3SRT855ggiCMiwstTHACGgNM+AZNqt6k8nSfXc6k1gw"\ 49 | "5a7SGjzkWzMaZC3ChBeCzt/vIAGlMyXeqTRhjTCdc/ygRv3NPrhUKKsxUYyXRk5v"\ 50 | "g/g6MwxzXfQP3IyFu3a9Jia/P89Z1rQCNRY="\ 51 | "-----END CERTIFICATE-----"\ 52 | ) 53 | privKey_str_newLines = str( 54 | "-----BEGIN PRIVATE KEY-----\n"\ 55 | "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANEJBHmpEslfyzLU\n"\ 56 | "3gEXUbV+aXW81blLqjiHc95YO2DskSf6Mi0z81l6Ssa//7eBT0L2LEiYlTpT5PPe\n"\ 57 | "RTburDRf7iUMkBnxVmCpBOn8xYn0OrPZLLLJBZS9Q1SP3Q/2Z+7IM7mtj9UsiyR0\n"\ 58 | "E07NTLTG9e9P319hAT5A8/tpGCjdAgMBAAECgYBVItsTwezI358fANu6jgjVZrsF\n"\ 59 | "HPffFBYsF971O/JTM4abRaeSCYqfctNpx2EbGCt0FldK6fo9W1XwjSKbkPHJVo12\n"\ 60 | "Lfeyn48iRlTfzp/VVSpydieaCyexRAQElC59RmaA0z5t9H5F+WLgx7DyVDSyitn5\n"\ 61 | "3b/l+wzSDzRCGLkzcQJBAO9d4LKtzLS78dkU2MiWjJdoAi9q9notzqB/OcJJ8dzl\n"\ 62 | "jCmU5jt0hanwVFElzJeQDfvSXl0nQRePkbG51X1BDjcCQQDfj5HGNGTgNPtmj61s\n"\ 63 | "z8WSiLuOHX/SEWRTk0MfB4l4f+Ymx6Ie2wco5w8a0QYEGpPYo09ZXPgWPX0uJSaa\n"\ 64 | "NZeLAkEAgGzj07n/7LAx0ACpVuW/RLSfB4Xh/Cd7hwz7lkxKIfRewSiMZjXcSRMS\n"\ 65 | "if83x9GYTxXNXzliaRu0VaCY9Hzk/QJBAKx6VZs3XQRlm/f6rXAftGxjNWBlffIS\n"\ 66 | "HPclzEkqRXNEKcqNhpSLozB5Y3vq+9s6rgobpOJrCbQO6H8rhma/JhUCQGmkTlFF\n"\ 67 | "CpeK/UoX1sCtwAke8ubS+cc+l/XIhCvltbqeMG4vipzGVoolUZFdPvIW2PZ+PSC/\n"\ 68 | "f3XiNjay5aqnxck=\n"\ 69 | "-----END PRIVATE KEY-----\n") 70 | cert_str_newLines = str( 71 | "-----BEGIN CERTIFICATE-----\n"\ 72 | "MIIB9jCCAV+gAwIBAgIJAMyn9DpsTG55MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV\n"\ 73 | "BAMMCWxvY2FsaG9zdDAeFw0xNTAxMjExNDQzMDFaFw0xNTAyMjAxNDQzMDFaMBQx\n"\ 74 | "EjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n"\ 75 | "0QkEeakSyV/LMtTeARdRtX5pdbzVuUuqOIdz3lg7YOyRJ/oyLTPzWXpKxr//t4FP\n"\ 76 | "QvYsSJiVOlPk895FNu6sNF/uJQyQGfFWYKkE6fzFifQ6s9kssskFlL1DVI/dD/Zn\n"\ 77 | "7sgzua2P1SyLJHQTTs1MtMb170/fX2EBPkDz+2kYKN0CAwEAAaNQME4wHQYDVR0O\n"\ 78 | "BBYEFJtvXbRmxRFXYVMOPH/29pXCpGmLMB8GA1UdIwQYMBaAFJtvXbRmxRFXYVMO\n"\ 79 | "PH/29pXCpGmLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEAkOgC7LP/\n"\ 80 | "Rd6uJXY28HlD2K+/hMh1C3SRT855ggiCMiwstTHACGgNM+AZNqt6k8nSfXc6k1gw\n"\ 81 | "5a7SGjzkWzMaZC3ChBeCzt/vIAGlMyXeqTRhjTCdc/ygRv3NPrhUKKsxUYyXRk5v\n"\ 82 | "g/g6MwxzXfQP3IyFu3a9Jia/P89Z1rQCNRY=\n"\ 83 | "-----END CERTIFICATE-----\n"\ 84 | ) 85 | 86 | # generated with: 87 | # openssl genrsa -out privkey.pem 1024 88 | privRSAKey_str = str( 89 | "-----BEGIN RSA PRIVATE KEY-----"\ 90 | "MIICXAIBAAKBgQCnBW08FYymHDwA+Vug5QWH2g0nX2EnTnzdyvaZ/mE1pCTxV+Fp"\ 91 | "j0glrRIoPJPP+rZTcl/cqm7FSD+n2QDWHrg4h8xFPC7uPyfrbd/u6hTO3edu0los"\ 92 | "tKkq93ZiM/kmfHIS57/nOiG9ETySx4TP4ca6dhNoIAU5uMQDHjhgSXSU4wIDAQAB"\ 93 | "AoGAOB2PpOdMmSbVVjJxga5Q3GL7lmXqW214cIBXuEeKW55ptxiiqHe2csoiVph7"\ 94 | "xR3kEkdUQ+yTSP9MO9Wh/U7W78RTKM21tRn2uwzVD4p0whVK/WCa0zsSu41VQ23l"\ 95 | "wxN3Byrxw6jTTKD3gSLJc/4kGaduXgc/1IHCtmVaD9L2XJkCQQDVjqaDuQhPqzGI"\ 96 | "kHZ77PARFLf3q+nVIFSIf1m/wxLQEj1HZ9PuyHNm0USQYswwDnh9g7F25YylWex+"\ 97 | "yiefS0/fAkEAyDcekKtYudtgOhyN7tgSlUiHEyLCRo5IeazKQ0wNCDWfok9HYpEo"\ 98 | "mOuE+NIQEcCJu+sRXK6rykJQGkHgYsALfQJAN5aJK3Jngm1aWGTaIonbN2cAN/zM"\ 99 | "wghHWLxlfS/m3rhQsRyKovYUa+f/A+JjqgKqRGmaMQuxX30XvS0bwTAWWwJAQl3j"\ 100 | "B9mEg7cwYpLsiWueXVW5UKKI+5JWe97G/R/MghgkXk0hQI8VgfswDLq1EO1duqjl"\ 101 | "DG/qChWJL+r+Uj2OkQJBAK22WDZnIa52dm6G2dC+pM7TC10p7pwOS+G4YsA92Jd2"\ 102 | "rBjtgPGNR6tCjWMh0+2AUF5lTbXAPqECeV6MIvJXGpg="\ 103 | "-----END RSA PRIVATE KEY-----"\ 104 | ) 105 | privRSAKey_str_newLines = str( 106 | "-----BEGIN RSA PRIVATE KEY-----\n"\ 107 | "MIICXAIBAAKBgQCnBW08FYymHDwA+Vug5QWH2g0nX2EnTnzdyvaZ/mE1pCTxV+Fp\n"\ 108 | "j0glrRIoPJPP+rZTcl/cqm7FSD+n2QDWHrg4h8xFPC7uPyfrbd/u6hTO3edu0los\n"\ 109 | "tKkq93ZiM/kmfHIS57/nOiG9ETySx4TP4ca6dhNoIAU5uMQDHjhgSXSU4wIDAQAB\n"\ 110 | "AoGAOB2PpOdMmSbVVjJxga5Q3GL7lmXqW214cIBXuEeKW55ptxiiqHe2csoiVph7\n"\ 111 | "xR3kEkdUQ+yTSP9MO9Wh/U7W78RTKM21tRn2uwzVD4p0whVK/WCa0zsSu41VQ23l\n"\ 112 | "wxN3Byrxw6jTTKD3gSLJc/4kGaduXgc/1IHCtmVaD9L2XJkCQQDVjqaDuQhPqzGI\n"\ 113 | "kHZ77PARFLf3q+nVIFSIf1m/wxLQEj1HZ9PuyHNm0USQYswwDnh9g7F25YylWex+\n"\ 114 | "yiefS0/fAkEAyDcekKtYudtgOhyN7tgSlUiHEyLCRo5IeazKQ0wNCDWfok9HYpEo\n"\ 115 | "mOuE+NIQEcCJu+sRXK6rykJQGkHgYsALfQJAN5aJK3Jngm1aWGTaIonbN2cAN/zM\n"\ 116 | "wghHWLxlfS/m3rhQsRyKovYUa+f/A+JjqgKqRGmaMQuxX30XvS0bwTAWWwJAQl3j\n"\ 117 | "B9mEg7cwYpLsiWueXVW5UKKI+5JWe97G/R/MghgkXk0hQI8VgfswDLq1EO1duqjl\n"\ 118 | "DG/qChWJL+r+Uj2OkQJBAK22WDZnIa52dm6G2dC+pM7TC10p7pwOS+G4YsA92Jd2\n"\ 119 | "rBjtgPGNR6tCjWMh0+2AUF5lTbXAPqECeV6MIvJXGpg=\n"\ 120 | "-----END RSA PRIVATE KEY-----\n"\ 121 | ) 122 | 123 | @unittest.skipIf(cryptomath.m2cryptoLoaded, "requires no M2Crypto") 124 | def test_with_missing_m2crypto(self): 125 | with self.assertRaises(ValueError): 126 | key = parsePEMKey(self.privKey_str, 127 | private=True, 128 | implementations=["openssl"]) 129 | 130 | @unittest.skipUnless(cryptomath.m2cryptoLoaded, "requires M2Crypto") 131 | def test_key_parse_using_openssl(self): 132 | 133 | # XXX doesn't handle files without newlines 134 | with self.assertRaises(SyntaxError): 135 | key = parsePEMKey(self.privKey_str, 136 | private=True, 137 | implementations=["openssl"]) 138 | 139 | #self.assertIsInstance(key, RSAKey) 140 | #self.assertEqual(1024, len(key)) 141 | #self.assertTrue(key.hasPrivateKey()) 142 | 143 | @unittest.skipUnless(cryptomath.m2cryptoLoaded, "requires M2Crypto") 144 | def test_key_parse_with_new_lines_using_openssl(self): 145 | 146 | key = parsePEMKey(self.privKey_str_newLines, 147 | private=True, 148 | implementations=["openssl"]) 149 | 150 | self.assertIsInstance(key, RSAKey) 151 | self.assertEqual(1024, len(key)) 152 | self.assertTrue(key.hasPrivateKey()) 153 | 154 | @unittest.skipUnless(cryptomath.m2cryptoLoaded, "requires M2Crypto") 155 | def test_rsa_key_parse_using_openssl(self): 156 | # XXX doesn't handle files without newlines 157 | with self.assertRaises(SyntaxError): 158 | key = parsePEMKey(self.privRSAKey_str, 159 | private=True, 160 | implementations=["openssl"]) 161 | 162 | #self.assertIsInstance(key, RSAKey) 163 | #self.assertEqual(1024, len(key)) 164 | #self.assertTrue(key.hasPrivateKey()) 165 | 166 | @unittest.skipUnless(cryptomath.m2cryptoLoaded, "requires M2Crypto") 167 | def test_rsa_key_parse_with_new_lines_using_openssl(self): 168 | key = parsePEMKey(self.privRSAKey_str_newLines, 169 | private=True, 170 | implementations=["openssl"]) 171 | 172 | self.assertIsInstance(key, RSAKey) 173 | self.assertEqual(1024, len(key)) 174 | self.assertTrue(key.hasPrivateKey()) 175 | 176 | def test_key_parse_using_python(self): 177 | 178 | key = parsePEMKey(self.privKey_str, 179 | private=True, 180 | implementations=["python"]) 181 | 182 | self.assertIsInstance(key, RSAKey) 183 | self.assertEqual(1024, len(key)) 184 | self.assertTrue(key.hasPrivateKey()) 185 | 186 | def test_key_parse_with_new_lines_using_python(self): 187 | 188 | key = parsePEMKey(self.privKey_str_newLines, 189 | private=True, 190 | implementations=["python"]) 191 | 192 | self.assertIsInstance(key, RSAKey) 193 | self.assertEqual(1024, len(key)) 194 | self.assertTrue(key.hasPrivateKey()) 195 | 196 | def test_rsa_key_parse_using_python(self): 197 | key = parsePEMKey(self.privRSAKey_str, 198 | private=True, 199 | implementations=["python"]) 200 | 201 | self.assertIsInstance(key, RSAKey) 202 | self.assertEqual(1024, len(key)) 203 | self.assertTrue(key.hasPrivateKey()) 204 | 205 | def test_rsa_key_parse_with_new_lines_using_python(self): 206 | key = parsePEMKey(self.privRSAKey_str_newLines, 207 | private=True, 208 | implementations=["python"]) 209 | 210 | self.assertIsInstance(key, RSAKey) 211 | self.assertEqual(1024, len(key)) 212 | self.assertTrue(key.hasPrivateKey()) 213 | --------------------------------------------------------------------------------