What prevents Java from verifying signed jars with multiple signature algorithms

后端 未结 3 1626
挽巷
挽巷 2021-02-12 18:05

Quick background: We release a webstart application, which includes our own application jars and numerous third-party jars. Webstart requires that all distrib

相关标签:
3条回答
  • 2021-02-12 18:35

    I know this is a bit late - but we are going thru this now. Our problem was the "MD2withRSA" signing issue. I resolved the problem in a couple steps:

    1) Worked with Verisign to remove the 'old' algorithm from our certificate - so the MD2withRSA algorithm was no longer used to sign our jars.

    2) We also have a pile of 3rd party jars and we just re-sign them with out our certificate. We encountered the 'not all jars signed with the same certificate' when both the SHA1 and SHA-256 algorithms were listed in the MANIFEST.MF. This was just a small subset of the jars - so for those, we removed the bottom half of the MANIFEST.MF file; that part with the Name: class and the algorithm spec. That data is re-generated in the last part of our process. We unzip, exclude the old signing info and re-jar. Last step is to re-sign the jars. We found that in some cases, if the old Name: entry with the SHA1 entry was in the MANIFEST.MF, that the signing did not replace it with the SHA-256 - so we manually handle those jars (for now). Working on updating our Ant tasks to handle this.

    Sorry - can't speak to why web start doesn't handle/allow it - just figured out how to make it work!

    Good Luck!

    0 讨论(0)
  • 2021-02-12 18:41

    Seems like a bug in the JRE. Personally I'm assuming the old default signing algorithm (DSA with SHA1 digest) is less secure than the new one (RSA with SHA256 digest), so it's best not to use the "-digestalg SHA1" option.

    I solved this problem by using a custom Ant task in my build script to 'unsign' my jars before signing them. That way there is only one signature for each jar.

    Here's my Ant task:

    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);
        }
    
    }
    
    0 讨论(0)
  • 2021-02-12 18:43

    Rather than re-signing the third party jars yourself, you can create a separate JNLP file for each third-party signer that refers to the relevant jar files, then have your main JNLP depend on these using the <extension> element. The restriction that all JAR files must be signed by the same signer only applies within one JNLP, each extension can have a different signer.

    Failing that, you could strip out the third party signatures before adding your own (by repacking them without META-INF/*.{SF,DSA,RSA})

    0 讨论(0)
提交回复
热议问题