From 29045203f3f694cddea7b3f115ea82f648ba0cba Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Tue, 31 May 2016 16:04:49 -0700 Subject: Use correct cert chain from PKCS#7 SignedData block. This fixes a bug where APK JAR signature verifier returned the wrong certificate chain. Rather than returning the cert chain of the verified SignerInfo, it was returning the bag of certs of the PKCS#7 SignedData block. This issue was introduced in Android N and thus does not affect earlier Android platform versions. Bug: 29055836 Change-Id: I684c0f8e9ff47b922030645e07b6a114c0eb0963 --- core/java/android/util/jar/StrictJarVerifier.java | 33 ++++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'core/java') diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java index 6da50ba85b37..cb71ecc1da8b 100644 --- a/core/java/android/util/jar/StrictJarVerifier.java +++ b/core/java/android/util/jar/StrictJarVerifier.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -41,6 +42,7 @@ import android.util.apk.ApkSignatureSchemeV2Verifier; import libcore.io.Base64; import sun.security.jca.Providers; import sun.security.pkcs.PKCS7; +import sun.security.pkcs.SignerInfo; /** * Non-public class used by {@link JarFile} and {@link JarInputStream} to manage @@ -308,18 +310,29 @@ class StrictJarVerifier { obj = Providers.startJarVerification(); PKCS7 block = new PKCS7(blockBytes); - if (block.verify(sfBytes) == null) { - throw new GeneralSecurityException("Failed to verify signature"); + SignerInfo[] verifiedSignerInfos = block.verify(sfBytes); + if ((verifiedSignerInfos == null) || (verifiedSignerInfos.length == 0)) { + throw new GeneralSecurityException( + "Failed to verify signature: no verified SignerInfos"); } - X509Certificate[] blockCerts = block.getCertificates(); - Certificate[] signerCertChain = null; - if (blockCerts != null) { - signerCertChain = new Certificate[blockCerts.length]; - for (int i = 0; i < blockCerts.length; ++i) { - signerCertChain[i] = blockCerts[i]; - } + // Ignore any SignerInfo other than the first one, to be compatible with older Android + // platforms which have been doing this for years. See + // libcore/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java + // verifySignature method of older platforms. + SignerInfo verifiedSignerInfo = verifiedSignerInfos[0]; + List verifiedSignerCertChain = + verifiedSignerInfo.getCertificateChain(block); + if (verifiedSignerCertChain == null) { + // Should never happen + throw new GeneralSecurityException( + "Failed to find verified SignerInfo certificate chain"); + } else if (verifiedSignerCertChain.isEmpty()) { + // Should never happen + throw new GeneralSecurityException( + "Verified SignerInfo certificate chain is emtpy"); } - return signerCertChain; + return verifiedSignerCertChain.toArray( + new X509Certificate[verifiedSignerCertChain.size()]); } catch (IOException e) { throw new GeneralSecurityException("IO exception verifying jar cert", e); } finally { -- cgit v1.2.3