APK v4 签名方案验证过程

Android 11 引入了 v4 签名方案来支持增量安装APK,其验证过程时序图如下:

1. PackageManagerService.addForInitLI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
// 在平台初始化期间向内部数据结构添加一个新包。添加后,该包对于系统是已知的,并且可以查询。
// 对于位于设备ROM上的软件包[例如位于 system,vendor 等的软件包中,则执行其他检查。
// 如果程序包与以前已知的程序包相同,则会进行基本验证(例如确保匹配的签名,检查版本代码等)。
// 如果软件包未通过签名检查,则将删除 data 上安装的版本。如果新软件包的版本小于/等于 data上的版本,它将被忽略。
// 无论包的位置如何,结果都将应用于内部结构,并且包可用于系统的其余部分。返回值应删除。 这是传入的包对象。
@GuardedBy({"mInstallLock", "mLock"})
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
final boolean scanSystemPartition = (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
final String renamedPkgName;
final PackageSetting disabledPkgSetting;
final boolean isSystemPkgUpdated;
final boolean pkgAlreadyExists;
PackageSetting pkgSetting;
// installPackageLI() 具有相同的代码来设置软件包的应用信息。
// 这可能应该在调用堆栈中的较低位置进行,例如 scanPackageOnly()。但是在 scanPackageNew() 中之前验证了应用信息,因此必须尽早设置应用信息。
synchronized (mLock) {
renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage());
final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName);
if (realPkgName != null) {
ensurePackageRenamed(parsedPackage, renamedPkgName);
}
final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage,
renamedPkgName);
final PackageSetting installedPkgSetting = mSettings.getPackageLPr(
parsedPackage.getPackageName());
pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting;
pkgAlreadyExists = pkgSetting != null;
final String disabledPkgName = pkgAlreadyExists
? pkgSetting.name : parsedPackage.getPackageName();
if (scanSystemPartition && !pkgAlreadyExists
&& mSettings.getDisabledSystemPkgLPr(disabledPkgName) != null) {
// 在 data apk 的数据意外丢失后, system apk 的升级数据与之不一致。为了恢复它,需启用 system apk 并将其安装为未升级的系统应用。
Slog.w(TAG, "Inconsistent package setting of updated system app for "
+ disabledPkgName + ". To recover it, enable the system app"
+ "and install it as non-updated system app.");
mSettings.removeDisabledSystemPackageLPw(disabledPkgName);
}
disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName);
isSystemPkgUpdated = disabledPkgSetting != null;
if (DEBUG_INSTALL && isSystemPkgUpdated) {
Slog.d(TAG, "updatedPkg = " + disabledPkgSetting);
}
final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null)
? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
: null;
if (DEBUG_PACKAGE_SCANNING
&& (parseFlags & PackageParser.PARSE_CHATTY) != 0
&& sharedUserSetting != null) {
Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
+ " (uid=" + sharedUserSetting.userId + "):"
+ " packages=" + sharedUserSetting.packages);
}
if (scanSystemPartition) {
// 如果 system 分区上的应用已通过 OTA 更新,但 data 上的版本扔被禁用,则遍历其所有子程序包并删除不再定义的子程序。
if (isSystemPkgUpdated) {
boolean isPlatformPackage = mPlatformPackage != null
&& Objects.equals(mPlatformPackage.getPackageName(),
parsedPackage.getPackageName());
// 对正在升级的禁用的软件包进行扫描设置。
final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting,
null, disabledPkgSetting /* pkgSetting */,
null /* disabledPkgSetting */, null /* originalPkgSetting */,
null, parseFlags, scanFlags, isPlatformPackage, user, null);
applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage, true);
final ScanResult scanResult =
scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L);
if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) {
scanResult.request.pkgSetting.updateFrom(scanResult.pkgSetting);
}
}
}
}
final boolean newPkgChangedPaths =
pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath());
final boolean newPkgVersionGreater =
pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
&& newPkgChangedPaths && newPkgVersionGreater;
if (isSystemPkgBetter) {
// 如果 system 上的应用版本大于 data 上的版本,则切到 system 上的应用。
// 假设 system 上的应用都将被正确扫描,否则将没有该应用的副本。
synchronized (mLock) {
// 只需从软件包列表中删除已加载的条目。
mPackages.remove(pkgSetting.name);
}
logCriticalInfo(Log.WARN,
"System package updated;"
+ " name: " + pkgSetting.name
+ "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
+ "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath());
final InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(
pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
args.cleanUpResourcesLI();
synchronized (mLock) {
mSettings.enableSystemPackageLPw(pkgSetting.name);
}
}
if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
// 如果 system 分区上的应用版本小于 data 分区上的版本,则触发异常并使用 data 分区上已安装的应用。
throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName()
+ " at " + parsedPackage.getCodePath() + " ignored: updated version "
+ pkgSetting.versionCode + " better than this "
+ parsedPackage.getLongVersionCode());
}
// 如果进行了升级,并且这是系统分区中的一个应用,或者这是升级的 priv-app,则将强制重新收集证书。
final boolean forceCollect = scanSystemPartition ? mIsUpgrade
: PackageManagerServiceUtils.isApkVerificationForced(pkgSetting);
if (DEBUG_VERIFY && forceCollect) {
Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName());
}
// 仅 APK 位于经过验证的分区时,或在访问时跳过强制验证时,才可以跳过完整的 APK 验证,而改为仅验证签名块中的数据。
final boolean skipVerify = scanSystemPartition
|| (forceCollect && canSkipForcedPackageVerification(parsedPackage));
collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify);
// 如果更改了应用版本,则重置配置文件。
maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage);
// 出现了一个新的系统应用,但是之前已经安装了一个非系统的同名应用。
boolean shouldHideSystemApp = false;
if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists
&& !pkgSetting.isSystem()) {
if (!parsedPackage.getSigningDetails()
.checkCapability(pkgSetting.signatures.mSigningDetails,
PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
&& !pkgSetting.signatures.mSigningDetails.checkCapability(
parsedPackage.getSigningDetails(),
PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
logCriticalInfo(Log.WARN,
"System package signature mismatch;"
+ " name: " + pkgSetting.name);
try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage(
parsedPackage.getPackageName(),
"scanPackageInternalLI")) {
deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null,
false, null);
}
pkgSetting = null;
} else if (newPkgVersionGreater) {
// system 上的应用比 data 上的应用新。只需删除 data 上的应用[保留应用程序数据],然后将其替换为 system 上的版本。
logCriticalInfo(Log.WARN,
"System package enabled;"
+ " name: " + pkgSetting.name
+ "; " + pkgSetting.versionCode + " --> "
+ parsedPackage.getLongVersionCode()
+ "; " + pkgSetting.codePathString + " --> "
+ parsedPackage.getCodePath());
InstallArgs args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(
pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
} else {
// system 上的应用比 data 上的应用旧。则隐藏 system 上的应用, data 上的版本将在以后扫描并像升级一样重新被添加。
shouldHideSystemApp = true;
logCriticalInfo(Log.INFO,
"System package disabled;"
+ " name: " + pkgSetting.name
+ "; old: " + pkgSetting.codePathString + " @ "
+ pkgSetting.versionCode
+ "; new: " + parsedPackage.getCodePath() + " @ "
+ parsedPackage.getCodePath());
}
}
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user, null);
if (scanResult.success) {
synchronized (mLock) {
boolean appIdCreated = false;
try {
final String pkgName = scanResult.pkgSetting.name;
final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
new ReconcileRequest(
Collections.singletonMap(pkgName, scanResult),
mSharedLibraries,
mPackages,
Collections.singletonMap(
pkgName, getSettingsVersionForPackage(parsedPackage)),
Collections.singletonMap(pkgName,
getSharedLibLatestVersionSetting(scanResult))),
mSettings.mKeySetManagerService);
appIdCreated = optimisticallyRegisterAppId(scanResult);
commitReconciledScanResultLocked(
reconcileResult.get(pkgName), mUserManager.getUserIds());
} catch (PackageManagerException e) {
if (appIdCreated) {
cleanUpAppIdCreation(scanResult);
}
throw e;
}
}
}
if (shouldHideSystemApp) {
synchronized (mLock) {
mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
}
}
return scanResult.pkgSetting.pkg;
}

2. PackageManagerService.collectCertificatesLI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage,
boolean forceCollect, boolean skipVerify) throws PackageManagerException {
// 若是从 pre-N MR1 升级上来的,则使用软件包目录的时间戳,否则使用 APK 文件来的时间戳。
final long lastModifiedTime = mIsPreNMR1Upgrade
? new File(parsedPackage.getCodePath()).lastModified()
: getLastModifiedTime(parsedPackage);
final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
if (ps != null && !forceCollect
&& ps.codePathString.equals(parsedPackage.getCodePath())
&& ps.timeStamp == lastModifiedTime
&& !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
&& !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
if (ps.signatures.mSigningDetails.signatures != null
&& ps.signatures.mSigningDetails.signatures.length != 0
&& ps.signatures.mSigningDetails.signatureSchemeVersion
!= SignatureSchemeVersion.UNKNOWN) {
// 如果程序包没有变化,则继续使用现有的缓存签名数据。
parsedPackage.setSigningDetails(
new PackageParser.SigningDetails(ps.signatures.mSigningDetails));
return;
}
Slog.w(TAG, "PackageSetting for " + ps.name
+ " is missing signatures. Collecting certs again to recover them.");
} else {
Slog.i(TAG, parsedPackage.getCodePath() + " changed; collecting certs" +
(forceCollect ? " (forced)" : ""));
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
parsedPackage.setSigningDetails(
ParsingPackageUtils.getSigningDetails(parsedPackage, skipVerify));
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

3. PackageParser.setSigningDetails

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// frameworks/base/core/java/android/content/pm/PackageParser.java
public final static class Package implements Parcelable {
...
public void setSigningDetails(@NonNull SigningDetails signingDetails) {
mSigningDetails = signingDetails;
if (childPackages != null) {
final int packageCount = childPackages.size();
for (int i = 0; i < packageCount; i++) {
childPackages.get(i).mSigningDetails = signingDetails;
}
}
}
...
}

4. ParsingPackageUtils.getSigningDetails

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
// 从指定的 APK 中收集证书,判断所有 APK 内容是否已被正确签名。
// 如果被请求,则在原始解析调用期间取消此操作以收集证书。将其保留为调用方的可选方法意味着必须构造一个虚拟 ParseInput。
@CheckResult
public static SigningDetails getSigningDetails(ParsingPackageRead pkg, boolean skipVerify)
throws PackageParserException {
SigningDetails signingDetails = SigningDetails.UNKNOWN;
ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
ParseResult<SigningDetails> result = getSigningDetails(
input,
pkg.getBaseCodePath(),
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
if (result.isError()) {
throw new PackageParser.PackageParserException(result.getErrorCode(),
result.getErrorMessage(), result.getException());
}
signingDetails = result.getResult();
String[] splitCodePaths = pkg.getSplitCodePaths();
if (!ArrayUtils.isEmpty(splitCodePaths)) {
for (int i = 0; i < splitCodePaths.length; i++) {
result = getSigningDetails(
input,
splitCodePaths[i],
skipVerify,
pkg.isStaticSharedLibrary(),
signingDetails,
pkg.getTargetSdkVersion()
);
if (result.isError()) {
throw new PackageParser.PackageParserException(result.getErrorCode(),
result.getErrorMessage(), result.getException());
}
signingDetails = result.getResult();
}
}
return signingDetails;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
@CheckResult
public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary,
@NonNull SigningDetails existingSigningDetails, int targetSdk) {
// android r及以上版本系统最低支持的 apk 签名是v2,android r以下系统支持最低的 apk 签名是v1。
int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
targetSdk);
// 静态共享库必须使用v2版本签名。
if (isStaticSharedLibrary) {
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
SigningDetails verified;
try {
if (skipVerify) {
// 仅限系统分区的 APK,因为默认系统分区 APK 已获得信任,无需再验证以节省时间。
// 因为这些应用签名没有验证,且部分系统应用的 v2 签名可以被移除,因为支持从 jar 签名(v1)获取证书。
verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(
baseCodePath, SigningDetails.SignatureSchemeVersion.JAR);
} else {
// 验证 APK 的签名返回证书。
verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme);
}
} catch (PackageParserException e) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed collecting certificates for " + baseCodePath, e);
}
// 验证条目是否与遇到的第一个 APK 包签名一致。证书可能已经在基 APK 的较早解析期间被填充了。
if (existingSigningDetails == SigningDetails.UNKNOWN) {
return input.success(verified);
} else {
if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) {
return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
baseCodePath + " has mismatched certificates");
}
return input.success(existingSigningDetails);
}
}

5. ApkSignatureVerifier.verify

1
2
3
4
5
6
7
// frameworks/base/core/java/android/util/apk/ApkSignatureVerifier.java
// 验证 APK 并返回与每个签名者关联的证书。
public static PackageParser.SigningDetails verify(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion)
throws PackageParserException {
return verifySignatures(apkPath, minSignatureSchemeVersion, true);
}

6. ApkSignatureVerifier.verifySignatures

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// frameworks/base/core/java/android/util/apk/ApkSignatureVerifier.java
private static PackageParser.SigningDetails verifySignatures(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws PackageParserException {
// 最高支持 v4 版本签名。
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V4) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
// 验证v4版本的签名的 APK。
try {
return verifyV4Signature(apkPath, minSignatureSchemeVersion, verifyFull);
} catch (SignatureNotFoundException e) {
if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V4) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No APK Signature Scheme v4 signature in package " + apkPath, e);
}
}
if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"No signature found in package of version " + minSignatureSchemeVersion
+ " or newer for package " + apkPath);
}
// 验证v3及更低版本签名的 APK。
return verifyV3AndBelowSignatures(apkPath, minSignatureSchemeVersion, verifyFull);
}

7. ApkSignatureSchemeV4Verifier.verifyV4Signature

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
// 验证V4签名版本的APK的签名
private static PackageParser.SigningDetails verifyV4Signature(String apkPath,
@SignatureSchemeVersion int minSignatureSchemeVersion, boolean verifyFull)
throws SignatureNotFoundException, PackageParserException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV4" : "certsOnlyV4");
try {
ApkSignatureSchemeV4Verifier.VerifiedSigner vSigner =
ApkSignatureSchemeV4Verifier.extractCertificates(apkPath);
Certificate[][] signerCerts = new Certificate[][]{vSigner.certs};
Signature[] signerSigs = convertToSignatures(signerCerts);
if (verifyFull) {
byte[] nonstreamingDigest = null;
Certificate[][] nonstreamingCerts = null;
try {
// v4是附加组件,需要v2或v3签名才能针对其证书和摘要进行验证。
ApkSignatureSchemeV3Verifier.VerifiedSigner v3Signer =
ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
nonstreamingDigest = v3Signer.digest;
nonstreamingCerts = new Certificate[][]{v3Signer.certs};
} catch (SignatureNotFoundException e) {
try {
ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer =
ApkSignatureSchemeV2Verifier.verify(apkPath, false);
nonstreamingDigest = v2Signer.digest;
nonstreamingCerts = v2Signer.certs;
} catch (SignatureNotFoundException ee) {
throw new SecurityException(
"V4 verification failed to collect V2/V3 certificates from : "
+ apkPath, ee);
}
}
Signature[] nonstreamingSigs = convertToSignatures(nonstreamingCerts);
if (nonstreamingSigs.length != signerSigs.length) {
throw new SecurityException(
"Invalid number of certificates: " + nonstreamingSigs.length);
}
for (int i = 0, size = signerSigs.length; i < size; ++i) {
if (!nonstreamingSigs[i].equals(signerSigs[i])) {
throw new SecurityException(
"V4 signature certificate does not match V2/V3");
}
}
if (!ArrayUtils.equals(vSigner.apkDigest, nonstreamingDigest,
vSigner.apkDigest.length)) {
throw new SecurityException("APK digest in V4 signature does not match V2/V3");
}
}
return new PackageParser.SigningDetails(signerSigs,
SignatureSchemeVersion.SIGNING_BLOCK_V4);
} catch (SignatureNotFoundException e) {
throw e;
} catch (Exception e) {
// 找到v4版本APK签名方案,但未验证。
throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
"Failed to collect certificates from " + apkPath
+ " using APK Signature Scheme v4", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}

8. ApkSignatureSchemeV4Verifier.extractCertificates

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
// 提取并验证提供的APK的APK签名方案v4签名,并返回与每个签名者关联的证书。
public static VerifiedSigner extractCertificates(String apkFile)
throws SignatureNotFoundException, SecurityException {
final File apk = new File(apkFile);
final byte[] signatureBytes = IncrementalManager.unsafeGetFileSignature(
apk.getAbsolutePath());
if (signatureBytes == null || signatureBytes.length == 0) {
throw new SignatureNotFoundException("Failed to obtain signature bytes from IncFS.");
}
final V4Signature signature;
final V4Signature.HashingInfo hashingInfo;
final V4Signature.SigningInfo signingInfo;
try {
signature = V4Signature.readFrom(signatureBytes);
if (!signature.isVersionSupported()) {
throw new SecurityException(
"v4 signature version " + signature.version + " is not supported");
}
hashingInfo = V4Signature.HashingInfo.fromByteArray(signature.hashingInfo);
signingInfo = V4Signature.SigningInfo.fromByteArray(signature.signingInfo);
} catch (IOException e) {
throw new SignatureNotFoundException("Failed to read V4 signature.", e);
}
final byte[] signedData = V4Signature.getSigningData(apk.length(), hashingInfo,
signingInfo);
return verifySigner(signingInfo, signedData);
}

9. ApkSignatureSchemeV4Verifier.verifySigner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
private static VerifiedSigner verifySigner(V4Signature.SigningInfo signingInfo,
final byte[] signedData) throws SecurityException {
if (!isSupportedSignatureAlgorithm(signingInfo.signatureAlgorithmId)) {
throw new SecurityException("No supported signatures found");
}
final int signatureAlgorithmId = signingInfo.signatureAlgorithmId;
final byte[] signatureBytes = signingInfo.signature;
final byte[] publicKeyBytes = signingInfo.publicKey;
final byte[] encodedCert = signingInfo.certificate;
String keyAlgorithm = getSignatureAlgorithmJcaKeyAlgorithm(signatureAlgorithmId);
Pair<String, ? extends AlgorithmParameterSpec> signatureAlgorithmParams =
getSignatureAlgorithmJcaSignatureAlgorithm(signatureAlgorithmId);
String jcaSignatureAlgorithm = signatureAlgorithmParams.first;
AlgorithmParameterSpec jcaSignatureAlgorithmParams = signatureAlgorithmParams.second;
boolean sigVerified;
try {
PublicKey publicKey =
KeyFactory.getInstance(keyAlgorithm)
.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
Signature sig = Signature.getInstance(jcaSignatureAlgorithm);
sig.initVerify(publicKey);
if (jcaSignatureAlgorithmParams != null) {
sig.setParameter(jcaSignatureAlgorithmParams);
}
sig.update(signedData);
sigVerified = sig.verify(signatureBytes);
} catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException
| InvalidAlgorithmParameterException | SignatureException e) {
throw new SecurityException(
"Failed to verify " + jcaSignatureAlgorithm + " signature", e);
}
if (!sigVerified) {
throw new SecurityException(jcaSignatureAlgorithm + " signature did not verify");
}
// 签名数据已经被验证。
CertificateFactory certFactory;
try {
certFactory = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
throw new RuntimeException("Failed to obtain X.509 CertificateFactory", e);
}
X509Certificate certificate;
try {
certificate = (X509Certificate)
certFactory.generateCertificate(new ByteArrayInputStream(encodedCert));
} catch (CertificateException e) {
throw new SecurityException("Failed to decode certificate", e);
}
certificate = new VerbatimX509Certificate(certificate, encodedCert);
byte[] certificatePublicKeyBytes = certificate.getPublicKey().getEncoded();
if (!Arrays.equals(publicKeyBytes, certificatePublicKeyBytes)) {
throw new SecurityException(
"Public key mismatch between certificate and signature record");
}
return new VerifiedSigner(new Certificate[]{certificate}, signingInfo.apkDigest);
}

10. ApkSignatureSchemeV2Verifier.isSupportedSignatureAlgorithm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// frameworks/base/core/java/android/util/apk/ApkSigningBlockUtils.java
static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
case SIGNATURE_RSA_PSS_WITH_SHA512:
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
case SIGNATURE_ECDSA_WITH_SHA256:
case SIGNATURE_ECDSA_WITH_SHA512:
case SIGNATURE_DSA_WITH_SHA256:
case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
case SIGNATURE_VERITY_DSA_WITH_SHA256:
return true;
default:
return false;
}
}

11. ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// frameworks/base/core/java/android/util/apk/ApkSigningBlockUtils.java
static String getSignatureAlgorithmJcaKeyAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
case SIGNATURE_RSA_PSS_WITH_SHA512:
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
return "RSA";
case SIGNATURE_ECDSA_WITH_SHA256:
case SIGNATURE_ECDSA_WITH_SHA512:
case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
return "EC";
case SIGNATURE_DSA_WITH_SHA256:
case SIGNATURE_VERITY_DSA_WITH_SHA256:
return "DSA";
default:
throw new IllegalArgumentException(
"Unknown signature algorithm: 0x"
+ Long.toHexString(sigAlgorithm & 0xffffffff));
}
}

12. ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// frameworks/base/core/java/android/util/apk/ApkSigningBlockUtils.java
static Pair<String, ? extends AlgorithmParameterSpec>
getSignatureAlgorithmJcaSignatureAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
return Pair.create(
"SHA256withRSA/PSS",
new PSSParameterSpec(
"SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 256 / 8, 1));
case SIGNATURE_RSA_PSS_WITH_SHA512:
return Pair.create(
"SHA512withRSA/PSS",
new PSSParameterSpec(
"SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 512 / 8, 1));
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA256:
case SIGNATURE_VERITY_RSA_PKCS1_V1_5_WITH_SHA256:
return Pair.create("SHA256withRSA", null);
case SIGNATURE_RSA_PKCS1_V1_5_WITH_SHA512:
return Pair.create("SHA512withRSA", null);
case SIGNATURE_ECDSA_WITH_SHA256:
case SIGNATURE_VERITY_ECDSA_WITH_SHA256:
return Pair.create("SHA256withECDSA", null);
case SIGNATURE_ECDSA_WITH_SHA512:
return Pair.create("SHA512withECDSA", null);
case SIGNATURE_DSA_WITH_SHA256:
case SIGNATURE_VERITY_DSA_WITH_SHA256:
return Pair.create("SHA256withDSA", null);
default:
throw new IllegalArgumentException(
"Unknown signature algorithm: 0x"
+ Long.toHexString(sigAlgorithm & 0xffffffff));
}
}

13. ApkSignatureSchemeV4Verifier.VerifiedSigner

1
2
3
4
5
6
7
8
9
// frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
public static class VerifiedSigner {
public final Certificate[] certs;
public byte[] apkDigest;
public VerifiedSigner(Certificate[] certs, byte[] apkDigest) {
this.certs = certs;
this.apkDigest = apkDigest;
}
}

14. ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification

1
2
3
4
5
// frameworks/base/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
public static VerifiedSigner unsafeGetCertsWithoutVerification(String apkFile)
throws SignatureNotFoundException, SecurityException, IOException {
return verify(apkFile, false);
}

15. ApkSignatureVerifier.convertToSignatures

1
2
3
4
5
6
7
8
9
10
// frameworks/base/core/java/android/util/apk/ApkSignatureVerifier.java
// 将证书链数组转换为PackageManager使用的等效签名。
private static Signature[] convertToSignatures(Certificate[][] certs)
throws CertificateEncodingException {
final Signature[] res = new Signature[certs.length];
for (int i = 0; i < certs.length; i++) {
res[i] = new Signature(certs[i]);
}
return res;
}