Подтвердить что ты не робот

Что мешает Java проверять подписанные банки с несколькими сигнатурными алгоритмами

Быстрый исход: Мы публикуем приложение webstart, в которое входят наши собственные банки приложений и многочисленные сторонние банки. Webstart требует, чтобы все распределенные банки, на которые ссылается файл jnlp, подписывались одним сертификатом. Поэтому мы подписываем все банки (наши банки и сторонние банки) с использованием самозаверяющего сертификата. Некоторые сторонние банки уже подписаны стороной, которая их создала, но мы просто подписываем их снова, и это работает нормально. До сих пор.

Проблема: Недавно мы перешли с Java 6 на Java 7, и вдруг webstart отказывается загружать некоторые баночки, жалуясь: "Недопустимый дайджест файла подписи SHA1". Это происходит только для некоторых банок, а не для других, и среди тех банок, которые не работают, появляется общий поток.

После поиска по S.O. и Интернет, похоже, что алгоритм подписи по умолчанию для Java jarsigner изменился между Java 6 и Java 7, от SHA1 до SHA256, и различные люди рекомендуют использовать "jarsigner -digestalg SHA1" для решения проблем проверки. Я пробовал это, и, безусловно, наши многократные подписанные банки теперь проверяют. Таким образом, это, как представляется, является обходным путем для нашей проблемы.

Из того, что я могу собрать, похоже, что сигнатура сторонней стороны является сигнатурой SHA1, и мы подписывались с по умолчанию - SHA256, что приводило к смешению подписей. Когда я нажимаю SHA1 с помощью переключателя '-digestalg', у нас есть две подписи того же типа, и проверка теперь работает. Похоже, проблема связана с наличием нескольких подписей с разными алгоритмами? Или есть какой-то другой фактор, который мне не хватает.

Вопросы:

  • Почему это не удается проверить с помощью SHA1 + SHA256, но проверяет с помощью SHA1 + SHA1? Есть ли техническая причина? Причина политики безопасности? Почему он не может проверить правильность обеих подписей?
  • Есть ли у нас недостаток использования (продолжение использования) SHA1 вместо текущего SHA256 по умолчанию?
4b9b3361

Ответ 1

Вместо того, чтобы повторно подписывать сторонние банки самостоятельно, вы можете создать отдельный JNLP файл для каждого стороннего подписчика, который ссылается на соответствующие файлы jar, а затем ваш основной JNLP зависит от них с помощью элемента <extension>. Ограничение того, что все файлы JAR должны быть подписаны одним и тем же подписывающим агентом, применяется только в одном JNLP, каждое расширение может иметь другой подписант.

В противном случае вы можете лишить сторонние подписи перед добавлением собственных (путем их переупаковки без META-INF/*.{SF,DSA,RSA})

Ответ 2

Я знаю, что это немного поздно, но мы сейчас это сделаем. Наша проблема заключалась в выпуске подписи "MD2withRSA". Я решил проблему в пару шагов:

1) Работала с Verisign для удаления "старого" алгоритма из нашего сертификата - поэтому алгоритм MD2withRSA больше не использовался для подписи наших банок.

2) У нас также есть куча сторонних банках, и мы просто переписываем их без нашего сертификата. Мы встретили "не все банки, подписанные с тем же сертификатом", когда оба алгоритма SHA1 и SHA-256 были перечислены в MANIFEST.MF. Это было всего лишь небольшое подмножество банок - поэтому для них мы удалили нижнюю половину файла MANIFEST.MF; эта часть с классом Name: и спецификацией алгоритма. Эти данные повторно генерируются в последней части нашего процесса. Мы разархивируем, исключаем старую подпись и повторную банку. Последний шаг заключается в повторной подписке на банки. Мы обнаружили, что в некоторых случаях, если старая запись Name: с записью SHA1 была в MANIFEST.MF, что подпись не заменила ее SHA-256, поэтому мы вручную обрабатываем эти банки (на данный момент). Работая над обновлением наших задач Ant, чтобы справиться с этим.

Извините - не могу сказать, почему веб-старт не обрабатывает/не разрешает его - просто понял, как заставить его работать!

Удачи!

Ответ 3

Похоже на ошибку в JRE. Лично я предполагаю, что старый алгоритм подписи по умолчанию (DSA с SHA1 digest) менее безопасен, чем новый (RSA с SHA256 digest), поэтому лучше не использовать параметр "-digestalg SHA1".

Я решил эту проблему, используя специальную задачу Ant в моей сборке script для "unsign" моих банок перед их подписанием. Таким образом, для каждой банки есть только одна подпись.

Здесь моя задача 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);
    }

}