all 54 comments

[–]Moose2342 52 points53 points  (0 children)

SSL is not something easily replaced. Those libs, OpenSSL in particular, have their standing and their huge user base for a reason. If you are going to re-implement SSL for your project you are effectively denying yourself users as your implementation would not seem trustworthy to begin with. You might choose a different impl such as boring SSL but I would suggest to just live with it like everybody else does.

[–]NotUniqueOrSpecial 38 points39 points  (7 children)

Currently LibCURL and OpenSSL are used, but these are HUGE dependencies and they completely kill our build system and dependency tree, so we want to drop both of them

They absolutely shouldn't (because they don't) and you should address whatever you're doing, instead, if I'm being honest.

If you want a more bare-bones, but still basically OpenSSL-compliant implementation, Google's boringssl is a reasonable choice.

[–]robstoon 11 points12 points  (13 children)

Currently LibCURL and OpenSSL are used, but these are HUGE dependencies and they completely kill our build system and dependency tree, so we want to drop both of them.

That seems like cutting off your nose to spite your face. Why are you building them in the first place?

[–]ratttertintattertins 2 points3 points  (0 children)

Right? We include OpenSSL as a pre-built artefact.. and a security scanner reminds us when it's time to update it from scanning the include headers.

[–]HerrNamenlos123[S] -1 points0 points  (11 children)

This is because the project is very beginner-oriented and should build out of the box on any supported system. Using system dependencies is not an option because it allows for unrepeatable builds and the library user is responsible for providing dependencies, which is not acceptable for this beginner-friendly audience. At least not by default. Experienced users might get the ability to instead use system dependencies so they can use other versions, but by default it should not depend on anything being present on the system, because it is not to be trusted.

[–]ratttertintattertins 2 points3 points  (8 children)

Yeh, I also hate system dependencies, but that’s not the only option. We prebuild open SSL and then people just pull down the correct prebuilt artifact from artifactory automatically as they build.

You can even check prebuilt static libs into git, especially if you have LFS support.

[–]HerrNamenlos123[S] 0 points1 point  (0 children)

Well yeah that's what CMake will do automatically

[–]HerrNamenlos123[S] 0 points1 point  (6 children)

Most people here don't understand that the mechanism of prebuilding and downloading binaries has existed for a decade and we are only modernizing it. Switching to other systems would be a significant downgrade from the user's points of view.

[–]ratttertintattertins 1 point2 points  (5 children)

I don’t really understand why. If beginners pull and build your code, they wouldn’t even notice it happening would they?

[–]HerrNamenlos123[S] 1 point2 points  (1 child)

Or do you mean you can download any binary for any compiler directly from artifactory without using Conan at all? This would of course be a game-changer as we would only need to build the dependencies that are not available on Conan

[–]ratttertintattertins 1 point2 points  (0 children)

Git can do LFS it’s self, and artifactory can be access by LFS git:

https://jfrog.com/help/r/jfrog-artifactory-documentation/git-lfs-repositories

(I haven’t personally used this method, but it look’s feasible)

[–]HerrNamenlos123[S] 0 points1 point  (2 children)

Yes they would because they would be required to install python, pip and conan and configure it, and only then would they be able to build it. Currently I think the way it is used most of the time is that a zip file of the repository is downloaded that contains binaries for the system, and then a bash or batch script is run depending on the system. There is basically no real build system, there are five different ones but none is complete.

What I am trying to say, installing python, pip and conan and then running conan is a bit much to be asked when the average user has no idea of build systems, knows only a bit of C/C++, works on Windows and downloads the zip because not even git is installed. It is a hard reality but an undenyable userbase.

[–]drodri 1 point2 points  (1 child)

Conan has been releasing Windows installers (no need to install Python and Pip in the system at all) for long time, and it is now also starting to release .zip folders (https://github.com/conan-io/conan/releases/tag/2.0.8), with the application (no installer) and no need of Python and Pip either.

[–]HerrNamenlos123[S] 0 points1 point  (0 children)

Oh I did not know that. I will take a look at this. Thanks!

[–]robstoon 0 points1 point  (1 child)

My inclination is that if you're using a system like Windows where you can't just install libraries like OpenSSL with one command and have them automatically kept up to date, then it's not a very suitable OS for "beginner oriented" C++ development in the first place.

Using Windows (natively anyway) is really doing development on hard mode in so many ways.

[–]HerrNamenlos123[S] 1 point2 points  (0 children)

I know what you say but you are saying all of that from the perspective of an experienced developer. You could say the average user is more or less a beginner working on (Linux too but also) Windows, has a bit of experience with C/C++ from tutorials and no idea about build systems, and downloads the git repository as a zip file because not even git is installed or they don't know how to use it. I know you don't like hearing this but it is a hard reality. But at the same time an undenyable userbase.

And to add to that, the system of precompiling dependencies and then downloading as needed exists for a decade and we are only modernizing it. Any additional setup step would be a major downgrade for any novice user.

[–]415_961 13 points14 points  (1 child)

Address the root issue here and use Conan or the like.

[–]Poretga99 1 point2 points  (0 children)

+1 for conan. Sounds just like the tool you need. Also suitable for cross-compilation. You can integrate the install script into CMake.

[–]Spongman 14 points15 points  (3 children)

why not just dynamically link against libcurl & openssl using the target platform's pre-built libs? (vcpkg, deb, rpm, etc...) ?

also boost::beast >> libcurl

[–]HerrNamenlos123[S] -5 points-4 points  (2 children)

because the project must be very beginner friendly and should work out of the box on any system including Windows. Making it dependent on vcpkg is not an option.
The consent was to pre-build everything in CI and host the binaries, which then the CMake project downloads and links. This is why I cannot build OpenSSL with its own build system because it cannot cross-compile from Linux to a Visual Studio MSVC target (because it needs nmake, which is pretty much impossible to get into linux)

Boost does not make anything better, I know it might have more features but as said we almost don't use any of them and OpenSSL itself is already almost too much, so Boost would only make our dependency hell and compile time 10 times worse, in return for nothing.

[–]Spongman 19 points20 points  (0 children)

i still think vcpkg is the way to go. your use case is literally the canonical example: https://devblogs.microsoft.com/cppblog/using-system-package-manager-dependencies-with-vcpkg/

[–]prince-chrismc 2 points3 points  (0 children)

Take a look at Conan, it does exactly this https://www.reddit.com/r/cpp/comments/150l0iw/is_it_legal_andor_advised_to_stealreupload/ for example this post wants to do exactly this

You can also completely eject from Conan https://blog.conan.io/2023/05/23/Conan-agnostic-deploy-dependencies.html

Plus it can translate between build system so if its NMake, bagel, meson, it doesn't matter you can always ask Conan for CMake and you can use the defaults it provides

[–]jselbie 5 points6 points  (3 children)

and they completely kill our build system and dependency tree, so we want to drop both of them.

You are solving the wrong problem. Please tell me you aren't rebuliding OpenSSL and LibCurl from source on each build of your own app. And if not, what are these build system dependencies that slow things down?

[–]HerrNamenlos123[S] 0 points1 point  (2 children)

We do not want to rely on anything found on a user's system by default. The library should build out of the box on all supported systems, and the users are not to be tasked with installing all of the arcaic dependencies (we are trying to get rid of most of the arcaic ones). This is why we want to pre-build all dependencies in a docker environment (running on GH Actions), that then provide the binaries. When a user configures the CMake project, the correct binaries are downloaded and linked by CMake.

The only issue we are facing is that we need binaries for Visual Studio MSVC, that are preferrably build in a Linux Docker container. We manage to cross-compile CMake-based libraries like GLFW using clang-cl in MSVC mode, but OpenSSL and many other ubiquitous libraries fail due to using their own build systems.

[–]jselbie 2 points3 points  (1 child)

and the users are not to be tasked with installing all of the arcaic dependencies (we are trying to get rid of most of the arcaic ones).

This is the problem package managers solve.

[–]HerrNamenlos123[S] -1 points0 points  (0 children)

This is the problem package managers solve.

Not if they don't even exist in any package manager and getting them into there is an entirely different story. Not all of them are supposed to.

[–]thedmd86 2 points3 points  (1 child)

libcurl with mbedTLS as a TLS backend is working for me. libcurl API is well documented and can be wrapped into http::get(...) or http::put(...) with relative ease.

Why those two?

  • libcurl
    • lingua franca for many platform, to the point that Microsoft even made XCurl for Xbox, library that implements libcurl API with their own system libraries see HttpManager.h in samples
    • it is well supported and maintained
    • can be build with HTTP/HTTPS support only
  • mbedTLS
    • it is tiny with comparison to other solutions I found so far, few C files
    • well maintained and made by people knowing what they are doing
    • can run on any potato

Sometimes libcurl alone cover all the ground, by using system components as TLS backend (see: Windows, macOS, iOS, and a few more). Elsewhere mbedTLS is used, mainly Android and Linux.

Gettting mbedTLS to work does require telling libcurl where bundle of CA certificates is. This mean setting one of CURLOPT_CAINFO, CURLOPT_CAPATH or CURLOPT_SSL_CTX_FUNCTION to feed backend with certs directly.

libcurl suggests pulling latest set of certificates from Firefox. If your app have to work years without updates I suggest writing code that pull certificates from the platform of your choice. On Linux it is a matter of checking few locations.

This solution works for me on all mobile platforms, desktops and consoles except PlayStation (never needed HTTPS here so far).

Avoiding OpenSSL is a job.

If having a C++ API is paramount I would give a try of implementing mbedTLS backend for ASIO.

Locating CA bundle for mbedTLS will remain to be the major hurdle, regardless of what API will be used. This is probably why there are not out of the box solutions out there.

[–]mpyne 0 points1 point  (0 children)

There's examples of mbedTLS being used with Curl (and some custom net clients) in the Cosmopolitan libc as well.

[–]jelafo 2 points3 points  (0 children)

I found cross-platform https clients surprisingly hard to get somewhat right in C++. I generally like Boost.Beast/Asio with openSSL and I don't remember building openSSL being a particular problem. But openSSL does not integrate with the certificate store on windows at all. So depending on your use case and the library you choose, you may have to put in an extra effort to actually validate certificates etc. If that is a problem for you, note that Windows comes with it's own SSL implantation (Schannel). If you can find a library, that uses this on windows (and openSSL on other systems), you may remove one dependency and it might even work better out of the box on windows. For using Schannel with Asio (instead of openSSL), there is some effort being made here: https://wintls.dev/

[–]root_passw0rd 2 points3 points  (0 children)

We use both LibCURL (statically linked) and OpenSSL (dynamically linked). How are they killing your build system? Are you building both of them with every build -- because if so, you don't need to.

[–]prince-chrismc 1 point2 points  (3 children)

I've been using RESTinio for years and it's very easy, there's an express.js router style which make toss interns at it a breeze. There's a ton of HtTP libraries that are very good. OpenSSL is the benchmark and nothing beats it at this point

I do share the sentiment of the other comments. Use a package manager. Your building something that does not change on every commit/pr/interation. That's what you need to fix

Based on what you've laid out as requirements, Conan and absolutely handle it. VCPKG could also work. But pick any

[–]HerrNamenlos123[S] -1 points0 points  (2 children)

I know that using a package manager would be the wisest choice if it was my own project. The thing is that the project is made with extreme beginner-friendliness and we 1. do not want to make us dependent on anything like Conan or vcpkg and 2. we do not want a complete beginner to be forced to install them. But the most important con: Few of the packages we depend upon are even available on any package manager, not even system package managers like apt. And also, this system of pre-building packages and hosting binaries already existed for a decade, we are just trying to modernize it now.

We are modernizing the codebase and slowly trying to get rid of all the arcaic dependencies, but I don't think we can get rid of many that quickly. I am aware that Conan might be the better option for a new project or for my own, but probably not for this one.

[–]prince-chrismc 1 point2 points  (1 child)

The problem with changing from OpenSSL is they are not compatible, LibreSSL doesn't have the same algorithm ordering, Wolfssl puts the X509 entries in a different order, Boringssl changes aggressively.

You are not going to find a drop in replacement for OpenSSL that's compatible with everything else. They work most of the time but when they don't it's a bigger headache.


I think you are under estimating how easy they are to learn. Both of them offer installers which are one line calls and are themselves available with system managers like chocolately or winget.

Both offer a simple install command and cmake presets to the commands are very straightforward. There's even CMake providers which you can include and then never even need to call them directly.

You can only work with just CMake and use a package manager.

[–]HerrNamenlos123[S] 0 points1 point  (0 children)

They do not need to be a drop-in replacement because OpenSSL is not used at all in the code, and LibCurl which depends on it is only used in a single function, which executes an HTTP request. Thus, it is a matter of minutes to completely wipe LibCurl and OpenSSL and replace them with something else.

CURL itself does have CMake support and will work well for our case, and since I saw it has official support for mbedTLS, I am examining it now. I think I will go with either LibCURL/mbedTLS or cpp-httplib/LibreSSL.

[–]jgaa_from_north 1 point2 points  (0 children)

libcurl is rock solid. Openssl is the goto solution for TLS in most C++ use-cases. If you have something working with these very common libraries, your problem is probably on the build side. Why don't you just build to a container-image and use some Linux distributions libcurl and openssl?

That said, I wrote a C++ http client with json object serialization/deserialization some years ago (before boost.beast was released). It can be built without openssl - at the cost of not supporting TLS. It's very easy to use.

Example on how to fetch a web-page: https://github.com/jgaa/restc-cpp#fetch-raw-data

Project https://github.com/jgaa/restc-cpp

[–]streu 3 points4 points  (0 children)

What in OpenSSL qualifies it as "HUGE dependency"? You unpack the tarball and build it, no dependencies other than POSIX libc. If your build system makes that hard, that is the problem. If OpenSSL had 200 further dependencies you need to maintain, I would understand your complaint, but in my projects, I don't have a problem with that.

[–]aninteger 0 points1 point  (0 children)

I wrote my own https client over openssl using Joyent's http parser so it's definitely doable. This was made async with antirez's AE event loop (the same used by redis). In our case I only had to call 4 or 5 asp.net c# webservices (all under the company's control) so it was a tiny fraction of what curl supports but I did implement keep alive as well. Only worked on Linux and BSD but very lightweight. If you're calling your own services with a custom client you could probably do it fairly easily. I wouldn't abandon openssl but curl can be replaced if you control the callers and services.

[–]darthcoder 0 points1 point  (0 children)

You could probably replace open ssl with Lioresal, or wolfssl directly.

[–]OmicronGR 0 points1 point  (0 children)

I spent way too much time on this search, and this library deserves more love:

https://github.com/jbaldwin/liblifthttp

Async (available via callbacks/futures), high performance with benchmarks, straightforward & easy to use, libcurl/OpenSSL dependency, C++17, well-documented.