Difference between revisions of "Fipsld and C++"
m (Added note on -stdlib-libc++ for Mac OS X.) |
m (Added ellipses...) |
||
(37 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | This wiki page will cover building a C++ | + | This wiki page will cover building a C++ executable program from the command line that statically links to <tt>libssl.a</tt> and <tt>libcrypto.a</tt>. When performing a static link against the OpenSSL library, you have to embed the expected FIPS signature in your executable after final linking. Embedding the FIPS signature in your executable is most often accomplished with <tt>fisld</tt>. |
<tt>fisld</tt> will take the place of the linker (or compiler if invoking via a compiler driver). If you use <tt>fisld</tt> to compile a source file, <tt>fisld</tt> will do nothing and simply invoke the compiler you specify through <tt>FIPSLD_CC</tt>. When it comes time to link, <tt>fisld</tt> will compile <tt>fips_premain.c</tt>, add <tt>fipscanister.o</tt>, and then perform the final link of your program. Once your program is linked, <tt>fisld</tt> will then invoke <tt>incore</tt> to embed the FIPS signature in your program. | <tt>fisld</tt> will take the place of the linker (or compiler if invoking via a compiler driver). If you use <tt>fisld</tt> to compile a source file, <tt>fisld</tt> will do nothing and simply invoke the compiler you specify through <tt>FIPSLD_CC</tt>. When it comes time to link, <tt>fisld</tt> will compile <tt>fips_premain.c</tt>, add <tt>fipscanister.o</tt>, and then perform the final link of your program. Once your program is linked, <tt>fisld</tt> will then invoke <tt>incore</tt> to embed the FIPS signature in your program. | ||
− | The procedure requires three minor modifications to <tt>fipsld</tt>. The modifications will produce <tt>fipsld++</tt> that follows the exiting procedures and re- | + | The procedure requires three minor modifications to <tt>fipsld</tt>. The modifications will produce <tt>fipsld++</tt> that follows the exiting procedures and re-uses the existing components. After <tt>fipsld++</tt> is modified, its copied into <tt>fips-2.0</tt> with the other FIPS binary components. According to Dr. Henson on the [https://groups.google.com/d/msg/mailing.openssl.users/ms0U4svnokc/dIgMgkxGy88J OpenSSL user list], <tt>fipsld</tt> is ''not'' sequestered and can be changed within reason as long as it performs the same basic steps and does not negatively affect the FIPS Object Module or resulting binary. |
− | The example below demonstrates the procedures on Debian 7.3 (x64) using OpenSSL FIPS Capable 1.0.1f and the FIPS Object Module 2.0.5. The example demonstrates Clang and Clang++ with <tt>-stdlib=libstdc++</tt>. However, the procedures work equally well with GCC and G++ (you omit the <tt>-stdlib=libstdc++</tt> for GNU compilers). The modified <tt>fisld</tt> script also works on Mac OS X 10.8. | + | The example below demonstrates the procedures on Debian 7.3 (x64) using OpenSSL FIPS Capable 1.0.1f and the FIPS Object Module 2.0.5. The example demonstrates Clang and Clang++ with <tt>-stdlib=libstdc++</tt>. However, the procedures work equally well with GCC and G++ (you omit the <tt>-stdlib=libstdc++</tt> for GNU compilers). The modified <tt>fisld</tt> script also works on Mac OS X 10.8 (be sure to use <tt>-stdlib=libc++</tt> rather than <tt>libstdc++</tt>). |
== Background == | == Background == | ||
Line 32: | Line 32: | ||
== FIPS Object Module == | == FIPS Object Module == | ||
− | The FIPS Object Module is built in accordance with the steps detailed in the [https://www.openssl.org/docs/fips/SecurityPolicy-2.0.pdf OpenSSL FIPS 2.0 Security Policy]. The OpenSSL Foundation also publishes a user guide at [https://www.openssl.org/docs/fips/UserGuide-2.0.pdf User Guide for the OpenSSL FIPS Object Module v2.0]. A grossly simplified | + | The FIPS Object Module is built in accordance with the steps detailed in the [https://www.openssl.org/docs/fips/SecurityPolicy-2.0.pdf OpenSSL FIPS 2.0 Security Policy]. The OpenSSL Foundation also publishes a user guide at [https://www.openssl.org/docs/fips/UserGuide-2.0.pdf User Guide for the OpenSSL FIPS Object Module v2.0]. A grossly simplified version is presented below, but the steps are essentially the same as detailed in the guides and on other pages in the wiki. |
<pre># Download and verify signature on openssl-fips-2.0.5.tar.gz | <pre># Download and verify signature on openssl-fips-2.0.5.tar.gz | ||
Line 55: | Line 55: | ||
./fips/fipsld | ./fips/fipsld | ||
$ sudo cp fips/fipsld /usr/local/ssl/fips-2.0/bin/</pre> | $ sudo cp fips/fipsld /usr/local/ssl/fips-2.0/bin/</pre> | ||
+ | |||
+ | After the above executes, the FIPS Object Module components will be installed in <tt>/usr/local/ssl/fips-2.0</tt> directory. The components include <tt>fipscanister.o</tt> (and integrity signature), <tt>fips_premain.c</tt> (and integrity signature), <tt>incore</tt> and <tt>fipsld</tt>. | ||
== FIPS Capable Library == | == FIPS Capable Library == | ||
Line 65: | Line 67: | ||
$ pgp openssl-1.0.1f.tar.gz.asc | $ pgp openssl-1.0.1f.tar.gz.asc | ||
pgp: Signature made Mon 06 Jan 2014 09:36:10 AM EST using RSA key ID F295C759 | pgp: Signature made Mon 06 Jan 2014 09:36:10 AM EST using RSA key ID F295C759 | ||
+ | ... | ||
− | # Build and install the | + | # Build and install the FIPS Capable Library |
$ tar -xzf openssl-1.0.1f.tar.gz | $ tar -xzf openssl-1.0.1f.tar.gz | ||
$ cd openssl-1.0.1f/ | $ cd openssl-1.0.1f/ | ||
− | $ ./config fips no-ssl2 <other options> | + | $ ./config fips shared no-ssl2 <other options> |
$ make all | $ make all | ||
$ sudo make install</pre> | $ sudo make install</pre> | ||
+ | |||
+ | After the above executes, the OpenSSL library will be FIPS capable and have static archives and shared objects available. The components will be installed in <tt>/usr/local/ssl</tt> directory. | ||
== The C++ Program == | == The C++ Program == | ||
Line 123: | Line 128: | ||
* Links with <tt>fipsld</tt> via <tt>CXX</tt> | * Links with <tt>fipsld</tt> via <tt>CXX</tt> | ||
− | Compiling occurs as normal, and includes <tt>-std=c++11</tt> (via <tt>CXXSTD</tt>) and <tt>-stdlib=libstdc++</tt> (via <tt>CXXSTDLIB</tt>). Linking will still use the compiler driver and <tt>CXXFLAGS</tt>, but it ''omits'' <tt>-std=c++11</tt> and <tt>-stdlib=libstdc++</tt>. ''Note'': if you are building on Mac OS X, you will need to include <tt>-stdlib=libc++</tt> when linking. | + | Compiling occurs as normal, and includes <tt>-std=c++11</tt> (via <tt>CXXSTD</tt>) and <tt>-stdlib=libstdc++</tt> (via <tt>CXXSTDLIB</tt>). Linking will still use the compiler driver and <tt>CXXFLAGS</tt>, but it ''omits'' <tt>-std=c++11</tt> and <tt>-stdlib=libstdc++</tt>. ''Note'': if you are building on Mac OS X, you will need to include <tt>-stdlib=libc++</tt> when compiling ''and'' linking. |
<pre>#! /bin/bash | <pre>#! /bin/bash | ||
+ | |||
+ | ################################ | ||
+ | # OpenSSL directory | ||
+ | |||
+ | if [ -z $OPENSSLDIR ] && [ -d /usr/local/ssl ]; then | ||
+ | OPENSSLDIR=/usr/local/ssl | ||
+ | fi | ||
+ | |||
+ | if [ -z "$OPENSSLDIR" ]; then | ||
+ | echo "Could not locate OpenSSL installation directory" | ||
+ | fi | ||
################################ | ################################ | ||
Line 133: | Line 149: | ||
CXX=/usr/local/bin/clang++ | CXX=/usr/local/bin/clang++ | ||
− | CFLAGS="-Wall -Wextra" | + | CFLAGS="-Os -g3 -Wall -Wextra" |
− | CXXFLAGS="-Wall -Wextra" | + | CXXFLAGS="-Os -g3 -Wall -Wextra" |
+ | |||
CXXSTD="-std=c++11" | CXXSTD="-std=c++11" | ||
CXXSTDLIB="-stdlib=libstdc++" | CXXSTDLIB="-stdlib=libstdc++" | ||
Line 143: | Line 160: | ||
if [ ! -z "$C_SOURCES" ]; then | if [ ! -z "$C_SOURCES" ]; then | ||
echo "Compiling C sources..." | echo "Compiling C sources..." | ||
− | (set -x; $CC $CFLAGS $C_SOURCES -c) | + | (set -x; $CC $CFLAGS -I$OPENSSLDIR/include $C_SOURCES -c) |
fi | fi | ||
if [ ! -z "$CXX_SOURCES" ]; then | if [ ! -z "$CXX_SOURCES" ]; then | ||
echo "Compiling C++ sources..." | echo "Compiling C++ sources..." | ||
− | (set -x; $CXX $CXXFLAGS $CXXSTD $CXXSTDLIB $CXX_SOURCES -c) | + | (set -x; $CXX $CXXFLAGS $CXXSTD $CXXSTDLIB -I$OPENSSLDIR/include $CXX_SOURCES -c) |
fi | fi | ||
################################ | ################################ | ||
# OpenSSL and fipsld | # OpenSSL and fipsld | ||
− | |||
− | |||
− | |||
− | |||
export FIPS_SIG=`find $OPENSSLDIR/fips-2.0 -iname incore 2>/dev/null` | export FIPS_SIG=`find $OPENSSLDIR/fips-2.0 -iname incore 2>/dev/null` | ||
Line 165: | Line 178: | ||
if [ -z "$CXX" ]; then | if [ -z "$CXX" ]; then | ||
− | echo "Could not locate 'fipsld' in $OPENSSLDIR/fips-2.0" | + | echo "Could not locate 'fipsld++' in $OPENSSLDIR/fips-2.0" |
fi | fi | ||
Line 184: | Line 197: | ||
(set -x; $CXX $CXXFLAGS -o main.exe $PROG_OBJECTS $OPENSSLDIR/lib/libssl.a $OPENSSLDIR/lib/libcrypto.a -ldl) | (set -x; $CXX $CXXFLAGS -o main.exe $PROG_OBJECTS $OPENSSLDIR/lib/libssl.a $OPENSSLDIR/lib/libcrypto.a -ldl) | ||
</pre> | </pre> | ||
+ | |||
+ | Be wary of using <tt>-Bstatic</tt>, <tt>-lssl</tt> and <tt>-lcrypto</tt>. The Apple linker will simply ignore your request for static linking if a shared object is available. You will have to use the full archive path or delete the shared objects to ensure static linking. Apple linkers will also ignore <tt>rpath</tt>'s and <tt>LD_PRELOAD_PATH</tt>s (and sometimes <tt>DYLD_INSERT_LIBRARIES</tt>), so you will silently link to their 0.9.8 version of the library and subsequently crash for mysterious reasons. | ||
== fipsld Modifications == | == fipsld Modifications == | ||
− | You have to make | + | Painting with a broad brush, there are three sections to <tt>fipsld</tt>. The first one-third or so is configuration, and it does things like locate <tt>fipscanister.o</tt> and <tt>fips_premain.c</tt>. The second one-third are steps to build a library or share object. The last one-third are steps to build a stand alone executable. |
+ | |||
+ | You have to make three modifications to <tt>fipsld</tt>, and the modifications generally apply to the last one-third of the <tt>fipsld</tt> since you are building a executable. If you are building a C++ shared object that statically links to OpenSSL, then you may have to fix the second one-third of <tt>fipsld</tt> too. Building a shared object that statically links to OpenSSL will encounter additional hardships due to <tt>{PREMAIN_DSO}</tt> and <tt>fips_premain_dso</tt>. | ||
+ | |||
+ | To begin, make a copy of ''<tt>fipsld</tt>'' and name it ''<tt>fipsld++</tt>''. | ||
=== First Change === | === First Change === | ||
− | Open <tt>fipsld++</tt> and find occurrences where <tt>fips_premain.c</tt> is compiled. There are four instances around lines | + | Open <tt>fipsld++</tt> and find occurrences where <tt>fips_premain.c</tt> is compiled. It is compiled through the variable <tt>{PREMAIN_C}</tt>. There are four instances around lines 125, 145, 175 and 195, and they look similar to the following. |
<pre>${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ | <pre>${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ | ||
Line 202: | Line 221: | ||
-x c "${PREMAIN_C}" -x none \ | -x c "${PREMAIN_C}" -x none \ | ||
${_WL_PREMAIN} "$@"</pre> | ${_WL_PREMAIN} "$@"</pre> | ||
+ | |||
+ | Forcing C compilation on <tt>fips_premain.c</tt> applies to all configurations (libraries, shared objects, and executables), so you are safe to apply it to all sections of <tt>fipsld++</tt>. | ||
If you build now, you will receive an error similar to <tt>main.exe is not cross-compiler aware</tt>: | If you build now, you will receive an error similar to <tt>main.exe is not cross-compiler aware</tt>: | ||
Line 207: | Line 228: | ||
<pre>:+/usr/local/ssl/fips-2.0/bin/incore ./main.exe | <pre>:+/usr/local/ssl/fips-2.0/bin/incore ./main.exe | ||
./main.exe is not cross-compiler aware.</pre> | ./main.exe is not cross-compiler aware.</pre> | ||
+ | |||
+ | The error is due to <tt>incore</tt> looking for the <tt>FIPS_text_startX</tt> and <tt>FIPS_text_endX</tt> symbols, which are ''not'' present in this configuration. <tt>incore</tt> will attempt to use the <tt>FIPS_text_start</tt> and <tt>FIPS_text_end</tt> symbols (notice the lack of '''X'''), but it needs the <tt>-exe</tt> switch. The <tt>-exe</tt> switch is discussed next. | ||
=== Second Change === | === Second Change === | ||
− | To fix the <tt>main.exe is not cross-compiler aware</tt> error, find occurrences where <tt>incore</tt> is invoked. <tt>incore</tt> is invoked through <tt>{FIPS_SIG}</tt>, and there are 2 instances around line | + | To fix the <tt>main.exe is not cross-compiler aware</tt> error, find occurrences where <tt>incore</tt> is invoked. <tt>incore</tt> is invoked through <tt>{FIPS_SIG}</tt>, and there are 2 instances around line 130 and 180. Fix the '''second''' instance around line 180 (you may have to fix the first instance too if building a C++ shared object, but that was not tested). The lines of interest look similar to the following. |
<pre>if [ "x${FIPS_SIG}" != "x" ]; then | <pre>if [ "x${FIPS_SIG}" != "x" ]; then | ||
Line 232: | Line 255: | ||
:+exit 0</pre> | :+exit 0</pre> | ||
− | But the <tt>fipsld++</tt> program exits early so that | + | But the <tt>fipsld++</tt> program exits early so that your compiled program only spews the expected signature: |
<pre>$ ./main.exe | <pre>$ ./main.exe | ||
669f9b0dfd1654fa0ff49574d988b8bfbd17338f</pre> | 669f9b0dfd1654fa0ff49574d988b8bfbd17338f</pre> | ||
+ | |||
+ | The program only outputs the expected fingerprint because the program's <tt>init</tt> was modified to execute <tt>FINGERPRINT_premain</tt>. <tt>FINGERPRINT_premain</tt> calculates the fingerprint, prints it to <tt>stdout</tt> and then exits. A second compilation of <tt>fips_premain.c</tt> and linking is required to complete the process. The second compilation and linking of <tt>fips_premain.c</tt> embeds the fingerprint calculated by the first instance and leaves <tt>init</tt> unchanged. The fingerprint is passed into <tt>fips_premain.c</tt> via <tt>-DHMAC_SHA1_SIG=...</tt> preprocessor macro. | ||
=== Third Change === | === Third Change === | ||
− | To fix the early exit of <tt>fipsld++</tt>, find the '''second''' occurrence of <tt>[ $? -ne 42 ] && exit $?</tt> and delete it. | + | To fix the early exit of <tt>fipsld++</tt>, find the '''second''' occurrence of <tt>[ $? -ne 42 ] && exit $?</tt> and delete it. The second instance occurs around line 180 (you may have to fix the first instance too if building a C++ shared object, but that was not tested): |
<pre>if [ "x${FIPS_SIG}" != "x" ]; then | <pre>if [ "x${FIPS_SIG}" != "x" ]; then | ||
Line 246: | Line 271: | ||
fi</pre> | fi</pre> | ||
− | After deleting the second instance of the | + | The value 42 is a magic value returned by <tt>incore</tt> that <tt>fipsld</tt> uses to determine if and how <tt>fipsld</tt> should continue. After deleting the second instance of the test, your program will build and run as expected. |
=== Unified Diff === | === Unified Diff === | ||
− | The unified diff between <tt>fipsld</tt> and <tt>fipsld++</tt> is shown below. | + | The unified diff between <tt>fipsld</tt> and <tt>fipsld++</tt> is shown below. The lines around 125 and 145 are the one-third of the script that applies to libraries and shared objects. The lines around 170 and 190 are the one-third of the script that applies to executable programs. If you are building a C++ shared object, then you might need to make the changes to both sections of <tt>fipsld++</tt> (a C++ shared object was not tested, so the guidance was not provided). |
− | <pre>/usr/local/ssl/fips-2.0/bin$ diff -u fipsld fipsld++ | + | <pre>/usr/local/ssl/fips-2.0/bin$ diff -u fipsld fipsld++ |
--- fipsld 2014-03-09 14:24:55.868366777 -0400 | --- fipsld 2014-03-09 14:24:55.868366777 -0400 | ||
− | +++ fipsld++ 2014-03- | + | +++ fipsld++ 2014-03-10 01:54:26.471892960 -0400 |
− | @@ -124, | + | @@ -124,7 +124,7 @@ |
/bin/rm -f "${TARGET}" | /bin/rm -f "${TARGET}" | ||
Line 264: | Line 289: | ||
if [ "x${FIPS_SIG}" != "x" ]; then | if [ "x${FIPS_SIG}" != "x" ]; then | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
@@ -143,7 +143,7 @@ | @@ -143,7 +143,7 @@ | ||
Line 322: | Line 341: | ||
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4a80d2c000) | libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4a80d2c000) | ||
/lib64/ld-linux-x86-64.so.2 (0x00007f4a81a72000)</pre> | /lib64/ld-linux-x86-64.so.2 (0x00007f4a81a72000)</pre> | ||
+ | |||
+ | On Mac OS X, <tt>otool</tt> is the <tt>ldd</tt> equivalent: | ||
+ | |||
+ | <pre>$ otool -L main.exe | ||
+ | main.exe: | ||
+ | /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0) | ||
+ | /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 65.1.0)</pre> | ||
== Downloads == | == Downloads == | ||
− | [[Media:fipsld++.tar.gz|fipsld++.tar.gz]] - | + | [[Media:fipsld++.tar.gz|fipsld++.tar.gz]] - The modified fipsld++ to create stand alone EXEs. |
+ | |||
+ | [[Category:FIPS 140]] |
Latest revision as of 19:02, 17 March 2014
This wiki page will cover building a C++ executable program from the command line that statically links to libssl.a and libcrypto.a. When performing a static link against the OpenSSL library, you have to embed the expected FIPS signature in your executable after final linking. Embedding the FIPS signature in your executable is most often accomplished with fisld.
fisld will take the place of the linker (or compiler if invoking via a compiler driver). If you use fisld to compile a source file, fisld will do nothing and simply invoke the compiler you specify through FIPSLD_CC. When it comes time to link, fisld will compile fips_premain.c, add fipscanister.o, and then perform the final link of your program. Once your program is linked, fisld will then invoke incore to embed the FIPS signature in your program.
The procedure requires three minor modifications to fipsld. The modifications will produce fipsld++ that follows the exiting procedures and re-uses the existing components. After fipsld++ is modified, its copied into fips-2.0 with the other FIPS binary components. According to Dr. Henson on the OpenSSL user list, fipsld is not sequestered and can be changed within reason as long as it performs the same basic steps and does not negatively affect the FIPS Object Module or resulting binary.
The example below demonstrates the procedures on Debian 7.3 (x64) using OpenSSL FIPS Capable 1.0.1f and the FIPS Object Module 2.0.5. The example demonstrates Clang and Clang++ with -stdlib=libstdc++. However, the procedures work equally well with GCC and G++ (you omit the -stdlib=libstdc++ for GNU compilers). The modified fisld script also works on Mac OS X 10.8 (be sure to use -stdlib=libc++ rather than libstdc++).
Background[edit]
When attempting to link through the compiler driver when the compiler is C++, you will encounter at least two errors due to fips_premain.c:
/tmp/fips_premain-20db15.o: In function `FINGERPRINT_premain()': /usr/local/ssl/fips-2.0/lib/fips_premain.c:103: undefined reference to `FIPS_text_start()' /usr/local/ssl/fips-2.0/lib/fips_premain.c:116: undefined reference to `FIPS_incore_fingerprint(unsigned char*, unsigned int)'
If you link with the -Wl,--no-demangle linker flag, you will see the linker is looking for a C++ mangled name because fips_premain.c was compiled with a C++ compiler:
/tmp/fips_premain-be4611.o: In function `_Z19FINGERPRINT_premainv': /usr/local/ssl/fips-2.0/lib/fips_premain.c:103: undefined reference to `_Z15FIPS_text_startv' /usr/local/ssl/fips-2.0/lib/fips_premain.c:116: undefined reference to `_Z23FIPS_incore_fingerprintPhj'
The problem occurs because the symbols are declared extern, and not extern "C" in fips_premain.c (from around line 85):
extern const void *FIPS_text_start(), *FIPS_text_end(); extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[]; extern unsigned char FIPS_signature[20]; extern unsigned int FIPS_incore_fingerprint(unsigned char *,unsigned int);
fips_premain.c cannot be changed because it is sequestered under the FIPS process. A different method must be used to link a C++ project.
FIPS Object Module[edit]
The FIPS Object Module is built in accordance with the steps detailed in the OpenSSL FIPS 2.0 Security Policy. The OpenSSL Foundation also publishes a user guide at User Guide for the OpenSSL FIPS Object Module v2.0. A grossly simplified version is presented below, but the steps are essentially the same as detailed in the guides and on other pages in the wiki.
# Download and verify signature on openssl-fips-2.0.5.tar.gz $ wget http://www.openssl.org/source/openssl-fips-2.0.5.tar.gz $ wget http://www.openssl.org/source/openssl-fips-2.0.5.tar.gz.asc $ pgp openssl-fips-2.0.5.tar.gz.asc pgp: Signature made Thu 20 Jun 2013 03:16:19 PM EDT using RSA key ID F295C759 ... # Build and install the FIPS Object Module $ tar -xzf openssl-fips-2.0.5.tar.gz $ cd openssl-fips-2.0.5 $ ./config $ make $ sudo make install # Copy required files missed by 'make install' $ find . -iname incore ./util/incore $ sudo cp util/incore /usr/local/ssl/fips-2.0/bin/ $ find . -iname fipsld ./fips/fipsld $ sudo cp fips/fipsld /usr/local/ssl/fips-2.0/bin/
After the above executes, the FIPS Object Module components will be installed in /usr/local/ssl/fips-2.0 directory. The components include fipscanister.o (and integrity signature), fips_premain.c (and integrity signature), incore and fipsld.
FIPS Capable Library[edit]
The FIP Capable Library is a version of OpenSSL that uses the FIPS Object Module. The difference between building the standard library and the capable library is simply a switch to config - the fips switch.
# # Download and verify signature on openssl-1.0.1f.tar.gz $ wget http://www.openssl.org/source/openssl-1.0.1f.tar.gz $ wget http://www.openssl.org/source/openssl-1.0.1f.tar.gz.asc $ pgp openssl-1.0.1f.tar.gz.asc pgp: Signature made Mon 06 Jan 2014 09:36:10 AM EST using RSA key ID F295C759 ... # Build and install the FIPS Capable Library $ tar -xzf openssl-1.0.1f.tar.gz $ cd openssl-1.0.1f/ $ ./config fips shared no-ssl2 <other options> $ make all $ sudo make install
After the above executes, the OpenSSL library will be FIPS capable and have static archives and shared objects available. The components will be installed in /usr/local/ssl directory.
The C++ Program[edit]
The sample C++ program is named main.cpp and simply enters FIPS mode.
#include <iostream> using std::cout; using std::endl; #include <openssl/evp.h> #include <openssl/err.h> int main(int argc, char* argv[]) { int rc, mode; mode = FIPS_mode(); if(mode == 0) { rc = FIPS_mode_set(1); if(rc == 0) { cout << "Failed to enable FIPS mode, "; cout << "error: " << ERR_get_error() << endl; } else { cout << "Enabled FIPS mode" << endl; } } else { cout << "Already in FIPS mode" << endl; } return 0; }
Build Script[edit]
A build script is used to build the sample program. The build script performs the following and is shown below:
- Sets OPENSSLDIR if its empty
- Sets FIPS_SIG to point to incore
- Sets FIPSLIBDIR to point to $OPENSSLDIR/fips-2.0/lib
- Collects C sources in C_SOURCES
- Collects C++ sources in CXX_SOURCES
- Invokes CC on C_SOURCES
- Invokes CXX on CXX_SOURCES
- Collects object files in PROG_OBJECTS
- Sets FIPSLD_CC to point to CXX
- Sets CXX to point to fipsld
- Links with fipsld via CXX
Compiling occurs as normal, and includes -std=c++11 (via CXXSTD) and -stdlib=libstdc++ (via CXXSTDLIB). Linking will still use the compiler driver and CXXFLAGS, but it omits -std=c++11 and -stdlib=libstdc++. Note: if you are building on Mac OS X, you will need to include -stdlib=libc++ when compiling and linking.
#! /bin/bash ################################ # OpenSSL directory if [ -z $OPENSSLDIR ] && [ -d /usr/local/ssl ]; then OPENSSLDIR=/usr/local/ssl fi if [ -z "$OPENSSLDIR" ]; then echo "Could not locate OpenSSL installation directory" fi ################################ # Standard build stuff CC=/usr/local/bin/clang CXX=/usr/local/bin/clang++ CFLAGS="-Os -g3 -Wall -Wextra" CXXFLAGS="-Os -g3 -Wall -Wextra" CXXSTD="-std=c++11" CXXSTDLIB="-stdlib=libstdc++" C_SOURCES=`ls *.c 2>/dev/null` CXX_SOURCES=`ls *.cpp 2>/dev/null` if [ ! -z "$C_SOURCES" ]; then echo "Compiling C sources..." (set -x; $CC $CFLAGS -I$OPENSSLDIR/include $C_SOURCES -c) fi if [ ! -z "$CXX_SOURCES" ]; then echo "Compiling C++ sources..." (set -x; $CXX $CXXFLAGS $CXXSTD $CXXSTDLIB -I$OPENSSLDIR/include $CXX_SOURCES -c) fi ################################ # OpenSSL and fipsld export FIPS_SIG=`find $OPENSSLDIR/fips-2.0 -iname incore 2>/dev/null` export FIPSLIBDIR=`find $OPENSSLDIR/fips-2.0 -iname lib 2>/dev/null` export FIPSLD_CC=$CXX export CXX=`find $OPENSSLDIR/fips-2.0 -iname fipsld++ 2>/dev/null` if [ -z "$CXX" ]; then echo "Could not locate 'fipsld++' in $OPENSSLDIR/fips-2.0" fi if [ -z "$FIPS_SIG" ]; then echo "Could not locate 'incore' in $OPENSSLDIR/fips-2.0" fi if [ -z "$FIPSLIBDIR" ]; then echo "Could not locate 'FIPS library directory' in $OPENSSLDIR/fips-2.0" fi ################################ # Back to linking PROG_OBJECTS=`ls *.o` echo "Linking..." (set -x; $CXX $CXXFLAGS -o main.exe $PROG_OBJECTS $OPENSSLDIR/lib/libssl.a $OPENSSLDIR/lib/libcrypto.a -ldl)
Be wary of using -Bstatic, -lssl and -lcrypto. The Apple linker will simply ignore your request for static linking if a shared object is available. You will have to use the full archive path or delete the shared objects to ensure static linking. Apple linkers will also ignore rpath's and LD_PRELOAD_PATHs (and sometimes DYLD_INSERT_LIBRARIES), so you will silently link to their 0.9.8 version of the library and subsequently crash for mysterious reasons.
fipsld Modifications[edit]
Painting with a broad brush, there are three sections to fipsld. The first one-third or so is configuration, and it does things like locate fipscanister.o and fips_premain.c. The second one-third are steps to build a library or share object. The last one-third are steps to build a stand alone executable.
You have to make three modifications to fipsld, and the modifications generally apply to the last one-third of the fipsld since you are building a executable. If you are building a C++ shared object that statically links to OpenSSL, then you may have to fix the second one-third of fipsld too. Building a shared object that statically links to OpenSSL will encounter additional hardships due to {PREMAIN_DSO} and fips_premain_dso.
To begin, make a copy of fipsld and name it fipsld++.
First Change[edit]
Open fipsld++ and find occurrences where fips_premain.c is compiled. It is compiled through the variable {PREMAIN_C}. There are four instances around lines 125, 145, 175 and 195, and they look similar to the following.
${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ "${PREMAIN_C}" \ ${_WL_PREMAIN} "$@"
Change the lines so that -x c proceeds "${PREMAIN_C}", and -x none follows it. An example is shown below.
${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ -x c "${PREMAIN_C}" -x none \ ${_WL_PREMAIN} "$@"
Forcing C compilation on fips_premain.c applies to all configurations (libraries, shared objects, and executables), so you are safe to apply it to all sections of fipsld++.
If you build now, you will receive an error similar to main.exe is not cross-compiler aware:
:+/usr/local/ssl/fips-2.0/bin/incore ./main.exe ./main.exe is not cross-compiler aware.
The error is due to incore looking for the FIPS_text_startX and FIPS_text_endX symbols, which are not present in this configuration. incore will attempt to use the FIPS_text_start and FIPS_text_end symbols (notice the lack of X), but it needs the -exe switch. The -exe switch is discussed next.
Second Change[edit]
To fix the main.exe is not cross-compiler aware error, find occurrences where incore is invoked. incore is invoked through {FIPS_SIG}, and there are 2 instances around line 130 and 180. Fix the second instance around line 180 (you may have to fix the first instance too if building a C++ shared object, but that was not tested). The lines of interest look similar to the following.
if [ "x${FIPS_SIG}" != "x" ]; then # embed signature "${FIPS_SIG}" "${TARGET}" [ $? -ne 42 ] && exit $? fi
Change the lines so the invocation includes the -exe switch:
if [ "x${FIPS_SIG}" != "x" ]; then # embed signature "${FIPS_SIG}" -exe "${TARGET}" [ $? -ne 42 ] && exit $? fi
If you build now, you will calculate the expected signature using your program (main.exe below).
:+/usr/local/ssl/fips-2.0/bin/incore -exe ./main.exe 7d0e8dfc1912fca2b02e3e4cc5b0f05ee90fc67d:+[ 0 -ne 42 ] :+exit 0
But the fipsld++ program exits early so that your compiled program only spews the expected signature:
$ ./main.exe 669f9b0dfd1654fa0ff49574d988b8bfbd17338f
The program only outputs the expected fingerprint because the program's init was modified to execute FINGERPRINT_premain. FINGERPRINT_premain calculates the fingerprint, prints it to stdout and then exits. A second compilation of fips_premain.c and linking is required to complete the process. The second compilation and linking of fips_premain.c embeds the fingerprint calculated by the first instance and leaves init unchanged. The fingerprint is passed into fips_premain.c via -DHMAC_SHA1_SIG=... preprocessor macro.
Third Change[edit]
To fix the early exit of fipsld++, find the second occurrence of [ $? -ne 42 ] && exit $? and delete it. The second instance occurs around line 180 (you may have to fix the first instance too if building a C++ shared object, but that was not tested):
if [ "x${FIPS_SIG}" != "x" ]; then # embed signature "${FIPS_SIG}" -exe "${TARGET}" fi
The value 42 is a magic value returned by incore that fipsld uses to determine if and how fipsld should continue. After deleting the second instance of the test, your program will build and run as expected.
Unified Diff[edit]
The unified diff between fipsld and fipsld++ is shown below. The lines around 125 and 145 are the one-third of the script that applies to libraries and shared objects. The lines around 170 and 190 are the one-third of the script that applies to executable programs. If you are building a C++ shared object, then you might need to make the changes to both sections of fipsld++ (a C++ shared object was not tested, so the guidance was not provided).
/usr/local/ssl/fips-2.0/bin$ diff -u fipsld fipsld++ --- fipsld 2014-03-09 14:24:55.868366777 -0400 +++ fipsld++ 2014-03-10 01:54:26.471892960 -0400 @@ -124,7 +124,7 @@ /bin/rm -f "${TARGET}" ${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ - "${PREMAIN_C}" \ + -x c "${PREMAIN_C}" -x none \ ${_WL_PREMAIN} "$@" if [ "x${FIPS_SIG}" != "x" ]; then @@ -143,7 +143,7 @@ # recompile with signature... ${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ - -DHMAC_SHA1_SIG=\"${SIG}\" "${PREMAIN_C}" \ + -DHMAC_SHA1_SIG=\"${SIG}\" -x c "${PREMAIN_C}" -x none \ ${_WL_PREMAIN} "$@" ;; @@ -172,13 +172,12 @@ /bin/rm -f "${TARGET}" ${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ - "${PREMAIN_C}" \ + -x c "${PREMAIN_C}" -x none \ ${_WL_PREMAIN} "$@" if [ "x${FIPS_SIG}" != "x" ]; then # embed signature - "${FIPS_SIG}" "${TARGET}" - [ $? -ne 42 ] && exit $? + "${FIPS_SIG}" -exe "${TARGET}" fi # generate signature... @@ -191,7 +190,7 @@ # recompile with signature... ${CC} ${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \ - -DHMAC_SHA1_SIG=\"${SIG}\" "${PREMAIN_C}" \ + -DHMAC_SHA1_SIG=\"${SIG}\" -x c "${PREMAIN_C}" -x none \ ${_WL_PREMAIN} "$@" ;; esac
Program Correctness[edit]
You can confirm the program executes successfully with the message Enabled FIPS mode:
$ ./main.exe Enabled FIPS mode
In addition, there will be no shared object dependencies on libssl or libcrypto:
$ ldd ./main.exe linux-vdso.so.1 => (0x00007fff4d5ff000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f4a81857000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4a81550000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4a812cd000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f4a810b7000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4a80d2c000) /lib64/ld-linux-x86-64.so.2 (0x00007f4a81a72000)
On Mac OS X, otool is the ldd equivalent:
$ otool -L main.exe main.exe: /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 65.1.0)
Downloads[edit]
fipsld++.tar.gz - The modified fipsld++ to create stand alone EXEs.