Construir y flashear una compilación AOSP segura con arranque verificado y contraseña de pantalla de bloqueo independiente para el Nexus 5X

Exención de responsabilidad y licencia

Todos los datos e información proporcionados en este tutorial son sólo para fines informativos. El autor no se hace responsable de la exactitud, integridad, actualidad, idoneidad o validez de la información de este tutorial y no se responsabiliza de los errores, omisiones o retrasos de esta información ni de las pérdidas, lesiones o daños derivados de su visualización o uso. Toda la información se proporciona tal cual.

En ningún caso, el autor o howtoforge serán responsables de ninguna pérdida o daño, incluyendo, sin limitación, las pérdidas o daños indirectos o consecuentes, o cualquier pérdida o daño derivado de la pérdida de datos o de beneficios que surjan de, o estén relacionados con, el uso de este tutorial.

Salvo que se indique lo contrario, el contenido de esta página tiene una licencia Creative Commons Attribution 3.0, y los ejemplos de código tienen una licencia Apache 2.0.

Motivación

Los Nexus 5X y 6P fueron los primeros dispositivos que admitían el arranque verificado basado en claves de firma proporcionadas por el usuario (y no por el proveedor). Antes de su «implosión» [1], CopperheadOS (una variante de AOSP mejorada en cuanto a seguridad) solía proporcionar una buena documentación y scripts para construir y flashear una versión AOSP segura [2]. Sin embargo, el proyecto dejó de proporcionar actualizaciones en los últimos meses, por lo que la mayoría de los antiguos usuarios están buscando alternativas viables.

Mi impresión es que muchos usuarios están de acuerdo en que ejecutar una ROM AOSP autoconstruida es una alternativa mucho mejor que otras opciones como el cambio a, por ejemplo, LineageOS. Hay una serie de buenas razones para ello:

  • AOSP es simplemente stock y sólo tiene unas pocas características posiblemente no deseadas
  • AOSP se puede compilar como variante de compilación «user» en lugar de «userdebug» y, por lo tanto, se espera que sea más seguro (he intentado compilar compilaciones de usuario de LineageOS, pero parece que están rotas debido a los cambios invasivos que LineageOS ha hecho en las fuentes de AOSP)
  • Una vez obtenidas las fuentes, AOSP se puede compilar de forma sencilla. A diferencia de LineageOS, no empieza a descargar fuentes adicionales durante la compilación.

Dado que se cree que el Nexus 5X es un dispositivo bien soportado por los desarrolladores, esperaba que el proceso de construcción de AOSP fuera fácil y estuviera bien documentado. Sin embargo, resulta que hay una serie de advertencias:

  • incluir los binarios del proveedor siguiendo la documentación oficial da como resultado construcciones incompletas que no pueden utilizarse para actualizaciones incrementales sin desbloquear y borrar cada vez (la partición del proveedor, la radio ROM, etc., no se incluyen en la construcción)
  • la documentación oficial no describe cómo utilizar la compilación verificada de forma que sea directamente aplicable. Hay una documentación mejor en los documentos de CopperheadOS [05], pero las instrucciones se basan en scripts anticuados que no son aplicables a AOSP.
  • no hay documentación sobre cómo utilizar un PIN «débil» como frase de paso, pero una contraseña fuerte como clave de cifrado del disco (a diferencia de los nuevos dispositivos Pixel, el Nexus 5X se basa en el antiguo enfoque FDE). Los métodos que funcionan para los dispositivos LineageOS no son aplicables, ya que suponen que el dispositivo está rooteado, lo que no es el caso de las construcciones normales de los usuarios de AOSP.

Este tutorial tiene como objetivo proporcionar instrucciones detalladas sobre cómo resolver estas advertencias, construyendo y flasheando AOSP para el Nexus 5X con arranque verificado y utilizando secretos de bloqueo/cifrado separados. También debería aplicarse al Nexus 6P con pequeños cambios, pero no he podido probarlo porque no tenía un Nexus 6P a mano.

A excepción de una pequeña colección de scripts (necesarios para extraer correctamente los blobs de proveedor de los binarios suministrados por Google) y su dependencia «oatdump» (que se descarga como binario desde un recurso compartido público), las instrucciones no hacen uso de ningún recurso «no oficial» (en el sentido de «no proporcionado por Google») de terceros.

Ten en cuenta los siguientes problemas de libertad:

  • El árbol de fuentes de la AOSP contiene una serie de binarios preconstruidos (por ejemplo, la cadena de herramientas, el núcleo de Linux, …). Aunque estos binarios podrían reconstruirse desde el código fuente, los pasos necesarios no se cubren en este tutorial.
  • El código fuente de los blobs de proveedor necesarios para utilizar muchos componentes de hardware del Nexus 5X no está disponible públicamente.
  • La herramienta «android-prepare-vendor» que se utiliza para extraer los archivos propietarios del proveedor utiliza binarios preconstruidos por ella misma (algunos incluso alojados externamente).

Requisitos y suposiciones

El tutorial asume que tienes los siguientes requisitos previos (otras versiones/distribuciones podrían funcionar también, pero podrían requerir otros paquetes o adicionales)

– un Nexus 5X con el cargador de arranque desbloqueado (el desbloqueo no se trata en este tutorial)

– máquina (virtual) que ejecute Debian9 en la variante x86_64, utilizada exclusivamente para nuestro propósito (suponemos que utilizas sudo, si no, adapta los comandos)

– al menos 5 GB de RAM (más es mejor)

– unos 200 MB de espacio en disco

– conexión rápida a internet (necesitamos descargar unos 30G de datos)

Instalar las dependencias

En primer lugar, instala las dependencias como se describe en las instrucciones de compilación de LineageOS [3] (las instrucciones de compilación de AOSP no proporcionan esta lista):

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

Ahora, instala las dependencias adicionales:

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

A continuación, configura una ruta bin en tu directorio personal (en Debian 9 esta ruta se configura automáticamente en el perfil bash):

mkdir -p ~/bin

Instala el comando repo:

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

Comprueba la suma de comprobación del binario del repo. Debería ser e147f0392686c40cfd7d5e6f332c6ee74c4eab4d24e2694b3b0a0c037bf51dc5 para la versión actual 1.23. Para versiones posteriores, consulta la página de instrucciones de compilación de AOSP [4]. Utiliza el siguiente comando para calcular la suma de comprobación:

sha256sum ~/bin/repo

A continuación, proporciona una identidad git ejecutando los siguientes comandos (puedes dejar los datos del ejemplo si prefieres permanecer anónimo):

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

Desgraciadamente, el paquete brotli (necesario para empaquetar las construcciones) en Debian 9 es demasiado antiguo, así que tenemos que construir la versión actual nosotros mismos. Primero consigue el código fuente y cámbialo en su directorio:

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

Ejecuta la compilación (sustituye -j15 por el número de hilos de tu cpu):

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

Por último, copia el binario resultante a nuestra ruta bin:

cp brotli ~/bin/

Por último, cierra la sesión y vuelve a conectarte para que tu perfil bash sea releído.

Obtener los blobs de los vendedores

Hay varios problemas con el uso de los blobs de proveedores de los paquetes de controladores binarios proporcionados por Google (ver [5]). Para resolverlos, utilizamos el conjunto de scripts externos «android-prepare-vendor» de «anestisb» que extrae los vendor blobs de las imágenes de fábrica.

Primero, clona el repositorio:

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

Utilizando el sitio de Google [6], averigua la última etiqueta de compilación para tu Nexus 5X (actualmente es OPM6.171019.030.K1).

Cambia al repositorio, crea un directorio de salida y ejecuta el script (nosotros ejecutamos el script como root debido a problemas con fuse en 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

Descarga de las fuentes AOSP

Nota: Los siguientes pasos carecen de instrucciones para verificar las fuentes descargadas.

En primer lugar, crea un directorio en el que se almacenarán las fuentes:

mkdir -p ~/aosp

Conociendo la etiqueta de compilación actual del Nexus 5X, averigua cuál es la etiqueta de Android correspondiente utilizando la descripción general disponible en [6]. A continuación, comprueba el manifiesto de Android para la rama correspondiente (en este ejemplo, utilizamos android-8.1.0_r46):

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

Ahora, puedes editar el ~/aosp.repo/manifest.xml para excluir ciertos repositorios o incluir otros (nota: esto es puramente opcional). Utiliza <!-- y --> como es habitual en el XML para comentar los repositorios. Recomiendo excluir/sustituir lo siguiente:

  • <project path="packages/apps/QuickSearchBox" name="platform/packages/apps/QuickSearchBox" groups="pdk-fs" /> - de todas formas, QuickSearchBox está casi siempre roto en AOSP
  • <ruta de proyecto="device/lge/bullhead" name="device/lge/bullhead" groups="device,bullhead,pdk" /> - sustituye esto por un repositorio que contenga un árbol de dispositivos parcheado en el que los dos núcleos de cpu defectuosos estén desactivados. Esto conlleva una penalización de rendimiento de ~30%. Sin embargo, se recomienda, incluso si tienes un Nexus 5X que no está afectado por el bootloop, ya que es probable que se vea afectado en el futuro.
  • <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" /> - hay mejores alternativas al calendario AOSP de serie que puedes instalar más tarde (como Etar)
  • <ruta del proyecto="paquetes/apps/Mensajería" name="plataforma/paquetes/apps/Mensajería" groups="pdk-fs" / > - Silence.im es una alternativa mejor para la aplicación de mensajería de AOSP
  • <ruta del proyecto="packages/apps/Camera2" name="platform/packages/apps/Camera2" groups="pdk-fs" / > - OpenCamera es una mejor alternativa para la cámara de serie

Ahora, busca todos los repositorios (puede llevar mucho tiempo, sobre todo dependiendo de tu conexión a Internet):

repo sync

Por último, copia los blobs de proveedor generados anteriormente como root (esto es necesario, o qmus y otros blobs faltarán y causarán un fallo de compilación posterior) en el directorio de proveedores de tu árbol AOSP (sustituye el número de compilación de fábrica por el actual):

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 .

Haz que tu usuario sea el propietario de los directorios vendor (o la compilación fallará después). Sustituye tu nombre de usuario por tu nombre de usuario real:

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

Generar claves

Establece las variables de construcción:

source build/envsetup.sh

Construye la herramienta necesaria para generar la clave de verificación:

make generate_verity_key

Crea un directorio para almacenar tus claves (los documentos de CopperheadOS [2] recomiendan utilizar una clave distinta para cada dispositivo, en este caso 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

Convierte la clave de verificación al formato requerido por AOSP:

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

Compilando

Asegúrate de que tus variables de compilación están configuradas:

cd ~/aosp
source build/envsetup.sh

Crea un user-lunchconfig para el dispositivo bullhead (sustituye user por userdebug si quieres una configuración userdebug en su lugar):

lunch aosp_bullhead-user

Desactiva Jack (a menudo causa problemas de compilación y, de todas formas, se ha obviado en Android 9):

export ANDROID_COMPILE_WITH_JACK=false

Compila el paquete de archivos de destino (sustituye -j15 por el número de hilos de tu cpu):

make target-files-package -j15

Empaquetar y firmar

Crea un directorio para almacenar los archivos de salida (fuera del directorio de compilación habitual llamado out):

mkdir dist

Ejecuta el objetivo dist (sustituye -j15 por el número de hilos de tu cpu):

make dist -j15

Crea un paquete signed-target-files, sustituyendo las claves de prueba por defecto por tus claves (sustituye tu nombre de usuario por tu nombre de usuario real en el sistema):

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

Crea un paquete OTA firmado:

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

Flasheando

Arranca tu dispositivo Nexus 5X en el cargador de arranque (mantén pulsado el volumen y luego pulsa el botón de encendido).

Conecta tu dispositivo por USB a tu máquina (y ponlo a disposición de la VM en caso de que la construyas en una VM). También puedes copiar el contenido del directorio dist a otra máquina y flashear desde allí, pero suponemos que flashearás utilizando los binarios fastboot/adb construidos a partir de fuentes AOSP (si flasheas desde fuera, asegúrate de que tu binario fastboot es reciente).

Descomprime las imágenes del archivo signed-target-files.zip:

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

Ahora, flashea todas las imágenes:

../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

Selecciona "reiniciar el sistema" utilizando los botones físicos de tu dispositivo y asegúrate de que tu nuevo sistema funciona.

Por último, reinicia de nuevo el bootloader y vuelve a bloquearlo (borrará todos los datos):

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

¡Ya está!

Establecer secretos de arranque/pantalla de bloqueo separados

Establecer una contraseña de arranque/pantalla de bloqueo separada puede hacerse con un pequeño truco:

  • Desbloquea el cargador de arranque (borra todos los datos)
  • compila y flashea una compilación userdebug (ver arriba)
  • bloquea el cargador de arranque
  • establece un pin/contraseña de pantalla de bloqueo utilizando la interfaz de usuario de Android. Asegúrate de que eliges el correcto porque no podrás volver a cambiarlo sin borrar tus datos una vez que cambies a la versión de usuario.
  • conéctate al dispositivo mediante adb
  • como root, ejecuta el siguiente comando: vdc cryptfs changepw password your-new-password
  • reinicia y asegúrate de que funciona
  • compila una compilación de usuario normal (¡no desbloquees el cargador de arranque!)
  • flashea la compilación de usuario

Nota: Sin pasos adicionales, el recovery no permite flashear builds antiguos. Por lo tanto, tienes que flashear una compilación de usuario que sea más reciente que tu compilación userdebug.

Manejo de las actualizaciones

Si quieres actualizar a una nueva versión de AOSP, primero tienes que averiguar el número de la nueva versión.

A continuación, borra el manifiesto antiguo (haz una copia de seguridad, por si has hecho cambios que quieras rehacer en el actualizado):

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

Borra también los blobs de proveedores (entonces obsoletos) y el repositorio de preparación de proveedores:

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

Además, limpia el árbol de construcción y los artefactos de construcción:

rm -rf out
rm -rf dist

Luego, rehaz SOLO los siguientes pasos:

  • Obtener los blobs del proveedor
  • Descargar los fuentes AOSP (esto será mucho más rápido, porque sólo se introducirán los cambios)
  • Compilar
  • Empaquetar y firmar

En teoría, deberías poder cargar lateralmente las actualizaciones como nuevos paquetes OTA desde el recovery sin necesidad de hacer wiping (ya que se firmará con las mismas - tus - claves). En la práctica, todavía no funciona (ver la siguiente sección). En este caso, también tendrás que proceder de la siguiente manera

  • Haz una copia de seguridad de todos tus datos
  • Desbloquear el cargador de arranque (tus datos se borrarán)
  • Flashea las imágenes actualizadas y vuelve a bloquear el cargador de arranque como se describe en la sección "Flasheo".

WIP: Actualizaciones OTA firmadas

Esta sección es WIP, ¡las instrucciones descritas aún no funcionan!

En teoría, debería ser posible crear y flashear actualizaciones OTA firmadas desde el recovery. Sin embargo, todos mis intentos de hacerlo han dado como resultado un error de "Verificación de la firma fallida". Dado que esto funciona cuando se utilizan los archivos de proveedor suministrados por Google directamente en lugar de utilizar android-prepare-vendor, supongo que está relacionado con que los archivos de proveedor u otros archivos (como el cargador de arranque o las imágenes de radio) no están firmados correctamente.

Crea el paquete OTA firmado como sigue:

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

Reinicia a la recuperación utilizando los botones físicos de tu dispositivo.

En la recuperación, verás un pequeño símbolo de Android. Mantén pulsado el botón de encendido y pulsa volumen arriba para entrar en el menú de recuperación.

Ahora, selecciona "actualizar desde adb" utilizando los botones físicos de tu dispositivo.

Carga lateralmente tu paquete OTA firmado:

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

Referencias

[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

También te podría gustar...