什么阻止Javavalidation具有多个签名算法的签名jar

快速背景:我们发布了一个webstart应用程序,其中包括我们自己的应用程序jar和众多第三方jar。 Webstart要求jnlp文件引用的所有分布式jar都由单个证书签名。 因此,我们使用自签名证书签署所有jar子(我们的jar子和第三方jar子)。 一些第三方jar子已经由生产它们的一方签署,但我们只是再次签署它们,这很好。 到现在。

问题:我们最近从Java 6迁移到Java 7,突然webstart拒绝加载一些jar,抱怨:“无效的SHA1签名文件摘要”。 这只发生在一些jar子而不是其他jar子上,并且在那些失败的jar子中出现的共同线程似乎有多个签名。

在搜索SO和互联网之后,似乎Java的jarsigner的默认签名算法在Java 6和Java 7之间发生了变化,从SHA1到SHA256,并且各种人都建议使用“jarsigner -digestalg SHA1”来解决validation问题。 我试过了,果然我们的多重签名jar子validation了。 所以这似乎是我们问题的解决方法。

从我可以收集到的内容来看,第三方签名似乎是SHA1签名,我们使用默认签名 – SHA256进行签名 – 导致签名混合。 当我使用’-digestalg’开关强制SHA1时,我们有两个相同类型的签名,现在validation工作正常。 所以似乎问题是由多个签名使用不同的算法引起的? 或者是否还有其他一些我缺失的因素。

问题:

  1. 为什么无法使用SHA1 + SHA256validation,但使用SHA1 + SHA1进行validation? 有技术原因吗? 安全政策的原因? 为什么不能validation两个签名是否正确?
  2. 使用(继续使用)SHA1而不是现在默认的SHA256有什么缺点吗?

您可以为每个引用相关jar文件的第三方签名者创建单独的JNLP文件,然后让您的主JNLP使用元素依赖于这些文件,而不是自己重新签名第三方jar。 所有JAR文件必须由同一签名者签名的限制仅适用于一个JNLP,每个扩展可以具有不同的签名者。

如果做不到这一点,您可以在添加自己的签名之前删除第三方签名(通过重新打包而不使用META-INF/*.{SF,DSA,RSA}

我知道这有点晚了 – 但我们现在正在通过这个。 我们的问题是“MD2withRSA”签名问题。 我分几步解决了这个问题:

1)与Verisign合作从我们的证书中删除“旧”算法 – 因此MD2withRSA算法不再用于签署我们的jar子。

2)我们还有一堆第三方jar子,我们只是用我们的证书重新签名。 当MANIFEST.MF中列出了SHA1和SHA-256算法时,我们遇到了“并非所有使用相同证书签名的jar”。 这只是jar子的一小部分 – 所以对于那些,我们删除了MANIFEST.MF文件的下半部分; 具有Name:class和算法规范的那部分。 该数据在我们流程的最后部分重新生成。 我们解压缩,排除旧的签名信息并重新jar。 最后一步是重新签名jar子。 我们发现在某些情况下,如果带有SHA1条目的旧Name:条目在MANIFEST.MF中,那么签名没有用SHA-256替换它 – 所以我们手动处理这些jar(现在)。 致力于更新我们的Ant任务来处理这个问题。

对不起 – 不能说为什么网站启动不处理/允许它 – 只是弄清楚如何让它工作!

祝好运!

看起来像是JRE中的一个错误。 就个人而言,我假设旧的默认签名算法(带有SHA1摘要的DSA)不如新的(带有SHA256摘要的RSA)安全,所以最好不要使用“-digestalg SHA1”选项。

我通过在构建脚本中使用自定义Ant任务来解决此问题,以便在签名之前“取消签名”我的jar。 这样每个jar子只有一个签名。

这是我的Ant任务:

 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.resources.FileProvider; import org.apache.tools.ant.types.resources.FileResource; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.ResourceUtils; public class UnsignJar extends Task { protected List filesets = new ArrayList(); protected File todir; public void addFileset(final FileSet set) { filesets.add(set); } public void setTodir(File todir) { this.todir = todir; } @Override public void execute() throws BuildException { if (todir == null) { throw new BuildException("todir attribute not specified"); } if (filesets.isEmpty()) { throw new BuildException("no fileset specified"); } Path path = new Path(getProject()); for (FileSet fset : filesets) { path.addFileset(fset); } for (Resource r : path) { FileResource from = ResourceUtils.asFileResource(r .as(FileProvider.class)); File destFile = new File(todir, from.getName()); File fromFile = from.getFile(); if (!isUpToDate(destFile, fromFile)) { unsign(destFile, fromFile); } } } private void unsign(File destFile, File fromFile) { log("Unsigning " + fromFile); try { ZipInputStream zin = new ZipInputStream( new FileInputStream(fromFile)); ZipOutputStream zout = new ZipOutputStream( new FileOutputStream(destFile)); ZipEntry entry = zin.getNextEntry(); while (entry != null) { if (!entry.getName().startsWith("META-INF")) { copyEntry(zin, zout, entry); } zin.closeEntry(); entry = zin.getNextEntry(); } zin.close(); zout.close(); } catch (IOException e) { throw new BuildException(e); } } private void copyEntry(ZipInputStream zin, ZipOutputStream zout, ZipEntry entry) throws IOException { zout.putNextEntry(entry); byte[] buffer = new byte[1024 * 16]; int byteCount = zin.read(buffer); while (byteCount != -1) { zout.write(buffer, 0, byteCount); byteCount = zin.read(buffer); } zout.closeEntry(); } private boolean isUpToDate(File destFile, File fromFile) { return FileUtils.getFileUtils().isUpToDate(fromFile, destFile); } }