Generación de firmas de sistema Android e integración de keystore en Android Studio

  1. Introducción a los archivos de firma de Android

¿Por qué es necesaria la firma?

Toda aplicación instalable requiere una firma. El propósito de firmar una app es demostrar que fue desarrollada por un autor específico. La firma establece una relación de confianza entre la aplicación y el desarrollador.

Garantías que ofrece el sistema Android mediante la firma:

  • Al obtener un paquete de instalación, se puede identificar al autor.
  • Al actualizar una app, se verifica que la nueva versión proviene del mismo autor.
  • Si se modifican archivos internos de la app, se puede detectar si el cambio fue realizado por el autor original.

Si la firma cambia, no es posible realizar una instalación por actualización.

Si no se especifica un archivo de firma, Android utiliza por defecto el debug.keystore ubicado en:

~/.android/debug.keystore

Los archivos de clave estándar de Android se encuentran en el directorio build/target/product/security del código fuente. Se usan principalmente para firmar APK compilados con Android.mk. Existen cuatro claves principales:

  • testkey: firma genérica para APK (usada por defecto).
  • platform: se usa cuando el AndroidManifest.xml incluye android:sharedUserId="android.uid.system" y en el Android.mk se agrega LOCAL_CERTIFICATE := platform.
  • shared: similar con android:sharedUserId="android.uid.shared" y LOCAL_CERTIFICATE := shared.
  • media: con android:sharedUserId="android.media" y LOCAL_CERTIFICATE := media.

En el archivo Android.mk de la aplicación, el campo LOCAL_CERTIFICATE especifica qué clave usar; si no se define, se toma testkey. En Android.bp se utiliza certificate: "platform".

Contenido del directorio build/target/product/security (ejemplo):

Android.bp  cts_uicc_2021.pk8          media.pk8         networkstack.x509.pem  shared.pk8       testkey.x509.pem  verity_key
Android.mk  cts_uicc_2021.x509.pem     media.x509.pem    platform.pk8           shared.x509.pem  testkey.pk8       verity.pk8
README      fsverity-release.x509.der  networkstack.pk8  platform.x509.pem      verity.x509.pem  verity.x509.pem

Los archivos .pk8 contienen la clave privada y los .x509.pem la clave pública; siempre se presentan en pares.

  1. Creación de claves personalizadas

2.1 Generar claves con make_key

Según el archivo README en build/target/product/security, las claves se generan con el script development/tools/make_key. Requiere dos parámetros: el nombre de la clave y los atributos X.509.

Significado de los atirbutos:

  • C — Código de país (2 letras)
  • ST — Estado o provincia
  • L — Localidad (ciudad)
  • O — Organización (empresa)
  • OU — Unidad organizativa
  • CN — Nombre común (nombre o host)
  • emailAddress — Correo de contacto

Durante la generación se puede solicitar una contraseña; basta con presionar Enter para omitirla.

2.2 Eliminar claves existentes

En el directorio build/target/product/security ejecutar:

rm ./*.p*

2.3 Generar nuevas claves

Desde la raíz del AOSP, ejecutar los siguientes comandos (ejemplo con datos ficticios):

./development/tools/make_key build/target/product/security/testkey '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/platform '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/media '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/shared '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/networkstack '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'
./development/tools/make_key build/target/product/security/verity '/C=CN/ST=Zhejiang/L=Ningbo/O=Android/OU=DEV/CN=example.com/emailAddress=dev@example.com'

2.4 Verificar las claves

Usar OpenSSL para comprobar que se generaron correctamente:

openssl x509 -noout -subject -issuer -in build/target/product/security/platform.x509.pem

Salida esperada (similar a):

subject=C = CN, ST = Zhejiang, L = Ningbo, O = Android, OU = DEV, CN = example.com, emailAddress = dev@example.com
issuer=C = CN, ST = Zhejiang, L = Ningbo, O = Android, OU = DEV, CN = example.com, emailAddress = dev@example.com

2.5 Modificar la clave predeterminada del sistema

Si un APK no especifica LOCAL_CERTIFICATE, se usa testkey. Se puede cambiar a una clave propia, por ejemplo releasekey.

  1. En build/core/config.mk cambiar:
    DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkey
    por
    DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/releasekey
  2. En build/core/Makefile.mk agregar (o modificar):
    ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/releasekey)  
       BUILD_VERSION_TAGS += release-keys
    
  3. Modificar los archivos system/sepolicy/private/keys.conf y system/sepolicy/prebuilts/api/{apilevel}/private/keys.conf (para todos los niveles de API):
    [@RELEASE]
    ENG       : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem
    USER      : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem
    USERDEBUG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem
    
  4. Recompilar el sistema. En build.prop se podrá ver ro.build.tags=release-keys.

2.6 Generar generate_verity_key

Compilar la herramienta:

make generate_verity_key
# o: mmm system/extras/verity/

Luego ejecutar:

out/host/linux-x86/bin/generate_verity_key -convert build/target/product/security/verity.x509.pem verity_key

Renombrar verity_key.pub a verity_key y copiarlo al directorio build/target/product/security/ reemplazando el existente.

Tras estos cambios, recompilar el sistema para usar las nuevas claves.

  1. Generar un keystore a partir de las claves del sistema

El keystore se utiliza para firmar aplicaciones externas. Tomamos como ejemplo la clave platform.

3.1 Obtener el archivo .pem de la clave privada

openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out platform.pem -nocrypt

3.2 Crear el archivo .p12 (PKCS12)

openssl pkcs12 -export -in platform.x509.pem -inkey platform.pem -out platform.pk12 -name myAlias

Se solicitará una contraseña; debe recordarse para el siguiente paso.

3.3 Convertir PKCS12 a JKS (keystore)

keytool -importkeystore -destkeystore platform.keystore -srckeystore platform.pk12 -srcstoretype PKCS12 -srcstorepass tu_contraseña -alias myAlias

Se generará platform.keystore listo para usar.

  1. Importar el keystore en Android Studio

Colocar el archivo platform.keystore en la carpeta app/ del proyecto.

Configurar el archivo build.gradle (nivel app) de la siguiente manera:

android {
    signingConfigs {
        main {
            storeFile file("platform.keystore")
            storePassword "tu_contraseña"
            keyAlias "myAlias"
            keyPassword "tu_contraseña"
        }
    }

    buildTypes {
        debug {
            minifyEnabled false
            signingConfig signingConfigs.main
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            signingConfig signingConfigs.main
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

Después de limpiar y reconstruir el proyecto, el APK generado tendrá la firma platform.

Referencias: Documentación oficial de AOSP sobre firmas y guías de reemplazo de claves del sistema.

Etiquetas: Android AOSP firma keystore platform

Publicado el 6-23 20:07