Add SourceStamp verification result model am: b8be05176d

Change-Id: Iddfdda1e16af153fa84c0f84208918a28172e869
diff --git a/src/main/java/com/android/apksig/ApkVerifier.java b/src/main/java/com/android/apksig/ApkVerifier.java
index a164805..2671bcf 100644
--- a/src/main/java/com/android/apksig/ApkVerifier.java
+++ b/src/main/java/com/android/apksig/ApkVerifier.java
@@ -567,12 +567,14 @@
         private final List<V2SchemeSignerInfo> mV2SchemeSigners = new ArrayList<>();
         private final List<V3SchemeSignerInfo> mV3SchemeSigners = new ArrayList<>();
         private final List<V4SchemeSignerInfo> mV4SchemeSigners = new ArrayList<>();
+        private SourceStampInfo mSourceStampInfo;
 
         private boolean mVerified;
         private boolean mVerifiedUsingV1Scheme;
         private boolean mVerifiedUsingV2Scheme;
         private boolean mVerifiedUsingV3Scheme;
         private boolean mVerifiedUsingV4Scheme;
+        private boolean mSourceStampVerified;
         private SigningCertificateLineage mSigningCertificateLineage;
 
         /**
@@ -615,6 +617,13 @@
         }
 
         /**
+         * Returns {@code true} if the APK's SourceStamp signature verified.
+         */
+        public boolean isSourceStampVerified() {
+            return mSourceStampVerified;
+        }
+
+        /**
          * Returns the verified signers' certificates, one per signer.
          */
         public List<X509Certificate> getSignerCertificates() {
@@ -671,6 +680,13 @@
         }
 
         /**
+         * Returns information about SourceStamp associated with the APK's signature.
+         */
+        public SourceStampInfo getSourceStampInfo() {
+            return mSourceStampInfo;
+        }
+
+        /**
          * Returns the combined SigningCertificateLineage associated with this APK's APK Signature
          * Scheme v3 signing block.
          */
@@ -729,6 +745,11 @@
                         mV4SchemeSigners.add(new V4SchemeSignerInfo(signer));
                     }
                     break;
+                case ApkSigningBlockUtils.VERSION_SOURCE_STAMP:
+                    mSourceStampVerified = source.verified;
+                    if (!source.signers.isEmpty()) {
+                        mSourceStampInfo = new SourceStampInfo(source.signers.get(0));
+                    }
                 default:
                     throw new IllegalArgumentException("Unknown Signing Block Scheme Id");
             }
@@ -765,6 +786,9 @@
                     }
                 }
             }
+            if (mSourceStampInfo != null && mSourceStampInfo.containsErrors()) {
+                return true;
+            }
 
             return false;
         }
@@ -1053,12 +1077,55 @@
                 return mContentDigests;
             }
         }
+
+        /**
+         * Information about SourceStamp associated with the APK's signature.
+         */
+        public static class SourceStampInfo {
+            private final List<X509Certificate> mCertificates;
+
+            private final List<IssueWithParams> mErrors;
+            private final List<IssueWithParams> mWarnings;
+
+            private SourceStampInfo(ApkSigningBlockUtils.Result.SignerInfo result) {
+                mCertificates = result.certs;
+                mErrors = result.getErrors();
+                mWarnings = result.getWarnings();
+            }
+
+            /**
+             * Returns the SourceStamp's signing certificate or {@code null} if not available. The
+             * certificate is guaranteed to be available if no errors were encountered during
+             * verification (see {@link #containsErrors()}.
+             *
+             * <p>This certificate contains the SourceStamp's public key.
+             */
+            public X509Certificate getCertificate() {
+                return mCertificates.isEmpty() ? null : mCertificates.get(0);
+            }
+
+            private void addError(Issue msg, Object... parameters) {
+                mErrors.add(new IssueWithParams(msg, parameters));
+            }
+
+            public boolean containsErrors() {
+                return !mErrors.isEmpty();
+            }
+
+            public List<IssueWithParams> getErrors() {
+                return mErrors;
+            }
+
+            public List<IssueWithParams> getWarnings() {
+                return mWarnings;
+            }
+        }
     }
 
     /**
      * Error or warning encountered while verifying an APK's signatures.
      */
-    public static enum Issue {
+    public enum Issue {
 
         /**
          * APK is not JAR-signed.
@@ -2064,11 +2131,92 @@
          */
         V4_SIG_VERSION_NOT_CURRENT(
                 "V4 signature format version %1$d is different from the tool's current "
-                        + "version %2$d");
+                        + "version %2$d"),
+
+        /** APK contains SourceStamp file, but does not contain a SourceStamp signature. */
+        SOURCE_STAMP_SIG_MISSING("No SourceStamp signature"),
+
+        /**
+         * SourceStamp's certificate could not be parsed.
+         *
+         * <ul>
+         *   <li>Parameter 1: error details ({@code Throwable})
+         * </ul>
+         */
+        SOURCE_STAMP_MALFORMED_CERTIFICATE("Malformed certificate: %1$s"),
+
+        /** Failed to parse SourceStamp's signature. */
+        SOURCE_STAMP_MALFORMED_SIGNATURE("Malformed SourceStamp signature"),
+
+        /**
+         * SourceStamp contains a signature produced using an unknown algorithm.
+         *
+         * <ul>
+         *   <li>Parameter 1: algorithm ID ({@code Integer})
+         * </ul>
+         */
+        SOURCE_STAMP_UNKNOWN_SIG_ALGORITHM("Unknown signature algorithm: %1$#x"),
+
+        /**
+         * An exception was encountered while verifying SourceStamp signature.
+         *
+         * <ul>
+         *   <li>Parameter 1: signature algorithm ({@link SignatureAlgorithm})
+         *   <li>Parameter 2: exception ({@code Throwable})
+         * </ul>
+         */
+        SOURCE_STAMP_VERIFY_EXCEPTION("Failed to verify %1$s signature: %2$s"),
+
+        /**
+         * SourceStamp signature block did not verify.
+         *
+         * <ul>
+         *   <li>Parameter 1: signature algorithm ({@link SignatureAlgorithm})
+         * </ul>
+         */
+        SOURCE_STAMP_DID_NOT_VERIFY("%1$s signature over signed-data did not verify"),
+
+        /** SourceStamp offers no signatures. */
+        SOURCE_STAMP_NO_SIGNATURE("No signature"),
+
+        /** SourceStamp offers an unsupported signature. */
+        SOURCE_STAMP_NO_SUPPORTED_SIGNATURE("Signature not supported"),
+
+        /** SourceStamp offers no certificates. */
+        SOURCE_STAMP_NO_CERTIFICATE("No certificates"),
+
+        /**
+         * SourceStamp's certificate listed in the APK signing block does not match the certificate
+         * listed in the SourceStamp file in the APK.
+         *
+         * <ul>
+         *   <li>Parameter 1: SHA-256 hash of certificate from SourceStamp block in APK signing
+         *       block ({@code String})
+         *   <li>Parameter 2: SHA-256 hash of certificate from SourceStamp file in APK ({@code
+         *       String})
+         * </ul>
+         */
+        SOURCE_STAMP_CERTIFICATE_MISMATCH_BETWEEN_SIGNATURE_BLOCK_AND_APK(
+                "Certificate mismatch between SourceStamp block in APK signing block and"
+                        + " SourceStamp file in APK: <%1$s> vs <%2$s>"),
+
+        /**
+         * The APK's digest in APK signing block does not match the digest contained in the
+         * SourceStamp signature.
+         *
+         * <ul>
+         *   <li>Parameter 1: content digest algorithm ({@link ContentDigestAlgorithm})
+         *   <li>Parameter 2: hex-encoded expected digest of the APK ({@code String})
+         *   <li>Parameter 3: hex-encoded actual digest of the APK ({@code String})
+         * </ul>
+         */
+        SOURCE_STAMP_APK_DIGEST_DID_NOT_VERIFY(
+                "APK integrity check failed. %1$s digest mismatch."
+                        + " Expected: <%2$s>, actual: <%3$s>");
 
         private final String mFormat;
 
-        private Issue(String format) {
+        Issue(String format) {
             mFormat = format;
         }
 
diff --git a/src/main/java/com/android/apksig/internal/util/AndroidSdkVersion.java b/src/main/java/com/android/apksig/internal/util/AndroidSdkVersion.java
index 615d251..4ef67c7 100644
--- a/src/main/java/com/android/apksig/internal/util/AndroidSdkVersion.java
+++ b/src/main/java/com/android/apksig/internal/util/AndroidSdkVersion.java
@@ -47,4 +47,7 @@
 
     /** Android P. */
     public static final int P = 28;
+
+    /** Android R. */
+    public static final int R = 30;
 }