1

好的,我正在尝试执行针对 iText (7) 和 BouncyCastle (154) jar 文件编译的测试 Java 程序。一切正常运行,直到我在调用 signDetached 函数时尝试添加 OCSP 响应。

我的代码基本上是来自 iText 网站的这段代码:

http://developers.itextpdf.com/examples/security/digital-signatures-white-paper/digital-signatures-chapter-3#855-c3_07_signwithocsp.java

在必要时替换我的证书和密码详细信息。一切都可以编译,但是当我运行它时,Java代码会出现以下错误:

线程“主”java.lang.NoClassDefFoundError 中的异常:com.itextpdf.signatures.OcspClientBouncyCastle.getEncoded(OcspClientBouncyCastle.getEncoded(OcspClientBouncyCastle.java:148) 处的 org.bouncycastle.ocsp.RevokedStatus com.itextpdf.signatures.PdfSigner.signDetached(PdfSigner.java) :510) 在 DECSignHello.DoSign(DECSignHello.java:314) 在 DECSignHello.main(DECSignHello.java:125) 引起:java.lang.ClassNotFoundException: org.bouncycastle.ocsp.RevokedStatus 在 java.net.URLClassLoader.findClass( URLClassLoader.java:600) 在 java.lang.ClassLoader.loadClassHelper(ClassLoader.java:777) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:750) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java :326) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:731) ... 4 更多

当我深入挖掘时,我发现 iText7 正在使用一个名为的 java 类OcspClientBouncyCastle,它引用了一个来自更老的 BouncyCastle 实现的类文件(151 之前的东西 - 尚未确定包含此类的确切版本)。它引用的类是org.bouncycastle.ocsp.RevokedStatus. 导致问题的代码是这样的:

status instanceof org.bouncycastle.ocsp.RevokedStatus

在第 148 行OcspClientBouncyCastle.java。它不存在于 151 及以上版本的任何 BouncyCastle jar 文件中......

同一个 iText 类OcspClientBouncyCastle.java文件似乎也使用在路径org.bouncycastle.cert.ocsp.*中找到的较新的 BouncyCastle 类来处理与 BouncyCastle 相关的所有其他内容,因此看起来好像它使用了两种不同的 BouncyCastle 实现。至少在我看来是这样的。

这导致我的 OCSP 测试失败,因为当我从我的服务提供商处获得无效的 OCSP 响应时(这是预期的,因为我正在使用已撤销的证书进行测试)OcspClientBouncyCastle.java源代码引用的类在类路径中找不到 - 所以这一切都因无法捕获的错误而崩溃。

现在,我可以通过使用 154 BouncyCastle 实现中的有效类进行手动 OCSP 验证来解决这个问题,如下所示:

BasicOCSPResp l_resp = l_ocsp_client.getBasicOCSPResp(l_other_cert, l_root_cert, l_ocsp_url);
SingleResp[] l_response = l_resp.getResponses();

等等...

但是,只要我使用 iText7函数( OCSP 客户端参数的PdfSigner.signDetached传递和实例),就会调用代码并使用“旧”类。OcspClientBouncyCastleOcspClientBouncyCastle.java

我想我可以通过在我的类路径中包含较旧的(尚未确定的)BouncyCastle jar 文件来解决该错误,但这似乎是一个混乱的解决方案。

我还可以编辑OcspClientBouncyCastle.java文件并更正错误函数以使用 BouncyCastle 函数的更新实现,但这似乎也有点过头了。

我应该提到我在命令行上的 AIX 环境中工作。所以没有Java开发工具/环境——只是vi我手动构建我的类路径(在编译和运行时)并使用ksh shell脚本执行我的代码。

所以,毕竟,我想我的问题是:谁能想到 iText 以OcspClientBouncyCastle这种方式实现该类的合理原因?

我是这个论坛的长期追随者/用户,但这是我第一次发布任何内容。我意识到我的“问题”范围相当广泛,因此对此表示歉意。

附上示例代码:

/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 * 
 * For more info, go to: http://itextpdf.com/learn
 */
package signatures.chapter3;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.Properties;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.OcspClient;
import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;

public class C3_07_SignWithOCSP extends C3_01_SignWithCAcert {
    public static final String SRC = "src/main/resources/hello.pdf";
    public static final String DEST = "results/chapter3/hello_cacert_ocsp.pdf";

    public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("c:/home/blowagie/key.properties"));
        String path = properties.getProperty("PRIVATE");
        char[] pass = properties.getProperty("PASSWORD").toCharArray();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance("pkcs12", provider.getName());
        ks.load(new FileInputStream(path), pass);
        String alias = (String)ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, pass);
        Certificate[] chain = ks.getCertificateChain(alias);
        OcspClient ocspClient = new OcspClientBouncyCastle();
        C3_07_SignWithOCSP app = new C3_07_SignWithOCSP();
        app.sign(SRC, DEST, chain, pk, DigestAlgorithms.SHA256, provider.getName(), CryptoStandard.CMS, "Test", "Ghent", 
                null, ocspClient, null, 0);
    }

} 
C3_08_GetTsaUrl.java 
/*
 * This class is part of the white paper entitled
 * "Digital Signatures for PDF documents"
 * written by Bruno Lowagie
 * 
 * For more info, go to: http://itextpdf.com/learn
 */
package signatures.chapter3;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Properties;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.itextpdf.text.pdf.security.CertificateUtil;

public class C3_08_GetTsaUrl {
    public static void main(String[] args) throws IOException, GeneralSecurityException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("c:/home/blowagie/key.properties"));
        String path = properties.getProperty("PRIVATE");
        char[] pass = properties.getProperty("PASSWORD").toCharArray();

        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance("pkcs12", provider.getName());
        ks.load(new FileInputStream(path), pass);
        String alias = (String)ks.aliases().nextElement();
        Certificate[] chain = ks.getCertificateChain(alias);        
        for (int i = 0; i < chain.length; i++) {
            X509Certificate cert = (X509Certificate)chain[i];
            System.out.println(String.format("[%s] %s", i, cert.getSubjectDN()));
            System.out.println(CertificateUtil.getTSAURL(cert));
        }
    }
}
4

0 回答 0