Skip to content

Commit 8a663c8

Browse files
krutonAndroid (Google) Code Review
authored andcommitted
Merge "Allow non-required package verifiers"
2 parents 3eb34a9 + 05ca4c9 commit 8a663c8

File tree

18 files changed

+984
-73
lines changed

18 files changed

+984
-73
lines changed

core/java/android/content/pm/PackageInfoLite.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public class PackageInfoLite implements Parcelable {
4141
public int recommendedInstallLocation;
4242
public int installLocation;
4343

44+
public VerifierInfo[] verifiers;
45+
4446
public PackageInfoLite() {
4547
}
4648

@@ -58,6 +60,13 @@ public void writeToParcel(Parcel dest, int parcelableFlags) {
5860
dest.writeString(packageName);
5961
dest.writeInt(recommendedInstallLocation);
6062
dest.writeInt(installLocation);
63+
64+
if (verifiers == null || verifiers.length == 0) {
65+
dest.writeInt(0);
66+
} else {
67+
dest.writeInt(verifiers.length);
68+
dest.writeTypedArray(verifiers, parcelableFlags);
69+
}
6170
}
6271

6372
public static final Parcelable.Creator<PackageInfoLite> CREATOR
@@ -75,5 +84,13 @@ private PackageInfoLite(Parcel source) {
7584
packageName = source.readString();
7685
recommendedInstallLocation = source.readInt();
7786
installLocation = source.readInt();
87+
88+
final int verifiersLength = source.readInt();
89+
if (verifiersLength == 0) {
90+
verifiers = new VerifierInfo[0];
91+
} else {
92+
verifiers = new VerifierInfo[verifiersLength];
93+
source.readTypedArray(verifiers, VerifierInfo.CREATOR);
94+
}
7895
}
7996
}

core/java/android/content/pm/PackageManager.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,16 @@ public NameNotFoundException(String name) {
724724
*/
725725
public static final int MOVE_EXTERNAL_MEDIA = 0x00000002;
726726

727+
/**
728+
* Usable by the required verifier as the {@code verificationCode} argument
729+
* for {@link PackageManager#verifyPendingInstall} to indicate that it will
730+
* allow the installation to proceed without any of the optional verifiers
731+
* needing to vote.
732+
*
733+
* @hide
734+
*/
735+
public static final int VERIFICATION_ALLOW_WITHOUT_SUFFICIENT = 2;
736+
727737
/**
728738
* Used as the {@code verificationCode} argument for
729739
* {@link PackageManager#verifyPendingInstall} to indicate that the calling

core/java/android/content/pm/PackageParser.java

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import android.os.Bundle;
2929
import android.os.PatternMatcher;
3030
import android.util.AttributeSet;
31+
import android.util.Base64;
3132
import android.util.DisplayMetrics;
33+
import android.util.Log;
3234
import android.util.Slog;
3335
import android.util.TypedValue;
3436
import com.android.internal.util.XmlUtils;
@@ -40,11 +42,18 @@
4042
import java.io.IOException;
4143
import java.io.InputStream;
4244
import java.lang.ref.WeakReference;
45+
import java.security.KeyFactory;
46+
import java.security.NoSuchAlgorithmException;
47+
import java.security.PublicKey;
4348
import java.security.cert.Certificate;
4449
import java.security.cert.CertificateEncodingException;
50+
import java.security.spec.EncodedKeySpec;
51+
import java.security.spec.InvalidKeySpecException;
52+
import java.security.spec.X509EncodedKeySpec;
4553
import java.util.ArrayList;
4654
import java.util.Enumeration;
4755
import java.util.Iterator;
56+
import java.util.List;
4857
import java.util.jar.Attributes;
4958
import java.util.jar.JarEntry;
5059
import java.util.jar.JarFile;
@@ -150,12 +159,14 @@ static class ParseComponentArgs extends ParsePackageItemArgs {
150159
* @hide
151160
*/
152161
public static class PackageLite {
153-
public String packageName;
154-
public int installLocation;
155-
public String mScanPath;
156-
public PackageLite(String packageName, int installLocation) {
162+
public final String packageName;
163+
public final int installLocation;
164+
public final VerifierInfo[] verifiers;
165+
166+
public PackageLite(String packageName, int installLocation, List<VerifierInfo> verifiers) {
157167
this.packageName = packageName;
158168
this.installLocation = installLocation;
169+
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
159170
}
160171
}
161172

@@ -619,8 +630,9 @@ public boolean collectCertificates(Package pkg, int flags) {
619630
* @return PackageLite object with package information or null on failure.
620631
*/
621632
public static PackageLite parsePackageLite(String packageFilePath, int flags) {
622-
XmlResourceParser parser = null;
623633
AssetManager assmgr = null;
634+
final XmlResourceParser parser;
635+
final Resources res;
624636
try {
625637
assmgr = new AssetManager();
626638
assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -631,18 +643,22 @@ public static PackageLite parsePackageLite(String packageFilePath, int flags) {
631643
return null;
632644
}
633645

646+
final DisplayMetrics metrics = new DisplayMetrics();
647+
metrics.setToDefaults();
648+
res = new Resources(assmgr, metrics, null);
634649
parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
635650
} catch (Exception e) {
636651
if (assmgr != null) assmgr.close();
637652
Slog.w(TAG, "Unable to read AndroidManifest.xml of "
638653
+ packageFilePath, e);
639654
return null;
640655
}
641-
AttributeSet attrs = parser;
642-
String errors[] = new String[1];
656+
657+
final AttributeSet attrs = parser;
658+
final String errors[] = new String[1];
643659
PackageLite packageLite = null;
644660
try {
645-
packageLite = parsePackageLite(parser, attrs, flags, errors);
661+
packageLite = parsePackageLite(res, parser, attrs, flags, errors);
646662
} catch (IOException e) {
647663
Slog.w(TAG, packageFilePath, e);
648664
} catch (XmlPullParserException e) {
@@ -719,9 +735,9 @@ private static String parsePackageName(XmlPullParser parser,
719735
return pkgName.intern();
720736
}
721737

722-
private static PackageLite parsePackageLite(XmlPullParser parser,
723-
AttributeSet attrs, int flags, String[] outError)
724-
throws IOException, XmlPullParserException {
738+
private static PackageLite parsePackageLite(Resources res, XmlPullParser parser,
739+
AttributeSet attrs, int flags, String[] outError) throws IOException,
740+
XmlPullParserException {
725741

726742
int type;
727743
while ((type = parser.next()) != XmlPullParser.START_TAG
@@ -759,7 +775,26 @@ private static PackageLite parsePackageLite(XmlPullParser parser,
759775
break;
760776
}
761777
}
762-
return new PackageLite(pkgName.intern(), installLocation);
778+
779+
// Only search the tree when the tag is directly below <manifest>
780+
final int searchDepth = parser.getDepth() + 1;
781+
782+
final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();
783+
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
784+
&& (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {
785+
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
786+
continue;
787+
}
788+
789+
if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) {
790+
final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags, outError);
791+
if (verifier != null) {
792+
verifiers.add(verifier);
793+
}
794+
}
795+
}
796+
797+
return new PackageLite(pkgName.intern(), installLocation, verifiers);
763798
}
764799

765800
/**
@@ -2691,6 +2726,63 @@ private Bundle parseMetaData(Resources res,
26912726
return data;
26922727
}
26932728

2729+
private static VerifierInfo parseVerifier(Resources res, XmlPullParser parser,
2730+
AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException,
2731+
IOException {
2732+
final TypedArray sa = res.obtainAttributes(attrs,
2733+
com.android.internal.R.styleable.AndroidManifestPackageVerifier);
2734+
2735+
final String packageName = sa.getNonResourceString(
2736+
com.android.internal.R.styleable.AndroidManifestPackageVerifier_name);
2737+
2738+
final String encodedPublicKey = sa.getNonResourceString(
2739+
com.android.internal.R.styleable.AndroidManifestPackageVerifier_publicKey);
2740+
2741+
sa.recycle();
2742+
2743+
if (packageName == null || packageName.length() == 0) {
2744+
Slog.i(TAG, "verifier package name was null; skipping");
2745+
return null;
2746+
} else if (encodedPublicKey == null) {
2747+
Slog.i(TAG, "verifier " + packageName + " public key was null; skipping");
2748+
}
2749+
2750+
EncodedKeySpec keySpec;
2751+
try {
2752+
final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT);
2753+
keySpec = new X509EncodedKeySpec(encoded);
2754+
} catch (IllegalArgumentException e) {
2755+
Slog.i(TAG, "Could not parse verifier " + packageName + " public key; invalid Base64");
2756+
return null;
2757+
}
2758+
2759+
/* First try the key as an RSA key. */
2760+
try {
2761+
final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
2762+
final PublicKey publicKey = keyFactory.generatePublic(keySpec);
2763+
return new VerifierInfo(packageName, publicKey);
2764+
} catch (NoSuchAlgorithmException e) {
2765+
Log.wtf(TAG, "Could not parse public key because RSA isn't included in build");
2766+
return null;
2767+
} catch (InvalidKeySpecException e) {
2768+
// Not a RSA public key.
2769+
}
2770+
2771+
/* Now try it as a DSA key. */
2772+
try {
2773+
final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
2774+
final PublicKey publicKey = keyFactory.generatePublic(keySpec);
2775+
return new VerifierInfo(packageName, publicKey);
2776+
} catch (NoSuchAlgorithmException e) {
2777+
Log.wtf(TAG, "Could not parse public key because DSA isn't included in build");
2778+
return null;
2779+
} catch (InvalidKeySpecException e) {
2780+
// Not a DSA public key.
2781+
}
2782+
2783+
return null;
2784+
}
2785+
26942786
private static final String ANDROID_RESOURCES
26952787
= "http://schemas.android.com/apk/res/android";
26962788

core/java/android/content/pm/Signature.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@
1919
import android.os.Parcel;
2020
import android.os.Parcelable;
2121

22+
import java.io.ByteArrayInputStream;
2223
import java.lang.ref.SoftReference;
24+
import java.security.PublicKey;
25+
import java.security.cert.Certificate;
26+
import java.security.cert.CertificateException;
27+
import java.security.cert.CertificateFactory;
2328
import java.util.Arrays;
2429

2530
/**
@@ -135,6 +140,20 @@ public byte[] toByteArray() {
135140
return bytes;
136141
}
137142

143+
/**
144+
* Returns the public key for this signature.
145+
*
146+
* @throws CertificateException when Signature isn't a valid X.509
147+
* certificate; shouldn't happen.
148+
* @hide
149+
*/
150+
public PublicKey getPublicKey() throws CertificateException {
151+
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
152+
final ByteArrayInputStream bais = new ByteArrayInputStream(mSignature);
153+
final Certificate cert = certFactory.generateCertificate(bais);
154+
return cert.getPublicKey();
155+
}
156+
138157
@Override
139158
public boolean equals(Object obj) {
140159
try {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright 2011, The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.content.pm;
18+
19+
parcelable VerifierInfo;
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (C) 2011 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.content.pm;
18+
19+
import android.os.Parcel;
20+
import android.os.Parcelable;
21+
22+
import java.security.PublicKey;
23+
24+
/**
25+
* Contains information about a package verifier as used by
26+
* {@code PackageManagerService} during package verification.
27+
*
28+
* @hide
29+
*/
30+
public class VerifierInfo implements Parcelable {
31+
/** Package name of the verifier. */
32+
public final String packageName;
33+
34+
/** Signatures used to sign the package verifier's package. */
35+
public final PublicKey publicKey;
36+
37+
/**
38+
* Creates an object that represents a verifier info object.
39+
*
40+
* @param packageName the package name in Java-style. Must not be {@code
41+
* null} or empty.
42+
* @param publicKey the public key for the signer encoded in Base64. Must
43+
* not be {@code null} or empty.
44+
* @throws IllegalArgumentException if either argument is null or empty.
45+
*/
46+
public VerifierInfo(String packageName, PublicKey publicKey) {
47+
if (packageName == null || packageName.length() == 0) {
48+
throw new IllegalArgumentException("packageName must not be null or empty");
49+
} else if (publicKey == null) {
50+
throw new IllegalArgumentException("publicKey must not be null");
51+
}
52+
53+
this.packageName = packageName;
54+
this.publicKey = publicKey;
55+
}
56+
57+
private VerifierInfo(Parcel source) {
58+
packageName = source.readString();
59+
publicKey = (PublicKey) source.readSerializable();
60+
}
61+
62+
@Override
63+
public int describeContents() {
64+
return 0;
65+
}
66+
67+
@Override
68+
public void writeToParcel(Parcel dest, int flags) {
69+
dest.writeString(packageName);
70+
dest.writeSerializable(publicKey);
71+
}
72+
73+
public static final Parcelable.Creator<VerifierInfo> CREATOR
74+
= new Parcelable.Creator<VerifierInfo>() {
75+
public VerifierInfo createFromParcel(Parcel source) {
76+
return new VerifierInfo(source);
77+
}
78+
79+
public VerifierInfo[] newArray(int size) {
80+
return new VerifierInfo[size];
81+
}
82+
};
83+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
LOCAL_PATH:= $(call my-dir)
2+
include $(CLEAR_VARS)
3+
4+
LOCAL_MODULE_TAGS := tests
5+
6+
LOCAL_SRC_FILES := $(call all-subdir-java-files)
7+
8+
LOCAL_PACKAGE_NAME := FrameworkCoreTests_install_verifier_bad
9+
10+
include $(BUILD_PACKAGE)
11+

0 commit comments

Comments
 (0)