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
Fix: detect OpenSSL/LibreSSL from official C headers #7245
base: master
Are you sure you want to change the base?
Fix: detect OpenSSL/LibreSSL from official C headers #7245
Conversation
I manually tested OpenSSL versions 1.0.1f, 1.0.2h, 1.1.0e and 1.1.1. Can someone test LibreSSL? |
e52e6ee
to
150c501
Compare
Needs a format, and it's broken on osx :( I suspect that osx might not even package openssl headers by default. |
Yeah, macOS doesn't, but brew installed recent, supported, versions of OpenSSL:
But |
OpenSSL has become a cost centre for the standard library, and I'd like to propose replacing it with mbedtls. mbedtls, previously known as polarssl, is an established tls library which:
I suggest that we can switch to using polarssl exclusively as our TLS implementation, and it would save a lot of headaches going forward. Here's how I suggest switching:
|
I'm all in favor to abstract a TLS module in Crystal's stdlib, allowing to choose or switch to any library (OpenSSL, BearSSL, GnuTLS, ...) by using a selected shard. I have some concerns with mbedtls. Looking at TLS linux distributions, there are differently named libraries: libpolarssl.so, libmbedtls.so, and some different ABI versions, which will probably be confusing. Packaged versions of PolarSSL are far outdated (1.3.9 in Debian Jessie for example). It probably requires to switch to mbedtls which may be available or not. One must enable jessie-backports to install it on Debian Jessie, and it's an old 2.4.2 release, that didn't get any update since sept 2017, despite seeing some CVE in newer releases... I'm not sure it has the kind of extended support that old OpenSSL releases can have (in RHEL, Ubuntu or Debian). OpenSSL is ubiquitous. The API doesn't break much. I spend a couple hours once a year to fix some removed deprecations when a new version is released, and that's it. A real issue has been detecting and supporting LibreSSL, which is supposed to be an OpenSSL 1.0.0 replacement, but isn't exactly, and choosing to use text version numbers, instead of extracting the real version numbers was probably a bad choice. The last issue is that some OS are stuck with a far outdated 0.9.8 for which we should just drop support, like Ruby did 2 years ago: ruby/openssl@4eb4b32. |
Note that the
This means we need to set some things up to use the library we asked to install (sic). Anyway: CI/darwin is fixed by defaulting to 0.9.8. |
@RX14 Let's make that a separate thread, first of all focusing on extracting an implementation-independent TLS API. |
41e5183
to
c894e3c
Compare
Alright, we have 2 choices here:
We can also fail compilation when headers can't be found. It's an error after all. I believe the TLS interface and mbedtls are different topics :) |
I much prefer version 2. We shouldn't support unmaintained openssl versions. |
c894e3c
to
a9ddfba
Compare
Squashed and reordered, with a patch to fix LibreSSL support. Manually tested against:
|
|
Yes, it's ugly, but that's the way to distinguish versions for OpenSSL, let's not fight it (we lose). We can't expect the pkgconfig definition to be present. OPENSSL_VERSION_TEXT is an arbitrary text and parsing it to extract the version will probably break. We could build the version text by parsing OPENSSL_VERSION_NUMBER, but is that really worth the hassle?
I don't know. Can someone run the openssl specs from this pull request on a recent macOS release (high sierra or later)? Maybe the libressl integration got a little better... or maybe it happens to work because libressl keeps openssl 1.0.0 ABI compatibility, and still doesn't provide any header (:hankey:) ?
The formula may not, but the log of |
Openssl doesn't even follow semver ;) |
Oh well...
ruby formula which is updated to 2.3.7 seems to be the one that installs openssl. |
Yes, it should. Crystal's debian packages already depend on pkg-config. A lot of Crystal assumes pkg-config is available in practice. The crystal homebrew formula should ensure that the correct |
Looking at some openssl bindings, I noticed that the rust crate had some very nice ideas:
|
No, I refuse to merge this. This hack belongs in Homebrew, not Crystal. If Crystal even needs to know Homebrew exists, I will strongly argue against merging it. Homebrew should wrap |
I don't care about homebrew and macOS, but lots of developers do use them. Adding a few lines to a script file to help the most common scenario ain't much. Especially since this patch will break all macOS+brew installations, because it only worked by chance until now —defaulting to a 0.9.8/1.0.0 version that happened to be the system installed one. |
I'm not advocating breaking anything, I'm just advocating moving the hack where it belongs. |
Then I let someone that's actually using macOS and brew to handle the fix properly in the crystal brew formula. For example:
Until some as an acceptable solution for both crystal and homebrew, we should wait before merging this PR, or just merge it with the brew fix. I'm fine with whatever, as long as we do fix openssl for homebrew users in the end. |
Detecting the OpenSSL version using pkg-config is prone to bugs when a pkg-config definition for libssl or libcrypto isn't available. Using a C preprocessor to extract the official OPENSSL_VERSION_NUMBER and LIBRESSL_VERSION_NUMBER constants from the openssl/opensslv.h header. Version numbers are less descriptive than their text counterparts, but they should always be correct. Also the Crystal notation allows for readable version numbers like 0xM_NN_FF_PP_S for "major minor fix patch status" as per the official openssl documentation. Introduces a version.sh guess script to search for the OpenSSL or LibreSSL installation, using whatever means: by specifying the OPENSSL_DIR environment variable, using pkg-config if available, and falling back system headers. Also fixes LibreSSL integration, properly enabling ALPN (protocol negotiation) as well as a few differently spelled error messages.
c4cab14
to
fe07222
Compare
This was what I was proposing. Either Looking at homebrew: Can you test CI without any osx hacks and just install homebrew's |
|
||
LIBNAME=$1 | ||
|
||
if [ -z $OPENSSL_DIR ]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is OPENSSL_DIR
coming from?
No it won't.
Just a simple mean to quickly select an installed version. Could be removed, but it's nice to just type pkgconfig is a nice tool when things are installed globally on the system, yet awful when they're not —and we circle with brew's openssl installation not being in a standard location 😭 |
I don't understand why they'd do this :/ If Homebrew wants to be awkward, we need to discuss with Homebrew what the proper fix is. Hacking around it without understanding Homebrew's point of view seems ill-advised.
Then can it become |
This just need to be merged without the macos-specific stuff and then use a wrapper script to fix the build environment in Homebrew. I don't see why homebrew wouldn't accept that. For now the |
Hey, sorry to dig-up such an old thread, |
Echoing @InfRandomness question above. On FreeBSD, openssl is available both from the base system and from ports, and Crystal currently requires patching to use openssl from the base (#7244). It looks that HomeBrew issue was resolved by Homebrew/homebrew-core#48028, which seemed to be the only objection to merging this PR. |
I wouldn't mind polishing up this PR and merging it. But overall, I'd rather like a more flexible, general approach for configuring lib bindings. There should be easy options to specify which libraries and versions to link to at compile time. This should technically work without having OpenSSL sources locally installed (or rather, despite), for example for cross-compiling workflows. |
Honestly, I don't see any alternative, especially a generic one. There is #8336 but it only works for types and "constants", so we still need checking versions to know whether a function is available or not. It would help avoid the shell script, though, which does just that (preprocess the C headers to extract the version constants). |
We can always improve #8336 or do something similar that checks whether a function is define. This can be done by creating a small C program and check if it compiles or not. |
Detecting the OpenSSL version using pkg-config is prone to bugs when a libssl.pc or libcrypto.pc definition aren't available, or pkg-config itself isn't available. Using a C preprocessor to extract the official
OPENSSL_VERSION_NUMBER
andLIBRESSL_VERSION_NUMBER
constants from theopenssl/opensslv.h
header should always be correct.The version numbers are a little cryptic when compared to their text counterpart, but this is what's expected by OpenSSL, so we should follow.
Of course, if
pkg-config
if installed we use it to detect the correct version (linking will use it).fixes #7244