Reject PKCS#7 SignerInfo with unsupported parameters.
This addresses the TODO to mimic the behavior of Android when
verifying APK JAR signatures. Unfortunately, the behavior of Android
kept changing in interesting ways between different platform versions.
This is hard-coded as a big lookup.
Bug: 27461702
Change-Id: I49bc181ee05f774ef8ee041af870385b35212c23
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java b/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java
index a40607a..9c58085 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java
@@ -663,6 +663,21 @@
JAR_SIG_VERIFY_EXCEPTION("Failed to verify JAR signature %1$s against %2$s: %3$s"),
/**
+ * JAR signature contains unsupported digest algorithm.
+ *
+ * <ul>
+ * <li>Parameter 1: name of the signature block file ({@code String})</li>
+ * <li>Parameter 2: digest algorithm OID ({@code String})</li>
+ * <li>Parameter 2: signature algorithm OID ({@code String})</li>
+ * <li>Parameter 3: API Levels on which this combination of algorithms is not supported
+ * ({@code String})</li>
+ * </ul>
+ */
+ JAR_SIG_UNSUPPORTED_SIG_ALG(
+ "JAR signature %1$s uses digest algorithm %2$s and signature algorithm %3$s which"
+ + " is not supported on API Levels %4$s"),
+
+ /**
* An exception was encountered while parsing JAR signature contained in a signature block.
*
* <ul>
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java
index 91d1990..1a4a90b 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java
@@ -562,7 +562,8 @@
// SignatureAlgorithm: dsaWithSha256 (2.16.840.1.101.3.4.3.2) and
// dsa (1.2.840.10040.4.1). The latter works only on API Level 22+. Thus, we use
// the former.
- sigAlgId = getSupportedAlgorithmId("2.16.840.1.101.3.4.3.2"); // DSA with SHA-256
+ sigAlgId =
+ getSupportedAlgorithmId("2.16.840.1.101.3.4.3.2"); // DSA with SHA-256
break;
default:
throw new IllegalArgumentException(
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java
index 762f5aa..91aa62e 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java
@@ -44,6 +44,7 @@
import com.android.apksigner.core.apk.ApkUtils;
import com.android.apksigner.core.internal.jar.ManifestParser;
import com.android.apksigner.core.internal.util.AndroidSdkVersion;
+import com.android.apksigner.core.internal.util.InclusiveIntRange;
import com.android.apksigner.core.internal.util.MessageDigestSink;
import com.android.apksigner.core.internal.zip.CentralDirectoryRecord;
import com.android.apksigner.core.internal.zip.LocalFileHeader;
@@ -412,7 +413,8 @@
mResult.addError(
Issue.JAR_SIG_MALFORMED_CERTIFICATE, mSignatureBlockEntry.getName(), e);
} else {
- mResult.addError(Issue.JAR_SIG_PARSE_EXCEPTION, mSignatureBlockEntry.getName(), e);
+ mResult.addError(
+ Issue.JAR_SIG_PARSE_EXCEPTION, mSignatureBlockEntry.getName(), e);
}
return;
}
@@ -426,7 +428,25 @@
if ((unverifiedSignerInfos != null) && (unverifiedSignerInfos.length > 0)) {
for (int i = 0; i < unverifiedSignerInfos.length; i++) {
SignerInfo unverifiedSignerInfo = unverifiedSignerInfos[i];
- // TODO: Reject sig/dig algorithms not supported on Android
+ String digestAlgorithmOid =
+ unverifiedSignerInfo.getDigestAlgorithmId().getOID().toString();
+ String signatureAlgorithmOid =
+ unverifiedSignerInfo
+ .getDigestEncryptionAlgorithmId().getOID().toString();
+ InclusiveIntRange desiredApiLevels = InclusiveIntRange.from(minSdkVersion);
+ List<InclusiveIntRange> apiLevelsWhereDigestAndSigAlgorithmSupported =
+ getSigAlgSupportedApiLevels(digestAlgorithmOid, signatureAlgorithmOid);
+ List<InclusiveIntRange> apiLevelsWhereDigestAlgorithmNotSupported =
+ desiredApiLevels.getValuesNotIn(apiLevelsWhereDigestAndSigAlgorithmSupported);
+ if (!apiLevelsWhereDigestAlgorithmNotSupported.isEmpty()) {
+ mResult.addError(
+ Issue.JAR_SIG_UNSUPPORTED_SIG_ALG,
+ mSignatureBlockEntry.getName(),
+ digestAlgorithmOid,
+ signatureAlgorithmOid,
+ String.valueOf(apiLevelsWhereDigestAlgorithmNotSupported));
+ return;
+ }
try {
verifiedSignerInfo = sigBlock.verify(unverifiedSignerInfo, mSigFileBytes);
} catch (NoSuchAlgorithmException | SignatureException e) {
@@ -472,6 +492,351 @@
mResult.certChain.addAll(certChain);
}
+ private static final String OID_DIGEST_MD5 = "1.2.840.113549.2.5";
+ private static final String OID_DIGEST_SHA1 = "1.3.14.3.2.26";
+ private static final String OID_DIGEST_SHA224 = "2.16.840.1.101.3.4.2.4";
+ private static final String OID_DIGEST_SHA256 = "2.16.840.1.101.3.4.2.1";
+ private static final String OID_DIGEST_SHA384 = "2.16.840.1.101.3.4.2.2";
+ private static final String OID_DIGEST_SHA512 = "2.16.840.1.101.3.4.2.3";
+
+ private static final String OID_SIG_RSA = "1.2.840.113549.1.1.1";
+ private static final String OID_SIG_MD5_WITH_RSA = "1.2.840.113549.1.1.4";
+ private static final String OID_SIG_SHA1_WITH_RSA = "1.2.840.113549.1.1.5";
+ private static final String OID_SIG_SHA224_WITH_RSA = "1.2.840.113549.1.1.14";
+ private static final String OID_SIG_SHA256_WITH_RSA = "1.2.840.113549.1.1.11";
+ private static final String OID_SIG_SHA384_WITH_RSA = "1.2.840.113549.1.1.12";
+ private static final String OID_SIG_SHA512_WITH_RSA = "1.2.840.113549.1.1.13";
+
+ private static final String OID_SIG_DSA = "1.2.840.10040.4.1";
+ private static final String OID_SIG_SHA1_WITH_DSA = "1.2.840.10040.4.3";
+ private static final String OID_SIG_SHA224_WITH_DSA = "2.16.840.1.101.3.4.3.1";
+ private static final String OID_SIG_SHA256_WITH_DSA = "2.16.840.1.101.3.4.3.2";
+
+ private static final String OID_SIG_SHA1_WITH_ECDSA = "1.2.840.10045.4.1";
+ private static final String OID_SIG_SHA224_WITH_ECDSA = "1.2.840.10045.4.3.1";
+ private static final String OID_SIG_SHA256_WITH_ECDSA = "1.2.840.10045.4.3.2";
+ private static final String OID_SIG_SHA384_WITH_ECDSA = "1.2.840.10045.4.3.3";
+ private static final String OID_SIG_SHA512_WITH_ECDSA = "1.2.840.10045.4.3.4";
+
+ private static final Map<String, List<InclusiveIntRange>> SUPPORTED_SIG_ALG_OIDS =
+ new HashMap<>();
+ {
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_RSA,
+ InclusiveIntRange.from(0));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_MD5_WITH_RSA,
+ InclusiveIntRange.fromTo(0, 8), InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA1_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA224_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA256_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA384_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA512_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_RSA,
+ InclusiveIntRange.from(0));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_MD5_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA1_WITH_RSA,
+ InclusiveIntRange.from(0));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA224_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA256_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA384_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA512_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_RSA,
+ InclusiveIntRange.fromTo(0, 8), InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_MD5_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA1_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA224_WITH_RSA,
+ InclusiveIntRange.fromTo(0, 8), InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA256_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA384_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA512_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_RSA,
+ InclusiveIntRange.fromTo(0, 8), InclusiveIntRange.from(18));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_MD5_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA1_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA224_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA256_WITH_RSA,
+ InclusiveIntRange.fromTo(0, 8), InclusiveIntRange.from(18));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA384_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA512_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_RSA,
+ InclusiveIntRange.from(18));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_MD5_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA1_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA224_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA256_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA384_WITH_RSA,
+ InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA512_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_RSA,
+ InclusiveIntRange.from(18));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_MD5_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA1_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA224_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA256_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA384_WITH_RSA,
+ InclusiveIntRange.fromTo(21, 21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA512_WITH_RSA,
+ InclusiveIntRange.from(21));
+
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA1_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA224_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA256_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_DSA,
+ InclusiveIntRange.from(0));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA1_WITH_DSA,
+ InclusiveIntRange.from(9));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA224_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA256_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_DSA,
+ InclusiveIntRange.from(22));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA1_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA224_WITH_DSA,
+ InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA256_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_DSA,
+ InclusiveIntRange.from(22));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA1_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA224_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA256_WITH_DSA,
+ InclusiveIntRange.from(21));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA1_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA224_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA256_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA1_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA224_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA256_WITH_DSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA1_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA224_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA256_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA384_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_MD5, OID_SIG_SHA512_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA1_WITH_ECDSA,
+ InclusiveIntRange.from(18));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA224_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA256_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA384_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA1, OID_SIG_SHA512_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA1_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA224_WITH_ECDSA,
+ InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA256_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA384_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA224, OID_SIG_SHA512_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA1_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA224_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA256_WITH_ECDSA,
+ InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA384_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA256, OID_SIG_SHA512_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA1_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA224_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA256_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA384_WITH_ECDSA,
+ InclusiveIntRange.from(21));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA384, OID_SIG_SHA512_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA1_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA224_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA256_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA384_WITH_ECDSA,
+ InclusiveIntRange.fromTo(21, 23));
+ addSupportedSigAlg(
+ OID_DIGEST_SHA512, OID_SIG_SHA512_WITH_ECDSA,
+ InclusiveIntRange.from(21));
+ }
+
+ private static void addSupportedSigAlg(
+ String digestAlgorithmOid,
+ String signatureAlgorithmOid,
+ InclusiveIntRange... supportedApiLevels) {
+ SUPPORTED_SIG_ALG_OIDS.put(
+ digestAlgorithmOid + "with" + signatureAlgorithmOid,
+ Arrays.asList(supportedApiLevels));
+ }
+
+ private List<InclusiveIntRange> getSigAlgSupportedApiLevels(
+ String digestAlgorithmOid,
+ String signatureAlgorithmOid) {
+ List<InclusiveIntRange> result =
+ SUPPORTED_SIG_ALG_OIDS.get(digestAlgorithmOid + "with" + signatureAlgorithmOid);
+ return (result != null) ? result : Collections.emptyList();
+ }
+
public void verifySigFileAgainstManifest(
byte[] manifestBytes,
ManifestParser.Section manifestMainSection,
@@ -864,8 +1229,10 @@
MIN_SDK_VESION_FROM_WHICH_DIGEST_SUPPORTED_IN_MANIFEST.put("MD5", 0);
MIN_SDK_VESION_FROM_WHICH_DIGEST_SUPPORTED_IN_MANIFEST.put("SHA-1", 0);
MIN_SDK_VESION_FROM_WHICH_DIGEST_SUPPORTED_IN_MANIFEST.put("SHA-256", 0);
- MIN_SDK_VESION_FROM_WHICH_DIGEST_SUPPORTED_IN_MANIFEST.put("SHA-384", 9);
- MIN_SDK_VESION_FROM_WHICH_DIGEST_SUPPORTED_IN_MANIFEST.put("SHA-512", 9);
+ MIN_SDK_VESION_FROM_WHICH_DIGEST_SUPPORTED_IN_MANIFEST.put(
+ "SHA-384", AndroidSdkVersion.GINGERBREAD);
+ MIN_SDK_VESION_FROM_WHICH_DIGEST_SUPPORTED_IN_MANIFEST.put(
+ "SHA-512", AndroidSdkVersion.GINGERBREAD);
}
private static byte[] getDigest(Collection<NamedDigest> digests, String jcaDigestAlgorithm) {
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/util/AndroidSdkVersion.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/util/AndroidSdkVersion.java
index f7fb7cd..3e9d039 100644
--- a/tools/apksigner/core/src/com/android/apksigner/core/internal/util/AndroidSdkVersion.java
+++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/util/AndroidSdkVersion.java
@@ -24,6 +24,9 @@
/** Hidden constructor to prevent instantiation. */
private AndroidSdkVersion() {}
+ /** Android 2.3. */
+ public static final int GINGERBREAD = 9;
+
/** Android 4.3. The revenge of the beans. */
public static final int JELLY_BEAN_MR2 = 18;
diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/util/InclusiveIntRange.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/util/InclusiveIntRange.java
new file mode 100644
index 0000000..baf3655
--- /dev/null
+++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/util/InclusiveIntRange.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apksigner.core.internal.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Inclusive interval of integers.
+ */
+public class InclusiveIntRange {
+ private final int min;
+ private final int max;
+
+ private InclusiveIntRange(int min, int max) {
+ this.min = min;
+ this.max = max;
+ }
+
+ public int getMin() {
+ return min;
+ }
+
+ public int getMax() {
+ return max;
+ }
+
+ public static InclusiveIntRange fromTo(int min, int max) {
+ return new InclusiveIntRange(min, max);
+ }
+
+ public static InclusiveIntRange from(int min) {
+ return new InclusiveIntRange(min, Integer.MAX_VALUE);
+ }
+
+ public List<InclusiveIntRange> getValuesNotIn(
+ List<InclusiveIntRange> sortedNonOverlappingRanges) {
+ if (sortedNonOverlappingRanges.isEmpty()) {
+ return Collections.singletonList(this);
+ }
+
+ int testValue = min;
+ List<InclusiveIntRange> result = null;
+ for (InclusiveIntRange range : sortedNonOverlappingRanges) {
+ int rangeMax = range.max;
+ if (testValue > rangeMax) {
+ continue;
+ }
+ int rangeMin = range.min;
+ if (testValue < range.min) {
+ if (result == null) {
+ result = new ArrayList<>();
+ }
+ result.add(fromTo(testValue, rangeMin - 1));
+ }
+ if (rangeMax >= max) {
+ return (result != null) ? result : Collections.emptyList();
+ }
+ testValue = rangeMax + 1;
+ }
+ if (testValue <= max) {
+ if (result == null) {
+ result = new ArrayList<>(1);
+ }
+ result.add(fromTo(testValue, max));
+ }
+ return (result != null) ? result : Collections.emptyList();
+ }
+
+ @Override
+ public String toString() {
+ return "[" + min + ", " + ((max < Integer.MAX_VALUE) ? (max + "]") : "\u221e)");
+ }
+}