Austin Kottke's Code Site

Thoughts about Architecture – Java, C/C++, JS, Objective-C, Swift, Groovy, Grails, (RIP Flash)

July 10th, 2018

Deploying C++/Qt/Objective-C based software which runs modern OpenSSL/TLS on old OSX machines — Pre OSX 10.6

C++, OSX, QT, SSL, by austin.

Integration of TLS/SSL on old hardware can be challenging. You open up the machine and open up chrome and low and behold nothing works. You try to download chrome and are blocked. You try to do just about anything on the machine and basically you are locked down due to the fact that the SSL support is too outdated and modern web servers are rejecting any in-secure connections. Well what if you needed to build software that could run on a machine from about 13 years ago, and do modern SSL without an OS upgrade.

Qt 4.5 does not work well with modern TLS 1.2

If you remember OSX circa 2010, you’ll remember Apple moving over to ARC based Objective-C. So on top of the SSL issues you have to work with pre-arc objective-C and build an app. Well, I decided – rather than go down to the Xcode 3 level Ill just use something like QT. That way, all of the code and memory management are handled by Qt – no problem. App was built in Qt. However, due to issues with SSL – I could not get Qt building a binary which used the modern openssl libraries.

No matter what I tried. Even recompiling Qt with OpenSSL 1.02. Comes down to the fact that out-of-the-box Qt has a library called QtNetwork which is tied down to a specific openssl version and it uses whats installed on the machine. Well – I cant do any changes to the underlying operating system so getting an openssl binary installed is out of the question.

After hours of pondering for a solution, repackaging the openssl libs, using install_name_tool I found that nothing worked.

Breaking out Xcode 3 – Replacing QtNetwork Rest client with ASIHTTPRequest :

Decided to instead of using Qt’s networking package, Ill integrate in an old favorite package of mine. ASIHTTPRequest objective-c. Been around since the stone age. And lo and behold, with CFNetwork and openssl packaged I found I could deploy the qt binary and it would do TLS 1.2!

Solution: Create a Hybrid QT based C++ Rest Client which wraps the ASIHTTPRequest Objective-C implementation:

 
#import <Cocoa/Cocoa.h>
 
#include "ASIHttpClient.h"
 
@interface ASIHttpOSXRestHandler()
 
#if QT_VERSION < 0x050000
ASIHttpClient *_cppclass;
#endif
 
@end
 
@implementation ASIHttpOSXRestHandler
 
- (void) buildRequest:(NSString *) url content:(NSString *) content type:(NSString *) type
{
 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
    NSURL *url_endpoint = [NSURL URLWithString:url];
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url_endpoint] ;
 
    [request setRequestMethod:type];
 
    if( [type isEqualToString:@"POST"]){
        [request appendPostData:[content dataUsingEncoding:NSUTF8StringEncoding]];
    }
 
    [request setDelegate:self];
    [request startAsynchronous];
 
    [url release];
    [content release];
    [type release];
 
    [pool release];
 
}
 
@end

You can see that this is very simple. But Im using autorelease pool because objective-c leaks like crazy.

Essentially Im now mixing C++ code with QT and calling objective-c code for the Rest portion.

 
// Add an obj-c category (extension) to return the expected bundle identifier
@implementation NSBundle(returnCorrectIdentifier)
- (NSString *)__bundleIdentifier
{
    if (self == [NSBundle mainBundle]) {
        return @"com.app";
    } else {
        return [self __bundleIdentifier];
    }
}
 
ASIHttpOSXRestHandler *request = [[ASIHttpOSXRestHandler alloc] init];
 
@end
 
void ASIHttpClient::buildRequest(QString destination, QString json_content, QString method_type) {
 
    this->destination_URL = destination;
 
    [request setParent:this];
    [request buildRequest:[[NSString alloc] initWithUTF8String:destination.toUtf8().data()]
      content:[[NSString alloc] initWithUTF8String:json_content.toUtf8().data()]
      type:[[NSString alloc] initWithUTF8String:method_type.toUtf8().data()]];
 
}

And with that. Your Qt 4.5 app can now use modern TLS 1.2 on an outdated machine. Atleast for OSX.

Next hurdle C++11, C++14 ?

There are many aspects of Qt 5 that I would just LOVE to use. Id even love to use C++11, C++14.
Well. Essentially we are in a certain era where you just cant use C++11.

Another fun tidbit:

Mainline libstdc++ has switched to GPL3, a license which the developers of libc++ cannot use. libstdc++ 4.2 (the last GPL2 version) could be independently extended to support C++11, but this would be a fork of the codebase (which is often seen as worse for a project than starting a new independent one). Another problem with libstdc++ is that it is tightly integrated with G++ development, tending to be tied fairly closely to the matching version of G++.

So all those fancy C++11 lambdas and things I just love? Yea – you cant use it.

QObject::connect(
        socket, static_cast<void ( QTcpSocket::* )( QAbstractSocket::SocketError )>( &QAbstractSocket::error ),
        [socket]( QAbstractSocket::SocketError ) {
            qDebug() << "ERROR " << socket->errorString();
            socket->deleteLater();
        }
    );
</div>

Not gonna work!

And modern QT 5 requires C++11. So. New development going forward. I had to swap out entire implementations based on the version of QT and the compiler. LLVM has had major advances in its dependencies.

Here’s another one. Look at the steps to install: Getting libc++, C++11, and C++14 on Leopard and Snow Leopard

Moral of the Story: SSL/TLS is a moving target.

Around 2010 there were MAJOR changes to OSX, Objective-C and LLVM which makes getting a modern SSL version compiled even that much harder.

A small history lesson on some of the reasoning.

The history of Objective-C in GCC is somewhat complicated. Originally, NeXT was forced to release the original Objective-C front end in order to comply with the GPL. This code was not quite compatible with the GNU runtime and so it was modified. NeXT did not adopt these modifications and so each release of GCC by NeXT, and then Apple, contained changes that needed back-porting to the main branch of GCC.

For a long time, GCC was the only compiler that worked with GNUstep. Unfortunately, the GCC team has not invested much effort in Objective-C in the last few years and it currently lags behind Apple’s version by a significant amount.

As of version 4.3, the Free Software Foundation changed the license of GCC to version 3 of the GNU General Public License. This means that future versions will not be shipped by Apple. OS X 10.6 ships with three compilers:

Apple’s fork of GCC 4.2.1
LLVM-GCC
Clang
The latter two use the Low Level Virtual Machine for code generation. This is a BSD-licensed compiler infrastructure used by several other projects. LLVM-GCC is a hybrid, using Apple’s version of GCC for parsing and LLVM for optimisation and native code generation. Clang is a new front end for LLVM.

Currently, LLVM-GCC is based on Apple’s GCC and so does not support the GNU runtime. There is an effort underway to rewrite LLVM-GCC as a plugin for GCC 4.5, at which point it should support as much Objective-C as GCC currently does.

Sometimes, instead of going for a pure cross platform solution, you need to go native.

Austin

Please follow and like us:
0

Back Top

Leave a Reply

Your email address will not be published. Required fields are marked *

*