Self-signing custom Android ROMs
Jul. 4th, 2014 05:40 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
The security model on the Google Nexus devices is pretty straightforward. The OS is (nominally) secure and prevents anything from accessing the raw MTD devices. The bootloader will only allow the user to write to partitions if it's unlocked. The recovery image will only permit you to install images that are signed with a trusted key. In combination, these facts mean that it's impossible for an attacker to modify the OS image without unlocking the bootloader[1], and unlocking the bootloader wipes all your data. You'll probably notice that.
The problem comes when you want to run something other than the stock Google images. Step number one for basically all of these is "Unlock your bootloader", which is fair enough. Step number two is "Install a new recovery image", which is also reasonable in that the key database is stored in the recovery image and so there's no way to update it without doing so. Except, unfortunately, basically every third party Android image is either unsigned or is signed with the (publicly available) Android test keys, so this new recovery image will flash anything. Feel free to relock your bootloader - the recovery image will still happily overwrite your OS.
This is unfortunate. Even if you've encrypted your phone, anyone with physical access can simply reboot into recovery and reflash /system with something that'll stash your encryption key and mail your data to the NSA. Surely there's a better way of doing this?
Thankfully, there is. Kind of. It's annoying and involves a bunch of manual processes and you'll need to re-sign every update yourself. But it is possible to configure Nexus devices in such a way that you retain the same level of security you had when you were using the Google keys without losing the freedom to run whatever you want. Here's how.
Note: This is not straightforward. If you're not an experienced developer, you shouldn't attempt this. I'm documenting this so people can create more user-friendly approaches.
First: Unlock your bootloader. /data will be wiped.
Second: Get a copy of the stock recovery.img for your device. You can get it from the factory images available here
Third: Grab mkbootimg from here and build it. Run unpackbootimg against recovery.img.
Fourth: Generate some keys. Get this script and run it.
Fifth: zcat recovery.img-ramdisk.gz | cpio -id to extract your recovery image ramdisk. Do this in an otherwise empty directory.
Sixth: Get DumpPublicKey.java from here and run it against the .x509.pem file generated in step 4. Replace /res/keys from the recover image ramdisk with the output. Include the "v2" bit at the beginning.
Seventh: Repack the ramdisk image (find . | cpio -o -H newc | gzip > ../recovery.img-ramdisk.gz) and rebuild recovery.img with mkbootimg.
Eighth: Write the new recovery image to your device
Ninth: Get signapk from here and build it. Run it against the ROM you want to sign, using the keys you generated earlier. Make sure you use the -w option to sign the whole zip rather than signing individual files.
Tenth: Relock your bootloader
Eleventh: Boot into recovery mode and sideload your newly signed image.
At this point you'll want to set a reasonable security policy on the image (eg, if it grants root access, ensure that it requires a PIN or something), but otherwise you're set - the recovery image can't be overwritten without unlocking the bootloader and wiping all your data, and the recovery image will only write images that are signed with your key. For obvious reasons, keep the key safe.
This, well. It's obviously an excessively convoluted workflow. A *lot* of it could be avoided by providing a standardised mechanism for key management. One approach would be to add a new fastboot command for modifying the key database, and only permit this to be run when the bootloader is unlocked. The workflow would then be something like
I'd actually previously criticised Google on the grounds that using custom keys wasn't possible on Android devices. I was wrong. It is, it's just that (as far as I can tell) nobody's actually documented it before. It's important that users not be forced into treating security and freedom as mutually exclusive, and it's great that Google have made that possible.
[1] This model fails if it's possible to gain root on the device. Thankfully this would never hold on what's that over there is that a distraction?
The problem comes when you want to run something other than the stock Google images. Step number one for basically all of these is "Unlock your bootloader", which is fair enough. Step number two is "Install a new recovery image", which is also reasonable in that the key database is stored in the recovery image and so there's no way to update it without doing so. Except, unfortunately, basically every third party Android image is either unsigned or is signed with the (publicly available) Android test keys, so this new recovery image will flash anything. Feel free to relock your bootloader - the recovery image will still happily overwrite your OS.
This is unfortunate. Even if you've encrypted your phone, anyone with physical access can simply reboot into recovery and reflash /system with something that'll stash your encryption key and mail your data to the NSA. Surely there's a better way of doing this?
Thankfully, there is. Kind of. It's annoying and involves a bunch of manual processes and you'll need to re-sign every update yourself. But it is possible to configure Nexus devices in such a way that you retain the same level of security you had when you were using the Google keys without losing the freedom to run whatever you want. Here's how.
Note: This is not straightforward. If you're not an experienced developer, you shouldn't attempt this. I'm documenting this so people can create more user-friendly approaches.
First: Unlock your bootloader. /data will be wiped.
Second: Get a copy of the stock recovery.img for your device. You can get it from the factory images available here
Third: Grab mkbootimg from here and build it. Run unpackbootimg against recovery.img.
Fourth: Generate some keys. Get this script and run it.
Fifth: zcat recovery.img-ramdisk.gz | cpio -id to extract your recovery image ramdisk. Do this in an otherwise empty directory.
Sixth: Get DumpPublicKey.java from here and run it against the .x509.pem file generated in step 4. Replace /res/keys from the recover image ramdisk with the output. Include the "v2" bit at the beginning.
Seventh: Repack the ramdisk image (find . | cpio -o -H newc | gzip > ../recovery.img-ramdisk.gz) and rebuild recovery.img with mkbootimg.
Eighth: Write the new recovery image to your device
Ninth: Get signapk from here and build it. Run it against the ROM you want to sign, using the keys you generated earlier. Make sure you use the -w option to sign the whole zip rather than signing individual files.
Tenth: Relock your bootloader
Eleventh: Boot into recovery mode and sideload your newly signed image.
At this point you'll want to set a reasonable security policy on the image (eg, if it grants root access, ensure that it requires a PIN or something), but otherwise you're set - the recovery image can't be overwritten without unlocking the bootloader and wiping all your data, and the recovery image will only write images that are signed with your key. For obvious reasons, keep the key safe.
This, well. It's obviously an excessively convoluted workflow. A *lot* of it could be avoided by providing a standardised mechanism for key management. One approach would be to add a new fastboot command for modifying the key database, and only permit this to be run when the bootloader is unlocked. The workflow would then be something like
- Unlock bootloader
- Generate keys
- Install new key
- Lock bootloader
- Sign image
- Install image
- Unlock bootloader
- Install ROM key
- Lock bootloader
- Install ROM
I'd actually previously criticised Google on the grounds that using custom keys wasn't possible on Android devices. I was wrong. It is, it's just that (as far as I can tell) nobody's actually documented it before. It's important that users not be forced into treating security and freedom as mutually exclusive, and it's great that Google have made that possible.
[1] This model fails if it's possible to gain root on the device. Thankfully this would never hold on what's that over there is that a distraction?
no subject
Date: 2014-07-04 10:52 pm (UTC)Obviously that doesn't solve the problem (that it'd be nice to be able to drop in replacement or additional keys in a more straightforward way), but since most alternate OS images involve "flash this alternate recovery image", it would seem that if the alternate image projects provided their public keys, it'd be easy for the necessary recovery images to include them.
There were a couple instances of OEMs shipping test keys a few years back, and I believe the CTS was updated to check for that, but I didn't realize that the third party images were using the test keys (augh, no!) or (worse) no signing at all...
- brian (too lazy to figure out the login system today)
no subject
Date: 2014-07-04 11:01 pm (UTC)The model I was thinking of was something along the lines of having an additional (small) mtd partition in the system image which would ship empty. If it's empty, stock recovery would use the built-in keys. If it's populated, stock recovery would ignore /res/keys and pull them from the partition instead.
Hmm. Does fastboot inherently know about partition names, or does the bootloader parse the mtd metadata? If the latter, this seems easy enough to prototype...
no subject
Date: 2014-07-04 11:06 pm (UTC)In recent years, Nexus devices have been using GPT (which conveniently allow named partitions), but different OEM bootloaders take different approaches to managing this (including forcibly overwriting the partition table if it doesn't match what's expected...)
Being more prescriptive about bootloader behaviour is on my "what to do next time" list.
- brian
no subject
Date: 2014-07-04 11:12 pm (UTC)If the major popular custom distros made a point of publishing their public keys, the major custom recovery developers could also choose to include them (possibly with UI to enable/disable, etc).
- brian
Full disk encryption?
Date: 2014-07-05 01:35 am (UTC)Re: Full disk encryption?
Date: 2014-07-05 04:02 pm (UTC)Bricking the device
Date: 2014-07-05 07:59 am (UTC)I mean, if your signed bootloader fails to boot, do you have a brick? If you lose your keys?
Re: Bricking the device
Date: 2014-07-05 04:01 pm (UTC)Re: Bricking the device
Date: 2014-07-06 02:30 pm (UTC)-srwalter
Test-keys still used elsewhere
Date: 2014-07-07 05:36 am (UTC)This still compromises Android's security model.
More details can be found by Dianne Hackborn comments when CyanogenMod tried to push some "workaround" for that to AOSP:
https://android-review.googlesource.com/#/c/22694/
[1] Only official Omnirom builds and CyanogenMod Installer builds are not using those AOSP keys, but their own really private ones.
Re: Test-keys still used elsewhere
Date: 2014-07-07 05:56 am (UTC)http://www.cs.cuhk.hk/~cslui/PUBLICATION/ASIACCS2014DROIDRAY.pdf
P.S. Normal CyanogenMod builds are different from Installer builds and still signed with AOSP keys. To get Installer builds use the CyanogenMod Installer.
Re: Test-keys still used elsewhere
Date: 2014-07-07 06:39 am (UTC)Up to ROM devs and app developers now
Date: 2014-07-07 06:11 am (UTC)Re: Up to ROM devs and app developers now
Date: 2014-07-07 08:56 am (UTC)Even then it wouldn't solve the fundamental security problems of custom roms. Not only the ZIP is signed with publicly known keys:
http://wiki.rootzwiki.com/Signing#Shared_Keys
Second:
If you automate it, you are again one checkbox away from disaster.
You can already achieve something like that if you flash back the OEM stock recovery and just boot/flash to a custom recovery when really needed.
Custom Rom scene doesn't even manage to correctly sign their ZIPs, so not even signature verification against itself is enforced by default in custom recoveries:
http://wiki.rootzwiki.com/Signing#ZIPs
Third:
The other problems with custom recoveries is that they are usually already too powerful. Allowing adb root (tho CWMR does at least check for authorized adb_keys), allowing full backups, TWRP coming with a file manager, full busybox environments, etc.
That's why CyanogenMod went a different route for their OEMs devices/Installer builds and made a new simple recovery (sr), which just allows updates which are signed with CM's private keys and wipes:
https://github.com/CyanogenMod/android_bootable_recovery-cm
http://review.cyanogenmod.org/#/c/64135/
TWRP also tried an OEM-friendly version, but didn't investigate further:
https://gerrit.omnirom.org/#/c/6631/
At least that commit doesn't mention signature enforcing.
Finally, my questions are answered
Date: 2014-07-07 06:29 am (UTC)I'll probably need to try this out myself.
other devices
Date: 2014-07-07 02:10 pm (UTC)Re: other devices
Date: 2014-07-07 03:51 pm (UTC)MTD
Date: 2014-07-07 05:46 pm (UTC)AFAIK, all of the modern Google Nexus devices use eMMC storage (flash with an integrated flash controller), not raw flash, and so they would not be considered "raw MTD devices."
http://www.linux-mtd.infradead.org/faq/general.html#L_mtd_vs_hdd
Brian
Re: MTD
Date: 2014-07-07 06:17 pm (UTC)Alternative: unlock the bootloader without wiping
Date: 2014-07-07 08:34 pm (UTC)I think you can have nearly the same level of security (minus allowing only your own keys) by keeping the bootloader locked and keeping the stock recovery. If you want to update, you have to: get root access (secured by PIN), unlock the bootloader, reboot into the bootloader, boot a custom recovery image (using 'fastboot boot', this won't flash it), install update, reboot, get root access, lock the bootloader again.
But there might still be a completely different attack vector, depending on some debug interfaces hidden behind multiplexers. This is a good starting point: http://greatscottgadgets.com/infiltrate2013/ossmann-osborn-bhusa2013-whitepaper.txt
Re: Alternative: unlock the bootloader without wiping
Date: 2014-07-07 08:40 pm (UTC)Re: Alternative: unlock the bootloader without wiping
Date: 2014-07-07 09:00 pm (UTC)I don't see any way to crack either version of security - besides exploitable bugs in the bootloader or recovery system. The only way into a system secured like this I could think of, but didn't inspect any further, are these multiplexer-hidden interfaces. Once such an interface allows low-level write access (ignoring any key checking measurements), you're pwned. Might be a place for "data forensics" backdoors.
test-keys and root detection
Date: 2014-08-11 09:03 am (UTC)It's used as a common test for a rooted device. This means that apps that test for rooted devices will find a false positive where a Custom ROM has been installed.
This screws Flixster, FoxDigitalCopy, and the UK-based Blinkbox, Sky Go and 4oD TV streaming services.
If there was a neat way to replace "test-keys" with something else, this would enable the use of these apps on non-rooted custom ROMs.
More details
Date: 2014-10-24 01:37 pm (UTC)In step 6., you need the bouncy castle provider. In Debian, that's the libbcprov-java package. Add the jar to the classpath.
Step 7: rebuilding the recovery image needs to include all the settings and files from the original. unpackbootimg tells you these, make sure to include all the options (and any dt files / secondary bootloaders) when repacking.
In step 9, the same applies as for step no 6, but you also need to add PKIX bouncy castle things (Debian: libbcpkix-java) to the classpath.
However, some devices (e.g. the OnePlus One) will automatically overwrite your recovery image on update. For the OnePlus One, this behaviour is configurable in the developer options, but very inconvenient nonetheless. In the worst case, it means that after an update you are stuck with a locked bootloader and without root, unable to create a full backup. You might just have to wipe again.
Problems in booting custom signed recovery
Date: 2016-01-21 08:00 am (UTC)However, I have rather basic doubt, If I use custom recovery with a locked bootloader, how can the recovery boot ?
As per android secure boot specifications, a locked bootloader will check the Recovery for being signed by Manufacturer's key. If the recovery is not signed by Manufacturer's key then I can't boot it and the update process will get stuck.
I tried all the steps on my samsung J200G and after relocking bootloader, I get the error that "FRP lock is on, can't boot custom ROM" while booting into recovery. Is there something that I'm missing in these steps ?
Re: Problems in booting custom signed recovery
Date: 2016-01-21 08:15 am (UTC)DumpPublicKey.java Moved
Date: 2016-03-20 05:34 am (UTC)"txt" link at the bottom is base64 encoded for some reason.
Don't see a platform_bootable_recovery on github.
dm-verity
Date: 2017-03-10 06:44 am (UTC)Two questions:
1. Does the boot image need to be signed as well?
2. Does the fstab in boot image need to turn off verify for /system or is there anything else to be done to take care of dm-verity.
Thanks,
Not Working Anymore
Date: 2018-05-17 08:55 am (UTC)