Las imágenes del sistema operativo Android utilizan firmas criptográficas en dos lugares:
- Cada archivo
.apk
dentro de la imagen debe estar firmado. El Administrador de paquetes de Android utiliza una firma.apk
de dos maneras:- Cuando se reemplaza una aplicación, debe estar firmada con la misma clave que la aplicación anterior para poder acceder a los datos de la aplicación anterior. Esto es válido tanto para actualizar aplicaciones de usuario sobrescribiendo el
.apk
como para anular una aplicación del sistema con una versión más nueva instalada en/data
. - Si dos o más aplicaciones quieren compartir una ID de usuario (para poder compartir datos, etc.), deben estar firmadas con la misma clave.
- Cuando se reemplaza una aplicación, debe estar firmada con la misma clave que la aplicación anterior para poder acceder a los datos de la aplicación anterior. Esto es válido tanto para actualizar aplicaciones de usuario sobrescribiendo el
- Los paquetes de actualización OTA deben firmarse con una de las claves esperadas por el sistema o el proceso de instalación los rechazará.
Teclas de liberación
El árbol de Android incluye claves de prueba en build/target/product/security
. Al crear una imagen del sistema operativo Android usando make
se firmarán todos los archivos .apk
usando las claves de prueba. Dado que las claves de prueba son de conocimiento público, cualquiera puede firmar sus propios archivos .apk con las mismas claves, lo que puede permitirles reemplazar o secuestrar aplicaciones del sistema integradas en la imagen de su sistema operativo. Por este motivo, es fundamental firmar cualquier imagen del sistema operativo Android publicada o implementada con un conjunto especial de claves de versión a las que solo usted tiene acceso.
Para generar su propio conjunto exclusivo de claves de liberación, ejecute estos comandos desde la raíz de su árbol de Android:
subject='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
mkdir ~/.android-certs
for x in releasekey platform shared media networkstack; do \ ./development/tools/make_key ~/.android-certs/$x "$subject"; \ done
$subject
debe cambiarse para reflejar la información de su organización. Puede utilizar cualquier directorio, pero tenga cuidado de elegir una ubicación que tenga una copia de seguridad y sea segura. Algunos proveedores optan por cifrar su clave privada con una frase de contraseña segura y almacenar la clave cifrada en el control de fuente; otros almacenan sus claves de liberación en otro lugar, como en una computadora con espacio de aire.
Para generar una imagen de lanzamiento, use:
make dist
sign_target_files_apks \ -o \ # explained in the next section --default_key_mappings ~/.android-certs out/dist/*-target_files-*.zip \ signed-target_files.zip
El script sign_target_files_apks
toma un .zip
de archivos de destino como entrada y produce un nuevo .zip
de archivos de destino en el que todos los archivos .apk
se han firmado con nuevas claves. Las imágenes recién firmadas se pueden encontrar en IMAGES/
en signed-target_files.zip
.
Firmar paquetes OTA
Un zip de archivos de destino firmado se puede convertir en un zip de actualización OTA firmado mediante el siguiente procedimiento:
ota_from_target_files \
-k (--package_key)
signed-target_files.zip \
signed-ota_update.zip
Firmas y transferencia
La descarga no pasa por alto el mecanismo normal de verificación de la firma del paquete de recuperación: antes de instalar un paquete, la recuperación verificará que esté firmado con una de las claves privadas que coincidan con las claves públicas almacenadas en la partición de recuperación, tal como lo haría con un paquete entregado a través de la partición de recuperación. -aire.
Los paquetes de actualización recibidos del sistema principal generalmente se verifican dos veces: una vez por el sistema principal, usando el método RecoverySystem.verifyPackage()
en la API de Android, y luego otra vez por recuperación. La API RecoverySystem verifica la firma con las claves públicas almacenadas en el sistema principal, en el archivo /system/etc/security/otacerts.zip
(de forma predeterminada). La recuperación verifica la firma con las claves públicas almacenadas en el disco RAM de la partición de recuperación, en el archivo /res/keys
.
De forma predeterminada, los archivos de destino .zip
producidos por la compilación configuran el certificado OTA para que coincida con la clave de prueba. En una imagen publicada, se debe utilizar un certificado diferente para que los dispositivos puedan verificar la autenticidad del paquete de actualización. Pasar el indicador -o
a sign_target_files_apks
, como se muestra en la sección anterior, reemplaza el certificado de clave de prueba con el certificado de clave de liberación de su directorio de certificados.
Normalmente, la imagen del sistema y la imagen de recuperación almacenan el mismo conjunto de claves públicas OTA. Al agregar una clave solo al conjunto de claves de recuperación, es posible firmar paquetes que solo se pueden instalar mediante descarga (suponiendo que el mecanismo de descarga de actualizaciones del sistema principal esté realizando correctamente la verificación con otacerts.zip). Puede especificar claves adicionales para que se incluyan solo en la recuperación configurando la variable PRODUCT_EXTRA_RECOVERY_KEYS en la definición de su producto:
vendor/yoyodyne/tardis/products/tardis.mk
[...] PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
Esto incluye la clave pública vendor/yoyodyne/security/tardis/sideload.x509.pem
en el archivo de claves de recuperación para que pueda instalar paquetes firmados con ella. Sin embargo, la clave adicional no está incluida en otacerts.zip, por lo que los sistemas que verifican correctamente los paquetes descargados no invocan la recuperación de los paquetes firmados con esta clave.
Certificados y claves privadas
Cada clave viene en dos archivos: el certificado , que tiene la extensión .x509.pem, y la clave privada , que tiene la extensión .pk8. La clave privada debe mantenerse en secreto y es necesaria para firmar un paquete. La clave puede estar protegida por una contraseña. El certificado, por el contrario, contiene sólo la mitad pública de la clave, por lo que puede distribuirse ampliamente. Se utiliza para verificar que un paquete ha sido firmado con la clave privada correspondiente.
La compilación estándar de Android utiliza cinco claves, todas las cuales residen en build/target/product/security
:
- clave de prueba
- Clave predeterminada genérica para paquetes que de otro modo no especifican una clave.
- plataforma
- Clave de prueba para paquetes que forman parte de la plataforma principal.
- compartido
- Clave de prueba para cosas que se comparten en el proceso de inicio/contactos.
- medios de comunicación
- Clave de prueba para paquetes que forman parte del sistema de medios/descarga.
Los paquetes individuales especifican una de estas claves configurando LOCAL_CERTIFICATE en su archivo Android.mk. (Se utiliza testkey si esta variable no está configurada). También puede especificar una clave completamente diferente por nombre de ruta, por ejemplo:
device/yoyodyne/apps/SpecialApp/Android.mk
[...] LOCAL_CERTIFICATE := device/yoyodyne/security/special
Ahora la compilación usa la clave device/yoyodyne/security/special.{x509.pem,pk8}
para firmar SpecialApp.apk. La compilación solo puede utilizar claves privadas que no estén protegidas con contraseña.
Opciones de firma avanzadas
Reemplazo de clave de firma de APK
El script de firma sign_target_files_apks
funciona en los archivos de destino generados para una compilación. Toda la información sobre los certificados y las claves privadas utilizadas en el momento de la compilación se incluye en los archivos de destino. Al ejecutar el script de firma para firmar para su lanzamiento, las claves de firma se pueden reemplazar según el nombre de la clave o el nombre del APK.
Utilice los indicadores --key_mapping
y --default_key_mappings
para especificar el reemplazo de claves según los nombres de las claves:
- El indicador
--key_mapping src_key = dest_key
especifica el reemplazo de una clave a la vez. - El indicador
--default_key_mappings dir
especifica un directorio con cinco claves para reemplazar todas las claves enbuild/target/product/security
; es equivalente a usar--key_mapping
cinco veces para especificar las asignaciones.
build/target/product/security/testkey = dir/releasekey build/target/product/security/platform = dir/platform build/target/product/security/shared = dir/shared build/target/product/security/media = dir/media build/target/product/security/networkstack = dir/networkstack
Utilice el indicador --extra_apks apk_name1,apk_name2,... = key
para especificar los reemplazos de claves de firma según los nombres de APK. Si key
se deja vacía, el script trata los APK especificados como prefirmados.
Para el producto tardis hipotético, necesita seis claves protegidas con contraseña: cinco para reemplazar las cinco en build/target/product/security
y una para reemplazar la clave adicional device/yoyodyne/security/special
requerida por SpecialApp en el ejemplo anterior. Si las claves estuvieran en los siguientes archivos:
vendor/yoyodyne/security/tardis/releasekey.x509.pem vendor/yoyodyne/security/tardis/releasekey.pk8 vendor/yoyodyne/security/tardis/platform.x509.pem vendor/yoyodyne/security/tardis/platform.pk8 vendor/yoyodyne/security/tardis/shared.x509.pem vendor/yoyodyne/security/tardis/shared.pk8 vendor/yoyodyne/security/tardis/media.x509.pem vendor/yoyodyne/security/tardis/media.pk8 vendor/yoyodyne/security/tardis/networkstack.x509.pem vendor/yoyodyne/security/tardis/networkstack.pk8 vendor/yoyodyne/security/special.x509.pem vendor/yoyodyne/security/special.pk8 # NOT password protected vendor/yoyodyne/security/special-release.x509.pem vendor/yoyodyne/security/special-release.pk8 # password protected
Luego firmarías todas las aplicaciones de esta manera:
./build/make/tools/releasetools/sign_target_files_apks \
--default_key_mappings vendor/yoyodyne/security/tardis \
--key_mapping vendor/yoyodyne/security/special=vendor/yoyodyne/security/special-release \
--extra_apks PresignedApp= \
-o tardis-target_files.zip \
signed-tardis-target_files.zip
Esto trae a colación lo siguiente:
Enter password for vendor/yoyodyne/security/special-release key> Enter password for vendor/yoyodyne/security/tardis/networkstack key> Enter password for vendor/yoyodyne/security/tardis/media key> Enter password for vendor/yoyodyne/security/tardis/platform key> Enter password for vendor/yoyodyne/security/tardis/releasekey key> Enter password for vendor/yoyodyne/security/tardis/shared key> signing: Phone.apk (vendor/yoyodyne/security/tardis/platform) signing: Camera.apk (vendor/yoyodyne/security/tardis/media) signing: NetworkStack.apk (vendor/yoyodyne/security/tardis/networkstack) signing: Special.apk (vendor/yoyodyne/security/special-release) signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey) [...] signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared) signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared) NOT signing: PresignedApp.apk (skipped due to special cert string) rewriting SYSTEM/build.prop: replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform) rewriting RECOVERY/RAMDISK/default.prop: replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys using: vendor/yoyodyne/security/tardis/releasekey.x509.pem for OTA package verification done.
Después de solicitar al usuario las contraseñas para todas las claves protegidas con contraseña, el script vuelve a firmar todos los archivos APK en el archivo .zip
de destino de entrada con las claves de liberación. Antes de ejecutar el comando, también puede configurar la variable de entorno ANDROID_PW_FILE
en un nombre de archivo temporal; Luego, el script invoca a su editor para permitirle ingresar contraseñas para todas las claves (esta puede ser una forma más conveniente de ingresar contraseñas).
Reemplazo de clave de firma APEX
Android 10 introduce el formato de archivo APEX para instalar módulos del sistema de nivel inferior. Como se explica en Firma APEX , cada archivo APEX se firma con dos claves: una para la imagen del mini sistema de archivos dentro de un APEX y la otra para todo el APEX.
Al firmar para la liberación, las dos claves de firma de un archivo APEX se reemplazan por claves de liberación. La clave de carga útil del sistema de archivos se especifica con el indicador --extra_apex_payload
y toda la clave de firma del archivo APEX se especifica con el indicador --extra_apks
.
Para el producto tardis, suponga que tiene la siguiente configuración de clave para los archivos APEX com.android.conscrypt.apex
, com.android.media.apex
y com.android.runtime.release.apex
.
name="com.android.conscrypt.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" name="com.android.media.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" name="com.android.runtime.release.apex" public_key="vendor/yoyodyne/security/testkeys/com.android.runtime.avbpubkey" private_key="vendor/yoyodyne/security/testkeys/com.android.runtime.pem" container_certificate="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.x509.pem" container_private_key="vendor/yoyodyne/security/testkeys/com.google.android.runtime.release_container.pk8"
Y tiene los siguientes archivos que contienen las claves de liberación:
vendor/yoyodyne/security/runtime_apex_container.x509.pem vendor/yoyodyne/security/runtime_apex_container.pk8 vendor/yoyodyne/security/runtime_apex_payload.pem
El siguiente comando anula las claves de firma para com.android.runtime.release.apex
y com.android.tzdata.apex
durante la firma de la versión. En particular, com.android.runtime.release.apex
está firmado con las claves de versión especificadas ( runtime_apex_container
para el archivo APEX y runtime_apex_payload
para la carga útil de la imagen del archivo). com.android.tzdata.apex
se trata como prefirmado. Todos los demás archivos APEX se manejan mediante la configuración predeterminada que se enumera en los archivos de destino.
./build/make/tools/releasetools/sign_target_files_apks \
--default_key_mappings vendor/yoyodyne/security/tardis \
--extra_apks com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_container \
--extra_apex_payload_key com.android.runtime.release.apex=vendor/yoyodyne/security/runtime_apex_payload.pem \
--extra_apks com.android.media.apex= \
--extra_apex_payload_key com.android.media.apex= \
-o tardis-target_files.zip \
signed-tardis-target_files.zip
Al ejecutar el comando anterior se obtienen los siguientes registros:
[...] signing: com.android.runtime.release.apex container (vendor/yoyodyne/security/runtime_apex_container) : com.android.runtime.release.apex payload (vendor/yoyodyne/security/runtime_apex_payload.pem) NOT signing: com.android.conscrypt.apex (skipped due to special cert string) NOT signing: com.android.media.apex (skipped due to special cert string) [...]
Otras opciones
El script de firma sign_target_files_apks
reescribe la descripción de la compilación y la huella digital en los archivos de propiedades de la compilación para reflejar que la compilación es una compilación firmada. El indicador --tag_changes
controla qué ediciones se realizan en la huella digital. Ejecute el script con -h
para ver la documentación sobre todos los indicadores.
Generar claves manualmente
Android utiliza claves RSA de 2048 bits con exponente público 3. Puede generar pares de certificado/clave privada utilizando la herramienta openssl de openssl.org :
# generate RSA keyopenssl genrsa -3 -out temp.pem 2048
Generating RSA private key, 2048 bit long modulus ....+++ .....................+++ e is 3 (0x3) # create a certificate with the public part of the keyopenssl req -new -x509 -key temp.pem -out releasekey.x509.pem -days 10000 -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'
# create a PKCS#8-formatted version of the private keyopenssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt
# securely delete the temp.pem fileshred --remove temp.pem
El comando openssl pkcs8 proporcionado anteriormente crea un archivo .pk8 sin contraseña, adecuado para usar con el sistema de compilación. Para crear un .pk8 protegido con una contraseña (lo que debe hacer para todas las claves de liberación reales), reemplace el argumento -nocrypt
con -passout stdin
; luego openssl cifrará la clave privada con una contraseña leída de la entrada estándar. No se imprime ningún mensaje, por lo que si stdin es el terminal, el programa parecerá bloquearse cuando en realidad solo está esperando que ingrese una contraseña. Se pueden usar otros valores para el argumento-passout para leer la contraseña desde otras ubicaciones; Para obtener más detalles, consulte la documentación de openssl .
El archivo intermedio temp.pem contiene la clave privada sin ningún tipo de protección con contraseña, así que deséchelo con cuidado al generar claves de liberación. En particular, es posible que la utilidad GNUshred no sea eficaz en sistemas de archivos de red o registrados por diario. Puede utilizar un directorio de trabajo ubicado en un disco RAM (como una partición tmpfs) al generar claves para garantizar que los intermedios no queden expuestos inadvertidamente.
Crear archivos de imagen
Cuando haya signed-target_files.zip
, deberá crear la imagen para poder colocarla en un dispositivo. Para crear la imagen firmada a partir de los archivos de destino, ejecute el siguiente comando desde la raíz del árbol de Android:
img_from_target_files signed-target_files.zip signed-img.zipEl archivo resultante,
signed-img.zip
, contiene todos los archivos .img
. Para cargar una imagen en un dispositivo, use fastboot de la siguiente manera:fastboot update signed-img.zip