From b141ded82bef9af3c65b4192f986605f6c0dc21e Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Tue, 3 May 2016 18:12:45 -0700 Subject: [PATCH] SHA-256 with ECDSA supported only on API Level 21 and higher. Turns out APK signatures using SHA-256 with ECDSA are accepted only by platforms with API Level 21 and higher, not 18 and higher. Bug: 28296599 Change-Id: I3fab5be17bf3a9bdbf4d84d90d51448027c7e761 --- tools/signapk/src/com/android/signapk/SignApk.java | 34 ++++++++++------------ 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/tools/signapk/src/com/android/signapk/SignApk.java b/tools/signapk/src/com/android/signapk/SignApk.java index 69f17e2bb..c80d93ccb 100644 --- a/tools/signapk/src/com/android/signapk/SignApk.java +++ b/tools/signapk/src/com/android/signapk/SignApk.java @@ -82,6 +82,7 @@ import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.regex.Pattern; + import javax.crypto.Cipher; import javax.crypto.EncryptedPrivateKeyInfo; import javax.crypto.SecretKeyFactory; @@ -126,34 +127,29 @@ class SignApk { private static final String APK_SIG_SCHEME_V2_DIGEST_ALGORITHM = "SHA-256"; /** - * Minimum Android SDK API Level which accepts JAR signatures which use SHA-256. Older platform - * versions accept only SHA-1 signatures. - */ - private static final int MIN_API_LEVEL_FOR_SHA256_JAR_SIGNATURES = 18; - - /** * Returns the digest algorithm ID (one of {@code USE_SHA1} or {@code USE_SHA256}) to be used - * for v1 signing (using JAR Signature Scheme) an APK using the private key corresponding to the - * provided certificate. + * for v1 signing (JAR signing) an APK using the private key corresponding to the provided + * certificate. * * @param minSdkVersion minimum Android platform API Level supported by the APK (see * minSdkVersion attribute in AndroidManifest.xml). The higher the minSdkVersion, the * stronger hash may be used for signing the APK. */ private static int getV1DigestAlgorithmForApk(X509Certificate cert, int minSdkVersion) { - String sigAlg = cert.getSigAlgName().toUpperCase(Locale.US); - if ("SHA1WITHRSA".equals(sigAlg) || "MD5WITHRSA".equals(sigAlg)) { - // see "HISTORICAL NOTE" above. - if (minSdkVersion < MIN_API_LEVEL_FOR_SHA256_JAR_SIGNATURES) { - return USE_SHA1; - } else { - return USE_SHA256; + String keyAlgorithm = cert.getPublicKey().getAlgorithm(); + if ("RSA".equalsIgnoreCase(keyAlgorithm)) { + // RSA can be used only with SHA-1 prior to API Level 18. + return (minSdkVersion < 18) ? USE_SHA1 : USE_SHA256; + } else if ("EC".equalsIgnoreCase(keyAlgorithm)) { + // ECDSA cannot be used prior to API Level 18 at all. It can only be used with SHA-1 + // on API Levels 18, 19, and 20. + if (minSdkVersion < 18) { + throw new IllegalArgumentException( + "ECDSA signatures only supported for minSdkVersion 18 and higher"); } - } else if (sigAlg.startsWith("SHA256WITH")) { - return USE_SHA256; + return (minSdkVersion < 21) ? USE_SHA1 : USE_SHA256; } else { - throw new IllegalArgumentException("unsupported signature algorithm \"" + sigAlg + - "\" in cert [" + cert.getSubjectDN()); + throw new IllegalArgumentException("Unsupported key algorithm: " + keyAlgorithm); } } -- 2.11.0