6

I'm writing a cross-platform C++ library which relies upon OpenSSL, which I link statically & bundle with my library for easy consumption. I would like to have a single #include directory for my library, which would obviously contain an "openssl" subdirectory.

Unfortunately, contents of the OpenSSL #include directory are different per architecture, per platform. So, for example, there are (minimally) three different versions of OpenSSL header files for iOS. Add more for TV-OS support and simulator versions. The same problem exists to different degrees on Windows & Android.

Upon closer examination, the only file that's common but different across all platforms & architectures is "opensslconf.h", and it usually only differs by a few lines, or sometimes even a single line.

For example, the tvOS version of "opensslconf.h" contains:

#ifndef OPENSSL_NO_ASYNC
# define OPENSSL_NO_ASYNC
#endif

Whereas the iOS version does not.

A more frequent difference is in the definition of RC4_INT:

// 64-bit architectures?
#define RC4_INT unsigned int

// 32-bit architectures?
#define RC4_INT unsigned char

I would like to have only ONE set of OpenSSL #includes that applies to all architectures & platforms. I don't want to have duplicates of all these files for every arch/platform, especially since there are so many variations.

My first question is if it's possible to have just one OpenSSL #include directory as I'd like? If so, which version of "opensslconf.h" should I choose, and how do I know it will work?

My second question is why this is an issue AT ALL. Why can't these platform differences be encapsulated by OpenSSL? Isn't it already keeping track of many other variables and types that change as you build for different architectures?

Bungles
  • 1,969
  • 2
  • 25
  • 54

3 Answers3

3

As a workaround, you can generate several versions of opensslconf.h (one for each of archs you plan to support), call them opensslconf-win.h, opensslconf-tvos.h, etc. Then write an opensslconf which will contain only includes of the generated files based on platform:

#ifdef WIN32
#include opensslconf-win.h
#endif
// and so for every arch
Alien_AV
  • 345
  • 1
  • 9
  • This is a great idea. In fact, it's something I do in all my cross-platform libraries. And something that IMHO the OpenSSL code should already do. – Bungles Feb 13 '17 at 19:14
0

Why is opensslconf.h different for each architecture?

opensslconf.h holds platform specific configuration and installation information. As you noted, an example of platform configuration data is RC4_INT.

Other examples of platform configuration information include the defines OPENSSL_NO_SSL2 if ./Configure no-ssl2; and OPENSSL_NO_SSL3 if ./Configure no-ssl3. Examples of installation information are the OPENSSLDIR, which holds the location of OpenSSL's configuration file openssl.conf (among other location information)

The last examples, no-ssl2, no-ssl3 and OPENSSLDIR, are specified by the user. They are not fixed for a platform.

(A related question pertains the usefulness of OPENSSLDIR in sandboxes and walled gardens, but I've never seen an answer to it. Also see CONF-less OpenSSL configuration? on the OpenSSL mailing list).


Unfortunately, contents of the OpenSSL #include directory are different per architecture, per platform... Upon closer examination, the only file that's common but different across all platforms & architectures is "opensslconf.h".

That's not exactly correct. bn.h is different, too.


I would like to have only ONE set of OpenSSL #includes that applies to all architectures & platforms... My first question is if it's possible to have just one OpenSSL #include directory as I'd like? If so, which version of "opensslconf.h" should I choose, and how do I know it will work?

Yes, its possible to have only one opensslconf.h and only one bh.h. But you will have to build it by hand, and it will work if you diligently guard the defines of interest and transcribe them without error. You cannot choose one and expect it to work for all architectures and platforms.

I've used the following technique to combine them on OS X and iOS for fat libraries. The steps are detailed at Build Multiarch OpenSSL on OS X, but I'm guessing you know what's going on by looking at it.

$ cat $HOME/ssl/include/openssl/opensslconf.h
#ifndef OPENSSL_MULTIARCH_CONF_HEADER
#define OPENSSL_MULTIARCH_CONF_HEADER

#if __i386 || __i386__
# include "opensslconf-x86.h"
#elif __x86_64 || __x86_64__ || __amd64 || __amd64__
# include "opensslconf-x64.h"
#else
# error Unknown architecture
#endif

#endif /* OPENSSL_MULTIARCH_CONF_HEADER */

and:

$ cat $HOME/ssl/include/openssl/bn.h
#ifndef OPENSSL_MULTIARCH_BN_HEADER
#define OPENSSL_MULTIARCH_BN_HEADER

#if __i386 || __i386__
# include "bn-x86.h"
#elif __x86_64 || __x86_64__ || __amd64 || __amd64__
# include "bn-x64.h"
#else
# error Unknown architecture
#endif

#endif /* OPENSSL_MULTIARCH_BN_HEADER */

My second question is why this is an issue AT ALL. Why can't these platform differences be encapsulated by OpenSSL? Isn't it already keeping track of many other variables and types that change as you build for different architectures?

I've never seen a definitive answer on the subject. Maybe you should ask on one of the OpenSSL mailing lists, like openssl-dev.

My guess is, there's too many platforms and configuration options to stuff them all in one opensslconf.h (and one bn.h). Here's the short list of built-in targets. wc -l tells us there are 144 of them.

The list does not include the various configuration options, like enable-ec_nistp_64_gcc_128 for certain processors (it has nothing to do with NIST or FIPS). Also see Compilation and Installation | Configure Options on the OpenSSL wiki.

$ ./Configure LIST
Configuring OpenSSL version 1.1.1-dev (0x10101000L)
BS2000-OSD
BSD-generic32
BSD-generic64
BSD-ia64
BSD-sparc64
BSD-sparcv8
BSD-x86
BSD-x86-elf
BSD-x86_64
Cygwin
Cygwin-i386
Cygwin-i486
Cygwin-i586
Cygwin-i686
Cygwin-x86
Cygwin-x86_64
DJGPP
MPE/iX-gcc
OS390-Unix
QNX6
QNX6-i386
UEFI
UWIN
VC-CE
VC-WIN32
VC-WIN64A
VC-WIN64A-masm
VC-WIN64I
aix-cc
aix-gcc
aix64-cc
aix64-gcc
android
android-armeabi
android-mips
android-x86
android64
android64-aarch64
android64-mips64
android64-x86_64
bsdi-elf-gcc
cc
darwin-i386-cc
darwin-ppc-cc
darwin64-debug-test-64-clang
darwin64-ppc-cc
darwin64-x86_64-cc
debug
debug-erbridge
debug-linux-ia32-aes
debug-linux-pentium
debug-linux-ppro
debug-test-64-clang
dist
gcc
haiku-x86
haiku-x86_64
hpux-ia64-cc
hpux-ia64-gcc
hpux-parisc-cc
hpux-parisc-gcc
hpux-parisc1_1-cc
hpux-parisc1_1-gcc
hpux64-ia64-cc
hpux64-ia64-gcc
hpux64-parisc2-cc
hpux64-parisc2-gcc
hurd-x86
ios-cross
ios64-cross
iphoneos-cross
irix-mips3-cc
irix-mips3-gcc
irix64-mips4-cc
irix64-mips4-gcc
linux-aarch64
linux-alpha-gcc
linux-aout
linux-arm64ilp32
linux-armv4
linux-c64xplus
linux-elf
linux-generic32
linux-generic64
linux-ia64
linux-mips32
linux-mips64
linux-ppc
linux-ppc64
linux-ppc64le
linux-sparcv8
linux-sparcv9
linux-x32
linux-x86
linux-x86-clang
linux-x86_64
linux-x86_64-clang
linux32-s390x
linux64-mips64
linux64-s390x
linux64-sparcv9
mingw
mingw64
nextstep
nextstep3.3
purify
qnx4
sco5-cc
sco5-gcc
solaris-sparcv7-cc
solaris-sparcv7-gcc
solaris-sparcv8-cc
solaris-sparcv8-gcc
solaris-sparcv9-cc
solaris-sparcv9-gcc
solaris-x86-gcc
solaris64-sparcv9-cc
solaris64-sparcv9-gcc
solaris64-x86_64-cc
solaris64-x86_64-gcc
tru64-alpha-cc
tru64-alpha-gcc
uClinux-dist
uClinux-dist64
unixware-2.0
unixware-2.1
unixware-7
unixware-7-gcc
vms-alpha
vms-alpha-p32
vms-alpha-p64
vms-ia64
vms-ia64-p32
vms-ia64-p64
vos-gcc
vxworks-mips
vxworks-ppc405
vxworks-ppc60x
vxworks-ppc750
vxworks-ppc750-debug
vxworks-ppc860
vxworks-ppcgen
vxworks-simlinux

The same problem exists to different degrees on Windows & Android...

I'm thinking "not really". You can't build fat libraries on those platforms, so the problem does not really exist. You still need to specify a specific path for a platform specific library, so what's the problem with headers?

There's some handwaiving since I recall seeing something about it in Linux (I can't find the reference at the moment), but Android does not have it.


Related, you can see a comprehensive list of platform and user configuration options with:

$ openssl version -a
OpenSSL 1.0.2g  1 Mar 2016
built on: reproducible build, date unspecified
platform: debian-amd64
options:  bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx)
compiler: cc -I. -I.. -I../include  -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REE
NTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -g -O2 -fstack-protector-stron
g -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wl,-Bsymboli
c-functions -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32
_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_
ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIR
LPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
OPENSSLDIR: "/usr/lib/ssl"
Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • I'm not seeing any differences across platforms in the 'bn.h' file, although I'm not compiling for ALL platforms. – Bungles Feb 14 '17 at 23:47
  • @Bungle - The last time I checked (OpenSSL 1.0.1 or 1.0.2), `bn.h` had some struct's that depended on word size. Do you know what version of OpenSSL you are using? – jww Feb 15 '17 at 00:21
  • I'm building 1.1.0d – Bungles Feb 15 '17 at 18:37
0

Alien_AV gave the answer but I'm posting this in order to follow that up with some code, which can only be displayed properly in an answer.

Below is the solution that worked for me. I still think it's something that should be an integrated part of the OpenSSL build process rather than something every single user may need to do.

It should be fairly easy to implement, since there's nothing platform-specific in this file -- one just has to know all the supported platforms.

#ifndef __OPENSSLCONF_H__
#define __OPENSSLCONF_H__

// ************************************************ ANDROID
#if defined(__ANDROID__)
    #if defined (__i386__)
        #include <openssl/opensslconf-android-x86.h>
    #elif defined (__arm__)
        #include <openssl/opensslconf-android-arm.h>
    #elif defined (_MIPS_ARCH)
        // Unsupported
    #endif

// ************************************************ IOS
// Reference:     http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
#elif defined(__APPLE__) && defined(__MACH__)
    #include <TargetConditionals.h>
    #ifdef TARGET_OS_WATCHOS
        // Unsupported
    #elif TARGET_OS_TV
        #if TARGET_OS_SIMULATOR
            #include <openssl/opensslconf-atv-sim64.h>
        #elif
            #include <openssl/opensslconf-atv-arm64.h>
        #endif
    #elif TARGET_OS_IOS
        #if TARGET_OS_SIMULATOR
            #include <openssl/opensslconf-ios-sim32.h>
            #include <openssl/opensslconf-ios-sim64.h>
        #else
            #include <openssl/opensslconf-ios-arm32.h>
            #include <openssl/opensslconf-ios-arm64.h>
        #endif
    #endif

// ************************************************ WINDOWS
// Reference: https://msdn.microsoft.com/en-us/library/b0084kay(v=vs.120).aspx
#elif defined(_WIN32)
    #if defined(_M_X64)
        #include <openssl/opensslconf-win64.h>
    #else
        #include <openssl/opensslconf-win32.h>
    #endif
#endif

#endif // __OPENSSLCONF_H__
Bungles
  • 1,969
  • 2
  • 25
  • 54