Android: Switch to BearSSL

This commit is contained in:
UnknownShadow200 2025-07-03 22:38:09 +10:00
parent 9b55b3a958
commit a7705d16e5
7 changed files with 263 additions and 48 deletions

View File

@ -36,33 +36,32 @@ jobs:
env:
COMMON_FLAGS: "-O1 -s -fno-stack-protector -fno-math-errno -Qn -Werror"
DROID_FLAGS: "-fPIC -shared -fvisibility=hidden -rdynamic -funwind-tables"
DROID_LIBS: "-lGLESv2 -lEGL -lm -landroid -llog"
LIBS: "-lGLESv2 -lEGL -lm -landroid -llog"
SRCS: "src/*.c third_party/bearssl/src/*.c"
run: |
LATEST_FLAG=-DCC_COMMIT_SHA=\"${GITHUB_SHA::9}\"
DROID_FLAGS="-fPIC -shared -s -O1 -fvisibility=hidden -rdynamic -funwind-tables"
DROID_LIBS="-lGLESv2 -lEGL -lm -landroid -llog"
ROOT_DIR=$PWD
NDK_ROOT="/opt/android-sdk-linux/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin"
TOOLS_ROOT=$ROOT_DIR/build-tools
SDK_ROOT="/opt/android-sdk-linux/platforms/android-34"
cd $ROOT_DIR/src
$NDK_ROOT/armv7a-linux-androideabi19-clang *.c $COMMON_FLAGS $DROID_FLAGS -march=armv5 -rtlib=libgcc -L $ROOT_DIR/build-tools/runtime $DROID_LIBS $LATEST_FLAG -o cc-droid-arm_16
$NDK_ROOT/armv7a-linux-androideabi19-clang *.c $COMMON_FLAGS $DROID_FLAGS $DROID_LIBS $LATEST_FLAG -o cc-droid-arm_32
$NDK_ROOT/aarch64-linux-android21-clang *.c $COMMON_FLAGS $DROID_FLAGS $DROID_LIBS $LATEST_FLAG -o cc-droid-arm_64
$NDK_ROOT/i686-linux-android21-clang *.c $COMMON_FLAGS $DROID_FLAGS $DROID_LIBS $LATEST_FLAG -o cc-droid-x86_32
$NDK_ROOT/x86_64-linux-android21-clang *.c $COMMON_FLAGS $DROID_FLAGS $DROID_LIBS $LATEST_FLAG -o cc-droid-x86_64
$NDK_ROOT/armv7a-linux-androideabi19-clang ${{ env.SRCS }} $COMMON_FLAGS $DROID_FLAGS -march=armv5 -rtlib=libgcc -L $ROOT_DIR/build-tools/runtime ${{ env.LIBS }} $LATEST_FLAG -o cc-droid-arm_16
$NDK_ROOT/armv7a-linux-androideabi19-clang ${{ env.SRCS }} $COMMON_FLAGS $DROID_FLAGS ${{ env.LIBS }} $LATEST_FLAG -o cc-droid-arm_32
$NDK_ROOT/aarch64-linux-android21-clang ${{ env.SRCS }} $COMMON_FLAGS $DROID_FLAGS ${{ env.LIBS }} $LATEST_FLAG -o cc-droid-arm_64
$NDK_ROOT/i686-linux-android21-clang ${{ env.SRCS }} $COMMON_FLAGS $DROID_FLAGS ${{ env.LIBS }} $LATEST_FLAG -o cc-droid-x86_32
$NDK_ROOT/x86_64-linux-android21-clang ${{ env.SRCS }} $COMMON_FLAGS $DROID_FLAGS ${{ env.LIBS }} $LATEST_FLAG -o cc-droid-x86_64
cd $ROOT_DIR/android/app/src/main
# copy required native libraries
mkdir lib lib/armeabi lib/armeabi-v7a lib/arm64-v8a lib/x86 lib/x86_64
cp $ROOT_DIR/src/cc-droid-arm_16 lib/armeabi/libclassicube.so
cp $ROOT_DIR/src/cc-droid-arm_32 lib/armeabi-v7a/libclassicube.so
cp $ROOT_DIR/src/cc-droid-arm_64 lib/arm64-v8a/libclassicube.so
cp $ROOT_DIR/src/cc-droid-x86_32 lib/x86/libclassicube.so
cp $ROOT_DIR/src/cc-droid-x86_64 lib/x86_64/libclassicube.so
cp $ROOT_DIR/cc-droid-arm_16 lib/armeabi/libclassicube.so
cp $ROOT_DIR/cc-droid-arm_32 lib/armeabi-v7a/libclassicube.so
cp $ROOT_DIR/cc-droid-arm_64 lib/arm64-v8a/libclassicube.so
cp $ROOT_DIR/cc-droid-x86_32 lib/x86/libclassicube.so
cp $ROOT_DIR/cc-droid-x86_64 lib/x86_64/libclassicube.so
# The following commands are for manually building an .apk, see
# https://spin.atomicobject.com/2011/08/22/building-android-application-bundles-apks-by-hand/

1
.gitignore vendored
View File

@ -11,6 +11,7 @@
*.VC.VC.opendb
# Android build results
android/app/.cxx/
android/.cxx/
android/.idea/
android/.gradle/

View File

@ -22,7 +22,6 @@ set(${CMAKE_C_FLAGS}, "${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -Werror")
add_library(classicube SHARED
../../src/main.c
../../src/IsometricDrawer.c
../../src/Builder.c
../../src/ExtMath.c
@ -107,9 +106,130 @@ add_library(classicube SHARED
../../src/MenuOptions.c
../../src/FancyLighting.c
../../src/Queue.c
../../src/SSL.c
../../src/Certs.c
../../third_party/bearssl/src/aes_big_cbcdec.c
../../third_party/bearssl/src/aes_big_cbcenc.c
../../third_party/bearssl/src/aes_big_ctr.c
../../third_party/bearssl/src/aes_big_ctrcbc.c
../../third_party/bearssl/src/aes_big_dec.c
../../third_party/bearssl/src/aes_big_enc.c
../../third_party/bearssl/src/aes_common.c
../../third_party/bearssl/src/aesctr_drbg.c
../../third_party/bearssl/src/aes_x86ni.c
../../third_party/bearssl/src/aes_x86ni_cbcdec.c
../../third_party/bearssl/src/aes_x86ni_cbcenc.c
../../third_party/bearssl/src/aes_x86ni_ctr.c
../../third_party/bearssl/src/aes_x86ni_ctrcbc.c
../../third_party/bearssl/src/asn1enc.c
../../third_party/bearssl/src/ccm.c
../../third_party/bearssl/src/ccopy.c
../../third_party/bearssl/src/chacha20_ct.c
../../third_party/bearssl/src/chacha20_sse2.c
../../third_party/bearssl/src/dec32be.c
../../third_party/bearssl/src/dec32le.c
../../third_party/bearssl/src/dec64be.c
../../third_party/bearssl/src/dec64le.c
../../third_party/bearssl/src/dig_oid.c
../../third_party/bearssl/src/dig_size.c
../../third_party/bearssl/src/ec_all_m31.c
../../third_party/bearssl/src/ec_c25519_i31.c
../../third_party/bearssl/src/ec_c25519_m31.c
../../third_party/bearssl/src/ec_c25519_m62.c
../../third_party/bearssl/src/ec_c25519_m64.c
../../third_party/bearssl/src/ec_curve25519.c
../../third_party/bearssl/src/ec_default.c
../../third_party/bearssl/src/ecdsa_atr.c
../../third_party/bearssl/src/ecdsa_default_vrfy_asn1.c
../../third_party/bearssl/src/ecdsa_default_vrfy_raw.c
../../third_party/bearssl/src/ecdsa_i31_bits.c
../../third_party/bearssl/src/ecdsa_i31_vrfy_asn1.c
../../third_party/bearssl/src/ecdsa_i31_vrfy_raw.c
../../third_party/bearssl/src/ec_p256_m31.c
../../third_party/bearssl/src/ec_p256_m62.c
../../third_party/bearssl/src/ec_p256_m64.c
../../third_party/bearssl/src/ec_prime_i31.c
../../third_party/bearssl/src/ec_secp256r1.c
../../third_party/bearssl/src/ec_secp384r1.c
../../third_party/bearssl/src/ec_secp521r1.c
../../third_party/bearssl/src/enc32be.c
../../third_party/bearssl/src/enc32le.c
../../third_party/bearssl/src/enc64be.c
../../third_party/bearssl/src/enc64le.c
../../third_party/bearssl/src/gcm.c
../../third_party/bearssl/src/ghash_ctmul64.c
../../third_party/bearssl/src/ghash_ctmul.c
../../third_party/bearssl/src/ghash_pclmul.c
../../third_party/bearssl/src/hmac.c
../../third_party/bearssl/src/hmac_ct.c
../../third_party/bearssl/src/hmac_drbg.c
../../third_party/bearssl/src/i31_add.c
../../third_party/bearssl/src/i31_bitlen.c
../../third_party/bearssl/src/i31_decmod.c
../../third_party/bearssl/src/i31_decode.c
../../third_party/bearssl/src/i31_decred.c
../../third_party/bearssl/src/i31_encode.c
../../third_party/bearssl/src/i31_fmont.c
../../third_party/bearssl/src/i31_iszero.c
../../third_party/bearssl/src/i31_moddiv.c
../../third_party/bearssl/src/i31_modpow2.c
../../third_party/bearssl/src/i31_modpow.c
../../third_party/bearssl/src/i31_montmul.c
../../third_party/bearssl/src/i31_mulacc.c
../../third_party/bearssl/src/i31_muladd.c
../../third_party/bearssl/src/i31_ninv31.c
../../third_party/bearssl/src/i31_reduce.c
../../third_party/bearssl/src/i31_rshift.c
../../third_party/bearssl/src/i31_sub.c
../../third_party/bearssl/src/i31_tmont.c
../../third_party/bearssl/src/i32_div32.c
../../third_party/bearssl/src/i62_modpow2.c
../../third_party/bearssl/src/md5.c
../../third_party/bearssl/src/md5sha1.c
../../third_party/bearssl/src/multihash.c
../../third_party/bearssl/src/poly1305_ctmul.c
../../third_party/bearssl/src/poly1305_ctmulq.c
../../third_party/bearssl/src/prf.c
../../third_party/bearssl/src/prf_md5sha1.c
../../third_party/bearssl/src/prf_sha256.c
../../third_party/bearssl/src/prf_sha384.c
../../third_party/bearssl/src/rsa_default_pkcs1_vrfy.c
../../third_party/bearssl/src/rsa_default_priv.c
../../third_party/bearssl/src/rsa_default_pub.c
../../third_party/bearssl/src/rsa_i31_pkcs1_vrfy.c
../../third_party/bearssl/src/rsa_i31_priv.c
../../third_party/bearssl/src/rsa_i31_pub.c
../../third_party/bearssl/src/rsa_i62_pkcs1_vrfy.c
../../third_party/bearssl/src/rsa_i62_priv.c
../../third_party/bearssl/src/rsa_i62_pub.c
../../third_party/bearssl/src/rsa_pkcs1_sig_unpad.c
../../third_party/bearssl/src/sha1.c
../../third_party/bearssl/src/sha2big.c
../../third_party/bearssl/src/sha2small.c
../../third_party/bearssl/src/ssl_client.c
../../third_party/bearssl/src/ssl_client_default_rsapub.c
../../third_party/bearssl/src/ssl_client_full.c
../../third_party/bearssl/src/ssl_engine.c
../../third_party/bearssl/src/ssl_engine_default_aescbc.c
../../third_party/bearssl/src/ssl_engine_default_aesccm.c
../../third_party/bearssl/src/ssl_engine_default_aesgcm.c
../../third_party/bearssl/src/ssl_engine_default_chapol.c
../../third_party/bearssl/src/ssl_engine_default_ec.c
../../third_party/bearssl/src/ssl_engine_default_ecdsa.c
../../third_party/bearssl/src/ssl_engine_default_rsavrfy.c
../../third_party/bearssl/src/ssl_hashes.c
../../third_party/bearssl/src/ssl_hs_client.c
../../third_party/bearssl/src/ssl_io.c
../../third_party/bearssl/src/ssl_rec_cbc.c
../../third_party/bearssl/src/ssl_rec_ccm.c
../../third_party/bearssl/src/ssl_rec_chapol.c
../../third_party/bearssl/src/ssl_rec_gcm.c
../../third_party/bearssl/src/x509_minimal.c
../../third_party/bearssl/src/x509_minimal_full.c
)
# add lib dependencies
target_include_directories(classicube PRIVATE
../../third_party/bearssl/inc)
target_link_libraries(classicube
android
EGL

View File

@ -1,14 +1,16 @@
package com.classicube;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
@ -28,25 +30,23 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.provider.Settings.Secure;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.View;
import android.view.Window;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
// This class contains all the glue/interop code for bridging ClassiCube to the java Android world.
// Some functionality is only available on later Android versions - try {} catch {} is used in such places
// to ensure that the game can still run on earlier Android versions (albeit with reduced functionality)
@ -1016,4 +1016,68 @@ public class MainActivity extends Activity
native static void httpParseHeader(String header);
native static void httpAppendData(byte[] data, int len);
// ======================================================================
// -------------------------------- SSL ---------------------------------
// ======================================================================
static X509TrustManager trust;
static CertificateFactory certFactory;
static ArrayList<X509Certificate> chain = new ArrayList<X509Certificate>();
static X509TrustManager CreateTrust() throws Exception {
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// Load default Trust Anchor certificates
factory.init((KeyStore)null);
TrustManager[] trustManagers = factory.getTrustManagers();
for (int i = 0; i < trustManagers.length; i++)
{
// Should be first entry, e.g. X509TrustManagerImpl
if (trustManagers[i] instanceof X509TrustManager)
return (X509TrustManager)trustManagers[i];
}
return null;
}
public static int sslCreateTrust() {
try {
trust = CreateTrust();
return 1;
} catch (Exception ex) {
ex.printStackTrace();
return 0;
}
}
public static void sslAddCert(byte[] data) {
try {
if (certFactory == null) certFactory = CertificateFactory.getInstance("X.509");
if (certFactory == null) return;
InputStream in = new ByteArrayInputStream(data);
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
chain.add(cert);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static int sslVerifyChain() {
int result = -200;
try {
X509Certificate[] certs = new X509Certificate[chain.size()];
for (int i = 0; i < chain.size(); i++) certs[i] = chain.get(i);
trust.checkServerTrusted(certs, "INV");
// standard java checks auth type, but android doesn't
// See https://issues.chromium.org/issues/40955801
result = 0;
} catch (Exception ex) {
ex.printStackTrace();
}
chain.clear();
return result;
}
}

View File

@ -1,8 +1,7 @@
#include "Certs.h"
#ifndef CC_CRT_BACKEND
#include "Errors.h"
#ifndef CC_CRT_BACKEND
void CertsBackend_Init(void) { }
void Certs_BeginChain(struct X509CertContext* ctx) { }
@ -57,7 +56,6 @@ void Certs_FreeChain( struct X509CertContext* ctx) {
}
#if CC_CRT_BACKEND == CC_CRT_BACKEND_OPENSSL
#include "Errors.h"
#include "Funcs.h"
/* === BEGIN OPENSSL HEADERS === */
typedef struct X509_ X509;
@ -104,20 +102,13 @@ static cc_bool ossl_loaded;
void CertsBackend_Init(void) {
static const struct DynamicLibSym funcs[] = {
DynamicLib_ReqSym(OPENSSL_sk_new_null),
DynamicLib_ReqSym(OPENSSL_sk_push),
DynamicLib_ReqSym(OPENSSL_sk_pop_free),
DynamicLib_ReqSym(d2i_X509),
DynamicLib_ReqSym(X509_new),
DynamicLib_ReqSym(X509_free),
DynamicLib_ReqSym(X509_STORE_new),
DynamicLib_ReqSym(X509_STORE_set_default_paths),
DynamicLib_ReqSym(X509_STORE_CTX_new),
DynamicLib_ReqSym(X509_STORE_CTX_free),
DynamicLib_ReqSym(X509_STORE_CTX_get_error),
DynamicLib_ReqSym(X509_STORE_CTX_init),
DynamicLib_ReqSym(X509_verify_cert),
DynamicLib_ReqSym(X509_verify_cert_error_string),
DynamicLib_ReqSym(d2i_X509), DynamicLib_ReqSym(OPENSSL_sk_new_null),
DynamicLib_ReqSym(OPENSSL_sk_push), DynamicLib_ReqSym(OPENSSL_sk_pop_free),
DynamicLib_ReqSym(X509_new), DynamicLib_ReqSym(X509_free),
DynamicLib_ReqSym(X509_STORE_new), DynamicLib_ReqSym(X509_STORE_set_default_paths),
DynamicLib_ReqSym(X509_STORE_CTX_new), DynamicLib_ReqSym(X509_STORE_CTX_free),
DynamicLib_ReqSym(X509_STORE_CTX_init), DynamicLib_ReqSym(X509_STORE_CTX_get_error),
DynamicLib_ReqSym(X509_verify_cert), DynamicLib_ReqSym(X509_verify_cert_error_string),
};
void* lib;
@ -148,7 +139,6 @@ int Certs_VerifyChain(struct X509CertContext* chain) {
_X509_STORE_set_default_paths(store);
}
if (!chain->numCerts) return ERR_INVALID_ARGUMENT;
/* End/Leaf certificate */
cert = ToOpenSSLCert(&chain->certs[0]);
@ -190,7 +180,6 @@ int Certs_VerifyChain(struct X509CertContext* chain) {
#include <Security/SecPolicySearch.h>
#include <Security/oidsalg.h>
#endif
#include "Errors.h"
void CertsBackend_Init(void) {
@ -248,8 +237,6 @@ int Certs_VerifyChain(struct X509CertContext* x509) {
if (!policy) CreateX509Policy();
if (!policy) return ERR_OUT_OF_MEMORY;
if (!x509->numCerts) return ERR_NOT_SUPPORTED;
chain = CFArrayCreateMutable(NULL, x509->numCerts, &kCFTypeArrayCallBacks);
if (!chain) return ERR_OUT_OF_MEMORY;
@ -269,6 +256,38 @@ int Certs_VerifyChain(struct X509CertContext* x509) {
CFRelease(chain);
return res;
}
#elif CC_CRT_BACKEND == CC_CRT_BACKEND_ANDROID
static jmethodID JAVA_sslCreateTrust, JAVA_sslAddCert, JAVA_sslVerifyChain;
static int created_trust;
void CertsBackend_Init(void) {
JNIEnv* env;
JavaGetCurrentEnv(env);
JAVA_sslCreateTrust = JavaGetSMethod(env, "sslCreateTrust", "()I");
JAVA_sslAddCert = JavaGetSMethod(env, "sslAddCert", "([B)V");
JAVA_sslVerifyChain = JavaGetSMethod(env, "sslVerifyChain", "()I");
}
int Certs_VerifyChain(struct X509CertContext* x509) {
JNIEnv* env;
jvalue args[1];
int i;
JavaGetCurrentEnv(env);
if (!created_trust) created_trust = JavaSCall_Int(env, JAVA_sslCreateTrust, NULL);
if (!created_trust) return ERR_NOT_SUPPORTED;
for (i = 0; i < x509->numCerts; i++)
{
struct X509Cert* cert = &x509->certs[i];
args[0].l = JavaMakeBytes(env, cert->data, cert->offset);
JavaSCall_Void(env, JAVA_sslAddCert, args);
(*env)->DeleteLocalRef(env, args[0].l);
}
return JavaSCall_Int(env, JAVA_sslVerifyChain, NULL);
}
#endif
#endif

View File

@ -156,6 +156,7 @@ typedef cc_uint8 cc_bool;
#define CC_CRT_BACKEND_OPENSSL 1
#define CC_CRT_BACKEND_APPLESEC 2
#define CC_CRT_BACKEND_ANDROID 3
#define CC_AUD_BACKEND_OPENAL 1
#define CC_AUD_BACKEND_WINMM 2
@ -227,6 +228,9 @@ typedef cc_uint8 cc_bool;
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENSLES
#define DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL2
#define DEFAULT_WIN_BACKEND CC_WIN_BACKEND_ANDROID
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL
#define DEFAULT_CRT_BACKEND CC_CRT_BACKEND_ANDROID
#elif defined __serenity__
#define CC_BUILD_SERENITY
#define CC_BUILD_POSIX

View File

@ -470,14 +470,22 @@ static unsigned x509_maybe_skip_verify(unsigned r) {
return r;
}
static unsigned x509_maybe_system_verify(struct SSLContext* ssl, unsigned r) {
/* Only fallback to system verification for potentially untrusted certificate case */
/* This ensures consistent validation behaviour in other cases between all platforms */
if (r != BR_ERR_X509_NOT_TRUSTED) return r;
if (!ssl->x509.numCerts) return r;
if (Certs_VerifyChain(&ssl->x509) == 0) r = 0;
return r;
}
static unsigned x509_end_chain(const br_x509_class** ctx) {
struct SSLContext* ssl = (struct SSLContext*)ctx;
unsigned r = br_x509_minimal_vtable.end_chain(ctx);
r = x509_maybe_skip_verify(r);
/* Fallback to system specific certificate validation */
if (r == BR_ERR_X509_NOT_TRUSTED && Certs_VerifyChain(&ssl->x509) == 0) r = 0;
r = x509_maybe_system_verify(ssl, r);
Certs_FreeChain(&ssl->x509);
return r;