Technical Note TNNaN: OpenSSL on OS X
Long story short: we screwed up when we included OpenSSL (libcrypto) in OS X in the first place.
(We learned our lesson and didn’t repeat the mistake with iOS.)
Now there’s some transitionin’ to do.
Recommendations
New Code Should Use SecTransform. SecTransform is cool: it’s high-level, rather declarative, fast and even leverages GCD. It solves OpenSSL’s issues described below in the Backgrounder section.
Code That Uses OpenSSL Just for Hashing Should Switch to CommonCrypto. CommonCrypto provides a thin OpenSSL compatibility shim for common cryptographic message digests. It’s called COMMON_DIGEST_FOR_OPENSSL and lives in CommonDigest.h.
Apps That Need OpenSSL Should Include Their Own Copy. You should stop using the system’s supplied libcrypto.dylib, build your own and link it into your app.
We know that’s a pain, but this project should help you out.
Add -isystem "$(SRCROOT)/openssl-1.0.1c/include" to OTHER_C_FLAGS to pick up your project’s local OpenSSL headers instead of the system’s headers (which are outdated and throb with deprecation attributes).
Backgrounder
The crux of the problem is OpenSSL doesn’t offer API compatibility between versions.
We’d love to ship updated versions of OpenSSL, but there’s only two feasible routes, both of which are seriously problematic:
Apps link to /usr/lib/libcrypto.dylib symlink. In theory we should be able to always point that to the latest version of libcrypto.dylib and apps get free security + capability updates.
In practice we’d break shipping apps since the APIs are different. So it’s kinda stuck. (Notice we’re still shipping v0.9.8r when v1.0.1c is the latest.)
Apps link to a specific version of libcrypto. For example: /usr/lib/libcrypto.0.9.8.dylib.
Now your app doesn’t get security + capability updates for free. When there’s a security hole, it’s now our job to backport the fixes in the latest OpenSSL into the old-ass version your app is linked against.
Nobody wins in this case.
Ideally the OpenSSL project would do a better job at API compatibility, but it’s really not in their unixy source-code-oriented worldview. Sure we could get big into the project to try to improve it, but we’d rather put the resources into making OS X rock harder.
Both SecTransform and lowly CommonCrypto offer API compatibility, allowing us to add functionality and fix security problems even in shipping apps, which is awesome for users.
Apple has started deprecating OpenSSL on Mac OS X 10.7 SDK and later. I guess they’d prefer you use SecTransform or something. Unfortunately SecTransform isn’t on iOS yet and even it were, some of us have codebases that aren’t Apple-platform exclusive. Feels kind of like a dick move to me.
Anyway, I continued to use OpenSSL in my code — I just stuck a big fat
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
on the top of my OpenSSL-using source files.
Unfortunately that turns off deprecation warnings for the entire file. I tried downloading OpenSSL (/usr/include/openssl/opensslv.h’s OPENSSL_VERSION_TEXT indicates you want v0.9.8r) and using their header files directly but was stumped:
lazytwitter: how do I get Xcode to prefer my local openssl header dir to the SDK’s (that’s littered with with deprecation attributes)?
(setting
ALWAYS_SEARCH_USER_PATHS,HEADER_SEARCH_PATHS&USER_HEADER_SEARCH_PATHSdoesn’t seem to be enough or I’m doing it wrong)
Fortunately Christopher Lloyd answered my query:
@rentzsch -isystem <myincludedir> added using other c flags should do it
I just tried it and it works. Thanks again, Christopher!
Update: I take back my “feels kind of like a dick move” statement. There are good reasons for Apple to deprecate OpenSSL, I just wish they wrote a Technote about it. So I wrote one for them as penance. Apologies, Apple peeps.