Skip to content

Commit

Permalink
Added TLS_method TLS_client_method and TLS_server_method hooks into t…
Browse files Browse the repository at this point in the history
…he bindings with support for LibreSSL and OpenSSL

Updated tests to cover new interfaces
  • Loading branch information
th3b0x committed Oct 6, 2020
1 parent bc4b956 commit 07b8132
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 1 deletion.
16 changes: 16 additions & 0 deletions src/_cffi_src/openssl/ssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
static const long Cryptography_HAS_TLSv1_1;
static const long Cryptography_HAS_TLSv1_2;
static const long Cryptography_HAS_TLSv1_3;
static const long Cryptography_HAS_TLS_METHOD;
static const long Cryptography_HAS_SECURE_RENEGOTIATION;
static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB;
static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP;
Expand Down Expand Up @@ -362,6 +363,11 @@
const SSL_METHOD *DTLSv1_server_method(void);
const SSL_METHOD *DTLSv1_client_method(void);
/* Added in 1.1.0 */
const SSL_METHOD *TLS_method(void);
const SSL_METHOD *TLS_client_method(void);
const SSL_METHOD *TLS_server_method(void);
/* Added in 1.0.2 */
const SSL_METHOD *DTLS_method(void);
const SSL_METHOD *DTLS_server_method(void);
Expand Down Expand Up @@ -501,6 +507,7 @@
"""

CUSTOMIZATIONS = """
#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
static const long Cryptography_HAS_VERIFIED_CHAIN = 0;
Cryptography_STACK_OF_X509 *(*SSL_get0_verified_chain)(const SSL *) = NULL;
Expand Down Expand Up @@ -755,4 +762,13 @@
#else
static const long Cryptography_HAS_TLSv1_3 = 1;
#endif
#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
static const long Cryptography_HAS_TLS_METHOD = 0;
const SSL_METHOD* (*TLS_method)(void) = NULL;
const SSL_METHOD* (*TLS_client_method)(void) = NULL;
const SSL_METHOD* (*TLS_server_method)(void) = NULL;
#else
static const long Cryptography_HAS_TLS_METHOD = 1;
#endif
"""
13 changes: 13 additions & 0 deletions src/cryptography/hazmat/bindings/openssl/_conditional.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,10 @@ def cryptography_has_engine():
"ENGINE_free",
"ENGINE_get_name",
"Cryptography_add_osrandom_engine",
"ENGINE_ctrl_cmd_string",
"ENGINE_load_builtin_engines",
"ENGINE_load_private_key",
"ENGINE_load_public_key",
]


Expand All @@ -287,6 +291,14 @@ def cryptography_has_srtp():
]


def cryptography_has_tls_method():
return [
"TLS_method",
"TLS_client_method",
"TLS_server_method",
]


# This is a mapping of
# {condition: function-returning-names-dependent-on-that-condition} so we can
# loop over them and delete unsupported names at runtime. It will be removed
Expand Down Expand Up @@ -338,4 +350,5 @@ def cryptography_has_srtp():
"Cryptography_HAS_ENGINE": cryptography_has_engine,
"Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain,
"Cryptography_HAS_SRTP": cryptography_has_srtp,
"Cryptography_HAS_TLS_METHOD": cryptography_has_tls_method,
}
16 changes: 15 additions & 1 deletion tests/hazmat/backends/test_openssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ def test_nonexistent_cipher(self, mode):
type(mode),
lambda backend, cipher, mode: backend._ffi.NULL,
)
cipher = Cipher(DummyCipherAlgorithm(), mode, backend=b,)
cipher = Cipher(
DummyCipherAlgorithm(),
mode,
backend=b,
)
with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER):
cipher.encryptor()

Expand Down Expand Up @@ -119,6 +123,16 @@ def test_ssl_ciphers_registered(self):
assert ctx != backend._ffi.NULL
backend._lib.SSL_CTX_free(ctx)

@pytest.mark.skipif(
backend._lib.Cryptography_HAS_TLS_METHOD == 0,
reason="Requires Library with TLS_method",
)
def test_tls_ciphers_registered(self):
meth = backend._lib.TLS_method()
ctx = backend._lib.SSL_CTX_new(meth)
assert ctx != backend._ffi.NULL
backend._lib.SSL_CTX_free(ctx)

def test_evp_ciphers_registered(self):
cipher = backend._lib.EVP_get_cipherbyname(b"aes-256-cbc")
assert cipher != backend._ffi.NULL
Expand Down
67 changes: 67 additions & 0 deletions tests/hazmat/bindings/test_openssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

from __future__ import absolute_import, division, print_function

import pretend

import pytest

from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings.openssl.binding import (
Binding,
_consume_errors,
_openssl_assert,
_verify_openssl_version,
_verify_package_version,
)

Expand Down Expand Up @@ -82,6 +85,61 @@ def test_ssl_mode(self):
assert resp == expected_options
assert b.lib.SSL_get_mode(ssl) == expected_options

@pytest.mark.skipif(
Binding.lib.Cryptography_HAS_TLS_METHOD == 0,
reason="TLS_method requires OpenSSL >= 1.1.0",
)
def test_tls_ctx_options(self):
# Test that we're properly handling 32-bit unsigned on all platforms.
b = Binding()
assert b.lib.SSL_OP_ALL > 0
ctx = b.lib.SSL_CTX_new(b.lib.TLS_method())
assert ctx != b.ffi.NULL
ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free)
current_options = b.lib.SSL_CTX_get_options(ctx)
resp = b.lib.SSL_CTX_set_options(ctx, b.lib.SSL_OP_ALL)
expected_options = current_options | b.lib.SSL_OP_ALL
assert resp == expected_options
assert b.lib.SSL_CTX_get_options(ctx) == expected_options

@pytest.mark.skipif(
Binding.lib.Cryptography_HAS_TLS_METHOD == 0,
reason="TLS_method requires OpenSSL >= 1.1.0",
)
def test_tls_options(self):
# Test that we're properly handling 32-bit unsigned on all platforms.
b = Binding()
assert b.lib.SSL_OP_ALL > 0
ctx = b.lib.SSL_CTX_new(b.lib.TLS_method())
assert ctx != b.ffi.NULL
ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free)
ssl = b.lib.SSL_new(ctx)
ssl = b.ffi.gc(ssl, b.lib.SSL_free)
current_options = b.lib.SSL_get_options(ssl)
resp = b.lib.SSL_set_options(ssl, b.lib.SSL_OP_ALL)
expected_options = current_options | b.lib.SSL_OP_ALL
assert resp == expected_options
assert b.lib.SSL_get_options(ssl) == expected_options

@pytest.mark.skipif(
Binding.lib.Cryptography_HAS_TLS_METHOD == 0,
reason="TLS_method requires OpenSSL >= 1.1.0",
)
def test_tls_mode(self):
# Test that we're properly handling 32-bit unsigned on all platforms.
b = Binding()
assert b.lib.SSL_OP_ALL > 0
ctx = b.lib.SSL_CTX_new(b.lib.TLS_method())
assert ctx != b.ffi.NULL
ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free)
ssl = b.lib.SSL_new(ctx)
ssl = b.ffi.gc(ssl, b.lib.SSL_free)
current_options = b.lib.SSL_get_mode(ssl)
resp = b.lib.SSL_set_mode(ssl, b.lib.SSL_OP_ALL)
expected_options = current_options | b.lib.SSL_OP_ALL
assert resp == expected_options
assert b.lib.SSL_get_mode(ssl) == expected_options

def test_conditional_removal(self):
b = Binding()

Expand Down Expand Up @@ -125,3 +183,12 @@ def test_check_startup_errors_are_allowed(self):
def test_version_mismatch(self):
with pytest.raises(ImportError):
_verify_package_version("nottherightversion")

def test_verify_openssl_version(self, monkeypatch):
monkeypatch.delenv("CRYPTOGRAPHY_ALLOW_OPENSSL_102", raising=False)
lib = pretend.stub(
CRYPTOGRAPHY_OPENSSL_LESS_THAN_110=True,
CRYPTOGRAPHY_IS_LIBRESSL=False,
)
with pytest.raises(RuntimeError):
_verify_openssl_version(lib)

0 comments on commit 07b8132

Please sign in to comment.