验证Jar签名

时间:2011-04-07 21:05:20

标签: java jar-signing

我正在尝试以编程方式验证jar文件是否未被明显篡改。我有2个用例我想阻止。 1)现有类的修改 2)在jar中添加新类

我使用jarsigner签署了jar。当我用jarsigner验证上述任何一种情况时,它就像我期望的那样工作。

当我尝试使用中的示例以编程方式执行此操作时 How to verify a jar signed with jarsigner programmatically 要么 How to verify signature on self signed jar? 但是,我没有得到任何SecurityExceptions ...或任何例外。

不确定我做错了什么,因为这些片段似乎对其他人有用。有任何想法吗?这是JDK 1.6 BTW。

编辑: 如下所述,代码示例...提供您自己的修改jar :)

    JarFile myJar;

    try
    {
        //Insert the full path to the jar here      
        String libPath =  ""
        stature = new JarFile(libPath,true);

        //Don't really need this right now but was using it to inspect the SHA1 hashes

        InputStream is = myJar.getInputStream(myJar.getEntry("META-INF/MANIFEST.MF"));
        Manifest man = myJar.getManifest();            
        is.close();

        verifyJar(myJar);

    }
    catch (IOException ioe)
    {
        throw new Exception("Cannot load jar file", ioe);
    }


private void verifyJar(JarFile jar) throws Exception
{
    Enumeration<java.util.jar.JarEntry> entries = jar.entries();
    while (entries.hasMoreElements())
    {
        java.util.jar.JarEntry entry = entries.nextElement();

        try
        {
            jar.getInputStream(entry);

            //Also tried actually creating a variable from the stream in case it was discarding it before verification
            //InputStream is = jar.getInputStream(entry);
            //is.close();
        }
            catch (SecurityException se)
            {
                /* Incorrect signature */                    
                throw new Exception("Signature verification failed", se);
            }
            catch (IOException ioe)
            {
                throw new Exception("Cannot load jar file entry", ioe);
            }
    }
}

JarFile myJar; try { //Insert the full path to the jar here String libPath = "" stature = new JarFile(libPath,true); //Don't really need this right now but was using it to inspect the SHA1 hashes InputStream is = myJar.getInputStream(myJar.getEntry("META-INF/MANIFEST.MF")); Manifest man = myJar.getManifest(); is.close(); verifyJar(myJar); } catch (IOException ioe) { throw new Exception("Cannot load jar file", ioe); } private void verifyJar(JarFile jar) throws Exception { Enumeration<java.util.jar.JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { java.util.jar.JarEntry entry = entries.nextElement(); try { jar.getInputStream(entry); //Also tried actually creating a variable from the stream in case it was discarding it before verification //InputStream is = jar.getInputStream(entry); //is.close(); } catch (SecurityException se) { /* Incorrect signature */ throw new Exception("Signature verification failed", se); } catch (IOException ioe) { throw new Exception("Cannot load jar file entry", ioe); } } }

2 个答案:

答案 0 :(得分:9)

使用下面的示例,我获得了正确签名的JAR(true)和更改的JAR(false)的预期结果。触发测试效果的一种简单方法是更改​​META-INF/MANIFEST.MF中列出的一个摘要。

请注意,此方法会忽略清单中列出的条目。使用jarsigner -verify报告,“此jar包含未经过完整性检查的未签名条目。”完全读取流后,entry.getCodeSigners()可用于确定条目是否有任何签名者。

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/** @see http://stackoverflow.com/questions/5587656 */
public class Verify {

    public static void main(String[] args) throws IOException {
        System.out.println(verify(new JarFile(args[0])));
    }

    private static boolean verify(JarFile jar) throws IOException {
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            try {
                byte[] buffer = new byte[8192];
                InputStream is = jar.getInputStream(entry);
                while ((is.read(buffer, 0, buffer.length)) != -1) {
                    // We just read. This will throw a SecurityException
                    // if a signature/digest check fails.
                }
            } catch (SecurityException se) {
                return false;
            }
        }
        return true;
    }
}

注意:对于JDK 8,仅仅获取输入流还不够。与在jarsigner中一样,也必须读取流。在上面的代码中,在获取输入流后添加了从jar signer source改编的循环。

答案 1 :(得分:1)

我弄清楚为什么会发生这种情况......这是一个愚蠢的错误。

我有被篡改的签名jar,但我也编译了所有相同的类,因为这是我的开发环境。因此,类加载器在jar类中选择了已编译的类。编译的类没有清单,因此没有生成安全错误。

删除编译后的类后,我得到了预期的安全例外。