系统签名客制化——基于LineageOS21

系统签名客制化——基于LineageOS21

一、系统签名是什么

在Android中,系统签名是对其核心组件、应用程序和系统更新包以及一些其他系统组件进行数字签名的机制。该机制依赖于公钥加密体系,能确保系统中的关键文件以及应用程序都是可信任的来源,并且在传输、安装过程中未被篡改。

通常,系统签名由设备制造商(OEM厂商)或系统供应商(Google)持有,使用一对秘钥。其中私钥用于对秘钥系统中的核心部件、应用程序、OTA升级包等进行签名,公钥用于内置于系统中,用于验证私钥是否正确。Android系统中通过多个不同的签名来保证系统的完整性,使其不会被恶意篡改。

二、系统签名的类型:

通过查看`system/sepolicy/private/keys.conf`文件
#
# Maps an arbitrary tag [TAGNAME] with the string contents found in
# TARGET_BUILD_VARIANT. Common convention is to start TAGNAME with an @ and
# name it after the base file name of the pem file.
#
# Each tag (section) then allows one to specify any string found in
# TARGET_BUILD_VARIANT. Typcially this is user, eng, and userdebug. Another
# option is to use ALL which will match ANY TARGET_BUILD_VARIANT string.
#

[@PLATFORM]
ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/platform.x509.pem

[@SDK_SANDBOX]
ALL : $MAINLINE_SEPOLICY_DEV_CERTIFICATES/sdk_sandbox.x509.pem

[@BLUETOOTH]
ALL : $MAINLINE_SEPOLICY_DEV_CERTIFICATES/bluetooth.x509.pem

[@MEDIA]
ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/media.x509.pem

[@NETWORK_STACK]
ALL : $MAINLINE_SEPOLICY_DEV_CERTIFICATES/networkstack.x509.pem

[@NFC]
ALL : $MAINLINE_SEPOLICY_DEV_CERTIFICATES/nfc.x509.pem

[@SHARED]
ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/shared.x509.pem

# Example of ALL TARGET_BUILD_VARIANTS
[@RELEASE]
ENG       : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem
USER      : $DEFAULT_SYSTEM_DEV_CERTIFICATE/releasekey.x509.pem
USERDEBUG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem

就我们可知,Android中存在如下几种类型的系统签名:

  1. Platform 签名
    用于对具有 platform 权限的应用程序和系统核心组件(如 framework.jar 和 services.jar)进行签名。获得 Platform 签名的应用程序拥有系统的所有权限,能够执行系统级操作。然而,在使用 SeLinux 的系统中,某些操作可能受到 SeLinux 的限制,即使拥有 Platform 签名,也无法进行。
  2. SDK Sandbox 签名
    SDK_SANDBOX 签名用于对 Android SDK 沙箱内运行的组件进行签名。这些组件通常与开发者工具或新的运行时功能相关联。通过 SDK Sandbox 签名,系统可以保证这些组件只拥有特定的权限,不会影响系统的核心安全性。
  3. Bluetooth 签名
    BLUETOOTH 签名用于对系统中的蓝牙相关组件进行签名,包括蓝牙协议栈、蓝牙管理服务等。拥有 Bluetooth 签名的组件可以管理设备的蓝牙功能,例如配对、设备发现和蓝牙连接的权限。
  4. Media 签名
    MEDIA 签名专门用于对多媒体框架(如音频、视频、相机服务)相关的组件进行签名。被 Media 签名的应用或组件可以访问系统的多媒体资源,如音频管理、摄像头和媒体播放器的相关功能。
  5. Network Stack 签名
    NETWORK_STACK 签名用于对网络协议栈和网络管理相关的系统组件进行签名。网络堆栈签名的组件具有网络连接管理、流量控制和网络安全相关的权限,确保设备能够可靠地连接互联网和其他网络服务。
  6. NFC 签名
    NFC 签名用于对 NFC(近场通信)相关的系统组件进行签名。这些组件可以管理设备的 NFC 功能,包括 NFC 数据交换、支付功能以及设备间的快速配对。
  7. Shared 签名
    SHARED 签名用于那些需要在不同应用之间共享代码或数据的组件。共享签名允许这些应用程序运行在同一个进程中,共享相同的 UID,并能够直接访问彼此的数据和资源。这种签名通常用于一组紧密耦合的应用,例如 Google 的核心服务。
  8. Release 签名
    RELEASE 签名用于产品发布时对所有系统组件进行签名,确保发布的系统是完整的、可信的。这个签名文件通常会在发布固件包、OTA升级包的时候使用。当我们需要对系统进行OTA升级时我们会生成一个OTA整包或者差分包,OTA包的签名私钥必须与我们系统中内置的OTA公钥匹配才能成功升级。

通过这些不同类型的系统签名,Android 能够为系统中的不同组件和服务提供适当的权限和安全性。每个签名都有其特定的用途和作用范围,确保系统组件既能够正确运行,又能够维持整个系统的安全性与稳定性。

由于AOSP中自带了一个公开的秘钥,LineageOS没有针对签名做任何定制(即便是做了定制我们也需要重新生成,因为这个签名必须随源码发布才能使用),所以我们利用LineageOS编译出来的系统固件是默认使用公版签名的,一些APP厂商为了防止一些不法分子使用自定义的系统来做灰黑产业定制了一些反制策略,其中一项就有检测系统签名是否为公版签名,当我们使用这台机器来登录一些网络账号可能会导致被封号。另外若我们在开发产品时为了产品的安全性我们也要对系统签名做定制。

三、生成并指定默认系统签名

系统签名客制化的方案

我们系统中的签名文件位于`build/make/target/product/security`目录,该目录有一个Readme文档中描述如何编生成和使用签名。
For detailed information on key types and image signing, please see:

https://source.android.com/devices/tech/ota/sign_builds.html

The test keys in this directory are used in development only and should
NEVER be used to sign packages in publicly released images (as that would
open a major security hole).

key generation
--------------

The following commands were used to generate the test key pairs:

  development/tools/make_key testkey       '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
  development/tools/make_key platform      '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
  development/tools/make_key shared        '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
  development/tools/make_key media         '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
  development/tools/make_key cts_uicc_2021 '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

signing using the openssl commandline (for boot/system images)
--------------------------------------------------------------

1. convert pk8 format key to pem format
   % openssl pkcs8 -inform DER -nocrypt -in testkey.pk8 -out testkey.pem

2. create a signature using the pem format key
   % openssl dgst -binary -sha1 -sign testkey.pem FILE > FILE.sig

extracting public keys for embedding
------------------------------------

dumpkey.jar is a Java tool that takes an x.509 certificate in PEM format as
input and prints a C structure to standard output:

    $ java -jar out/host/linux-x86/framework/dumpkey.jar build/make/target/product/security/testkey.x509.pem
    {64,0xc926ad21,{1795090719,2141396315,950055447,2581568430,4268923165,1920809988,546586521,3498997798,1776797858,3740060814,1805317999,1429410244,129622599,1422441418,1783893377,1222374759,2563319927,323993566,28517732,609753416,1826472888,215237850,4261642700,4049082591,3228462402,774857746,154822455,2497198897,2758199418,3019015328,2794777644,87251430,2534927978,120774784,571297800,3695899472,2479925187,3811625450,3401832990,2394869647,3267246207,950095497,555058928,414729973,1136544882,3044590084,465547824,4058146728,2731796054,1689838846,3890756939,1048029507,895090649,247140249,178744550,3547885223,3165179243,109881576,3944604415,1044303212,3772373029,2985150306,3737520932,3599964420},{3437017481,3784475129,2800224972,3086222688,251333580,2131931323,512774938,325948880,2657486437,2102694287,3820568226,792812816,1026422502,2053275343,2800889200,3113586810,165549746,4273519969,4065247892,1902789247,772932719,3941848426,3652744109,216871947,3164400649,1942378755,3996765851,1055777370,964047799,629391717,2232744317,3910558992,191868569,2758883837,3682816752,2997714732,2702529250,3570700455,3776873832,3924067546,3555689545,2758825434,1323144535,61311905,1997411085,376844204,213777604,4077323584,9135381,1625809335,2804742137,2952293945,1117190829,4237312782,1825108855,3013147971,1111251351,2568837572,1684324211,2520978805,367251975,810756730,2353784344,1175080310}}

This is called by build/make/core/Makefile to incorporate the OTA signing keys
into the recovery image.

我们在定制签名的时候有两种方案:

  1. 生成新的签名替换原有系统签名文件
  • 优点
    • 直接替换即可使用:无需修改构建系统,生成新的签名后可以直接替换原有系统签名文件,整个过程比较简单快速。
    • 无需额外配置:不需要对 build 系统进行任何额外的配置调整,降低了配置复杂度。
    • 适合小规模定制:这种方法适合对系统进行小规模的定制修改时使用。
  • 缺点
    • 需要删除原有文件:必须手动删除系统中的原有签名文件,增加了操作步骤和出错的可能性。
    • 原有文件丢失问题:原有签名文件删除后可能无法恢复,除非备份,导致后续调试和回滚变得复杂。
    • 对系统更新的影响:在系统更新时,新的签名文件可能被覆盖,需要重新替换,增加维护成本。
    • 无法保留公版签名:不能同时保留公版和自定义签名,某些场景下可能不够灵活。
  1. 生成新的签名放置到特定的厂商目录,并通过配置 Product 或 build 系统来指定
  • 优点
    • 私有签名更加明确:通过放置在厂商目录中,可以更直观地看到使用的是厂商定制的私有签名,容易区分。
    • 无需删除公版签名:公版签名可以保留在系统中,且自定义签名和公版签名可以共存,便于调试和比较。
    • 与系统更新的兼容性更好:由于不需要直接替换原有签名文件,系统更新时自定义签名文件不会被覆盖,减少维护工作量。
  • 缺点
    • 需要修改构建系统:需要额外配置 Product 文件或修改 build 系统,使其指向新签名文件,增加了构建系统的复杂性。
    • 增加操作步骤:相比直接替换签名文件,需要配置路径,操作步骤相对较多。
    • 可能出现配置错误:若路径或配置出现问题,可能导致签名文件引用错误,影响系统编译和运行。

本文使用第二种方案来实现。

生成系统签名

首先我们需要使用`development/tools/make_key`工具生成一系列签名并存放到某个目录。执行一下`development/tools/make_key -h` 查看命令使用文档
Usage: development/tools/make_key <name> <subject> [<keytype>]

Creates <name>.pk8 key and <name>.x509.pem cert.  Cert contains the
given <subject>. A keytype of "rsa" or "ec" is accepted.

结合上一小节的README文档,可知我们生成时只需要输入name、subject两个参数,其中name为生成的文件名(经过试验,可在生成时输入相对路径,如name参数为 vendor/xxx/releasekey,则会在vendor/xxx/目录生成一个releasekey.pk8 和 一个releasekey.x509.pem密钥对),subject为一些描述信息,这些信息的意义如下:

'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'

C = 国家 (Country Name),通常为两位字母代码(如 CN 表示中国)
ST = 省或州 (State or Province Name),完整名称,如 Guangdong(广东省)
L = 城市 (Locality Name),如 Shenzhen(深圳)
O = 组织名称 (Organization Name),如 XXX
OU = 部门名称 (Organizational Unit Name),如 Android
CN = 通用名称 (Common Name),如 XXX(可以是组织或个人的名字)
emailAddress = 联系邮箱地址,如 xxx@xxx.ink

结合以上内容,我们可以得到如下命令:

development/tools/make_key vendor/xxx/security/releasekeys/releasekey 	'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/platform 		'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/media 				'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/sdk_sandbox 	'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/bluetooth 		'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/nfc 					'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/networkstack '/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/shared 			'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'
development/tools/make_key vendor/xxx/security/releasekeys/testkey 			'/C=CN/ST=Guangdong/L=Shenzhen/O=XXX/OU=Android/CN=XXX/emailAddress=xxx@xxx.com'

执行如上命令,生成密钥时会提示输入密码,若不需要设置密码直接回车将密码设置为空即可。

配置签名目录

通过`system/sepolicy/private/keys.conf`文件可知,密钥文件是通过变量`DEFAULT_SYSTEM_DEV_CERTIFICATE`与`MAINLINE_SEPOLICY_DEV_CERTIFICATES`,通过grep命令搜索,发现在`build/make/core/config.mk`文件下有如下内容
# The default key if not set as LOCAL_CERTIFICATE
ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
  DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
else
  DEFAULT_SYSTEM_DEV_CERTIFICATE := build/make/target/product/security/testkey
endif
.KATI_READONLY := DEFAULT_SYSTEM_DEV_CERTIFICATE

# Certificate for the NetworkStack sepolicy context
ifdef PRODUCT_MAINLINE_SEPOLICY_DEV_CERTIFICATES
  MAINLINE_SEPOLICY_DEV_CERTIFICATES := $(PRODUCT_MAINLINE_SEPOLICY_DEV_CERTIFICATES)
else
  MAINLINE_SEPOLICY_DEV_CERTIFICATES := $(dir $(DEFAULT_SYSTEM_DEV_CERTIFICATE))
endif

其规则如下:

若在产品配置中定义了PRODUCT_DEFAULT_DEV_CERTIFICATEDEFAULT_SYSTEM_DEV_CERTIFICATE取其值,否则使用默认值build/make/target/product/security/testkey

若配置了PRODUCT_MAINLINE_SEPOLICY_DEV_CERTIFICATESMAINLINE_SEPOLICY_DEV_CERTIFICATES取其值,否则读取DEFAULT_SYSTEM_DEV_CERTIFICATE的文件夹路径即build/make/target/product/security

在上一小节我们生成签名文件时,是将所有签名文件都放置到一个目录的,因此我们将DEFAULT_SYSTEM_DEV_CERTIFICATE的默认值修改为我们生成签名文件的位置即可。

注意:这里要写的是签名文件不带后缀的路径,如我们的签名文件为**vendor/xxx/security/releasekeys/**目录下的**releasekey**则应改为vendor/xxx/security/releasekeys/releasekey

修改为如下内容:

# The default key if not set as LOCAL_CERTIFICATE
ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
  DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
else
  DEFAULT_SYSTEM_DEV_CERTIFICATE := vendor/xxx/security/releasekeys/releasekey
endif
.KATI_READONLY := DEFAULT_SYSTEM_DEV_CERTIFICATE

# Certificate for the NetworkStack sepolicy context
ifdef PRODUCT_MAINLINE_SEPOLICY_DEV_CERTIFICATES
  MAINLINE_SEPOLICY_DEV_CERTIFICATES := $(PRODUCT_MAINLINE_SEPOLICY_DEV_CERTIFICATES)
else
  MAINLINE_SEPOLICY_DEV_CERTIFICATES := $(dir $(DEFAULT_SYSTEM_DEV_CERTIFICATE))
endif

修改build.tags属性值

修改了以上内容之后我们编译出的系统固件已经使用了修改之后的签名秘钥了,但是我们发现通过`adb shell getprop`读出的几个ro.*.build.tags 属性值还是test-keys,我们应该在使用releasekey的时候使其显示release-keys才对。

通过检索,发现在build/make/core/sysprop.mk文件下发现如下内容

# The "test-keys" tag marks builds signed with the old test keys,
# which are available in the SDK.  "dev-keys" marks builds signed with
# non-default dev keys (usually private keys from a vendor directory).
# Both of these tags will be removed and replaced with "release-keys"
# when the target-files is signed in a post-build step.
ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/make/target/product/security/testkey)
BUILD_KEYS := test-keys
else
BUILD_KEYS := dev-keys
endif

我们将其修改为如下内容

ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/make/target/product/security/testkey)
BUILD_KEYS := test-keys
else ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),vendor/xxx/security/releasekeys/releasekey)
BUILD_KEYS := release-keys
else
BUILD_KEYS := dev-keys
endif

我们添加了一个判断分支,当使用的是我们生成的releasekey时则使BUILD_KEYS为release-keys

修改Patch

本文Patch如下:

build/make

diff --git a/core/config.mk b/core/config.mk
index a8a5e5f711..acf6ab3cfb 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -858,7 +858,8 @@ endif
 ifdef PRODUCT_DEFAULT_DEV_CERTIFICATE
   DEFAULT_SYSTEM_DEV_CERTIFICATE := $(PRODUCT_DEFAULT_DEV_CERTIFICATE)
 else
-  DEFAULT_SYSTEM_DEV_CERTIFICATE := build/make/target/product/security/testkey
+  # DEFAULT_SYSTEM_DEV_CERTIFICATE := build/make/target/product/security/testkey
+  DEFAULT_SYSTEM_DEV_CERTIFICATE := vendor/xxx/security/releasekeys/releasekey
 endif
 .KATI_READONLY := DEFAULT_SYSTEM_DEV_CERTIFICATE
 
diff --git a/core/sysprop.mk b/core/sysprop.mk
index 0fcc92c84f..e3b59305ae 100644
--- a/core/sysprop.mk
+++ b/core/sysprop.mk
@@ -179,6 +179,8 @@ endif
 # when the target-files is signed in a post-build step.
 ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/make/target/product/security/testkey)
 BUILD_KEYS := test-keys
+else ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),vendor/xxx/security/releasekeys/releasekey) # 修改build.tags值
+BUILD_KEYS := release-keys
 else
 BUILD_KEYS := dev-keys
 endif

ps:使用adb sideload 升级系统需要恢复出厂设置或利用Recovery进行双清操作,否则会导致蓝牙与nfc相关应用crash,且移动网络与Wifi无法连接

四、参考文献

[Android 系统生成 releasekey——https://developer.aliyun.com/article/1197564](https://developer.aliyun.com/article/1197564)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值