If you think the user interface is bad, try the programmer interface. OMG. Layer upon layer of nonsensical objects to initialize and chain together, each with a bazillion options and no decent documentation about which few are secure. No decent interface for getting the specifics about an error. Not thread-safe unless you create your own array of locking functions (which must meet barely-documented requirements) and pass them in for the library to call at random times. Weird WANT_READ/WANT_WRITE nonsense that makes integration with a bog-standard poll/select loop more difficult. It's like the OpenSSL developers think SSL is the main thing your program should be doing and you're lucky they let any other functionality exist in the same program. The phrase "fractal of bad design" was originally invented for PHP but applies to OpenSSL just as much.
The developer interface is _much_ worse than the user interface. At least the user interface had shell completions to guide your guess work. As you suggested, having to initialise a bunch of things in some undisclosed order is bordering on meddling with the dark arts, good luck tearing it all down again safely. Then let's say you want to streaming-encrypt something on the fly, good luck understanding the correct way to chain BIOs and what exactly the behaviour for seeking, buffering, writing, closing, opening, decrypting, reading, popping BIOs and then working with the remainder of the chain, before pushing a BIO back on is.
I wrote a steaming data encryptor a little while back using openssl, just in C, it works fine now but the majority of my reading was existing implementations on the web and some out-of-date blogs coupled with some, sometimes-correct documentation and just pain trial-and-error paired with my good old friend Valgrind.
Unfortunately, in some industries it's go-FIPS-or-go-home, so we don't even have the choice of using a fork or an alternative at times.