Merge "Add proof-of-rotation information to PackageParser.SigningDetails"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4ec3efce54
@@ -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. */
|
||||
@@ -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) {
|
||||
@@ -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>() {
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
return;
|
||||
} catch (CertificateException e) {
|
||||
Slog.e(TAG, "Attempt to read public keys from persisted signatures failed for "
|
||||
+ ps.name, e);
|
||||
}
|
||||
pkg.mSigningDetails =
|
||||
new PackageParser.SigningDetails(ps.signatures.mSigningDetails);
|
||||
return;
|
||||
}
|
||||
|
||||
Slog.w(TAG, "PackageSetting for " + ps.name
|
||||
@@ -8573,8 +8569,9 @@ 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)
|
||||
!= PackageManager.SIGNATURE_MATCH) {
|
||||
if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures,
|
||||
pkg.mSigningDetails.signatures)
|
||||
!= PackageManager.SIGNATURE_MATCH) {
|
||||
logCriticalInfo(Log.WARN,
|
||||
"System package signature mismatch;"
|
||||
+ " name: " + pkgSetting.name);
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
@@ -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 " +
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 "
|
||||
@@ -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 "
|
||||
@@ -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) {
|
||||
|
||||
@@ -509,7 +509,7 @@ public class PackageManagerServiceUtils {
|
||||
private static boolean matchSignaturesCompat(String packageName,
|
||||
PackageSignatures packageSignatures, PackageParser.SigningDetails parsedSignatures) {
|
||||
ArraySet<Signature> existingSet = new ArraySet<Signature>();
|
||||
for (Signature sig : packageSignatures.mSignatures) {
|
||||
for (Signature sig : packageSignatures.mSigningDetails.signatures) {
|
||||
existingSet.add(sig);
|
||||
}
|
||||
ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
|
||||
@@ -526,7 +526,7 @@ public class PackageManagerServiceUtils {
|
||||
// make sure the expanded scanned set contains all signatures in the existing one
|
||||
if (scannedCompatSet.equals(existingSet)) {
|
||||
// migrate the old signatures to the new scheme
|
||||
packageSignatures.assignSignatures(parsedSignatures);
|
||||
packageSignatures.mSigningDetails = parsedSignatures;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -561,8 +561,8 @@ public class PackageManagerServiceUtils {
|
||||
try {
|
||||
PackageParser.collectCertificates(disabledPkgSetting.pkg,
|
||||
PackageParser.PARSE_IS_SYSTEM_DIR);
|
||||
if (compareSignatures(pkgSetting.signatures.mSignatures,
|
||||
disabledPkgSetting.signatures.mSignatures)
|
||||
if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures,
|
||||
disabledPkgSetting.signatures.mSigningDetails.signatures)
|
||||
!= PackageManager.SIGNATURE_MATCH) {
|
||||
logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " +
|
||||
pkgSetting.name);
|
||||
@@ -593,9 +593,9 @@ public class PackageManagerServiceUtils {
|
||||
throws PackageManagerException {
|
||||
final String packageName = pkgSetting.name;
|
||||
boolean compatMatch = false;
|
||||
if (pkgSetting.signatures.mSignatures != null) {
|
||||
if (pkgSetting.signatures.mSigningDetails.signatures != null) {
|
||||
// Already existing package. Make sure signatures match
|
||||
boolean match = compareSignatures(pkgSetting.signatures.mSignatures,
|
||||
boolean match = compareSignatures(pkgSetting.signatures.mSigningDetails.signatures,
|
||||
parsedSignatures.signatures)
|
||||
== PackageManager.SIGNATURE_MATCH;
|
||||
if (!match && compareCompat) {
|
||||
@@ -605,7 +605,7 @@ public class PackageManagerServiceUtils {
|
||||
}
|
||||
if (!match && compareRecover) {
|
||||
match = matchSignaturesRecover(
|
||||
packageName, pkgSetting.signatures.mSignatures,
|
||||
packageName, pkgSetting.signatures.mSigningDetails.signatures,
|
||||
parsedSignatures.signatures);
|
||||
}
|
||||
|
||||
@@ -620,17 +620,21 @@ public class PackageManagerServiceUtils {
|
||||
}
|
||||
}
|
||||
// Check for shared user signatures
|
||||
if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
|
||||
if (pkgSetting.sharedUser != null
|
||||
&& pkgSetting.sharedUser.signatures.mSigningDetails.signatures != null) {
|
||||
// Already existing package. Make sure signatures match
|
||||
boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
|
||||
parsedSignatures.signatures) == PackageManager.SIGNATURE_MATCH;
|
||||
boolean match =
|
||||
compareSignatures(
|
||||
pkgSetting.sharedUser.signatures.mSigningDetails.signatures,
|
||||
parsedSignatures.signatures) == PackageManager.SIGNATURE_MATCH;
|
||||
if (!match && compareCompat) {
|
||||
match = matchSignaturesCompat(
|
||||
packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
|
||||
}
|
||||
if (!match && compareRecover) {
|
||||
match = matchSignaturesRecover(packageName,
|
||||
pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures.signatures);
|
||||
pkgSetting.sharedUser.signatures.mSigningDetails.signatures,
|
||||
parsedSignatures.signatures);
|
||||
compatMatch |= match;
|
||||
}
|
||||
if (!match) {
|
||||
|
||||
@@ -233,7 +233,7 @@ public abstract class PackageSettingBase extends SettingBase {
|
||||
}
|
||||
|
||||
public Signature[] getSignatures() {
|
||||
return signatures.mSignatures;
|
||||
return signatures.mSigningDetails.signatures;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,91 +22,148 @@ import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.pm.PackageParser;
|
||||
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
|
||||
import android.content.pm.Signature;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
class PackageSignatures {
|
||||
Signature[] mSignatures;
|
||||
@SignatureSchemeVersion int mSignatureSchemeVersion;
|
||||
|
||||
@NonNull PackageParser.SigningDetails mSigningDetails;
|
||||
|
||||
PackageSignatures(PackageSignatures orig) {
|
||||
if (orig != null && orig.mSignatures != null) {
|
||||
mSignatures = orig.mSignatures.clone();
|
||||
mSignatureSchemeVersion = orig.mSignatureSchemeVersion;
|
||||
if (orig != null && orig.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) {
|
||||
mSigningDetails = new PackageParser.SigningDetails(orig.mSigningDetails);
|
||||
} else {
|
||||
mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
PackageSignatures(PackageParser.SigningDetails signingDetails) {
|
||||
assignSignatures(signingDetails);
|
||||
mSigningDetails = signingDetails;
|
||||
}
|
||||
|
||||
PackageSignatures() {
|
||||
mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
|
||||
}
|
||||
|
||||
void writeXml(XmlSerializer serializer, String tagName,
|
||||
ArrayList<Signature> pastSignatures) throws IOException {
|
||||
if (mSignatures == null) {
|
||||
ArrayList<Signature> writtenSignatures) throws IOException {
|
||||
if (mSigningDetails.signatures == null) {
|
||||
return;
|
||||
}
|
||||
serializer.startTag(null, tagName);
|
||||
serializer.attribute(null, "count",
|
||||
Integer.toString(mSignatures.length));
|
||||
serializer.attribute(null, "schemeVersion", Integer.toString(mSignatureSchemeVersion));
|
||||
for (int i=0; i<mSignatures.length; i++) {
|
||||
serializer.startTag(null, "cert");
|
||||
final Signature sig = mSignatures[i];
|
||||
final int sigHash = sig.hashCode();
|
||||
final int numPast = pastSignatures.size();
|
||||
int j;
|
||||
for (j=0; j<numPast; j++) {
|
||||
Signature pastSig = pastSignatures.get(j);
|
||||
if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
|
||||
serializer.attribute(null, "index", Integer.toString(j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= numPast) {
|
||||
pastSignatures.add(sig);
|
||||
serializer.attribute(null, "index", Integer.toString(numPast));
|
||||
serializer.attribute(null, "key", sig.toCharsString());
|
||||
}
|
||||
serializer.endTag(null, "cert");
|
||||
serializer.attribute(null, "count", Integer.toString(mSigningDetails.signatures.length));
|
||||
serializer.attribute(null, "schemeVersion",
|
||||
Integer.toString(mSigningDetails.signatureSchemeVersion));
|
||||
writeCertsListXml(serializer, writtenSignatures, mSigningDetails.signatures, null);
|
||||
|
||||
// if we have past signer certificate information, write it out
|
||||
if (mSigningDetails.pastSigningCertificates != null) {
|
||||
serializer.startTag(null, "pastSigs");
|
||||
serializer.attribute(null, "count",
|
||||
Integer.toString(mSigningDetails.pastSigningCertificates.length));
|
||||
writeCertsListXml(
|
||||
serializer, writtenSignatures, mSigningDetails.pastSigningCertificates,
|
||||
mSigningDetails.pastSigningCertificatesFlags);
|
||||
serializer.endTag(null, "pastSigs");
|
||||
}
|
||||
serializer.endTag(null, tagName);
|
||||
}
|
||||
|
||||
void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
|
||||
private void writeCertsListXml(XmlSerializer serializer, ArrayList<Signature> writtenSignatures,
|
||||
Signature[] signatures, int[] flags) throws IOException {
|
||||
for (int i=0; i<signatures.length; i++) {
|
||||
serializer.startTag(null, "cert");
|
||||
final Signature sig = signatures[i];
|
||||
final int sigHash = sig.hashCode();
|
||||
final int numWritten = writtenSignatures.size();
|
||||
int j;
|
||||
for (j=0; j<numWritten; j++) {
|
||||
Signature writtenSig = writtenSignatures.get(j);
|
||||
if (writtenSig.hashCode() == sigHash && writtenSig.equals(sig)) {
|
||||
serializer.attribute(null, "index", Integer.toString(j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= numWritten) {
|
||||
writtenSignatures.add(sig);
|
||||
serializer.attribute(null, "index", Integer.toString(numWritten));
|
||||
serializer.attribute(null, "key", sig.toCharsString());
|
||||
}
|
||||
if (flags != null) {
|
||||
serializer.attribute(null, "flags", Integer.toString(flags[i]));
|
||||
}
|
||||
serializer.endTag(null, "cert");
|
||||
}
|
||||
}
|
||||
|
||||
void readXml(XmlPullParser parser, ArrayList<Signature> readSignatures)
|
||||
throws IOException, XmlPullParserException {
|
||||
PackageParser.SigningDetails.Builder builder =
|
||||
new PackageParser.SigningDetails.Builder();
|
||||
|
||||
String countStr = parser.getAttributeValue(null, "count");
|
||||
if (countStr == null) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <signatures> has"
|
||||
"Error in package manager settings: <sigs> has"
|
||||
+ " no count at " + parser.getPositionDescription());
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
final int count = Integer.parseInt(countStr);
|
||||
|
||||
String schemeVersionStr = parser.getAttributeValue(null, "schemeVersion");
|
||||
int signatureSchemeVersion;
|
||||
if (schemeVersionStr == null) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <signatures> has no schemeVersion at "
|
||||
"Error in package manager settings: <sigs> has no schemeVersion at "
|
||||
+ parser.getPositionDescription());
|
||||
mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN;
|
||||
signatureSchemeVersion = SignatureSchemeVersion.UNKNOWN;
|
||||
} else {
|
||||
mSignatureSchemeVersion = Integer.parseInt(countStr);
|
||||
signatureSchemeVersion = Integer.parseInt(schemeVersionStr);
|
||||
}
|
||||
final int count = Integer.parseInt(countStr);
|
||||
mSignatures = new Signature[count];
|
||||
builder.setSignatureSchemeVersion(signatureSchemeVersion);
|
||||
Signature[] signatures = new Signature[count];
|
||||
int pos = readCertsListXml(parser, readSignatures, signatures, null, builder);
|
||||
builder.setSignatures(signatures);
|
||||
if (pos < count) {
|
||||
// Should never happen -- there is an error in the written
|
||||
// settings -- but if it does we don't want to generate
|
||||
// a bad array.
|
||||
Signature[] newSigs = new Signature[pos];
|
||||
System.arraycopy(signatures, 0, newSigs, 0, pos);
|
||||
builder = builder.setSignatures(newSigs);
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <sigs> count does not match number of "
|
||||
+ " <cert> entries" + parser.getPositionDescription());
|
||||
}
|
||||
|
||||
try {
|
||||
mSigningDetails = builder.build();
|
||||
} catch (CertificateException e) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <sigs> "
|
||||
+ "unable to convert certificate(s) to public key(s).");
|
||||
mSigningDetails = PackageParser.SigningDetails.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private int readCertsListXml(XmlPullParser parser, ArrayList<Signature> readSignatures,
|
||||
Signature[] signatures, int[] flags, PackageParser.SigningDetails.Builder builder)
|
||||
throws IOException, XmlPullParserException {
|
||||
int count = signatures.length;
|
||||
int pos = 0;
|
||||
|
||||
int outerDepth = parser.getDepth();
|
||||
int type;
|
||||
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& (type != XmlPullParser.END_TAG
|
||||
|| parser.getDepth() > outerDepth)) {
|
||||
&& (type != XmlPullParser.END_TAG
|
||||
|| parser.getDepth() > outerDepth)) {
|
||||
if (type == XmlPullParser.END_TAG
|
||||
|| type == XmlPullParser.TEXT) {
|
||||
continue;
|
||||
@@ -121,83 +178,128 @@ class PackageSignatures {
|
||||
int idx = Integer.parseInt(index);
|
||||
String key = parser.getAttributeValue(null, "key");
|
||||
if (key == null) {
|
||||
if (idx >= 0 && idx < pastSignatures.size()) {
|
||||
Signature sig = pastSignatures.get(idx);
|
||||
if (idx >= 0 && idx < readSignatures.size()) {
|
||||
Signature sig = readSignatures.get(idx);
|
||||
if (sig != null) {
|
||||
mSignatures[pos] = pastSignatures.get(idx);
|
||||
signatures[pos] = readSignatures.get(idx);
|
||||
pos++;
|
||||
} else {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <cert> "
|
||||
+ "index " + index + " is not defined at "
|
||||
+ parser.getPositionDescription());
|
||||
+ "index " + index + " is not defined at "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
} else {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <cert> "
|
||||
+ "index " + index + " is out of bounds at "
|
||||
+ parser.getPositionDescription());
|
||||
+ "index " + index + " is out of bounds at "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
} else {
|
||||
while (pastSignatures.size() <= idx) {
|
||||
pastSignatures.add(null);
|
||||
while (readSignatures.size() <= idx) {
|
||||
readSignatures.add(null);
|
||||
}
|
||||
Signature sig = new Signature(key);
|
||||
pastSignatures.set(idx, sig);
|
||||
mSignatures[pos] = sig;
|
||||
readSignatures.set(idx, sig);
|
||||
signatures[pos] = sig;
|
||||
pos++;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <cert> "
|
||||
+ "index " + index + " is not a number at "
|
||||
+ parser.getPositionDescription());
|
||||
+ "index " + index + " is not a number at "
|
||||
+ parser.getPositionDescription());
|
||||
} catch (IllegalArgumentException e) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <cert> "
|
||||
+ "index " + index + " has an invalid signature at "
|
||||
+ parser.getPositionDescription() + ": "
|
||||
+ e.getMessage());
|
||||
+ "index " + index + " has an invalid signature at "
|
||||
+ parser.getPositionDescription() + ": "
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
if (flags != null) {
|
||||
String flagsStr = parser.getAttributeValue(null, "flags");
|
||||
if (flagsStr != null) {
|
||||
try {
|
||||
flags[pos] = Integer.parseInt(flagsStr);
|
||||
} catch (NumberFormatException e) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <cert> "
|
||||
+ "flags " + flagsStr + " is not a number at "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
} else {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <cert> has no"
|
||||
+ " flags at " + parser.getPositionDescription());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <cert> has"
|
||||
+ " no index at " + parser.getPositionDescription());
|
||||
+ " no index at " + parser.getPositionDescription());
|
||||
}
|
||||
} else {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: too "
|
||||
+ "many <cert> tags, expected " + count
|
||||
+ " at " + parser.getPositionDescription());
|
||||
+ "many <cert> tags, expected " + count
|
||||
+ " at " + parser.getPositionDescription());
|
||||
}
|
||||
} else if (tagName.equals("pastSigs")) {
|
||||
if (flags == null) {
|
||||
// we haven't encountered pastSigs yet, go ahead
|
||||
String countStr = parser.getAttributeValue(null, "count");
|
||||
if (countStr == null) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <pastSigs> has"
|
||||
+ " no count at " + parser.getPositionDescription());
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
try {
|
||||
final int pastSigsCount = Integer.parseInt(countStr);
|
||||
Signature[] pastSignatures = new Signature[pastSigsCount];
|
||||
int[] pastSignaturesFlags = new int[pastSigsCount];
|
||||
int pastSigsPos = readCertsListXml(parser, readSignatures, pastSignatures,
|
||||
pastSignaturesFlags, builder);
|
||||
builder = builder
|
||||
.setPastSigningCertificates(pastSignatures)
|
||||
.setPastSigningCertificatesFlags(pastSignaturesFlags);
|
||||
|
||||
if (pastSigsPos < pastSigsCount) {
|
||||
// Should never happen -- there is an error in the written
|
||||
// settings -- but if it does we don't want to generate
|
||||
// a bad array.
|
||||
Signature[] newSigs = new Signature[pastSigsPos];
|
||||
System.arraycopy(pastSignatures, 0, newSigs, 0, pastSigsPos);
|
||||
int[] newFlags = new int[pastSigsPos];
|
||||
System.arraycopy(pastSignaturesFlags, 0, newFlags, 0, pastSigsPos);
|
||||
builder = builder
|
||||
.setPastSigningCertificates(newSigs)
|
||||
.setPastSigningCertificatesFlags(newFlags);
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <pastSigs> count does not "
|
||||
+ "match number of <cert> entries "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Error in package manager settings: <pastSigs> "
|
||||
+ "count " + countStr + " is not a number at "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
} else {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"<pastSigs> encountered multiple times under the same <sigs> at "
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
} else {
|
||||
PackageManagerService.reportSettingsProblem(Log.WARN,
|
||||
"Unknown element under <cert>: "
|
||||
+ parser.getName());
|
||||
"Unknown element under <sigs>: "
|
||||
+ parser.getName());
|
||||
}
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
}
|
||||
|
||||
if (pos < count) {
|
||||
// Should never happen -- there is an error in the written
|
||||
// settings -- but if it does we don't want to generate
|
||||
// a bad array.
|
||||
Signature[] newSigs = new Signature[pos];
|
||||
System.arraycopy(mSignatures, 0, newSigs, 0, pos);
|
||||
mSignatures = newSigs;
|
||||
}
|
||||
}
|
||||
|
||||
void assignSignatures(PackageParser.SigningDetails signingDetails) {
|
||||
mSignatureSchemeVersion = signingDetails.signatureSchemeVersion;
|
||||
if (!signingDetails.hasSignatures()) {
|
||||
mSignatures = null;
|
||||
return;
|
||||
}
|
||||
mSignatures = new Signature[signingDetails.signatures.length];
|
||||
for (int i=0; i<signingDetails.signatures.length; i++) {
|
||||
mSignatures[i] = signingDetails.signatures[i];
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -206,16 +308,26 @@ class PackageSignatures {
|
||||
buf.append("PackageSignatures{");
|
||||
buf.append(Integer.toHexString(System.identityHashCode(this)));
|
||||
buf.append(" version:");
|
||||
buf.append(mSignatureSchemeVersion);
|
||||
buf.append(mSigningDetails.signatureSchemeVersion);
|
||||
buf.append(", signatures:[");
|
||||
if (mSignatures != null) {
|
||||
for (int i=0; i<mSignatures.length; i++) {
|
||||
if (mSigningDetails.signatures != null) {
|
||||
for (int i = 0; i < mSigningDetails.signatures.length; i++) {
|
||||
if (i > 0) buf.append(", ");
|
||||
buf.append(Integer.toHexString(
|
||||
mSignatures[i].hashCode()));
|
||||
mSigningDetails.signatures[i].hashCode()));
|
||||
}
|
||||
}
|
||||
buf.append("]}");
|
||||
buf.append(", past signatures:[");
|
||||
if (mSigningDetails.pastSigningCertificates != null) {
|
||||
for (int i = 0; i < mSigningDetails.pastSigningCertificates.length; i++) {
|
||||
if (i > 0) buf.append(", ");
|
||||
buf.append(Integer.toHexString(
|
||||
mSigningDetails.pastSigningCertificates[i].hashCode()));
|
||||
buf.append(" flags: ");
|
||||
buf.append(Integer.toHexString(mSigningDetails.pastSigningCertificatesFlags[i]));
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
@@ -920,13 +920,13 @@ public final class Settings {
|
||||
// by that time.
|
||||
void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) {
|
||||
// Update signatures if needed.
|
||||
if (p.signatures.mSignatures == null) {
|
||||
p.signatures.assignSignatures(pkg.mSigningDetails);
|
||||
if (p.signatures.mSigningDetails.signatures == null) {
|
||||
p.signatures.mSigningDetails = pkg.mSigningDetails;
|
||||
}
|
||||
// If this app defines a shared user id initialize
|
||||
// the shared user signatures as well.
|
||||
if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
|
||||
p.sharedUser.signatures.assignSignatures(pkg.mSigningDetails);
|
||||
if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) {
|
||||
p.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails;
|
||||
}
|
||||
addPackageSettingLPw(p, p.sharedUser);
|
||||
}
|
||||
|
||||
@@ -497,7 +497,9 @@ public class PackageParserTest {
|
||||
new PackageParser.SigningDetails(
|
||||
new Signature[] { new Signature(new byte[16]) },
|
||||
2,
|
||||
new ArraySet<>());
|
||||
new ArraySet<>(),
|
||||
null,
|
||||
null);
|
||||
pkg.mExtras = new Bundle();
|
||||
pkg.mRestrictedAccountType = "foo19";
|
||||
pkg.mRequiredAccountType = "foo20";
|
||||
|
||||
Reference in New Issue
Block a user