Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68b40294 authored by Michael Groover's avatar Michael Groover Committed by Android (Google) Code Review
Browse files

Merge "Add PackageSignatures readXml tests"

parents 9bf8ba3c a117b0d4
Loading
Loading
Loading
Loading
+9 −61
Original line number Diff line number Diff line
@@ -5785,52 +5785,32 @@ public class PackageParser {
            int AUTH = 16;
        }

        /**
         * APK Signature Scheme v3 includes support for adding a proof-of-rotation record that
         * contains two pieces of information:
         *   1) the past signing certificates
         *   2) the flags that APK wants to assign to each of the past signing certificates.
         *
         * These flags, which have a one-to-one relationship for the {@code pastSigningCertificates}
         * collection, represent the second piece of information and are viewed as capabilities.
         * They are an APK's way of telling the platform: "this is how I want to trust my old certs,
         * please enforce that." This is useful for situation where this app itself is using its
         * signing certificate as an authorization mechanism, like whether or not to allow another
         * app to have its SIGNATURE permission.  An app could specify whether to allow other apps
         * signed by its old cert 'X' to still get a signature permission it defines, for example.
         */
        @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, null, null);
                new SigningDetails(null, SignatureSchemeVersion.UNKNOWN, null, null);

        @VisibleForTesting
        public SigningDetails(Signature[] signatures,
                @SignatureSchemeVersion int signatureSchemeVersion,
                ArraySet<PublicKey> keys, Signature[] pastSigningCertificates,
                int[] pastSigningCertificatesFlags) {
                ArraySet<PublicKey> keys, Signature[] pastSigningCertificates) {
            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)
                Signature[] pastSigningCertificates)
                throws CertificateException {
            this(signatures, signatureSchemeVersion, toSigningKeys(signatures),
                    pastSigningCertificates, pastSigningCertificatesFlags);
                    pastSigningCertificates);
        }

        public SigningDetails(Signature[] signatures,
                @SignatureSchemeVersion int signatureSchemeVersion)
                throws CertificateException {
            this(signatures, signatureSchemeVersion,
                    null, null);
            this(signatures, signatureSchemeVersion, null);
        }

        public SigningDetails(SigningDetails orig) {
@@ -5844,17 +5824,14 @@ public class PackageParser {
                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;
            }
        }

@@ -5956,7 +5933,7 @@ public class PackageParser {
                    if (Signature.areEffectiveMatch(
                            oldDetails.signatures[0],
                            pastSigningCertificates[i])
                            && pastSigningCertificatesFlags[i] == flags) {
                            && pastSigningCertificates[i].getFlags() == flags) {
                        return true;
                    }
                }
@@ -6006,7 +5983,7 @@ public class PackageParser {
                for (int i = 0; i < pastSigningCertificates.length - 1; i++) {
                    if (pastSigningCertificates[i].equals(signature)) {
                        if (flags == PAST_CERT_EXISTS
                                || (flags & pastSigningCertificatesFlags[i]) == flags) {
                                || (flags & pastSigningCertificates[i].getFlags()) == flags) {
                            return true;
                        }
                    }
@@ -6090,7 +6067,7 @@ public class PackageParser {
                            pastSigningCertificates[i].toByteArray());
                    if (Arrays.equals(sha256Certificate, digest)) {
                        if (flags == PAST_CERT_EXISTS
                                || (flags & pastSigningCertificatesFlags[i]) == flags) {
                                || (flags & pastSigningCertificates[i].getFlags()) == flags) {
                            return true;
                        }
                    }
@@ -6127,7 +6104,6 @@ public class PackageParser {
            dest.writeInt(this.signatureSchemeVersion);
            dest.writeArraySet(this.publicKeys);
            dest.writeTypedArray(this.pastSigningCertificates, flags);
            dest.writeIntArray(this.pastSigningCertificatesFlags);
        }

        protected SigningDetails(Parcel in) {
@@ -6136,7 +6112,6 @@ public class PackageParser {
            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>() {
@@ -6175,9 +6150,6 @@ public class PackageParser {
            if (!Arrays.equals(pastSigningCertificates, that.pastSigningCertificates)) {
                return false;
            }
            if (!Arrays.equals(pastSigningCertificatesFlags, that.pastSigningCertificatesFlags)) {
                return false;
            }

            return true;
        }
@@ -6188,7 +6160,6 @@ public class PackageParser {
            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;
        }

@@ -6199,7 +6170,6 @@ public class PackageParser {
            private Signature[] mSignatures;
            private int mSignatureSchemeVersion = SignatureSchemeVersion.UNKNOWN;
            private Signature[] mPastSigningCertificates;
            private int[] mPastSigningCertificatesFlags;

            @UnsupportedAppUsage
            public Builder() {
@@ -6226,34 +6196,12 @@ public class PackageParser {
                return this;
            }

            /** set the flags for the {@code pastSigningCertificates} */
            @UnsupportedAppUsage
            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 */
            @UnsupportedAppUsage
@@ -6261,7 +6209,7 @@ public class PackageParser {
                    throws CertificateException {
                checkInvariants();
                return new SigningDetails(mSignatures, mSignatureSchemeVersion,
                        mPastSigningCertificates, mPastSigningCertificatesFlags);
                        mPastSigningCertificates);
            }
        }
    }
+31 −1
Original line number Diff line number Diff line
@@ -45,6 +45,20 @@ public class Signature implements Parcelable {
    private boolean mHaveHashCode;
    private SoftReference<String> mStringRef;
    private Certificate[] mCertificateChain;
    /**
     * APK Signature Scheme v3 includes support for adding a proof-of-rotation record that
     * contains two pieces of information:
     *   1) the past signing certificates
     *   2) the flags that APK wants to assign to each of the past signing certificates.
     *
     * These flags represent the second piece of information and are viewed as capabilities.
     * They are an APK's way of telling the platform: "this is how I want to trust my old certs,
     * please enforce that." This is useful for situation where this app itself is using its
     * signing certificate as an authorization mechanism, like whether or not to allow another
     * app to have its SIGNATURE permission.  An app could specify whether to allow other apps
     * signed by its old cert 'X' to still get a signature permission it defines, for example.
     */
    private int mFlags;

    /**
     * Create Signature from an existing raw byte array.
@@ -108,6 +122,22 @@ public class Signature implements Parcelable {
        mSignature = sig;
    }

    /**
     * Sets the flags representing the capabilities of the past signing certificate.
     * @hide
     */
    public void setFlags(int flags) {
        this.mFlags = flags;
    }

    /**
     * Returns the flags representing the capabilities of the past signing certificate.
     * @hide
     */
    public int getFlags() {
        return mFlags;
    }

    /**
     * Encode the Signature as ASCII text.
     */
+4 −8
Original line number Diff line number Diff line
@@ -81,19 +81,17 @@ public class ApkSignatureVerifier {
            Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
            Signature[] signerSigs = convertToSignatures(signerCerts);
            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);
                    pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
                }
            }
            return new PackageParser.SigningDetails(
                    signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
                    pastSignerSigs, pastSignerSigsFlags);
                    pastSignerSigs);
        } catch (SignatureNotFoundException e) {
            // not signed with v3, try older if allowed
            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
@@ -323,19 +321,17 @@ public class ApkSignatureVerifier {
            Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
            Signature[] signerSigs = convertToSignatures(signerCerts);
            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);
                    pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
                }
            }
            return new PackageParser.SigningDetails(
                    signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
                    pastSignerSigs, pastSignerSigsFlags);
                    pastSignerSigs);
        } catch (SignatureNotFoundException e) {
            // not signed with v3, try older if allowed
            if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
+56 −51
Original line number Diff line number Diff line
@@ -16,18 +16,18 @@

package com.android.server.pm;

import com.android.internal.util.XmlUtils;

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 com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
@@ -61,23 +61,22 @@ class PackageSignatures {
        serializer.attribute(null, "count", Integer.toString(mSigningDetails.signatures.length));
        serializer.attribute(null, "schemeVersion",
                Integer.toString(mSigningDetails.signatureSchemeVersion));
        writeCertsListXml(serializer, writtenSignatures, mSigningDetails.signatures, null);
        writeCertsListXml(serializer, writtenSignatures, mSigningDetails.signatures, false);

        // 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);
            writeCertsListXml(serializer, writtenSignatures,
                    mSigningDetails.pastSigningCertificates, true);
            serializer.endTag(null, "pastSigs");
        }
        serializer.endTag(null, tagName);
    }

    private void writeCertsListXml(XmlSerializer serializer, ArrayList<Signature> writtenSignatures,
            Signature[] signatures, int[] flags) throws IOException {
            Signature[] signatures, boolean isPastSigs) throws IOException {
        for (int i=0; i<signatures.length; i++) {
            serializer.startTag(null, "cert");
            final Signature sig = signatures[i];
@@ -96,8 +95,10 @@ class PackageSignatures {
                serializer.attribute(null, "index", Integer.toString(numWritten));
                serializer.attribute(null, "key", sig.toCharsString());
            }
            if (flags != null) {
                serializer.attribute(null, "flags", Integer.toString(flags[i]));
            // The flags attribute is only written for previous signatures to represent the
            // capabilities the developer wants to grant to the previous signing certificates.
            if (isPastSigs) {
                serializer.attribute(null, "flags", Integer.toString(sig.getFlags()));
            }
            serializer.endTag(null, "cert");
        }
@@ -114,6 +115,7 @@ class PackageSignatures {
                    "Error in package manager settings: <sigs> has"
                       + " no count at " + parser.getPositionDescription());
            XmlUtils.skipCurrentTag(parser);
            return;
        }
        final int count = Integer.parseInt(countStr);

@@ -128,16 +130,11 @@ class PackageSignatures {
            signatureSchemeVersion = Integer.parseInt(schemeVersionStr);
        }
        builder.setSignatureSchemeVersion(signatureSchemeVersion);
        Signature[] signatures = new Signature[count];
        int pos = readCertsListXml(parser, readSignatures, signatures, null, builder);
        ArrayList<Signature> signatureList = new ArrayList<>();
        int pos = readCertsListXml(parser, readSignatures, signatureList, count, false, builder);
        Signature[] signatures = signatureList.toArray(new Signature[signatureList.size()]);
        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());
@@ -154,9 +151,9 @@ class PackageSignatures {
    }

    private int readCertsListXml(XmlPullParser parser, ArrayList<Signature> readSignatures,
            Signature[] signatures, int[] flags, PackageParser.SigningDetails.Builder builder)
            ArrayList<Signature> signatures, int count, boolean isPastSigs,
            PackageParser.SigningDetails.Builder builder)
            throws IOException, XmlPullParserException {
        int count = signatures.length;
        int pos = 0;

        int outerDepth = parser.getDepth();
@@ -174,6 +171,7 @@ class PackageSignatures {
                if (pos < count) {
                    String index = parser.getAttributeValue(null, "index");
                    if (index != null) {
                        boolean signatureParsed = false;
                        try {
                            int idx = Integer.parseInt(index);
                            String key = parser.getAttributeValue(null, "key");
@@ -181,7 +179,8 @@ class PackageSignatures {
                                if (idx >= 0 && idx < readSignatures.size()) {
                                    Signature sig = readSignatures.get(idx);
                                    if (sig != null) {
                                        signatures[pos] = readSignatures.get(idx);
                                        signatures.add(sig);
                                        signatureParsed = true;
                                    } else {
                                        PackageManagerService.reportSettingsProblem(Log.WARN,
                                                "Error in package manager settings: <cert> "
@@ -195,12 +194,15 @@ class PackageSignatures {
                                                    + parser.getPositionDescription());
                                }
                            } else {
                                while (readSignatures.size() <= idx) {
                                // Create the signature first to prevent adding null entries to the
                                // output List if the key value is invalid.
                                Signature sig = new Signature(key);
                                while (readSignatures.size() < idx) {
                                    readSignatures.add(null);
                                }
                                Signature sig = new Signature(key);
                                readSignatures.set(idx, sig);
                                signatures[pos] = sig;
                                readSignatures.add(sig);
                                signatures.add(sig);
                                signatureParsed = true;
                            }
                        } catch (NumberFormatException e) {
                            PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -215,11 +217,22 @@ class PackageSignatures {
                                            + e.getMessage());
                        }

                        if (flags != null) {
                        if (isPastSigs) {
                            String flagsStr = parser.getAttributeValue(null, "flags");
                            if (flagsStr != null) {
                                try {
                                    flags[pos] = Integer.parseInt(flagsStr);
                                    int flagsValue = Integer.parseInt(flagsStr);
                                    // only modify the flags if the signature of the previous signer
                                    // was successfully parsed above
                                    if (signatureParsed) {
                                        signatures.get(signatures.size() - 1).setFlags(flagsValue);
                                    } else {
                                        PackageManagerService.reportSettingsProblem(Log.WARN,
                                                "Error in package manager settings: signature not "
                                                        + "available at index "
                                                        + pos + " to set flags at "
                                                        + parser.getPositionDescription());
                                    }
                                } catch (NumberFormatException e) {
                                    PackageManagerService.reportSettingsProblem(Log.WARN,
                                            "Error in package manager settings: <cert> "
@@ -246,7 +259,7 @@ class PackageSignatures {
                pos++;
                XmlUtils.skipCurrentTag(parser);
            } else if (tagName.equals("pastSigs")) {
                if (flags == null) {
                if (!isPastSigs) {
                    // we haven't encountered pastSigs yet, go ahead
                    String countStr = parser.getAttributeValue(null, "count");
                    if (countStr == null) {
@@ -254,28 +267,19 @@ class PackageSignatures {
                                "Error in package manager settings: <pastSigs> has"
                                        + " no count at " + parser.getPositionDescription());
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                    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);
                        ArrayList<Signature> pastSignatureList = new ArrayList<>();
                        int pastSigsPos = readCertsListXml(parser, readSignatures,
                                pastSignatureList,
                                pastSigsCount, true, builder);
                        Signature[] pastSignatures = pastSignatureList.toArray(
                                new Signature[pastSignatureList.size()]);
                        builder = builder.setPastSigningCertificates(pastSignatures);

                        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 "
@@ -326,7 +330,8 @@ class PackageSignatures {
                buf.append(Integer.toHexString(
                        mSigningDetails.pastSigningCertificates[i].hashCode()));
                buf.append(" flags: ");
                buf.append(Integer.toHexString(mSigningDetails.pastSigningCertificatesFlags[i]));
                buf.append(
                        Integer.toHexString(mSigningDetails.pastSigningCertificates[i].getFlags()));
            }
        }
        buf.append("]}");
+0 −1

File changed.

Preview size limit exceeded, changes collapsed.

Loading