2828import android .os .Bundle ;
2929import android .os .PatternMatcher ;
3030import android .util .AttributeSet ;
31+ import android .util .Base64 ;
3132import android .util .DisplayMetrics ;
33+ import android .util .Log ;
3234import android .util .Slog ;
3335import android .util .TypedValue ;
3436import com .android .internal .util .XmlUtils ;
4042import java .io .IOException ;
4143import java .io .InputStream ;
4244import java .lang .ref .WeakReference ;
45+ import java .security .KeyFactory ;
46+ import java .security .NoSuchAlgorithmException ;
47+ import java .security .PublicKey ;
4348import java .security .cert .Certificate ;
4449import java .security .cert .CertificateEncodingException ;
50+ import java .security .spec .EncodedKeySpec ;
51+ import java .security .spec .InvalidKeySpecException ;
52+ import java .security .spec .X509EncodedKeySpec ;
4553import java .util .ArrayList ;
4654import java .util .Enumeration ;
4755import java .util .Iterator ;
56+ import java .util .List ;
4857import java .util .jar .Attributes ;
4958import java .util .jar .JarEntry ;
5059import 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
0 commit comments