Skip to content

Commit

Permalink
Ressurect the PoC of OpenSSL from Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
alex committed May 1, 2022
1 parent 178f91a commit bd41955
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 44 deletions.
4 changes: 2 additions & 2 deletions .circleci/build-wheel.sh
Expand Up @@ -23,8 +23,8 @@ if [[ "${PYBIN}" =~ $REGEX ]]; then
PY_LIMITED_API="--py-limited-api=cp3${BASH_REMATCH[1]}"
fi

LDFLAGS="-L/opt/pyca/cryptography/openssl/lib" \
CFLAGS="-I/opt/pyca/cryptography/openssl/include -Wl,--exclude-libs,ALL" \
OPENSSL_DIR="/opt/pyca/cryptography/openssl" \
RUSTFLAGS="-Clink-arg=-Wl,--exclude-libs,ALL" \
../../.venv/bin/python setup.py bdist_wheel "$PY_LIMITED_API"

auditwheel repair --plat "${PLATFORM}" -w wheelhouse/ dist/cryptography*.whl
Expand Down
18 changes: 9 additions & 9 deletions .github/workflows/ci.yml
Expand Up @@ -40,7 +40,7 @@ jobs:
- {VERSION: "3.10", TOXENV: "py310", OPENSSL: {TYPE: "libressl", VERSION: "3.2.7"}}
- {VERSION: "3.10", TOXENV: "py310", OPENSSL: {TYPE: "libressl", VERSION: "3.3.6"}}
- {VERSION: "3.10", TOXENV: "py310", OPENSSL: {TYPE: "libressl", VERSION: "3.4.3"}}
- {VERSION: "3.10", TOXENV: "py310", OPENSSL: {TYPE: "libressl", VERSION: "3.5.2"}}
# - {VERSION: "3.10", TOXENV: "py310", OPENSSL: {TYPE: "libressl", VERSION: "3.5.2"}}
- {VERSION: "3.11-dev", TOXENV: "py311-nocoverage"}
- {VERSION: "3.10", TOXENV: "py310-randomorder"}
# Latest commit on the master branch, as of April 29, 2022.
Expand Down Expand Up @@ -115,8 +115,9 @@ jobs:
if: matrix.PYTHON.OPENSSL && steps.ossl-cache.outputs.cache-hit != 'true'
- name: Set CFLAGS/LDFLAGS
run: |
echo "CFLAGS=${CFLAGS} -Werror=implicit-function-declaration -I${OSSL_PATH}/include" >> $GITHUB_ENV
echo "LDFLAGS=${LDFLAGS} -L${OSSL_PATH}/lib -L${OSSL_PATH}/lib64 -Wl,-rpath=${OSSL_PATH}/lib -Wl,-rpath=${OSSL_PATH}/lib64" >> $GITHUB_ENV
echo "OPENSSL_DIR=${OSSL_PATH}" >> $GITHUB_ENV
echo "CFLAGS=${CFLAGS} -Werror=implicit-function-declaration" >> $GITHUB_ENV
echo "RUSTFLAGS=-Clink-arg=-Wl,-rpath=${OSSL_PATH}/lib -Clink-arg=-Wl,-rpath=${OSSL_PATH}/lib64" >> $GITHUB_ENV
if: matrix.PYTHON.OPENSSL
- name: Tests
run: |
Expand Down Expand Up @@ -303,7 +304,7 @@ jobs:
repository: "google/wycheproof"
path: "wycheproof"
ref: "master"
- run: python -m pip install tox coverage
- run: python -m pip install tox coverage cffi
- name: Tests
run: |
tox -vvv -r -- --color=yes --wycheproof-root=wycheproof
Expand Down Expand Up @@ -409,9 +410,9 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Tests
run: |
CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS=1 \
LDFLAGS="${HOME}/openssl-macos-x86-64/lib/libcrypto.a ${HOME}/openssl-macos-x86-64/lib/libssl.a" \
CFLAGS="-I${HOME}/openssl-macos-x86-64/include -Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -Wno-error=unused-command-line-argument -mmacosx-version-min=10.10 -march=core2 $EXTRA_CFLAGS" \
OPENSSL_DIR="${HOME}/openssl-macos-x86-64" \
OPENSSL_STATIC=1 \
CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -Wno-error=unused-command-line-argument -mmacosx-version-min=10.10 -march=core2 $EXTRA_CFLAGS" \
tox -vvv -r -- --color=yes --wycheproof-root=wycheproof
env:
TOXENV: ${{ matrix.PYTHON.TOXENV }}
Expand Down Expand Up @@ -474,8 +475,7 @@ jobs:
- name: Download OpenSSL
run: |
python .github/workflows/download_openssl.py windows openssl-${{ matrix.WINDOWS.WINDOWS }}
echo "INCLUDE=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}/include;$INCLUDE" >> $GITHUB_ENV
echo "LIB=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}/lib;$LIB" >> $GITHUB_ENV
echo "OPENSSL_DIR=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}" >> $GITHUB_ENV
echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Expand Up @@ -30,7 +30,7 @@ warn_unused_ignores = true

[[tool.mypy.overrides]]
module = [
"cryptography.hazmat.bindings._openssl",
"cryptography.hazmat.bindings._rust._openssl",
"pretend"
]
ignore_missing_imports = true
3 changes: 0 additions & 3 deletions setup.py
Expand Up @@ -37,9 +37,6 @@
try:
# See setup.cfg for most of the config metadata.
setup(
cffi_modules=[
"src/_cffi_src/build_openssl.py:ffi",
],
rust_extensions=[
RustExtension(
"_rust",
Expand Down
15 changes: 15 additions & 0 deletions src/_cffi_src/build_openssl.py
Expand Up @@ -4,6 +4,7 @@


import os
import platform
import sys
from distutils import dist
from distutils.ccompiler import get_default_compiler
Expand Down Expand Up @@ -112,3 +113,17 @@ def _extra_compile_args(platform):
libraries=_get_openssl_libraries(sys.platform),
extra_compile_args=_extra_compile_args(sys.platform),
)

if __name__ == "__main__":
out_dir = os.getenv("OUT_DIR")
module_name, source, source_extension, kwds = ffi._assigned_source
c_file = os.path.join(out_dir, module_name + source_extension)
# Necessary because CFFI will ignore this if there's no declarations.
if platform.python_implementation() == "PyPy":
ffi.embedding_api(
"""
extern "Python" void Cryptography_unused(void);
"""
)
ffi.embedding_init_code("")
ffi.emit_c_code(c_file)
7 changes: 7 additions & 0 deletions src/_cffi_src/utils.py
Expand Up @@ -4,6 +4,7 @@


import os
import platform
import sys
from distutils.ccompiler import new_compiler
from distutils.dist import Distribution
Expand Down Expand Up @@ -71,6 +72,12 @@ def build_ffi(
verify_source += '\n#define CRYPTOGRAPHY_PACKAGE_VERSION "{}"'.format(
about["__version__"]
)
if platform.python_implementation() == "PyPy":
verify_source += r"""
int Cryptography_make_openssl_module(void) {
return cffi_start_python();
}
"""
ffi.cdef(cdef_source)
ffi.set_source(
module_name,
Expand Down
8 changes: 8 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/_openssl.pyi
@@ -0,0 +1,8 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

import typing

ffi = typing.Any
lib = typing.Any
5 changes: 5 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl.pyi
@@ -0,0 +1,5 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

def openssl_version() -> int: ...
23 changes: 16 additions & 7 deletions src/cryptography/hazmat/bindings/openssl/binding.py
Expand Up @@ -11,7 +11,7 @@
import cryptography
from cryptography import utils
from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._openssl import ffi, lib
from cryptography.hazmat.bindings._rust import _openssl, openssl
from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES

_OpenSSLErrorWithText = typing.NamedTuple(
Expand Down Expand Up @@ -62,9 +62,9 @@ def _errors_with_text(
) -> typing.List[_OpenSSLErrorWithText]:
errors_with_text = []
for err in errors:
buf = ffi.new("char[]", 256)
lib.ERR_error_string_n(err.code, buf, len(buf))
err_text_reason: bytes = ffi.string(buf)
buf = _openssl.ffi.new("char[]", 256)
_openssl.lib.ERR_error_string_n(err.code, buf, len(buf))
err_text_reason: bytes = _openssl.ffi.string(buf)

errors_with_text.append(
_OpenSSLErrorWithText(
Expand Down Expand Up @@ -120,7 +120,7 @@ class Binding:
"""

lib: typing.ClassVar = None
ffi = ffi
ffi = _openssl.ffi
_lib_loaded = False
_init_lock = threading.Lock()
_legacy_provider: typing.Any = None
Expand Down Expand Up @@ -161,7 +161,9 @@ def _register_osrandom_engine(cls):
def _ensure_ffi_initialized(cls):
with cls._init_lock:
if not cls._lib_loaded:
cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)
cls.lib = build_conditional_library(
_openssl.lib, CONDITIONAL_NAMES
)
cls._lib_loaded = True
cls._register_osrandom_engine()
# As of OpenSSL 3.0.0 we must register a legacy cipher provider
Expand Down Expand Up @@ -210,7 +212,9 @@ def _verify_package_version(version):
# up later this code checks that the currently imported package and the
# shared object that were loaded have the same version and raise an
# ImportError if they do not
so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION)
so_package_version = _openssl.ffi.string(
_openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION
)
if version.encode("ascii") != so_package_version:
raise ImportError(
"The version of cryptography does not match the loaded "
Expand All @@ -222,6 +226,11 @@ def _verify_package_version(version):
)
)

_openssl_assert(
_openssl.lib,
_openssl.lib.OpenSSL_version_num() == openssl.openssl_version(),
)


_verify_package_version(cryptography.__version__)

Expand Down
72 changes: 72 additions & 0 deletions src/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/rust/Cargo.toml
Expand Up @@ -12,6 +12,11 @@ asn1 = { version = "0.9.0", default-features = false, features = ["derive"] }
pem = "1.0"
chrono = { version = "0.4", default-features = false, features = ["alloc", "clock"] }
ouroboros = "0.15"
openssl = "0.10.38"
openssl-sys = "0.9.72"

[build-dependencies]
cc = "1.0.72"

[features]
extension-module = ["pyo3/extension-module"]
Expand All @@ -24,3 +29,7 @@ crate-type = ["cdylib"]
[profile.release]
lto = "thin"
overflow-checks = true

[patch.crates-io]
openssl-sys = { git = "https://github.com/sfackler/rust-openssl.git" }
openssl = { git = "https://github.com/sfackler/rust-openssl.git" }

0 comments on commit bd41955

Please sign in to comment.