Loading core/java/android/content/pm/PackageParser.java +144 −5 Original line number Diff line number Diff line Loading @@ -5684,23 +5684,74 @@ public class PackageParser { @Nullable public final ArraySet<PublicKey> publicKeys; /** * Collection of {@code Signature} objects, each of which is formed from a former signing * certificate of this APK before it was changed by signing certificate rotation. */ @Nullable public final Signature[] pastSigningCertificates; /** * Flags for the {@code pastSigningCertificates} collection, which indicate the capabilities * the including APK wishes to grant to its past signing certificates. */ @Nullable public final int[] pastSigningCertificatesFlags; /** A representation of unknown signing details. Use instead of null. */ public static final SigningDetails UNKNOWN = new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null); new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null, null, null); @VisibleForTesting public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion, ArraySet<PublicKey> keys) { ArraySet<PublicKey> keys, Signature[] pastSigningCertificates, int[] pastSigningCertificatesFlags) { this.signatures = signatures; this.signatureSchemeVersion = signatureSchemeVersion; this.publicKeys = keys; this.pastSigningCertificates = pastSigningCertificates; this.pastSigningCertificatesFlags = pastSigningCertificatesFlags; } public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion, Signature[] pastSigningCertificates, int[] pastSigningCertificatesFlags) throws CertificateException { this(signatures, signatureSchemeVersion, toSigningKeys(signatures), pastSigningCertificates, pastSigningCertificatesFlags); } public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion) throws CertificateException { this(signatures, signatureSchemeVersion, toSigningKeys(signatures)); this(signatures, signatureSchemeVersion, null, null); } public SigningDetails(SigningDetails orig) { if (orig != null) { if (orig.signatures != null) { this.signatures = orig.signatures.clone(); } else { this.signatures = null; } this.signatureSchemeVersion = orig.signatureSchemeVersion; this.publicKeys = new ArraySet<>(orig.publicKeys); if (orig.pastSigningCertificates != null) { this.pastSigningCertificates = orig.pastSigningCertificates.clone(); this.pastSigningCertificatesFlags = orig.pastSigningCertificatesFlags.clone(); } else { this.pastSigningCertificates = null; this.pastSigningCertificatesFlags = null; } } else { this.signatures = null; this.signatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; this.publicKeys = null; this.pastSigningCertificates = null; this.pastSigningCertificatesFlags = null; } } /** Returns true if the signing details have one or more signatures. */ Loading Loading @@ -5728,6 +5779,8 @@ public class PackageParser { dest.writeTypedArray(this.signatures, flags); dest.writeInt(this.signatureSchemeVersion); dest.writeArraySet(this.publicKeys); dest.writeTypedArray(this.pastSigningCertificates, flags); dest.writeIntArray(this.pastSigningCertificatesFlags); } protected SigningDetails(Parcel in) { Loading @@ -5735,6 +5788,8 @@ public class PackageParser { this.signatures = in.createTypedArray(Signature.CREATOR); this.signatureSchemeVersion = in.readInt(); this.publicKeys = (ArraySet<PublicKey>) in.readArraySet(boot); this.pastSigningCertificates = in.createTypedArray(Signature.CREATOR); this.pastSigningCertificatesFlags = in.createIntArray(); } public static final Creator<SigningDetails> CREATOR = new Creator<SigningDetails>() { Loading @@ -5761,8 +5816,23 @@ public class PackageParser { if (signatureSchemeVersion != that.signatureSchemeVersion) return false; if (!Signature.areExactMatch(signatures, that.signatures)) return false; return publicKeys != null ? publicKeys.equals(that.publicKeys) : that.publicKeys == null; if (publicKeys != null) { if (!publicKeys.equals((that.publicKeys))) { return false; } } else if (that.publicKeys != null) { return false; } // can't use Signature.areExactMatch() because order matters with the past signing certs if (!Arrays.equals(pastSigningCertificates, that.pastSigningCertificates)) { return false; } if (!Arrays.equals(pastSigningCertificatesFlags, that.pastSigningCertificatesFlags)) { return false; } return true; } @Override Loading @@ -5770,8 +5840,77 @@ public class PackageParser { int result = +Arrays.hashCode(signatures); result = 31 * result + signatureSchemeVersion; result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0); result = 31 * result + Arrays.hashCode(pastSigningCertificates); result = 31 * result + Arrays.hashCode(pastSigningCertificatesFlags); return result; } /** * Builder of {@code SigningDetails} instances. */ public static class Builder { private Signature[] mSignatures; private int mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; private Signature[] mPastSigningCertificates; private int[] mPastSigningCertificatesFlags; public Builder() { } /** get signing certificates used to sign the current APK */ public Builder setSignatures(Signature[] signatures) { mSignatures = signatures; return this; } /** set the signature scheme version used to sign the APK */ public Builder setSignatureSchemeVersion(int signatureSchemeVersion) { mSignatureSchemeVersion = signatureSchemeVersion; return this; } /** set the signing certificates by which the APK proved it can be authenticated */ public Builder setPastSigningCertificates(Signature[] pastSigningCertificates) { mPastSigningCertificates = pastSigningCertificates; return this; } /** set the flags for the {@code pastSigningCertificates} */ public Builder setPastSigningCertificatesFlags(int[] pastSigningCertificatesFlags) { mPastSigningCertificatesFlags = pastSigningCertificatesFlags; return this; } private void checkInvariants() { // must have signatures and scheme version set if (mSignatures == null) { throw new IllegalStateException("SigningDetails requires the current signing" + " certificates."); } // pastSigningCerts and flags must match up boolean pastMismatch = false; if (mPastSigningCertificates != null && mPastSigningCertificatesFlags != null) { if (mPastSigningCertificates.length != mPastSigningCertificatesFlags.length) { pastMismatch = true; } } else if (!(mPastSigningCertificates == null && mPastSigningCertificatesFlags == null)) { pastMismatch = true; } if (pastMismatch) { throw new IllegalStateException("SigningDetails must have a one to one mapping " + "between pastSigningCertificates and pastSigningCertificatesFlags"); } } /** build a {@code SigningDetails} object */ public SigningDetails build() throws CertificateException { checkInvariants(); return new SigningDetails(mSignatures, mSignatureSchemeVersion, mPastSigningCertificates, mPastSigningCertificatesFlags); } } } /** Loading core/java/android/util/apk/ApkSignatureVerifier.java +34 −10 Original line number Diff line number Diff line Loading @@ -80,10 +80,22 @@ public class ApkSignatureVerifier { ApkSignatureSchemeV3Verifier.verify(apkPath); Certificate[][] signerCerts = new Certificate[][] { vSigner.certs }; Signature[] signerSigs = convertToSignatures(signerCerts); return new PackageParser.SigningDetails(signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3); Signature[] pastSignerSigs = null; int[] pastSignerSigsFlags = null; if (vSigner.por != null) { // populate proof-of-rotation information pastSignerSigs = new Signature[vSigner.por.certs.size()]; pastSignerSigsFlags = new int[vSigner.por.flagsList.size()]; for (int i = 0; i < pastSignerSigs.length; i++) { pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded()); pastSignerSigsFlags[i] = vSigner.por.flagsList.get(i); } } return new PackageParser.SigningDetails( signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs, pastSignerSigsFlags); } catch (SignatureNotFoundException e) { // not signed with v2, try older if allowed // not signed with v3, try older if allowed if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) { throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "No APK Signature Scheme v3 signature in package " + apkPath, e); Loading @@ -92,7 +104,7 @@ public class ApkSignatureVerifier { // APK Signature Scheme v2 signature found but did not verify throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath + " using APK Signature Scheme v2", e); + " using APK Signature Scheme v3", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading Loading @@ -304,25 +316,37 @@ public class ApkSignatureVerifier { } // first try v3 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV3"); try { ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner = ApkSignatureSchemeV3Verifier.plsCertsNoVerifyOnlyCerts(apkPath); Certificate[][] signerCerts = new Certificate[][] { vSigner.certs }; Signature[] signerSigs = convertToSignatures(signerCerts); return new PackageParser.SigningDetails(signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3); Signature[] pastSignerSigs = null; int[] pastSignerSigsFlags = null; if (vSigner.por != null) { // populate proof-of-rotation information pastSignerSigs = new Signature[vSigner.por.certs.size()]; pastSignerSigsFlags = new int[vSigner.por.flagsList.size()]; for (int i = 0; i < pastSignerSigs.length; i++) { pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded()); pastSignerSigsFlags[i] = vSigner.por.flagsList.get(i); } } return new PackageParser.SigningDetails( signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs, pastSignerSigsFlags); } catch (SignatureNotFoundException e) { // not signed with v2, try older if allowed // not signed with v3, try older if allowed if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) { throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "No APK Signature Scheme v3 signature in package " + apkPath, e); } } catch (Exception e) { // APK Signature Scheme v2 signature found but did not verify // APK Signature Scheme v3 signature found but did not verify throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath + " using APK Signature Scheme v2", e); + " using APK Signature Scheme v3", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading services/core/java/com/android/server/pm/PackageManagerService.java +33 −30 Original line number Diff line number Diff line Loading @@ -5421,13 +5421,13 @@ Slog.e("TODD", if (isCallerInstantApp) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s1 = ((SharedUserSetting)obj).signatures.mSignatures; s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (filterAppAccessLPr(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s1 = ps.signatures.mSignatures; s1 = ps.signatures.mSigningDetails.signatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } Loading @@ -5440,13 +5440,13 @@ Slog.e("TODD", if (isCallerInstantApp) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s2 = ((SharedUserSetting)obj).signatures.mSignatures; s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (filterAppAccessLPr(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s2 = ps.signatures.mSignatures; s2 = ps.signatures.mSigningDetails.signatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } Loading Loading @@ -8233,19 +8233,15 @@ Slog.e("TODD", && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(pkg) && !isRecoverSignatureUpdateNeeded(pkg)) { if (ps.signatures.mSignatures != null && ps.signatures.mSignatures.length != 0 && ps.signatures.mSignatureSchemeVersion != SignatureSchemeVersion.UNKNOWN) { if (ps.signatures.mSigningDetails.signatures != null && ps.signatures.mSigningDetails.signatures.length != 0 && ps.signatures.mSigningDetails.signatureSchemeVersion != SignatureSchemeVersion.UNKNOWN) { // Optimization: reuse the existing cached signing data // if the package appears to be unchanged. try { pkg.mSigningDetails = new PackageParser.SigningDetails(ps.signatures.mSignatures, ps.signatures.mSignatureSchemeVersion); pkg.mSigningDetails = new PackageParser.SigningDetails(ps.signatures.mSigningDetails); return; } catch (CertificateException e) { Slog.e(TAG, "Attempt to read public keys from persisted signatures failed for " + ps.name, e); } } Slog.w(TAG, "PackageSetting for " + ps.name Loading Loading @@ -8573,7 +8569,8 @@ Slog.e("TODD", if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists && !pkgSetting.isSystem()) { // if the signatures don't match, wipe the installed application and its data if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSigningDetails.signatures) if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { logCriticalInfo(Log.WARN, "System package signature mismatch;" Loading Loading @@ -9936,14 +9933,14 @@ Slog.e("TODD", if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; } else { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); } else { pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; String msg = "System package " + pkg.packageName + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); Loading @@ -9963,21 +9960,22 @@ Slog.e("TODD", } // We just determined the app is signed correctly, so bring // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; } catch (PackageManagerException e) { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw e; } // The signature has changed, but this package is in the system // image... let's recover! pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; // However... if this package is part of a shared user, but it // doesn't match the signature of the shared user, let's fail. // What this means is that you can't change the signatures // associated with an overall shared user, which doesn't seem all // that unreasonable. if (signatureCheckPs.sharedUser != null) { if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures, if (compareSignatures( signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new PackageManagerException( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, Loading Loading @@ -10804,9 +10802,12 @@ Slog.e("TODD", if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); if ((platformPkgSetting.signatures.mSignatures != null) && (compareSignatures(platformPkgSetting.signatures.mSignatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) { if ((platformPkgSetting.signatures.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( platformPkgSetting.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + pkg.packageName + " shares privileged user " + Loading Loading @@ -14248,9 +14249,10 @@ Slog.e("TODD", Object obj = mSettings.getUserIdLPr(callingUid); if (obj != null) { if (obj instanceof SharedUserSetting) { callerSignature = ((SharedUserSetting)obj).signatures.mSignatures; callerSignature = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { callerSignature = ((PackageSetting)obj).signatures.mSignatures; callerSignature = ((PackageSetting)obj).signatures.mSigningDetails.signatures; } else { throw new SecurityException("Bad object " + obj + " for uid " + callingUid); } Loading @@ -14262,7 +14264,7 @@ Slog.e("TODD", // not signed with the same cert as the caller. if (installerPackageSetting != null) { if (compareSignatures(callerSignature, installerPackageSetting.signatures.mSignatures) installerPackageSetting.signatures.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( "Caller does not have same cert as new installer package " Loading @@ -14279,7 +14281,7 @@ Slog.e("TODD", // okay to change it. if (setting != null) { if (compareSignatures(callerSignature, setting.signatures.mSignatures) setting.signatures.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( "Caller does not have same cert as old installer package " Loading Loading @@ -16787,7 +16789,8 @@ Slog.e("TODD", sourcePackageSetting, scanFlags))) { sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg); } else { sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures, sigsOk = compareSignatures( sourcePackageSetting.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH; } if (!sigsOk) { services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +15 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/pm/PackageSettingBase.java +1 −1 Original line number Diff line number Diff line Loading @@ -233,7 +233,7 @@ public abstract class PackageSettingBase extends SettingBase { } public Signature[] getSignatures() { return signatures.mSignatures; return signatures.mSigningDetails.signatures; } /** Loading Loading
core/java/android/content/pm/PackageParser.java +144 −5 Original line number Diff line number Diff line Loading @@ -5684,23 +5684,74 @@ public class PackageParser { @Nullable public final ArraySet<PublicKey> publicKeys; /** * Collection of {@code Signature} objects, each of which is formed from a former signing * certificate of this APK before it was changed by signing certificate rotation. */ @Nullable public final Signature[] pastSigningCertificates; /** * Flags for the {@code pastSigningCertificates} collection, which indicate the capabilities * the including APK wishes to grant to its past signing certificates. */ @Nullable public final int[] pastSigningCertificatesFlags; /** A representation of unknown signing details. Use instead of null. */ public static final SigningDetails UNKNOWN = new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null); new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null, null, null); @VisibleForTesting public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion, ArraySet<PublicKey> keys) { ArraySet<PublicKey> keys, Signature[] pastSigningCertificates, int[] pastSigningCertificatesFlags) { this.signatures = signatures; this.signatureSchemeVersion = signatureSchemeVersion; this.publicKeys = keys; this.pastSigningCertificates = pastSigningCertificates; this.pastSigningCertificatesFlags = pastSigningCertificatesFlags; } public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion, Signature[] pastSigningCertificates, int[] pastSigningCertificatesFlags) throws CertificateException { this(signatures, signatureSchemeVersion, toSigningKeys(signatures), pastSigningCertificates, pastSigningCertificatesFlags); } public SigningDetails(Signature[] signatures, @SignatureSchemeVersion int signatureSchemeVersion) throws CertificateException { this(signatures, signatureSchemeVersion, toSigningKeys(signatures)); this(signatures, signatureSchemeVersion, null, null); } public SigningDetails(SigningDetails orig) { if (orig != null) { if (orig.signatures != null) { this.signatures = orig.signatures.clone(); } else { this.signatures = null; } this.signatureSchemeVersion = orig.signatureSchemeVersion; this.publicKeys = new ArraySet<>(orig.publicKeys); if (orig.pastSigningCertificates != null) { this.pastSigningCertificates = orig.pastSigningCertificates.clone(); this.pastSigningCertificatesFlags = orig.pastSigningCertificatesFlags.clone(); } else { this.pastSigningCertificates = null; this.pastSigningCertificatesFlags = null; } } else { this.signatures = null; this.signatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; this.publicKeys = null; this.pastSigningCertificates = null; this.pastSigningCertificatesFlags = null; } } /** Returns true if the signing details have one or more signatures. */ Loading Loading @@ -5728,6 +5779,8 @@ public class PackageParser { dest.writeTypedArray(this.signatures, flags); dest.writeInt(this.signatureSchemeVersion); dest.writeArraySet(this.publicKeys); dest.writeTypedArray(this.pastSigningCertificates, flags); dest.writeIntArray(this.pastSigningCertificatesFlags); } protected SigningDetails(Parcel in) { Loading @@ -5735,6 +5788,8 @@ public class PackageParser { this.signatures = in.createTypedArray(Signature.CREATOR); this.signatureSchemeVersion = in.readInt(); this.publicKeys = (ArraySet<PublicKey>) in.readArraySet(boot); this.pastSigningCertificates = in.createTypedArray(Signature.CREATOR); this.pastSigningCertificatesFlags = in.createIntArray(); } public static final Creator<SigningDetails> CREATOR = new Creator<SigningDetails>() { Loading @@ -5761,8 +5816,23 @@ public class PackageParser { if (signatureSchemeVersion != that.signatureSchemeVersion) return false; if (!Signature.areExactMatch(signatures, that.signatures)) return false; return publicKeys != null ? publicKeys.equals(that.publicKeys) : that.publicKeys == null; if (publicKeys != null) { if (!publicKeys.equals((that.publicKeys))) { return false; } } else if (that.publicKeys != null) { return false; } // can't use Signature.areExactMatch() because order matters with the past signing certs if (!Arrays.equals(pastSigningCertificates, that.pastSigningCertificates)) { return false; } if (!Arrays.equals(pastSigningCertificatesFlags, that.pastSigningCertificatesFlags)) { return false; } return true; } @Override Loading @@ -5770,8 +5840,77 @@ public class PackageParser { int result = +Arrays.hashCode(signatures); result = 31 * result + signatureSchemeVersion; result = 31 * result + (publicKeys != null ? publicKeys.hashCode() : 0); result = 31 * result + Arrays.hashCode(pastSigningCertificates); result = 31 * result + Arrays.hashCode(pastSigningCertificatesFlags); return result; } /** * Builder of {@code SigningDetails} instances. */ public static class Builder { private Signature[] mSignatures; private int mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN; private Signature[] mPastSigningCertificates; private int[] mPastSigningCertificatesFlags; public Builder() { } /** get signing certificates used to sign the current APK */ public Builder setSignatures(Signature[] signatures) { mSignatures = signatures; return this; } /** set the signature scheme version used to sign the APK */ public Builder setSignatureSchemeVersion(int signatureSchemeVersion) { mSignatureSchemeVersion = signatureSchemeVersion; return this; } /** set the signing certificates by which the APK proved it can be authenticated */ public Builder setPastSigningCertificates(Signature[] pastSigningCertificates) { mPastSigningCertificates = pastSigningCertificates; return this; } /** set the flags for the {@code pastSigningCertificates} */ public Builder setPastSigningCertificatesFlags(int[] pastSigningCertificatesFlags) { mPastSigningCertificatesFlags = pastSigningCertificatesFlags; return this; } private void checkInvariants() { // must have signatures and scheme version set if (mSignatures == null) { throw new IllegalStateException("SigningDetails requires the current signing" + " certificates."); } // pastSigningCerts and flags must match up boolean pastMismatch = false; if (mPastSigningCertificates != null && mPastSigningCertificatesFlags != null) { if (mPastSigningCertificates.length != mPastSigningCertificatesFlags.length) { pastMismatch = true; } } else if (!(mPastSigningCertificates == null && mPastSigningCertificatesFlags == null)) { pastMismatch = true; } if (pastMismatch) { throw new IllegalStateException("SigningDetails must have a one to one mapping " + "between pastSigningCertificates and pastSigningCertificatesFlags"); } } /** build a {@code SigningDetails} object */ public SigningDetails build() throws CertificateException { checkInvariants(); return new SigningDetails(mSignatures, mSignatureSchemeVersion, mPastSigningCertificates, mPastSigningCertificatesFlags); } } } /** Loading
core/java/android/util/apk/ApkSignatureVerifier.java +34 −10 Original line number Diff line number Diff line Loading @@ -80,10 +80,22 @@ public class ApkSignatureVerifier { ApkSignatureSchemeV3Verifier.verify(apkPath); Certificate[][] signerCerts = new Certificate[][] { vSigner.certs }; Signature[] signerSigs = convertToSignatures(signerCerts); return new PackageParser.SigningDetails(signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3); Signature[] pastSignerSigs = null; int[] pastSignerSigsFlags = null; if (vSigner.por != null) { // populate proof-of-rotation information pastSignerSigs = new Signature[vSigner.por.certs.size()]; pastSignerSigsFlags = new int[vSigner.por.flagsList.size()]; for (int i = 0; i < pastSignerSigs.length; i++) { pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded()); pastSignerSigsFlags[i] = vSigner.por.flagsList.get(i); } } return new PackageParser.SigningDetails( signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs, pastSignerSigsFlags); } catch (SignatureNotFoundException e) { // not signed with v2, try older if allowed // not signed with v3, try older if allowed if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) { throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "No APK Signature Scheme v3 signature in package " + apkPath, e); Loading @@ -92,7 +104,7 @@ public class ApkSignatureVerifier { // APK Signature Scheme v2 signature found but did not verify throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath + " using APK Signature Scheme v2", e); + " using APK Signature Scheme v3", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading Loading @@ -304,25 +316,37 @@ public class ApkSignatureVerifier { } // first try v3 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV3"); try { ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner = ApkSignatureSchemeV3Verifier.plsCertsNoVerifyOnlyCerts(apkPath); Certificate[][] signerCerts = new Certificate[][] { vSigner.certs }; Signature[] signerSigs = convertToSignatures(signerCerts); return new PackageParser.SigningDetails(signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3); Signature[] pastSignerSigs = null; int[] pastSignerSigsFlags = null; if (vSigner.por != null) { // populate proof-of-rotation information pastSignerSigs = new Signature[vSigner.por.certs.size()]; pastSignerSigsFlags = new int[vSigner.por.flagsList.size()]; for (int i = 0; i < pastSignerSigs.length; i++) { pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded()); pastSignerSigsFlags[i] = vSigner.por.flagsList.get(i); } } return new PackageParser.SigningDetails( signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3, pastSignerSigs, pastSignerSigsFlags); } catch (SignatureNotFoundException e) { // not signed with v2, try older if allowed // not signed with v3, try older if allowed if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) { throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "No APK Signature Scheme v3 signature in package " + apkPath, e); } } catch (Exception e) { // APK Signature Scheme v2 signature found but did not verify // APK Signature Scheme v3 signature found but did not verify throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath + " using APK Signature Scheme v2", e); + " using APK Signature Scheme v3", e); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } Loading
services/core/java/com/android/server/pm/PackageManagerService.java +33 −30 Original line number Diff line number Diff line Loading @@ -5421,13 +5421,13 @@ Slog.e("TODD", if (isCallerInstantApp) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s1 = ((SharedUserSetting)obj).signatures.mSignatures; s1 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (filterAppAccessLPr(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s1 = ps.signatures.mSignatures; s1 = ps.signatures.mSigningDetails.signatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } Loading @@ -5440,13 +5440,13 @@ Slog.e("TODD", if (isCallerInstantApp) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s2 = ((SharedUserSetting)obj).signatures.mSignatures; s2 = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (filterAppAccessLPr(ps, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } s2 = ps.signatures.mSignatures; s2 = ps.signatures.mSigningDetails.signatures; } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } Loading Loading @@ -8233,19 +8233,15 @@ Slog.e("TODD", && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(pkg) && !isRecoverSignatureUpdateNeeded(pkg)) { if (ps.signatures.mSignatures != null && ps.signatures.mSignatures.length != 0 && ps.signatures.mSignatureSchemeVersion != SignatureSchemeVersion.UNKNOWN) { if (ps.signatures.mSigningDetails.signatures != null && ps.signatures.mSigningDetails.signatures.length != 0 && ps.signatures.mSigningDetails.signatureSchemeVersion != SignatureSchemeVersion.UNKNOWN) { // Optimization: reuse the existing cached signing data // if the package appears to be unchanged. try { pkg.mSigningDetails = new PackageParser.SigningDetails(ps.signatures.mSignatures, ps.signatures.mSignatureSchemeVersion); pkg.mSigningDetails = new PackageParser.SigningDetails(ps.signatures.mSigningDetails); return; } catch (CertificateException e) { Slog.e(TAG, "Attempt to read public keys from persisted signatures failed for " + ps.name, e); } } Slog.w(TAG, "PackageSetting for " + ps.name Loading Loading @@ -8573,7 +8569,8 @@ Slog.e("TODD", if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists && !pkgSetting.isSystem()) { // if the signatures don't match, wipe the installed application and its data if (compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSigningDetails.signatures) if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { logCriticalInfo(Log.WARN, "System package signature mismatch;" Loading Loading @@ -9936,14 +9933,14 @@ Slog.e("TODD", if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; } else { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); } else { pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; String msg = "System package " + pkg.packageName + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); Loading @@ -9963,21 +9960,22 @@ Slog.e("TODD", } // We just determined the app is signed correctly, so bring // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; } catch (PackageManagerException e) { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw e; } // The signature has changed, but this package is in the system // image... let's recover! pkgSetting.signatures.mSignatures = pkg.mSigningDetails.signatures; pkgSetting.signatures.mSigningDetails = pkg.mSigningDetails; // However... if this package is part of a shared user, but it // doesn't match the signature of the shared user, let's fail. // What this means is that you can't change the signatures // associated with an overall shared user, which doesn't seem all // that unreasonable. if (signatureCheckPs.sharedUser != null) { if (compareSignatures(signatureCheckPs.sharedUser.signatures.mSignatures, if (compareSignatures( signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new PackageManagerException( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, Loading Loading @@ -10804,9 +10802,12 @@ Slog.e("TODD", if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); if ((platformPkgSetting.signatures.mSignatures != null) && (compareSignatures(platformPkgSetting.signatures.mSignatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) { if ((platformPkgSetting.signatures.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( platformPkgSetting.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + pkg.packageName + " shares privileged user " + Loading Loading @@ -14248,9 +14249,10 @@ Slog.e("TODD", Object obj = mSettings.getUserIdLPr(callingUid); if (obj != null) { if (obj instanceof SharedUserSetting) { callerSignature = ((SharedUserSetting)obj).signatures.mSignatures; callerSignature = ((SharedUserSetting)obj).signatures.mSigningDetails.signatures; } else if (obj instanceof PackageSetting) { callerSignature = ((PackageSetting)obj).signatures.mSignatures; callerSignature = ((PackageSetting)obj).signatures.mSigningDetails.signatures; } else { throw new SecurityException("Bad object " + obj + " for uid " + callingUid); } Loading @@ -14262,7 +14264,7 @@ Slog.e("TODD", // not signed with the same cert as the caller. if (installerPackageSetting != null) { if (compareSignatures(callerSignature, installerPackageSetting.signatures.mSignatures) installerPackageSetting.signatures.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( "Caller does not have same cert as new installer package " Loading @@ -14279,7 +14281,7 @@ Slog.e("TODD", // okay to change it. if (setting != null) { if (compareSignatures(callerSignature, setting.signatures.mSignatures) setting.signatures.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH) { throw new SecurityException( "Caller does not have same cert as old installer package " Loading Loading @@ -16787,7 +16789,8 @@ Slog.e("TODD", sourcePackageSetting, scanFlags))) { sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg); } else { sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures, sigsOk = compareSignatures( sourcePackageSetting.signatures.mSigningDetails.signatures, pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH; } if (!sigsOk) {
services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +15 −11 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/pm/PackageSettingBase.java +1 −1 Original line number Diff line number Diff line Loading @@ -233,7 +233,7 @@ public abstract class PackageSettingBase extends SettingBase { } public Signature[] getSignatures() { return signatures.mSignatures; return signatures.mSigningDetails.signatures; } /** Loading