== Context == In Replicant we don't have any infrastructure nor procedure to handle long term secret key storage, and when building an image, some keys are generated. These keys are then used to sign various Android system applications that are built as part of the image, such as the dialer, the launcher, etc. So when a new release is built, new keys are generated. This creates an issue because the data of a given application is tied to the application signing key. So when the signing key changes, the applications cannot access its data anymore. == How to solve the issue == In the android_vendor_cm repository[1] from LineageOS, there is the following commit: 2f7c7decc4cd5b42f044a7841a74468e4cacd694 2f7c7decc (refs/changes/27/156327/3) Add startup script to update the package signatures It fixes that issue with a shell script (key-migration.sh) that runs at startup and removes the offending keys in /data/system/packages.xml, and makes sure not to run again when done. Removing the keys didn't work for us, however slightly modifying the script to replace them instead worked fine. As the keys were hardcoded in the key-migration.sh script, and that we keep changing keys at each new release, it makes sense to have a more automatic process that generates the key-migration.sh script from the packages.xml file. This is what the generate_key_migration_script.py does. References: ----------- [1]https://github.com/LineageOS/android_vendor_cm/ == Usage == To use this script: - You need the public part of all the old certificates you want to migrate from. - You also need the public part of the new certificates you want to migrate to. Certificates to use with this tool can be found in several places: - The public part of all the certificates used for official releases are published as part of the Replicant releases. Some older releases don't have certificates as they didn't use them. The releases certificates are also available in distros/releases/certificates in the vendor_replicant-data git repository[1] for convenience. If you have the Replicant 6.0 source code, they are located in vendor/replicant-data/distros/releases/certificates/. - The new certificates are generated as part of the build procedure and are available in vendor/replicant-security/*x509.pem in the replicant source code directory. - Certificates are also available in encoded form in data/system/packages.xml, however they would need to be extracted from this file and put in a dedicated directory to be able to be used by this script. The certificates need to be in a dedicated directory as the script expect that. For instance, if we have the following directory structure: $ ls vendor/replicant-security/*x509.pem vendor/replicant-security/media.x509.pem vendor/replicant-security/releasekey.x509.pem vendor/replicant-security/platform.x509.pem vendor/replicant-security/shared.x509.pem The tool will expect us to pass it the vendor/replicant-security/ argument. For the older release we can also have a directory that contains subdirectories that in turn contains the certificates. This way we can have one directory for each Replicant releases with the releases certificates inside. The tool will then use the directory names as releases names in the generated script. For instance if we have the following structure: $ cd vendor/replicant-data/distros/ $ ls releases/certificates/*/*.x509.pem releases/certificates/replicant-4.2-0001/media.x509.pem releases/certificates/replicant-4.2-0001/platform.x509.pem releases/certificates/replicant-4.2-0001/shared.x509.pem releases/certificates/replicant-4.2-0001/system.x509.pem releases/certificates/replicant-4.2-0002/media.x509.pem releases/certificates/replicant-4.2-0002/platform.x509.pem releases/certificates/replicant-4.2-0002/shared.x509.pem releases/certificates/replicant-4.2-0002/system.x509.pem releases/certificates/replicant-4.2-0003/media.x509.pem releases/certificates/replicant-4.2-0003/platform.x509.pem releases/certificates/replicant-4.2-0003/shared.x509.pem releases/certificates/replicant-4.2-0003/system.x509.pem releases/certificates/replicant-4.2-0004/media.x509.pem releases/certificates/replicant-4.2-0004/platform.x509.pem releases/certificates/replicant-4.2-0004/shared.x509.pem releases/certificates/replicant-4.2-0004/system.x509.pem releases/certificates/replicant-6.0-0001/media.x509.pem releases/certificates/replicant-6.0-0001/platform.x509.pem releases/certificates/replicant-6.0-0001/releasekey.x509.pem releases/certificates/replicant-6.0-0001/shared.x509.pem releases/certificates/replicant-6.0-0002/media.x509.pem releases/certificates/replicant-6.0-0002/platform.x509.pem releases/certificates/replicant-6.0-0002/releasekey.x509.pem releases/certificates/replicant-6.0-0002/shared.x509.pem releases/certificates/replicant-6.0-0003/media.x509.pem releases/certificates/replicant-6.0-0003/platform.x509.pem releases/certificates/replicant-6.0-0003/releasekey.x509.pem releases/certificates/replicant-6.0-0003/shared.x509.pem releases/certificates/replicant-6.0-0004-rc1/media.x509.pem releases/certificates/replicant-6.0-0004-rc1/platform.x509.pem releases/certificates/replicant-6.0-0004-rc1/releasekey.x509.pem releases/certificates/replicant-6.0-0004-rc1/shared.x509.pem releases/certificates/replicant-6.0-0004-rc2/media.x509.pem releases/certificates/replicant-6.0-0004-rc2/platform.x509.pem releases/certificates/replicant-6.0-0004-rc2/releasekey.x509.pem releases/certificates/replicant-6.0-0004-rc2/shared.x509.pem we we will then need to pass the path of releases/certificates/ to the tool. So in practice, with the directories structure above, we can use the generate_key_migration_script.py as follow to generate the key-migration.sh script: $ ./gen_key_migration_script.py gen-script \ vendor/replicant/prebuilt/common/bin/key-migration.sh \ vendor/replicant-data/distros/releases/certificates/ \ vendor/replicant-security/ References: ----------- [1]https://git.replicant.us/replicant/vendor_replicant-data/ == Running the key-migration.sh script at boot == Now that we have a key-migration.sh script, we need to make sure that the script is shipped to the device, and that it is run at boot. In Replicant 6.0, the modifications to do that should already be there. However if you want to use that tool with newer Replicant versions or other distributions, you will need to do several modifications. With Replicant 6.0, the following modifications were made in vendor/replicant to make the key-migration.sh script run at boot: - The key-migration.sh script was copied in prebuilt/common/etc/key-migration.sh in the vendor_replicant repository. - The following patches from Gabriele M was applied: diff --git a/prebuilt/common/Android.mk b/prebuilt/common/Android.mk index f15b178c..f39105d0 100644 --- a/prebuilt/common/Android.mk +++ b/prebuilt/common/Android.mk @@ -8,3 +8,10 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := key-migration.sh +LOCAL_SRC_FILES := etc/key-migration.sh +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +include $(BUILD_PREBUILT) diff --git a/prebuilt/common/etc/init.local.rc b/prebuilt/common/etc/init.local.rc index 53f972c9..bce1dc63 100644 --- a/prebuilt/common/etc/init.local.rc +++ b/prebuilt/common/etc/init.local.rc @@ -24,6 +24,8 @@ on post-fs-data mkdir /data/ssh/empty 0600 root shell mkdir /cache/recovery 0770 system cache + exec u:r:init:s0 root root -- /system/bin/sh /system/etc/key-migration.sh + # Run sysinit start sysinit diff --git a/config/common.mk b/config/common.mk index 91d5e99b..132fd61a 100644 --- a/config/common.mk +++ b/config/common.mk @@ -230,6 +230,10 @@ PRODUCT_PACKAGES += \ endif endif +# test-keys migration script +PRODUCT_PACKAGES += \ + key-migration.sh + DEVICE_PACKAGE_OVERLAYS += vendor/replicant/overlay/common ifeq ($(USE_OPENGL_RENDERER),true) == Running the key-migration.sh in the recovery == In addition, it is also possible to use the key-migration.sh script in the recovery. This can be handy if you use custom images and that you don't want to build an entire Replicant image, or if you want to keep your data while downgrading to an older Replicant image. To do that you will first need to have adb configured so that you can get root in it. At the time of writing, the BackupTheEFS[1] wiki page has instructions on how to do that. Once this is done you can copy the key-migration.sh script inside the recovery. It can be done with the following command: $ adb push key-migration.sh / You then need to mount the data partition. Here's an example on how to do it on the Galaxy SIII (GT-I9300) with the Replicant 6.0 recovery: $ adb shell root@m0:/ # root@m0:/ # mount /dev/block/platform/dw_mmc/by-name/USERDATA /data/ As the path of the data partition changes from device to device, you may need to adjust the path in the command above. The BackupTheEFS[1] wiki page has examples of that for mounting the EFS partition. You can then run the script. Note that you will need to use sh to run it as the interpreter path is hardcoded to /system/bin/sh which is absent in the recovery. You can do that like this: root@m0:/ # sh key-migration.sh Note that once it executed, it will create the /data/system/.key-migration-done file which will tell the script not to do anything anymore the next times it runs. So if for some reason you need to force its execution or do two different upgrades, you can simply delete /data/system/.key-migration-done and retry to run the script. For example: root@m0:/ # rm /data/system/.key-migration-done root@m0:/ # sh key-migration.sh References: ----------- [1]https://redmine.replicant.us/projects/replicant/wiki/BackupTheEFS == License == - The key-migration.sh script is under the Apache License, Version 2.0 as its header states. - All the other files are under the AGPLv3 or later. == Credits == - Gabriele M for the 2f7c7decc4cd5b42f044a7841a74468e4cacd694 patch - Kurtis Hanna for finding that patch.