From b1c88db1ce72e11ba44add0f481b6786c4ce17d2 Mon Sep 17 00:00:00 2001
From: Claudia <claui@users.noreply.github.com>
Date: Mon, 4 Sep 2023 15:36:25 +0200
Subject: [PATCH] Feature: install self-signed cacert to trust store
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

For analysis and reverse engineering, it can be helpful to insert a
custom CA certificate into Waydroid’s system-wide trust store.
Users used to be able to do that via Android’s settings but not anymore.

The `install mitm` command accepts a path to a file that contains a
– typically self-signed – CA certificate in PEM format.
It then renames [1] and copies the file into the overlay file system,
placing it into Waydroid’s trust store.

As a usage example, the following command lines enable your host to use
mitmproxy [2] to act as a proxy and to intercept [3] HTTP(S) connections
that come from the Waydroid container:

```sh
$ timeout --preserve-status 2 mitmdump -n                           # creates a CA cert in ~/.mitmproxy
$ sudo venv/bin/python3 main.py install mitm --ca-cert ~/.mitmproxy/mitmproxy-ca-cert.pem
INFO: Creating directory: /system/etc/security/cacerts
INFO: Copying /home/yourname/.mitmproxy/mitmproxy-ca-cert.pem to system trust store
INFO: Target file: /system/etc/security/cacerts/6320a7db.0
INFO: mitm installation finished
$ sudo waydroid shell -- ls -l /system/etc/security/cacerts         # double-check that it worked
[…]
-rw-r--r-- 1 root root 1191 2024-01-01 00:00 6320a7db.0
[…]
$ adb shell settings put global http_proxy ${YOUR_IP_HERE?}:3128    # tell Waydroid to use the proxy
                                                                    #     for all connections
$ mitmproxy -p 3128                                                 # start proxy and display a TUI
                                                                    #     with HTTP(S) connections
                                                                    #     coming from Waydroid
```

[1]: https://docs.mitmproxy.org/stable/howto-install-system-trusted-ca-android/#2-rename-certificate

[2]: https://mitmproxy.org/

[3]: https://docs.mitmproxy.org/stable/mitmproxytutorial-interceptrequests/
---
 README.md     |  8 +++++++-
 main.py       | 14 ++++++++++++--
 stuff/mitm.py | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 59 insertions(+), 3 deletions(-)
 create mode 100644 stuff/mitm.py

diff --git a/README.md b/README.md
index 9d586de..7795c7f 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ cd waydroid_script
 python3 -m venv venv
 venv/bin/pip install -r requirements.txt
 # install something
-sudo venv/bin/python3 main.py install {gapps, magisk, libndk, libhoudini, nodataperm, smartdock, microg}
+sudo venv/bin/python3 main.py install {gapps, magisk, libndk, libhoudini, nodataperm, smartdock, microg, mitm}
 # uninstall something
 sudo venv/bin/python3 main.py uninstall {gapps, magisk, libndk, libhoudini, nodataperm, smartdock, microg}
 # get Android device ID
@@ -122,6 +122,12 @@ Open terminal and switch to directory where "main.py" is located then run:
 
     sudo venv/bin/python3 main.py install smartdock
 
+## Install a self-signed CA certificate
+
+Open terminal and switch to directory where "main.py" is located then run:
+
+    sudo venv/bin/python3 main.py install mitm --ca-cert mycert.pem
+
 ## Granting full permission for apps data (HACK)
 
 
diff --git a/main.py b/main.py
index 79889fe..af90935 100755
--- a/main.py
+++ b/main.py
@@ -12,6 +12,7 @@ from stuff.hidestatusbar import HideStatusBar
 from stuff.houdini import Houdini
 from stuff.magisk import Magisk
 from stuff.microg import MicroG
+from stuff.mitm import Mitm
 from stuff.ndk import Ndk
 from stuff.nodataperm import Nodataperm
 from stuff.smartdock import Smartdock
@@ -83,6 +84,8 @@ def install_app(args):
         install_list.append(Smartdock())
     if "microg" in app:
         install_list.append(MicroG(args.android_version, args.microg_variant))
+    if "mitm" in app:
+        install_list.append(Mitm(args.ca_cert_file))
 
     if not container.use_overlayfs():
         copy_dir = "/tmp/waydroid"
@@ -130,6 +133,8 @@ def remove_app(args):
         remove_list.append(Smartdock())
     if "microg" in app:
         remove_list.append(MicroG(args.android_version, args.microg_variant))
+    if "mitm" in app:
+        remove_list.append(Mitm())
     if "nodataperm" in app:
         remove_list.append(Nodataperm(args.android_version))
     if "hidestatusbar" in app:
@@ -286,8 +291,8 @@ def main():
         'certified', help='Get device ID to obtain Play Store certification')
     certified.set_defaults(func=get_certified)
 
-    install_choices = ["gapps", "microg", "libndk",
-                       "libhoudini", "magisk", "smartdock", "widevine"]
+    install_choices = ["gapps", "microg", "libndk", "libhoudini",
+                       "magisk", "mitm", "smartdock", "widevine"]
     hack_choices = ["nodataperm", "hidestatusbar"]
     micrg_variants = ["Standard", "NoGoolag", "UNLP", "Minimal", "MinimalIAP"]
     remove_choices = install_choices
@@ -305,6 +310,7 @@ microg: Add microG, Aurora Store and Aurora Droid to WayDriod
 libndk: Add libndk arm translation, better for AMD CPUs
 libhoudini: Add libhoudini arm translation, better for Intel CPUs
 magisk: Install Magisk Delta to WayDroid
+mitm -c CA_CERT_FILE: Install root CA cert into system trust store
 smartdock: A desktop mode launcher for Android
 widevine: Add support for widevine DRM L3
     """
@@ -313,6 +319,10 @@ widevine: Add support for widevine DRM L3
         'install', formatter_class=argparse.RawTextHelpFormatter, help='Install an app')
     install_parser.add_argument(
         **arg_template, choices=install_choices, help=install_help)
+    install_parser.add_argument('-c', '--ca-cert',
+                                dest='ca_cert_file',
+                                help='[for mitm only] The CA certificate file (*.pem) to install',
+                                default=None)
     install_parser.set_defaults(func=install_app)
 
     # remove and its aliases
diff --git a/stuff/mitm.py b/stuff/mitm.py
new file mode 100644
index 0000000..8468a9a
--- /dev/null
+++ b/stuff/mitm.py
@@ -0,0 +1,40 @@
+import os
+import shutil
+from stuff.general import General
+from tools.helper import run
+from tools.logger import Logger
+
+class Mitm(General):
+    id = "mitm"
+    partition = "system"
+
+    def __init__(self, ca_cert_file: str=None) -> None:
+        super().__init__()
+        self.ca_cert_file = ca_cert_file
+
+    def download(self):
+        pass
+
+    def skip_extract(self):
+        return True
+
+    def copy(self):
+        file_hash = run([
+            'openssl', 'x509', '-noout', '-subject_hash_old', '-in',
+            self.ca_cert_file,
+        ]).stdout.decode("ascii").strip()
+        target_dir = os.path.join(
+            self.copy_dir, self.partition, "etc", "security", "cacerts")
+        Logger.info(f"Creating directory: {target_dir}")
+        os.makedirs(target_dir, exist_ok=True)
+        target_path = os.path.join(target_dir, f'{file_hash}.0')
+        Logger.info(f"Copying {self.ca_cert_file} to system trust store")
+        Logger.info(f"Target file: {target_path}")
+        shutil.copyfile(self.ca_cert_file, target_path)
+        os.chmod(target_path, 0o644)
+
+    def install(self):
+        if not self.ca_cert_file:
+            raise ValueError(
+                "This command requires the --ca-cert switch and a *.pem file")
+        super().install()