2012-09-27 15 views
18

Szybkie tło: Wydajemy aplikację internetową, która obejmuje nasze własne słoiki aplikacji i liczne słoiki innych firm. Webstart wymaga, aby wszystkie rozproszone słoiki, do których odnosi się plik jnlp, były podpisane przez pojedynczy certyfikat. Dlatego podpisujemy wszystkie słoiki (nasze słoiki i słoiki firm trzecich) za pomocą samopodpisanego certyfikatu. Niektóre słoiki innych firm są już podpisane przez stronę, która je wyprodukowała, ale po prostu podpisujemy je ponownie i działa to dobrze. Do teraz.Co uniemożliwia Java weryfikowanie podpisanych słoików z wieloma algorytmami podpisów.

Problem: Niedawno przeniósł się z Java 6 Java 7 i nagle webstart odmawia załadować kilka słoików, twierdząc: "Nieprawidłowy plik SHA1 podpis Digest". Dzieje się tak tylko w przypadku niektórych słoików, a nie w innych, a wspólny wątek pojawia się wśród tych słoików, które zawierują się, wydaje się, że mają wiele sygnatur.

Po wyszukiwaniu w witrynie S.O. oraz Internet, wydaje się, że domyślny algorytm podpisu dla jarsignera Javy zmienił się między Java 6 i Java 7, z SHA1 na SHA256, a różne osoby zalecają użycie "jarsigner -digestalg SHA1", aby obejść problemy z weryfikacją. Wypróbowałem to i na pewno nasze słoje z wieloma znakami teraz sprawdzają. Wygląda to na obejście naszego problemu.

Z tego, co mogę zebrać, wynika, że ​​podpis strony trzeciej jest sygnaturą SHA1, a my podpisywaliśmy domyślnie - SHA256 - co skutkowało miksowaniem podpisów. Kiedy wymuszam SHA1 przy użyciu przełącznika "-digestalg", mamy dwa sygnatury tego samego typu, a weryfikacja działa. Więc wydaje się, że problem jest spowodowany posiadaniem wielu sygnatur z różnymi algorytmami? Czy jest jakiś inny czynnik, którego mi brakuje?

Pytania:

  1. Dlaczego nie sprawdzić z SHA1 + SHA256, ale sprawdza się SHA1 + SHA1? Czy jest jakiś techniczny powód? Przyczyna polityki bezpieczeństwa? Dlaczego nie można sprawdzić, czy oba podpisy są poprawne?
  2. Czy jest jakaś wada przy użyciu (kontynuowaniu używania) SHA1 zamiast domyślnego SHA256?
+0

I zauważył, że nawet chociaż SHA1 + SHA256 nie przy użyciu różnych kluczy ... jeśli podpisał JAR przy użyciu SHA1 + SHA256 z tym samym kluczem, nigdy weryfikacja zakończy się niepowodzeniem. –

Odpowiedz

7

Zamiast ponownego podpisania słoików strona trzecia siebie, można utworzyć osobny plik JNLP dla każdej osoby podpisującej stronę trzecią, która odnosi się do odpowiednich plików jar, a potem mają swoją główną JNLP zależy od nich za pomocą elementu <extension> . Ograniczenie, że wszystkie pliki JAR muszą być podpisane przez tego samego podpisującego, dotyczy tylko jednego JNLP, każde rozszerzenie może mieć innego sygnatariusza.

W przeciwnym razie, można rozebrać się podpisy osób trzecich przed dodaniem własnych (poprzez ich przepakowywania bez META-INF/*.{SF,DSA,RSA})

+0

Dzięki za sugestie. Po prostu zbyt uciążliwe jest tworzenie oddzielnych jnlps dla każdej biblioteki stron trzecich (mamy ponad 150 słoików). Rozważyłem usunięcie innych podpisów w naszym skrypcie budowy, ale: (1) nasze obecne obejście (opisane w moim pytaniu) było * znacznie * mniejszym wysiłkiem; (2) nasze obecne obejście powoduje szybszą kompilację (bez konieczności odbudowywania tych słoików), co jest ważne w przypadku dużej aplikacji; (3) nie jestem pewien, czy usunięcie tych podpisów może faktycznie spowodować problem dla którejkolwiek z tych bibliotek. – JimN

+0

Rozumiem twój punkt widzenia, ale pamiętaj, że to tylko licencje stron trzecich, które są podpisane przez kod, które musisz wprowadzić do rozszerzeń (w mojej aplikacji JAR 50+ był tylko javaamail i aktywacja, do której to się odnosiło). –

1

Wiem, że to trochę późno - ale mamy zamiar thru to teraz. Naszym problemem był problem z podpisywaniem "MD2withRSA". Rozwiązałem problem w kilku krokach:

1) Współpracowałem z firmą Verisign w celu usunięcia "starego" algorytmu z naszego certyfikatu - więc algorytm MD2withRSA nie był już używany do podpisywania naszych słoików.

2) Mamy również stos słoików innych firm, a my po prostu ponownie je podpisujemy bez naszego certyfikatu. Napotkaliśmy na "nie wszystkie słoje podpisane tym samym certyfikatem", gdy oba algorytmy SHA1 i SHA-256 zostały wymienione w pliku MANIFEST.MF. To był tylko niewielki podzbiór słoików - więc dla nich usunęliśmy dolną połowę pliku MANIFEST.MF; część z klasą Nazwa i specyfikacja algorytmu. Dane te są ponownie generowane w ostatniej części naszego procesu. Rozpakowujemy, wykluczamy stare informacje o podpisach i ponownie je przechowujemy.Ostatnim krokiem jest ponowne podpisanie słoików. Okazało się, że w niektórych przypadkach, jeśli stary wpis Name: z wpisem SHA1 znajdował się w pliku MANIFEST.MF, oznacza to, że podpis nie zastąpił go SHA-256 - więc ręcznie obsługujemy te słoiki (na razie). Pracuje nad aktualizowaniem naszych zadań Ant, aby sobie z tym poradzić.

Niestety - nie można mówić o przyczynach, dla których uruchomienie strony internetowej nie obsługuje/nie pozwala - po prostu zorientowali się, jak to zrobić!

Powodzenia!

1

Wygląda jak błąd w JRE. Osobiście zakładam, że stary domyślny algorytm podpisywania (DSA z trawieniem SHA1) jest mniej bezpieczny niż nowy (RSA z skrótem SHA256), więc najlepiej nie używać opcji "-digestalg SHA1".

Rozwiązałem ten problem, używając niestandardowego zadania Ant w moim skrypcie kompilacji, aby "wyrejestrować" moje słoiki przed ich podpisaniem. W ten sposób dla każdego słoika jest tylko jeden podpis.

Oto mój Ant zadanie:

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); 
    } 

} 
Powiązane problemy