├── oscrypto ├── _mac │ ├── __init__.py │ ├── _common_crypto.py │ ├── _common_crypto_ctypes.py │ ├── _common_crypto_cffi.py │ └── _security.py ├── _win │ ├── __init__.py │ ├── _kernel32.py │ ├── _decode.py │ ├── _kernel32_cffi.py │ ├── _kernel32_ctypes.py │ ├── _crypt32.py │ ├── _secur32_cffi.py │ └── _secur32.py ├── _linux_bsd │ ├── __init__.py │ └── trust_list.py ├── _openssl │ ├── __init__.py │ ├── _libssl.py │ ├── _libssl_cffi.py │ └── _libcrypto.py ├── version.py ├── tls.py ├── keys.py ├── _int.py ├── _types.py ├── _rand.py ├── _errors.py ├── util.py ├── symmetric.py ├── _asn1.py ├── errors.py └── _pkcs5.py ├── requires ├── api_docs ├── release ├── coverage ├── ci └── lint ├── tests ├── fixtures │ ├── message.txt │ ├── dsa_signature │ ├── message.sha1 │ ├── message.sha256 │ ├── rsa_signature │ ├── ecdsa_signature │ ├── keys │ │ ├── test-der.crt │ │ ├── test-der.key │ │ ├── test-dsa.p12 │ │ ├── test-rc2.p12 │ │ ├── test-third.p12 │ │ ├── test-aes128.p12 │ │ ├── test-aes256.p12 │ │ ├── test-dsa-der.crt │ │ ├── test-dsa-der.key │ │ ├── test-ec-der.crt │ │ ├── test-ec-der.key │ │ ├── test-inter-der.crt │ │ ├── test-pkcs8-der.key │ │ ├── test-third-der.crt │ │ ├── test-third-der.key │ │ ├── test-tripledes.p12 │ │ ├── test-dsa-1024-der.crt │ │ ├── test-dsa-1024-der.key │ │ ├── test-dsa-2048-der.crt │ │ ├── test-dsa-2048-der.key │ │ ├── test-ec-named-der.crt │ │ ├── test-ec-named-der.key │ │ ├── test-pkcs8-ec-der.key │ │ ├── test-pkcs8-blank-der.key │ │ ├── test-pkcs8-dsa-der.key │ │ ├── test-public-dsa-der.key │ │ ├── test-public-ec-der.key │ │ ├── test-public-rsa-der.key │ │ ├── test-tripledes-blank.p12 │ │ ├── test-dsa-2048-sha2-der.crt │ │ ├── test-dsa-2048-sha2-der.key │ │ ├── test-pkcs8-aes128-der.key │ │ ├── test-pkcs8-ec-named-der.key │ │ ├── test-public-dsa-1024-der.key │ │ ├── test-public-dsa-2048-der.key │ │ ├── test-public-ec-named-der.key │ │ ├── test-public-dsa-2048-sha2-der.key │ │ ├── test-public-rsapublickey-der.key │ │ ├── test-public-ec-named.key │ │ ├── test-ec-named.key │ │ ├── test-pkcs8-ec-named.key │ │ ├── test-public-rsapublickey.key │ │ ├── test-public-rsa.key │ │ ├── test-dsa-1024.param │ │ ├── test-public-ec.key │ │ ├── test-ec.key │ │ ├── test-pkcs8-ec.key │ │ ├── test-ec-aes128.key │ │ ├── test-public-dsa-1024.key │ │ ├── test-dsa-1024.key │ │ ├── test-dsa-2048.param │ │ ├── test-dsa-2048-sha2.param │ │ ├── test-ec-named.crt │ │ ├── test-dsa-512.crt │ │ ├── test-inter.csr │ │ ├── test-third.csr │ │ ├── test-dsa.param │ │ ├── test-public-dsa-2048.key │ │ ├── test-dsa-2048.key │ │ ├── test-public-dsa-2048-sha2.key │ │ ├── test-dsa-2048-sha2.key │ │ ├── test-pkcs8-dsa.key │ │ ├── test-ec.crt │ │ ├── test-third.crt │ │ ├── test-inter.crt │ │ ├── test-pss.crt │ │ ├── test-dsa-1024.crt │ │ ├── test.key │ │ ├── test-inter.key │ │ ├── test-third.key │ │ ├── test-pss.key │ │ ├── test-pkcs8.key │ │ ├── test.crt │ │ ├── test-public-dsa.key │ │ ├── test-dsa.key │ │ ├── test-tripledes.key │ │ ├── test-aes128.key │ │ ├── test-aes256.key │ │ ├── test-pkcs8-blank.key │ │ ├── test-pkcs8-des.key │ │ ├── test-dsa-aes128.key │ │ ├── test-pkcs8-tripledes.key │ │ ├── test-pkcs8-aes256.key │ │ ├── test-dsa-2048-sha2.crt │ │ ├── test-4096.crt │ │ ├── test-dsa-2048.crt │ │ ├── test-dsa.crt │ │ ├── test-4096.key │ │ └── test-third-chain.crt │ ├── rsa_pss_signature │ ├── rsa_signature_raw │ ├── rsa_public_encrypted │ ├── rsa_pss_signature_pss_cert │ ├── rsa_public_encrypted_oaep │ ├── DSAParametersInheritedCACert.crt │ ├── badtls.io_ca.crt │ ├── macos_12_public_key_export_issue.crt │ └── digicert_ca.crt ├── readme.md ├── __main__.py ├── exception_context.py ├── LICENSE ├── _socket_server.py ├── test_kdf.py ├── test_legacy_module.py ├── _socket_proxy.py ├── unittest_data.py └── test_trust_list.py ├── .github └── FUNDING.yml ├── dev ├── codecov.json ├── ci-cleanup.py ├── lint.py ├── ci.py ├── __init__.py ├── release.py ├── ci-driver.py ├── python-install.py ├── tests.py ├── version.py ├── build.py └── _task.py ├── run.py ├── .gitignore ├── tox.ini ├── .circleci └── config.yml ├── LICENSE └── docs ├── util.md ├── oscrypto.md ├── keys.md ├── kdf.md └── readme.md /oscrypto/_mac/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oscrypto/_win/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oscrypto/_linux_bsd/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /oscrypto/_openssl/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requires/api_docs: -------------------------------------------------------------------------------- 1 | CommonMark >= 0.6.0 2 | -------------------------------------------------------------------------------- /tests/fixtures/message.txt: -------------------------------------------------------------------------------- 1 | This is the message to sign -------------------------------------------------------------------------------- /requires/release: -------------------------------------------------------------------------------- 1 | wheel >= 0.31.0 2 | twine >= 1.11.0 3 | setuptools >= 38.6.0 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: wbond 4 | -------------------------------------------------------------------------------- /tests/fixtures/dsa_signature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/dsa_signature -------------------------------------------------------------------------------- /tests/fixtures/message.sha1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/message.sha1 -------------------------------------------------------------------------------- /tests/fixtures/message.sha256: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/message.sha256 -------------------------------------------------------------------------------- /tests/fixtures/rsa_signature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/rsa_signature -------------------------------------------------------------------------------- /tests/fixtures/ecdsa_signature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/ecdsa_signature -------------------------------------------------------------------------------- /tests/fixtures/keys/test-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa.p12 -------------------------------------------------------------------------------- /tests/fixtures/keys/test-rc2.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-rc2.p12 -------------------------------------------------------------------------------- /tests/fixtures/keys/test-third.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-third.p12 -------------------------------------------------------------------------------- /tests/fixtures/rsa_pss_signature: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/rsa_pss_signature -------------------------------------------------------------------------------- /tests/fixtures/rsa_signature_raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/rsa_signature_raw -------------------------------------------------------------------------------- /tests/fixtures/keys/test-aes128.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-aes128.p12 -------------------------------------------------------------------------------- /tests/fixtures/keys/test-aes256.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-aes256.p12 -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-ec-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-ec-der.key -------------------------------------------------------------------------------- /tests/fixtures/rsa_public_encrypted: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/rsa_public_encrypted -------------------------------------------------------------------------------- /tests/fixtures/keys/test-inter-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-inter-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-pkcs8-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-third-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-third-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-third-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-third-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-tripledes.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-tripledes.p12 -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-1024-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-1024-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-1024-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-1024-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-2048-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-2048-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec-named-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-ec-named-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec-named-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-ec-named-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-ec-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-pkcs8-ec-der.key -------------------------------------------------------------------------------- /tests/fixtures/rsa_pss_signature_pss_cert: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/rsa_pss_signature_pss_cert -------------------------------------------------------------------------------- /tests/fixtures/rsa_public_encrypted_oaep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/rsa_public_encrypted_oaep -------------------------------------------------------------------------------- /dev/codecov.json: -------------------------------------------------------------------------------- 1 | { 2 | "slug": "wbond/oscrypto", 3 | "token": "020411b6-d436-4c7e-8866-640c263cb774", 4 | "disabled": true 5 | } 6 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-blank-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-pkcs8-blank-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-dsa-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-pkcs8-dsa-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-dsa-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-ec-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-ec-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-rsa-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-rsa-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-tripledes-blank.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-tripledes-blank.p12 -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048-sha2-der.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-2048-sha2-der.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048-sha2-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-dsa-2048-sha2-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-aes128-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-pkcs8-aes128-der.key -------------------------------------------------------------------------------- /tests/fixtures/DSAParametersInheritedCACert.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/DSAParametersInheritedCACert.crt -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-ec-named-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-pkcs8-ec-named-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa-1024-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-dsa-1024-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa-2048-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-dsa-2048-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-ec-named-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-ec-named-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa-2048-sha2-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-dsa-2048-sha2-der.key -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-rsapublickey-der.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wbond/oscrypto/HEAD/tests/fixtures/keys/test-public-rsapublickey-der.key -------------------------------------------------------------------------------- /oscrypto/version.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | 5 | __version__ = '1.3.0' 6 | __version_info__ = (1, 3, 0) 7 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | from __future__ import unicode_literals, division, absolute_import, print_function 4 | 5 | from dev._task import run_task 6 | 7 | 8 | run_task() 9 | -------------------------------------------------------------------------------- /tests/readme.md: -------------------------------------------------------------------------------- 1 | # oscrypto_tests 2 | 3 | Run the test suite via: 4 | 5 | ```bash 6 | python -m oscrypto_tests 7 | ``` 8 | 9 | Full documentation a . 10 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-ec-named.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhZsAC88J/JKU9GLcjEn/96zWjPkh 3 | I2UZuJkpIMVGZBS4Yy+40ctzFXrnGVptNAK1TTq1ZeE7X2gpQUYR+qN++w== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info/ 2 | .tox/ 3 | __pycache__/ 4 | build/ 5 | dist/ 6 | tests/output/ 7 | *.pyc 8 | .coverage 9 | .DS_Store 10 | .python-version 11 | coverage.xml 12 | oscrypto.sublime-project 13 | oscrypto.sublime-workspace 14 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec-named.key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MHcCAQEEIIQtgbLFPj1EGIBWhUjb8MKem8OaYkgy1mtqzxacT+n3oAoGCCqGSM49 3 | AwEHoUQDQgAEhZsAC88J/JKU9GLcjEn/96zWjPkhI2UZuJkpIMVGZBS4Yy+40ctz 4 | FXrnGVptNAK1TTq1ZeE7X2gpQUYR+qN++w== 5 | -----END EC PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py26,py27,py32,py33,py34,py35,py36,py37,py38,py39,py310,py311,pypy 3 | 4 | [testenv] 5 | deps = -rrequires/ci 6 | commands = {envpython} run.py ci 7 | 8 | [pep8] 9 | max-line-length = 120 10 | 11 | [flake8] 12 | max-line-length = 120 13 | jobs = 1 14 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-ec-named.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghC2BssU+PUQYgFaF 3 | SNvwwp6bw5piSDLWa2rPFpxP6fehRANCAASFmwALzwn8kpT0YtyMSf/3rNaM+SEj 4 | ZRm4mSkgxUZkFLhjL7jRy3MVeucZWm00ArVNOrVl4TtfaClBRhH6o377 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /requires/coverage: -------------------------------------------------------------------------------- 1 | coverage == 4.4.1 ; python_version == '2.6' 2 | coverage == 4.5.4 ; python_version == '3.3' or python_version == '3.4' 3 | coverage == 5.5 ; python_version == '2.7' or python_version == '3.5' or python_version == '3.6' 4 | coverage == 6.5.0 ; python_version == '3.7' 5 | coverage == 7.3.0 ; python_version >= '3.8' 6 | -------------------------------------------------------------------------------- /tests/__main__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | import unittest 6 | 7 | from . import test_classes 8 | 9 | 10 | suite = unittest.TestSuite() 11 | loader = unittest.TestLoader() 12 | for test_class in test_classes(): 13 | suite.addTest(loader.loadTestsFromTestCase(test_class)) 14 | unittest.TextTestRunner(stream=sys.stdout, verbosity=2).run(suite) 15 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-rsapublickey.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIIBCgKCAQEAvVsoB3Ti5kosAiq9UN54F6rsUDZ+lLnGRZyodtqvO8PX/8Qb+QJC 3 | KsmvfTae6yMkXF2OLdpUNEY/HT5ZbAZqPL6Ta9ibS3uZI/9uZUYIzTqh+8NlQxZX 4 | Ut3hLIiceu5LVCPjEeUHv9n6YBZikK52YAUgkSC2UcPN7Oq7qQsRU0HWVssf6U83 5 | K6fBcL0VJhaF6SMDIFp+UUGShBX3SNd+5Mbs+HSbgMB9mfmfmv9im+YoQOQ+RpbW 6 | YC3yp6XhvxGSUCHy3y9NJ+9C5N7LDcYVwp7srKYochoMPHDCcAt8ZY1re3tihVk/ 7 | 19WuCGRHvcMEKccjHba4MdROTAGYh1QvXwIDAQAB 8 | -----END RSA PUBLIC KEY----- 9 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-rsa.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvVsoB3Ti5kosAiq9UN54 3 | F6rsUDZ+lLnGRZyodtqvO8PX/8Qb+QJCKsmvfTae6yMkXF2OLdpUNEY/HT5ZbAZq 4 | PL6Ta9ibS3uZI/9uZUYIzTqh+8NlQxZXUt3hLIiceu5LVCPjEeUHv9n6YBZikK52 5 | YAUgkSC2UcPN7Oq7qQsRU0HWVssf6U83K6fBcL0VJhaF6SMDIFp+UUGShBX3SNd+ 6 | 5Mbs+HSbgMB9mfmfmv9im+YoQOQ+RpbWYC3yp6XhvxGSUCHy3y9NJ+9C5N7LDcYV 7 | wp7srKYochoMPHDCcAt8ZY1re3tihVk/19WuCGRHvcMEKccjHba4MdROTAGYh1Qv 8 | XwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-1024.param: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PARAMETERS----- 2 | MIIBHgKBgQDULV67W/7oQImr84BkkPBqp5Dqflll+1rF9CtEBSlmiz3mbaHcaOoW 3 | I75X905/DdWj3qlX8YURpBZ1zXJ7+muXFhwT5noAAOtSq2yQJx1L+yxEm8mREmQi 4 | Ezir/IeaUBZPuFHq+OtzW0huJSeN6lHAkCzqQhV9tBwiHWHMNe4fnwIVAMhBG4/y 5 | BAMeN0p8+/wodBWwAxMpAoGAFy80rVlJ6VkGK5kWRMwPGJb6rGHLPQGIpRjLtA6s 6 | Ea+t9g22tkc7NXdGbFPmqKDmgUv0yXGNKw10dt7NE6x16/d+mGrF3n0al9Lr5La9 7 | u9JIQGb5cTiykzQmnu3OJP8HEiFG3egKc1rs9e/zGOSEQ2L4YSx7ligqKipuVVem 8 | 2tE= 9 | -----END DSA PARAMETERS----- 10 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-ec.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA 3 | AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA//// 4 | ///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd 5 | NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5 6 | RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA 7 | //////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABItdTHH31sajSWNCXEefy3Mk 8 | Hcnd0S3xOp+3BN4g0FgAk1T2iccvhyv3+T07NO2eew49V0LfeAMLzDHGA9efYAE= 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /requires/ci: -------------------------------------------------------------------------------- 1 | setuptools == 36.8.0 ; python_version == '2.6' 2 | setuptools == 44.1.1 ; python_version == '2.7' and sys_platform == 'win32' 3 | setuptools == 18.4 ; python_version == '3.2' 4 | setuptools == 39.2.0 ; python_version == '3.3' 5 | https://github.com/wbond/asn1crypto/archive/master.zip 6 | -r ./coverage 7 | -r ./lint 8 | # cffi 3.15.0 is required for Python 3.10 9 | cffi == 1.15.0 ; (python_version == '2.7' or python_version >= '3.6') and sys_platform == 'darwin' 10 | pycparser == 2.19 ; (python_version == '2.7' or python_version >= '3.6') and sys_platform == 'darwin' 11 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | python2.7: 4 | machine: 5 | image: ubuntu-2004:202101-01 6 | resource_class: arm.medium 7 | steps: 8 | - checkout 9 | - run: python run.py deps 10 | - run: python run.py ci-driver 11 | python3.9: 12 | machine: 13 | image: ubuntu-2004:202101-01 14 | resource_class: arm.medium 15 | steps: 16 | - checkout 17 | - run: python run.py deps 18 | - run: python3 run.py ci-driver 19 | workflows: 20 | version: 2 21 | arm64: 22 | jobs: 23 | - python2.7 24 | - python3.9 25 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec.key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | MIIBaAIBAQQg6OWPI5AB6xIvibu6NwIv2Myye+QfQp4+U/mJ0GmFQ12ggfowgfcC 3 | AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA//////////////// 4 | MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr 5 | vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE 6 | axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W 7 | K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8 8 | YyVRAgEBoUQDQgAEi11McffWxqNJY0JcR5/LcyQdyd3RLfE6n7cE3iDQWACTVPaJ 9 | xy+HK/f5PTs07Z57Dj1XQt94AwvMMcYD159gAQ== 10 | -----END EC PRIVATE KEY----- 11 | -------------------------------------------------------------------------------- /oscrypto/_mac/_common_crypto.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | 6 | if ffi() == 'cffi': 7 | from ._common_crypto_cffi import CommonCrypto 8 | else: 9 | from ._common_crypto_ctypes import CommonCrypto 10 | 11 | 12 | __all__ = [ 13 | 'CommonCrypto', 14 | 'CommonCryptoConst', 15 | ] 16 | 17 | 18 | class CommonCryptoConst(): 19 | kCCPBKDF2 = 2 20 | kCCPRFHmacAlgSHA1 = 1 21 | kCCPRFHmacAlgSHA224 = 2 22 | kCCPRFHmacAlgSHA256 = 3 23 | kCCPRFHmacAlgSHA384 = 4 24 | kCCPRFHmacAlgSHA512 = 5 25 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-ec.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB 3 | AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA 4 | ///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV 5 | AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg 6 | 9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A 7 | AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQg6OWPI5AB6xIv 8 | ibu6NwIv2Myye+QfQp4+U/mJ0GmFQ12hRANCAASLXUxx99bGo0ljQlxHn8tzJB3J 9 | 3dEt8TqftwTeINBYAJNU9onHL4cr9/k9OzTtnnsOPVdC33gDC8wxxgPXn2AB 10 | -----END PRIVATE KEY----- 11 | -------------------------------------------------------------------------------- /oscrypto/tls.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from . import backend 5 | 6 | 7 | _backend = backend() 8 | 9 | 10 | if _backend == 'mac': 11 | from ._mac.tls import ( 12 | TLSSession, 13 | TLSSocket, 14 | ) 15 | 16 | elif _backend == 'win' or _backend == 'winlegacy': 17 | from ._win.tls import ( 18 | TLSSession, 19 | TLSSocket, 20 | ) 21 | 22 | else: 23 | from ._openssl.tls import ( 24 | TLSSession, 25 | TLSSocket, 26 | ) 27 | 28 | 29 | __all__ = [ 30 | 'TLSSession', 31 | 'TLSSocket', 32 | ] 33 | -------------------------------------------------------------------------------- /oscrypto/keys.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from . import backend 5 | from ._asymmetric import parse_certificate, parse_private, parse_public 6 | 7 | 8 | _backend = backend() 9 | 10 | 11 | if _backend == 'mac': 12 | from ._mac.asymmetric import parse_pkcs12 13 | elif _backend == 'win' or _backend == 'winlegacy': 14 | from ._win.asymmetric import parse_pkcs12 15 | else: 16 | from ._openssl.asymmetric import parse_pkcs12 17 | 18 | 19 | __all__ = [ 20 | 'parse_certificate', 21 | 'parse_pkcs12', 22 | 'parse_private', 23 | 'parse_public', 24 | ] 25 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec-aes128.key: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-128-CBC,0B30DBF3A302FAACF03A6CC97FB03F8A 4 | 5 | 9EEoQMvYmw0gsVmR1mKCAcfvbnQ9WwLjz3+PZwW3WIP13tLUy2dYqp6MS0ALriJw 6 | 54WNaOQJZz6oF1ppMz/fTvAXVC9uTNgUhHJ9C2l6+BGpZFZVlW9q2LOw5IxZPfYB 7 | 0bLAXu82PVH4g9Mygr9773a+7y3mki2tA1K05L0HTVYKMpvRm4kV/a2ANKRbdAv9 8 | 77u/B+ftTUezpCkI9UApxXG318yQUA1fFhmCebGb2IRBtTls+NmvswBy76xNeJLw 9 | q+/N2KPkDyQTRpSbZ8+MMIGaY/ZB9tAR8H31uG+Qv9hgSMahXadWdwJuofoIiq9l 10 | N3dHLD9TwedfrnEWVtLA84ynum0DWhWxGiNb7vHqtTDoAYbSR+c/rM2rnUFMGJ3o 11 | 5vw9avcLkgEEW5wB5XRhdPZsuVQNgOF1BhLX/UqODkBNFSUnxwNhe4ofdFNRECIm 12 | fe56AXrE7uhBXIHMm+s234fFPMbh3tpUdif9AsTA7P8= 13 | -----END EC PRIVATE KEY----- 14 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa-1024.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBtzCCASsGByqGSM44BAEwggEeAoGBANQtXrtb/uhAiavzgGSQ8GqnkOp+WWX7 3 | WsX0K0QFKWaLPeZtodxo6hYjvlf3Tn8N1aPeqVfxhRGkFnXNcnv6a5cWHBPmegAA 4 | 61KrbJAnHUv7LESbyZESZCITOKv8h5pQFk+4Uer463NbSG4lJ43qUcCQLOpCFX20 5 | HCIdYcw17h+fAhUAyEEbj/IEAx43Snz7/Ch0FbADEykCgYAXLzStWUnpWQYrmRZE 6 | zA8YlvqsYcs9AYilGMu0DqwRr632Dba2Rzs1d0ZsU+aooOaBS/TJcY0rDXR23s0T 7 | rHXr936YasXefRqX0uvktr270khAZvlxOLKTNCae7c4k/wcSIUbd6ApzWuz17/MY 8 | 5IRDYvhhLHuWKCoqKm5VV6ba0QOBhQACgYEArrmT63ySk3VhckLcZuQzY5fQJ94D 9 | Y58zCCldk6qrHNOj1+fz/rOqTpnxgZ7UqhibVXiD1BHITBlrNDQXW+pnWq6zHtoX 10 | wiO3UcNuY2oeI74c6NVDgXXEmBIKcqBrHzQvVwNnuhqkUnHEIQIcUDLOOehJpkwJ 11 | 89/2hCeocgMpjO8= 12 | -----END PUBLIC KEY----- 13 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-1024.key: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIBuwIBAAKBgQDULV67W/7oQImr84BkkPBqp5Dqflll+1rF9CtEBSlmiz3mbaHc 3 | aOoWI75X905/DdWj3qlX8YURpBZ1zXJ7+muXFhwT5noAAOtSq2yQJx1L+yxEm8mR 4 | EmQiEzir/IeaUBZPuFHq+OtzW0huJSeN6lHAkCzqQhV9tBwiHWHMNe4fnwIVAMhB 5 | G4/yBAMeN0p8+/wodBWwAxMpAoGAFy80rVlJ6VkGK5kWRMwPGJb6rGHLPQGIpRjL 6 | tA6sEa+t9g22tkc7NXdGbFPmqKDmgUv0yXGNKw10dt7NE6x16/d+mGrF3n0al9Lr 7 | 5La9u9JIQGb5cTiykzQmnu3OJP8HEiFG3egKc1rs9e/zGOSEQ2L4YSx7ligqKipu 8 | VVem2tECgYEArrmT63ySk3VhckLcZuQzY5fQJ94DY58zCCldk6qrHNOj1+fz/rOq 9 | TpnxgZ7UqhibVXiD1BHITBlrNDQXW+pnWq6zHtoXwiO3UcNuY2oeI74c6NVDgXXE 10 | mBIKcqBrHzQvVwNnuhqkUnHEIQIcUDLOOehJpkwJ89/2hCeocgMpjO8CFBJB0OE4 11 | Bm5BYpqkLptYN3evcZV9 12 | -----END DSA PRIVATE KEY----- 13 | -------------------------------------------------------------------------------- /oscrypto/_int.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Function to fill ensure integers converted to a byte string are a specific 5 | width. Exports the following items: 6 | 7 | - fill_width() 8 | """ 9 | 10 | from __future__ import unicode_literals, division, absolute_import, print_function 11 | 12 | 13 | __all__ = [ 14 | 'fill_width', 15 | ] 16 | 17 | 18 | def fill_width(bytes_, width): 19 | """ 20 | Ensure a byte string representing a positive integer is a specific width 21 | (in bytes) 22 | 23 | :param bytes_: 24 | The integer byte string 25 | 26 | :param width: 27 | The desired width as an integer 28 | 29 | :return: 30 | A byte string of the width specified 31 | """ 32 | 33 | while len(bytes_) < width: 34 | bytes_ = b'\x00' + bytes_ 35 | return bytes_ 36 | -------------------------------------------------------------------------------- /oscrypto/_mac/_common_crypto_ctypes.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from ctypes import CDLL, c_uint32, c_char_p, c_size_t, c_int, c_uint 5 | 6 | from .._ffi import FFIEngineError 7 | 8 | 9 | __all__ = [ 10 | 'CommonCrypto', 11 | ] 12 | 13 | 14 | common_crypto_path = '/usr/lib/system/libcommonCrypto.dylib' 15 | 16 | CommonCrypto = CDLL(common_crypto_path, use_errno=True) 17 | 18 | try: 19 | CommonCrypto.CCKeyDerivationPBKDF.argtypes = [ 20 | c_uint32, 21 | c_char_p, 22 | c_size_t, 23 | c_char_p, 24 | c_size_t, 25 | c_uint32, 26 | c_uint, 27 | c_char_p, 28 | c_size_t 29 | ] 30 | CommonCrypto.CCKeyDerivationPBKDF.restype = c_int 31 | except (AttributeError): 32 | raise FFIEngineError('Error initializing ctypes') 33 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048.param: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PARAMETERS----- 2 | MIICIQKCAQEA5/jKAdpfXdDKgYytCbjkZaCjpB3HWlI0lx/wh5dgwbEeKGrGhU0I 3 | S/AjVyywG/h+2jwGexAV+p/g76bV60rZ210w5P3tepwvUAKBPGkl2llM8DcMogHr 4 | uQXsD9XCRvztoklkEySrZKtrbuuszpHMnbKycS6O5zkWSXWPtGNjQHirv5QIHTea 5 | 4/JAVp2BVslKwbSLXqChr7Uipl9+3mkQj8f8s64iVINuKqKuAJNlb6zz6W7pNT6R 6 | whRXv8Hpb0BUWsfvJ0e8mQwt9UQIPp2XwvEP/MevuZ3Cbp6NbRD0FJOs+Fgs9mhY 7 | FTt3tYrqDGgnJJZoVGpXujQUZvAO1IuvtwIVAI+g8itQ+KAjWVkM26Pyv7BnNCMT 8 | AoIBAQDe/LGUpxVRWUooD4vbJquJIfLXh+Z2veN4oWn4BWCbEW9WBlGa8VDV9XKJ 9 | yIzVZRBD7f4zH4zLgLN1vmr2zXNng5eiJtTJICkWBqBa9OEtsqaZUC5K7perA7pY 10 | tQhQ47I22c2CeTqaMoIndm7GrglwLWtHVKvK7qrm+5vKcC/Z8WcN/LQ9seqDsqS+ 11 | 7FFM9IfYiKfV9Zmt9Wkiq50OV1zOPadk4QOyZ+mDWLqHDkrynmJgW4b4vAcJbP6X 12 | ysTmlatxR3qqeqJW0Ev9GREjCSXsbgZO41aVe0/gR0kUDeSL/7mggjEzAeW19qrp 13 | Ls8YERW/LQZzksj3W22HdBPh4eOF 14 | -----END DSA PARAMETERS----- 15 | -------------------------------------------------------------------------------- /dev/ci-cleanup.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | import shutil 6 | 7 | from . import build_root, other_packages 8 | 9 | 10 | def run(): 11 | """ 12 | Cleans up CI dependencies - used for persistent GitHub Actions 13 | Runners since they don't clean themselves up. 14 | """ 15 | 16 | print("Removing ci dependencies") 17 | deps_dir = os.path.join(build_root, 'modularcrypto-deps') 18 | if os.path.exists(deps_dir): 19 | shutil.rmtree(deps_dir, ignore_errors=True) 20 | 21 | print("Removing modularcrypto packages") 22 | for other_package in other_packages: 23 | pkg_dir = os.path.join(build_root, other_package) 24 | if os.path.exists(pkg_dir): 25 | shutil.rmtree(pkg_dir, ignore_errors=True) 26 | print() 27 | 28 | return True 29 | -------------------------------------------------------------------------------- /oscrypto/_mac/_common_crypto_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .._ffi import register_ffi 5 | 6 | from cffi import FFI 7 | 8 | 9 | __all__ = [ 10 | 'CommonCrypto', 11 | ] 12 | 13 | 14 | ffi = FFI() 15 | ffi.cdef(""" 16 | typedef uint32_t CCPBKDFAlgorithm; 17 | 18 | typedef uint32_t CCPseudoRandomAlgorithm; 19 | typedef unsigned int uint; 20 | 21 | int CCKeyDerivationPBKDF(CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen, 22 | const char *salt, size_t saltLen, CCPseudoRandomAlgorithm prf, uint rounds, 23 | char *derivedKey, size_t derivedKeyLen); 24 | """) 25 | 26 | common_crypto_path = '/usr/lib/system/libcommonCrypto.dylib' 27 | 28 | CommonCrypto = ffi.dlopen(common_crypto_path) 29 | register_ffi(CommonCrypto, ffi) 30 | -------------------------------------------------------------------------------- /requires/lint: -------------------------------------------------------------------------------- 1 | setuptools >= 39.0.1 ; python_version == '2.7' or python_version >= '3.3' 2 | enum34 == 1.1.6 ; python_version == '2.7' or python_version == '3.3' 3 | configparser == 3.5.0 ; python_version == '2.7' 4 | mccabe == 0.6.1 ; python_version == '3.3' 5 | pycodestyle == 2.3.1 ; python_version == '3.3' 6 | pyflakes == 1.6.0 ; python_version == '3.3' 7 | flake8 == 3.5.0 ; python_version == '3.3' 8 | mccabe == 0.6.1 ; python_version == '2.7' or python_version >= '3.4' 9 | pycodestyle == 2.5.0 ; python_version == '2.7' or python_version >= '3.4' 10 | pyflakes == 2.1.1 ; python_version == '2.7' or python_version >= '3.4' 11 | functools32 == 3.2.3-2 ; python_version == '2.7' 12 | typing == 3.7.4.1 ; python_version == '2.7' or python_version == '3.4' 13 | entrypoints == 0.3 ; python_version == '2.7' or python_version >= '3.4' 14 | flake8 == 3.7.9 ; python_version == '2.7' or python_version >= '3.4' 15 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048-sha2.param: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PARAMETERS----- 2 | MIICLAKCAQEAh94gPPdViRPhA3VUYhgehtieTEIX7gS6nf6AhuTh2zopRB8fFRyy 3 | mi2GfAM7z2BwO4+l0RRF+VhbeY7Ta3IPtr5iDsZtMkZ3vjQwWE5Oq+eNK+10LT4O 4 | oUmdsqJ/M43d/OvPXzj/ne6YXV+8h0gVrID76+m7saSImhfqDUA35sBwPccpvGVM 5 | egC7QB+Ma1tT4BjQRJqV/Qrb9bHO8BsR41jzNG/jyLsiL7zBmO949FpXRgXh5jYc 6 | FlEiCDwxAGx2oEM9+tMLmZuAM+VM1WRWWqfnwWpB3iRw2PvYwOL8M0pQt20T3M1O 7 | HeJYAJeJICa7pVtuNocLPtpFkppMPSJwKQIhAPFXIWyQWQ6KvkMjPUs3W0BsWxUE 8 | 3t/rRzMIf3RvjLpdAoIBAG2svmmB0EpiZbvP8kLWLRtBKRSEkVfgGjMgSMX4W7Jc 9 | beY7peMq8BY4Oy5NdyR2HTVb15MqwqVBOQtoAaTiMtF4oy3mVFSxKEqRlL/ZpySl 10 | tuGsmq+pqLcyMmZRABtDUa8zjs0MVZFhWG5OGgUkzPG/vV4uUQvWBNLg/cQXmnEo 11 | aRcEvcR7hB9L8l10R39mafS6zWZh8ng32HWhDiFetXKEtP8hCCv8CWmN8vUJKK82 12 | yFY0ax3+HrIXQjbk5TMrqr8cNX2DfFxMP+7/ves6efX941oTJk0SuvO5p4d1O8N/ 13 | D8QL3EFq9sMbK3XCT6nVidOmwgLoRqJK9l0bdfWfE+Y= 14 | -----END DSA PARAMETERS----- 15 | -------------------------------------------------------------------------------- /oscrypto/_win/_kernel32.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from ._decode import _try_decode 6 | from .._types import str_cls 7 | 8 | if ffi() == 'cffi': 9 | from ._kernel32_cffi import kernel32, get_error 10 | else: 11 | from ._kernel32_ctypes import kernel32, get_error 12 | 13 | 14 | __all__ = [ 15 | 'handle_error', 16 | 'kernel32', 17 | ] 18 | 19 | 20 | def handle_error(result): 21 | """ 22 | Extracts the last Windows error message into a python unicode string 23 | 24 | :param result: 25 | A function result, 0 or None indicates failure 26 | 27 | :return: 28 | A unicode string error message 29 | """ 30 | 31 | if result: 32 | return 33 | 34 | _, error_string = get_error() 35 | 36 | if not isinstance(error_string, str_cls): 37 | error_string = _try_decode(error_string) 38 | 39 | raise OSError(error_string) 40 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec-named.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICgzCCAimgAwIBAgIJAOWsWhjG4kOgMAoGCCqGSM49BAMCMIGdMQswCQYDVQQG 3 | EwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czEQMA4GA1UEBwwHTmV3YnVyeTEe 4 | MBwGA1UECgwVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLDAdUZXN0aW5n 5 | MRIwEAYDVQQDDAlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhu 6 | cy5pbzAeFw0xNTA2MTcxNTQ5MDNaFw0xNTA3MTcxNTQ5MDNaMIGdMQswCQYDVQQG 7 | EwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czEQMA4GA1UEBwwHTmV3YnVyeTEe 8 | MBwGA1UECgwVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLDAdUZXN0aW5n 9 | MRIwEAYDVQQDDAlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhu 10 | cy5pbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABIWbAAvPCfySlPRi3IxJ//es 11 | 1oz5ISNlGbiZKSDFRmQUuGMvuNHLcxV65xlabTQCtU06tWXhO19oKUFGEfqjfvuj 12 | UDBOMB0GA1UdDgQWBBQjje7uR0gq5DVUuP1WaBZf4qrNgTAfBgNVHSMEGDAWgBQj 13 | je7uR0gq5DVUuP1WaBZf4qrNgTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gA 14 | MEUCIQDGxGHBYh2VpgzM6GFctdVxwEo8oumb+Mv/2G9YyNH/bgIgVO4qPsVFvE6G 15 | hY9L6tWXKiU4OD8E7GrySzDBRqjhIDU= 16 | -----END CERTIFICATE----- 17 | -------------------------------------------------------------------------------- /tests/exception_context.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import re 5 | import sys 6 | from contextlib import contextmanager 7 | 8 | 9 | if sys.version_info < (3,): 10 | str_cls = unicode # noqa 11 | else: 12 | str_cls = str 13 | 14 | 15 | @contextmanager 16 | def assert_exception(test_case, expected_class, expected_msg): 17 | """ 18 | Look for a specific exception type and message, allowing the exception 19 | to be raised if it doesn't match 20 | """ 21 | 22 | expected_re = re.compile(expected_msg) 23 | 24 | try: 25 | yield 26 | 27 | except Exception as e: 28 | should_raise = True 29 | if isinstance(e, expected_class): 30 | test_case.assertIsInstance(e, expected_class) 31 | msg = str_cls(e) 32 | if expected_re.search(msg): 33 | test_case.assertRegex(msg, expected_re) 34 | should_raise = False 35 | if should_raise: 36 | raise 37 | -------------------------------------------------------------------------------- /oscrypto/_types.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | import inspect 6 | 7 | 8 | if sys.version_info < (3,): 9 | str_cls = unicode # noqa 10 | byte_cls = str 11 | int_types = (int, long) # noqa 12 | 13 | def bytes_to_list(byte_string): 14 | return [ord(b) for b in byte_string] 15 | 16 | else: 17 | str_cls = str 18 | byte_cls = bytes 19 | int_types = (int,) 20 | 21 | bytes_to_list = list 22 | 23 | 24 | def type_name(value): 25 | """ 26 | Returns a user-readable name for the type of an object 27 | 28 | :param value: 29 | A value to get the type name of 30 | 31 | :return: 32 | A unicode string of the object's type name 33 | """ 34 | 35 | if inspect.isclass(value): 36 | cls = value 37 | else: 38 | cls = value.__class__ 39 | if cls.__module__ in set(['builtins', '__builtin__']): 40 | return cls.__name__ 41 | return '%s.%s' % (cls.__module__, cls.__name__) 42 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-512.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICpzCCAhACAg4AMA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG 3 | A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE 4 | MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl 5 | YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw 6 | ODIyMDcyNjQzWhcNMTcwODIxMDcyNjQzWjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE 7 | CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs 8 | ZS5jb20wgfAwgagGByqGSM44BAEwgZwCQQDKVt7ZYtFRCzrm2/NTjl45YtMgVctQ 9 | pLadAowFRydY13uhGw+JXyM+qmngfQkXImQpoYdIe+A8DWG2vaO3wKQ3AhUAxx6d 10 | eaDs+XNHcbsiVQ1osvxrG8sCQHQYZDlSy/A5AFXrWXUNlTJbNhWDnitiG/95qYCe 11 | FGnwYPp/WyhX+/lbDmQujkrbd4wYStudZM0cc4iDAWeOHQ0DQwACQDtK/S6POMQE 12 | 8aI+skBdNQn+Ch76kNDhztC/suOr9FbCSxnZ/CfhSgE1phOJyEkdR2jgErl3uh51 13 | lo+7to76LLUwDQYJKoZIhvcNAQEFBQADgYEAnrmxZ3HB0LmVoFYdBJWxNBkRaFyn 14 | jBmRsSJp2xvFg2nyAF77AOqBuFOFqOxg04eDxH8TGLQOWjqdyCFCY79AQlmkdB+8 15 | Z5SWqPEwLJHVLd91O9avQwwRQT5TAxGXFkHTlQxOoaGfTsVQFqSDnlYC4mFjspA7 16 | W+K8+llxOFmtVzU= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /oscrypto/_win/_decode.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import locale 5 | 6 | from .._types import str_cls 7 | 8 | 9 | _encoding = locale.getpreferredencoding() 10 | _fallback_encodings = ['utf-8', 'cp1252'] 11 | 12 | 13 | def _try_decode(byte_string): 14 | """ 15 | Tries decoding a byte string from the OS into a unicode string 16 | 17 | :param byte_string: 18 | A byte string 19 | 20 | :return: 21 | A unicode string 22 | """ 23 | 24 | try: 25 | return str_cls(byte_string, _encoding) 26 | 27 | # If the "correct" encoding did not work, try some defaults, and then just 28 | # obliterate characters that we can't seen to decode properly 29 | except (UnicodeDecodeError): 30 | for encoding in _fallback_encodings: 31 | try: 32 | return str_cls(byte_string, encoding, errors='strict') 33 | except (UnicodeDecodeError): 34 | pass 35 | 36 | return str_cls(byte_string, errors='replace') 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2022 Will Bond 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /oscrypto/_win/_kernel32_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .._ffi import register_ffi 5 | from .._types import str_cls 6 | from ..errors import LibraryNotFoundError 7 | 8 | import cffi 9 | 10 | 11 | __all__ = [ 12 | 'get_error', 13 | 'kernel32', 14 | ] 15 | 16 | 17 | ffi = cffi.FFI() 18 | if cffi.__version_info__ >= (0, 9): 19 | ffi.set_unicode(True) 20 | ffi.cdef(""" 21 | typedef long long LARGE_INTEGER; 22 | BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); 23 | 24 | typedef struct _FILETIME { 25 | DWORD dwLowDateTime; 26 | DWORD dwHighDateTime; 27 | } FILETIME; 28 | 29 | void GetSystemTimeAsFileTime(FILETIME *lpSystemTimeAsFileTime); 30 | """) 31 | 32 | 33 | try: 34 | kernel32 = ffi.dlopen('kernel32.dll') 35 | register_ffi(kernel32, ffi) 36 | 37 | except (OSError) as e: 38 | if str_cls(e).find('cannot load library') != -1: 39 | raise LibraryNotFoundError('kernel32.dll could not be found') 40 | raise 41 | 42 | 43 | def get_error(): 44 | return ffi.getwinerror() 45 | -------------------------------------------------------------------------------- /tests/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2019 Will Bond 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-inter.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIC8DCCAdgCAQAwgaoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl 3 | dHRzMRAwDgYDVQQHEwdOZXdidXJ5MR4wHAYDVQQKExVDb2RleCBOb24gU3VmZmlj 4 | aXQgTEMxHTAbBgNVBAsTFFRlc3RpbmcgSW50ZXJtZWRpYXRlMRIwEAYDVQQDEwlX 5 | aWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhucy5pbzCCASIwDQYJ 6 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL89U52iC2p7aCpdnbR1YHk0XGMlfrPo 7 | DnvMapPXU5+I2ZyQirExErx5OhHr38MmZU1tBMnL9wV7Fnfd1v5Su0Qi3E6SUUVs 8 | b/pOOaqw5gXztOQmoZfvNez9nsPVeXT/YI2Hq8889uL+jUUe0qeTgdg6fJQtEzHG 9 | 23To7+7//B2dZeJIA4o5qwtPt4/oW6iTbz4F5Db0YHdQ0vygLtuLKG/z3I1WEOUc 10 | CST7N+sY/h02rE5jxKTAjQZiSL2yQRyTB/s3LP68DzNUlojKa1795GJwIUVgXGH5 11 | C1CHLEXsPCwHn9ciARYpFed3+K/I5EyUhVzzcIcIzivK9eAbT4jta5kCAwEAAaAA 12 | MA0GCSqGSIb3DQEBCwUAA4IBAQBMlRtzNp//q2kFXLYaQbWv6q87Z32HMp6Jq814 13 | TP0lz2CYZQ2KXtk+AHc+cKU8XHvVRFfydd15xikWM8z4Sn4LgXLD9UvKswFeTnQV 14 | gHkFC41Cp5H5K5shB0dNtIoKh/Lip7EIH2EyH/6ocgqrymqd2VoO3nIE5ysyzGrW 15 | +BVaZtmXVbyWDhQK10TmPe4GJN22VPzkvlPlqDRQC70IfJoFkZAdd085FT+sq7ny 16 | X7D73jBfYgfd9Z9h0t+vKN5NWWN5OI3IZADkMOYhest7RgZTFX2NBqHbigCJaUk8 17 | f/KDImyMWk+vaDGrkUoOfKKXvdRSUL1mQDgt/FmPq9EdZt4j 18 | -----END CERTIFICATE REQUEST----- 19 | -------------------------------------------------------------------------------- /dev/lint.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | 6 | from . import package_name, package_root 7 | 8 | import flake8 9 | if not hasattr(flake8, '__version_info__') or flake8.__version_info__ < (3,): 10 | from flake8.engine import get_style_guide 11 | else: 12 | from flake8.api.legacy import get_style_guide 13 | 14 | 15 | def run(): 16 | """ 17 | Runs flake8 lint 18 | 19 | :return: 20 | A bool - if flake8 did not find any errors 21 | """ 22 | 23 | print('Running flake8 %s' % flake8.__version__) 24 | 25 | flake8_style = get_style_guide(config_file=os.path.join(package_root, 'tox.ini')) 26 | 27 | paths = [] 28 | for _dir in [package_name, 'dev', 'tests']: 29 | for root, _, filenames in os.walk(_dir): 30 | for filename in filenames: 31 | if not filename.endswith('.py'): 32 | continue 33 | paths.append(os.path.join(root, filename)) 34 | report = flake8_style.check_files(paths) 35 | success = report.total_errors == 0 36 | if success: 37 | print('OK') 38 | return success 39 | -------------------------------------------------------------------------------- /oscrypto/_rand.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | 6 | from ._errors import pretty_message 7 | from ._types import type_name, int_types 8 | 9 | 10 | __all__ = [ 11 | 'rand_bytes', 12 | ] 13 | 14 | 15 | def rand_bytes(length): 16 | """ 17 | Returns a number of random bytes suitable for cryptographic purposes 18 | 19 | :param length: 20 | The desired number of bytes 21 | 22 | :raises: 23 | ValueError - when any of the parameters contain an invalid value 24 | TypeError - when any of the parameters are of the wrong type 25 | OSError - when an error is returned by OpenSSL 26 | 27 | :return: 28 | A byte string 29 | """ 30 | 31 | if not isinstance(length, int_types): 32 | raise TypeError(pretty_message( 33 | ''' 34 | length must be an integer, not %s 35 | ''', 36 | type_name(length) 37 | )) 38 | 39 | if length < 1: 40 | raise ValueError('length must be greater than 0') 41 | 42 | if length > 1024: 43 | raise ValueError('length must not be greater than 1024') 44 | 45 | return os.urandom(length) 46 | -------------------------------------------------------------------------------- /oscrypto/_errors.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Helper for formatting exception messages. Exports the following items: 5 | 6 | - pretty_message() 7 | """ 8 | 9 | from __future__ import unicode_literals, division, absolute_import, print_function 10 | 11 | import re 12 | import textwrap 13 | 14 | 15 | __all__ = [ 16 | 'pretty_message', 17 | ] 18 | 19 | 20 | def pretty_message(string, *params): 21 | """ 22 | Takes a multi-line string and does the following: 23 | 24 | - dedents 25 | - converts newlines with text before and after into a single line 26 | - strips leading and trailing whitespace 27 | 28 | :param string: 29 | The string to format 30 | 31 | :param *params: 32 | Params to interpolate into the string 33 | 34 | :return: 35 | The formatted string 36 | """ 37 | 38 | output = textwrap.dedent(string) 39 | 40 | # Unwrap lines, taking into account bulleted lists, ordered lists and 41 | # underlines consisting of = signs 42 | if output.find('\n') != -1: 43 | output = re.sub('(?<=\\S)\n(?=[^ \n\t\\d\\*\\-=])', ' ', output) 44 | 45 | if params: 46 | output = output % params 47 | 48 | output = output.strip() 49 | 50 | return output 51 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-third.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIIDITCCAgkCAQAwgbIxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl 3 | dHRzMRAwDgYDVQQHEwdOZXdidXJ5MR4wHAYDVQQKExVDb2RleCBOb24gU3VmZmlj 4 | aXQgTEMxJTAjBgNVBAsTHFRlc3QgVGhpcmQtTGV2ZWwgQ2VydGlmaWNhdGUxEjAQ 5 | BgNVBAMTCVdpbGwgQm9uZDEeMBwGCSqGSIb3DQEJARYPd2lsbEBjb2RleG5zLmlv 6 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwAos1V0CURRsF4Ap9LPd 7 | iZ3vy23qXaOMR3PhAyoWRgNJuXmkwHRE/7JEodVKv6Av30XfABcegxvzVsVUi0t3 8 | LHe8rWorYWEy+a7DzI1TLejhojAT816hunh5YtY1bB2qY/I2m9zyDwd1WyeT3u71 9 | lQaiIcRuW8tny6KO9vErmFsKQoeM6EcINPl6C08o7IWo5YnVbMg0gJF8R4iNkzRy 10 | 4tRZUmbNv1AnwKY3g7pHWtgrXfV4hnoVaUlOnHWfsy/KBM6YOLJUTQ0x8kVPN2Nr 11 | yRDGLB3Ko30j058epF5+HxMJAG4CC67A9TIC71V7jl4OrN95auCjKKdnQpeKqsfk 12 | NQIDAQABoCkwJwYJKoZIhvcNAQkOMRowGDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF 13 | 4DANBgkqhkiG9w0BAQsFAAOCAQEAdg+HQ3MVFJHnY3Lb+5vSXaYA4F1rXTSZ1jJg 14 | P+TACsuqZ0PaFsg+6OCec78F3yDvntXu3KfUwvshP6PmkIaVjahdLEp0ng9nwtWq 15 | d0DMoUFKeEYhr8T8Z+dbCsZfvUyk8KNMsWuPncCWPQduz5i0g/5vZ9G5na/cmqtJ 16 | GmSY4XLkb3StXJ6sk+uEhlPCuCfL9Dq0r87COTFj4pC7x2+PrDdLu5YJXdTR8mmn 17 | GA44HDNW6XX8t5A5YC5iFnFIgQO2z+B9X2UETajoMxL+HhyE+AopU/n1Wxm1c4oW 18 | 1/q3lvrYLiZ+XX76QbIY/4IgAlry7B1eyxHe732lroEvKgezjA== 19 | -----END CERTIFICATE REQUEST----- 20 | -------------------------------------------------------------------------------- /tests/_socket_server.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | 5 | import socket 6 | import select 7 | import threading 8 | 9 | 10 | def listen(server, on_read): 11 | sock, addr = server.accept() 12 | 13 | timeout = 10 14 | try: 15 | read_ready, _, _ = select.select([sock], [], [], timeout) 16 | while len(read_ready): 17 | data = sock.recv(8192) 18 | if on_read(sock, data): 19 | read_ready, _, _ = select.select([sock], [], [], 0) 20 | else: 21 | read_ready = [] 22 | except (socket.error, select.error, OSError, ValueError): 23 | pass 24 | try: 25 | sock.shutdown(socket.SHUT_RDWR) 26 | except (socket.error, OSError, ValueError): 27 | pass 28 | sock.close() 29 | 30 | 31 | def make_socket_server(port, on_read=None): 32 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 33 | server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 34 | server.bind(('', port)) 35 | server.listen(1) 36 | t = threading.Thread( 37 | target=listen, 38 | args=(server, on_read) 39 | ) 40 | t.start() 41 | return server 42 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa.param: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PARAMETERS----- 2 | MIIDLAKCAYEAxs9NJJSz/AsqFZNtes5PpXWGqaHygvzHcb+Ur1UCqqa+1BIQjxAp 3 | /5MCxo6CrW8vJv7NwydmNf+fS4mYUfEWTxVBju95Z8b4LjEWmNZSjFtWd2JXJ9sG 4 | MowPuLUiMVuDa7ddiULw4ZWKJz4zWKo1smrByP2it8kjJVZW9YMNbeDQn4rAtCSH 5 | YM1l3OfPTjO7FiM7cxBRrPhBIwldATlYvFn0TI2kbqPYcPhL+S2zE8u6xCuASuYT 6 | 3DHRcEztUhTMcSaKVJGn5fzytc8jWMta2Kw1g4qKj4XA0Lf9VPp37xlKCrwYhB3x 7 | 9U+Ou7+VDFIsy4JSeBFgnmB1P+7UJnqdxQn/G7skmWM5jL4HivGpxSrI7pBrcUMH 8 | J7wjw/2y05uHr2zSiCt9IyEXACAg/jlycgLFNvOMvdjDuDlumtHc2ptrxqsPc5qY 9 | zWZYrb57wnLksO7dvNrcv6aCakcS0I24LKKqY8MGDgnpoGEpQjSe10NP5FKx0z62 10 | xgpfGL8dCwpJAiEAnkVJjX/zoVIpoUK4QYH6qB8plXAfUcRa+CcKV1BpXbsCggGA 11 | IY19GLDlLFQmkbkjKyQXHa/DXroSGZpzyBj1jK618blAP12y2Btpnh6eLi+17psd 12 | GoQChtcnPWTNdlFvnGZtRpn/moGR3CVADKtcf8On82isvu6i1OMrrVXtLgRPWeeZ 13 | pfWIlrijf1yvSAOh/uyuAuYLQihQh/XdcLokyxFmzgfj3mG9Df1Gw36qLuPcv2Il 14 | hBtpQLsGBkM2KyhG4RakCRM8PnGzG1+m4PObXgAo2jOhtQj75LQSCZMIzOq8bhsx 15 | jfMBbqE5P8AgUPLd1t91yEvqJExB5G2OhM+OsmDQx/iLSWq5bWWlgPyNN6ZTKo8J 16 | QCqVK13GqZPsCp8j97E60pokLz1mGtK94i34OPH1ODTv1Skv1g2AiLi/nVcHDERc 17 | iN4uBs1cEKphi8zBalQCsNRsQMJ9Jf5WfRpGKAMtoNQ5nxjVy/FeyCEarnc/zlb7 18 | 6F235fpUX6WmSVCfc3g6C2v1+CQCkyZdysNGgo9E/6xjlXfgcdJBaziPX4i6NF1q 19 | -----END DSA PARAMETERS----- 20 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa-2048.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIDOzCCAi4GByqGSM44BAEwggIhAoIBAQDn+MoB2l9d0MqBjK0JuORloKOkHcda 3 | UjSXH/CHl2DBsR4oasaFTQhL8CNXLLAb+H7aPAZ7EBX6n+DvptXrStnbXTDk/e16 4 | nC9QAoE8aSXaWUzwNwyiAeu5BewP1cJG/O2iSWQTJKtkq2tu66zOkcydsrJxLo7n 5 | ORZJdY+0Y2NAeKu/lAgdN5rj8kBWnYFWyUrBtIteoKGvtSKmX37eaRCPx/yzriJU 6 | g24qoq4Ak2VvrPPpbuk1PpHCFFe/welvQFRax+8nR7yZDC31RAg+nZfC8Q/8x6+5 7 | ncJuno1tEPQUk6z4WCz2aFgVO3e1iuoMaCcklmhUale6NBRm8A7Ui6+3AhUAj6Dy 8 | K1D4oCNZWQzbo/K/sGc0IxMCggEBAN78sZSnFVFZSigPi9smq4kh8teH5na943ih 9 | afgFYJsRb1YGUZrxUNX1conIjNVlEEPt/jMfjMuAs3W+avbNc2eDl6Im1MkgKRYG 10 | oFr04S2ypplQLkrul6sDuli1CFDjsjbZzYJ5Opoygid2bsauCXAta0dUq8ruqub7 11 | m8pwL9nxZw38tD2x6oOypL7sUUz0h9iIp9X1ma31aSKrnQ5XXM49p2ThA7Jn6YNY 12 | uocOSvKeYmBbhvi8Bwls/pfKxOaVq3FHeqp6olbQS/0ZESMJJexuBk7jVpV7T+BH 13 | SRQN5Iv/uaCCMTMB5bX2qukuzxgRFb8tBnOSyPdbbYd0E+Hh44UDggEFAAKCAQB1 14 | 9r3VOP10nLrunBYz3DRCuaz4CuCFnrc+Z2ZMhR4wwer7g3ejbjN0aAMWvjDCTKyR 15 | TDcJtufmWV4nd2+76M5xRygkV40PUft5T9FYl3d0/teC6QA6e2is3L2xURDzlZnS 16 | PwpnZfjF06AA5oHoQOC/cwecRPnhcmV/3dpVN0Fhgn2EfHRN2I07AJJ5N+jEAt+v 17 | CeoLFh+ZMUoMnW/KRE1nE5d3l6f3oMojqap5ebMgf08yuKvvxswlaUWHLVbVioYR 18 | vPiaTyTRIJbUqzIxc/kxrJCXxxTzTbwS1NykN0qjWTogMj/Pp8UT4QMyv72COctI 19 | W0+XyJnW6KRisA/vqr01 20 | -----END PUBLIC KEY----- 21 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048.key: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIDPgIBAAKCAQEA5/jKAdpfXdDKgYytCbjkZaCjpB3HWlI0lx/wh5dgwbEeKGrG 3 | hU0IS/AjVyywG/h+2jwGexAV+p/g76bV60rZ210w5P3tepwvUAKBPGkl2llM8DcM 4 | ogHruQXsD9XCRvztoklkEySrZKtrbuuszpHMnbKycS6O5zkWSXWPtGNjQHirv5QI 5 | HTea4/JAVp2BVslKwbSLXqChr7Uipl9+3mkQj8f8s64iVINuKqKuAJNlb6zz6W7p 6 | NT6RwhRXv8Hpb0BUWsfvJ0e8mQwt9UQIPp2XwvEP/MevuZ3Cbp6NbRD0FJOs+Fgs 7 | 9mhYFTt3tYrqDGgnJJZoVGpXujQUZvAO1IuvtwIVAI+g8itQ+KAjWVkM26Pyv7Bn 8 | NCMTAoIBAQDe/LGUpxVRWUooD4vbJquJIfLXh+Z2veN4oWn4BWCbEW9WBlGa8VDV 9 | 9XKJyIzVZRBD7f4zH4zLgLN1vmr2zXNng5eiJtTJICkWBqBa9OEtsqaZUC5K7per 10 | A7pYtQhQ47I22c2CeTqaMoIndm7GrglwLWtHVKvK7qrm+5vKcC/Z8WcN/LQ9seqD 11 | sqS+7FFM9IfYiKfV9Zmt9Wkiq50OV1zOPadk4QOyZ+mDWLqHDkrynmJgW4b4vAcJ 12 | bP6XysTmlatxR3qqeqJW0Ev9GREjCSXsbgZO41aVe0/gR0kUDeSL/7mggjEzAeW1 13 | 9qrpLs8YERW/LQZzksj3W22HdBPh4eOFAoIBAHX2vdU4/XScuu6cFjPcNEK5rPgK 14 | 4IWetz5nZkyFHjDB6vuDd6NuM3RoAxa+MMJMrJFMNwm25+ZZXid3b7voznFHKCRX 15 | jQ9R+3lP0ViXd3T+14LpADp7aKzcvbFREPOVmdI/Cmdl+MXToADmgehA4L9zB5xE 16 | +eFyZX/d2lU3QWGCfYR8dE3YjTsAknk36MQC368J6gsWH5kxSgydb8pETWcTl3eX 17 | p/egyiOpqnl5syB/TzK4q+/GzCVpRYctVtWKhhG8+JpPJNEgltSrMjFz+TGskJfH 18 | FPNNvBLU3KQ3SqNZOiAyP8+nxRPhAzK/vYI5y0hbT5fImdbopGKwD++qvTUCFDIR 19 | 7yWv6mDP+b+lRsmz40+pAN6+ 20 | -----END DSA PRIVATE KEY----- 21 | -------------------------------------------------------------------------------- /docs/util.md: -------------------------------------------------------------------------------- 1 | # oscrypto.util API Documentation 2 | 3 | The *oscrypto.util* submodule implements supporting cryptographic functionality. 4 | The following functions comprise the public API: 5 | 6 | - [`rand_bytes()`](#rand_bytes-function) 7 | - [`constant_compare()`](#constant_compare-function) 8 | 9 | ### `rand_bytes()` function 10 | 11 | > ```python 12 | > def rand_bytes(length): 13 | > """ 14 | > :param length: 15 | > The desired number of bytes 16 | > 17 | > :raises: 18 | > ValueError - when any of the parameters contain an invalid value 19 | > TypeError - when any of the parameters are of the wrong type 20 | > OSError - when an error is returned by the OS crypto library 21 | > 22 | > :return: 23 | > A byte string 24 | > """ 25 | > ``` 26 | > 27 | > Returns a number of random bytes suitable for cryptographic purposes 28 | 29 | ### `constant_compare()` function 30 | 31 | > ```python 32 | > def constant_compare(a, b): 33 | > """ 34 | > :param a: 35 | > The first byte string 36 | > 37 | > :param b: 38 | > The second byte string 39 | > 40 | > :return: 41 | > A boolean if the two byte strings are equal 42 | > """ 43 | > ``` 44 | > 45 | > Compares two byte strings in constant time to see if they are equal 46 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa-2048-sha2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIDRjCCAjkGByqGSM44BAEwggIsAoIBAQCH3iA891WJE+EDdVRiGB6G2J5MQhfu 3 | BLqd/oCG5OHbOilEHx8VHLKaLYZ8AzvPYHA7j6XRFEX5WFt5jtNrcg+2vmIOxm0y 4 | Rne+NDBYTk6r540r7XQtPg6hSZ2yon8zjd38689fOP+d7phdX7yHSBWsgPvr6bux 5 | pIiaF+oNQDfmwHA9xym8ZUx6ALtAH4xrW1PgGNBEmpX9Ctv1sc7wGxHjWPM0b+PI 6 | uyIvvMGY73j0WldGBeHmNhwWUSIIPDEAbHagQz360wuZm4Az5UzVZFZap+fBakHe 7 | JHDY+9jA4vwzSlC3bRPczU4d4lgAl4kgJrulW242hws+2kWSmkw9InApAiEA8Vch 8 | bJBZDoq+QyM9SzdbQGxbFQTe3+tHMwh/dG+Mul0CggEAbay+aYHQSmJlu8/yQtYt 9 | G0EpFISRV+AaMyBIxfhbslxt5jul4yrwFjg7Lk13JHYdNVvXkyrCpUE5C2gBpOIy 10 | 0XijLeZUVLEoSpGUv9mnJKW24ayar6motzIyZlEAG0NRrzOOzQxVkWFYbk4aBSTM 11 | 8b+9Xi5RC9YE0uD9xBeacShpFwS9xHuEH0vyXXRHf2Zp9LrNZmHyeDfYdaEOIV61 12 | coS0/yEIK/wJaY3y9QkorzbIVjRrHf4eshdCNuTlMyuqvxw1fYN8XEw/7v+96zp5 13 | 9f3jWhMmTRK687mnh3U7w38PxAvcQWr2wxsrdcJPqdWJ06bCAuhGokr2XRt19Z8T 14 | 5gOCAQUAAoIBAEcgdPmSMyGlTD8Q63rw2dzt6kZ5R/NMxrSLuIPW3Clgyxsg4rb5 15 | rriNFXqjqw0MjwU0mQiDO+M1xUMa8DEu4Ei/J+PT/QxrhV3I0CPiHTQSCYUW6BGr 16 | FBH9BRMQXt4JOiuAYUGDztQFKGc10d/bGQPQgOa88iyvN2kDrMLsrj3Nf6L81gZS 17 | TZjUHJxAmH3Xf2T0FCEM0nRzMJSFh7dRqvUyV+I9d++0I+mcAMB1dxCfZPkq2eyD 18 | 0TLj0r3j5nafdOxOC/O5ZcmqSzcMyL7Usp03wDaZGxxLJRikM6WiSkfkffrKUMFc 19 | bDk9hxtEDnlexl9MTGKfFGGeogm2H19wOVw= 20 | -----END PUBLIC KEY----- 21 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048-sha2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIDVQIBAAKCAQEAh94gPPdViRPhA3VUYhgehtieTEIX7gS6nf6AhuTh2zopRB8f 3 | FRyymi2GfAM7z2BwO4+l0RRF+VhbeY7Ta3IPtr5iDsZtMkZ3vjQwWE5Oq+eNK+10 4 | LT4OoUmdsqJ/M43d/OvPXzj/ne6YXV+8h0gVrID76+m7saSImhfqDUA35sBwPccp 5 | vGVMegC7QB+Ma1tT4BjQRJqV/Qrb9bHO8BsR41jzNG/jyLsiL7zBmO949FpXRgXh 6 | 5jYcFlEiCDwxAGx2oEM9+tMLmZuAM+VM1WRWWqfnwWpB3iRw2PvYwOL8M0pQt20T 7 | 3M1OHeJYAJeJICa7pVtuNocLPtpFkppMPSJwKQIhAPFXIWyQWQ6KvkMjPUs3W0Bs 8 | WxUE3t/rRzMIf3RvjLpdAoIBAG2svmmB0EpiZbvP8kLWLRtBKRSEkVfgGjMgSMX4 9 | W7JcbeY7peMq8BY4Oy5NdyR2HTVb15MqwqVBOQtoAaTiMtF4oy3mVFSxKEqRlL/Z 10 | pySltuGsmq+pqLcyMmZRABtDUa8zjs0MVZFhWG5OGgUkzPG/vV4uUQvWBNLg/cQX 11 | mnEoaRcEvcR7hB9L8l10R39mafS6zWZh8ng32HWhDiFetXKEtP8hCCv8CWmN8vUJ 12 | KK82yFY0ax3+HrIXQjbk5TMrqr8cNX2DfFxMP+7/ves6efX941oTJk0SuvO5p4d1 13 | O8N/D8QL3EFq9sMbK3XCT6nVidOmwgLoRqJK9l0bdfWfE+YCggEARyB0+ZIzIaVM 14 | PxDrevDZ3O3qRnlH80zGtIu4g9bcKWDLGyDitvmuuI0VeqOrDQyPBTSZCIM74zXF 15 | QxrwMS7gSL8n49P9DGuFXcjQI+IdNBIJhRboEasUEf0FExBe3gk6K4BhQYPO1AUo 16 | ZzXR39sZA9CA5rzyLK83aQOswuyuPc1/ovzWBlJNmNQcnECYfdd/ZPQUIQzSdHMw 17 | lIWHt1Gq9TJX4j1377Qj6ZwAwHV3EJ9k+SrZ7IPRMuPSvePmdp907E4L87llyapL 18 | NwzIvtSynTfANpkbHEslGKQzpaJKR+R9+spQwVxsOT2HG0QOeV7GX0xMYp8UYZ6i 19 | CbYfX3A5XAIgI/jW8JIBrIiVK4RDMXrpFYpWcVIh1YAFfuPBW+LH764= 20 | -----END DSA PRIVATE KEY----- 21 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-dsa.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIDZQIBADCCAzkGByqGSM44BAEwggMsAoIBgQDGz00klLP8CyoVk216zk+ldYap 3 | ofKC/Mdxv5SvVQKqpr7UEhCPECn/kwLGjoKtby8m/s3DJ2Y1/59LiZhR8RZPFUGO 4 | 73lnxvguMRaY1lKMW1Z3Ylcn2wYyjA+4tSIxW4Nrt12JQvDhlYonPjNYqjWyasHI 5 | /aK3ySMlVlb1gw1t4NCfisC0JIdgzWXc589OM7sWIztzEFGs+EEjCV0BOVi8WfRM 6 | jaRuo9hw+Ev5LbMTy7rEK4BK5hPcMdFwTO1SFMxxJopUkafl/PK1zyNYy1rYrDWD 7 | ioqPhcDQt/1U+nfvGUoKvBiEHfH1T467v5UMUizLglJ4EWCeYHU/7tQmep3FCf8b 8 | uySZYzmMvgeK8anFKsjukGtxQwcnvCPD/bLTm4evbNKIK30jIRcAICD+OXJyAsU2 9 | 84y92MO4OW6a0dzam2vGqw9zmpjNZlitvnvCcuSw7t282ty/poJqRxLQjbgsoqpj 10 | wwYOCemgYSlCNJ7XQ0/kUrHTPrbGCl8Yvx0LCkkCIQCeRUmNf/OhUimhQrhBgfqo 11 | HymVcB9RxFr4JwpXUGlduwKCAYAhjX0YsOUsVCaRuSMrJBcdr8NeuhIZmnPIGPWM 12 | rrXxuUA/XbLYG2meHp4uL7Xumx0ahAKG1yc9ZM12UW+cZm1Gmf+agZHcJUAMq1x/ 13 | w6fzaKy+7qLU4yutVe0uBE9Z55ml9YiWuKN/XK9IA6H+7K4C5gtCKFCH9d1wuiTL 14 | EWbOB+PeYb0N/UbDfqou49y/YiWEG2lAuwYGQzYrKEbhFqQJEzw+cbMbX6bg85te 15 | ACjaM6G1CPvktBIJkwjM6rxuGzGN8wFuoTk/wCBQ8t3W33XIS+okTEHkbY6Ez46y 16 | YNDH+ItJarltZaWA/I03plMqjwlAKpUrXcapk+wKnyP3sTrSmiQvPWYa0r3iLfg4 17 | 8fU4NO/VKS/WDYCIuL+dVwcMRFyI3i4GzVwQqmGLzMFqVAKw1GxAwn0l/lZ9GkYo 18 | Ay2g1DmfGNXL8V7IIRqudz/OVvvoXbfl+lRfpaZJUJ9zeDoLa/X4JAKTJl3Kw0aC 19 | j0T/rGOVd+Bx0kFrOI9fiLo0XWoEIwIhAJUN+c1g4U0Po+7Wx2LUiiZhEHwwn4c/ 20 | ItFl1L631UoM 21 | -----END PRIVATE KEY----- 22 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-ec.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDeDCCAx2gAwIBAgIJANwFLdPfoenEMAoGCCqGSM49BAMCMIGdMQswCQYDVQQG 3 | EwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czEQMA4GA1UEBwwHTmV3YnVyeTEe 4 | MBwGA1UECgwVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLDAdUZXN0aW5n 5 | MRIwEAYDVQQDDAlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhu 6 | cy5pbzAeFw0xNTA1MjAxMjU2NDZaFw0yNTA1MTcxMjU2NDZaMIGdMQswCQYDVQQG 7 | EwJVUzEWMBQGA1UECAwNTWFzc2FjaHVzZXR0czEQMA4GA1UEBwwHTmV3YnVyeTEe 8 | MBwGA1UECgwVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLDAdUZXN0aW5n 9 | MRIwEAYDVQQDDAlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhu 10 | cy5pbzCCAUswggEDBgcqhkjOPQIBMIH3AgEBMCwGByqGSM49AQECIQD/////AAAA 11 | AQAAAAAAAAAAAAAAAP///////////////zBbBCD/////AAAAAQAAAAAAAAAAAAAA 12 | AP///////////////AQgWsY12Ko6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsD 13 | FQDEnTYIhucEk2pmeOETnSa3gZ9+kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLesz 14 | oPShOUXYmMKWT+NC4v4af5uO5+tKfA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD///// 15 | AAAAAP//////////vOb6racXnoTzucrC/GMlUQIBAQNCAASLXUxx99bGo0ljQlxH 16 | n8tzJB3J3dEt8TqftwTeINBYAJNU9onHL4cr9/k9OzTtnnsOPVdC33gDC8wxxgPX 17 | n2ABo1AwTjAdBgNVHQ4EFgQUVKpUcGw0Gm3rXZfXHvzVJDyKDtcwHwYDVR0jBBgw 18 | FoAUVKpUcGw0Gm3rXZfXHvzVJDyKDtcwDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQD 19 | AgNJADBGAiEA9D5hQQo7QqQNufAlMB4Dq0RWytRShGgp2gu5C6BCSJ0CIQDE6YAV 20 | vKH2xayaPtml3X1TP+BmNORDjILENbGqBPaJ9Q== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /tests/fixtures/badtls.io_ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDlTCCAn+gAwIBAgIIVvpPzLyqk+0wCwYJKoZIhvcNAQELMGoxaDAJBgNVBAYT 3 | AlVTMBQGA1UECAwNTWFzc2FjaHVzZXR0czAOBgNVBAcMB05ld2J1cnkwFgYDVQQK 4 | DA9CYWQgVExTIExpbWl0ZWQwHQYDVQQDDBZCYWQgVExTIExpbWl0ZWQgUlNBIENB 5 | MB4XDTE2MDEwMTAwMDAwMFoXDTI2MDEwMTAwMDAwMFowajFoMAkGA1UEBhMCVVMw 6 | FAYDVQQIDA1NYXNzYWNodXNldHRzMA4GA1UEBwwHTmV3YnVyeTAWBgNVBAoMD0Jh 7 | ZCBUTFMgTGltaXRlZDAdBgNVBAMMFkJhZCBUTFMgTGltaXRlZCBSU0EgQ0EwggEi 8 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSHu3OR1RS0D2xLKGK2Ts5eLoO 9 | /P+IXst5WPdaD9UwGI8edfAy3U8wcMFDoXNhBQM+ZW69Z5uOZVxs704+j5cgCEAT 10 | LbtyIrF2X8BixXFzrJFd+kpojURheyxML20GbZsznJgKzYvGqFqWa/1lYwy/v0SP 11 | RNGPEkjFXb/tItDwrDxcuDzY6zjNlW5MwqvS11P1H8eg0idUrANY2MzT8+oyH3Sn 12 | JLCsmulnmj1b6IZZDN4i8rKXEbH14jIsANHIgTqvS+kJf3Z1PqHAOUqVGlO3SDZd 13 | KIqZ8olS6ty9/pco6cxvX2Te9m1z5f1fSrdxAtx7lHM3pdvs9DhML+8FAewDAgMB 14 | AAGjQzBBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFGEbxkZbhgwiZRAMx7Vs 15 | VCRXl/tkMA8GA1UdDwEB/wQFAwMHBgAwCwYJKoZIhvcNAQELA4IBAQBKv0TJoRhd 16 | wg7dPOFDVuKaLtuVzXEeUWfsA86iW4wjXFO/npI+1exSBX92MhsWk5Gjn9dO/Hq4 17 | EZ1pMJ8hFdrOXoEHlvhnZSavtoy25ZvEoxJ9XWYPqWCmwdfB3xhT4hoEaIlu5Azf 18 | Fw/QV5oFV8SYgwClQ+fTStxdW7CBKEX55KPUn4FOOXV5TfbLOJj3w/1V2pBTKn2f 19 | 2safgWyIpNw7OyvYVICdW5/NvD+VTBp+4PfWkTfRD5LEAxqvaGXupBaI2qGYVibJ 20 | WQ77yy6bOvcJh4heqtIJuYg5F3vhvSGo4i5Bkx+daRKFzFwsoiexgRNTdlPCEGsQ 21 | 15WBlk3X/9bt 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /tests/fixtures/macos_12_public_key_export_issue.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDuTCCAqGgAwIBAgIQfCoOUTBOfHengHo4iS1DmjANBgkqhkiG9w0BAQsFADBM 3 | MSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xv 4 | YmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjAeFw0yMjA4MDcwMDAwMDBaFw0y 5 | MjExMTUwMDAwMDBaMFsxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWdu 6 | IG52LXNhMTEwLwYDVQQDEyhHbG9iYWxTaWduIE9DU1AgZm9yIFJvb3QgUjMgLSBT 7 | aWduZXIgMS4yMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArrYtuWRO 8 | QRqEM8cSyLzpgbIVeZ7n/dG7DIpGHcl4SBo99ji0IEFab/Mi7k2ML9hTQ8jaWUPa 9 | zllvmpMrKqzU/nobvcq5XGewtXPY8XNQfHDch9ruqI5Xii/mxCfX0dxbP5pHOm2Y 10 | FfJe+ObYHpZy4jtifd3GtYlGODnfSkrL+s6NwZX3b4pAZVt7MWjKg3UQI5W3hskO 11 | zhAdOmhWacMeM4HeyHCwMz/S9caQ2v+g8ZC8eTQoeqfGzknvMNl9GbipED4CWYgG 12 | ++4cKYmIbXlgdOm1I6jDtVjWjmXahQKYGh/EC39wlVukWoUhtSfE6oK3TXq5hdg3 13 | JXcAlu970y0ErQIDAQABo4GHMIGEMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAK 14 | BggrBgEFBQcDCTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQpps1+5UkBfCYf2+XI 15 | r2Cd+Tw2fjAfBgNVHSMEGDAWgBSP8Et/qC5FJK5NUPpjmove4t0bvDAPBgkrBgEF 16 | BQcwAQUEAgUAMA0GCSqGSIb3DQEBCwUAA4IBAQDEdJsZuNVxwdR4jSluEWXmVW16 17 | RDarknBhHxd8Cq1q4FPfN+BcltDoBUDISEvOHffKm1VPCjOTxvWuvSd630u6TQSn 18 | 9Uut/IrjeAnq1eRrEkdDE09772G/Q5tfBHGB+cZdFqICv94YqGHlT1f5tNWfTmV6 19 | /3wd86AxrBOWcYnd4HgXBid5kBiRoFcP4v8z94A9zuPsZDLmHrbrqqLH4zi9Z+ak 20 | YMCBTfYQUAJuT/kUbGX4PuxDYT3CnYW54ukUrfmsWHtSUA/cUGY+WlyNxG2y+cD+ 21 | 3GgZxwTQpy7ik8wj1McBYh6X99Nud8D29Hfkj9YtBIqrjPXUM9F2ik+x0u3l 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /oscrypto/_win/_kernel32_ctypes.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import ctypes 5 | from ctypes import windll, wintypes, POINTER, c_longlong, Structure 6 | 7 | from .._ffi import FFIEngineError 8 | from .._types import str_cls 9 | from ..errors import LibraryNotFoundError 10 | 11 | 12 | __all__ = [ 13 | 'get_error', 14 | 'kernel32', 15 | ] 16 | 17 | 18 | try: 19 | kernel32 = windll.kernel32 20 | except (OSError) as e: 21 | if str_cls(e).find('The specified module could not be found') != -1: 22 | raise LibraryNotFoundError('kernel32.dll could not be found') 23 | raise 24 | 25 | LARGE_INTEGER = c_longlong 26 | 27 | try: 28 | kernel32.QueryPerformanceCounter.argtypes = [POINTER(LARGE_INTEGER)] 29 | kernel32.QueryPerformanceCounter.restype = wintypes.BOOL 30 | 31 | class FILETIME(Structure): 32 | _fields_ = [ 33 | ("dwLowDateTime", wintypes.DWORD), 34 | ("dwHighDateTime", wintypes.DWORD), 35 | ] 36 | 37 | kernel32.GetSystemTimeAsFileTime.argtypes = [POINTER(FILETIME)] 38 | kernel32.GetSystemTimeAsFileTime.restype = None 39 | 40 | except (AttributeError): 41 | raise FFIEngineError('Error initializing ctypes') 42 | 43 | 44 | setattr(kernel32, 'LARGE_INTEGER', LARGE_INTEGER) 45 | setattr(kernel32, 'FILETIME', FILETIME) 46 | 47 | 48 | def get_error(): 49 | error = ctypes.GetLastError() 50 | return (error, ctypes.FormatError(error)) 51 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-third.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID+zCCAuOgAwIBAgIFAJOEAykwDQYJKoZIhvcNAQELBQAwgZgxCzAJBgNVBAYT 3 | AlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMR4wHAYDVQQKExVDb2RleCBOb24g 4 | U3VmZmljaXQgTEMxHTAbBgNVBAsTFFRlc3RpbmcgSW50ZXJtZWRpYXRlMRIwEAYD 5 | VQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhucy5pbzAe 6 | Fw0xNTA1MTEyMTQyNTZaFw0yNTA1MDgyMTQyNTZaMIGgMQswCQYDVQQGEwJVUzEW 7 | MBQGA1UECBMNTWFzc2FjaHVzZXR0czEeMBwGA1UEChMVQ29kZXggTm9uIFN1ZmZp 8 | Y2l0IExDMSUwIwYDVQQLExxUZXN0IFRoaXJkLUxldmVsIENlcnRpZmljYXRlMRIw 9 | EAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhucy5p 10 | bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMAKLNVdAlEUbBeAKfSz 11 | 3Ymd78tt6l2jjEdz4QMqFkYDSbl5pMB0RP+yRKHVSr+gL99F3wAXHoMb81bFVItL 12 | dyx3vK1qK2FhMvmuw8yNUy3o4aIwE/Neobp4eWLWNWwdqmPyNpvc8g8HdVsnk97u 13 | 9ZUGoiHEblvLZ8uijvbxK5hbCkKHjOhHCDT5egtPKOyFqOWJ1WzINICRfEeIjZM0 14 | cuLUWVJmzb9QJ8CmN4O6R1rYK131eIZ6FWlJTpx1n7MvygTOmDiyVE0NMfJFTzdj 15 | a8kQxiwdyqN9I9OfHqRefh8TCQBuAguuwPUyAu9Ve45eDqzfeWrgoyinZ0KXiqrH 16 | 5DUCAwEAAaNCMEAwHQYDVR0OBBYEFEQ44OAmhb+Yhtwb4R31MjC+q6wNMB8GA1Ud 17 | IwQYMBaAFNIK/S4l0bch11B+u6R9vzTvUl4CMA0GCSqGSIb3DQEBCwUAA4IBAQAb 18 | Wq6ueTRDgY5hDAcVn3j5Eaco88rzhhzgfnH4GSES/QOQlOEFbj0/zzAk7LCgcXq3 19 | 7ud/cbA0tuoFmra9Q4D3YEcL0xHiDlXkvzcy2MJ6MysRiQftvHE9o1f8lxWqEfHK 20 | EtL3espMfVE8zisiA7kS07Jm4t7OSBte21JVwqC+dlqYca2T0coJ47Fw/yVvlaQU 21 | O5h6wvHuUS4L0myNdW+/V2yoUex8C9OK3qs8H61ULcgoVnvn/DJJerad53LBfJR3 22 | jmmamq6Pu7COWU07N7MOGkrG8bwal64ncdzwvTtBj9NdoDataw9LvjyAGxYDSY6X 23 | KiqBZoOHm108hjAfW+XC 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-inter.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEBDCCAuygAwIBAgIDGEN5MA0GCSqGSIb3DQEBCwUAMIGdMQswCQYDVQQGEwJV 3 | UzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmV3YnVyeTEeMBwG 4 | A1UEChMVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLEwdUZXN0aW5nMRIw 5 | EAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhucy5p 6 | bzAeFw0xNTA1MDkwMDQxMzlaFw0yNTA1MDYwMDQxMzlaMIGYMQswCQYDVQQGEwJV 7 | UzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEeMBwGA1UEChMVQ29kZXggTm9uIFN1 8 | ZmZpY2l0IExDMR0wGwYDVQQLExRUZXN0aW5nIEludGVybWVkaWF0ZTESMBAGA1UE 9 | AxMJV2lsbCBCb25kMR4wHAYJKoZIhvcNAQkBFg93aWxsQGNvZGV4bnMuaW8wggEi 10 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/PVOdogtqe2gqXZ20dWB5NFxj 11 | JX6z6A57zGqT11OfiNmckIqxMRK8eToR69/DJmVNbQTJy/cFexZ33db+UrtEItxO 12 | klFFbG/6TjmqsOYF87TkJqGX7zXs/Z7D1Xl0/2CNh6vPPPbi/o1FHtKnk4HYOnyU 13 | LRMxxtt06O/u//wdnWXiSAOKOasLT7eP6Fuok28+BeQ29GB3UNL8oC7biyhv89yN 14 | VhDlHAkk+zfrGP4dNqxOY8SkwI0GYki9skEckwf7Nyz+vA8zVJaIymte/eRicCFF 15 | YFxh+QtQhyxF7DwsB5/XIgEWKRXnd/ivyORMlIVc83CHCM4ryvXgG0+I7WuZAgMB 16 | AAGjUDBOMB0GA1UdDgQWBBTSCv0uJdG3IddQfrukfb8071JeAjAfBgNVHSMEGDAW 17 | gBS+QoU9zP/j+SgCj35YVrT9A1zqSzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB 18 | CwUAA4IBAQAKnbphxDozjob2qobtO5QRfZNwIANr/Pyz6SoD8UnJDfZAg9y1jb/I 19 | OutcURjYfV4vyLKI5oyhepyBMkuwvnB/lRpLERAwv5lJgq4sIGDn5Sp56yYcxazC 20 | QXLyG5YJ2Q29kVuq9//IE/dkLVaP444iJZZ7IgrGN4EFQwvFRVa6toeVpwzp8kkn 21 | 5eQaiKQYt/1dVsQ5mv8ksT/gNJRMD4xJ7xvlats+Jc6cyygJk18h+JqMYDoFTTu6 22 | fJmjtnjPFg+XU0q9GnJfrW+FjxYGMv+5tv0pJrujEq7+8gz5A4viSCzHHoc4O/Qs 23 | 0Jt6dQ/xmGYswxjrR/ZgsSjPx3lib7XC 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /oscrypto/util.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | 6 | from ._errors import pretty_message 7 | from ._types import type_name, byte_cls 8 | 9 | if sys.platform == 'darwin': 10 | from ._mac.util import rand_bytes 11 | elif sys.platform == 'win32': 12 | from ._win.util import rand_bytes 13 | else: 14 | from ._openssl.util import rand_bytes 15 | 16 | 17 | __all__ = [ 18 | 'constant_compare', 19 | 'rand_bytes', 20 | ] 21 | 22 | 23 | def constant_compare(a, b): 24 | """ 25 | Compares two byte strings in constant time to see if they are equal 26 | 27 | :param a: 28 | The first byte string 29 | 30 | :param b: 31 | The second byte string 32 | 33 | :return: 34 | A boolean if the two byte strings are equal 35 | """ 36 | 37 | if not isinstance(a, byte_cls): 38 | raise TypeError(pretty_message( 39 | ''' 40 | a must be a byte string, not %s 41 | ''', 42 | type_name(a) 43 | )) 44 | 45 | if not isinstance(b, byte_cls): 46 | raise TypeError(pretty_message( 47 | ''' 48 | b must be a byte string, not %s 49 | ''', 50 | type_name(b) 51 | )) 52 | 53 | if len(a) != len(b): 54 | return False 55 | 56 | if sys.version_info < (3,): 57 | a = [ord(char) for char in a] 58 | b = [ord(char) for char in b] 59 | 60 | result = 0 61 | for x, y in zip(a, b): 62 | result |= x ^ y 63 | return result == 0 64 | -------------------------------------------------------------------------------- /dev/ci.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | import site 6 | import sys 7 | 8 | from . import build_root, requires_oscrypto 9 | from ._import import _preload 10 | 11 | 12 | deps_dir = os.path.join(build_root, 'modularcrypto-deps') 13 | if os.path.exists(deps_dir): 14 | site.addsitedir(deps_dir) 15 | # In case any of the deps are installed system-wide 16 | sys.path.insert(0, deps_dir) 17 | 18 | if sys.version_info[0:2] not in [(2, 6), (3, 2)]: 19 | from .lint import run as run_lint 20 | else: 21 | run_lint = None 22 | 23 | if sys.version_info[0:2] != (3, 2): 24 | from .coverage import run as run_coverage 25 | from .coverage import coverage 26 | run_tests = None 27 | 28 | else: 29 | from .tests import run as run_tests 30 | run_coverage = None 31 | 32 | 33 | def run(): 34 | """ 35 | Runs the linter and tests 36 | 37 | :return: 38 | A bool - if the linter and tests ran successfully 39 | """ 40 | 41 | _preload(requires_oscrypto, True) 42 | 43 | if run_lint: 44 | print('') 45 | lint_result = run_lint() 46 | else: 47 | lint_result = True 48 | 49 | if run_coverage: 50 | print('\nRunning tests (via coverage.py %s)' % coverage.__version__) 51 | sys.stdout.flush() 52 | tests_result = run_coverage(ci=True) 53 | else: 54 | print('\nRunning tests') 55 | sys.stdout.flush() 56 | tests_result = run_tests(ci=True) 57 | sys.stdout.flush() 58 | 59 | return lint_result and tests_result 60 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pss.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEgTCCAzigAwIBAgIUHUhBPuha4XBidArC3PoG4Y2NU3IwPgYJKoZIhvcNAQEK 3 | MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC 4 | AgDeMIGfMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTmV3IEhhbXBzaGlyZTERMA8G 5 | A1UEBwwIUGx5bW91dGgxHzAdBgNVBAoMFkNvZGV4IE5vbiBTdWZmaWNpdCBMTEMx 6 | EDAOBgNVBAsMB1Rlc3RpbmcxEjAQBgNVBAMMCVdpbGwgQm9uZDEeMBwGCSqGSIb3 7 | DQEJARYPd2lsbEBjb2RleG5zLmlvMB4XDTIyMDMxNTAwMDAwMFoXDTMyMDMxNDAw 8 | MDAwMFowgZ8xCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1OZXcgSGFtcHNoaXJlMREw 9 | DwYDVQQHDAhQbHltb3V0aDEfMB0GA1UECgwWQ29kZXggTm9uIFN1ZmZpY2l0IExM 10 | QzEQMA4GA1UECwwHVGVzdGluZzESMBAGA1UEAwwJV2lsbCBCb25kMR4wHAYJKoZI 11 | hvcNAQkBFg93aWxsQGNvZGV4bnMuaW8wggEgMAsGCSqGSIb3DQEBCgOCAQ8AMIIB 12 | CgKCAQEAnDpE0BB8DGErRF2u7pSMx297L9j28C6G3WbKi9KUd2NI5l8qLIp8TrLN 13 | bgQQX+UzfRXaqdESycA5I0RRW+QtHITBzjXnPNWlJGUf5VNvNa+GEOPzNjo93QpM 14 | FYOB+QeX6O4BM+gkqWDt7R+2/VUHuisJIJsfE8vBZkxcq9pQyaMAdcUzgvQN3dB+ 15 | HxUdj6DNi4QufcBDNB7RFJM+4Sk36u+723cnBn0YhpkyYbgzRua/u5omsS7fZH3E 16 | y8+cadfGofWoZKLAeTzYgrM/2it5gXBYudD5OURK/RUOKBHzbmY3IwFDGtJBH3j0 17 | Xc5JBVhUWOWK4owkS/RiPvZzY0MUrQIDAQABo1MwUTAdBgNVHQ4EFgQUNwXHVWt9 18 | syO/IPs7hREMrYi5KYIwHwYDVR0jBBgwFoAUNwXHVWt9syO/IPs7hREMrYi5KYIw 19 | DwYDVR0TAQH/BAUwAwEB/zA+BgkqhkiG9w0BAQowMaANMAsGCWCGSAFlAwQCAaEa 20 | MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiBAICAN4DggEBABGYo8yF9Q69i+pm 21 | mi3sj+SXpx5GoSDmQoRp7J/n3KedERftR/j5T9w4py04K2pL4bl+OHmE8WJCmXWr 22 | RuN9M12t0qwF86koRcZz1NlsVYCBVBJSYGnd3TOGyIKbq8M/WMXqAe2UiK+hYp16 23 | MqfQEvj+pAAolWaxwC2/wbE8Isse4eXr/ax0SmyRMVncs6ivW6z5IGDgJdgolA2d 24 | pyfqQGFSABMu9AvQNnYX0vsxmSZH9NqU4Q/JJ2EO8ydvwH2TbQnqcIXFNccjV0L1 25 | upXJ9oeT14Ia40PhzY9aJrSB7hMoFoRGRDSwFxKPjr81fM9312ZmZDJTMlMPet8d 26 | eLIy5aY= 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-1024.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEgTCCBECgAwIBAgIJAMyl5GyXYow+MAkGByqGSM44BAMwgZ0xCzAJBgNVBAYT 3 | AlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMRAwDgYDVQQHEwdOZXdidXJ5MR4w 4 | HAYDVQQKExVDb2RleCBOb24gU3VmZmljaXQgTEMxEDAOBgNVBAsTB1Rlc3Rpbmcx 5 | EjAQBgNVBAMTCVdpbGwgQm9uZDEeMBwGCSqGSIb3DQEJARYPd2lsbEBjb2RleG5z 6 | LmlvMB4XDTE1MDYxNzEyNDAxNloXDTE1MDcxNzEyNDAxNlowgZ0xCzAJBgNVBAYT 7 | AlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMRAwDgYDVQQHEwdOZXdidXJ5MR4w 8 | HAYDVQQKExVDb2RleCBOb24gU3VmZmljaXQgTEMxEDAOBgNVBAsTB1Rlc3Rpbmcx 9 | EjAQBgNVBAMTCVdpbGwgQm9uZDEeMBwGCSqGSIb3DQEJARYPd2lsbEBjb2RleG5z 10 | LmlvMIIBtzCCASsGByqGSM44BAEwggEeAoGBANQtXrtb/uhAiavzgGSQ8GqnkOp+ 11 | WWX7WsX0K0QFKWaLPeZtodxo6hYjvlf3Tn8N1aPeqVfxhRGkFnXNcnv6a5cWHBPm 12 | egAA61KrbJAnHUv7LESbyZESZCITOKv8h5pQFk+4Uer463NbSG4lJ43qUcCQLOpC 13 | FX20HCIdYcw17h+fAhUAyEEbj/IEAx43Snz7/Ch0FbADEykCgYAXLzStWUnpWQYr 14 | mRZEzA8YlvqsYcs9AYilGMu0DqwRr632Dba2Rzs1d0ZsU+aooOaBS/TJcY0rDXR2 15 | 3s0TrHXr936YasXefRqX0uvktr270khAZvlxOLKTNCae7c4k/wcSIUbd6ApzWuz1 16 | 7/MY5IRDYvhhLHuWKCoqKm5VV6ba0QOBhQACgYEArrmT63ySk3VhckLcZuQzY5fQ 17 | J94DY58zCCldk6qrHNOj1+fz/rOqTpnxgZ7UqhibVXiD1BHITBlrNDQXW+pnWq6z 18 | HtoXwiO3UcNuY2oeI74c6NVDgXXEmBIKcqBrHzQvVwNnuhqkUnHEIQIcUDLOOehJ 19 | pkwJ89/2hCeocgMpjO+jggEGMIIBAjAdBgNVHQ4EFgQU6/EGkD/7OzwyCFqOaA4t 20 | F+xD7uQwgdIGA1UdIwSByjCBx4AU6/EGkD/7OzwyCFqOaA4tF+xD7uShgaOkgaAw 21 | gZ0xCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMRAwDgYDVQQH 22 | EwdOZXdidXJ5MR4wHAYDVQQKExVDb2RleCBOb24gU3VmZmljaXQgTEMxEDAOBgNV 23 | BAsTB1Rlc3RpbmcxEjAQBgNVBAMTCVdpbGwgQm9uZDEeMBwGCSqGSIb3DQEJARYP 24 | d2lsbEBjb2RleG5zLmlvggkAzKXkbJdijD4wDAYDVR0TBAUwAwEB/zAJBgcqhkjO 25 | OAQDAzAAMC0CFQCj4RcGomwsBiMNN549e4Mw1s0wlQIUA2UWE2RTggnBYWAdKGZP 26 | AL4GYlQ= 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAvVsoB3Ti5kosAiq9UN54F6rsUDZ+lLnGRZyodtqvO8PX/8Qb 3 | +QJCKsmvfTae6yMkXF2OLdpUNEY/HT5ZbAZqPL6Ta9ibS3uZI/9uZUYIzTqh+8Nl 4 | QxZXUt3hLIiceu5LVCPjEeUHv9n6YBZikK52YAUgkSC2UcPN7Oq7qQsRU0HWVssf 5 | 6U83K6fBcL0VJhaF6SMDIFp+UUGShBX3SNd+5Mbs+HSbgMB9mfmfmv9im+YoQOQ+ 6 | RpbWYC3yp6XhvxGSUCHy3y9NJ+9C5N7LDcYVwp7srKYochoMPHDCcAt8ZY1re3ti 7 | hVk/19WuCGRHvcMEKccjHba4MdROTAGYh1QvXwIDAQABAoIBAE8NH0j9ozxA+t5s 8 | uVxpg/ldggp6tZ2hcQTewfXclgt9V0+Pr53lM3ppeLntc6r2oNdut0ytOToZmX+7 9 | 59kRVIjHhwQfCbYZg3VjzdK5yjLjp3xTtpKrYQlXWAoffjRUB165HLL7yqBtf/ld 10 | XwjHzOOJQG9WGMdJ105xMKcB19nJijgY19Eg/9svNQq6wwfDACKAYXusoz8ApGoz 11 | T6b8+o2nINQHaCgmf5qPbg44JfX3+k2er7bK+mk7cuoOIWOB5ItSfyq4GdbLM+XW 12 | /GIGkclXUOWRDmitudoLKtv5WtvYrsWe1iznHIrlIy7gI1i9Z+V9mEYb+aZPDtjB 13 | 4Kuy/gECgYEA7VBSov4Oph78yiIIwmJ6T+4+tdbJQ2lxV7GusSVjj76vmZASNJ7E 14 | gpR5woH1APEyHgnUkoRK8fGUHp+Lxms2rrYivcjXZ4DTvpZ/qQVJBNJ4pVyWn+iq 15 | 7gLro2wotiLDBzeG9oo46Czn0QCOk7tofxSbcEkhkO+Uuwc3ZSlEOfcCgYEAzEQf 16 | HQNFzBHqlvPVbfy9+IxnG+u33WEKSMr+1ek/hae43+D4vndBX1DPuhaWUapsU9Gg 17 | A5YIXOhCIrnx4MbMvcBn55CWIf7J+dEdPaUOGN+YtYbV29U45nX0dS4QXxBOVZwn 18 | qUBRDwptSFVaLHDUrOC4vnkST6iRHh/OJ5AuG9kCgYEAm8+SAiwWSCGuTbSc1au8 19 | rMA68j7sc9NGNJKXpP1sahODzapXGa9oTGfZrciPqSezhR9lLzGm10WKv7R3HDaG 20 | d51kIAE+1Fk0LT044itzLrRVvBSXXLRxjcXjGrBH5pXaQOHHPhWwmVfqeEIKWprA 21 | WDeaetW5MSTsHQP27fdzMS8CgYA4DXl8PKmqlkAJrF+lDvYSfnTM9KI/3aE02H+V 22 | s6v6wUu6I8IeghsuTL60Ef6t6lZPqfZ/BWzGEfYUEXKOe/8zEtlwcfzA12oVY4zi 23 | naiAqtr89UM6UAiNNVEf1sQnUhIs6+z2RO/5cKMMdl+IUm4KAqCvpAmiUl+AJLot 24 | oSMGAQKBgQCcWwsTbMnFJrBxHVe05C8Y/DeU1Cj7TlKKuYSidASus0KhJv7bkSIE 25 | N3x3RJFDVrkEW30AH/b+oMKHSjileWP7NLCT4Y/d/ZybhavhOziol408GsZNe6YV 26 | Tzk/USt/a4ZBK1K5RlHmTiFYNXvecXqzHnk77OzCMsJtteW/gr1ABQ== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-inter.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEAvz1TnaILantoKl2dtHVgeTRcYyV+s+gOe8xqk9dTn4jZnJCK 3 | sTESvHk6EevfwyZlTW0Eycv3BXsWd93W/lK7RCLcTpJRRWxv+k45qrDmBfO05Cah 4 | l+817P2ew9V5dP9gjYerzzz24v6NRR7Sp5OB2Dp8lC0TMcbbdOjv7v/8HZ1l4kgD 5 | ijmrC0+3j+hbqJNvPgXkNvRgd1DS/KAu24sob/PcjVYQ5RwJJPs36xj+HTasTmPE 6 | pMCNBmJIvbJBHJMH+zcs/rwPM1SWiMprXv3kYnAhRWBcYfkLUIcsRew8LAef1yIB 7 | FikV53f4r8jkTJSFXPNwhwjOK8r14BtPiO1rmQIDAQABAoIBAFkm5cwetuO1FCJr 8 | 8hEmhwr59ffiiuajz9y2txik0T8WNRxf5cgk8G8ctI2WQIJha+hkYk8Q3t+XOio3 9 | KPr25oYlGj8mxuxuWOV/gjKotRMhQbr6p2qFAcaxlUoGQtDgHMrd7KJ38UBxGrqW 10 | W+3zPhznZxxMxx31bmlaDkCE5auH3WRBVj5tVd7L75It0BStFG/smzF45S+7/7nS 11 | k3hWgWLvdZNYrE46LShyZ0r/RktrgxHMRZV3fMEnMt1gqpHCyFXdt3jb2hs0ku1X 12 | OKFcCBUd918/oHWW/jXsMsemM0aORskJRHT6ZA4sT4fnP6qYEydY2+2Gh8KxLOur 13 | V2uZ14ECgYEA9u27PfPCW/XWNtmmiWTw0DqJ/V/HeqpXs01AEci1GxkG9Ej0PdI5 14 | V+QPi9s8Kn/AVnMo0zkizKiExu2bHqTXKxtif76qZjL5AkIeAq4asIzOn5Pd6GBN 15 | lo0IT6HMLBklM1v/WIky/oExQ49fnLM583oWpuUUEX0Bg/Rze+HFic0CgYEAxkPc 16 | YuqyZXA49qOkz363H74YiEXQIocMKm27CIl37EezqBfArfJR8HGoTk3hX8JQvgxw 17 | LDGoMKRZ4xtW0RGqFNd3yn0bweDuISn3Gdrg2B+VvPlgq7wG240trcCsVsEGG5Pe 18 | xlP+IHG8XsChhjFSAiv2TMNij2zRfgNQ7QAZLP0CgYAQRO2XUV427OWmS4TbfJkZ 19 | PyIkXZEpFdwdZjOYeF7mYCnDIqNlB1rb3ZzgnBtEuZIUoBXKhPM0BM5qxPD5febn 20 | YjCFNizH+wfJDE4p4wrDIyPiA74VN3MlPjmT9ZccOLPoxGD4lmGTvzNdvi6QhoaE 21 | 8kBX0rQVyuS0qwCI4wE+6QKBgDP0mI47XqCCdgr7+zZ8yFRDJn6ffNlvdlqwArFM 22 | BOcgKw5DmzR6KcrOngJXGlZTv4DuFX8fTCnjB8Mh6PBEpsNra3LesiVuYjjCnIRj 23 | /UPlkwHAf/rA/TMPngbIVOEvGACmEVz7qb6qz2gtJqbZydnT12lqUiuvon5ZNB3H 24 | RtGpAoGAFaYxkr2+v3Bax3dJrpHb1NgY42vKajo2Tb9hHm65hBdCm0G2toOGDpui 25 | wq9k2Ed17kW1NPetGR1H5T2uto/gsz0Y9I6y5M5jYn9OWm4ZjOlj4Lr+VHlX9Q6C 26 | kUq8NRho40913BcYjR9LhKVP7rsBLhvtUGaet/IsP1AgIqX+Tjc= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-third.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpQIBAAKCAQEAwAos1V0CURRsF4Ap9LPdiZ3vy23qXaOMR3PhAyoWRgNJuXmk 3 | wHRE/7JEodVKv6Av30XfABcegxvzVsVUi0t3LHe8rWorYWEy+a7DzI1TLejhojAT 4 | 816hunh5YtY1bB2qY/I2m9zyDwd1WyeT3u71lQaiIcRuW8tny6KO9vErmFsKQoeM 5 | 6EcINPl6C08o7IWo5YnVbMg0gJF8R4iNkzRy4tRZUmbNv1AnwKY3g7pHWtgrXfV4 6 | hnoVaUlOnHWfsy/KBM6YOLJUTQ0x8kVPN2NryRDGLB3Ko30j058epF5+HxMJAG4C 7 | C67A9TIC71V7jl4OrN95auCjKKdnQpeKqsfkNQIDAQABAoIBAQCyxkYqcqV/eXWP 8 | Ax8L0I3CWScsyCxP87rZocStP3bwworVgaqgBx1ctEY0Ke2mKqemQNNysBMVluWX 9 | t6gW7LAK04TwI1AzHVtpGQrp1/7BVHUImZ1ZCJWilBjcq/Gbrpo65Pd1beBhoV3c 10 | +CEufmJc04oHyWe7SMZdyf0xYh5le2yq6qbRjihjOdGtGxJF/BkGT7MVGZwOE21Z 11 | wTtW9hto26rCSFoUDhnHNQLEBNSsxwIov2VJ1lp7VN6ruvisN3SddJl9068dvorn 12 | cLyYcelR7i9efM1/VdsI9xmQOaLF9p8HizYex/euQ7vyMp3APAepf5pCT4DkpZpD 13 | PmlJoUCBAoGBAPLwQpliNUofOIfmqiQ3/v0c5tTapoG9NwFyRtRfnm46Ou810OPs 14 | e/L89Wreo2+sfW54Y7J2ftqI6+XmuGRGCv0AgeZaYC8Hx7+o3uUitNTcwvVFqdKM 15 | SmDAhzy/WZGhHE5dDEAmXEDF0NNSgHWjNVwrewT6+RHdpv4EMavum5oRAoGBAMpd 16 | W62XfLVCVNxUCjRCMwozf46Cybx3NLwVtJKbB2kGDqUXYLs4f4F0OzFt5XPIluFA 17 | kQSro5CrexVXMhcIigOadk6dGegJPGFaAmw5ZSjyGLjr1wmaskCzTBqguDUta1Up 18 | IA6swmYK9eR8tHZNNFRBkL/KNEY9+ZwWdQ62WuPlAoGBAN0nMrmG2ZQcT84HgaNv 19 | BkVM5iWm1iUNJuG+MhRq50LY54WTrBGQ2lUdShx7iLTEhXrnRXrUvC4crwKewgUm 20 | biJbL+WPKDgoEQK8rAxTR+LvBNtbC3mMFLl3CqWWW+diju4XbmuHgDvG2I9Hb4Gn 21 | jY/WVSr3fX1yFe7vyngFwsjBAoGAZkO9k8EtTXBi8CEsMvKNVodl27/ucOaQ6MfT 22 | RA9CNGnSNs3UnWhUzzfMvhL6VIO288gsQP74HqD6B3PUJV20WVPSm7G6qM8aC1xw 23 | Qv7SR1no8nKEbh8WG6pAOGimDoGQby3kPGZDq0u4ranzjKFBY57qpnFp72FcZevX 24 | ZgLzdZ0CgYEAzhkOEjC82l1tm9oWbkrdLdx/Sox2mBEnxkkvt30oRUTt89xA2epS 25 | q/4zBCTSCg+OhHfASg+ek8zMOtKnOQnis8F2Z6lvboA1Hg/iWv6mZ7EYj78C5yZh 26 | nsdKM+U/5sxUa4RCc0Aj5s8irpZZfc0SxwmYZH/NMQuY3e3HMuyGLKM= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pss.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADALBgkqhkiG9w0BAQoEggSoMIIEpAIBAAKCAQEAnDpE0BB8DGErRF2u 3 | 7pSMx297L9j28C6G3WbKi9KUd2NI5l8qLIp8TrLNbgQQX+UzfRXaqdESycA5I0RR 4 | W+QtHITBzjXnPNWlJGUf5VNvNa+GEOPzNjo93QpMFYOB+QeX6O4BM+gkqWDt7R+2 5 | /VUHuisJIJsfE8vBZkxcq9pQyaMAdcUzgvQN3dB+HxUdj6DNi4QufcBDNB7RFJM+ 6 | 4Sk36u+723cnBn0YhpkyYbgzRua/u5omsS7fZH3Ey8+cadfGofWoZKLAeTzYgrM/ 7 | 2it5gXBYudD5OURK/RUOKBHzbmY3IwFDGtJBH3j0Xc5JBVhUWOWK4owkS/RiPvZz 8 | Y0MUrQIDAQABAoIBAE0bTT9MA42wn8Q8YMyMMPd2BFzXPvnIXPQFec6M/o32SNK7 9 | AXu+ViAZi97Szqol28XO9X9/G0DMSOcpHua1tbYvp9/5JsoVwE44QwfSqD7dBNRt 10 | TWrkUAg6vtaXc5zPrKBgZ+OQnhejKYsxbgWW5Bt0hiq7pRkGJcwxwENpmxoJPgFW 11 | WFH1CpC+m/1C3FzMcnvgsFwog6u52x0tm40jvK4BEXFMk/KQ8EK14qs1gMe068ZY 12 | k7k0JFzmYw8mv95yIGkJaR3ILhA0Uf/robGL31cgRNgLZX4OOLLwBHKQQaF4cT4b 13 | dsH970sasTHnnpMzpcAVygF1LVdbB+BNZv5PQVkCgYEAzcUOavafJLdYZV1VwQms 14 | sTGAZpZ6A418PwCf4PwZjtEnTlSyXUpGqCWSn1KEHkLMXvSTWjvvUc6av2EY71HF 15 | fKjdlBYuFCnKtjB9S8763se8x+J/oURi5j9P9Y1jZjQRLrz/EGsKKOK6czYX9hK0 16 | 3tqFLwjBMZTAV8ZIlmVyzR8CgYEAwl062KC9eNSXz9mkcISN4LzTM0OIqvf3qO02 17 | NMwSs3yKhoyHvfssPRinr3ao0ehvw1FeMG9MNCj6dslnPSik771HO3UlpA96eWjZ 18 | U29TnF0bEiT87paXGk4LUViXQARS07MrLAr3VWhWQNqGN2IejWnFWJye5+qIhosP 19 | 6aglWLMCgYEArSHOfcVAJf52S+N6Uc+4E+cYqDiYNQEIt2HpI746KuZkcg3lfYUP 20 | ak8izRb6vxNpLcQPb27acDSsE7a46jQdPERBG2aGIsT/IMgvxGdEwcnBV1WGGcSW 21 | ijBfMLZkGgxZIMA4xDGr/La4NlQfWRZoRNIMGYT+OJ92LuRREuoM6/UCgYEAlXFF 22 | i8abqEodp+y56OGijQfig+oLLRmXzMUHBrVaM7Mwd5+Zx1NWgmtwkxLzXuIO/OiV 23 | OTx6JSjU23yj6nxTxRmNqYO7O1fDXZJmdyaD7RgRdnQGHhSffdRAE33AXbJ1VNzP 24 | 9v8/iOW+XAMpa2//+c83s5hI/hxweLJ3u7pTbM0CgYAyw1rLSjUgBs/KPr55dod8 25 | Yl2XCG3dxmx2JwIkqXbGzWsJ6gWhXTAUGqhqSdW7enKn5AGXc/5IcHaipQ6jmlZr 26 | JSErJ1fCQjpOpuqoncTv7uz12UiQuWPuglov/golFvhFr7fl6/THsUnxG0Kw77jn 27 | /FlTWhrj0N5RhKvaiSF9BA== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9WygHdOLmSiwC 3 | Kr1Q3ngXquxQNn6UucZFnKh22q87w9f/xBv5AkIqya99Np7rIyRcXY4t2lQ0Rj8d 4 | PllsBmo8vpNr2JtLe5kj/25lRgjNOqH7w2VDFldS3eEsiJx67ktUI+MR5Qe/2fpg 5 | FmKQrnZgBSCRILZRw83s6rupCxFTQdZWyx/pTzcrp8FwvRUmFoXpIwMgWn5RQZKE 6 | FfdI137kxuz4dJuAwH2Z+Z+a/2Kb5ihA5D5GltZgLfKnpeG/EZJQIfLfL00n70Lk 7 | 3ssNxhXCnuyspihyGgw8cMJwC3xljWt7e2KFWT/X1a4IZEe9wwQpxyMdtrgx1E5M 8 | AZiHVC9fAgMBAAECggEATw0fSP2jPED63my5XGmD+V2CCnq1naFxBN7B9dyWC31X 9 | T4+vneUzeml4ue1zqvag1263TK05OhmZf7vn2RFUiMeHBB8JthmDdWPN0rnKMuOn 10 | fFO2kqthCVdYCh9+NFQHXrkcsvvKoG1/+V1fCMfM44lAb1YYx0nXTnEwpwHX2cmK 11 | OBjX0SD/2y81CrrDB8MAIoBhe6yjPwCkajNPpvz6jacg1AdoKCZ/mo9uDjgl9ff6 12 | TZ6vtsr6aTty6g4hY4Hki1J/KrgZ1ssz5db8YgaRyVdQ5ZEOaK252gsq2/la29iu 13 | xZ7WLOcciuUjLuAjWL1n5X2YRhv5pk8O2MHgq7L+AQKBgQDtUFKi/g6mHvzKIgjC 14 | YnpP7j611slDaXFXsa6xJWOPvq+ZkBI0nsSClHnCgfUA8TIeCdSShErx8ZQen4vG 15 | azautiK9yNdngNO+ln+pBUkE0nilXJaf6KruAuujbCi2IsMHN4b2ijjoLOfRAI6T 16 | u2h/FJtwSSGQ75S7BzdlKUQ59wKBgQDMRB8dA0XMEeqW89Vt/L34jGcb67fdYQpI 17 | yv7V6T+Fp7jf4Pi+d0FfUM+6FpZRqmxT0aADlghc6EIiufHgxsy9wGfnkJYh/sn5 18 | 0R09pQ4Y35i1htXb1TjmdfR1LhBfEE5VnCepQFEPCm1IVVoscNSs4Li+eRJPqJEe 19 | H84nkC4b2QKBgQCbz5ICLBZIIa5NtJzVq7yswDryPuxz00Y0kpek/WxqE4PNqlcZ 20 | r2hMZ9mtyI+pJ7OFH2UvMabXRYq/tHccNoZ3nWQgAT7UWTQtPTjiK3MutFW8FJdc 21 | tHGNxeMasEfmldpA4cc+FbCZV+p4QgpamsBYN5p61bkxJOwdA/bt93MxLwKBgDgN 22 | eXw8qaqWQAmsX6UO9hJ+dMz0oj/doTTYf5Wzq/rBS7ojwh6CGy5MvrQR/q3qVk+p 23 | 9n8FbMYR9hQRco57/zMS2XBx/MDXahVjjOKdqICq2vz1QzpQCI01UR/WxCdSEizr 24 | 7PZE7/lwowx2X4hSbgoCoK+kCaJSX4Akui2hIwYBAoGBAJxbCxNsycUmsHEdV7Tk 25 | Lxj8N5TUKPtOUoq5hKJ0BK6zQqEm/tuRIgQ3fHdEkUNWuQRbfQAf9v6gwodKOKV5 26 | Y/s0sJPhj939nJuFq+E7OKiXjTwaxk17phVPOT9RK39rhkErUrlGUeZOIVg1e95x 27 | erMeeTvs7MIywm215b+CvUAF 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIExzCCA6+gAwIBAgIJAL3l2aQQMVyCMA0GCSqGSIb3DQEBCwUAMIGdMQswCQYD 3 | VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmV3YnVy 4 | eTEeMBwGA1UEChMVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLEwdUZXN0 5 | aW5nMRIwEAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29k 6 | ZXhucy5pbzAeFw0xNTA1MDYxNDM3MTZaFw0yNTA1MDMxNDM3MTZaMIGdMQswCQYD 7 | VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmV3YnVy 8 | eTEeMBwGA1UEChMVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLEwdUZXN0 9 | aW5nMRIwEAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29k 10 | ZXhucy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL1bKAd04uZK 11 | LAIqvVDeeBeq7FA2fpS5xkWcqHbarzvD1//EG/kCQirJr302nusjJFxdji3aVDRG 12 | Px0+WWwGajy+k2vYm0t7mSP/bmVGCM06ofvDZUMWV1Ld4SyInHruS1Qj4xHlB7/Z 13 | +mAWYpCudmAFIJEgtlHDzezqu6kLEVNB1lbLH+lPNyunwXC9FSYWhekjAyBaflFB 14 | koQV90jXfuTG7Ph0m4DAfZn5n5r/YpvmKEDkPkaW1mAt8qel4b8RklAh8t8vTSfv 15 | QuTeyw3GFcKe7KymKHIaDDxwwnALfGWNa3t7YoVZP9fVrghkR73DBCnHIx22uDHU 16 | TkwBmIdUL18CAwEAAaOCAQYwggECMB0GA1UdDgQWBBS+QoU9zP/j+SgCj35YVrT9 17 | A1zqSzCB0gYDVR0jBIHKMIHHgBS+QoU9zP/j+SgCj35YVrT9A1zqS6GBo6SBoDCB 18 | nTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEDAOBgNVBAcT 19 | B05ld2J1cnkxHjAcBgNVBAoTFUNvZGV4IE5vbiBTdWZmaWNpdCBMQzEQMA4GA1UE 20 | CxMHVGVzdGluZzESMBAGA1UEAxMJV2lsbCBCb25kMR4wHAYJKoZIhvcNAQkBFg93 21 | aWxsQGNvZGV4bnMuaW+CCQC95dmkEDFcgjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 22 | DQEBCwUAA4IBAQA/5fmvWSMRWqD6JalrNr3Saio5+c/LzxbQ7kZZX1EH5Bo+vhD6 23 | Pfs6lrhzE5OVS86sOItPTtT2KQIE0wTxNfX9wQzjekH4Q2sZRpWaKvK6cH+YzqUK 24 | n3DiICpu8vau4wHDrlfV/C2XhKf5u5qIB+SyOhGDo+XhY0cjgh/FS2//1/qGxrfx 25 | TeOHxoRN5YH4yKNGNapL3XF+utpwVFddmSRUWCBr7Fof9RJlzPCcVP/svTAXDi/y 26 | dhHevPEr21oYqX0KnJJa0JvJx92K8YKFTVj2x5PPCn9qze5C/Re/JFbCIuwq7kcX 27 | 3WQRd+S9zHbtG/4g3DnGibdczSw9529fZZw3 28 | -----END CERTIFICATE----- 29 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-public-dsa.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIExjCCAzkGByqGSM44BAEwggMsAoIBgQDGz00klLP8CyoVk216zk+ldYapofKC 3 | /Mdxv5SvVQKqpr7UEhCPECn/kwLGjoKtby8m/s3DJ2Y1/59LiZhR8RZPFUGO73ln 4 | xvguMRaY1lKMW1Z3Ylcn2wYyjA+4tSIxW4Nrt12JQvDhlYonPjNYqjWyasHI/aK3 5 | ySMlVlb1gw1t4NCfisC0JIdgzWXc589OM7sWIztzEFGs+EEjCV0BOVi8WfRMjaRu 6 | o9hw+Ev5LbMTy7rEK4BK5hPcMdFwTO1SFMxxJopUkafl/PK1zyNYy1rYrDWDioqP 7 | hcDQt/1U+nfvGUoKvBiEHfH1T467v5UMUizLglJ4EWCeYHU/7tQmep3FCf8buySZ 8 | YzmMvgeK8anFKsjukGtxQwcnvCPD/bLTm4evbNKIK30jIRcAICD+OXJyAsU284y9 9 | 2MO4OW6a0dzam2vGqw9zmpjNZlitvnvCcuSw7t282ty/poJqRxLQjbgsoqpjwwYO 10 | CemgYSlCNJ7XQ0/kUrHTPrbGCl8Yvx0LCkkCIQCeRUmNf/OhUimhQrhBgfqoHymV 11 | cB9RxFr4JwpXUGlduwKCAYAhjX0YsOUsVCaRuSMrJBcdr8NeuhIZmnPIGPWMrrXx 12 | uUA/XbLYG2meHp4uL7Xumx0ahAKG1yc9ZM12UW+cZm1Gmf+agZHcJUAMq1x/w6fz 13 | aKy+7qLU4yutVe0uBE9Z55ml9YiWuKN/XK9IA6H+7K4C5gtCKFCH9d1wuiTLEWbO 14 | B+PeYb0N/UbDfqou49y/YiWEG2lAuwYGQzYrKEbhFqQJEzw+cbMbX6bg85teACja 15 | M6G1CPvktBIJkwjM6rxuGzGN8wFuoTk/wCBQ8t3W33XIS+okTEHkbY6Ez46yYNDH 16 | +ItJarltZaWA/I03plMqjwlAKpUrXcapk+wKnyP3sTrSmiQvPWYa0r3iLfg48fU4 17 | NO/VKS/WDYCIuL+dVwcMRFyI3i4GzVwQqmGLzMFqVAKw1GxAwn0l/lZ9GkYoAy2g 18 | 1DmfGNXL8V7IIRqudz/OVvvoXbfl+lRfpaZJUJ9zeDoLa/X4JAKTJl3Kw0aCj0T/ 19 | rGOVd+Bx0kFrOI9fiLo0XWoDggGFAAKCAYApKrbhVeOVtIj66/sjETnKGSXYKXCg 20 | eRn5uZQnQHkfEzniwdMeQue1jFyJ8Dp/mhmA3ZkRf1Jd9yYlBsVjGmISqbsfBwrA 21 | 1VeRkBTW5YrEDlr1+1uZYA7ZFRft+hqXkTBfgBaldvb1A8qJBVYSv4SDy65LkUA+ 22 | 02h9Oc5kFn7/XmgJprvyQRDA9c/9RCEsq8iI1ypupEjXsc+bwdoCq/kGufubywwq 23 | IvRvAz5WxfzG6q6QHYkNVUNp15rWg2gTnrpRRZlqyL2zTd7t0x4z1SbtAsBFbB5K 24 | /CmvnIX8UmmNPhaFJh5KH67jSpWyryiUzUSkM3Vu6teg9gNcfR+RnqNAHthR3iYT 25 | ipeu3VdW4h7GhMqy3cpjvQWCwWKSSStSQbQzYZbX/lOjM8+3JdkfdoCnLadoAz4z 26 | xwYtUwfES0NdKGwpVtin3UzWAlMciDtsNZMf95Rofb2E1k225w7RmL0jvW+xpg05 27 | rYqOttN+bF8Nv4v66yJFtro88gMTfMtvmUQ= 28 | -----END PUBLIC KEY----- 29 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa.key: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | MIIE1gIBAAKCAYEAxs9NJJSz/AsqFZNtes5PpXWGqaHygvzHcb+Ur1UCqqa+1BIQ 3 | jxAp/5MCxo6CrW8vJv7NwydmNf+fS4mYUfEWTxVBju95Z8b4LjEWmNZSjFtWd2JX 4 | J9sGMowPuLUiMVuDa7ddiULw4ZWKJz4zWKo1smrByP2it8kjJVZW9YMNbeDQn4rA 5 | tCSHYM1l3OfPTjO7FiM7cxBRrPhBIwldATlYvFn0TI2kbqPYcPhL+S2zE8u6xCuA 6 | SuYT3DHRcEztUhTMcSaKVJGn5fzytc8jWMta2Kw1g4qKj4XA0Lf9VPp37xlKCrwY 7 | hB3x9U+Ou7+VDFIsy4JSeBFgnmB1P+7UJnqdxQn/G7skmWM5jL4HivGpxSrI7pBr 8 | cUMHJ7wjw/2y05uHr2zSiCt9IyEXACAg/jlycgLFNvOMvdjDuDlumtHc2ptrxqsP 9 | c5qYzWZYrb57wnLksO7dvNrcv6aCakcS0I24LKKqY8MGDgnpoGEpQjSe10NP5FKx 10 | 0z62xgpfGL8dCwpJAiEAnkVJjX/zoVIpoUK4QYH6qB8plXAfUcRa+CcKV1BpXbsC 11 | ggGAIY19GLDlLFQmkbkjKyQXHa/DXroSGZpzyBj1jK618blAP12y2Btpnh6eLi+1 12 | 7psdGoQChtcnPWTNdlFvnGZtRpn/moGR3CVADKtcf8On82isvu6i1OMrrVXtLgRP 13 | WeeZpfWIlrijf1yvSAOh/uyuAuYLQihQh/XdcLokyxFmzgfj3mG9Df1Gw36qLuPc 14 | v2IlhBtpQLsGBkM2KyhG4RakCRM8PnGzG1+m4PObXgAo2jOhtQj75LQSCZMIzOq8 15 | bhsxjfMBbqE5P8AgUPLd1t91yEvqJExB5G2OhM+OsmDQx/iLSWq5bWWlgPyNN6ZT 16 | Ko8JQCqVK13GqZPsCp8j97E60pokLz1mGtK94i34OPH1ODTv1Skv1g2AiLi/nVcH 17 | DERciN4uBs1cEKphi8zBalQCsNRsQMJ9Jf5WfRpGKAMtoNQ5nxjVy/FeyCEarnc/ 18 | zlb76F235fpUX6WmSVCfc3g6C2v1+CQCkyZdysNGgo9E/6xjlXfgcdJBaziPX4i6 19 | NF1qAoIBgCkqtuFV45W0iPrr+yMROcoZJdgpcKB5Gfm5lCdAeR8TOeLB0x5C57WM 20 | XInwOn+aGYDdmRF/Ul33JiUGxWMaYhKpux8HCsDVV5GQFNblisQOWvX7W5lgDtkV 21 | F+36GpeRMF+AFqV29vUDyokFVhK/hIPLrkuRQD7TaH05zmQWfv9eaAmmu/JBEMD1 22 | z/1EISyryIjXKm6kSNexz5vB2gKr+Qa5+5vLDCoi9G8DPlbF/MbqrpAdiQ1VQ2nX 23 | mtaDaBOeulFFmWrIvbNN3u3THjPVJu0CwEVsHkr8Ka+chfxSaY0+FoUmHkofruNK 24 | lbKvKJTNRKQzdW7q16D2A1x9H5Geo0Ae2FHeJhOKl67dV1biHsaEyrLdymO9BYLB 25 | YpJJK1JBtDNhltf+U6Mzz7cl2R92gKctp2gDPjPHBi1TB8RLQ10obClW2KfdTNYC 26 | UxyIO2w1kx/3lGh9vYTWTbbnDtGYvSO9b7GmDTmtio62035sXw2/i/rrIkW2ujzy 27 | AxN8y2+ZRAIhAJUN+c1g4U0Po+7Wx2LUiiZhEHwwn4c/ItFl1L631UoM 28 | -----END DSA PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-tripledes.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: DES-EDE3-CBC,1312914E72B2C4CA 4 | 5 | TCl8vMzxQmGNzeGelkkX6vEYRaYmsJXHWWobB8ANM1bc8nil/oo/SjFUeWq9LJbM 6 | lVtYm+sDiyZ9lgC55+pLXoUhibM/bWEUfB4413UaGMoVllkAjkhvlTWP0qCnrr1F 7 | XQNKyXdYU27MOHBbVFzxfsujsIIR8OAVFMzZjPSfZjSxKzn+08HHbXJ9/aROcg9B 8 | SrhrzS7ymZwSfINTFRQyvKvY3liqlxRVOCvnINC89tMUZ1YnL22NY9A+DDeEuaX1 9 | 9UoEPf7SiPuuvgjESL5CVU0s75y7YZz1UEeLoR1VDoS0aPB6m+zewnx53fSI6ZNV 10 | VTrdVicUkMm//sdWrrDi1LuOCv4wpbeT4JV6ozu8nA+6YBVOYXQXO68bs2n0FOGN 11 | +uS+zRXIKac8cuyCqrfqFmNx0AcVGhqnvU2L2k+ATY3/5sdAdMFOsbE/6ZRWcLQZ 12 | JY0OjtkhoAHaHlkbYWCSzkpEPzcuZKwadoazaKfK845u8YaLTXzbq33LyDd1qn8y 13 | VZLpCY+/OKP++Br3KNDYYMFI3MH4mc+S88mcxH2EWXqDIj+t1S84PTwe8XnNqLW7 14 | JU1opZnbP2mHi/EorLKYpxFWg9HvvHVOV46DZwH/KcWkxkqT18/kUdyKcn9qZwOA 15 | +ww7m8Ki38Yy0xXZRwiIUCAFlYQHqfwRXuh7ePzzabcCzqMcbEQhsp9Jj3BBCxse 16 | G/SNvTdpu/B+TiDD4hA2Vn93WRfrtzBrTmCpn+oMWMS7U2Xt1/5sVJQXrXBBRoD+ 17 | m/pVkaPCPyPJ48rP4uYAxqocSWFTQFh8hGyL8pc9wQgjBHsR12c2NsURNqgEwazw 18 | 0KEgeivGkbmTs7DtMBOgLSW5HmP3uHom3In0BlYQWMVOb7zCVyrvUXXR9QgmDe12 19 | RKcFyLjOeilFsbX9pyjAIimJofN9aNYDrgQdCGoynn+HlBCfY0o96TS6zNxElwcA 20 | xnkZxe3HucwTxv4gopLfy24brdPhrm7pq4jmctF4S6M3y1Fh40j0Iyy1TeK/JgEZ 21 | iPnbbcd/Vn95uaQtFVqdFz6zeqHvY1wMxAmRWrHneNdNdlSmuj8VgHGXMuRCCnIb 22 | dyaBzy7mL73Xe/NV363m6XFfQaokbVzBSNh89ZCjri12ufjVhHEXTj9dWr+Hxogx 23 | bhNzlDIEih8dFzAOuM2pW5Xt9yFs3xzO5DdiHSjPMoqLoiQFiw7nlMEjE8AO8pls 24 | 7Gdm4mY7Rln3p8FdSyeI4n9/JS/WeHU4VC/O8P8YhxnJPkmqRRuiqJQgH5Xry9xq 25 | o+oBrgNvzpJIfQd6CMwDko2YDB1RW9FBzFEHAYYzh23fBSqwGJPHf0K4/plPlCKr 26 | r6G48f3pl5xkNMsxd9bgV3PTvlf5mK32uP3dGyBdq3vrRxrwYsj9dBrxyoURV5Df 27 | 7uVpnPBXhm420ibdBHue6Sva3CY+wQtL+mqdprZ52fx8eJfXEI24I/dWMpQtIYj2 28 | LcE3UnHl6L5sNC2fA5mjm4KVZspCjpXHQ86pAXWwuUhZdk/+Ow04Vrope5vH68ve 29 | H4b/jAz3WMXlxM/zITusMOGv4AX21kdbVhC+IL8LergZLEs3x4T1ffgeEKd0yzB7 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-aes128.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-128-CBC,01F6EE04516C912788B11BD7377626C2 4 | 5 | 73aqVra5MCRJyYTjaqnm8d8OTBSdKvs8hTamsyIcHKe+hy8c/A5XaxQy6GZhGqze 6 | gpu1E8sRpvCHI5WpNflnzuiySamR5iC2OEoMtxHi4j9K0xw/jSdWn2H+uj4grPOo 7 | xIyMj8X9jyLHTa9N12Msvevdd6Zp6HCB6v8K9yi89Q6jl8B929sldQEftcHzLALi 8 | iI9QBs2uH47WyRY4PfZC3HHSynfZSE2Q5hm/Si3b7OGx14VZx78fPfVfBlwRGne6 9 | 7ZPQdpQm8HP1FR9XmfotZh6PjkcNEkfi6k8c3LPEcpOsRb0LdlHB3/H2+a6YAKOu 10 | ipA6HpDD3C6f8fq7n6S1pih681iTlVxaUMJkHEmTJPdKdc4tThAQ4V9rutqNIfhv 11 | y/FrmN/1klnulvwyGIbwaPatcrZyvPBbFt5hJYh55sGLzPq7pumaDSd+8jlTRr70 12 | KC/ivwGXxFNRah76S52v/tSVuiBxCc5q5tYE2dKHdrqNZGUjE80PUGQQEunCNjY9 13 | CFq84wDXZ4VZsPGMBQlhZmx/nyC9dQ8UGBwrLgfyFfp/W9j7o4xbAyremfgWVFvs 14 | ChYifyw5BErF0cfbfF1nGmMDH26mLcSLD18/dipzL1vUGLH5mJegPeD7KHScDUpy 15 | 4t/3wddEnbU4w9BUZhI4zqlSiAnxARO4maEFFgsuJNuwYwd7CSfIVQpYQS+2qVSZ 16 | Qp6pYzfmJFJ0CSqOtkK88clb7pKjOCBYHhfdcm84K8v0hhgDviVQ92HG9p7VmwDo 17 | gzNhUFwJ/mSkZQKz/CLy7dGoW0fD3xiseGTlsR658wcJcR7l8qkUBGF3D3hi4t83 18 | fiTCR9j8MBhezgqO6ATSxgN3rqKQUBVphYMgNsVBlSKr2h8TwJAADo8xVGS5TRR4 19 | OrY3TOminoG2Bn0KyavMiwIVQI/6U0Y5OrLDgl666NHVtjWMfK5NXD4pMTPRuLVF 20 | Snnsi1b0fxGMHtXLLA96iLNtyy5H91xqek1vFou2bsN9PW9TTihNMyTLO/BAi3oy 21 | kpRv99swSE6LaEBXKD1HvGJ3pyLarTRQvLE1YilBz8aHVM06Hh/MZIsQ1x6O9lZI 22 | 5mQSeFgcD/SAOrgxIE3tNnPSHHcBiRbUFxgfZQDlo4+WgYZl5WOTBuoqJKb0Zeeh 23 | ubH2I+EGW2kCQo87t4kt7fKEU+k+DfCMoLF+WoEo/s9jU/k5kuCC8iEnITUC8ew8 24 | 9ppGkcEf086WDVI4lG/Q7LNHyIZuzPNVf+ZpVDRYL8I/j6dgq5OWCv2uXFjZCE+q 25 | H664h31DV2TbaSZUsETzvVbzKmvYjzD1QayFrJIKtrgxlWxlw0HmucCm+K+Kbjk7 26 | SeJE21KbKkxl4dxjhrtsxXp9uhL4IgebeXBV88UetkdqvYtDTRHUtyPCnf8VQjJp 27 | DelBSgLahhZuuHcXBBrk5KUKzKMZElsYkS+RdR+P5nESseFtXqJH2kjsAJKGLra5 28 | 3dDeOMPluHKQKHtwYUaO9QpWwAwJu3V2l+Tmo20JyQAZJujDfQ1WECCES+Kb8VIN 29 | khp52v9TVhFKSTSLKNFyt8ytEX4wCR2T56Vv3Gwe9/6e6lDljx3eRgmGFhw1Fa6h 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-aes256.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-256-CBC,37A099C7348810152ED2CADA9AA7FE5A 4 | 5 | XkEjoXZJyptFIrmqIAT/fnEgVJutPjFM/kA6RUhlkHdRHV+vOF9vjrRSkY5NklNW 6 | 7kJi9RNFGByi8X+U7GED4TvDMRQbWkKSXylzwRsWcFdxz+OfnxFk5Zzih7+LGU7R 7 | DLXKGQh84Dw7raYm5YxQKiDYkolEJkN/DM3VxhU7i3XwhHOxzOHIDXWcpb30vsS/ 8 | v6NdF5MWGhmEL8bqE3TsQtbnhnmtvomNJpDDAtrRqSlWDq096AC/+6FSjdknWMp3 9 | sHt43F1ZiYdyviZq41qaGkHSLbSiXKvsfOhO1FrPpVhohrhcGWvIUpWl9KfKZe4A 10 | EGoKICZc6gSC40bgM80/f3iXEPKqseWLIybm44Hhm8eQhziYlGKV7PZMI0PhAr8T 11 | FI5zvTknza5XM1NPJFIYZDzTjImj1J9RcPcVNrB8hty0nvzG3mLbXCAG07agNl0/ 12 | kwqb8antczLog06ramE0PlF1O0wUf3AWZRu0Q5H3v09xNIgikAWRU55DX2m8eb2d 13 | n5uGAvNx7iCCoQoHFuJUkWlGg8D1SVHgw6vcKK1Uxjv8udsfJ79hn9bSMtpLfhYp 14 | TbVLBp0WRbyTlNC8PyJjAdmgQgdCbmR26rzLQVQ7lQms4rE0fcsslF8n++SIRmlU 15 | TJOZZ0W6nnXc+wQvkOu4bg0SunlYLNKIihB5sK22XOs9nALkeALoW7+CEzkgFmsZ 16 | Z7KxjNCh7Ae+2B22E9DX8qJALUsI0yhwhXGaxVAWEXkvAwd8J+GMSqixuQVvnPKw 17 | /g020YW0wfNcks/xbKYg0Gi41ruTnc2cqXtI/o9+wyz2TbDEU7HCduLJCheiuU6T 18 | IjdBYtbkOdjU+WSOLbMg566ImEYI3CSqEqhlLfDB/kStZKtX/8+b9XkIZIAWcalu 19 | DzW8ry3RvS4q3G2ucKpu/lBpJ1OyjhkcRSFp59T+ko96uq25fQ/awlVvYI5CE1nO 20 | ur04d41H7qFjMSvD+aANWC1iccSF/Au8iflGgobchbLMYVEdQdfrPAtZ8xrDZL6w 21 | +yrNQiO3FFwE+rYEqg0r5jgSsu09Bcl2y7uYZlrVCWOHfDwzX3YoGBdw1haRdZGy 22 | yvwVIprBCFeftqC6oZRe3FlZZYqFcjVgZfIuzh+NjU1QnnVAasYimVNfrUp4PftU 23 | FI5LRv+QJf3nkb7Lg9SWnjPOG22E/v2xLpCDerMfAOcLgqaat9V1so79adroxINW 24 | giixNZYGFesW6jTurC3WyJFj2nZWmHRPMGXUxky+0UR1zMrQiArzITVpc9Goy7Nr 25 | rHSvDpvVywORBfRAicQXG2jbwly56zLtWoMK51zNbG+z5rNdc55rwlxHwRJSCCSk 26 | COq9w1KQKc+w7bKDpzLkX9OH5MmkQRWHtlqYOlXNEBQuoo2e3N5upiQOzPIfQnnc 27 | ZcXP1lBnJFYVTdmxzEAGZVltvj4gx7IVNW6aTmRfxkcbSmxGPsHD8LmQUXLUBHki 28 | HBR22RaQXzztSYhEoMkEUJMALA9WSrODWTeuzgEu3t7BZzaDN6hObNXn/6Wrf9WR 29 | uyfVzePflL/f1mQ9h+YLv2xN1ATI2wnxbXv+QFK+FLt4VmErcxooUQQDPF7UvFup 30 | -----END RSA PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-blank.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIE6TAbBgkqhkiG9w0BBQMwDgQIsSetDKkFJYICAggABIIEyOOe9inXgJ/uBVQl 3 | 0qKB7VA8DWNcpVvD6p9HzNloffwSn4TtzqIC05lV71ixDoP1kbRALw2pckbO0vsH 4 | dxTQb/YvFEXyIsZI9v9rMwr/OA80CCmXMuHZOxeYcinF9N9x1BxR2hc75wSxlxXd 5 | C8C3lfVTgyZLOl9A8mtGVnCs5wAqrNdj9H1JyglAoF81VcTgFroxLrraaEGRvhyb 6 | XBV3PxW1WQ0jLB1C7SllmeOXaQVkAlgf+oUtX20nwja3V5H7XfkO3PLf/mqZINFT 7 | Nu1LqjkX6/KVXQOFoYkDJOscEGitSrns+YzTKcu/ZlEZqXTJ686F7WT1t6CLFpC3 8 | bAVYCejzv/FHL08WUZ1DODWK18cQTbKUAfMAPcgQ/i+HWlq7r3bPy8AlC7O1zeCN 9 | 3WN3Vd4Z5XeTpVGxj5kLqXg3HFgHnlvWd19kSZ4iYJ6QJ7e4UxGSybDfQ/vKveMy 10 | uD5o3kNep8JJ/AR4jrRgh9QLMHGXR9dGquK7X7AB8ubibnXkPMLsfprznGrh4r1F 11 | krgJbffEon1dNrpENL4lTpgWBq8UX0P9OYrli+Gh979s5WdcaKxgzRg0cFu29+eA 12 | 4efIZHodrgz0tClmwfBSj+JPvMLTRjksWoWB2oBr63RuarnDOmeNtgVWyNJU3pfO 13 | vRZ4vzUO8/3OIZX8BK0+mMXeHpKRBYW+MBlxlDczQwyOqSIfV5zsa+J9veRyJvBp 14 | a5fc9YTwotTS1YwHfgxdg9SPsju4AmfZMXPNFf9SMYmZGr+kLM6mOuBI8rwmxP7o 15 | mJ4ceuWxJsVHDzrcAv3ZbC/o+nIuEjvLy/n5Qi1fbNLjg0rEeWsnvqRYoP062u67 16 | RH3Lhi6GgVBMvPDGV2CCA2A+B6xNI/RmKjDXTGpVo2emDBzroPKNoQCluYZkeDYg 17 | JPa70kuaKQaKCEx1JiDSfNpGxpa9MjRTQ2yuRr8VI4qHR5cCeouX0ykNgsH2iZxN 18 | zVXtSHXBs+lk+uz+5+Q4RxITPSeges+QlwvAT9cxOEAT6vRnru2FyjDoUaF/8Ppp 19 | afJEx1xk0sv49AdzGMu3IOc5S+aS1gVMOrVx40xo/rQ44N9xuQHCp3eNAN7OXBv3 20 | CJgM15CJtE/VJLPunxOnnKeXud9hRfpPXkbKZ6nRnw8Qg094+VOJaptxmM+QvRtx 21 | HZr81AjSxK8PGcgY+RAGXy4LSuNLwGB04n7dArZ8b+6i9VA9kduhnvXg3dZpTV5b 22 | dIXHEfhVo0zI/gKCDgw+kXTFoC2iX1aun98b69T88+HTPceVEC/TG/uUWklphHpW 23 | hyWMQdnH7UAF2lxnoj0N2QdkPk9zM13UdSO8dgtr+it/FlcBKIhNgt0kqOpOSImV 24 | MXw+bGMWSyuBBJwo69QbJ8/WXalF61Z3hphffTcz4tn0Iv68I3jCDB5oNL9okQ/Z 25 | GbptFdMhP+DnvG8/vmC6neJ7TYa6//jOLysOTg7uuP/pMu9Ftxc0xeLkSxv/Q+hQ 26 | g3Wnak+A2bJ/cLaVXE4pgfWx0MW/QVMsc8OJXDcetcPOcVwub2JLPSNWkEFu33Op 27 | 4WbOSKAvZ9qElTlby6Z+6EUP/2uccHkwMawx7HRVhSwA4vbDA6wxQBVkEOeEShy0 28 | 7OJqMonBEYYaqBs49g== 29 | -----END ENCRYPTED PRIVATE KEY----- 30 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-des.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIE6TAbBgkqhkiG9w0BBQMwDgQIPIgi2uA9hbkCAggABIIEyNFrhiP9YxjTgadK 3 | ybooxFqa+Kq3TCwQRH3suoWdJZbaF3MKa86ghqXj7/tBzmqCmy5metQXHXnwQFEY 4 | 9noEcdauYjPQVstwPhsNZpcbR72PkndR8sGgqMtVtC2GPw2sQ3vMMZNbmqD/4zI1 5 | GY0tIt+hEprZJEDDN7xDvDxnAmN0sxbnBMN8DttgX9Awyur59qW+NlJw+ZJF7tto 6 | zglefFLI4f6MrpksfVrV8JDhrAkj3LEQeJ79cqp4cg3l7zbPjg+A+ImZEYliDB8U 7 | HH3Z/h2uHhmVJeVGJokspWIQLgcLpPLZ7JdrndVyGhVpMt48N3pKOHrUjJLAu/jN 8 | PStvOaSlb7iJJsdv0WVoQf+W2sW/uBVCZwdf3BHNWeXvXSsqJGNMfzhzSuHpRv4s 9 | qpVlTnY6howfU0qZ+x/Kt9tSeOa+wbOdyp13aVAIhAtxZBfl/QRtYL70I6K9+kSs 10 | CXfSyQOYMhqv5fw7h/UZge+M1KF1gGhy8GElw8ADg9FJ/Rc3Yl4kAzvBLcRvXo1K 11 | QMR5rLw2h/10WC9JFZ46GEY8BmoZFML2hX3ZCD7nXc0u+Q1jPFH4rdOLwuWHg4ry 12 | WpaVgq+f+nBtxgNQTU+GoxR1g1tzUaXR/fSEXwzg/w7aU5k+iq0i/UHb/xCW5sgK 13 | tHmqqKvfSmhOuaswVihXpcPY8CsfCwMnm7myIiMxRIResziAB0yEHG8WLqtiwJc8 14 | FRzJanKNdjXpD49Lk7KmncdhseupEIJXDZ6VrqxR7T8jDOAjOOUJsqoFvVFOGIBu 15 | Yuf0oyaETdJJzL7Sf+rOBc8q9lLLh7q8i8dNz04kYH0PoX9gBmLcbSYOIf2ID/sc 16 | skbLdEiZQQis/zkmkE6fzRhhBBWpqoitJ8G81QlPLWZYB51jL955G2SnQKxgWdk9 17 | JduoF7dvKvIUs2e0led1wSWP/ShRn39V67gDp8geH6TWFUYTkZXWlfSYK/uGfiO0 18 | bqv5BzyFZOaAbKBPlytyBhDkQw8pLEraztJKXrtwSj2wawFryb3w97/2lrVvdeJJ 19 | Jln1o8jBYhJnS/MgTh8DzzgaDOuwqWxNRASYfyqCIrddrgv8fUASvzThtqhu0w1U 20 | 7kJ9cjLV5a5v08Hd5txO3lWDQyiMx3cGyq7tZxDFJHpIIbuqf4VhV314UGLNnz64 21 | Xex5x5LNhACCmqwc6uBrwWofq1hfNfHDeddvxMeX++klM+O44UJz9oApQwM+vIye 22 | BYwKfvX/fbesrh3SbKrk2MgeSwZ50jI2RSmSZlxyph2rkoYrv2lndaKkzZB3w37q 23 | XpicoDRpuDGOx6iQrH2daHcfoJOCsWe5nR/InX/V9MDwSs5oaGfdqQ7R2ocUNs4t 24 | ++JGdnkKAOfI/ElywnyWS1g0DnsUuGC7C35Xwkyimoi/due/jUYVFURw+tBa1oC1 25 | C02+pPo75hvEF0zEPAZcUREAsalfLpFOj/N4Z3q1Uwi25YEI04q+ESSBlSSrcJEU 26 | VKeWyYi/5wyi8cOWUwgXh3NfuhJgHmtnhekTXkYWOoqpTv5FRxRlWxifNmRYYUMv 27 | EpzlHqj23Tr6V6dKjMr+Mi79LhI/9CQxkh/XsRRfURD+em/tuuiVzJZ7xzc2/mXa 28 | Rl+yyu7/lew7PS6rnQ== 29 | -----END ENCRYPTED PRIVATE KEY----- 30 | -------------------------------------------------------------------------------- /dev/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | 6 | 7 | package_name = "oscrypto" 8 | 9 | other_packages = [ 10 | "certbuilder", 11 | "certvalidator", 12 | "crlbuilder", 13 | "csrbuilder", 14 | "ocspbuilder" 15 | ] 16 | 17 | task_keyword_args = [ 18 | { 19 | 'name': 'use_openssl', 20 | 'placeholder': '/path/to/libcrypto,/path/to/libssl', 21 | 'env_var': 'OSCRYPTO_USE_OPENSSL', 22 | }, 23 | { 24 | 'name': 'use_winlegacy', 25 | 'placeholder': 'true', 26 | 'env_var': 'OSCRYPTO_USE_WINLEGACY', 27 | }, 28 | { 29 | 'name': 'use_ctypes', 30 | 'placeholder': 'true', 31 | 'env_var': 'OSCRYPTO_USE_CTYPES', 32 | }, 33 | { 34 | 'name': 'skip_internet', 35 | 'placeholder': 'true', 36 | 'env_var': 'OSCRYPTO_SKIP_INTERNET_TESTS', 37 | }, 38 | ] 39 | 40 | requires_oscrypto = True 41 | has_tests_package = True 42 | 43 | package_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) 44 | build_root = os.path.abspath(os.path.join(package_root, '..')) 45 | 46 | md_source_map = { 47 | 'docs/oscrypto.md': ['oscrypto/__init__.py'], 48 | 'docs/asymmetric.md': ['oscrypto/asymmetric.py', 'oscrypto/_openssl/asymmetric.py'], 49 | 'docs/kdf.md': ['oscrypto/kdf.py', 'oscrypto/_openssl/util.py'], 50 | 'docs/keys.md': ['oscrypto/keys.py', 'oscrypto/_asymmetric.py', 'oscrypto/_openssl/asymmetric.py'], 51 | 'docs/symmetric.md': ['oscrypto/_openssl/symmetric.py'], 52 | 'docs/tls.md': ['oscrypto/tls.py', 'oscrypto/_openssl/tls.py'], 53 | 'docs/trust_list.md': ['oscrypto/trust_list.py'], 54 | 'docs/util.md': ['oscrypto/util.py', 'oscrypto/_rand.py'], 55 | } 56 | 57 | definition_replacements = { 58 | ' is returned by OpenSSL': ' is returned by the OS crypto library' 59 | } 60 | -------------------------------------------------------------------------------- /dev/release.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import subprocess 5 | import sys 6 | 7 | import twine.cli 8 | 9 | from . import package_name, package_root, has_tests_package 10 | from .build import run as build 11 | 12 | 13 | def run(): 14 | """ 15 | Creates a sdist .tar.gz and a bdist_wheel --univeral .whl and uploads 16 | them to pypi 17 | 18 | :return: 19 | A bool - if the packaging and upload process was successful 20 | """ 21 | 22 | git_wc_proc = subprocess.Popen( 23 | ['git', 'status', '--porcelain', '-uno'], 24 | stdout=subprocess.PIPE, 25 | stderr=subprocess.STDOUT, 26 | cwd=package_root 27 | ) 28 | git_wc_status, _ = git_wc_proc.communicate() 29 | 30 | if len(git_wc_status) > 0: 31 | print(git_wc_status.decode('utf-8').rstrip(), file=sys.stderr) 32 | print('Unable to perform release since working copy is not clean', file=sys.stderr) 33 | return False 34 | 35 | git_tag_proc = subprocess.Popen( 36 | ['git', 'tag', '-l', '--contains', 'HEAD'], 37 | stdout=subprocess.PIPE, 38 | stderr=subprocess.PIPE, 39 | cwd=package_root 40 | ) 41 | tag, tag_error = git_tag_proc.communicate() 42 | 43 | if len(tag_error) > 0: 44 | print(tag_error.decode('utf-8').rstrip(), file=sys.stderr) 45 | print('Error looking for current git tag', file=sys.stderr) 46 | return False 47 | 48 | if len(tag) == 0: 49 | print('No git tag found on HEAD', file=sys.stderr) 50 | return False 51 | 52 | tag = tag.decode('ascii').strip() 53 | 54 | build() 55 | 56 | twine.cli.dispatch(['upload', 'dist/%s-%s*' % (package_name, tag)]) 57 | if has_tests_package: 58 | twine.cli.dispatch(['upload', 'dist/%s_tests-%s*' % (package_name, tag)]) 59 | 60 | return True 61 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-aes128.key: -------------------------------------------------------------------------------- 1 | -----BEGIN DSA PRIVATE KEY----- 2 | Proc-Type: 4,ENCRYPTED 3 | DEK-Info: AES-128-CBC,FD61FC37119474382557313D31F8E4C6 4 | 5 | PSjB7ez+he0SUh2/u40OnSsVw6WhOnL0RlKkXRL24dXHdpdYiNq8ToqB9zsmVu7/ 6 | 9C8r4aL94zu+JlZnEaHMuJUuevvpCAnxOguFQil/cQIfCMyNmYjyfFhr95eTxxvf 7 | tp5qKIgAgpHhTYuLZGMeWpYECIZJwiQ3lWFzjiQu+/n1mEGV66xjwIh15fwCOUoF 8 | vUQpDVGlW4bbBXqScThlKe4SW2YBH3KNEhMU9CbOeJRW5SFKNUEb58NiwAlm4tTE 9 | FOD+WwyXqHueqHmCpnRfunOA1dChnllrhKLL8FGrWcz/6zx788NwaLBziBo5e39r 10 | BQZ6gzv3RqXlBRWFc7SDIwo+rpCEegEcg17tc6VqOeJFzIerPcU57tQnYvxxhfT7 11 | Cnw9JeAaVOAtC3av66yvRFjN0l8A2CiD4Bcw8L9583CdW8YKpIUdRyXtt11Tb1HD 12 | oifCYEH1aPVPI0foZVLkrrQNbrDNkaXsEYPSBDp8S5XL5XuRpiJYdcrMwJl3qEho 13 | m+n+oo+s+7XpSE4MTOyAWqq8HbThyG9MXapS9JWsKWd0gbfUwMDPdb56ICBZSKVj 14 | SAVsFNfhbkhrHgQwRW0kyfB3uUV79jvXLHDvO3VoAm34zgcfxYNx/znE5/gvl7aY 15 | BbRBWS/YLlTPYHsNsyPJ+0TcwOPUPjdG73TMKln6h4rrdNylIAb1sBOGBdIQGVUq 16 | 1sQ/StzA7Og1wwm+KCLZJkxqNXW3vfuN3DzX9iSb/3k2Z6YlvVO/plEeO69Ie4SW 17 | 5Bv0HwhmODqql+0zkQ6JLQpvYMG/GZ9Y9bZwqrqTa07nV/kvZ+zDMdThO+ifVxUq 18 | ERmcWlass/VJndUloAeCK9D7jauqwoo18g0cg2/aEfBvzxoAuEKoiADt1QysxmG6 19 | sNekp1yscepjubvHKV/oD8rFBVvHPcV55jPLU0CbfXO2MfrD87V+eoVrqC4pnR5v 20 | 6VYnY3GqZLA7AiOCailt3D9UVzsRtGO2jArBnyMTR0NoI5er2V8n6IIqlwC1OyU4 21 | yJ0oSXunkq4+VkWGOr1CquLhyXSC//RyQSrHfra8ckEJtU/02hFeW374Fe2WaNr2 22 | k79hh6VT063LIDaTXI8Ls1qCdqsM7BXkQAMVwgNR17FvAInSrCYo03YbB4IOdfH4 23 | D+MC6tz1CJZB7mH5+uRCQ3vAg5047dm3ZcWwCCL2GqnUzHdVlvWEcV6R+ITXsovX 24 | vqTKoMrV2hSED9x4cLaAxrozxSPorkKaZqkd/N5E0pcgV4TuUX+Fm5NCChvSmsz8 25 | qkW+HwDUCq7ffd6nITEbjCjYUSGWaxlfzL/6XOgKPw7S3C15nxuGb6jLeEP8dHvN 26 | wetL0g6WYQ/ZjhgBdbZ1NLQOUUAztkB4Jd5r+mVjDG9nobyEC/squHxoBtsM1jRG 27 | UvtRWiMgqkBjx0HKKI4DEtX3VrwJ8b/JExSS9cqLTJF8gRHadd8AM7sx4YRU1M7Y 28 | fKWZKCIBruPtJTkIk9oqv/5Lk1dq10DU22T+GggBZ+fIctdIBA1/7IDvln6vkLXi 29 | MTYJMP0i/AGH/Ag0f5aNNVRPYMnLf2Nq6pWVKUhRKOyvhHARvtvX0U5ik5lnXUhn 30 | oq+Jrj5I9zPKG5oAqujc+7OQK6jgP1CgHYDxHG4fmDDtjNxpKOADrShygCfJnLn0 31 | -----END DSA PRIVATE KEY----- 32 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-tripledes.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIn6e16heAU4cCAggA 3 | MBQGCCqGSIb3DQMHBAjnH1OY41T/NASCBMifNpJWcjAlthILQqFyZ9U6l0Cm5pD9 4 | OpyFEdjEz6jG2JryGKAdpur9zwtYGAYaLBF94dlxLsVnbR00nxeYBfagImk9rTCC 5 | Xhdu1AFG24IQILwJJWMs/JX/Xz0gxLzVhaeikpm2gSaQytyldQAhaNWIJzfFU/t2 6 | q4URGS05MHIrSfdli1D5r1UwvOKd18p89ZX2EHNGu8Z6+lfiigyNgVngmDJ8L0OC 7 | 7IVNOG9+CkYcjez56lQfexspU2z8CeY2bZ2gp+5SfyOxSUZ4592bLBm+8sFf3gnL 8 | 02KvYDRuzWRMBAGkeCN+vRrQB0verefo8OVkJ++VqO5mBpvn2HOOUqdezl0lQDOX 9 | gx8fi/9ogv7ryPmXgSVTJEJm6I9rg4rDllpYVDANEXO4pZ4Wz2k/1sGRU2cCYUSj 10 | +sQBGGTqSwLBOVLOCihTAyO2IwpJklLZO2RTSwaGVwBzH34kd3FpVPAUdZvGINlp 11 | 8+7aRK8VltWk9C7xg6JxpOj1ynRbfo05lgUIPWZdag1CHL+HpK+t0rD98g4h+6fw 12 | 7N0LNo47GlSPGZLp4bv1OCb6lmGh8nhlm01s4uVR/YN/eJgiy5VXowd1e8pOs8KI 13 | QOsZFph8jkABxOd+aGDsvWTYorHAYvx4zNU8NjlYUTjKoT75viSAS8B+3uZTpJ7N 14 | UJgpZCVrkHx/OPeteKkmUQ7IWIrGs0vvxwybs2NWhU4dckqeFmQlJc+UVhvecdwS 15 | 57+f8fGH6NOpz3olCCusxWO3CyzpRRASGChrMrGGXHpZHmKbuXj5a6WtOH6uUuEL 16 | 0iYVTVQ67HFWapBd3OuyCkQhmripRaJBPaoIzsww6A8Cupp7s9xcYmZeg0t8oxTM 17 | kJ6rpXO2AKL4GV2FhWL+cdOXRum4WMiUnZ5Ty2xG5rrceQjIk/yaJo+/EJ+4t74R 18 | wFOWQJzswrdUx4G2c6kcqC/80eNyYWtHXKlfAOGQ5Cd6C6vkGQWLsMYnufkWk3AV 19 | pNYbfme+um8C+nd0uyb/iiue0LWVa3YNdJfYqD5McOL12hxX7EpIhAyytIjV02Rm 20 | oanhQg11pOPQWQ80CEYz2jPPO+rabl9Q8tmwcgWy4dHASfZ95746cDyaks9QR3KF 21 | HdSi0DmcPhin+QW0TxNgNxhe1dadxrQbCjh3t5dCrS46dYcn5y7ikI0+WO7eafFE 22 | vBQOrcFsqmt73i1MHpXgxhhHa+PZZVk7LxdrpUPWJNvGbkEdKU4U4R8d7kd6+WJe 23 | CguO0Ga9G7qQpnhE7dqQnCCOoreuoymHTk0qZPfDsCBhmoUwlUTMLCDppdRBjlnd 24 | J4sl9ds/pMbGLGgr27oFMcBzk6hBLpXp46ORE9ZOMMC1HZcELh3sa2dqRweke9CW 25 | oxnN75KDbtLqfVoydoYymwp37Q3i0xv7XkBBuoa5nub8M9PMLrGtq+h4VKTB75Wh 26 | kMku6pzTcJ8kvBdmJPBhK4Q1uxmBgxLO75TIJ4ff+lTOp4eRGeYjO518UypJJFjY 27 | GxPRgQx6DKJo2GzW6ku2xRzbVncFXYvDPfoEQotstTQ61p7X8+Y6Hrx2JR726Fsj 28 | kjqVIxKqFnGVyInB7XgaM/7V+OiMJKSynej9Le6++rJoCXQ6jLaJQieF22fguoLB 29 | URE= 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-pkcs8-aes256.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED PRIVATE KEY----- 2 | MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI2WI31tR33JUCAggA 3 | MB0GCWCGSAFlAwQBKgQQz9HGmQ20dNiIH9WFukhAQwSCBNCa49F9s7/Vno5q1Ly1 4 | gnbzrJfvOgSHy1P93MB1HeQq330iDr13fu8cGEMP6ngUBv8lFMClXBw8HB1eC+8f 5 | HT8X2CfGrorwDXpIJCI6j2rEmTc125np9VcYegQMQRFjKetFFO9zmfk+qIKl4hhg 6 | 98QYdx1DYr28En0vHbwqHoMkagiSLfR6/N+n4M237nUdjOuuB0o3+vX1OtYOiK0h 7 | WMS/IQqJ999pwsvPpwDV/LhtaIFdArRIs2+W+Cy1RwcGgFUxpbl/PnLFSFfIdYqF 8 | gC7g6pLtK3mRJq6uOHsPZjuEuhO6dgnDusvIkVKb4IsNVWld0VHcTyI5HKe+i/tW 9 | E/sQBR/zYzzd701t5DQcW/EXePEWiwY2vlyYHoGOEFFg0xgWc2w10GpBSir6WcV9 10 | yjElu04Dic7gjoPs7oH9RmoRKzMnJ9KMnSPGnQ3GDlv9imROehe1iqnLNN1bpTy6 11 | lHNVDDyOba+rRgra30iqeriZOmk4vBGnqA13c9tdWk3lLXrrYgst53xO7MIv6QMB 12 | 5gp/fCKcIAezMre4WfXJ/z6OxY+zaHo2B2oxXULtDTW4OfwmcuXPCj+NTtYTGlnC 13 | 4i2Q+BXiD+NQl4w6UrAipn5TlIWYXvxKvFKvcSONyEho+eEekiTBOxlNn9rxb9IB 14 | 3x2dVVd2gKCXkUlXBFAYIx0Q7NYmjX4jordXRuXRo8HDjtAx6wHvLNzvaSffMoYq 15 | D5eNtcSzuRm1xmErvDLXaxL5cs9mbKSDq86bQgm1xYd8QOqw4WYUh+zKuszK5XEw 16 | kTtc3CP5TTF0nkiEbQkwBW9Kaus2TjnhRrgVRtRBa21DVfI807+SlSdcpElWW8jS 17 | Zy+FJxWQNs8VOLcUMT5caxVJAHTEtlfP45smIF/jCvGLvHtaOJt0XIHWnY+uE/Lz 18 | GWXlzyKvwpq1wUu8bNaKCORzwKDLPsOh9qcfc65hYywC1l3OsndlKwMTvb4gfRIp 19 | r+gQ88NxP/9d/PICPBiJdCkPHe0EK4d0mmUIShP1OTAd7c9n+9rAB1KM2lCFlowP 20 | w6iPD8Swmjexd1NK/UTJysj3nsSgZKHiHH9AdPwDo/hTm5aO1ivlbXD4n35bUvQa 21 | Rabh1lSY/O/hda1M8IQNg9t59nEsqQBEz3v4ODx0fMUSrmeSy1UkoUOts3nGK0N/ 22 | ObpRBzF8fYqYOSfGG6zNt7ZXGhk9WmvURR4n34kjT+7cjGFC2DMbX8JuFmqfqd+F 23 | Ks9P1NfsUM1z12CH14X8PPWVFiwZw8b4QU8wyzZdYURym9NZ5ZZdcy06dI+g/yuN 24 | 2tr58XEEG2lXgEUvZWRR/KlQ3NOckxY3jSAXPyL2UpwEWvbRbGzt75JP91eWXayB 25 | 0gGcJOd9nXegxoR3OAFALEH8yRuDapuqm0PCb1FAG4lYqUjWcXsu6ivWN3g7PCQy 26 | LeubZBMTvf2B9nMeVeRXaBjXLguiithEz+vyaOE8T2hF4I7+ML4zc4EBYRRPK2nC 27 | MtjVkOo83Q46aOwOcXqLuf/4IOQYv9s66b8OY3YI9STtRm09mUoKtFazDwvx/bmK 28 | UuVMO9X1YBF8CVNHC0v9IkOmZaedAdqBZOFqsvvsaSlpoBO/Uc+OS2DkspEbvEze 29 | E/A4z5WSiMa8XHYnvgYebBkhew== 30 | -----END ENCRYPTED PRIVATE KEY----- 31 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048-sha2.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | 8ALbPqF+clh/ 32 | -----END CERTIFICATE----- 33 | -------------------------------------------------------------------------------- /oscrypto/symmetric.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from . import backend 5 | 6 | 7 | _backend = backend() 8 | 9 | 10 | if _backend == 'mac': 11 | from ._mac.symmetric import ( 12 | aes_cbc_no_padding_decrypt, 13 | aes_cbc_no_padding_encrypt, 14 | aes_cbc_pkcs7_decrypt, 15 | aes_cbc_pkcs7_encrypt, 16 | des_cbc_pkcs5_decrypt, 17 | des_cbc_pkcs5_encrypt, 18 | rc2_cbc_pkcs5_decrypt, 19 | rc2_cbc_pkcs5_encrypt, 20 | rc4_decrypt, 21 | rc4_encrypt, 22 | tripledes_cbc_pkcs5_decrypt, 23 | tripledes_cbc_pkcs5_encrypt, 24 | ) 25 | 26 | elif _backend == 'win' or _backend == 'winlegacy': 27 | from ._win.symmetric import ( 28 | aes_cbc_no_padding_decrypt, 29 | aes_cbc_no_padding_encrypt, 30 | aes_cbc_pkcs7_decrypt, 31 | aes_cbc_pkcs7_encrypt, 32 | des_cbc_pkcs5_decrypt, 33 | des_cbc_pkcs5_encrypt, 34 | rc2_cbc_pkcs5_decrypt, 35 | rc2_cbc_pkcs5_encrypt, 36 | rc4_decrypt, 37 | rc4_encrypt, 38 | tripledes_cbc_pkcs5_decrypt, 39 | tripledes_cbc_pkcs5_encrypt, 40 | ) 41 | 42 | else: 43 | from ._openssl.symmetric import ( 44 | aes_cbc_no_padding_decrypt, 45 | aes_cbc_no_padding_encrypt, 46 | aes_cbc_pkcs7_decrypt, 47 | aes_cbc_pkcs7_encrypt, 48 | des_cbc_pkcs5_decrypt, 49 | des_cbc_pkcs5_encrypt, 50 | rc2_cbc_pkcs5_decrypt, 51 | rc2_cbc_pkcs5_encrypt, 52 | rc4_decrypt, 53 | rc4_encrypt, 54 | tripledes_cbc_pkcs5_decrypt, 55 | tripledes_cbc_pkcs5_encrypt, 56 | ) 57 | 58 | 59 | __all__ = [ 60 | 'aes_cbc_no_padding_decrypt', 61 | 'aes_cbc_no_padding_encrypt', 62 | 'aes_cbc_pkcs7_decrypt', 63 | 'aes_cbc_pkcs7_encrypt', 64 | 'des_cbc_pkcs5_decrypt', 65 | 'des_cbc_pkcs5_encrypt', 66 | 'rc2_cbc_pkcs5_decrypt', 67 | 'rc2_cbc_pkcs5_encrypt', 68 | 'rc4_decrypt', 69 | 'rc4_encrypt', 70 | 'tripledes_cbc_pkcs5_decrypt', 71 | 'tripledes_cbc_pkcs5_encrypt', 72 | ] 73 | -------------------------------------------------------------------------------- /tests/test_kdf.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import unittest 5 | import sys 6 | 7 | from oscrypto import kdf, _pkcs5 8 | 9 | from ._unittest_compat import patch 10 | 11 | patch() 12 | 13 | if sys.version_info < (3,): 14 | byte_cls = str 15 | else: 16 | byte_cls = bytes 17 | 18 | 19 | class KDFTests(unittest.TestCase): 20 | 21 | def test_pbkdf1(self): 22 | key = kdf.pbkdf1('sha1', b'password', b'\x78\x57\x8E\x5A\x5D\x63\xCB\x06', 1000, 16) 23 | self.assertEqual(b'\xDC\x19\x84\x7E\x05\xC6\x4D\x2F\xAF\x10\xEB\xFB\x4A\x3D\x2A\x20', key) 24 | 25 | def test_pbkdf2(self): 26 | key = kdf.pbkdf2('sha1', b'password', b'\x78\x57\x8E\x5A\x5D\x63\xCB\x06', 2048, 24) 27 | self.assertEqual( 28 | b'\xBF\xDE\x6B\xE9\x4D\xF7\xE1\x1D\xD4\x09\xBC\xE2\x0A\x02\x55\xEC\x32\x7C\xB9\x36\xFF\xE9\x36\x43', 29 | key 30 | ) 31 | 32 | key = kdf.pbkdf2('sha1', b'password', b'\x09\xb7\x8c\xf0\x0c\x7f\xf5\x4a', 2048, 24) 33 | self.assertEqual( 34 | b'\x00\x74\x9d\x47\x49\xa0\x88\x2b\xe9\x48\xb8\x65\x7b\xf2\x64\x97\xf1\x1e\xa2\xf9\xfc\xd4\x70\x46', 35 | key 36 | ) 37 | 38 | def test_python_pbkdf2(self): 39 | key = _pkcs5.pbkdf2('sha1', b'password', b'\x78\x57\x8E\x5A\x5D\x63\xCB\x06', 2048, 24) 40 | self.assertEqual( 41 | b'\xBF\xDE\x6B\xE9\x4D\xF7\xE1\x1D\xD4\x09\xBC\xE2\x0A\x02\x55\xEC\x32\x7C\xB9\x36\xFF\xE9\x36\x43', 42 | key 43 | ) 44 | 45 | key = _pkcs5.pbkdf2('sha1', b'password', b'\x09\xb7\x8c\xf0\x0c\x7f\xf5\x4a', 2048, 24) 46 | self.assertEqual( 47 | b'\x00\x74\x9d\x47\x49\xa0\x88\x2b\xe9\x48\xb8\x65\x7b\xf2\x64\x97\xf1\x1e\xa2\xf9\xfc\xd4\x70\x46', 48 | key 49 | ) 50 | 51 | def test_pkcs12_kdf(self): 52 | key = kdf.pkcs12_kdf('sha1', b'sesame', b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF', 2048, 24, 1) 53 | self.assertEqual( 54 | b'\x7C\xD9\xFD\x3E\x2B\x3B\xE7\x69\x1A\x44\xE3\xBE\xF0\xF9\xEA\x0F\xB9\xB8\x97\xD4\xE3\x25\xD9\xD1', 55 | key 56 | ) 57 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-4096.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 32 | cvBhUyF0F7JZSdJfolKShNKTj+pkECUDUWyS 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /oscrypto/_win/_crypt32.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from ._decode import _try_decode 6 | from .._ffi import buffer_from_bytes 7 | from .._types import str_cls 8 | 9 | if ffi() == 'cffi': 10 | from ._crypt32_cffi import crypt32, get_error 11 | else: 12 | from ._crypt32_ctypes import crypt32, get_error 13 | 14 | 15 | __all__ = [ 16 | 'crypt32', 17 | 'Crypt32Const', 18 | 'handle_error', 19 | ] 20 | 21 | 22 | def handle_error(result): 23 | """ 24 | Extracts the last Windows error message into a python unicode string 25 | 26 | :param result: 27 | A function result, 0 or None indicates failure 28 | 29 | :return: 30 | A unicode string error message 31 | """ 32 | 33 | if result: 34 | return 35 | 36 | _, error_string = get_error() 37 | 38 | if not isinstance(error_string, str_cls): 39 | error_string = _try_decode(error_string) 40 | 41 | raise OSError(error_string) 42 | 43 | 44 | class Crypt32Const(): 45 | X509_ASN_ENCODING = 1 46 | 47 | ERROR_INSUFFICIENT_BUFFER = 122 48 | CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG = 0x4 49 | CRYPT_E_NOT_FOUND = -2146885628 50 | 51 | CERT_STORE_PROV_MEMORY = b'Memory' 52 | CERT_STORE_CREATE_NEW_FLAG = 0x00002000 53 | CERT_STORE_ADD_USE_EXISTING = 2 54 | USAGE_MATCH_TYPE_OR = 1 55 | CERT_CHAIN_POLICY_SSL = 4 56 | AUTHTYPE_SERVER = 2 57 | CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG = 0x00000010 58 | CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS = 0x00000F00 59 | CERT_CHAIN_CACHE_END_CERT = 1 60 | CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY = 0x80000000 61 | 62 | TRUST_E_CERT_SIGNATURE = 0x80096004 63 | 64 | CERT_E_EXPIRED = 0x800B0101 65 | CERT_E_ROLE = 0x800B0103 66 | CERT_E_PURPOSE = 0x800B0106 67 | CERT_E_UNTRUSTEDROOT = 0x800B0109 68 | CERT_E_CN_NO_MATCH = 0x800B010F 69 | CRYPT_E_REVOKED = 0x80092010 70 | 71 | PKIX_KP_SERVER_AUTH = buffer_from_bytes(b"1.3.6.1.5.5.7.3.1\x00") 72 | SERVER_GATED_CRYPTO = buffer_from_bytes(b"1.3.6.1.4.1.311.10.3.3\x00") 73 | SGC_NETSCAPE = buffer_from_bytes(b"2.16.840.1.113730.4.1\x00") 74 | -------------------------------------------------------------------------------- /docs/oscrypto.md: -------------------------------------------------------------------------------- 1 | # oscrypto API Documentation 2 | 3 | The *oscrypto* module provides functions to obtain information about the 4 | backend being used, and allows a custom version of OpenSSL to be used on any 5 | platform. *These functions are rarely necessary. Using the `backend()` function 6 | for non-debugging purposes is likely a sign tight-coupling.* 7 | 8 | - [`backend()`](#backend-function) 9 | - [`use_openssl()`](#use_openssl-function) 10 | 11 | ### `backend()` function 12 | 13 | > ```python 14 | > def backend(): 15 | > """ 16 | > :return: 17 | > A unicode string of the backend being used: "openssl", "mac", "win", 18 | > "winlegacy" 19 | > """ 20 | > ``` 21 | 22 | ### `use_openssl()` function 23 | 24 | > ```python 25 | > def use_openssl(libcrypto_path, libssl_path, trust_list_path=None): 26 | > """ 27 | > :param libcrypto_path: 28 | > A unicode string of the file path to the OpenSSL/LibreSSL libcrypto 29 | > dynamic library. 30 | > 31 | > :param libssl_path: 32 | > A unicode string of the file path to the OpenSSL/LibreSSL libssl 33 | > dynamic library. 34 | > 35 | > :param trust_list_path: 36 | > An optional unicode string of the path to a file containing 37 | > OpenSSL-compatible CA certificates in PEM format. If this is not 38 | > provided and the platform is OS X or Windows, the system trust roots 39 | > will be exported from the OS and used for all TLS connections. 40 | > 41 | > :raises: 42 | > ValueError - when one of the paths is not a unicode string 43 | > OSError - when the trust_list_path does not exist on the filesystem 44 | > oscrypto.errors.LibraryNotFoundError - when one of the path does not exist on the filesystem 45 | > RuntimeError - when this function is called after another part of oscrypto has been imported 46 | > """ 47 | > ``` 48 | > 49 | > Forces using OpenSSL dynamic libraries on OS X (.dylib) or Windows (.dll), 50 | > or using a specific dynamic library on Linux/BSD (.so). 51 | > 52 | > This can also be used to configure oscrypto to use LibreSSL dynamic 53 | > libraries. 54 | > 55 | > This method must be called before any oscrypto submodules are imported. 56 | -------------------------------------------------------------------------------- /tests/test_legacy_module.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from oscrypto import backend 5 | 6 | from ._unittest_compat import patch 7 | from .unittest_data import data_decorator 8 | 9 | import sys 10 | import unittest 11 | 12 | patch() 13 | 14 | if sys.version_info < (3,): 15 | byte_cls = str 16 | else: 17 | byte_cls = bytes 18 | 19 | _backend = backend() 20 | 21 | if _backend == 'openssl': 22 | from oscrypto._openssl._libcrypto import libcrypto_legacy_support, libcrypto 23 | supports_legacy = libcrypto_legacy_support 24 | 25 | from oscrypto._openssl._libcrypto_ctypes import version_info 26 | from oscrypto._ffi import null 27 | 28 | 29 | @data_decorator 30 | class LegacyProviderTests(unittest.TestCase): 31 | 32 | # OSSL_PROVIDER_available and the legacy provider only exist since OpenSSL 3 33 | 34 | def test_checkLegacy(self): 35 | if (_backend != 'openssl' or version_info < (3, )): 36 | if (sys.version_info < (2, 7)): 37 | # Python 2.6 doesn't support "skipTest", so just return 38 | return 39 | self.skipTest("This test only makes sense with OpenSSL 3") 40 | 41 | # OSSL_PROVIDER_available does NOT express if a provider can be loaded. 42 | # It expresses if a provider has been loaded and can be used. 43 | 44 | is_avail = libcrypto.OSSL_PROVIDER_available(null(), "legacy".encode("ascii")) 45 | self.assertEqual(is_avail, libcrypto_legacy_support, "legacy provider loaded but libcrypto claims it's not") 46 | 47 | if not is_avail: 48 | # Currently not loaded. See if we can load it 49 | # If we can (if "is_avail" is true after this), then oscrypto should have automatically loaded it 50 | # to allow the user to use legacy encryptions. 51 | libcrypto.OSSL_PROVIDER_load(null(), "legacy".encode("ascii")) 52 | libcrypto.OSSL_PROVIDER_load(null(), "default".encode("ascii")) 53 | is_avail = libcrypto.OSSL_PROVIDER_available(null(), "legacy".encode("ascii")) 54 | 55 | self.assertEqual(is_avail, libcrypto_legacy_support, "legacy provider should have been loaded") 56 | -------------------------------------------------------------------------------- /tests/_socket_proxy.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | 5 | import socket 6 | import select 7 | import threading 8 | 9 | 10 | _sockets = {} 11 | _socket_lock = threading.Lock() 12 | 13 | 14 | def proxy(src, dst, callback=None): 15 | timeout = 10 16 | try: 17 | read_ready, _, _ = select.select([src], [], [], timeout) 18 | while len(read_ready): 19 | if callback: 20 | callback(src, dst) 21 | else: 22 | dst.send(src.recv(8192)) 23 | read_ready, _, _ = select.select([src], [], [], timeout) 24 | except (socket.error, select.error, OSError, ValueError): 25 | pass 26 | try: 27 | src.shutdown(socket.SHUT_RDWR) 28 | except (socket.error, OSError, ValueError): 29 | pass 30 | src.close() 31 | try: 32 | dst.shutdown(socket.SHUT_RDWR) 33 | except (socket.error, OSError, ValueError): 34 | pass 35 | dst.close() 36 | 37 | 38 | def listen(server, ip, port, send_callback, recv_callback): 39 | lsock, laddr = server.accept() 40 | rsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 41 | rsock.connect((ip, port)) 42 | with _socket_lock: 43 | _sockets[threading.current_thread().ident] = { 44 | 'lsock': lsock, 45 | 'rsock': rsock 46 | } 47 | t1 = threading.Thread(target=proxy, args=(rsock, lsock, recv_callback)) 48 | t2 = threading.Thread(target=proxy, args=(lsock, rsock, send_callback)) 49 | t1.start() 50 | t2.start() 51 | 52 | 53 | def make_socket_proxy(ip, port, send_callback=None, recv_callback=None): 54 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 55 | server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 56 | server.bind(('', 8080)) 57 | server.listen(1) 58 | t = threading.Thread( 59 | target=listen, 60 | args=(server, ip, port, send_callback, recv_callback) 61 | ) 62 | t.start() 63 | sock = socket.create_connection(('localhost', 8080)) 64 | sock.settimeout(1) 65 | t.join() 66 | with _socket_lock: 67 | data = _sockets[t.ident] 68 | return (sock, data['lsock'], data['rsock'], server) 69 | -------------------------------------------------------------------------------- /dev/ci-driver.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | import platform 6 | import sys 7 | import subprocess 8 | 9 | 10 | run_args = [ 11 | { 12 | 'name': 'cffi', 13 | 'kwarg': 'cffi', 14 | }, 15 | { 16 | 'name': 'openssl', 17 | 'kwarg': 'openssl', 18 | }, 19 | { 20 | 'name': 'winlegacy', 21 | 'kwarg': 'winlegacy', 22 | }, 23 | ] 24 | 25 | 26 | def _write_env(env, key, value): 27 | sys.stdout.write("%s: %s\n" % (key, value)) 28 | sys.stdout.flush() 29 | if sys.version_info < (3,): 30 | env[key.encode('utf-8')] = value.encode('utf-8') 31 | else: 32 | env[key] = value 33 | 34 | 35 | def run(**_): 36 | """ 37 | Runs CI, setting various env vars 38 | 39 | :return: 40 | A bool - if the CI ran successfully 41 | """ 42 | 43 | env = os.environ.copy() 44 | options = set(sys.argv[2:]) 45 | 46 | newline = False 47 | if 'cffi' not in options: 48 | _write_env(env, 'OSCRYPTO_USE_CTYPES', 'true') 49 | newline = True 50 | if 'openssl' in options and sys.platform == 'darwin': 51 | mac_version_info = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) 52 | if mac_version_info < (10, 15): 53 | _write_env(env, 'OSCRYPTO_USE_OPENSSL', '/usr/lib/libcrypto.dylib,/usr/lib/libssl.dylib') 54 | else: 55 | _write_env(env, 'OSCRYPTO_USE_OPENSSL', '/usr/lib/libcrypto.42.dylib,/usr/lib/libssl.44.dylib') 56 | newline = True 57 | if 'openssl3' in options and sys.platform == 'darwin': 58 | _write_env( 59 | env, 60 | 'OSCRYPTO_USE_OPENSSL', 61 | '/usr/local/opt/openssl@3/lib/libcrypto.dylib,/usr/local/opt/openssl@3/lib/libssl.dylib' 62 | ) 63 | if 'winlegacy' in options: 64 | _write_env(env, 'OSCRYPTO_USE_WINLEGACY', 'true') 65 | newline = True 66 | 67 | if newline: 68 | sys.stdout.write("\n") 69 | 70 | proc = subprocess.Popen( 71 | [ 72 | sys.executable, 73 | 'run.py', 74 | 'ci', 75 | ], 76 | env=env 77 | ) 78 | proc.communicate() 79 | return proc.returncode == 0 80 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa-2048.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 34 | A/ZgHB/3k4g= 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /oscrypto/_asn1.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | # This file exists strictly to make it easier to vendor a combination of 5 | # oscrypto and asn1crypto 6 | 7 | from asn1crypto import algos, cms, core, keys, pem, pkcs12, util, x509 8 | 9 | DHParameters = algos.DHParameters 10 | DSASignature = algos.DSASignature 11 | KeyExchangeAlgorithm = algos.KeyExchangeAlgorithm 12 | Pbkdf2Salt = algos.Pbkdf2Salt 13 | 14 | EncryptedData = cms.EncryptedData 15 | 16 | Integer = core.Integer 17 | Null = core.Null 18 | OctetString = core.OctetString 19 | 20 | DSAParams = keys.DSAParams 21 | DSAPrivateKey = keys.DSAPrivateKey 22 | ECDomainParameters = keys.ECDomainParameters 23 | ECPointBitString = keys.ECPointBitString 24 | ECPrivateKey = keys.ECPrivateKey 25 | EncryptedPrivateKeyInfo = keys.EncryptedPrivateKeyInfo 26 | PrivateKeyAlgorithm = keys.PrivateKeyAlgorithm 27 | PrivateKeyInfo = keys.PrivateKeyInfo 28 | PublicKeyAlgorithm = keys.PublicKeyAlgorithm 29 | PublicKeyInfo = keys.PublicKeyInfo 30 | RSAPrivateKey = keys.RSAPrivateKey 31 | RSAPublicKey = keys.RSAPublicKey 32 | 33 | int_from_bytes = util.int_from_bytes 34 | int_to_bytes = util.int_to_bytes 35 | OrderedDict = util.OrderedDict 36 | timezone = util.timezone 37 | 38 | armor = pem.armor 39 | unarmor = pem.unarmor 40 | 41 | CertBag = pkcs12.CertBag 42 | Pfx = pkcs12.Pfx 43 | SafeContents = pkcs12.SafeContents 44 | 45 | Certificate = x509.Certificate 46 | TrustedCertificate = x509.TrustedCertificate 47 | 48 | __all__ = [ 49 | 'armor', 50 | 'CertBag', 51 | 'Certificate', 52 | 'DHParameters', 53 | 'DSAParams', 54 | 'DSAPrivateKey', 55 | 'DSASignature', 56 | 'ECDomainParameters', 57 | 'ECPointBitString', 58 | 'ECPrivateKey', 59 | 'EncryptedData', 60 | 'EncryptedPrivateKeyInfo', 61 | 'int_from_bytes', 62 | 'int_to_bytes', 63 | 'Integer', 64 | 'KeyExchangeAlgorithm', 65 | 'Null', 66 | 'OctetString', 67 | 'OrderedDict', 68 | 'Pbkdf2Salt', 69 | 'Pfx', 70 | 'PrivateKeyAlgorithm', 71 | 'PrivateKeyInfo', 72 | 'PublicKeyAlgorithm', 73 | 'PublicKeyInfo', 74 | 'RSAPrivateKey', 75 | 'RSAPublicKey', 76 | 'SafeContents', 77 | 'timezone', 78 | 'TrustedCertificate', 79 | 'unarmor', 80 | ] 81 | -------------------------------------------------------------------------------- /tests/fixtures/digicert_ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGWDCCBUCgAwIBAgIQCl8RTQNbF5EX0u/UA4w/OzANBgkqhkiG9w0BAQUFADBs 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j 5 | ZSBFViBSb290IENBMB4XDTA4MDQwMjEyMDAwMFoXDTIyMDQwMzAwMDAwMFowZjEL 6 | MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 7 | LmRpZ2ljZXJ0LmNvbTElMCMGA1UEAxMcRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug 8 | Q0EtMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9hCikQH17+NDdR 9 | CPge+yLtYb4LDXBMUGMmdRW5QYiXtvCgFbsIYOBC6AUpEIc2iihlqO8xB3RtNpcv 10 | KEZmBMcqeSZ6mdWOw21PoF6tvD2Rwll7XjZswFPPAAgyPhBkWBATaccM7pxCUQD5 11 | BUTuJM56H+2MEb0SqPMV9Bx6MWkBG6fmXcCabH4JnudSREoQOiPkm7YDr6ictFuf 12 | 1EutkozOtREqqjcYjbTCuNhcBoz4/yO9NV7UfD5+gw6RlgWYw7If48hl66l7XaAs 13 | zPw82W3tzPpLQ4zJ1LilYRyyQLYoEt+5+F/+07LJ7z20Hkt8HEyZNp496+ynaF4d 14 | 32duXvsCAwEAAaOCAvowggL2MA4GA1UdDwEB/wQEAwIBhjCCAcYGA1UdIASCAb0w 15 | ggG5MIIBtQYLYIZIAYb9bAEDAAIwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3 16 | LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUH 17 | AgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQBy 18 | AHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBj 19 | AGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAg 20 | AEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQ 21 | AGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBt 22 | AGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBj 23 | AG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBl 24 | AHIAZQBuAGMAZQAuMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYIKwYBBQUHAQEEKDAm 25 | MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wgY8GA1UdHwSB 26 | hzCBhDBAoD6gPIY6aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGln 27 | aEFzc3VyYW5jZUVWUm9vdENBLmNybDBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNl 28 | cnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDAfBgNVHSME 29 | GDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzAdBgNVHQ4EFgQUUOpzidsp+xCPnuUB 30 | INTeeZlIg/cwDQYJKoZIhvcNAQEFBQADggEBAB7ipUiebNtTOA/vphoqrOIDQ+2a 31 | vD6OdRvw/S4iWawTwGHi5/rpmc2HCXVUKL9GYNy+USyS8xuRfDEIcOI3ucFbqL2j 32 | CwD7GhX9A61YasXHJJlIR0YxHpLvtF9ONMeQvzHB+LGEhtCcAarfilYGzjrpDq6X 33 | dF3XcZpCdF/ejUN83ulV7WkAywXgemFhM9EZTfkI7qA5xSU1tyvED7Ld8aW3DiTE 34 | JiiNeXf1L/BXunwH1OH8zVowV36GEEfdMR/X/KLCvzB8XSSq6PmuX2p0ws5rs0bY 35 | Ib4p1I5eFdZCSucyb6Sxa1GDWL4/bcf72gMhy2oWGU4K8K2Eyl2Us1p292E= 36 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /tests/unittest_data.py: -------------------------------------------------------------------------------- 1 | # Written by Will Bond 2 | # 3 | # The author or authors of this code dedicate any and all copyright interest in 4 | # this code to the public domain. We make this dedication for the benefit of the 5 | # public at large and to the detriment of our heirs and successors. We intend 6 | # this dedication to be an overt act of relinquishment in perpetuity of all 7 | # present and future rights to this code under copyright law. 8 | 9 | 10 | def data(provider_method, first_param_name_suffix=False): 11 | """ 12 | A method decorator for unittest.TestCase classes that configured a 13 | static method to be used to provide multiple sets of test data to a single 14 | test 15 | 16 | :param provider_method: 17 | The name of the staticmethod of the class to use as the data provider 18 | 19 | :param first_param_name_suffix: 20 | If the first parameter for each set should be appended to the method 21 | name to generate the name of the test. Otherwise integers are used. 22 | 23 | :return: 24 | The decorated function 25 | """ 26 | 27 | def test_func_decorator(test_func): 28 | test_func._provider_method = provider_method 29 | test_func._provider_name_suffix = first_param_name_suffix 30 | return test_func 31 | return test_func_decorator 32 | 33 | 34 | def data_decorator(cls): 35 | """ 36 | A class decorator that works with the @provider decorator to generate test 37 | method from a data provider 38 | """ 39 | 40 | def generate_test_func(name, original_function, num, params): 41 | if original_function._provider_name_suffix: 42 | data_name = params[0] 43 | params = params[1:] 44 | else: 45 | data_name = num 46 | expanded_name = 'test_%s_%s' % (name, data_name) 47 | 48 | # We used expanded variable names here since this line is present in 49 | # backtraces that are generated from test failures. 50 | def generated_test_function(self): 51 | original_function(self, *params) 52 | 53 | setattr(cls, expanded_name, generated_test_function) 54 | 55 | for name in dir(cls): 56 | func = getattr(cls, name) 57 | if hasattr(func, '_provider_method'): 58 | num = 1 59 | for params in getattr(cls, func._provider_method)(): 60 | generate_test_func(name, func, num, params) 61 | num += 1 62 | 63 | return cls 64 | -------------------------------------------------------------------------------- /oscrypto/errors.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | import socket 6 | 7 | 8 | __all__ = [ 9 | 'AsymmetricKeyError', 10 | 'CACertsError', 11 | 'LibraryNotFoundError', 12 | 'SignatureError', 13 | 'TLSError', 14 | 'TLSConnectionError', 15 | 'TLSDisconnectError', 16 | 'TLSGracefulDisconnectError', 17 | 'TLSVerificationError', 18 | ] 19 | 20 | 21 | class LibraryNotFoundError(Exception): 22 | 23 | """ 24 | An exception when trying to find a shared library 25 | """ 26 | 27 | pass 28 | 29 | 30 | class SignatureError(Exception): 31 | 32 | """ 33 | An exception when validating a signature 34 | """ 35 | 36 | pass 37 | 38 | 39 | class AsymmetricKeyError(Exception): 40 | 41 | """ 42 | An exception when a key is invalid or unsupported 43 | """ 44 | 45 | pass 46 | 47 | 48 | class IncompleteAsymmetricKeyError(AsymmetricKeyError): 49 | 50 | """ 51 | An exception when a key is missing necessary information 52 | """ 53 | 54 | pass 55 | 56 | 57 | class CACertsError(Exception): 58 | 59 | """ 60 | An exception when exporting CA certs from the OS trust store 61 | """ 62 | 63 | pass 64 | 65 | 66 | class TLSError(socket.error): 67 | 68 | """ 69 | An exception related to TLS functionality 70 | """ 71 | 72 | message = None 73 | 74 | def __init__(self, message): 75 | self.args = (message,) 76 | self.message = message 77 | 78 | def __str__(self): 79 | output = self.__unicode__() 80 | if sys.version_info < (3,): 81 | output = output.encode('utf-8') 82 | return output 83 | 84 | def __unicode__(self): 85 | return self.message 86 | 87 | 88 | class TLSConnectionError(TLSError): 89 | pass 90 | 91 | 92 | class TLSDisconnectError(TLSConnectionError): 93 | pass 94 | 95 | 96 | class TLSGracefulDisconnectError(TLSDisconnectError): 97 | pass 98 | 99 | 100 | class TLSVerificationError(TLSError): 101 | 102 | """ 103 | A server certificate verification error happened during a TLS handshake 104 | """ 105 | 106 | certificate = None 107 | 108 | def __init__(self, message, certificate): 109 | TLSError.__init__(self, message) 110 | self.certificate = certificate 111 | self.args = (message, certificate) 112 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-dsa.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 39 | jtP1bbo4zQ== 40 | -----END CERTIFICATE----- 41 | -------------------------------------------------------------------------------- /dev/python-install.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | import shutil 6 | import subprocess 7 | import sys 8 | from urllib.parse import urlparse 9 | from urllib.request import urlopen 10 | 11 | 12 | run_args = [ 13 | { 14 | 'name': 'version', 15 | 'kwarg': 'version', 16 | }, 17 | { 18 | 'name': 'arch', 19 | 'kwarg': 'arch', 20 | }, 21 | ] 22 | 23 | 24 | def run(version=None, arch=None): 25 | """ 26 | Installs a version of Python on Windows 27 | 28 | :return: 29 | A bool - if Python was installed successfully 30 | """ 31 | 32 | if sys.platform != 'win32': 33 | raise ValueError('python-install is only designed for Windows') 34 | 35 | if version not in set(['2.6', '2.7', '3.3']): 36 | raise ValueError('Invalid version: %r' % version) 37 | 38 | if arch not in set(['x86', 'x64']): 39 | raise ValueError('Invalid arch: %r' % arch) 40 | 41 | if version == '2.6': 42 | if arch == 'x64': 43 | url = 'https://www.python.org/ftp/python/2.6.6/python-2.6.6.amd64.msi' 44 | else: 45 | url = 'https://www.python.org/ftp/python/2.6.6/python-2.6.6.msi' 46 | elif version == '2.7': 47 | if arch == 'x64': 48 | url = 'https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi' 49 | else: 50 | url = 'https://www.python.org/ftp/python/2.7.18/python-2.7.18.msi' 51 | else: 52 | if arch == 'x64': 53 | url = 'https://www.python.org/ftp/python/3.3.5/python-3.3.5.amd64.msi' 54 | else: 55 | url = 'https://www.python.org/ftp/python/3.3.5/python-3.3.5.msi' 56 | 57 | home = os.environ.get('USERPROFILE') 58 | msi_filename = os.path.basename(urlparse(url).path) 59 | msi_path = os.path.join(home, msi_filename) 60 | install_path = os.path.join(os.environ.get('LOCALAPPDATA'), 'Python%s-%s' % (version, arch)) 61 | 62 | if os.path.exists(os.path.join(install_path, 'python.exe')): 63 | print(install_path) 64 | return True 65 | 66 | try: 67 | with urlopen(url) as r, open(msi_path, 'wb') as f: 68 | shutil.copyfileobj(r, f) 69 | 70 | proc = subprocess.Popen( 71 | 'msiexec /passive /a %s TARGETDIR=%s' % (msi_filename, install_path), 72 | shell=True, 73 | cwd=home 74 | ) 75 | proc.communicate() 76 | 77 | finally: 78 | if os.path.exists(msi_path): 79 | os.unlink(msi_path) 80 | 81 | print(install_path) 82 | return True 83 | -------------------------------------------------------------------------------- /dev/tests.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import unittest 5 | import re 6 | import sys 7 | import warnings 8 | 9 | from . import requires_oscrypto 10 | from ._import import _preload 11 | 12 | from tests import test_classes 13 | 14 | if sys.version_info < (3,): 15 | range = xrange # noqa 16 | from cStringIO import StringIO 17 | else: 18 | from io import StringIO 19 | 20 | 21 | run_args = [ 22 | { 23 | 'name': 'regex', 24 | 'kwarg': 'matcher', 25 | }, 26 | { 27 | 'name': 'repeat_count', 28 | 'kwarg': 'repeat', 29 | 'cast': 'int', 30 | }, 31 | ] 32 | 33 | 34 | def run(matcher=None, repeat=1, ci=False): 35 | """ 36 | Runs the tests 37 | 38 | :param matcher: 39 | A unicode string containing a regular expression to use to filter test 40 | names by. A value of None will cause no filtering. 41 | 42 | :param repeat: 43 | An integer - the number of times to run the tests 44 | 45 | :param ci: 46 | A bool, indicating if the tests are being run as part of CI 47 | 48 | :return: 49 | A bool - if the tests succeeded 50 | """ 51 | 52 | _preload(requires_oscrypto, not ci) 53 | 54 | warnings.filterwarnings("error") 55 | 56 | loader = unittest.TestLoader() 57 | # We have to manually track the list of applicable tests because for 58 | # some reason with Python 3.4 on Windows, the tests in a suite are replaced 59 | # with None after being executed. This breaks the repeat functionality. 60 | test_list = [] 61 | for test_class in test_classes(): 62 | if matcher: 63 | names = loader.getTestCaseNames(test_class) 64 | for name in names: 65 | if re.search(matcher, name): 66 | test_list.append(test_class(name)) 67 | else: 68 | test_list.append(loader.loadTestsFromTestCase(test_class)) 69 | 70 | stream = sys.stdout 71 | verbosity = 1 72 | if matcher and repeat == 1: 73 | verbosity = 2 74 | elif repeat > 1: 75 | stream = StringIO() 76 | 77 | for _ in range(0, repeat): 78 | suite = unittest.TestSuite() 79 | for test in test_list: 80 | suite.addTest(test) 81 | result = unittest.TextTestRunner(stream=stream, verbosity=verbosity).run(suite) 82 | 83 | if len(result.errors) > 0 or len(result.failures) > 0: 84 | if repeat > 1: 85 | print(stream.getvalue()) 86 | return False 87 | 88 | if repeat > 1: 89 | stream.truncate(0) 90 | 91 | return True 92 | -------------------------------------------------------------------------------- /dev/version.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import codecs 5 | import os 6 | import re 7 | 8 | from . import package_root, package_name, has_tests_package 9 | 10 | 11 | run_args = [ 12 | { 13 | 'name': 'pep440_version', 14 | 'required': True 15 | }, 16 | ] 17 | 18 | 19 | def run(new_version): 20 | """ 21 | Updates the package version in the various locations 22 | 23 | :param new_version: 24 | A unicode string of the new library version as a PEP 440 version 25 | 26 | :return: 27 | A bool - if the version number was successfully bumped 28 | """ 29 | 30 | # We use a restricted form of PEP 440 versions 31 | version_match = re.match( 32 | r'(\d+)\.(\d+)\.(\d)+(?:\.((?:dev|a|b|rc)\d+))?$', 33 | new_version 34 | ) 35 | if not version_match: 36 | raise ValueError('Invalid PEP 440 version: %s' % new_version) 37 | 38 | new_version_info = ( 39 | int(version_match.group(1)), 40 | int(version_match.group(2)), 41 | int(version_match.group(3)), 42 | ) 43 | if version_match.group(4): 44 | new_version_info += (version_match.group(4),) 45 | 46 | version_path = os.path.join(package_root, package_name, 'version.py') 47 | setup_path = os.path.join(package_root, 'setup.py') 48 | setup_tests_path = os.path.join(package_root, 'tests', 'setup.py') 49 | tests_path = os.path.join(package_root, 'tests', '__init__.py') 50 | 51 | file_paths = [version_path, setup_path] 52 | if has_tests_package: 53 | file_paths.extend([setup_tests_path, tests_path]) 54 | 55 | for file_path in file_paths: 56 | orig_source = '' 57 | with codecs.open(file_path, 'r', encoding='utf-8') as f: 58 | orig_source = f.read() 59 | 60 | found = 0 61 | new_source = '' 62 | for line in orig_source.splitlines(True): 63 | if line.startswith('__version__ = '): 64 | found += 1 65 | new_source += '__version__ = %r\n' % new_version 66 | elif line.startswith('__version_info__ = '): 67 | found += 1 68 | new_source += '__version_info__ = %r\n' % (new_version_info,) 69 | elif line.startswith('PACKAGE_VERSION = '): 70 | found += 1 71 | new_source += 'PACKAGE_VERSION = %r\n' % new_version 72 | else: 73 | new_source += line 74 | 75 | if found == 0: 76 | raise ValueError('Did not find any versions in %s' % file_path) 77 | 78 | s = 's' if found > 1 else '' 79 | rel_path = file_path[len(package_root) + 1:] 80 | was_were = 'was' if found == 1 else 'were' 81 | if new_source != orig_source: 82 | print('Updated %d version%s in %s' % (found, s, rel_path)) 83 | with codecs.open(file_path, 'w', encoding='utf-8') as f: 84 | f.write(new_source) 85 | else: 86 | print('%d version%s in %s %s up-to-date' % (found, s, rel_path, was_were)) 87 | 88 | return True 89 | -------------------------------------------------------------------------------- /dev/build.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | import tarfile 6 | import zipfile 7 | 8 | import setuptools.sandbox 9 | 10 | from . import package_root, package_name, has_tests_package 11 | from ._import import _import_from 12 | 13 | 14 | def _list_zip(filename): 15 | """ 16 | Prints all of the files in a .zip file 17 | """ 18 | 19 | zf = zipfile.ZipFile(filename, 'r') 20 | for name in zf.namelist(): 21 | print(' %s' % name) 22 | 23 | 24 | def _list_tgz(filename): 25 | """ 26 | Prints all of the files in a .tar.gz file 27 | """ 28 | 29 | tf = tarfile.open(filename, 'r:gz') 30 | for name in tf.getnames(): 31 | print(' %s' % name) 32 | 33 | 34 | def run(): 35 | """ 36 | Creates a sdist .tar.gz and a bdist_wheel --univeral .whl 37 | 38 | :return: 39 | A bool - if the packaging process was successful 40 | """ 41 | 42 | setup = os.path.join(package_root, 'setup.py') 43 | tests_root = os.path.join(package_root, 'tests') 44 | tests_setup = os.path.join(tests_root, 'setup.py') 45 | 46 | # Trying to call setuptools.sandbox.run_setup(setup, ['--version']) 47 | # resulted in a segfault, so we do this instead 48 | package_dir = os.path.join(package_root, package_name) 49 | version_mod = _import_from('%s.version' % package_name, package_dir, 'version') 50 | 51 | pkg_name_info = (package_name, version_mod.__version__) 52 | print('Building %s-%s' % pkg_name_info) 53 | 54 | sdist = '%s-%s.tar.gz' % pkg_name_info 55 | whl = '%s-%s-py2.py3-none-any.whl' % pkg_name_info 56 | setuptools.sandbox.run_setup(setup, ['-q', 'sdist']) 57 | print(' - created %s' % sdist) 58 | _list_tgz(os.path.join(package_root, 'dist', sdist)) 59 | setuptools.sandbox.run_setup(setup, ['-q', 'bdist_wheel', '--universal']) 60 | print(' - created %s' % whl) 61 | _list_zip(os.path.join(package_root, 'dist', whl)) 62 | setuptools.sandbox.run_setup(setup, ['-q', 'clean']) 63 | 64 | if has_tests_package: 65 | print('Building %s_tests-%s' % (package_name, version_mod.__version__)) 66 | 67 | tests_sdist = '%s_tests-%s.tar.gz' % pkg_name_info 68 | tests_whl = '%s_tests-%s-py2.py3-none-any.whl' % pkg_name_info 69 | setuptools.sandbox.run_setup(tests_setup, ['-q', 'sdist']) 70 | print(' - created %s' % tests_sdist) 71 | _list_tgz(os.path.join(tests_root, 'dist', tests_sdist)) 72 | setuptools.sandbox.run_setup(tests_setup, ['-q', 'bdist_wheel', '--universal']) 73 | print(' - created %s' % tests_whl) 74 | _list_zip(os.path.join(tests_root, 'dist', tests_whl)) 75 | setuptools.sandbox.run_setup(tests_setup, ['-q', 'clean']) 76 | 77 | dist_dir = os.path.join(package_root, 'dist') 78 | tests_dist_dir = os.path.join(tests_root, 'dist') 79 | os.rename( 80 | os.path.join(tests_dist_dir, tests_sdist), 81 | os.path.join(dist_dir, tests_sdist) 82 | ) 83 | os.rename( 84 | os.path.join(tests_dist_dir, tests_whl), 85 | os.path.join(dist_dir, tests_whl) 86 | ) 87 | os.rmdir(tests_dist_dir) 88 | 89 | return True 90 | -------------------------------------------------------------------------------- /tests/test_trust_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import hashlib 5 | import os 6 | import unittest 7 | import sys 8 | 9 | from oscrypto import trust_list 10 | from asn1crypto import x509, pem 11 | 12 | from ._unittest_compat import patch 13 | 14 | patch() 15 | 16 | if sys.version_info < (3,): 17 | str_cls = unicode # noqa 18 | byte_cls = str 19 | else: 20 | str_cls = str 21 | byte_cls = bytes 22 | 23 | 24 | tests_root = os.path.dirname(__file__) 25 | fixtures_dir = os.path.join(tests_root, 'fixtures') 26 | 27 | digicert_ca_path = os.path.join(fixtures_dir, 'digicert_ca.crt') 28 | 29 | 30 | class TrustListTests(unittest.TestCase): 31 | 32 | def test_get_list(self): 33 | trust_list.clear_cache() 34 | 35 | certs = trust_list.get_list() 36 | self.assertIsInstance(certs, list) 37 | self.assertLess(10, len(certs)) 38 | for cert, trust_oids, reject_oids in certs: 39 | self.assertIsInstance(cert, x509.Certificate) 40 | self.assertIsInstance(trust_oids, set) 41 | self.assertIsInstance(reject_oids, set) 42 | cert.native 43 | 44 | def test_get_list_callback(self): 45 | trust_list.clear_cache() 46 | 47 | lambda_data = {'calls': 0, 'reasons': 0, 'certs': {}} 48 | 49 | def cb(cert, reason): 50 | if reason is not None: 51 | self.assertIsInstance(reason, str_cls) 52 | lambda_data['reasons'] += 1 53 | self.assertIsInstance(cert, x509.Certificate) 54 | sha1 = hashlib.sha1(cert.dump()).digest() 55 | message = None 56 | if sha1 in lambda_data['certs']: 57 | message = 'Certificate (%s) already passed to callback' % cert.subject.human_friendly 58 | self.assertNotIn(sha1, lambda_data['certs'], message) 59 | lambda_data['certs'][sha1] = True 60 | lambda_data['calls'] += 1 61 | 62 | certs = trust_list.get_list(cert_callback=cb) 63 | self.assertIsInstance(certs, list) 64 | self.assertLess(10, len(certs)) 65 | self.assertLessEqual(len(certs), lambda_data['calls']) 66 | self.assertEqual(lambda_data['calls'] - len(certs), lambda_data['reasons']) 67 | for cert, trust_oids, reject_oids in certs: 68 | self.assertIsInstance(cert, x509.Certificate) 69 | self.assertIsInstance(trust_oids, set) 70 | self.assertIsInstance(reject_oids, set) 71 | cert.native 72 | 73 | def test_get_list_mutate(self): 74 | trust_list.clear_cache() 75 | 76 | certs = trust_list.get_list() 77 | certs2 = trust_list.get_list() 78 | 79 | with open(digicert_ca_path, 'rb') as f: 80 | _, _, digicert_ca_bytes = pem.unarmor(f.read()) 81 | digicert_ca_cert = x509.Certificate.load(digicert_ca_bytes) 82 | certs.append(digicert_ca_cert) 83 | 84 | self.assertNotEqual(certs2, certs) 85 | 86 | def test_get_path(self): 87 | trust_list.clear_cache() 88 | 89 | certs = trust_list.get_path() 90 | with open(certs, 'rb') as f: 91 | cert_data = f.read() 92 | self.assertEqual(True, pem.detect(cert_data)) 93 | self.assertLess(10240, len(cert_data)) 94 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-4096.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | 9fiCcEiyfVs35wXjsfHm9YjRWQlx6qo= 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /oscrypto/_openssl/_libssl.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import re 5 | import sys 6 | 7 | from .. import ffi, _backend_config 8 | 9 | # Initialize OpenSSL 10 | from ._libcrypto import libcrypto_version_info 11 | 12 | if ffi() == 'cffi': 13 | from ._libssl_cffi import libssl 14 | else: 15 | from ._libssl_ctypes import libssl 16 | 17 | 18 | __all__ = [ 19 | 'libssl', 20 | 'LibsslConst', 21 | 'error_code_version_info', 22 | ] 23 | 24 | 25 | if libcrypto_version_info < (1, 1): 26 | libssl.SSL_library_init() 27 | # Enables SHA2 algorithms on 0.9.8n and older 28 | if libcrypto_version_info < (1, 0): 29 | libssl.OPENSSL_add_all_algorithms_noconf() 30 | 31 | 32 | class LibsslConst(): 33 | ERR_LIB_ASN1 = 13 34 | ERR_LIB_SSL = 20 35 | 36 | SSL_CTRL_OPTIONS = 32 37 | SSL_CTRL_SET_SESS_CACHE_MODE = 44 38 | 39 | SSL_VERIFY_NONE = 0 40 | SSL_VERIFY_PEER = 1 41 | 42 | SSL_ST_OK = 3 43 | 44 | SSL_ERROR_WANT_READ = 2 45 | SSL_ERROR_WANT_WRITE = 3 46 | SSL_ERROR_ZERO_RETURN = 6 47 | 48 | SSL_OP_NO_SSLv2 = 0x01000000 49 | SSL_OP_NO_SSLv3 = 0x02000000 50 | SSL_OP_NO_TLSv1 = 0x04000000 51 | SSL_OP_NO_TLSv1_2 = 0x08000000 52 | SSL_OP_NO_TLSv1_1 = 0x10000000 53 | 54 | SSL_SESS_CACHE_CLIENT = 0x0001 55 | 56 | SSL_R_NO_SHARED_CIPHER = 193 57 | 58 | SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM = 130 59 | SSL_F_SSL3_GET_KEY_EXCHANGE = 141 60 | SSL_F_SSL3_GET_SERVER_CERTIFICATE = 144 61 | SSL_R_BAD_DH_P_LENGTH = 110 62 | SSL_R_CERTIFICATE_VERIFY_FAILED = 134 63 | SSL_R_UNKNOWN_PROTOCOL = 252 64 | SSL_R_DH_KEY_TOO_SMALL = 372 65 | 66 | # OpenSSL 1.1.0 67 | SSL_F_TLS_PROCESS_SKE_DHE = 419 68 | SSL_F_SSL3_GET_RECORD = 143 69 | SSL_R_WRONG_VERSION_NUMBER = 267 70 | SSL_F_TLS_PROCESS_SERVER_CERTIFICATE = 367 71 | 72 | # OpenSSL < 1.1.0 73 | SSL_F_SSL23_GET_SERVER_HELLO = 119 74 | SSL_F_SSL3_READ_BYTES = 148 75 | SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE = 1040 76 | SSL_R_TLSV1_ALERT_PROTOCOL_VERSION = 1070 77 | 78 | SSL_CTRL_SET_TLSEXT_HOSTNAME = 55 79 | TLSEXT_NAMETYPE_host_name = 0 80 | 81 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20 82 | X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19 83 | X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18 84 | 85 | X509_V_ERR_CERT_NOT_YET_VALID = 9 86 | X509_V_ERR_CERT_HAS_EXPIRED = 10 87 | 88 | ASN1_F_ASN1_ITEM_VERIFY = 197 89 | ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM = 161 90 | 91 | 92 | if libcrypto_version_info >= (1, 1, 0): 93 | LibsslConst.SSL_R_DH_KEY_TOO_SMALL = 394 94 | 95 | 96 | error_code_version_info = libcrypto_version_info 97 | # The Apple version of libssl seems to have changed various codes for 98 | # some reason, but the rest of the API is still OpenSSL 1.0.1 99 | if sys.platform == 'darwin': 100 | libssl_abi_match = re.match(r'/usr/lib/libssl\.(\d+)', _backend_config().get('libssl_path', '')) 101 | if libssl_abi_match and int(libssl_abi_match.group(1)) >= 44: 102 | LibsslConst.SSL_F_TLS_PROCESS_SERVER_CERTIFICATE = 7 103 | LibsslConst.SSL_F_SSL3_GET_KEY_EXCHANGE = 9 104 | LibsslConst.SSL_F_SSL3_READ_BYTES = 4 105 | LibsslConst.SSL_F_SSL3_GET_RECORD = 4 106 | LibsslConst.SSL_F_SSL23_GET_SERVER_HELLO = 4 107 | error_code_version_info = (1, 1, 0) 108 | -------------------------------------------------------------------------------- /oscrypto/_openssl/_libssl_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import _backend_config 5 | from .._ffi import get_library, register_ffi 6 | from ..errors import LibraryNotFoundError 7 | from ._libcrypto import libcrypto_version_info 8 | 9 | from cffi import FFI 10 | 11 | 12 | __all__ = [ 13 | 'libssl', 14 | ] 15 | 16 | 17 | ffi = FFI() 18 | 19 | libssl_path = _backend_config().get('libssl_path') 20 | if libssl_path is None: 21 | libssl_path = get_library('ssl', 'libssl', '44') 22 | if not libssl_path: 23 | raise LibraryNotFoundError('The library libssl could not be found') 24 | 25 | libssl = ffi.dlopen(libssl_path) 26 | register_ffi(libssl, ffi) 27 | 28 | ffi.cdef(""" 29 | typedef ... SSL_METHOD; 30 | typedef uintptr_t SSL_CTX; 31 | typedef ... SSL_SESSION; 32 | typedef uintptr_t SSL; 33 | typedef ... BIO_METHOD; 34 | typedef uintptr_t BIO; 35 | typedef uintptr_t X509; 36 | typedef ... X509_STORE; 37 | typedef ... X509_STORE_CTX; 38 | typedef uintptr_t _STACK; 39 | 40 | BIO_METHOD *BIO_s_mem(void); 41 | BIO *BIO_new(BIO_METHOD *type); 42 | int BIO_free(BIO *a); 43 | int BIO_read(BIO *b, void *buf, int len); 44 | int BIO_write(BIO *b, const void *buf, int len); 45 | size_t BIO_ctrl_pending(BIO *b); 46 | 47 | SSL_CTX *SSL_CTX_new(const SSL_METHOD *method); 48 | long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); 49 | void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, 50 | int (*verify_callback)(int, X509_STORE_CTX *)); 51 | int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); 52 | int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, 53 | const char *CApath); 54 | long SSL_get_verify_result(const SSL *ssl); 55 | X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); 56 | int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); 57 | int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); 58 | long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); 59 | void SSL_CTX_free(SSL_CTX *a); 60 | 61 | SSL *SSL_new(SSL_CTX *ctx); 62 | void SSL_free(SSL *ssl); 63 | void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); 64 | long SSL_ctrl(SSL *ssl, int cmd, long larg, void *parg); 65 | _STACK *SSL_get_peer_cert_chain(const SSL *s); 66 | 67 | SSL_SESSION *SSL_get1_session(const SSL *ssl); 68 | int SSL_set_session(SSL *ssl, SSL_SESSION *session); 69 | void SSL_SESSION_free(SSL_SESSION *session); 70 | 71 | void SSL_set_connect_state(SSL *ssl); 72 | int SSL_do_handshake(SSL *ssl); 73 | int SSL_get_error(const SSL *ssl, int ret); 74 | const char *SSL_get_version(const SSL *ssl); 75 | 76 | int SSL_read(SSL *ssl, void *buf, int num); 77 | int SSL_write(SSL *ssl, const void *buf, int num); 78 | int SSL_pending(const SSL *ssl); 79 | 80 | int SSL_shutdown(SSL *ssl); 81 | """) 82 | 83 | if libcrypto_version_info < (1, 1): 84 | ffi.cdef(""" 85 | int sk_num(const _STACK *); 86 | X509 *sk_value(const _STACK *, int); 87 | 88 | int SSL_library_init(void); 89 | void OPENSSL_add_all_algorithms_noconf(void); 90 | 91 | SSL_METHOD *SSLv23_method(void); 92 | """) 93 | else: 94 | ffi.cdef(""" 95 | int OPENSSL_sk_num(const _STACK *); 96 | X509 *OPENSSL_sk_value(const _STACK *, int); 97 | 98 | SSL_METHOD *TLS_method(void); 99 | """) 100 | -------------------------------------------------------------------------------- /docs/keys.md: -------------------------------------------------------------------------------- 1 | # oscrypto.keys API Documentation 2 | 3 | The *oscrypto.keys* submodule implements functions to parse certificates, public 4 | keys, private keys and PKCS#12 (`.p12`/`.pfx`) files. The following functions 5 | comprise the public API: 6 | 7 | - [`parse_certificate()`](#parse_certificate-function) 8 | - [`parse_public()`](#parse_public-function) 9 | - [`parse_private()`](#parse_private-function) 10 | - [`parse_pkcs12()`](#parse_pkcs12-function) 11 | 12 | ### `parse_certificate()` function 13 | 14 | > ```python 15 | > def parse_certificate(data): 16 | > """ 17 | > :param data: 18 | > A byte string to load the certificate from 19 | > 20 | > :raises: 21 | > ValueError - when the data does not appear to contain a certificate 22 | > 23 | > :return: 24 | > An asn1crypto.x509.Certificate object 25 | > """ 26 | > ``` 27 | > 28 | > Loads a certificate from a DER or PEM-formatted file. Supports X.509 29 | > certificates only. 30 | 31 | ### `parse_public()` function 32 | 33 | > ```python 34 | > def parse_public(data): 35 | > """ 36 | > :param data: 37 | > A byte string to load the public key from 38 | > 39 | > :raises: 40 | > ValueError - when the data does not appear to contain a public key 41 | > 42 | > :return: 43 | > An asn1crypto.keys.PublicKeyInfo object 44 | > """ 45 | > ``` 46 | > 47 | > Loads a public key from a DER or PEM-formatted file. Supports RSA, DSA and 48 | > EC public keys. For RSA keys, both the old RSAPublicKey and 49 | > SubjectPublicKeyInfo structures are supported. Also allows extracting a 50 | > public key from an X.509 certificate. 51 | 52 | ### `parse_private()` function 53 | 54 | > ```python 55 | > def parse_private(data, password=None): 56 | > """ 57 | > :param data: 58 | > A byte string to load the private key from 59 | > 60 | > :param password: 61 | > The password to unencrypt the private key 62 | > 63 | > :raises: 64 | > ValueError - when the data does not appear to contain a private key, or the password is invalid 65 | > 66 | > :return: 67 | > An asn1crypto.keys.PrivateKeyInfo object 68 | > """ 69 | > ``` 70 | > 71 | > Loads a private key from a DER or PEM-formatted file. Supports RSA, DSA and 72 | > EC private keys. Works with the follow formats: 73 | > 74 | > - RSAPrivateKey (PKCS#1) 75 | > - ECPrivateKey (SECG SEC1 V2) 76 | > - DSAPrivateKey (OpenSSL) 77 | > - PrivateKeyInfo (RSA/DSA/EC - PKCS#8) 78 | > - EncryptedPrivateKeyInfo (RSA/DSA/EC - PKCS#8) 79 | > - Encrypted RSAPrivateKey (PEM only, OpenSSL) 80 | > - Encrypted DSAPrivateKey (PEM only, OpenSSL) 81 | > - Encrypted ECPrivateKey (PEM only, OpenSSL) 82 | 83 | ### `parse_pkcs12()` function 84 | 85 | > ```python 86 | > def parse_pkcs12(data, password=None): 87 | > """ 88 | > :param data: 89 | > A byte string of a DER-encoded PKCS#12 file 90 | > 91 | > :param password: 92 | > A byte string of the password to any encrypted data 93 | > 94 | > :raises: 95 | > ValueError - when any of the parameters are of the wrong type or value 96 | > OSError - when an error is returned by one of the OS decryption functions 97 | > 98 | > :return: 99 | > A three-element tuple of: 100 | > 1. An asn1crypto.keys.PrivateKeyInfo object 101 | > 2. An asn1crypto.x509.Certificate object 102 | > 3. A list of zero or more asn1crypto.x509.Certificate objects that are 103 | > "extra" certificates, possibly intermediates from the cert chain 104 | > """ 105 | > ``` 106 | > 107 | > Parses a PKCS#12 ANS.1 DER-encoded structure and extracts certs and keys 108 | -------------------------------------------------------------------------------- /oscrypto/_pkcs5.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | import hashlib 6 | import hmac 7 | import struct 8 | 9 | from ._asn1 import int_from_bytes, int_to_bytes 10 | from ._errors import pretty_message 11 | from ._types import type_name, byte_cls, int_types 12 | 13 | if sys.version_info < (3,): 14 | chr_cls = chr 15 | 16 | else: 17 | def chr_cls(num): 18 | return bytes([num]) 19 | 20 | 21 | __all__ = [ 22 | 'pbkdf2', 23 | ] 24 | 25 | 26 | def pbkdf2(hash_algorithm, password, salt, iterations, key_length): 27 | """ 28 | Implements PBKDF2 from PKCS#5 v2.2 in pure Python 29 | 30 | :param hash_algorithm: 31 | The string name of the hash algorithm to use: "md5", "sha1", "sha224", 32 | "sha256", "sha384", "sha512" 33 | 34 | :param password: 35 | A byte string of the password to use an input to the KDF 36 | 37 | :param salt: 38 | A cryptographic random byte string 39 | 40 | :param iterations: 41 | The numbers of iterations to use when deriving the key 42 | 43 | :param key_length: 44 | The length of the desired key in bytes 45 | 46 | :return: 47 | The derived key as a byte string 48 | """ 49 | 50 | if not isinstance(password, byte_cls): 51 | raise TypeError(pretty_message( 52 | ''' 53 | password must be a byte string, not %s 54 | ''', 55 | type_name(password) 56 | )) 57 | 58 | if not isinstance(salt, byte_cls): 59 | raise TypeError(pretty_message( 60 | ''' 61 | salt must be a byte string, not %s 62 | ''', 63 | type_name(salt) 64 | )) 65 | 66 | if not isinstance(iterations, int_types): 67 | raise TypeError(pretty_message( 68 | ''' 69 | iterations must be an integer, not %s 70 | ''', 71 | type_name(iterations) 72 | )) 73 | 74 | if iterations < 1: 75 | raise ValueError(pretty_message( 76 | ''' 77 | iterations must be greater than 0 - is %s 78 | ''', 79 | repr(iterations) 80 | )) 81 | 82 | if not isinstance(key_length, int_types): 83 | raise TypeError(pretty_message( 84 | ''' 85 | key_length must be an integer, not %s 86 | ''', 87 | type_name(key_length) 88 | )) 89 | 90 | if key_length < 1: 91 | raise ValueError(pretty_message( 92 | ''' 93 | key_length must be greater than 0 - is %s 94 | ''', 95 | repr(key_length) 96 | )) 97 | 98 | if hash_algorithm not in set(['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512']): 99 | raise ValueError(pretty_message( 100 | ''' 101 | hash_algorithm must be one of "md5", "sha1", "sha224", "sha256", 102 | "sha384", "sha512", not %s 103 | ''', 104 | repr(hash_algorithm) 105 | )) 106 | 107 | algo = getattr(hashlib, hash_algorithm) 108 | 109 | hash_length = { 110 | 'md5': 16, 111 | 'sha1': 20, 112 | 'sha224': 28, 113 | 'sha256': 32, 114 | 'sha384': 48, 115 | 'sha512': 64 116 | }[hash_algorithm] 117 | 118 | original_hmac = hmac.new(password, None, algo) 119 | 120 | block = 1 121 | output = b'' 122 | 123 | while len(output) < key_length: 124 | prf = original_hmac.copy() 125 | prf.update(salt + struct.pack(b'>I', block)) 126 | last = prf.digest() 127 | 128 | u = int_from_bytes(last) 129 | 130 | for _ in range(iterations-1): 131 | prf = original_hmac.copy() 132 | prf.update(last) 133 | last = prf.digest() 134 | u ^= int_from_bytes(last) 135 | 136 | output += int_to_bytes(u, width=hash_length) 137 | block += 1 138 | 139 | return output[0:key_length] 140 | 141 | 142 | pbkdf2.pure_python = True 143 | -------------------------------------------------------------------------------- /docs/kdf.md: -------------------------------------------------------------------------------- 1 | # oscrypto.kdf API Documentation 2 | 3 | The *oscrypto.kdf* submodule implements key derivation functions. The following 4 | functions comprise the public API: 5 | 6 | - [`pbkdf2()`](#pbkdf2-function) 7 | - [`pbkdf2_iteration_calculator()`](#pbkdf2_iteration_calculator-function) 8 | - [`pbkdf1()`](#pbkdf1-function) 9 | - [`pkcs12_kdf()`](#pkcs12_kdf-function) 10 | 11 | ### `pbkdf2()` function 12 | 13 | > ```python 14 | > def pbkdf2(hash_algorithm, password, salt, iterations, key_length): 15 | > """ 16 | > :param hash_algorithm: 17 | > The string name of the hash algorithm to use: "sha1", "sha224", "sha256", "sha384", "sha512" 18 | > 19 | > :param password: 20 | > A byte string of the password to use an input to the KDF 21 | > 22 | > :param salt: 23 | > A cryptographic random byte string 24 | > 25 | > :param iterations: 26 | > The numbers of iterations to use when deriving the key 27 | > 28 | > :param key_length: 29 | > The length of the desired key in bytes 30 | > 31 | > :raises: 32 | > ValueError - when any of the parameters contain an invalid value 33 | > TypeError - when any of the parameters are of the wrong type 34 | > 35 | > :return: 36 | > The derived key as a byte string 37 | > """ 38 | > ``` 39 | > 40 | > PBKDF2 from PKCS#5 41 | 42 | ### `pbkdf2_iteration_calculator()` function 43 | 44 | > ```python 45 | > def pbkdf2_iteration_calculator(hash_algorithm, key_length, target_ms=100, quiet=False): 46 | > """ 47 | > :param hash_algorithm: 48 | > The string name of the hash algorithm to use: "md5", "sha1", "sha224", 49 | > "sha256", "sha384", "sha512" 50 | > 51 | > :param key_length: 52 | > The length of the desired key in bytes 53 | > 54 | > :param target_ms: 55 | > The number of milliseconds the derivation should take 56 | > 57 | > :param quiet: 58 | > If no output should be printed as attempts are made 59 | > 60 | > :return: 61 | > An integer number of iterations of PBKDF2 using the specified hash 62 | > that will take at least target_ms 63 | > """ 64 | > ``` 65 | > 66 | > Runs pbkdf2() twice to determine the approximate number of iterations to 67 | > use to hit a desired time per run. Use this on a production machine to 68 | > dynamically adjust the number of iterations as high as you can. 69 | 70 | ### `pbkdf1()` function 71 | 72 | > ```python 73 | > def pbkdf1(hash_algorithm, password, salt, iterations, key_length): 74 | > """ 75 | > :param hash_algorithm: 76 | > The string name of the hash algorithm to use: "md2", "md5", "sha1" 77 | > 78 | > :param password: 79 | > A byte string of the password to use an input to the KDF 80 | > 81 | > :param salt: 82 | > A cryptographic random byte string 83 | > 84 | > :param iterations: 85 | > The numbers of iterations to use when deriving the key 86 | > 87 | > :param key_length: 88 | > The length of the desired key in bytes 89 | > 90 | > :return: 91 | > The derived key as a byte string 92 | > """ 93 | > ``` 94 | > 95 | > An implementation of PBKDF1 - should only be used for interop with legacy 96 | > systems, not new architectures 97 | 98 | ### `pkcs12_kdf()` function 99 | 100 | > ```python 101 | > def pkcs12_kdf(hash_algorithm, password, salt, iterations, key_length, id_): 102 | > """ 103 | > :param hash_algorithm: 104 | > The string name of the hash algorithm to use: "md5", "sha1", "sha224", "sha256", "sha384", "sha512" 105 | > 106 | > :param password: 107 | > A byte string of the password to use an input to the KDF 108 | > 109 | > :param salt: 110 | > A cryptographic random byte string 111 | > 112 | > :param iterations: 113 | > The numbers of iterations to use when deriving the key 114 | > 115 | > :param key_length: 116 | > The length of the desired key in bytes 117 | > 118 | > :param id_: 119 | > The ID of the usage - 1 for key, 2 for iv, 3 for mac 120 | > 121 | > :raises: 122 | > ValueError - when any of the parameters contain an invalid value 123 | > TypeError - when any of the parameters are of the wrong type 124 | > 125 | > :return: 126 | > The derived key as a byte string 127 | > """ 128 | > ``` 129 | > 130 | > KDF from RFC7292 appendix B.2 - https://tools.ietf.org/html/rfc7292#page-19 131 | -------------------------------------------------------------------------------- /oscrypto/_win/_secur32_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | 6 | from .._ffi import register_ffi 7 | from .._types import str_cls 8 | from ..errors import LibraryNotFoundError 9 | 10 | import cffi 11 | 12 | 13 | __all__ = [ 14 | 'get_error', 15 | 'secur32', 16 | ] 17 | 18 | 19 | ffi = cffi.FFI() 20 | if cffi.__version_info__ >= (0, 9): 21 | ffi.set_unicode(True) 22 | if sys.maxsize > 2 ** 32: 23 | ffi.cdef("typedef uint64_t ULONG_PTR;") 24 | else: 25 | ffi.cdef("typedef unsigned long ULONG_PTR;") 26 | ffi.cdef(""" 27 | typedef HANDLE HCERTSTORE; 28 | typedef unsigned int ALG_ID; 29 | typedef WCHAR SEC_WCHAR; 30 | typedef unsigned long SECURITY_STATUS; 31 | typedef void *LUID; 32 | typedef void *SEC_GET_KEY_FN; 33 | 34 | typedef struct _SecHandle { 35 | ULONG_PTR dwLower; 36 | ULONG_PTR dwUpper; 37 | } SecHandle; 38 | typedef SecHandle CredHandle; 39 | typedef SecHandle CtxtHandle; 40 | 41 | typedef struct _SCHANNEL_CRED { 42 | DWORD dwVersion; 43 | DWORD cCreds; 44 | void *paCred; 45 | HCERTSTORE hRootStore; 46 | DWORD cMappers; 47 | void **aphMappers; 48 | DWORD cSupportedAlgs; 49 | ALG_ID *palgSupportedAlgs; 50 | DWORD grbitEnabledProtocols; 51 | DWORD dwMinimumCipherStrength; 52 | DWORD dwMaximumCipherStrength; 53 | DWORD dwSessionLifespan; 54 | DWORD dwFlags; 55 | DWORD dwCredFormat; 56 | } SCHANNEL_CRED; 57 | 58 | typedef struct _TimeStamp { 59 | DWORD dwLowDateTime; 60 | DWORD dwHighDateTime; 61 | } TimeStamp; 62 | 63 | typedef struct _SecBuffer { 64 | ULONG cbBuffer; 65 | ULONG BufferType; 66 | BYTE *pvBuffer; 67 | } SecBuffer; 68 | 69 | typedef struct _SecBufferDesc { 70 | ULONG ulVersion; 71 | ULONG cBuffers; 72 | SecBuffer *pBuffers; 73 | } SecBufferDesc; 74 | 75 | typedef struct _SecPkgContext_StreamSizes { 76 | ULONG cbHeader; 77 | ULONG cbTrailer; 78 | ULONG cbMaximumMessage; 79 | ULONG cBuffers; 80 | ULONG cbBlockSize; 81 | } SecPkgContext_StreamSizes; 82 | 83 | typedef struct _CERT_CONTEXT { 84 | DWORD dwCertEncodingType; 85 | BYTE *pbCertEncoded; 86 | DWORD cbCertEncoded; 87 | void *pCertInfo; 88 | HCERTSTORE hCertStore; 89 | } CERT_CONTEXT; 90 | 91 | typedef struct _SecPkgContext_ConnectionInfo { 92 | DWORD dwProtocol; 93 | ALG_ID aiCipher; 94 | DWORD dwCipherStrength; 95 | ALG_ID aiHash; 96 | DWORD dwHashStrength; 97 | ALG_ID aiExch; 98 | DWORD dwExchStrength; 99 | } SecPkgContext_ConnectionInfo; 100 | 101 | SECURITY_STATUS AcquireCredentialsHandleW(SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, 102 | LUID *pvLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument, 103 | CredHandle *phCredential, TimeStamp *ptsExpiry); 104 | SECURITY_STATUS FreeCredentialsHandle(CredHandle *phCredential); 105 | SECURITY_STATUS InitializeSecurityContextW(CredHandle *phCredential, CtxtHandle *phContext, 106 | SEC_WCHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 107 | SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext, SecBufferDesc *pOutput, 108 | ULONG *pfContextAttr, TimeStamp *ptsExpiry); 109 | SECURITY_STATUS FreeContextBuffer(void *pvContextBuffer); 110 | SECURITY_STATUS ApplyControlToken(CtxtHandle *phContext, SecBufferDesc *pInput); 111 | SECURITY_STATUS DeleteSecurityContext(CtxtHandle *phContext); 112 | SECURITY_STATUS QueryContextAttributesW(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer); 113 | SECURITY_STATUS EncryptMessage(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo); 114 | SECURITY_STATUS DecryptMessage(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, ULONG *pfQOP); 115 | """) 116 | 117 | 118 | try: 119 | secur32 = ffi.dlopen('secur32.dll') 120 | register_ffi(secur32, ffi) 121 | 122 | except (OSError) as e: 123 | if str_cls(e).find('cannot load library') != -1: 124 | raise LibraryNotFoundError('secur32.dll could not be found') 125 | raise 126 | 127 | 128 | def get_error(): 129 | return ffi.getwinerror() 130 | -------------------------------------------------------------------------------- /oscrypto/_linux_bsd/trust_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | 6 | from .._asn1 import Certificate, TrustedCertificate, unarmor 7 | from .._errors import pretty_message 8 | 9 | 10 | __all__ = [ 11 | 'extract_from_system', 12 | 'system_path', 13 | ] 14 | 15 | 16 | def system_path(): 17 | """ 18 | Tries to find a CA certs bundle in common locations 19 | 20 | :raises: 21 | OSError - when no valid CA certs bundle was found on the filesystem 22 | 23 | :return: 24 | The full filesystem path to a CA certs bundle file 25 | """ 26 | 27 | ca_path = None 28 | 29 | # Common CA cert paths 30 | paths = [ 31 | '/usr/lib/ssl/certs/ca-certificates.crt', 32 | '/etc/ssl/certs/ca-certificates.crt', 33 | '/etc/ssl/certs/ca-bundle.crt', 34 | '/etc/pki/tls/certs/ca-bundle.crt', 35 | '/etc/ssl/ca-bundle.pem', 36 | '/usr/local/share/certs/ca-root-nss.crt', 37 | '/etc/ssl/cert.pem' 38 | ] 39 | 40 | # First try SSL_CERT_FILE 41 | if 'SSL_CERT_FILE' in os.environ: 42 | paths.insert(0, os.environ['SSL_CERT_FILE']) 43 | 44 | for path in paths: 45 | if os.path.exists(path) and os.path.getsize(path) > 0: 46 | ca_path = path 47 | break 48 | 49 | if not ca_path: 50 | raise OSError(pretty_message( 51 | ''' 52 | Unable to find a CA certs bundle in common locations - try 53 | setting the SSL_CERT_FILE environmental variable 54 | ''' 55 | )) 56 | 57 | return ca_path 58 | 59 | 60 | def extract_from_system(cert_callback=None, callback_only_on_failure=False): 61 | """ 62 | Extracts trusted CA certs from the system CA cert bundle 63 | 64 | :param cert_callback: 65 | A callback that is called once for each certificate in the trust store. 66 | It should accept two parameters: an asn1crypto.x509.Certificate object, 67 | and a reason. The reason will be None if the certificate is being 68 | exported, otherwise it will be a unicode string of the reason it won't. 69 | 70 | :param callback_only_on_failure: 71 | A boolean - if the callback should only be called when a certificate is 72 | not exported. 73 | 74 | :return: 75 | A list of 3-element tuples: 76 | - 0: a byte string of a DER-encoded certificate 77 | - 1: a set of unicode strings that are OIDs of purposes to trust the 78 | certificate for 79 | - 2: a set of unicode strings that are OIDs of purposes to reject the 80 | certificate for 81 | """ 82 | 83 | all_purposes = '2.5.29.37.0' 84 | ca_path = system_path() 85 | 86 | output = [] 87 | with open(ca_path, 'rb') as f: 88 | for armor_type, _, cert_bytes in unarmor(f.read(), multiple=True): 89 | # Without more info, a certificate is trusted for all purposes 90 | if armor_type == 'CERTIFICATE': 91 | if cert_callback: 92 | cert_callback(Certificate.load(cert_bytes), None) 93 | output.append((cert_bytes, set(), set())) 94 | 95 | # The OpenSSL TRUSTED CERTIFICATE construct adds OIDs for trusted 96 | # and rejected purposes, so we extract that info. 97 | elif armor_type == 'TRUSTED CERTIFICATE': 98 | cert, aux = TrustedCertificate.load(cert_bytes) 99 | reject_all = False 100 | trust_oids = set() 101 | reject_oids = set() 102 | for purpose in aux['trust']: 103 | if purpose.dotted == all_purposes: 104 | trust_oids = set([purpose.dotted]) 105 | break 106 | trust_oids.add(purpose.dotted) 107 | for purpose in aux['reject']: 108 | if purpose.dotted == all_purposes: 109 | reject_all = True 110 | break 111 | reject_oids.add(purpose.dotted) 112 | if reject_all: 113 | if cert_callback: 114 | cert_callback(cert, 'explicitly distrusted') 115 | continue 116 | if cert_callback and not callback_only_on_failure: 117 | cert_callback(cert, None) 118 | output.append((cert.dump(), trust_oids, reject_oids)) 119 | 120 | return output 121 | -------------------------------------------------------------------------------- /oscrypto/_openssl/_libcrypto.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from .._ffi import buffer_from_bytes, byte_string_from_buffer, null 6 | from .._types import str_cls 7 | 8 | if ffi() == 'cffi': 9 | from ._libcrypto_cffi import ( 10 | libcrypto, 11 | version as libcrypto_version, 12 | version_info as libcrypto_version_info 13 | ) 14 | else: 15 | from ._libcrypto_ctypes import ( 16 | libcrypto, 17 | version as libcrypto_version, 18 | version_info as libcrypto_version_info 19 | ) 20 | 21 | 22 | __all__ = [ 23 | 'handle_openssl_error', 24 | 'libcrypto', 25 | 'libcrypto_legacy_support', 26 | 'libcrypto_version', 27 | 'libcrypto_version_info', 28 | 'LibcryptoConst', 29 | 'peek_openssl_error', 30 | ] 31 | 32 | 33 | _encoding = 'utf-8' 34 | _fallback_encodings = ['utf-8', 'cp1252'] 35 | 36 | 37 | if libcrypto_version_info < (1, 1): 38 | libcrypto.ERR_load_crypto_strings() 39 | libcrypto.OPENSSL_config(null()) 40 | 41 | 42 | # This enables legacy algorithms in OpenSSL 3.0, such as RC2, etc 43 | # which are used by various tests and some old protocols and things 44 | # like PKCS12 45 | libcrypto_legacy_support = True 46 | if libcrypto_version_info >= (3, ): 47 | 48 | libcrypto.OSSL_PROVIDER_load(null(), "legacy".encode("ascii")) 49 | libcrypto.OSSL_PROVIDER_load(null(), "default".encode("ascii")) 50 | 51 | if libcrypto.OSSL_PROVIDER_available(null(), "legacy".encode("ascii")) == 0: 52 | libcrypto_legacy_support = False 53 | 54 | 55 | def _try_decode(value): 56 | 57 | try: 58 | return str_cls(value, _encoding) 59 | 60 | # If the "correct" encoding did not work, try some defaults, and then just 61 | # obliterate characters that we can't seen to decode properly 62 | except (UnicodeDecodeError): 63 | for encoding in _fallback_encodings: 64 | try: 65 | return str_cls(value, encoding, errors='strict') 66 | except (UnicodeDecodeError): 67 | pass 68 | 69 | return str_cls(value, errors='replace') 70 | 71 | 72 | def handle_openssl_error(result, exception_class=None): 73 | """ 74 | Checks if an error occurred, and if so throws an OSError containing the 75 | last OpenSSL error message 76 | 77 | :param result: 78 | An integer result code - 1 or greater indicates success 79 | 80 | :param exception_class: 81 | The exception class to use for the exception if an error occurred 82 | 83 | :raises: 84 | OSError - when an OpenSSL error occurs 85 | """ 86 | 87 | if result > 0: 88 | return 89 | 90 | if exception_class is None: 91 | exception_class = OSError 92 | 93 | error_num = libcrypto.ERR_get_error() 94 | buffer = buffer_from_bytes(120) 95 | libcrypto.ERR_error_string(error_num, buffer) 96 | 97 | # Since we are dealing with a string, it is NULL terminated 98 | error_string = byte_string_from_buffer(buffer) 99 | 100 | raise exception_class(_try_decode(error_string)) 101 | 102 | 103 | def peek_openssl_error(): 104 | """ 105 | Peeks into the error stack and pulls out the lib, func and reason 106 | 107 | :return: 108 | A three-element tuple of integers (lib, func, reason) 109 | """ 110 | 111 | error = libcrypto.ERR_peek_error() 112 | if libcrypto_version_info < (3, 0): 113 | lib = int((error >> 24) & 0xff) 114 | func = int((error >> 12) & 0xfff) 115 | reason = int(error & 0xfff) 116 | else: 117 | lib = int((error >> 23) & 0xff) 118 | # OpenSSL 3.0 removed ERR_GET_FUNC() 119 | func = 0 120 | reason = int(error & 0x7fffff) 121 | 122 | return (lib, func, reason) 123 | 124 | 125 | class LibcryptoConst(): 126 | EVP_CTRL_SET_RC2_KEY_BITS = 3 127 | 128 | SSLEAY_VERSION = 0 129 | 130 | RSA_PKCS1_PADDING = 1 131 | RSA_NO_PADDING = 3 132 | RSA_PKCS1_OAEP_PADDING = 4 133 | 134 | # OpenSSL 0.9.x 135 | EVP_MD_CTX_FLAG_PSS_MDLEN = -1 136 | 137 | # OpenSSL 1.x.x 138 | EVP_PKEY_CTRL_RSA_PADDING = 0x1001 139 | RSA_PKCS1_PSS_PADDING = 6 140 | EVP_PKEY_CTRL_RSA_PSS_SALTLEN = 0x1002 141 | EVP_PKEY_RSA = 6 142 | EVP_PKEY_OP_SIGN = 1 << 3 143 | EVP_PKEY_OP_VERIFY = 1 << 4 144 | 145 | NID_X9_62_prime256v1 = 415 146 | NID_secp384r1 = 715 147 | NID_secp521r1 = 716 148 | 149 | OPENSSL_EC_NAMED_CURVE = 1 150 | 151 | DH_GENERATOR_2 = 2 152 | -------------------------------------------------------------------------------- /oscrypto/_win/_secur32.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from ._decode import _try_decode 6 | from ..errors import TLSError 7 | from .._types import str_cls 8 | 9 | if ffi() == 'cffi': 10 | from ._secur32_cffi import secur32, get_error 11 | else: 12 | from ._secur32_ctypes import secur32, get_error 13 | 14 | 15 | __all__ = [ 16 | 'handle_error', 17 | 'secur32', 18 | 'Secur32Const', 19 | ] 20 | 21 | 22 | def handle_error(result, exception_class=None): 23 | """ 24 | Extracts the last Windows error message into a python unicode string 25 | 26 | :param result: 27 | A function result, 0 or None indicates failure 28 | 29 | :param exception_class: 30 | The exception class to use for the exception if an error occurred 31 | 32 | :return: 33 | A unicode string error message 34 | """ 35 | 36 | if result == 0: 37 | return 38 | 39 | if result == Secur32Const.SEC_E_OUT_OF_SEQUENCE: 40 | raise TLSError('A packet was received out of order') 41 | 42 | if result == Secur32Const.SEC_E_MESSAGE_ALTERED: 43 | raise TLSError('A packet was received altered') 44 | 45 | if result == Secur32Const.SEC_E_CONTEXT_EXPIRED: 46 | raise TLSError('The TLS session expired') 47 | 48 | _, error_string = get_error() 49 | 50 | if not isinstance(error_string, str_cls): 51 | error_string = _try_decode(error_string) 52 | 53 | if exception_class is None: 54 | exception_class = OSError 55 | 56 | raise exception_class(('SECURITY_STATUS error 0x%0.2X: ' % result) + error_string) 57 | 58 | 59 | class Secur32Const(): 60 | SCHANNEL_CRED_VERSION = 4 61 | 62 | SECPKG_CRED_OUTBOUND = 0x00000002 63 | UNISP_NAME = "Microsoft Unified Security Protocol Provider" 64 | 65 | SCH_CRED_MANUAL_CRED_VALIDATION = 0x00000008 66 | SCH_CRED_AUTO_CRED_VALIDATION = 0x00000020 67 | SCH_USE_STRONG_CRYPTO = 0x00400000 68 | SCH_CRED_NO_DEFAULT_CREDS = 0x00000010 69 | 70 | SECBUFFER_VERSION = 0 71 | 72 | SEC_E_OK = 0x00000000 73 | SEC_I_CONTINUE_NEEDED = 0x00090312 74 | SEC_I_CONTEXT_EXPIRED = 0x00090317 75 | SEC_I_RENEGOTIATE = 0x00090321 76 | SEC_E_INCOMPLETE_MESSAGE = 0x80090318 77 | SEC_E_INVALID_TOKEN = 0x80090308 78 | SEC_E_OUT_OF_SEQUENCE = 0x8009031 79 | SEC_E_MESSAGE_ALTERED = 0x8009030F 80 | SEC_E_CONTEXT_EXPIRED = 0x80090317 81 | SEC_E_INVALID_PARAMETER = 0x8009035D 82 | 83 | SEC_E_WRONG_PRINCIPAL = 0x80090322 # Domain name mismatch 84 | SEC_E_UNTRUSTED_ROOT = 0x80090325 85 | SEC_E_CERT_EXPIRED = 0x80090328 86 | SEC_E_ILLEGAL_MESSAGE = 0x80090326 # Handshake error 87 | SEC_E_INTERNAL_ERROR = 0x80090304 # Occurs when DH params are too small 88 | SEC_E_BUFFER_TOO_SMALL = 0x80090321 89 | SEC_I_INCOMPLETE_CREDENTIALS = 0x00090320 90 | 91 | ISC_REQ_REPLAY_DETECT = 4 92 | ISC_REQ_SEQUENCE_DETECT = 8 93 | ISC_REQ_CONFIDENTIALITY = 16 94 | ISC_REQ_ALLOCATE_MEMORY = 256 95 | ISC_REQ_INTEGRITY = 65536 96 | ISC_REQ_STREAM = 0x00008000 97 | ISC_REQ_USE_SUPPLIED_CREDS = 0x00000080 98 | 99 | ISC_RET_REPLAY_DETECT = 4 100 | ISC_RET_SEQUENCE_DETECT = 8 101 | ISC_RET_CONFIDENTIALITY = 16 102 | ISC_RET_ALLOCATED_MEMORY = 256 103 | ISC_RET_INTEGRITY = 65536 104 | ISC_RET_STREAM = 0x00008000 105 | 106 | SECBUFFER_ALERT = 17 107 | SECBUFFER_STREAM_HEADER = 7 108 | SECBUFFER_STREAM_TRAILER = 6 109 | SECBUFFER_EXTRA = 5 110 | SECBUFFER_TOKEN = 2 111 | SECBUFFER_DATA = 1 112 | SECBUFFER_EMPTY = 0 113 | 114 | SECPKG_ATTR_STREAM_SIZES = 0x04 115 | SECPKG_ATTR_CONNECTION_INFO = 0x5A 116 | SECPKG_ATTR_REMOTE_CERT_CONTEXT = 0x53 117 | 118 | SP_PROT_TLS1_2_CLIENT = 0x800 119 | SP_PROT_TLS1_1_CLIENT = 0x200 120 | SP_PROT_TLS1_CLIENT = 0x80 121 | SP_PROT_SSL3_CLIENT = 0x20 122 | SP_PROT_SSL2_CLIENT = 0x8 123 | 124 | CALG_AES_256 = 0x00006610 125 | CALG_AES_128 = 0x0000660E 126 | CALG_3DES = 0x00006603 127 | CALG_RC4 = 0x00006801 128 | CALG_RC2 = 0x00006602 129 | CALG_DES = 0x00006601 130 | 131 | CALG_MD5 = 0x00008003 132 | CALG_SHA1 = 0x00008004 133 | CALG_SHA256 = 0x0000800C 134 | CALG_SHA384 = 0x0000800D 135 | CALG_SHA512 = 0x0000800E 136 | 137 | CALG_DH_SF = 0x0000AA01 138 | CALG_DH_EPHEM = 0x0000AA02 139 | CALG_ECDH = 0x0000AA05 140 | CALG_ECDHE = 0x0000AE06 141 | CALG_RSA_KEYX = 0x0000A400 142 | 143 | CALG_RSA_SIGN = 0x00002400 144 | CALG_ECDSA = 0x00002203 145 | CALG_DSS_SIGN = 0x00002200 146 | -------------------------------------------------------------------------------- /tests/fixtures/keys/test-third-chain.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIID+zCCAuOgAwIBAgIFAJOEAykwDQYJKoZIhvcNAQELBQAwgZgxCzAJBgNVBAYT 3 | AlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMR4wHAYDVQQKExVDb2RleCBOb24g 4 | U3VmZmljaXQgTEMxHTAbBgNVBAsTFFRlc3RpbmcgSW50ZXJtZWRpYXRlMRIwEAYD 5 | VQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhucy5pbzAe 6 | Fw0xNTA1MTEyMTQyNTZaFw0yNTA1MDgyMTQyNTZaMIGgMQswCQYDVQQGEwJVUzEW 7 | MBQGA1UECBMNTWFzc2FjaHVzZXR0czEeMBwGA1UEChMVQ29kZXggTm9uIFN1ZmZp 8 | Y2l0IExDMSUwIwYDVQQLExxUZXN0IFRoaXJkLUxldmVsIENlcnRpZmljYXRlMRIw 9 | EAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhucy5p 10 | bzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMAKLNVdAlEUbBeAKfSz 11 | 3Ymd78tt6l2jjEdz4QMqFkYDSbl5pMB0RP+yRKHVSr+gL99F3wAXHoMb81bFVItL 12 | dyx3vK1qK2FhMvmuw8yNUy3o4aIwE/Neobp4eWLWNWwdqmPyNpvc8g8HdVsnk97u 13 | 9ZUGoiHEblvLZ8uijvbxK5hbCkKHjOhHCDT5egtPKOyFqOWJ1WzINICRfEeIjZM0 14 | cuLUWVJmzb9QJ8CmN4O6R1rYK131eIZ6FWlJTpx1n7MvygTOmDiyVE0NMfJFTzdj 15 | a8kQxiwdyqN9I9OfHqRefh8TCQBuAguuwPUyAu9Ve45eDqzfeWrgoyinZ0KXiqrH 16 | 5DUCAwEAAaNCMEAwHQYDVR0OBBYEFEQ44OAmhb+Yhtwb4R31MjC+q6wNMB8GA1Ud 17 | IwQYMBaAFNIK/S4l0bch11B+u6R9vzTvUl4CMA0GCSqGSIb3DQEBCwUAA4IBAQAb 18 | Wq6ueTRDgY5hDAcVn3j5Eaco88rzhhzgfnH4GSES/QOQlOEFbj0/zzAk7LCgcXq3 19 | 7ud/cbA0tuoFmra9Q4D3YEcL0xHiDlXkvzcy2MJ6MysRiQftvHE9o1f8lxWqEfHK 20 | EtL3espMfVE8zisiA7kS07Jm4t7OSBte21JVwqC+dlqYca2T0coJ47Fw/yVvlaQU 21 | O5h6wvHuUS4L0myNdW+/V2yoUex8C9OK3qs8H61ULcgoVnvn/DJJerad53LBfJR3 22 | jmmamq6Pu7COWU07N7MOGkrG8bwal64ncdzwvTtBj9NdoDataw9LvjyAGxYDSY6X 23 | KiqBZoOHm108hjAfW+XC 24 | -----END CERTIFICATE----- 25 | -----BEGIN CERTIFICATE----- 26 | MIIEBDCCAuygAwIBAgIDGEN5MA0GCSqGSIb3DQEBCwUAMIGdMQswCQYDVQQGEwJV 27 | UzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmV3YnVyeTEeMBwG 28 | A1UEChMVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLEwdUZXN0aW5nMRIw 29 | EAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29kZXhucy5p 30 | bzAeFw0xNTA1MDkwMDQxMzlaFw0yNTA1MDYwMDQxMzlaMIGYMQswCQYDVQQGEwJV 31 | UzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEeMBwGA1UEChMVQ29kZXggTm9uIFN1 32 | ZmZpY2l0IExDMR0wGwYDVQQLExRUZXN0aW5nIEludGVybWVkaWF0ZTESMBAGA1UE 33 | AxMJV2lsbCBCb25kMR4wHAYJKoZIhvcNAQkBFg93aWxsQGNvZGV4bnMuaW8wggEi 34 | MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/PVOdogtqe2gqXZ20dWB5NFxj 35 | JX6z6A57zGqT11OfiNmckIqxMRK8eToR69/DJmVNbQTJy/cFexZ33db+UrtEItxO 36 | klFFbG/6TjmqsOYF87TkJqGX7zXs/Z7D1Xl0/2CNh6vPPPbi/o1FHtKnk4HYOnyU 37 | LRMxxtt06O/u//wdnWXiSAOKOasLT7eP6Fuok28+BeQ29GB3UNL8oC7biyhv89yN 38 | VhDlHAkk+zfrGP4dNqxOY8SkwI0GYki9skEckwf7Nyz+vA8zVJaIymte/eRicCFF 39 | YFxh+QtQhyxF7DwsB5/XIgEWKRXnd/ivyORMlIVc83CHCM4ryvXgG0+I7WuZAgMB 40 | AAGjUDBOMB0GA1UdDgQWBBTSCv0uJdG3IddQfrukfb8071JeAjAfBgNVHSMEGDAW 41 | gBS+QoU9zP/j+SgCj35YVrT9A1zqSzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB 42 | CwUAA4IBAQAKnbphxDozjob2qobtO5QRfZNwIANr/Pyz6SoD8UnJDfZAg9y1jb/I 43 | OutcURjYfV4vyLKI5oyhepyBMkuwvnB/lRpLERAwv5lJgq4sIGDn5Sp56yYcxazC 44 | QXLyG5YJ2Q29kVuq9//IE/dkLVaP444iJZZ7IgrGN4EFQwvFRVa6toeVpwzp8kkn 45 | 5eQaiKQYt/1dVsQ5mv8ksT/gNJRMD4xJ7xvlats+Jc6cyygJk18h+JqMYDoFTTu6 46 | fJmjtnjPFg+XU0q9GnJfrW+FjxYGMv+5tv0pJrujEq7+8gz5A4viSCzHHoc4O/Qs 47 | 0Jt6dQ/xmGYswxjrR/ZgsSjPx3lib7XC 48 | -----END CERTIFICATE----- 49 | -----BEGIN CERTIFICATE----- 50 | MIIExzCCA6+gAwIBAgIJAL3l2aQQMVyCMA0GCSqGSIb3DQEBCwUAMIGdMQswCQYD 51 | VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmV3YnVy 52 | eTEeMBwGA1UEChMVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLEwdUZXN0 53 | aW5nMRIwEAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29k 54 | ZXhucy5pbzAeFw0xNTA1MDYxNDM3MTZaFw0yNTA1MDMxNDM3MTZaMIGdMQswCQYD 55 | VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmV3YnVy 56 | eTEeMBwGA1UEChMVQ29kZXggTm9uIFN1ZmZpY2l0IExDMRAwDgYDVQQLEwdUZXN0 57 | aW5nMRIwEAYDVQQDEwlXaWxsIEJvbmQxHjAcBgkqhkiG9w0BCQEWD3dpbGxAY29k 58 | ZXhucy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL1bKAd04uZK 59 | LAIqvVDeeBeq7FA2fpS5xkWcqHbarzvD1//EG/kCQirJr302nusjJFxdji3aVDRG 60 | Px0+WWwGajy+k2vYm0t7mSP/bmVGCM06ofvDZUMWV1Ld4SyInHruS1Qj4xHlB7/Z 61 | +mAWYpCudmAFIJEgtlHDzezqu6kLEVNB1lbLH+lPNyunwXC9FSYWhekjAyBaflFB 62 | koQV90jXfuTG7Ph0m4DAfZn5n5r/YpvmKEDkPkaW1mAt8qel4b8RklAh8t8vTSfv 63 | QuTeyw3GFcKe7KymKHIaDDxwwnALfGWNa3t7YoVZP9fVrghkR73DBCnHIx22uDHU 64 | TkwBmIdUL18CAwEAAaOCAQYwggECMB0GA1UdDgQWBBS+QoU9zP/j+SgCj35YVrT9 65 | A1zqSzCB0gYDVR0jBIHKMIHHgBS+QoU9zP/j+SgCj35YVrT9A1zqS6GBo6SBoDCB 66 | nTELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEDAOBgNVBAcT 67 | B05ld2J1cnkxHjAcBgNVBAoTFUNvZGV4IE5vbiBTdWZmaWNpdCBMQzEQMA4GA1UE 68 | CxMHVGVzdGluZzESMBAGA1UEAxMJV2lsbCBCb25kMR4wHAYJKoZIhvcNAQkBFg93 69 | aWxsQGNvZGV4bnMuaW+CCQC95dmkEDFcgjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 70 | DQEBCwUAA4IBAQA/5fmvWSMRWqD6JalrNr3Saio5+c/LzxbQ7kZZX1EH5Bo+vhD6 71 | Pfs6lrhzE5OVS86sOItPTtT2KQIE0wTxNfX9wQzjekH4Q2sZRpWaKvK6cH+YzqUK 72 | n3DiICpu8vau4wHDrlfV/C2XhKf5u5qIB+SyOhGDo+XhY0cjgh/FS2//1/qGxrfx 73 | TeOHxoRN5YH4yKNGNapL3XF+utpwVFddmSRUWCBr7Fof9RJlzPCcVP/svTAXDi/y 74 | dhHevPEr21oYqX0KnJJa0JvJx92K8YKFTVj2x5PPCn9qze5C/Re/JFbCIuwq7kcX 75 | 3WQRd+S9zHbtG/4g3DnGibdczSw9529fZZw3 76 | -----END CERTIFICATE----- 77 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # oscrypto Documentation 2 | 3 | *oscrypto* is a library that exposes cryptography primitives from the host 4 | operating system. It is broken down into a few different submodules: 5 | 6 | | Submodule | Functionality | 7 | | ---------------------------------------- | --------------------------------------------------------------------------------------------- | 8 | | [`oscrypto`](oscrypto.md) | Configuration and information about backend | 9 | | [`oscrypto.symmetric`](symmetric.md) | AES, Triple DES, DES, RC2 and RC4 encryption | 10 | | [`oscrypto.asymmetric`](asymmetric.md) | RSA, DSA and EC-key signing and verification, RSA encryption | 11 | | [`oscrypto.kdf`](kdf.md) | PBKDF2, PBKDF1 and PKCS#12 key derivation functions | 12 | | [`oscrypto.keys`](keys.md) | Certificate, public key and private key loading, parsing and normalization | 13 | | [`oscrypto.tls`](tls.md) | TLSv1.x socket wrappers utilizing OS trust store and modern cipher suites | 14 | | [`oscrypto.trust_list`](trust_list.md) | CA certificate list export from the OS trust store | 15 | | [`oscrypto.util`](util.md) | Random byte generation, constant time string comparison | 16 | 17 | Many of the supported ciphers and hashes are not necessarily modern, and should 18 | primarily be used for integration with legacy systems. For modern cryptography, 19 | please see [Modern Cryptography](#modern-cryptography). 20 | 21 | ## Modern Cryptography 22 | 23 | A good place to get an overview of the correct tools to use for modern 24 | cryptography is [(Updated) Cryptographic Right Answers](https://gist.github.com/tqbf/be58d2d39690c3b366ad) 25 | by Thomas Ptacek. 26 | 27 | In short, you probably want to be using [NaCl](http://nacl.cr.yp.to/) by Daniel 28 | J. Bernstein (DJB) - he is a very accomplished cryptographer. Using 29 | [scrypt](http://www.tarsnap.com/scrypt.html) by Colin Percival for password 30 | hashing is a good idea. Here are some libraries for Python that may be useful: 31 | 32 | - https://github.com/pyca/pynacl 33 | - https://pypi.python.org/pypi/scrypt/ 34 | 35 | Thomas‘s recommendations are an alternative, slightly-updated version 36 | of [Cryptographic Right Answers](http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html) 37 | by Colin Percival. Colin‘s contain recommendations that may be a little more 38 | accessible, using things like RSA PSS for signing, RSA OAEP for encryption, 39 | scrypt or PBKDF2 for password hashing, and AES CTR with HMAC for symmetric 40 | encryption. 41 | 42 | ## Learning 43 | 44 | Before using *oscrypto*, you should know a bit about cryptography, and how to 45 | safely use the primitives. If you don‘t, you could very likely utilize them in 46 | an unsafe way, resulting in exposure of confidential information, including 47 | secret keys, encrypted data, and more. 48 | 49 | Here are some topics worth learning about: 50 | 51 | - Block ciphers (AES, Triple DES (2-key and 3-key), DES, RC2) 52 | - Weak block ciphers (Triple DES 2-key, DES, RC2) 53 | - Block cipher padding (PKCS#7 and PKCS#5) 54 | - Block cipher padding oracle attacks 55 | - Block cipher modes of operation (CBC, ECB, CFB, OFB, CTR) 56 | - Block cipher modes to avoid (ECB) 57 | - Nonce reuse in CTR-mode 58 | - Authenticated encryption (AEAD, EtM, MtE, E&M) 59 | - Authenticated block cipher modes (GCM, CCM) 60 | - Stream ciphers (RC4) 61 | - Hashing (MD5, SHA1, SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA512/256)) 62 | - Weak hashes (MD5, SHA1) 63 | - Length extension attacks (MD5, SHA1, SHA-256, SHA-512) 64 | - HMAC 65 | - Cryptographically random numbers 66 | - RSA key sizes (1024, 2048, 3072, 4096) 67 | - DSA key sizes and hash algorithms 68 | - SHA1/1024 69 | - SHA1/2048 (non-standard) 70 | - SHA-2/2048 71 | - SHA-2/3072 72 | - Elliptic curve (EC) keys and named curves 73 | - P-192 / secp192r1 / prime192v1 74 | - P-224 / secp224r1 75 | - P-256 / secp256r1 / prime256v1 76 | - P-384 / secp384r1 77 | - P-521 / secp521r1 78 | - RSA signature padding (PKCS#1 v1.5 and PSS) 79 | - RSA encryption padding (PKCS#1 v1.5 and OAEP) 80 | - Weak RSA signature/encryption padding (PKCS#1 v1.5) 81 | - Timing attacks 82 | 83 | Some sources to learn more about cryptography: 84 | 85 | - [Crypto101](https://www.crypto101.io/) 86 | - [(Updated) Cryptographic Right Answers](https://gist.github.com/tqbf/be58d2d39690c3b366ad) 87 | - [How To Safely Generate a Random Number](http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/) 88 | - http://crypto.stackexchange.com/ 89 | -------------------------------------------------------------------------------- /oscrypto/_mac/_security.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from .._ffi import null 6 | from ..errors import TLSDisconnectError, TLSGracefulDisconnectError 7 | 8 | if ffi() == 'cffi': 9 | from ._security_cffi import Security, version_info as osx_version_info 10 | from ._core_foundation_cffi import CoreFoundation, CFHelpers 11 | else: 12 | from ._security_ctypes import Security, version_info as osx_version_info 13 | from ._core_foundation_ctypes import CoreFoundation, CFHelpers 14 | 15 | 16 | __all__ = [ 17 | 'handle_sec_error', 18 | 'osx_version_info', 19 | 'Security', 20 | 'SecurityConst', 21 | ] 22 | 23 | 24 | def handle_sec_error(error, exception_class=None): 25 | """ 26 | Checks a Security OSStatus error code and throws an exception if there is an 27 | error to report 28 | 29 | :param error: 30 | An OSStatus 31 | 32 | :param exception_class: 33 | The exception class to use for the exception if an error occurred 34 | 35 | :raises: 36 | OSError - when the OSStatus contains an error 37 | """ 38 | 39 | if error == 0: 40 | return 41 | 42 | if error in set([SecurityConst.errSSLClosedNoNotify, SecurityConst.errSSLClosedAbort]): 43 | raise TLSDisconnectError('The remote end closed the connection') 44 | if error == SecurityConst.errSSLClosedGraceful: 45 | raise TLSGracefulDisconnectError('The remote end closed the connection') 46 | 47 | cf_error_string = Security.SecCopyErrorMessageString(error, null()) 48 | output = CFHelpers.cf_string_to_unicode(cf_error_string) 49 | CoreFoundation.CFRelease(cf_error_string) 50 | 51 | if output is None or output == '': 52 | output = 'OSStatus %s' % error 53 | 54 | if exception_class is None: 55 | exception_class = OSError 56 | 57 | raise exception_class(output) 58 | 59 | 60 | def _extract_policy_properties(value): 61 | properties_dict = Security.SecPolicyCopyProperties(value) 62 | return CFHelpers.cf_dictionary_to_dict(properties_dict) 63 | 64 | 65 | CFHelpers.register_native_mapping( 66 | Security.SecPolicyGetTypeID(), 67 | _extract_policy_properties 68 | ) 69 | 70 | 71 | class SecurityConst(): 72 | kSecTrustSettingsDomainUser = 0 73 | kSecTrustSettingsDomainAdmin = 1 74 | kSecTrustSettingsDomainSystem = 2 75 | 76 | kSecTrustResultProceed = 1 77 | kSecTrustResultUnspecified = 4 78 | kSecTrustOptionImplicitAnchors = 0x00000040 79 | 80 | kSecFormatOpenSSL = 1 81 | 82 | kSecItemTypePrivateKey = 1 83 | kSecItemTypePublicKey = 2 84 | 85 | kSSLSessionOptionBreakOnServerAuth = 0 86 | 87 | kSSLProtocol2 = 1 88 | kSSLProtocol3 = 2 89 | kTLSProtocol1 = 4 90 | kTLSProtocol11 = 7 91 | kTLSProtocol12 = 8 92 | 93 | kSSLClientSide = 1 94 | kSSLStreamType = 0 95 | 96 | errSSLProtocol = -9800 97 | errSSLWouldBlock = -9803 98 | errSSLClosedGraceful = -9805 99 | errSSLClosedNoNotify = -9816 100 | errSSLClosedAbort = -9806 101 | 102 | errSSLXCertChainInvalid = -9807 103 | errSSLCrypto = -9809 104 | errSSLInternal = -9810 105 | errSSLCertExpired = -9814 106 | errSSLCertNotYetValid = -9815 107 | errSSLUnknownRootCert = -9812 108 | errSSLNoRootCert = -9813 109 | errSSLHostNameMismatch = -9843 110 | errSSLPeerHandshakeFail = -9824 111 | errSSLPeerProtocolVersion = -9836 112 | errSSLPeerUserCancelled = -9839 113 | errSSLWeakPeerEphemeralDHKey = -9850 114 | errSSLServerAuthCompleted = -9841 115 | errSSLRecordOverflow = -9847 116 | 117 | CSSMERR_APPLETP_HOSTNAME_MISMATCH = -2147408896 118 | CSSMERR_TP_CERT_EXPIRED = -2147409654 119 | CSSMERR_TP_CERT_NOT_VALID_YET = -2147409653 120 | CSSMERR_TP_CERT_REVOKED = -2147409652 121 | CSSMERR_TP_NOT_TRUSTED = -2147409622 122 | CSSMERR_TP_CERT_SUSPENDED = -2147409651 123 | 124 | CSSM_CERT_X_509v3 = 0x00000004 125 | 126 | APPLE_TP_REVOCATION_CRL = b'*\x86H\x86\xf7cd\x01\x06' 127 | APPLE_TP_REVOCATION_OCSP = b'*\x86H\x86\xf7cd\x01\x07' 128 | 129 | CSSM_APPLE_TP_OCSP_OPTS_VERSION = 0 130 | CSSM_TP_ACTION_OCSP_DISABLE_NET = 0x00000004 131 | CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE = 0x00000008 132 | 133 | CSSM_APPLE_TP_CRL_OPTS_VERSION = 0 134 | 135 | errSecVerifyFailed = -67808 136 | errSecNoTrustSettings = -25263 137 | errSecItemNotFound = -25300 138 | errSecInvalidTrustSettings = -25262 139 | 140 | kSecPaddingNone = 0 141 | kSecPaddingPKCS1 = 1 142 | 143 | CSSM_KEYUSE_SIGN = 0x00000004 144 | CSSM_KEYUSE_VERIFY = 0x00000008 145 | 146 | CSSM_ALGID_DH = 2 147 | CSSM_ALGID_RSA = 42 148 | CSSM_ALGID_DSA = 43 149 | CSSM_ALGID_ECDSA = 73 150 | CSSM_KEYATTR_PERMANENT = 0x00000001 151 | CSSM_KEYATTR_EXTRACTABLE = 0x00000020 152 | -------------------------------------------------------------------------------- /dev/_task.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import ast 5 | import _ast 6 | import os 7 | import sys 8 | 9 | from . import package_root, task_keyword_args 10 | from ._import import _import_from 11 | 12 | 13 | if sys.version_info < (3,): 14 | byte_cls = str 15 | else: 16 | byte_cls = bytes 17 | 18 | 19 | def _list_tasks(): 20 | """ 21 | Fetches a list of all valid tasks that may be run, and the args they 22 | accept. Does not actually import the task module to prevent errors if a 23 | user does not have the dependencies installed for every task. 24 | 25 | :return: 26 | A list of 2-element tuples: 27 | 0: a unicode string of the task name 28 | 1: a list of dicts containing the parameter definitions 29 | """ 30 | 31 | out = [] 32 | dev_path = os.path.join(package_root, 'dev') 33 | for fname in sorted(os.listdir(dev_path)): 34 | if fname.startswith('.') or fname.startswith('_'): 35 | continue 36 | if not fname.endswith('.py'): 37 | continue 38 | name = fname[:-3] 39 | args = () 40 | 41 | full_path = os.path.join(package_root, 'dev', fname) 42 | with open(full_path, 'rb') as f: 43 | full_code = f.read() 44 | if sys.version_info >= (3,): 45 | full_code = full_code.decode('utf-8') 46 | 47 | task_node = ast.parse(full_code, filename=full_path) 48 | for node in ast.iter_child_nodes(task_node): 49 | if isinstance(node, _ast.Assign): 50 | if len(node.targets) == 1 \ 51 | and isinstance(node.targets[0], _ast.Name) \ 52 | and node.targets[0].id == 'run_args': 53 | args = ast.literal_eval(node.value) 54 | break 55 | 56 | out.append((name, args)) 57 | return out 58 | 59 | 60 | def show_usage(): 61 | """ 62 | Prints to stderr the valid options for invoking tasks 63 | """ 64 | 65 | valid_tasks = [] 66 | for task in _list_tasks(): 67 | usage = task[0] 68 | for run_arg in task[1]: 69 | usage += ' ' 70 | name = run_arg.get('name', '') 71 | if run_arg.get('required', False): 72 | usage += '{%s}' % name 73 | else: 74 | usage += '[%s]' % name 75 | valid_tasks.append(usage) 76 | 77 | out = 'Usage: run.py' 78 | for karg in task_keyword_args: 79 | out += ' [%s=%s]' % (karg['name'], karg['placeholder']) 80 | out += ' (%s)' % ' | '.join(valid_tasks) 81 | 82 | print(out, file=sys.stderr) 83 | sys.exit(1) 84 | 85 | 86 | def _get_arg(num): 87 | """ 88 | :return: 89 | A unicode string of the requested command line arg 90 | """ 91 | 92 | if len(sys.argv) < num + 1: 93 | return None 94 | arg = sys.argv[num] 95 | if isinstance(arg, byte_cls): 96 | arg = arg.decode('utf-8') 97 | return arg 98 | 99 | 100 | def run_task(): 101 | """ 102 | Parses the command line args, invoking the requested task 103 | """ 104 | 105 | arg_num = 1 106 | task = None 107 | args = [] 108 | kwargs = {} 109 | 110 | # We look for the task name, processing any global task keyword args 111 | # by setting the appropriate env var 112 | while True: 113 | val = _get_arg(arg_num) 114 | if val is None: 115 | break 116 | 117 | next_arg = False 118 | for karg in task_keyword_args: 119 | if val.startswith(karg['name'] + '='): 120 | os.environ[karg['env_var']] = val[len(karg['name']) + 1:] 121 | next_arg = True 122 | break 123 | 124 | if next_arg: 125 | arg_num += 1 126 | continue 127 | 128 | task = val 129 | break 130 | 131 | if task is None: 132 | show_usage() 133 | 134 | task_mod = _import_from('dev.%s' % task, package_root, allow_error=True) 135 | if task_mod is None: 136 | show_usage() 137 | 138 | run_args = task_mod.__dict__.get('run_args', []) 139 | max_args = arg_num + 1 + len(run_args) 140 | 141 | if len(sys.argv) > max_args: 142 | show_usage() 143 | 144 | for i, run_arg in enumerate(run_args): 145 | val = _get_arg(arg_num + 1 + i) 146 | if val is None: 147 | if run_arg.get('required', False): 148 | show_usage() 149 | break 150 | 151 | if run_arg.get('cast') == 'int' and val.isdigit(): 152 | val = int(val) 153 | 154 | kwarg = run_arg.get('kwarg') 155 | if kwarg: 156 | kwargs[kwarg] = val 157 | else: 158 | args.append(val) 159 | 160 | run = task_mod.__dict__.get('run') 161 | 162 | result = run(*args, **kwargs) 163 | sys.exit(int(not result)) 164 | --------------------------------------------------------------------------------