diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index c72775788..0d82cab7e 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -33,7 +33,7 @@ jobs: # so we load the version the Gradle Plugin uses as default but which is # not installed anymore in the image - name: Install NDK - run: yes | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install 'ndk;21.4.7075529' + run: yes | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install 'ndk;23.1.7779620' - uses: actions/checkout@v3 - uses: actions/cache@v3 with: diff --git a/scripts/test.sh b/scripts/test.sh index 1ccd32beb..10d049355 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -110,13 +110,19 @@ build_openssl() echo "$ build_openssl()" - curl -L $SSL_SRC | tar xz -C $DEPS_BUILD_DIR && - cd $SSL_DIR && - ./config --prefix=$SSL_INS --openssldir=$SSL_INS --libdir=lib $SSL_OPT && - make -j4 >/dev/null && - sudo make install_sw >/dev/null && - sudo ldconfig || exit $? - cd - + curl -L $SSL_SRC | tar xz -C $DEPS_BUILD_DIR || exit $? + + if [ "$TEST" = "android" ]; then + OPENSSL_SRC=${SSL_DIR} \ + NO_DOCKER=1 src/frontends/android/openssl/build.sh || exit $? + else + cd $SSL_DIR && + ./config --prefix=$SSL_INS --openssldir=$SSL_INS --libdir=lib $SSL_OPT && + make -j4 >/dev/null && + sudo make install_sw >/dev/null && + sudo ldconfig || exit $? + cd - + fi } use_custom_openssl() @@ -308,9 +314,8 @@ win*) esac ;; android) - if test "$1" = "deps"; then - git clone https://github.com/strongswan/boringssl.git -b ndk-static \ - src/frontends/android/app/src/main/jni/openssl + if test "$1" = "build-deps"; then + build_openssl fi TARGET=distdir ;; diff --git a/src/frontends/android/app/build.gradle b/src/frontends/android/app/build.gradle index e181bb977..d67c53b6f 100644 --- a/src/frontends/android/app/build.gradle +++ b/src/frontends/android/app/build.gradle @@ -7,10 +7,10 @@ android { defaultConfig { applicationId "org.strongswan.android" - minSdkVersion 15 + minSdkVersion 21 targetSdkVersion 32 - versionCode 75 - versionName "2.3.3" + versionCode 77 + versionName "2.4.0" } sourceSets.main { diff --git a/src/frontends/android/app/src/main/jni/Android.mk b/src/frontends/android/app/src/main/jni/Android.mk index dcfe5f780..06cddaa77 100644 --- a/src/frontends/android/app/src/main/jni/Android.mk +++ b/src/frontends/android/app/src/main/jni/Android.mk @@ -5,9 +5,9 @@ include $(CLEAR_VARS) # MainActivity.java) strongswan_USE_BYOD := true -strongswan_CHARON_PLUGINS := android-log openssl fips-prf random nonce pubkey \ - chapoly curve25519 pkcs1 pkcs8 pem xcbc hmac kdf socket-default revocation \ - eap-identity eap-mschapv2 eap-md5 eap-gtc eap-tls x509 +strongswan_CHARON_PLUGINS := android-log socket-default openssl nonce \ + pkcs1 pem x509 xcbc kdf revocation \ + eap-identity eap-mschapv2 eap-md5 eap-gtc eap-tls ifneq ($(strongswan_USE_BYOD),) strongswan_BYOD_PLUGINS := eap-ttls eap-tnc tnc-imc tnc-tnccs tnccs-20 diff --git a/src/frontends/android/app/src/main/jni/Application.mk b/src/frontends/android/app/src/main/jni/Application.mk index 00a46d70e..2133d20c6 100644 --- a/src/frontends/android/app/src/main/jni/Application.mk +++ b/src/frontends/android/app/src/main/jni/Application.mk @@ -1 +1 @@ -APP_PLATFORM := android-19 +APP_PLATFORM := android-21 diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c b/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c index e81e22be7..89868a710 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c @@ -631,6 +631,27 @@ static void __attribute__ ((constructor))register_logger() dbg = dbg_android; } +/** + * Determine the application ID of the app + */ +static char *get_app_id(JNIEnv *env, jobject service) +{ + jclass cls; + jmethodID method_id; + jstring jstr; + char *name = NULL; + + cls = (*env)->FindClass(env, "android/content/Context"); + method_id = (*env)->GetMethodID(env, cls, "getPackageName", + "()Ljava/lang/String;"); + jstr = (*env)->CallObjectMethod(env, service, method_id); + if (jstr) + { + name = androidjni_convert_jstring(env, jstr); + } + return name; +} + /** * Initialize charon and the libraries via JNI */ @@ -639,7 +660,7 @@ JNI_METHOD(CharonVpnService, initializeCharon, jboolean, { struct sigaction action; struct utsname utsname; - char *logfile, *appdir, *plugins; + char *logfile, *appdir, *plugins, *app_id; /* initialize library */ if (!library_init(NULL, "charon")) @@ -685,10 +706,12 @@ JNI_METHOD(CharonVpnService, initializeCharon, jboolean, { memset(&utsname, 0, sizeof(utsname)); } + app_id = get_app_id(env, this); DBG1(DBG_DMN, "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"); DBG1(DBG_DMN, "Starting IKE service (strongSwan "VERSION", %s, %s, " - "%s %s, %s)", android_version_string, android_device_string, - utsname.sysname, utsname.release, utsname.machine); + "%s %s, %s, %s)", android_version_string, android_device_string, + utsname.sysname, utsname.release, utsname.machine, app_id ?: "(unknown)"); + free(app_id); #ifdef PLUGINS_BYOD if (byod) diff --git a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png index 2f56763dc..54d0923e9 100644 Binary files a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png and b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/1.png differ diff --git a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png index 6086fa6aa..5b0ab5469 100644 Binary files a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png and b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/2.png differ diff --git a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png index bb8029214..76e51e942 100644 Binary files a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png and b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/3.png differ diff --git a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/4.png b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/4.png new file mode 100644 index 000000000..37a289f4e Binary files /dev/null and b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/4.png differ diff --git a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/5.png b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/5.png new file mode 100644 index 000000000..88014f549 Binary files /dev/null and b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/5.png differ diff --git a/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/6.png b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/6.png new file mode 100644 index 000000000..f75755d4f Binary files /dev/null and b/src/frontends/android/app/src/main/play/listings/en-US/graphics/phone-screenshots/6.png differ diff --git a/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt b/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt index d25b162ea..5cfeafd75 100644 --- a/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt +++ b/src/frontends/android/app/src/main/play/release-notes/de-DE/default.txt @@ -1,11 +1,8 @@ -# 2.3.3 # +# 2.4.0 # -- Fügt einen Button zur Installation von Benutzer-Zertifikaten hinzu - -# 2.3.2 # - -- VPN Verbindungen nicht als getaktet markieren (der Default hat mit Android 10 als Ziel-SDK geändert) - -# 2.3.1 # - -- Optionale Verwendung von IPv6 Transport-Adressen für IKE und ESP. Benötigt Unterstützung für UDP Encapsulation für IPv6 auf dem Server (bei Linux erst seit 5.8 der Fall, viele Server bieten also noch keine Unterstützung) +- Wechsel von BoringSSL zu OpenSSL +- Unterstützung für folgende Algorithmen hinzugefügt: Curve448 ECDH, AES-CCM, Camellia (CBC/CTR/XCBC), SHA-3 (HMAC/PKCS#1) +- Problem behoben, welches File Descriptor Lecks beim Laden von OCSP/CRLs verursachte +- Verbesserte Übersetzung von vereinfachtem Chinesisch +- Ukrainische Übersetzung korrekt eingebunden +- Minimum SDK Version auf 21 (Android 5.0) erhöht diff --git a/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt b/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt index 971ef10dd..44958da2b 100644 --- a/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt +++ b/src/frontends/android/app/src/main/play/release-notes/en-US/default.txt @@ -1,11 +1,8 @@ -# 2.3.3 # +# 2.4.0 # -- Adds a button to install user certificates - -# 2.3.2 # - -- Don't mark VPN connections as metered (the default changed when targeting Android 10 with the last release) - -# 2.3.1 # - -- Optionally use IPv6 transport addresses for IKE and ESP. Can only be enabled if the server supports UDP encapsulation for IPv6 (the Linux kernel only supports this since 5.8, so many servers will not support it yet) +- Switched from BoringSSL to OpenSSL +- Added support for the following algorithms: Curve448 ECDH, AES-CCM, Camellia (CBC/CTR/XCBC), SHA-3 (HMAC/PKCS#1) +- Fixed an issue that caused file descriptor leaks when fetching OCSP/CRLs +- Improved translation for simplified Chinese +- Correctly included Ukrainian translation +- Increased minimum SDK version to 21 (Android 5.0) diff --git a/src/frontends/android/app/src/main/res/values-ua/arrays.xml b/src/frontends/android/app/src/main/res/values-uk/arrays.xml similarity index 100% rename from src/frontends/android/app/src/main/res/values-ua/arrays.xml rename to src/frontends/android/app/src/main/res/values-uk/arrays.xml diff --git a/src/frontends/android/app/src/main/res/values-ua/strings.xml b/src/frontends/android/app/src/main/res/values-uk/strings.xml similarity index 99% rename from src/frontends/android/app/src/main/res/values-ua/strings.xml rename to src/frontends/android/app/src/main/res/values-uk/strings.xml index 3c5bbebc9..e02a640a3 100644 --- a/src/frontends/android/app/src/main/res/values-ua/strings.xml +++ b/src/frontends/android/app/src/main/res/values-uk/strings.xml @@ -13,7 +13,7 @@ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. --> - + strongSwan VPN клієнт @@ -164,7 +164,7 @@ CRL cache Clear CRL cache? The CRL cache is empty - + The CRL cache contains %1$d file (%2$s). The CRL cache contains %1$d files (%2$s). @@ -213,7 +213,7 @@ This will disconnect the active VPN connection! Підключити Retry - + Retry in %1$d second Retry in %1$d seconds diff --git a/src/frontends/android/build.gradle b/src/frontends/android/build.gradle index f5acb1ef9..dc4fab06b 100644 --- a/src/frontends/android/build.gradle +++ b/src/frontends/android/build.gradle @@ -4,7 +4,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' + classpath 'com.android.tools.build:gradle:7.3.0' } } diff --git a/src/frontends/android/gradle/wrapper/gradle-wrapper.properties b/src/frontends/android/gradle/wrapper/gradle-wrapper.properties index 29c93626c..5cabee55d 100644 --- a/src/frontends/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/frontends/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/src/frontends/android/openssl/Dockerfile b/src/frontends/android/openssl/Dockerfile new file mode 100644 index 000000000..4b88928c1 --- /dev/null +++ b/src/frontends/android/openssl/Dockerfile @@ -0,0 +1,26 @@ +# Container for building OpenSSL's libcrypto for use in strongSwan's Android app +# +# Use the script to simplify the process of building the image and running +# the compilation in the container, e.g.: +# +# ANDROID_NDK_ROOT=~/android-ndk OPENSSL_SRC=~/openssl ./build.sh + +FROM debian:bullseye + +ARG packages="jq make perl" + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -qq -y \ + --no-install-recommends \ + $packages \ + && rm -rf /var/lib/apt/lists/* + +COPY compile.sh / +RUN chmod +x /compile.sh + +ENV ANDROID_NDK_ROOT /ndk +ENV OUT_DIR /out + +WORKDIR /src + +ENTRYPOINT ["/compile.sh"] diff --git a/src/frontends/android/openssl/build.sh b/src/frontends/android/openssl/build.sh new file mode 100755 index 000000000..fc541efb9 --- /dev/null +++ b/src/frontends/android/openssl/build.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# +# Build OpenSSL's libcrypto for use in strongSwan's Android app. Requires +# passing the path to the Android NDK as well as that to the OpenSSL sources, +# for instance: +# +# ANDROID_NDK_ROOT=~/android-ndk OPENSSL_SRC=~/openssl ./build.sh +# +# The files are written to the jni/openssl directory of the app, by default, but +# that can be changed via $OUT variable. +# +# Setting $NO_DOCKER disables the use of Docker (requires the necessary build +# tools on the system), otherwise, setting $TAG allows using a custom tag for +# the Docker image. +# + +set -e + +if [ -z "${ANDROID_NDK_ROOT}" ]; then + echo "ANDROID_NDK_ROOT is not set" + exit 1 +elif [ ! -d "${ANDROID_NDK_ROOT}" ]; then + echo "ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT} is not a directory" + exit 1 +fi + +if [ -z "${OPENSSL_SRC}" ]; then + echo "OPENSSL_SRC is not set" + exit 1 +elif [ ! -d "${OPENSSL_SRC}" ]; then + echo "OPENSSL_SRC=${OPENSSL_SRC} is not a directory" + exit 1 +fi + +: ${TAG=strongswan-android-openssl-builder} + +DIR=$(dirname `readlink -f $0`) +: ${OUT=$DIR/../app/src/main/jni/openssl} +mkdir -p $OUT + +if [ -z "${NO_DOCKER}" ]; then + docker build -t ${TAG} ${DIR} + docker run --rm -ti \ + -u $(id -u ${USER}):$(id -g ${USER}) \ + -v ${ANDROID_NDK_ROOT}:/ndk \ + -v ${OPENSSL_SRC}:/src \ + -v ${OUT}:/out \ + ${TAG} +else + pushd $OPENSSL_SRC + OUT_DIR=${OUT} $DIR/compile.sh + popd +fi + +if [ ! -f "${OUT}/Android.mk" ]; then + echo "## Creating Android.mk for OpenSSL's libcrypto" + cat << EOF > ${OUT}/Android.mk +LOCAL_PATH := \$(call my-dir) +include \$(CLEAR_VARS) +LOCAL_MODULE := libcrypto_static +LOCAL_SRC_FILES := \$(TARGET_ARCH_ABI)/libcrypto.a +LOCAL_EXPORT_C_INCLUDES := \$(LOCAL_PATH)/include +include \$(PREBUILT_STATIC_LIBRARY) +EOF +fi diff --git a/src/frontends/android/openssl/compile.sh b/src/frontends/android/openssl/compile.sh new file mode 100755 index 000000000..81463b903 --- /dev/null +++ b/src/frontends/android/openssl/compile.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# Compile static versions of OpenSSL's libcrypto for use with strongSwan's +# Android app. +# +# Copies archives and header files to $OUT_DIR. + +set -e + +export PATH=${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH +# necessary for OpenSSL 1.1.1 +export ANDROID_NDK_HOME=${ANDROID_NDK_ROOT} + +# automatically determine the ABIs supported by the NDK +: ${ABIS=$(jq -r 'keys | join(" ")' ${ANDROID_NDK_ROOT}/meta/abis.json)} + +# this should match APP_PLATFORM +: ${MIN_SDK=21} + +for ABI in ${ABIS} +do + +echo "## Building OpenSSL's libcrypto for ${ABI}" + +case ${ABI} in +armeabi-v7a) + OPTIONS="android-arm" + ;; +arm64-v8a) + OPTIONS="android-arm64" + ;; +x86) + OPTIONS="android-x86" + ;; +x86_64) + OPTIONS="android-x86_64" + ;; +esac + +OPTIONS="${OPTIONS} \ + no-shared no-ct no-cast no-comp no-dgram no-dsa no-gost no-idea \ + no-rmd160 no-seed no-sm2 no-sm3 no-sm4 no-sock no-srp no-srtp \ + no-asm no-err no-engine no-dso no-hw no-stdio no-ui-console \ + -fPIC -DOPENSSL_PIC \ + -ffast-math -O3 -funroll-loops -Wno-macro-redefined \ + -D__ANDROID_API__=${MIN_SDK} \ + " + +make distclean >/dev/null || true + +./Configure ${OPTIONS} +make -j $(nproc) build_generated >/dev/null +make -j $(nproc) libcrypto.a >/dev/null + +mkdir -p ${OUT_DIR}/${ABI} +cp libcrypto.a ${OUT_DIR}/${ABI} + +done + +# The only difference between ABIs is the config header (e.g. configuration.h +# for OpenSSL 3.0), which does define the size of BN_ULONG in bn.h. +# However, the only function we use that depends on it is BN_set_word() when +# generating RSA private keys, which isn't used in the Android app. +cp -R include/ ${OUT_DIR}