Bouwen en flashen van een beveiligde AOSP build met geverifieerd opstarten en apart lockscreen wachtwoord voor de Nexus 5X

Disclaimer en Licentie

Alle gegevens en informatie in deze handleiding zijn louter informatief. De auteur doet geen uitspraken over de nauwkeurigheid, volledigheid, actualiteit, geschiktheid of geldigheid van de informatie in deze handleiding en is niet aansprakelijk voor fouten, weglatingen of vertragingen in deze informatie of voor verliezen, verwondingen of schade als gevolg van de weergave of het gebruik ervan. Alle informatie wordt gegeven op een “as-is” basis.

In geen geval zal de auteur of howtoforge aansprakelijk zijn voor enig verlies of schade, met inbegrip van, maar niet beperkt tot, indirecte of gevolgschade, of enig verlies of schade als gevolg van verlies van gegevens of winst voortvloeiend uit, of in verband staand met, het gebruik van deze handleiding.

Tenzij anders vermeld, valt de inhoud van deze pagina onder de Creative Commons Naamsvermelding 3.0 Licentie, en code voorbeelden vallen onder de Apache 2.0 Licentie.

Motivatie

De Nexus 5X en 6P waren de eerste toestellen die geverifieerd opstarten ondersteunden op basis van door de gebruiker verstrekte (en niet door de verkoper afgedwongen) ondertekeningssleutels. Vóór zijn “implosie” [1] bood CopperheadOS (een AOSP variant met verbeterde beveiliging) goede documentatie en scripts om een veilige AOSP versie te bouwen en te flashen [2]. Het project stopte echter de laatste maanden met het verstrekken van updates, zodat de meeste voormalige gebruikers op zoek zijn naar bruikbare alternatieven.

Mijn indruk is dat veel gebruikers het ermee eens zijn dat het draaien van een zelfgebouwde AOSP ROM een veel beter alternatief is dan andere opties zoals overstappen op bv. LineageOS. Daar zijn een aantal goede redenen voor:

  • AOSP is gewoon standaard en heeft maar weinig mogelijk ongewenste functies
  • AOSP kan als “user” in plaats van als “userdebug” build vartiant gebouwd worden en is dus naar verwachting veiliger (ik heb geprobeerd gebruikers builds van LineageOS te compileren, maar die lijken gebroken te zijn door de indringende veranderingen die LineageOS aan de AOSP bronnen bracht).
  • Als de bronnen eenmaal opgehaald zijn, kan AOSP eenvoudig gebouwd worden. In tegenstelling tot LineageOS begint het tijdens het bouwen niet met het downloaden van extra bronnen.

Omdat verondersteld wordt dat de Nexus 5X een goed ondersteund ontwikkelaarstoestel is, verwachtte ik dat het proces om AOSP te bouwen eenvoudig zou zijn en goed gedocumenteerd. Het blijkt echter dat er een aantal caveats zijn:

  • het insluiten van de vendor binaries door de officiële documentatie te volgen resulteert in onvolledige builds die niet gebruikt kunnen worden voor incrementele updates zonder telkens te ontgrendelen en te wissen (de vendor partitie, radio ROM enz. is niet in de build opgenomen)
  • de officiële documentatie beschrijft niet hoe je geverifieerde build kunt gebruiken op een manier die direct toepasbaar is. Er is betere documentatie in de CopperheadOS docs [05], maar de instructies berusten op verouderde scripts die niet toepasbaar zijn voor AOSP.
  • er is geen documentatie over hoe je een “zwakke” PIN als passphrase maar een sterk wachtwoord als schijfversleutelingssleutel kunt gebruiken (in tegenstelling tot nieuwere Pixel toestellen is de Nexus 5X gebaseerd op de oudere FDE aanpak). De methodes die werken voor LineageOS toestellen zijn niet toepasbaar omdat ze veronderstellen dat het toestel geroot is, wat niet het geval is voor gewone builds van AOSP gebruikers.

Deze handleiding wil gedetailleerde instructies geven over hoe je deze caveats oplost, door AOSP te bouwen en te flashen voor de Nexus 5X met geverifieerde boot en met gebruik van aparte lockscreen/encryptie geheimen. Het zou met kleine veranderingen ook voor de Nexus 6P moeten gelden, maar ik kon het niet testen omdat ik geen Nexus 6P bij de hand had.

Behalve een kleine scriptverzameling (nodig om de vendor blobs op de juiste manier uit door Google geleverde binaries te halen) en zijn afhankelijkheid “oatdump” (die als binary van op een publiek deel wordt gedownload) maken de instructies geen gebruik van “onofficiële” (in de zin van “niet door Google geleverde”) hulpbronnen van derden.

Wees je bewust van de volgende vrijheidsproblemen:

  • De AOSP broncode boom bevat een aantal voorgebouwde binaries (b.v. toolchain, Linux kernel, …). Hoewel deze binaries vanaf broncode herbouwd kunnen worden, worden de daarvoor benodigde stappen in deze handleiding niet behandeld.
  • De broncode voor de vendor blobs die nodig zijn voor het gebruik van veel hardware componenten van de Nexus 5X is niet openbaar beschikbaar!
  • Het gereedschap “android-prepare-vendor” dat gebruikt wordt om de proprietary vendor files uit te pakken gebruikt zelf voorgebouwde binaries (sommige worden zelfs extern gehost).

Vereisten en aannames

De handleiding gaat ervan uit dat je de volgende vereisten hebt (andere versies/distributies kunnen ook werken, maar kunnen andere of extra pakketten nodig hebben):

– een Nexus 5X met een ontgrendelde bootloader (ontgrendelen wordt in deze handleiding niet behandeld)

– (virtuele) machine met Debian9 in de x86_64 variant, die uitsluitend voor ons doel gebruikt wordt (we nemen aan dat je sudo gebruikt, zo niet, pas dan de commando’s aan)

– minstens 5 GB RAM (meer is beter)

– aprox 200 MB schijfruimte

– snelle internetverbinding (we moeten ongeveer 30G aan gegevens downloaden)

Afhankelijkheden installeren

Installeer eerst afhankelijkheden zoals beschreven in de LineageOS bouwinstructies [3] (AOSP bouwinstructies geven deze lijst niet):

sudo apt install bc bison build-essential ccache curl flex g++-multilib gcc-multilib git gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5-dev libsdl1.2-dev libssl-dev libwxgtk3.0-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev

Installeer nu extra afhankelijkheden:

sudo apt install cmake zip unzip openjdk-8-jdk-headless

Zet dan een bin pad op in je thuismap (in Debian 9 wordt dit pad automatisch ingesteld in het bash profiel):

mkdir -p ~/bin

Installeer het repo commando:

curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

Controleer de controlesom van de repo binary. Hij zou e147f0392686c40cfd7d5e6f332c6ee74c4eab4d24e2694b3b0a0c037bf51dc5 moeten zijn voor de huidige versie 1.23. Kijk voor latere versies op de AOSP build instructies pagina [4]. Gebruik het volgende commando om de controlesom te berekenen:

sha256sum ~/bin/repo

Geef vervolgens een git identiteit op door de volgende commando’s uit te voeren (je kunt de voorbeeldgegevens erin laten staan als je liever anoniem blijft):

git config --global user.email "[email protected]"
git config --global user.name "Your Name"

Helaas is het brotli pakket (nodig om de builds in te pakken) in Debian 9 te oud, dus moeten we de huidige versie zelf bouwen. Haal eerst de broncode en verander in zijn directory:

git clone https://github.com/google/brotli.git

Voer de build uit (vervang -j15 door het aantal van je cpu threads):

cd ~/brotli
./configure-cmake
make -j15

Kopieer tenslotte de resulterende binary naar ons bin pad:

cp brotli ~/bin/

Log tenslotte uit en log weer in, zodat je bash profiel opnieuw gelezen wordt.

De vendor blobs krijgen

Er zijn verschillende problemen met het gebruik van de verkopers blobs uit de binaire driver pakketten die door Google worden verstrekt (zie [5]). Om ze op te lossen gebruiken we de set externe scripts “android-prepare-vendor” van “anestisb” die in plaats daarvan de vendor blobs ze uit de fabrieksimages haalt.

Eerst kloon je de repository:

git clone https://github.com/anestisb/android-prepare-vendor.git

Zoek met behulp van Google’s site [6] de nieuwste Build tag voor je Nexus 5X (momenteel is dat OPM6.171019.030.K1).

Ga naar de repository, maak een uitvoermap en voer het script uit (we voeren het script als root uit wegens problemen met fuse in Debian 9):

cd android-prepare-vendor
mkdir bullhead-blobs
sudo ./execute-all.sh -k -d bullhead -a bullhead -b OPM6.171019.030.K1 -o bullhead-blobs

Downloaden van AOSP broncode

Opmerking: In de volgende stappen ontbreken instructies voor het verifiëren van de gedownloade broncode.

Maak eerst een map waarin de broncode wordt opgeslagen:

mkdir -p ~/aosp

Ken je de huidige build tag voor de Nexus 5X, zoek dan uit wat de overeenkomstige Android tag is met het overzicht dat je vindt bij [6]. Bekijk dan het Android manifest voor de overeenkomstige tak (in dit voorbeeld gebruiken we android-8.1.0_r46):

cd ~/aosp
repo init -u https://android.googlesource.com/platform/manifest -b android-8.1.0_r46

Nu kun je de ~/aosp.repo/manifest.xml bewerken om bepaalde repositories uit te sluiten of andere op te nemen (let op: dit is louter optioneel). Gebruik <!-- en --> zoals gewoonlijk in XML om repositories uit te sluiten. Ik raad aan het volgende uit te sluiten/te vervangen:

  • <project path="packages/apps/QuickSearchBox" name="platform/packages/apps/QuickSearchBox" groups="pdk-fs" /> - de QuickSearchBox is in AOSP toch al grotendeels kapot.
  • <project path="device/lge/bullhead" name="device/lge/bullhead" groups="device,bullhead,pdk" /> - vervang dit door een repository die een gepatchte apparatenboom bevat waarin de twee defecte cpu-kernen zijn uitgeschakeld. Dit gaat gepaard met een ~30% prestatieverlies. Toch aan te raden, ook als je Nexus 5X hebt die niet door de bootloop getroffen wordt, want waarschijnlijk zal dat in de toekomst wel het geval zijn.
  • <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" /> - er zijn betere alternatieven voor de stock AOSP kalender die je later kunt installeren (zoals Etar).
  • <project path="packages/apps/Messaging" name="platform/packages/apps/Messaging" groups="pdk-fs" /> - Silence.im is een beter alternatief voor de AOSP messenging app
  • <project path="packages/apps/Camera2" name="platform/packages/apps/Camera2" groups="pdk-fs" /> - OpenCamera is een beter alternatief voor de standaard camera

Haal nu alle repositores op (kan lang duren, hangt meestal af van je internetverbinding):

repo sync

Kopieer tenslotte de eerder gegenereerde vendor blobs als root (dit is nodig, anders zullen qmus en andere blobs ontbreken en later compilatiefouten veroorzaken) naar de vendor directory van je AOSP tree (vervang het fabrieks build nummer door het huidige):

sudo cp -av ~/android-prepare-vendor/bullhead-blobs/bullhead/opm6.171019.030.k1/vendor .
sudo cp -av ~/android-prepare-vendor/bullhead-blobs/bullhead/opm6.171019.030.k1/vendor_overlay .

Maak je gebruiker de eigenaar van de vendor directories (anders mislukt het bouwen later). Vervang je gebruikersnaam door je werkelijke gebruikersnaam:

sudo chown -R yourusername:yourusername ~/aosp/vendor
sudo chown -R yourusername:yourusername ~/aosp/vendor_overlay

Sleutels genereren

Stel de bouwvariabelen in:

source build/envsetup.sh

Bouw het gereedschap dat nodig is voor het genereren van de verity key:

make generate_verity_key

Maak een map om je sleutels in op te slaan (CopperheadOS docs [2] raden aan een aparte sleutel te gebruiken voor elk apparaat, in dit geval bullhead):

mkdir -p keys/bullhead

Now it's time to generate the keys (do not set passwords on your keys):

cd keys/bullhead
../../development/tools/make_key releasekey '/C=DE/ST=Hometown/L=XX/O=yournamehere/OU=yournamehere/CN=yournamehere/[email protected]'
../../development/tools/make_key platform '/C=DE/ST=Hometown/L=XX/O=yournamehere/OU=yournamehere/CN=yournamehere/[email protected]'
../../development/tools/make_key shared '/C=DE/ST=Hometown/L=XX/O=yournamehere/OU=yournamehere/CN=yournamehere/[email protected]'
../../development/tools/make_key media '/C=DE/ST=Hometown/L=XX/O=yournameher /OU=yournamehere/CN=yournamehere/[email protected]'
../../development/tools/make_key verity '/C=DE/ST=Hometown/L=XX/O=yournamehere/OU=yournamehere/CN=yournamehere/[email protected]'
cd ~/aosp

Zet de verity key om in het door AOSP vereiste formaat:

out/host/linux-x86/bin/generate_verity_key -convert keys/bullhead/verity.x509.pem keys/bullhead/verity_key

Compileren

Zorg dat je build variabelen ingesteld zijn:

cd ~/aosp
source build/envsetup.sh

Maak een user-lunchconfig voor het bullhead apparaat (vervang user door userdebug als je in plaats daarvan een userdebug configuratie wilt):

lunch aosp_bullhead-user

Schakel Jack uit (het veroorzaakt vaak compileerproblemen en is in Android 9 toch al afgeschreven):

export ANDROID_COMPILE_WITH_JACK=false

Compileer het doel-bestanden-pakket (vervang -j15 door het aantal van je cpu threads):

make target-files-package -j15

Verpakken en ondertekenen

Maak een directory om de uitvoerbestanden in op te slaan (buiten de gebruikelijke build directory met de naam out):

mkdir dist

Voer het dist-doel uit (vervang -j15 door het aantal van je cpu threads):

make dist -j15

Maak een ondertekend-target-bestanden pakket, waarbij je de standaard testsleutels vervangt door jouw sleutels (vervang je gebruikersnaam door je werkelijke gebruikersnaam op het systeem):

build/tools/releasetools/sign_target_files_apks -o -d keys/bullhead --replace_verity_public_key keys/bullhead/verity_key.pub --replace_verity_private_key keys/bullhead/verity --replace_verity_keyid keys/bullhead/verity.x509.pem out/dist/aosp_bullhead-target_files-eng.yourusername.zip dist/signed-target-files.zip

Maak een ondertekend OTA pakket:

 build/tools/releasetools/ota_from_target_files -k keys/bullhead/releasekey dist/signed-target-files.zip dist/signed-ota-update.zip

Flashing

Start je Nexus 5X toestel op in bootloader (houd volume ingedrukt, druk dan op power).

Verbind je toestel via USB met je machine (en maak het beschikbaar voor de VM voor het geval je in een VM bouwt). Je kunt ook de inhoud van de dist directory naar een andere machine kopiëren en van daaruit flashen, maar we nemen aan dat je flasht met de fastboot/adb binaries die uit AOSP bronnen zijn gebouwd (als je van buitenaf flasht, zorg dan dat je fastboot binary recent is).

Pak de images uit de signed-target-files.zip:

cd ~/aosp/dist
unzip signed-target-files.zip IMAGES/*

Flash nu alle images:

../out/host/linux-x86/bin/fastboot flash boot boot.img
../out/host/linux-x86/bin/fastboot flash recovery recovery.img
../out/host/linux-x86/bin/fastboot flash vendor vendor.img
../out/host/linux-x86/bin/fastboot flash system system.img

Kies "reboot system" met de fysieke knoppen van je toestel en controleer of je nieuwe systeem werkt.

Herstart tenslotte terug naar de bootloader, en vergrendel hem opnieuw (zal alle gegevens wissen):

out/host/linux-x86/bin/fastboot flash oem locking

Dat is het!

Instellen van aparte boot/lockscreen geheimen

Een apart boot/lockscreen wachtwoord instellen kan met een kleine truc:

  • Ontgrendel de bootloader (wist alle gegevens)
  • compileer en flash een userdebug build (zie hierboven)
  • vergrendel de bootloader
  • stel een lockscreen pin/wachtwoord in met het Android UI. Zorg ervoor dat je het juiste kiest, want je zult het niet meer kunnen veranderen zonder je gegevens te wissen zodra je overschakelt op de gebruikers build.
  • maak verbinding met het toestel via adb
  • voer als root het volgende commando uit: vdc cryptfs changepw password your-new-password
  • herstart, en controleer of het werkt
  • compileer een gewone gebruikers build (ontgrendel de bootloader niet!)
  • flash de gebruikers build

Opmerking: Zonder aanvullende stappen staat het herstel niet toe oudere builds te flashen. Je moet dus een user build flashen die nieuwer is dan je userdebug build!

Omgaan met updates

Als je naar een nieuwere AOSP versie wilt upgraden, moet je eerst het nieuwe release nummer achterhalen.

Veeg dan het oude manifest weg (maak een backup, voor het geval je veranderingen hebt aangebracht die je op het bijgewerkte manifest opnieuw wilt doen):

cd ~/aosp
rm -rf .repo/manifests.git
rm -rf .repo/manifest.xml

Veeg ook de (dan verouderde) vendor blobs en het prepare-vendor repository weg:

rm -rf ~/android-prepare-vendor
rm -rf vendor
rm -rf vendor_overlay

Maak ook de build tree en de build artifacts schoon:

rm -rf out
rm -rf dist

Doe dan ALLEEN de volgende stappen opnieuw:

  • Verkrijgen van de vendor blobs
  • Downloaden van AOSP sources (dit zal veel sneller gaan, want alleen de veranderingen worden binnengehaald)
  • Compileren van
  • Verpakken en ondertekenen

In theorie zou je updates als nieuwe OTA pakketten vanuit herstel moeten kunnen sideloaden zonder te wissen (want ze worden ondertekend met dezelfde - jouw - sleutels). In de praktijk werkt dat nog niet (zie de volgende sectie). Ook daar zul je als volgt te werk moeten gaan:

  • Maak een back-up van al je gegevens
  • Ontgrendel de bootloader (je gegevens worden gewist)
  • Flash de bijgewerkte beelden en herblokkeer je bootloader zoals beschreven in de paragraaf "Flashing".

WIP: Getekende OTA updates

Dit gedeelte is WIP, de beschreven instructies werken nog niet!

In theorie zou het mogelijk moeten zijn om vanuit recovery gesigneerde OTA updates te maken en te flashen. Al mijn pogingen om dit te doen resulteerden echter in een foutmelding "Signature verification failed". Omdat dit wel werkt bij direct gebruik van de door Google geleverde vendor bestanden in plaats van met android-prepare-vendor, neem ik aan dat het te maken heeft met het feit dat de vendor bestanden of andere bestanden (zoals de bootloader of radio images) niet goed ondertekend zijn.

Maak het ondertekende OTA pakket als volgt:

 build/tools/releasetools/ota_from_target_files -k keys/bullhead/releasekey dist/signed-target-files.zip dist/signed-ota-update.zip

Herstart naar herstel met de fysieke knoppen van je toestel.

In herstel zie je een klein androïde symbool. Houd de powerknop ingedrukt en druk op volume omhoog om in het herstelmenu te komen.

Kies nu "update from adb" met de fysieke knoppen van je toestel.

Sideload je ondertekende OTA pakket:

out/host/linux-x86/bin/adb sideload dist/signed-ota-update.zip

Referenties

[1] https://www.reddit.com/r/CopperheadOS/comments/8qdnn3/goodbye/

[2] https://copperhead.co/android/docs/building

[3] https://wiki.lineageos.org/devices/bullhead/build

[4] https://source.android.com/setup/build/downloading

[5] https://github.com/anestisb/android-prepare-vendor

[6] https://source.android.com/setup/start/build-numbers.html#source-code-tags-and-builds