with check java jar code-signing java-web-start jarsigner

check - ¿Qué impide que Java verifique los frascos firmados con múltiples algoritmos de firma?



java sign jar (3)

Fondo rápido: lanzamos una aplicación webstart, que incluye nuestros propios archivos jar y numerosos archivos jar de terceros. Webstart requiere que todos los archivos jar distribuidos a los que hace referencia el archivo jnlp estén firmados por un solo certificado. Por lo tanto, firmamos todos los frascos (nuestros frascos y los frascos de terceros) utilizando un certificado autofirmado. Algunos frascos de terceros ya están firmados por la parte que los produjo, pero simplemente los firmamos nuevamente, y esto funciona bien. Hasta ahora.

Problema: recientemente pasamos de Java 6 a Java 7, y de repente, webstart se niega a cargar algunos archivos jar, quejándose: "Resumen de archivo de firma SHA1 no válido". Esto solo sucede con algunos frascos y no con otros, y el hilo común que aparece entre los frascos que fallan parece tener varias firmas.

Después de buscar en SO e Internet, parece que el algoritmo de firma predeterminado para el jarsigner de Java ha cambiado entre Java 6 y Java 7, de SHA1 a SHA256, y varias personas recomiendan usar "jarsigner -digestalg SHA1" para evitar problemas de verificación . Lo intenté, y estoy seguro de que nuestros frascos de firma múltiple ahora lo verifican. Así que esto parece ser una solución para nuestro problema.

De lo que puedo recopilar, parece que la firma de terceros es una firma SHA1, y firmamos con el valor predeterminado, SHA256, que resulta en una mezcla de firmas. Cuando fuerzo SHA1 usando el interruptor ''-digestalg'', tenemos dos firmas del mismo tipo, y la verificación ahora funciona. ¿Entonces parece que el problema es causado por tener varias firmas con diferentes algoritmos? ¿O hay algún otro factor que me falta?

Preguntas:

  1. ¿Por qué no se puede verificar con SHA1 + SHA256, pero se verifica con SHA1 + SHA1? ¿Hay alguna razón técnica? ¿Una razón de política de seguridad? ¿Por qué no se puede verificar que ambas firmas son correctas?
  2. ¿Hay algún inconveniente para nosotros al usar (seguir usando) SHA1 en lugar del SHA256 ahora predeterminado?

Parece un error en el JRE. Personalmente, asumo que el algoritmo de firma predeterminado anterior (DSA con resumen SHA1) es menos seguro que el nuevo (RSA con resumen SHA256), por lo que es mejor no usar la opción "-digestalg SHA1".

Resolví este problema usando una tarea Ant personalizada en mi script de compilación para "desasignar" mis archivos antes de firmarlos. De esa manera solo hay una firma para cada jarra.

Aquí está mi tarea 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<FileSet> filesets = new ArrayList<FileSet>(); 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); } }


Sé que esto es un poco tarde, pero estamos pasando por esto ahora. Nuestro problema fue el problema de firma "MD2withRSA". Resolví el problema en un par de pasos:

1) Trabajé con Verisign para eliminar el algoritmo "antiguo" de nuestro certificado, por lo que el algoritmo MD2withRSA ya no se usó para firmar nuestros frascos.

2) También tenemos una pila de frascos de terceros y los firmamos nuevamente con nuestro certificado. Encontramos los ''no todos los frascos firmados con el mismo certificado'' cuando los algoritmos SHA1 y SHA-256 estaban listados en MANIFEST.MF. Esto fue solo un pequeño subconjunto de los frascos, así que para ellos, eliminamos la mitad inferior del archivo MANIFEST.MF; esa parte con el Nombre: clase y la especificación de algoritmo. Esa información se vuelve a generar en la última parte de nuestro proceso. Descomprimimos, excluimos la información de firma anterior y re-jar. El último paso es volver a firmar los frascos. Descubrimos que, en algunos casos, si la entrada antigua de Nombre: con la entrada SHA1 estaba en MANIFEST.MF, la firma no la reemplazó con la SHA-256, por lo que manejamos esos frascos manualmente (por ahora). Trabajando en la actualización de nuestras tareas Ant para manejar esto.

Lo siento, no puedo hablar sobre por qué web start no lo maneja / no lo permite, ¡simplemente descubrí cómo hacerlo funcionar!

¡Buena suerte!


En lugar de volver a firmar los archivos jar de terceros, puede crear un archivo JNLP separado para cada firmante de terceros que haga referencia a los archivos jar relevantes, y luego hacer que su JNLP principal dependa de estos usando el elemento <extension> . La restricción de que todos los archivos JAR deben estar firmados por el mismo firmante solo se aplica dentro de un JNLP, cada extensión puede tener un firmante diferente.

Si falla, puede eliminar las firmas de terceros antes de agregar las suyas (volviendo a empaquetarlas sin META-INF/*.{SF,DSA,RSA} )