Christopher Fahlin d0c201dd9f fix(fips): regenerate fipsmodule.cnf for OpenSSL 3.1.2 arm64-v8a
HMAC fingerprint generated on-device via openssl fipsinstall against
the 3.1.2 FIPS provider binary. All 29 KATs passed.
2026-05-09 12:52:08 -07:00
2026-05-04 19:34:28 -07:00
2026-05-04 19:34:28 -07:00
2026-05-04 19:34:28 -07:00
2026-05-04 19:34:28 -07:00

fips-sqlcipher

A reproducible cross-compile pipeline that produces FIPS 140-3 compliant OpenSSL 3.1.x + SQLCipher 4.6.x for Android and iOS. Output:

  • Android: Self-contained AAR with arm64-v8a + x86_64 shared libs, FIPS provider module, and runtime config.
  • iOS: Universal XCFramework (device arm64 + simulator arm64/x86_64) with static libs, module maps for Swift/Objective-C++, and FIPS config.

Sources are fetched automatically. CMake's ExternalProject_Add downloads the OpenSSL tarball (sha256-pinned) and git clone --depth=1's SQLCipher at the configured tag. You do NOT need to vendor either source tree.


Quick Start

# 1. Install mise (one-time)
curl https://mise.run | sh

# 2. Bootstrap tooling
mise trust && mise install

# 3. Build everything
export ANDROID_NDK_ROOT="$HOME/Library/Android/sdk/ndk/26.3.11579264"
./build.sh all

# 4. Package
./build.sh package

Environment Setup (Mise)

This repo uses mise to pin deterministic versions of all host build tools. The .mise.toml declares:

Tool Version Purpose
cmake 3.29 Build system orchestration
ninja 1.12.1 iOS cmake generator (faster builds)
perl 5.40.2 OpenSSL Configure script
java temurin-17 AAR packaging (Gradle/AGP 8.x)
gradle 8.10.2 AAR packaging + test app

Not managed by mise (install separately):

  • Android NDK r26+ (via sdkmanager --install "ndk;26.3.11579264")
  • Xcode + Command Line Tools (for iOS builds)

Installation

# Install mise
curl https://mise.run | sh
# Add to shell (if not already)
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc
source ~/.zshrc

# From repo root:
mise trust
mise install

# Verify
cmake --version   # 3.29.x
ninja --version   # 1.12.1
perl --version    # 5.40.x

Android NDK

# Via sdkmanager
sdkmanager --install "ndk;26.3.11579264"
export ANDROID_NDK_ROOT="$HOME/Library/Android/sdk/ndk/26.3.11579264"

# Or via Android Studio:
# Settings -> Languages & Frameworks -> Android SDK -> SDK Tools -> NDK

Build Commands

# --- Android ---
./build.sh android                          # arm64-v8a (default)
ANDROID_ABI=x86_64 ./build.sh android      # emulator
./build.sh all                              # all platforms + arches

# --- iOS ---
./build.sh ios                              # device arm64
./build.sh ios-simulator                    # simulator arm64 + x86_64
./build.sh ios-all                          # device + simulator

# --- Packaging ---
./build.sh package-aar                      # -> dist/fips-sqlcipher.aar
./build.sh package-xcframework              # -> dist/FIPSSQLCipher.xcframework
./build.sh package                          # both

Configuration Variables

Variable Default Description
ANDROID_NDK_ROOT (required) Path to NDK r26+
ANDROID_ABI arm64-v8a arm64-v8a, armeabi-v7a, x86_64, x86
ANDROID_PLATFORM android-24 Minimum Android API level
OPENSSL_VERSION 3.1.2 FIPS 140-3 Cert #4985 baseline
SQLCIPHER_VERSION v4.6.1 SQLCipher git tag
IOS_DEPLOYMENT_TARGET 15.0 Minimum iOS version
OPENSSL_HOST_BIN (unset) Host openssl for in-tree fipsinstall
BUILD_TYPE Release CMake build type
JOBS auto Parallel compile jobs

Artifacts

Android (dist/<abi>/)

Path Purpose
lib/libcrypto.so OpenSSL crypto runtime
lib/libssl.so OpenSSL TLS runtime
lib/libsqlcipher.so SQLCipher (FIPS probe linked in)
fips/libfips.so FIPS provider (HMAC-protected)
fips/openssl.cnf Runtime config activating FIPS
fips/fipsmodule.cnf HMAC manifest (generated on-device)
fips/verify_integrity.sh CI integrity gate
fips/fips_integrity.gradle AGP no-strip guard

iOS (dist/ios-<arch>/)

Path Purpose
lib/libcrypto.a OpenSSL (static, FIPS-enabled)
lib/libssl.a OpenSSL TLS (static)
lib/libsqlcipher.a SQLCipher (static, FIPS probe)
fips/fips.a FIPS provider (static, incore HMAC)
fips/fips.a.sha256 Baseline integrity hash

Packaged

Path Format
dist/fips-sqlcipher.aar Android AAR
dist/FIPSSQLCipher.xcframework XCFramework

Android Integration (AAR)

Gradle Setup

// app/build.gradle.kts
dependencies {
    implementation(files("libs/fips-sqlcipher.aar"))
}

android {
    packaging {
        jniLibs {
            useLegacyPackaging = false
            keepDebugSymbols += setOf("**/libfips.so")
        }
    }
}

Runtime Initialization

class FipsInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        val fipsDir = File(context.filesDir, "fips").apply { mkdirs() }
        listOf("openssl.cnf", "fipsmodule.cnf").forEach { name ->
            val dst = File(fipsDir, name)
            if (!dst.exists()) {
                context.assets.open("fips/$name").use { src ->
                    dst.outputStream().use { src.copyTo(it) }
                }
            }
        }
        Env.setenv("OPENSSL_CONF", File(fipsDir, "openssl.cnf").absolutePath)
        Env.setenv("FIPSMODULE_CNF", File(fipsDir, "fipsmodule.cnf").absolutePath)
        Env.setenv("OPENSSL_MODULES", context.applicationInfo.nativeLibraryDir)

        System.loadLibrary("crypto")
        System.loadLibrary("fips")
        System.loadLibrary("sqlcipher")
    }
    override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
}

iOS Integration (XCFramework)

Setup

  1. Drag FIPSSQLCipher.xcframework into your Xcode project (or add via SPM binary target).
  2. In Build Settings, add to "Other Linker Flags": -lz
  3. Link Security.framework.
  4. Copy Resources/fips/openssl.cnf and fipsmodule.cnf into your app bundle.

Swift Usage

import FIPSSQLCipher

// Set env BEFORE any OpenSSL/SQLCipher call
let fipsDir = Bundle.main.path(forResource: "fips", ofType: nil)!
setenv("OPENSSL_CONF", "\(fipsDir)/openssl.cnf", 1)
setenv("FIPSMODULE_CNF", "\(fipsDir)/fipsmodule.cnf", 1)

Xcode Build Settings (FIPS Integrity)

Apply dist/ios-arm64/fips/fips_integrity.xcconfig or set manually:

STRIP_INSTALLED_PRODUCT = NO
COPY_PHASE_STRIP = NO
DEPLOYMENT_POSTPROCESSING = NO
ENABLE_BITCODE = NO

C++ Verification

The include/ directory ships a C++ verification class. Include path: -I<repo>/include (or it's bundled in the XCFramework headers).

#include "fips_verify.hpp"

// After opening and keying a database:
auto result = fips::Verifier::check_all(db);
assert(result.provider_active);       // OSSL_PROVIDER_available(NULL, "fips")
assert(result.self_test_passed);      // POST KATs passed
assert(result.cipher_fips_status);    // PRAGMA cipher_fips_status == 1

The fips_sqlcipher.h header wraps all OpenSSL and SQLCipher includes in extern "C" for safe C++ interop without ODR violations:

#include "fips_sqlcipher.h"  // Safe from any C++ TU

C++ flag compatibility:

  • Your C++ code can freely use -frtti, -fexceptions, or disable them.
  • The FIPS incore HMAC covers only the provider's .text/.rodata sections, not your application code. C++ flags in your TUs cannot invalidate it.
  • On Android, use the NDK's shared libc++ (default) to avoid ODR violations when multiple shared libs link against the STL.

Generating fipsmodule.cnf

The FIPS manifest must be produced on a matching CPU architecture.

Android (on-device)

adb push dist/arm64-v8a/fips /data/local/tmp/fips
adb push dist/arm64-v8a/bin/openssl /data/local/tmp/fips/openssl
adb shell sh /data/local/tmp/fips/run_fipsinstall_on_device.sh
adb pull /data/local/tmp/fips/fipsmodule.cnf dist/arm64-v8a/fips/

Android (host shortcut, x86_64 only)

OPENSSL_HOST_BIN=/opt/homebrew/bin/openssl ANDROID_ABI=x86_64 ./build.sh android

iOS

On macOS arm64, the device slice (ios-arm64) can run fipsinstall via Rosetta or on a connected device. For CI, use a matching-arch runner.


Integrity Verification (CI)

# Android
dist/arm64-v8a/fips/verify_integrity.sh dist/arm64-v8a/fips/libfips.so

# After APK packaging
unzip -p app-release.apk lib/arm64-v8a/libfips.so > /tmp/libfips.so
dist/arm64-v8a/fips/verify_integrity.sh /tmp/libfips.so
shasum -a 256 /tmp/libfips.so | diff - dist/arm64-v8a/fips/libfips.so.sha256

# iOS (static module baseline)
shasum -a 256 dist/ios-arm64/fips/fips.a | diff - dist/ios-arm64/fips/fips.a.sha256

FIPS Compliance Notes

  • Module boundary: libfips.so (Android) / fips.a (iOS) is the sole FIPS-validated cryptographic boundary. Everything else is a consumer.

  • Power-On Self-Tests (POST): Required by FIPS 140-3. Run at first OSSL_PROVIDER_load(NULL, "fips"). Failure aborts before any crypto API returns.

  • Post-build mutation: Strip, codesign with bitcode rewrite, ProGuard native-symbol manipulation, or APK compression invalidates the HMAC. The shipped verify_integrity.sh (Android) and .sha256 baselines (iOS) are your CI gates.

  • iOS static linking: Since iOS prohibits dlopen of arbitrary dylibs in production apps, the FIPS provider is statically linked. The incore integrity mechanism embeds the HMAC verification into the binary itself.

  • Reproducibility: OpenSSL tarball SHA256 is pinned in cmake/BuildOpenSSL.cmake. SQLCipher git tag is pinned in cmake/BuildSQLCipher.cmake. Do not bump without updating hashes and re-running integrity baselines.


Troubleshooting

Symptom Cause Fix
FATAL: missing required host tools: cmake mise not bootstrapped mise trust && mise install
FATAL: export ANDROID_NDK_ROOT=... NDK not exported See Android NDK
Ninja not found (iOS build) mise not activated eval "$(mise activate zsh)"
xcrun: error: SDK not found Xcode CLI tools missing xcode-select --install
App aborts: FIPS provider not active OPENSSL_CONF not set before first call Move env setup earlier
FIPS audit fails after release packaging AGP stripped libfips.so Apply fips_integrity.gradle
XCFramework link error: _EVP_* undefined Missing -lz or Security.framework Add to Other Linker Flags

Project Structure

.mise.toml                              # Pinned build tools
build.sh                                # Orchestration (android/ios/package)
CMakeLists.txt                          # Android entry point
CMakeLists_iOS.cmake                    # iOS entry point
cmake/
  BuildOpenSSL.cmake                    # Android OpenSSL (shared, enable-fips)
  BuildOpenSSL_iOS.cmake                # iOS OpenSSL (static, enable-fips)
  BuildSQLCipher.cmake                  # Android SQLCipher
  BuildSQLCipher_iOS.cmake              # iOS SQLCipher
  PreserveFipsIntegrity.cmake           # Strip kill-switch, integrity guards
include/
  fips_sqlcipher.h                      # C/C++ interop header (extern "C")
  fips_verify.hpp                       # C++ FIPS verification class
packaging/
  package_aar.sh                        # Android AAR assembly
  package_xcframework.sh                # iOS XCFramework assembly
tests/android-fips/                     # Runtime compliance test app
dist/                                   # Build output (gitignored)
S
Description
No description provided
Readme 783 KiB
Languages
CMake 28.7%
Kotlin 26%
Shell 22.9%
C 20.7%
C++ 1.7%