[personal profile] mjg59
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
  • Unlock bootloader
  • Generate keys
  • Install new key
  • Lock bootloader
  • Sign image
  • Install image
which seems more straightforward. Long term, individual projects could do the signing themselves and distribute their public keys, resulting in the install process becoming as easy as
  • Unlock bootloader
  • Install ROM key
  • Lock bootloader
  • Install ROM
which is actually easier than the current requirement to install an entirely new recovery image.

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?

Date: 2014-07-04 10:52 pm (UTC)
From: (Anonymous)
The reason that things like this are rather convoluted is that the build and deployment infrastructure for Android (and AOSP) is designed around "build system image from source" (in which case it's a matter of configuring your build to use an alternate keyfile or replacing the one in the recovery source).

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)

Date: 2014-07-04 11:06 pm (UTC)
From: (Anonymous)
Yeah, a keys partition (or a general boot/recovery metadata partition) would be useful for this sort of thing. I regret that we didn't define any standards for that (standardizing on the fastboot protocol and general boot/recovery mechanism worked very well).

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

Date: 2014-07-04 11:12 pm (UTC)
From: (Anonymous)
Custom recovery images could also just use the bottom X KB of the recovery partition to store user/distro keys. The bootimg header lets the bootloader know where to find the kernel and ramdisk (and I think DT these days), and the rest of the partition is ignored by the bootloader. You'd likely lose installed keys if you reflashed recovery with the bootloader, but that's probably a reasonable behaviour. Recovery could, of course, ensure that they survive self-updates.

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)
From: (Anonymous)
If your device uses full disk encryption, in theory even going into recovery mode and flashing a new image shouldn't allow bypassing the passphrase prompt, right? You'd still have a security problem if someone got to your device without your knowledge and then you kept using it, but not if you simply lost it, right?

Bricking the device

Date: 2014-07-05 07:59 am (UTC)
From: (Anonymous)
Will this make bricking your device easier?

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-06 02:30 pm (UTC)
From: (Anonymous)
Worst case you'd have to "fastboot unlock" your phone again. That would wipe your data, but it wouldn't be "bricked" in the sense of "unrecoverable by software means."

-srwalter

Test-keys still used elsewhere

Date: 2014-07-07 05:36 am (UTC)
From: (Anonymous)
Besides signing updates.zip, those (publicly available) AOSP testkey/platform/shared/media keys are used elsewhere in the custom ROM scene to sign system apps for example. [1]
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)
From: (Anonymous)
There's a related paper about that, too:
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.

Up to ROM devs and app developers now

Date: 2014-07-07 06:11 am (UTC)
From: [personal profile] voltagex
It's possible that TWRP, ClockWorkMod and JRummy ROM Toolbox et. al. could help the user do the generation/signing dance and make this quite usable.

Re: Up to ROM devs and app developers now

Date: 2014-07-07 08:56 am (UTC)
From: (Anonymous)
First:
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)
From: (Anonymous)
Thank you so much for this post, I was stumbling about the Androis security model for quite some time and couldn't believe that, except for encryption, using a custom ROM meant jeopardizing your data.

I'll probably need to try this out myself.

other devices

Date: 2014-07-07 02:10 pm (UTC)
From: (Anonymous)
Hi, what about other popular devices, such as Samsung S4 i9505 + cyanogenmod 11, is there similar option for signing/verifying? Or only nexus devices support this?

MTD

Date: 2014-07-07 05:46 pm (UTC)
From: (Anonymous)
> The OS is (nominally) secure and prevents anything from accessing the raw MTD devices.

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
From: (Anonymous)
It's possible to unlock the bootloader of most Nexus devices from the normal android system without losing data once you have gained root access. This works by simply using dd to change the unlock state: https://play.google.com/store/apps/details?id=net.segv11.bootunlocker

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
From: (Anonymous)
Right, I didn't mean to use this whole using-root-to-dd-the-bootloader procedure as an attack vector, but as a simpler alternative to your solution (which is much more elegant and portable).

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)
From: [personal profile] gooman
There's another side-effect of use of "test-keys".

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)
From: (Anonymous)
I just want to add a few more details to save some time for others who want to reproduce these instructions.

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)
From: (Anonymous)
Thanks for writing this excellent post. I was trying to secure my newly bought Samsung J200G after rooting and this is exactly what I needed.
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 ?

DumpPublicKey.java Moved

Date: 2016-03-20 05:34 am (UTC)
From: (Anonymous)
New location: https://android.googlesource.com/platform/bootable/recovery.git/+/master/tools/dumpkey/DumpPublicKey.java

"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)
From: [personal profile] r1a
I'm not a developer and am trying to adapt this for OnePlus 3. Apologies if this seems obvious to you folks.

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,
Edited Date: 2017-03-10 06:44 am (UTC)

Not Working Anymore

Date: 2018-05-17 08:55 am (UTC)
From: (Anonymous)
I tried to carry out this procedure on my Nexus 5X because Google Pay won't work anymore on an unlocked bootloader and I hoped this would let me use it on a custom ROM. Unfortunately, after flashing with the new recovery image I can't boot into recovery mode anymore.

Profile

Matthew Garrett

About Matthew

Power management, mobile and firmware developer on Linux. Security developer at Aurora. Ex-biologist. [personal profile] mjg59 on Twitter. Content here should not be interpreted as the opinion of my employer. Also on Mastodon.

Expand Cut Tags

No cut tags