2012-09-27 34 views
18

त्वरित पृष्ठभूमि: हम एक वेबस्टार्ट एप्लिकेशन जारी करते हैं, जिसमें हमारे अपने एप्लिकेशन जार और कई तृतीय-पक्ष जार शामिल हैं। वेबस्टार्ट की आवश्यकता है कि jnlp फ़ाइल द्वारा निर्दिष्ट सभी वितरित जार को एक प्रमाणपत्र द्वारा हस्ताक्षरित किया जाए। इसलिए हम एक स्व-हस्ताक्षरित प्रमाणपत्र का उपयोग कर सभी जार (हमारे जार और तीसरे पक्ष के जार) पर हस्ताक्षर करते हैं। कुछ तीसरे पक्ष के जार पहले से ही पार्टी द्वारा हस्ताक्षरित हैं जो उन्हें उत्पादित करते हैं, लेकिन हम उन्हें फिर से हस्ताक्षर करते हैं, और यह ठीक काम करता है। अब तक।जावा हस्ताक्षर किए गए जार को एकाधिक हस्ताक्षर एल्गोरिदम

समस्या: हमने हाल ही में जावा 6 से जावा 7 में ले जाया गया है, और अचानक webstart कुछ जार लोड करने के लिए इंकार कर रहा है, शिकायत: "अवैध SHA1 हस्ताक्षर फ़ाइल डाइजेस्ट"। यह केवल कुछ जारों के लिए होता है, न कि दूसरों के लिए, और आम धागा उन जारों में दिखाई देता है जो असफल होने पर कई हस्ताक्षर होते हैं।

एसओ पर चारों ओर खोज करने के बाद। और इंटरनेट, ऐसा लगता है कि जावा के jarsigner के लिए डिफ़ॉल्ट हस्ताक्षर एल्गोरिदम जावा 6 और जावा 7 के बीच बदल गया है, SHA1 से SHA256 तक, और विभिन्न लोग सत्यापन समस्याओं के आसपास काम करने के लिए "jarsigner -digestalg SHA1" का उपयोग करने की सिफारिश कर रहे हैं। मैंने कोशिश की, और सुनिश्चित करें कि हमारे गुणा-हस्ताक्षरित जार अब सत्यापित हैं। तो यह हमारे मुद्दे के लिए एक कामकाज प्रतीत होता है।

जो मैं एकत्र कर सकता हूं, ऐसा लगता है कि तीसरे पक्ष के हस्ताक्षर एक SHA1 हस्ताक्षर है, और हम डिफ़ॉल्ट - SHA256 पर हस्ताक्षर कर रहे थे - जिसके परिणामस्वरूप हस्ताक्षर का मिश्रण हुआ। जब मैं '-डिगेस्टल' स्विच का उपयोग करके SHA1 को मजबूर करता हूं, तो हमारे पास एक ही प्रकार के दो हस्ताक्षर होते हैं, और सत्यापन अब काम करता है। तो ऐसा लगता है कि समस्या विभिन्न एल्गोरिदम के साथ एकाधिक हस्ताक्षर होने के कारण होती है? या क्या मैं कुछ अन्य कारक लापता हूं।

सवाल:

  1. यह SHA1 + SHA256 साथ सत्यापित करने के लिए क्यों असफल, लेकिन SHA1 + SHA1 साथ की पुष्टि करता है? क्या कोई तकनीकी कारण है? एक सुरक्षा नीति कारण? यह सत्यापित क्यों नहीं कर सकता कि दोनों हस्ताक्षर सही हैं?
  2. क्या अब डिफ़ॉल्ट-डिफ़ॉल्ट SHA256 के बजाय SHA1 का उपयोग कर (जारी रखने के लिए) कोई दोष है?
+0

मैंने देखा कि यहां तक ​​कि-हालांकि SHA1 + SHA256 में विफल रहता है जब विभिन्न कुंजियों का उपयोग ... यदि आप जार एक ही कुंजी के साथ SHA1 + SHA256 का उपयोग करके हस्ताक्षरित, सत्यापन कभी असफल नहीं होता:

यहाँ मेरी चींटी कार्य है। –

उत्तर

7

के बजाय अपने आप को फिर से हस्ताक्षर करने के लिए तीसरे पक्ष के जार, आप प्रत्येक तीसरे पक्ष के हस्ताक्षरकर्ता है कि प्रासंगिक जार फ़ाइलों को संदर्भित के लिए एक अलग JNLP फ़ाइल बना सकते हैं, तो अपने मुख्य JNLP है इन <extension> तत्व का उपयोग पर निर्भर । प्रतिबंध है कि सभी जेएआर फाइलों को एक ही हस्ताक्षरकर्ता द्वारा हस्ताक्षरित किया जाना चाहिए केवल एक जेएनएलपी के भीतर लागू होता है, प्रत्येक एक्सटेंशन में एक अलग हस्ताक्षरकर्ता हो सकता है।

उसमें असफल होने पर आप

+0

सुझावों के लिए धन्यवाद। प्रत्येक थर्ड पार्टी लाइब्रेरी के लिए अलग-अलग jnlps बनाने के लिए यह बहुत बोझिल है (हमारे पास 150+ जार हैं)। मैंने अपनी बिल्ड स्क्रिप्ट में अन्य हस्ताक्षरों को अलग करने पर विचार किया, लेकिन: (1) हमारे वर्तमान कार्यवाही (मेरे प्रश्न में वर्णित) * बहुत कम प्रयास था; (2) हमारे वर्तमान कार्यवाही के परिणामस्वरूप तेजी से निर्माण (उन जारों को पुनर्निर्माण नहीं करना), जो एक बड़े आवेदन के लिए महत्वपूर्ण है; (3) सुनिश्चित नहीं है कि उन हस्ताक्षरों को हटाने से वास्तव में उन किसी भी libs के लिए समस्या हो सकती है। – JimN

+0

मैं आपके बिंदु को देखता हूं लेकिन ध्यान में रखता हूं कि यह केवल तीसरी पार्टी libs है, यह कोड-हस्ताक्षर_ है जिसे आपको एक्सटेंशन में बनाना होगा (मेरे 50+ JAR ऐप में यह केवल जावमेल और सक्रियण था जिसे यह लागू किया गया था)। –

1

(META-INF/*.{SF,DSA,RSA} बिना उन्हें repacking द्वारा) अपनी जोड़ने मैं जानता हूँ कि यह देर से एक सा है से पहले तीसरे पक्ष के हस्ताक्षर को निकाल देते हैं सकता है - लेकिन हम इस के माध्यम से अब जा रहे हैं। हमारी समस्या "MD2withRSA" हस्ताक्षर समस्या थी। मैंने कुछ चरणों में समस्या का समाधान किया:

1) हमारे प्रमाण पत्र से 'पुराने' एल्गोरिदम को हटाने के लिए Verisign के साथ काम किया - इसलिए MD2withRSA एल्गोरिदम का उपयोग अब हमारे जारों पर हस्ताक्षर करने के लिए नहीं किया गया था।

2) हमारे पास तीसरे पक्ष के जारों का ढेर भी है और हम उन्हें हमारे प्रमाण पत्र के साथ फिर से साइन-इन करते हैं। हमने 'प्रमाण पत्र के साथ हस्ताक्षरित सभी जारों' का सामना नहीं किया, जब SHIF1 और SHA-256 एल्गोरिदम दोनों MANIFEST.MF में सूचीबद्ध थे। यह जारों का सिर्फ एक छोटा सबसेट था - इसलिए उन लोगों के लिए, हमने MANIFEST.MF फ़ाइल के निचले हिस्से को हटा दिया; नाम: कक्षा और एल्गोरिदम spec के साथ वह हिस्सा। यह डेटा हमारी प्रक्रिया के अंतिम भाग में फिर से उत्पन्न होता है। हम अनजिप करते हैं, पुरानी हस्ताक्षर जानकारी और पुनः-जार को बहिष्कृत करते हैं।अंतिम कदम जार फिर से हस्ताक्षर करना है। हमने पाया कि कुछ मामलों में, यदि पुराना नाम: SHA1 प्रविष्टि के साथ प्रविष्टि MANIFEST.MF में थी, तो हस्ताक्षर ने इसे SHA-256 से प्रतिस्थापित नहीं किया - इसलिए हम मैन्युअल रूप से उन जारों को (अब के लिए) संभालते हैं। इसे संभालने के लिए हमारे चींटी कार्यों को अद्यतन करने पर काम करना।

क्षमा करें - वेब स्टार्ट क्यों संभाल नहीं सकता/इसे अनुमति नहीं देता है - बस यह समझने के लिए कि यह कैसे काम करता है!

शुभकामनाएं!

1

जेआरई में एक बग की तरह लगता है। व्यक्तिगत रूप से मैं पुराने डिफ़ॉल्ट हस्ताक्षर एल्गोरिदम (एसएचए 1 डाइजेस्ट के साथ डीएसए) मान रहा हूं कि नए (आरएएस 256 पाचन के साथ आरएसए) से कम सुरक्षित है, इसलिए "-डिगेस्टल एसएचए 1" विकल्प का उपयोग न करना सबसे अच्छा है।

मैंने अपनी बिल्ड स्क्रिप्ट में एक कस्टम चींटी कार्य का उपयोग करके इस समस्या को हल करने से पहले अपने जार 'अनजान' करने के लिए हल किया। इस तरह प्रत्येक जार के लिए केवल एक हस्ताक्षर है।

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

}