Las imágenes del sistema operativo Android usan firmas criptográficas en dos lugares:
- Cada archivo
.apk
dentro de la imagen debe estar firmado. El Administrador de paquetes de Android usa 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 identificación de usuario (para que puedan 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 estar firmados con una de las claves esperadas por el sistema o el proceso de instalación los rechazará.
Liberar teclas
El árbol de Android incluye claves de prueba en build/target/product/security
. La creación de una imagen del sistema operativo Android con make
firmará todos los archivos .apk
con 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 esta razón, es fundamental firmar cualquier imagen del sistema operativo Android lanzada o implementada públicamente con un conjunto especial de claves de lanzamiento a las que solo usted tiene acceso.
Para generar su propio conjunto único de claves de lanzamiento, 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 usar 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 código fuente; otros almacenan sus claves de liberación en otro lugar completamente diferente, 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 claves nuevas. Las imágenes recién firmadas se pueden encontrar en IMAGES/
en signed-target_files.zip
.
Firma de 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 sideloading
La instalación de prueba 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 Internet. -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 de RecoverySystem comprueba 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 compara 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, el archivo .zip
de los archivos de destino producido por la compilación configura el certificado OTA para que coincida con la clave de prueba. En una imagen publicada, se debe usar 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 versió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 a través de la instalación de prueba (suponiendo que el mecanismo de descarga de actualizaciones del sistema principal realiza 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 el vendor/yoyodyne/security/tardis/sideload.x509.pem
en el archivo de claves de recuperación para que pueda instalar paquetes firmados con él. 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 solo la mitad pública de la clave, por lo que puede distribuirse ampliamente. Se utiliza para verificar que un paquete ha sido firmado por la clave privada correspondiente.
La compilación estándar de Android usa 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 las 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/descargas.
Los paquetes individuales especifican una de estas claves configurando LOCAL_CERTIFICATE en su archivo Android.mk. (testkey se usa 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 device/yoyodyne/security/special.{x509.pem,pk8}
para firmar SpecialApp.apk. La compilación solo puede usar claves privadas que no estén protegidas con contraseña.
Opciones de firma avanzadas
Reemplazo de la 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 certificados y 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 el lanzamiento, las claves de firma se pueden reemplazar según el nombre de la clave o el nombre del APK.
Utilice las banderas --key_mapping
y --default_key_mappings
para especificar el reemplazo de claves en función de los nombres de las claves:
- El
--key_mapping src_key = dest_key
especifica el reemplazo de una clave a la vez. - El indicador de
--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
Use el --extra_apks apk_name1,apk_name2,... = key
para especificar los reemplazos de clave de firma según los nombres de APK. Si key
se deja vacía, la secuencia de comandos 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
Entonces firmarías todas las aplicaciones así:
./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 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, la secuencia de comandos vuelve a firmar todos los archivos APK en el .zip
de destino de entrada con las claves de liberación. Antes de ejecutar el comando, también puede establecer la variable de entorno ANDROID_PW_FILE
en un nombre de archivo temporal; la secuencia de comandos luego 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 presenta el formato de archivo APEX para instalar módulos de sistema de nivel inferior. Como se explica en la firma de 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 para un archivo APEX se reemplazan con 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 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 tienes los siguientes archivos que contienen las claves de lanzamiento:
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 lanzamiento. En particular, com.android.runtime.release.apex
se firma 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 son manejados por la configuración predeterminada como se indica 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
Ejecutar el comando anterior da 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 de todos los indicadores.
Generación manual de claves
Android usa 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 versión reales), reemplace el argumento -nocrypt
con -passout stdin
; luego, openssl cifrará la clave privada con una contraseña leída desde la entrada estándar. No se imprime ningún mensaje, por lo que si stdin es el terminal, el programa parecerá colgarse 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 información, consulte la documentación de openssl .
El archivo intermedio temp.pem contiene la clave privada sin ningún tipo de protección de contraseña, así que deséchelo cuidadosamente cuando genere claves de liberación. En particular, la utilidad GNUshred puede no ser efectiva en la red o en los sistemas de archivos registrados. Puede usar un directorio de trabajo ubicado en un disco RAM (como una partición tmpfs) al generar claves para asegurarse de que los intermedios no queden expuestos sin darse cuenta.
Creación de archivos de imagen
Una vez que haya firmado-target-files.zip, debe 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