Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it possible to write code that interacts with OpenSSL in Rust #6634

Closed
1 of 3 tasks
alex opened this issue Nov 20, 2021 · 10 comments
Closed
1 of 3 tasks

Make it possible to write code that interacts with OpenSSL in Rust #6634

alex opened this issue Nov 20, 2021 · 10 comments

Comments

@alex
Copy link
Member

alex commented Nov 20, 2021

Vision

The ability to write some primitives in Rust code, using the openssl crate.

Motivation

Performance -- Python code interacting with the OpenSSL APIs introduce nontrivial overhead (e.g. #6457). This also has the potential to be safer, because it means that the responsibility for dealing with OpenSSL's memory semantics (e.g. refcounting ownership) is handled in the openssl crate and isn't our responsibility.

Requirements

Must be entirely backwards compatible with our public API. This needs to also be compatible with standard build configurations, that is to say it needs to be possible to link OpenSSL both statically and dynamically. It also needs to continue to support our entire build matrix of OpenSSL versions.

Approach

This is a sketch of how we might do this:

Currently we produce two .so files, one for _openssl.c, which is CFFI based, and _rust.so which is obviously compiled from Rust. We need to get this down to a single .so to support statically linking OpenSSL and ensuring that both Rust and CFFI using code are using the same version of OpenSSL.

To accomplish this we can: Compile _openssl.c to a .o (not a .so!), link it with the Rust object files to produce a single bindings.so. In it's PyInit_bindings it will create two sub-modules, _rust and _openssl from the Rust and CFFI code. bindings.so will naturally also link OpenSSL in, either statically or dynamically as before.

At this point we now have Python code (via CFFI) and Rust code that are interacting with the same OpenSSL and are properly built.

Once we have that we can begin writing new Rust code using the openssl crate that does whatever we want. Any such code will of course need to pass all existing tests.

Known blockers

@tiran
Copy link
Contributor

tiran commented Nov 22, 2021

Support for accepting buffers as arguments with abi3

Are you referring to `Py_buffer``? They are currently excluded from stable API. I created https://bugs.python.org/issue45459 a month ago to include them.

@alex
Copy link
Member Author

alex commented Nov 22, 2021

Yes, Py_buffer. It will never (IMO) be part of the stable ABI because it's stack allocated and thus making it stable would require sizeof(Py_buffer) to be stable.

I think what we need is a middle ground, e.g. stable ABI functions to get a contiguous byte sequence from a memoryview. That would solve all of our problems.

@tiran
Copy link
Contributor

tiran commented Nov 22, 2021

I made an experimental PR that adds a heap-allocated Py_buffer * API to Python. The strides/shapes parts are bit a tricky, though. Antoine argues that Py_buffer is mature and stable enough to make the entire struct and sizeof(Py_buffer) part of the stable ABI. I'm not convinced it is the best idea, but it's certainly a pragmatic approach.

Now that you mention it, a simpler approach for one dimensional, contiguous memory makes a lot of sense. The multi dimensional buffer API is useful for NumPy or to express complex TIFF formats in PIL. A fair amount of libraries can get by with simple buffer views.

@messense
Copy link

messense commented Dec 3, 2021

I was thinking that you can generate the cffi C source code in build_openssl.py then compile and link it in Rust side using a build.rs build script.

diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py
index c5ab3cb3..4141ea99 100644
--- a/src/_cffi_src/build_openssl.py
+++ b/src/_cffi_src/build_openssl.py
@@ -112,3 +112,10 @@ ffi = build_ffi_for_binding(
     libraries=_get_openssl_libraries(sys.platform),
     extra_compile_args=_extra_compile_args(sys.platform),
 )
+
+if __name__ == "__main__":
+    from cffi import recompiler
+
+    module_name, source, source_extension, kwds = ffi._assigned_source
+    c_file = module_name + source_extension
+    updated = recompiler.make_c_source(ffi, module_name, source, c_file)

@messense
Copy link

messense commented Dec 3, 2021

Made some process here in case you're interested: https://github.com/messense/cryptography/tree/rust-openssl

❯ pytest
......
2681 passed, 1654 skipped in 58.20s

@alex
Copy link
Member Author

alex commented Dec 3, 2021 via email

@alex
Copy link
Member Author

alex commented Dec 12, 2021

@messense do you intend to continue working on this and ultimately send a PR, or is this a PoC for us to adopt?

@messense
Copy link

@alex This is currently a PoC, but I can continue work on it. And I think it's better to open a draft PR so we can have discussions on it. What do you think?

@alex
Copy link
Member Author

alex commented Dec 12, 2021 via email

@alex
Copy link
Member Author

alex commented Mar 16, 2023

this happened.

@alex alex closed this as completed Mar 16, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 15, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests

3 participants