LoginSignup
8
6

More than 3 years have passed since last update.

OpenSSL 1.0.1j を Android 向けに mac でビルドする

Last updated at Posted at 2019-08-13

:bangbang: 注意 :bangbang:

この記事でビルドする OpenSSL は 1.0.1j という古いバージョンです!!
脆弱性を考慮して、可能であれば最新バージョンを使うべきです。

最新バージョンをビルドするため公式ドキュメントはこちら
...のはずですが、ちっともビルドできんやんか :bangbang::anger::anger::anger:

はじめに

訳あって、OpenSSL の 1.0.1j という古いバージョンを
Android 向けにビルドしてスタティックライブラリ(.a)を作成する必要があり、
試行錯誤してなんとかビルドできたので記録しておきます。

まぁ、遅ればせながら、64ビット対応 をしたということです。

ソースコードを取得

公式サイトの Downloads にある source/old からソースコード(tar.gz形式)をダウンロードして適当なところに展開します。

$ mkdir OpenSSL
$ cd OpenSSL
$ curl https://www.openssl.org/source/old/1.0.1/openssl-1.0.1j.tar.gz -o openssl-1.0.1j.tar.gz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 4329k  100 4329k    0     0  1888k      0  0:00:02  0:00:02 --:--:-- 1889k
$ ls -1
total 8664
openssl-1.0.1j.tar.gz
$ tar zxf openssl-1.0.1j.tar.gz
$ ls -1
openssl-1.0.1j/
openssl-1.0.1j.tar.gz

NDKを取得

公式サイトDOWNLOADSからNDK(zip形式)をダウンロードして適当なところに解凍します。

ワタシの環境は mac なので darwin-x86_64 というのをダウンロードしました。

$ curl https://dl.google.com/android/repository/android-ndk-r20-darwin-x86_64.zip -o android-ndk-r20-darwin-x86_64.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  804M  100  804M    0     0  10.8M      0  0:01:14  0:01:14 --:--:-- 11.1M
$ unzip -q android-ndk-r20-darwin-x86_64.zip
$ ls -1
android-ndk-r20/
android-ndk-r20-darwin-x86_64.zip
openssl-1.0.1j/
openssl-1.0.1j.tar.gz

Makefile生成

ビルド環境 = 動作環境 であれば、

$ cd openssl-1.0.1j/
$ ./config

とやれば、ビルド用の Makefile が生成されるというパターンが多いみたいですが、
今回の場合は動作環境が Android なわけで、Androd 上で動作するバイナリをビルドする為の Makefile を生成しなくてはなりません。

ツールチェイン

前項で取得してきた NDK にはツールチェインというものが含まれていて、ソースコードをコンパイル/リンクするにあたっては、mac の gcc コマンドではなく、ツールチェインが提供するものを代わりを使うようです。

ツールチェインは NDKを解凍したフォルダ/toolchains/ にあります。

$ ls -1 android-ndk-r20/toolchains/
aarch64-linux-android-4.9/
arm-linux-androideabi-4.9/
llvm/
renderscript/
x86-4.9/
x86_64-4.9/

しかし、

「armeabi-v7a 用をビルドするには arm-linux-androideabi-4.9 を使えばいいのね」

ではないんです。

現在の mac(というかXcode)は、gccではなくclangを使っているためか、llvm を使うようです。

で、使うツール類は mac なら prebuilt/darwin-x86_64/bin の下に

$ ls android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/bin/
aarch64-linux-android-addr2line     armv7a-linux-androideabi21-clang    i686-linux-android27-clang
aarch64-linux-android-ar            armv7a-linux-androideabi21-clang++  i686-linux-android27-clang++
aarch64-linux-android-as            armv7a-linux-androideabi22-clang    i686-linux-android28-clang
aarch64-linux-android-c++filt       armv7a-linux-androideabi22-clang++  i686-linux-android28-clang++
aarch64-linux-android-dwp           armv7a-linux-androideabi23-clang    i686-linux-android29-clang
aarch64-linux-android-elfedit       armv7a-linux-androideabi23-clang++  i686-linux-android29-clang++
aarch64-linux-android-gprof         armv7a-linux-androideabi24-clang    ld.lld
aarch64-linux-android-ld            armv7a-linux-androideabi24-clang++  llvm-ar
aarch64-linux-android-ld.bfd        armv7a-linux-androideabi26-clang    llvm-as
aarch64-linux-android-ld.gold       armv7a-linux-androideabi26-clang++  llvm-config
aarch64-linux-android-nm            armv7a-linux-androideabi27-clang    llvm-cov
aarch64-linux-android-objcopy       armv7a-linux-androideabi27-clang++  llvm-dis
aarch64-linux-android-objdump       armv7a-linux-androideabi28-clang    llvm-link
aarch64-linux-android-ranlib        armv7a-linux-androideabi28-clang++  llvm-modextract
aarch64-linux-android-readelf       armv7a-linux-androideabi29-clang    llvm-nm
aarch64-linux-android-size          armv7a-linux-androideabi29-clang++  llvm-objcopy
aarch64-linux-android-strings       bisect_driver.py                    llvm-profdata
aarch64-linux-android-strip         clang                               llvm-readobj
aarch64-linux-android21-clang       clang++                             llvm-strip
aarch64-linux-android21-clang++     clang-check                         llvm-symbolizer
aarch64-linux-android22-clang       clang-format                        sancov
aarch64-linux-android22-clang++     clang-tidy                          sanstats
aarch64-linux-android23-clang       clang-tidy.real                     scan-build
aarch64-linux-android23-clang++     git-clang-format                    scan-view
aarch64-linux-android24-clang       i686-linux-android-addr2line        x86_64-linux-android-addr2line
aarch64-linux-android24-clang++     i686-linux-android-ar               x86_64-linux-android-ar
aarch64-linux-android26-clang       i686-linux-android-as               x86_64-linux-android-as
aarch64-linux-android26-clang++     i686-linux-android-c++filt          x86_64-linux-android-c++filt
aarch64-linux-android27-clang       i686-linux-android-dwp              x86_64-linux-android-dwp
aarch64-linux-android27-clang++     i686-linux-android-elfedit          x86_64-linux-android-elfedit
aarch64-linux-android28-clang       i686-linux-android-gprof            x86_64-linux-android-gprof
aarch64-linux-android28-clang++     i686-linux-android-ld               x86_64-linux-android-ld
aarch64-linux-android29-clang       i686-linux-android-ld.bfd           x86_64-linux-android-ld.bfd
aarch64-linux-android29-clang++     i686-linux-android-ld.gold          x86_64-linux-android-ld.gold
arm-linux-androideabi-addr2line     i686-linux-android-nm               x86_64-linux-android-nm
arm-linux-androideabi-ar            i686-linux-android-objcopy          x86_64-linux-android-objcopy
arm-linux-androideabi-as            i686-linux-android-objdump          x86_64-linux-android-objdump
arm-linux-androideabi-c++filt       i686-linux-android-ranlib           x86_64-linux-android-ranlib
arm-linux-androideabi-dwp           i686-linux-android-readelf          x86_64-linux-android-readelf
arm-linux-androideabi-elfedit       i686-linux-android-size             x86_64-linux-android-size
arm-linux-androideabi-gprof         i686-linux-android-strings          x86_64-linux-android-strings
arm-linux-androideabi-ld            i686-linux-android-strip            x86_64-linux-android-strip
arm-linux-androideabi-ld.bfd        i686-linux-android16-clang          x86_64-linux-android21-clang
arm-linux-androideabi-ld.gold       i686-linux-android16-clang++        x86_64-linux-android21-clang++
arm-linux-androideabi-nm            i686-linux-android17-clang          x86_64-linux-android22-clang
arm-linux-androideabi-objcopy       i686-linux-android17-clang++        x86_64-linux-android22-clang++
arm-linux-androideabi-objdump       i686-linux-android18-clang          x86_64-linux-android23-clang
arm-linux-androideabi-ranlib        i686-linux-android18-clang++        x86_64-linux-android23-clang++
arm-linux-androideabi-readelf       i686-linux-android19-clang          x86_64-linux-android24-clang
arm-linux-androideabi-size          i686-linux-android19-clang++        x86_64-linux-android24-clang++
arm-linux-androideabi-strings       i686-linux-android21-clang          x86_64-linux-android26-clang
arm-linux-androideabi-strip         i686-linux-android21-clang++        x86_64-linux-android26-clang++
armv7a-linux-androideabi16-clang    i686-linux-android22-clang          x86_64-linux-android27-clang
armv7a-linux-androideabi16-clang++  i686-linux-android22-clang++        x86_64-linux-android27-clang++
armv7a-linux-androideabi17-clang    i686-linux-android23-clang          x86_64-linux-android28-clang
armv7a-linux-androideabi17-clang++  i686-linux-android23-clang++        x86_64-linux-android28-clang++
armv7a-linux-androideabi18-clang    i686-linux-android24-clang          x86_64-linux-android29-clang
armv7a-linux-androideabi18-clang++  i686-linux-android24-clang++        x86_64-linux-android29-clang++
armv7a-linux-androideabi19-clang    i686-linux-android26-clang          yasm
armv7a-linux-androideabi19-clang++  i686-linux-android26-clang++

こんな感じでいっぱい入ってます。

たとえば、C言語のコンパイルは、APIレベル21以降を対象にする場合、

  • armeabi-v7a なら armv7a-linux-androideabi21-clang
  • arm64-v8a なら aarch64-linux-android21-clang

を使う、といった具合です。

環境変数を設定

OpenSSL の ./Configure が取り込む環境変数を、動作環境別に設定します。

とりあえず NDK の解凍場所とツールチェインの場所を設定して後の作業をラクにします。

$ export ANDROID_NDK_HOME=`pwd`/android-ndk-r20
$ env | grep ANDROID_NDK_HOME
ANDROID_NDK_HOME=/tmp/OpenSSL/android-ndk-r20
$ export NDK_TOOLCHAIN_ROOT=${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/darwin-x86_64
$ env | grep NDK_TOOLCHAIN_ROOT
NDK_TOOLCHAIN_ROOT=/tmp/OpenSSL/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64

ビルドされたブツの格納先もここで設定しておきます。

$ export OUTPUT_DIR=`pwd`/output/openssl-1.0.1j

armeabi-v7a 向け

ANDROID_API の値は適宜、サポートする最低バージョンに置き換えてください。

$ export        ARCH=android-armv7
$ export ANDROID_API=16
$ export          CC=${NDK_TOOLCHAIN_ROOT}/bin/armv7a-linux-androideabi${ANDROID_API}-clang
$ export         CXX=${NDK_TOOLCHAIN_ROOT}/bin/armv7a-linux-androideabi${ANDROID_API}-clang++
$ export          LD=${NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ld
$ export          AR=${NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ar
$ export      RANLIB=${NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-ranlib
$ export       STRIP=${NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-strip
$ export      CFLAGS="-mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -mfpu=neon -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing"
$ export     LDFLAGS="-Wl,--fix-cortex-a8"

arm64-v8a 向け

2019年8月1日以降は、64ビット対応していないと Play Store に登録できないので仕方ないですね。
Android の OS側 の64ビット対応は API 21 (Lolipop) かららしいです。

$ export        ARCH=android
$ export ANDROID_API=21
$ export          CC=${NDK_TOOLCHAIN_ROOT}/bin/aarch64-linux-android${ANDROID_API}-clang
$ export         CXX=${NDK_TOOLCHAIN_ROOT}/bin/aarch64-linux-android${ANDROID_API}-clang++
$ export          LD=${NDK_TOOLCHAIN_ROOT}/bin/aarch64-linux-android-ld
$ export          AR=${NDK_TOOLCHAIN_ROOT}/bin/aarch64-linux-android-ar
$ export      RANLIB=${NDK_TOOLCHAIN_ROOT}/bin/aarch64-linux-android-ranlib
$ export       STRIP=${NDK_TOOLCHAIN_ROOT}/bin/aarch64-linux-android-strip
$ export      CFLAGS="shared no-ssl2 no-ssl3 no-hw -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing"
$ export     LDFLAGS=""

x86 向け

エミュレータで動かせると便利なときもあるので。

$ export        ARCH=android-x86
$ export ANDROID_API=16
$ export          CC=${NDK_TOOLCHAIN_ROOT}/bin/i686-linux-android${ANDROID_API}-clang
$ export         CXX=${NDK_TOOLCHAIN_ROOT}/bin/i686-linux-android${ANDROID_API}-clang++
$ export          LD=${NDK_TOOLCHAIN_ROOT}/bin/i686-linux-android-ld
$ export          AR=${NDK_TOOLCHAIN_ROOT}/bin/i686-linux-android-ar
$ export      RANLIB=${NDK_TOOLCHAIN_ROOT}/bin/i686-linux-android-ranlib
$ export       STRIP=${NDK_TOOLCHAIN_ROOT}/bin/i686-linux-android-strip
$ export      CFLAGS="-mtune=intel -msse3 -mfpmath=sse -m32 -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing"
$ export     LDFLAGS=""

Configure 実行

CFLAGS 環境変数は自動で取り込まれないんで、引数として渡してやります。

Configure Options:
https://wiki.openssl.org/index.php/Compilation_and_Installation#Configure_Options

$ cd openssl-1.0.1j/
$ ./Configure \
        ${ARCH} \
        ${CFLAGS} \
        --prefix=${OUTPUT_DIR} \
        --with-zlib-include=${NDK_TOOLCHAIN_ROOT}/sysroot/usr/include \
        --with-zlib-lib=${NDK_TOOLCHAIN_ROOT}/sysroot/usr/lib \
        zlib no-asm no-shared no-unit-test
Configuring for android-armv7
(中略)
Configured for android-armv7.

で、Makefile が出来上がるわけですが、
その出来上がった Makefile に -mandroid というコンパイルオプションが指定されています。
このオプションは clang には存在せず、コンパイル時にエラーになるので除去します。

$ sed -i -e s/\-mandroid//g Makefile
$ diff Makefile-e Makefile
63c63
< CFLAG= -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -mfpu=neon -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -march=armv7-a -mandroid -I$(ANDROID_DEV)/include -B$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall
---
> CFLAG= -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -mfpu=neon -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -march=armv7-a  -I$(ANDROID_DEV)/include -B$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall

ビルド

やっとビルドです。

$ make
(中略)
making all in tools...
make[1]: Nothing to be done for `all'.
$ make install_sw
created directory `/tmp/OpenSSL/output'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/bin'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/lib'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/lib/engines'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/lib/pkgconfig'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/include'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/include/openssl'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/ssl'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/ssl/misc'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/ssl/certs'
created directory `/tmp/OpenSSL/output/openssl-1.0.1j/ssl/private'
making install in crypto...
making install in crypto/objects...
making install in crypto/md4...
making install in crypto/md5...
making install in crypto/sha...
making install in crypto/mdc2...
making install in crypto/hmac...
making install in crypto/ripemd...
making install in crypto/whrlpool...
making install in crypto/des...
making install in crypto/aes...
making install in crypto/rc2...
making install in crypto/rc4...
making install in crypto/idea...
making install in crypto/bf...
making install in crypto/cast...
making install in crypto/camellia...
making install in crypto/seed...
making install in crypto/modes...
making install in crypto/bn...
making install in crypto/ec...
making install in crypto/rsa...
making install in crypto/dsa...
making install in crypto/ecdsa...
making install in crypto/dh...
making install in crypto/ecdh...
making install in crypto/dso...
making install in crypto/engine...
making install in crypto/buffer...
making install in crypto/bio...
making install in crypto/stack...
making install in crypto/lhash...
making install in crypto/rand...
making install in crypto/err...
making install in crypto/evp...
making install in crypto/asn1...
making install in crypto/pem...
making install in crypto/x509...
making install in crypto/x509v3...
making install in crypto/conf...
making install in crypto/txt_db...
making install in crypto/pkcs7...
making install in crypto/pkcs12...
making install in crypto/comp...
making install in crypto/ocsp...
making install in crypto/ui...
making install in crypto/krb5...
making install in crypto/cms...
making install in crypto/pqueue...
making install in crypto/ts...
making install in crypto/srp...
making install in crypto/cmac...
making install in ssl...
making install in engines...
making install in engines/ccgost...
[ -n "/tmp/OpenSSL/output/openssl-1.0.1j" ] # should be set by top Makefile...
if [ -n "" ]; then \
        set -e; \
        echo installing gost; \
        pfx=lib; \
        if [ "android-armv7" != "Cygwin" ]; then \
            case "-I../../include -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -mfpu=neon -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -march=armv7-a  -I/include -B/lib -O3 -fomit-frame-pointer -Wall" in \
            *DSO_BEOS*) sfx=".so";; \
            *DSO_DLFCN*) sfx=`expr ".so.1.0.0" : '.*\(\.[a-z][a-z]*\)' \| ".so"`;; \
            *DSO_DL*) sfx=".sl";; \
            *DSO_WIN32*) sfx="eay32.dll"; pfx=;; \
            *) sfx=".bad";; \
            esac; \
            cp ${pfx}gost$sfx /tmp/OpenSSL/output/openssl-1.0.1j/lib/engines/${pfx}gost$sfx.new; \
        else \
            sfx=".so"; \
            cp cyggost.dll /tmp/OpenSSL/output/openssl-1.0.1j/lib/engines/${pfx}gost$sfx.new; \
        fi; \
        chmod 555 /tmp/OpenSSL/output/openssl-1.0.1j/lib/engines/${pfx}gost$sfx.new; \
        mv -f /tmp/OpenSSL/output/openssl-1.0.1j/lib/engines/${pfx}gost$sfx.new /tmp/OpenSSL/output/openssl-1.0.1j/lib/engines/${pfx}gost$sfx; \
    fi
making install in apps...
installing openssl
installing CA.sh
installing CA.pl
installing tsget
making install in test...
make[1]: Nothing to be done for `install'.
making install in tools...
installing libcrypto.a
installing libssl.a
cp libcrypto.pc /tmp/OpenSSL/output/openssl-1.0.1j/lib/pkgconfig
chmod 644 /tmp/OpenSSL/output/openssl-1.0.1j/lib/pkgconfig/libcrypto.pc
cp libssl.pc /tmp/OpenSSL/output/openssl-1.0.1j/lib/pkgconfig
chmod 644 /tmp/OpenSSL/output/openssl-1.0.1j/lib/pkgconfig/libssl.pc
cp openssl.pc /tmp/OpenSSL/output/openssl-1.0.1j/lib/pkgconfig
chmod 644 /tmp/OpenSSL/output/openssl-1.0.1j/lib/pkgconfig/openssl.pc

さて、終わりました。
ライブラリファイルは出来ているでしょうか...

$ ls -1 ../output/openssl-1.0.1j/lib/
engines/
libcrypto.a
libssl.a
pkgconfig/

できてるゥ:exclamation:

念のため、中身を確認してみます。

$ ${NDK_TOOLCHAIN_ROOT}/bin/arm-linux-androideabi-readelf -h ../output/openssl-1.0.1j/lib/libssl.a | grep Machine | uniq
  Machine:                           ARM

ちゃんと ARM になってますね。

arm64-v8a でビルドした場合も確認してみます。

$ ${NDK_TOOLCHAIN_ROOT}/bin/aarch64-linux-android-readelf -h ../output/openssl-1.0.1j/lib/libssl.a | grep Machine | uniq
  Machine:                           AArch64

これも AArch64 になっている!

ヘッダファイルも OUTPUT_DIR に出力されているので、
ライブラリを使う側で include するようにしましょう。

まとめ

各種コンパイルオプションの効能がいまだによくわかりませんが、
とりあえず動いているからヨシ!

これを取っ掛かりにして、最新バージョンのビルドを試みる所存。

こちらを参考にしました

https://github.com/cocochpie/android-openssl
https://github.com/leenjewel/openssl_for_ios_and_android

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6