summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2021-03-10 22:35:24 +0100
committerGitHub <noreply@github.com>2021-03-10 15:35:24 -0600
commit5dc698861c91b4aa83b284b282c0e91cdcee49a3 (patch)
treed98c73d18f263a76f0b10c7c75d1ea26d4ac858c
parentd290855aab9f12d7cf739c63aad9ca3699d936f7 (diff)
downloadpyopenssl-git-5dc698861c91b4aa83b284b282c0e91cdcee49a3.tar.gz
Add SSL_CTX_set_min_proto_version/SSL_CTX_set_max_proto_version bindings (#985)
* add Context.set_*_proto_version, fix #860 * docs: add new openssl tls methods * accept the fact that nothing can be taken for granted * bump minimum required cryptography version to 3.3 * drop support for Python 3.5 * use binary wheels for cryptography * Revert "use binary wheels for cryptography" This reverts commit 91a04c612ed1d0dd9fd541dfefe21cac7c25b1c1. * docker ci: compile cryptography with rust
-rw-r--r--.github/workflows/ci.yml5
-rw-r--r--CHANGELOG.rst5
-rw-r--r--doc/api/ssl.rst19
-rw-r--r--doc/introduction.rst2
-rwxr-xr-xsetup.py7
-rw-r--r--src/OpenSSL/SSL.py60
-rw-r--r--tests/test_ssl.py28
-rw-r--r--tox.ini4
8 files changed, 115 insertions, 15 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b65b728..2d45c88 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,7 +11,6 @@ jobs:
PYTHON:
# Base builds
- {VERSION: "2.7", TOXENV: "py27"}
- - {VERSION: "3.5", TOXENV: "py35"}
- {VERSION: "3.6", TOXENV: "py36"}
- {VERSION: "3.7", TOXENV: "py37"}
- {VERSION: "3.8", TOXENV: "py38"}
@@ -26,7 +25,6 @@ jobs:
- {VERSION: "pypy3", TOXENV: "pypy3-cryptographyMaster"}
# -cryptographyMinimum
- {VERSION: "2.7", TOXENV: "py27-cryptographyMinimum"}
- - {VERSION: "3.5", TOXENV: "py35-cryptographyMinimum"}
- {VERSION: "3.6", TOXENV: "py36-cryptographyMinimum"}
- {VERSION: "3.7", TOXENV: "py37-cryptographyMinimum"}
- {VERSION: "3.8", TOXENV: "py38-cryptographyMinimum"}
@@ -66,13 +64,14 @@ jobs:
matrix:
TEST:
- {CONTAINER: "stretch", TOXENV: "py27"}
- - {CONTAINER: "stretch", TOXENV: "py35"}
+ - {CONTAINER: "ubuntu-bionic", TOXENV: "py36"}
name: "${{ matrix.TEST.TOXENV }} on ${{ matrix.TEST.CONTAINER }}"
steps:
- uses: actions/checkout@v2
- run: tox -v
env:
TOXENV: ${{ matrix.TEST.TOXENV }}
+ RUSTUP_HOME: /root/.rustup
- name: Upload coverage
run: |
curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 220ee00..85fb1c3 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -10,6 +10,9 @@ The third digit is only for regressions.
Backward-incompatible changes:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- The minimum ``cryptography`` version is now 3.3.
+- Drop support for Python 3.5
+
Deprecations:
^^^^^^^^^^^^^
@@ -18,6 +21,8 @@ Changes:
- Raise an error when an invalid ALPN value is set.
`#993 <https://github.com/pyca/pyopenssl/pull/993>`_
+- Added ``OpenSSL.SSL.Context.set_min_proto_version`` and ``OpenSSL.SSL.Context.set_max_proto_version``
+ to set the minimum and maximum supported TLS version `#985 <https://github.com/pyca/pyopenssl/pull/985>`_.
20.0.1 (2020-12-15)
-------------------
diff --git a/doc/api/ssl.rst b/doc/api/ssl.rst
index ead1452..630ebfc 100644
--- a/doc/api/ssl.rst
+++ b/doc/api/ssl.rst
@@ -10,7 +10,10 @@
This module handles things specific to SSL. There are two objects defined:
Context, Connection.
-.. py:data:: SSLv2_METHOD
+.. py:data:: TLS_METHOD
+ TLS_SERVER_METHOD
+ TLS_CLIENT_METHOD
+ SSLv2_METHOD
SSLv3_METHOD
SSLv23_METHOD
TLSv1_METHOD
@@ -18,11 +21,21 @@ Context, Connection.
TLSv1_2_METHOD
These constants represent the different SSL methods to use when creating a
- context object. If the underlying OpenSSL build is missing support for any
- of these protocols, constructing a :py:class:`Context` using the
+ context object. New code should only use ``TLS_METHOD``, ``TLS_SERVER_METHOD``,
+ or ``TLS_CLIENT_METHOD``. If the underlying OpenSSL build is missing support
+ for any of these protocols, constructing a :py:class:`Context` using the
corresponding :py:const:`*_METHOD` will raise an exception.
+.. py:data:: SSL3_VERSION
+ TLS1_VERSION
+ TLS1_1_VERSION
+ TLS1_2_VERSION
+ TLS1_3_VERSION
+
+ These constants represent the different TLS versions to use when
+ setting the minimum or maximum TLS version.
+
.. py:data:: VERIFY_NONE
VERIFY_PEER
VERIFY_FAIL_IF_NO_PEER_CERT
diff --git a/doc/introduction.rst b/doc/introduction.rst
index a810fbb..2879829 100644
--- a/doc/introduction.rst
+++ b/doc/introduction.rst
@@ -14,7 +14,7 @@ Other OpenSSL wrappers for Python at the time were also limited, though in diffe
Later it was maintained by `Jean-Paul Calderone`_ who among other things managed to make pyOpenSSL a pure Python project which the current maintainers are *very* grateful for.
Over the time the standard library's ``ssl`` module improved, never reaching the completeness of pyOpenSSL's API coverage.
-Despite `PEP 466`_ many useful features remain Python 3-only and pyOpenSSL remains the only alternative for full-featured TLS code across all noteworthy Python versions from 2.7 through 3.5 and PyPy_.
+Despite `PEP 466`_ many useful features remain Python 3-only and pyOpenSSL remains the only alternative for full-featured TLS code across all noteworthy Python versions from 2.7 through 3.6 and PyPy_.
Development
diff --git a/setup.py b/setup.py
index fbd6571..1ca7b11 100755
--- a/setup.py
+++ b/setup.py
@@ -79,7 +79,6 @@ if __name__ == "__main__":
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
@@ -90,12 +89,14 @@ if __name__ == "__main__":
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Networking",
],
- python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*",
+ python_requires=(
+ ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
+ ),
packages=find_packages(where="src"),
package_dir={"": "src"},
install_requires=[
# Fix cryptographyMinimum in tox.ini when changing this!
- "cryptography>=3.2",
+ "cryptography>=3.3",
"six>=1.5.2",
],
extras_require={
diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py
index cd1e9be..660cd9f 100644
--- a/src/OpenSSL/SSL.py
+++ b/src/OpenSSL/SSL.py
@@ -44,6 +44,14 @@ __all__ = [
"TLSv1_METHOD",
"TLSv1_1_METHOD",
"TLSv1_2_METHOD",
+ "TLS_METHOD",
+ "TLS_SERVER_METHOD",
+ "TLS_CLIENT_METHOD",
+ "SSL3_VERSION",
+ "TLS1_VERSION",
+ "TLS1_1_VERSION",
+ "TLS1_2_VERSION",
+ "TLS1_3_VERSION",
"OP_NO_SSLv2",
"OP_NO_SSLv3",
"OP_NO_TLSv1",
@@ -139,6 +147,24 @@ SSLv23_METHOD = 3
TLSv1_METHOD = 4
TLSv1_1_METHOD = 5
TLSv1_2_METHOD = 6
+TLS_METHOD = 7
+TLS_SERVER_METHOD = 8
+TLS_CLIENT_METHOD = 9
+
+try:
+ SSL3_VERSION = _lib.SSL3_VERSION
+ TLS1_VERSION = _lib.TLS1_VERSION
+ TLS1_1_VERSION = _lib.TLS1_1_VERSION
+ TLS1_2_VERSION = _lib.TLS1_2_VERSION
+ TLS1_3_VERSION = _lib.TLS1_3_VERSION
+except AttributeError:
+ # Hardcode constants for cryptography < 3.4, see
+ # https://github.com/pyca/pyopenssl/pull/985#issuecomment-775186682
+ SSL3_VERSION = 768
+ TLS1_VERSION = 769
+ TLS1_1_VERSION = 770
+ TLS1_2_VERSION = 771
+ TLS1_3_VERSION = 772
OP_NO_SSLv2 = _lib.SSL_OP_NO_SSLv2
OP_NO_SSLv3 = _lib.SSL_OP_NO_SSLv3
@@ -603,8 +629,9 @@ class Context(object):
:class:`OpenSSL.SSL.Context` instances define the parameters for setting
up new SSL connections.
- :param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or
- TLSv1_METHOD.
+ :param method: One of TLS_METHOD, TLS_CLIENT_METHOD, or TLS_SERVER_METHOD.
+ SSLv23_METHOD, TLSv1_METHOD, etc. are deprecated and should
+ not be used.
"""
_methods = {
@@ -614,6 +641,9 @@ class Context(object):
TLSv1_METHOD: "TLSv1_method",
TLSv1_1_METHOD: "TLSv1_1_method",
TLSv1_2_METHOD: "TLSv1_2_method",
+ TLS_METHOD: "TLS_method",
+ TLS_SERVER_METHOD: "TLS_server_method",
+ TLS_CLIENT_METHOD: "TLS_client_method",
}
_methods = dict(
(identifier, getattr(_lib, name))
@@ -661,6 +691,32 @@ class Context(object):
self.set_mode(_lib.SSL_MODE_ENABLE_PARTIAL_WRITE)
+ def set_min_proto_version(self, version):
+ """
+ Set the minimum supported protocol version. Setting the minimum
+ version to 0 will enable protocol versions down to the lowest version
+ supported by the library.
+
+ If the underlying OpenSSL build is missing support for the selected
+ version, this method will raise an exception.
+ """
+ _openssl_assert(
+ _lib.SSL_CTX_set_min_proto_version(self._context, version) == 1
+ )
+
+ def set_max_proto_version(self, version):
+ """
+ Set the maximum supported protocol version. Setting the maximum
+ version to 0 will enable protocol versions up to the highest version
+ supported by the library.
+
+ If the underlying OpenSSL build is missing support for the selected
+ version, this method will raise an exception.
+ """
+ _openssl_assert(
+ _lib.SSL_CTX_set_max_proto_version(self._context, version) == 1
+ )
+
def load_verify_locations(self, cafile, capath=None):
"""
Let SSL know where we can find trusted certificates for the certificate
diff --git a/tests/test_ssl.py b/tests/test_ssl.py
index 27f2d43..e79d9fa 100644
--- a/tests/test_ssl.py
+++ b/tests/test_ssl.py
@@ -48,7 +48,14 @@ from OpenSSL.crypto import dump_privatekey, load_privatekey
from OpenSSL.crypto import dump_certificate, load_certificate
from OpenSSL.crypto import get_elliptic_curves
-from OpenSSL.SSL import OPENSSL_VERSION_NUMBER, SSLEAY_VERSION, SSLEAY_CFLAGS
+from OpenSSL.SSL import (
+ OPENSSL_VERSION_NUMBER,
+ SSLEAY_VERSION,
+ SSLEAY_CFLAGS,
+ TLS_METHOD,
+ TLS1_2_VERSION,
+ TLS1_1_VERSION,
+)
from OpenSSL.SSL import SSLEAY_PLATFORM, SSLEAY_DIR, SSLEAY_BUILT_ON
from OpenSSL.SSL import SENT_SHUTDOWN, RECEIVED_SHUTDOWN
from OpenSSL.SSL import (
@@ -1039,6 +1046,25 @@ class TestContext(object):
assert all(isinstance(conn, Connection) for conn, line in called)
assert all(b"CLIENT_RANDOM" in line for conn, line in called)
+ def test_set_proto_version(self):
+ server_context = Context(TLS_METHOD)
+ server_context.use_certificate(
+ load_certificate(FILETYPE_PEM, root_cert_pem)
+ )
+ server_context.use_privatekey(
+ load_privatekey(FILETYPE_PEM, root_key_pem)
+ )
+ server_context.set_min_proto_version(TLS1_2_VERSION)
+
+ client_context = Context(TLS_METHOD)
+ client_context.set_max_proto_version(TLS1_1_VERSION)
+
+ with pytest.raises(Error, match="unsupported protocol"):
+ self._handshake_test(server_context, client_context)
+
+ client_context.set_max_proto_version(0)
+ self._handshake_test(server_context, client_context)
+
def _load_verify_locations_test(self, *args):
"""
Create a client context which will verify the peer certificate and call
diff --git a/tox.ini b/tox.ini
index 90a4c6a..a4662c4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = {pypy,pypy3,py27,py35,py36,py37,py38,py39}{,-cryptographyMaster,-cryptographyMinimum}{,-randomorder},py37-twistedMaster,pypi-readme,check-manifest,flake8,docs,coverage-report
+envlist = {pypy,pypy3,py27,py36,py37,py38,py39}{,-cryptographyMaster,-cryptographyMinimum}{,-randomorder},py37-twistedMaster,pypi-readme,check-manifest,flake8,docs,coverage-report
[testenv]
whitelist_externals =
@@ -10,7 +10,7 @@ extras =
deps =
coverage>=4.2
cryptographyMaster: git+https://github.com/pyca/cryptography.git
- cryptographyMinimum: cryptography==3.2
+ cryptographyMinimum: cryptography==3.3
randomorder: pytest-randomly
setenv =
# Do not allow the executing environment to pollute the test environment