首页 > 解决方案 > 使用 Java 的 XLSX 和 XAdES-T 数字签名

问题描述


我正在尝试在 Office 2016 中签署 XLSX 文件并添加时间戳服务器,我使用了 apache poi 的代码,但它似乎不起作用,每个签名结果都返回 XAdES-EPES。我期望的结果是 XAdES-T。这是带有时间戳服务器签名的 apache poi 的源代码:

https://github.com/apache/poi/blob/trunk/poi-ooxml/src/test/java/org/apache/poi/poifs/crypt/dsig/TestSignatureInfo.java

void testSignEnvelopingDocument() throws Exception {
    String testFile = "hello-world-unsigned.xlsx";
    File sigCopy = testdata.getFile(testFile);
    UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream(50000);

    final String execTimestr;


    try (OPCPackage pkg = OPCPackage.open(copy(sigCopy), PackageAccess.READ_WRITE)) {

        initKeyPair();
        final X509CRL crl = generateCrl(x509, keyPair.getPrivate());

        // setup
        SignatureConfig signatureConfig = new SignatureConfig();
        signatureConfig.setKey(keyPair.getPrivate());

        /*
         * We need at least 2 certificates for the XAdES-C complete certificate
         * refs construction.
         */
        List<X509Certificate> certificateChain = new ArrayList<>();
        certificateChain.add(x509);
        certificateChain.add(x509);
        signatureConfig.setSigningCertificateChain(certificateChain);

        signatureConfig.addSignatureFacet(new OOXMLSignatureFacet());
        signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet());
        signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet());
        signatureConfig.addSignatureFacet(new XAdESSignatureFacet());
        signatureConfig.addSignatureFacet(new XAdESXLSignatureFacet());

        // check for internet, no error means it works
        boolean mockTsp = (getAccessError("http://timestamp.comodoca.com/rfc3161", true, 10000) != null);

        // http://timestamping.edelweb.fr/service/tsp
        // http://tsa.belgium.be/connect
        // http://timestamp.comodoca.com/authenticode
        // http://timestamp.comodoca.com/rfc3161
        // http://services.globaltrustfinder.com/adss/tsa
        signatureConfig.setTspUrl("http://timestamp.comodoca.com/rfc3161");
        signatureConfig.setTspRequestPolicy(null); // comodoca request fails, if default policy is set ...
        signatureConfig.setTspOldProtocol(false);

        signatureConfig.setXadesDigestAlgo(HashAlgorithm.sha512);
        signatureConfig.setXadesRole("Xades Reviewer");
        signatureConfig.setSignatureDescription("test xades signature");

        execTimestr = signatureConfig.formatExecutionTime();

        //set proxy info if any
        String proxy = System.getProperty("http_proxy");
        if (proxy != null && proxy.trim().length() > 0) {
            signatureConfig.setProxyUrl(proxy);
        }

        if (mockTsp) {
            TimeStampService tspService = (signatureInfo, data, revocationData) -> {
                revocationData.addCRL(crl);
                return "time-stamp-token".getBytes(LocaleUtil.CHARSET_1252);
            };
            signatureConfig.setTspService(tspService);
        } else {
            TimeStampServiceValidator tspValidator = (validateChain, revocationData) -> {
                for (X509Certificate certificate : validateChain) {
                    LOG.atDebug().log("certificate: {}", certificate.getSubjectX500Principal());
                    LOG.atDebug().log("validity: {} - {}", certificate.getNotBefore(), certificate.getNotAfter());
                }
            };
            signatureConfig.setTspValidator(tspValidator);
            signatureConfig.setTspOldProtocol(signatureConfig.getTspUrl().contains("edelweb"));
        }

        final RevocationData revocationData = new RevocationData();
        revocationData.addCRL(crl);
        OCSPResp ocspResp = createOcspResp(x509, x509, x509, keyPair.getPrivate(), cal.getTimeInMillis());
        revocationData.addOCSP(ocspResp.getEncoded());

        RevocationDataService revocationDataService = revocationChain -> revocationData;
        signatureConfig.setRevocationDataService(revocationDataService);

        // operate
        SignatureInfo si = new SignatureInfo();
        si.setOpcPackage(pkg);
        si.setSignatureConfig(signatureConfig);
        try {
            si.confirmSignature();
        } catch (RuntimeException e) {
            // only allow a ConnectException because of timeout, we see this in Jenkins from time to time...
            if (e.getCause() == null) {
                throw e;
            }
            if ((e.getCause() instanceof ConnectException) || (e.getCause() instanceof SocketTimeoutException)) {
                assumeFalse(e.getCause().getMessage().contains("timed out"),
                    "Only allowing ConnectException with 'timed out' as message here, but had: " + e);
            } else if (e.getCause() instanceof IOException) {
                assumeFalse(e.getCause().getMessage().contains("Error contacting TSP server"),
                    "Only allowing IOException with 'Error contacting TSP server' as message here, but had: " + e);
            } else if (e.getCause() instanceof RuntimeException) {
                assumeFalse(e.getCause().getMessage().contains("This site is cur"),
                    "Only allowing RuntimeException with 'This site is cur' as message here, but had: " + e);
            }
            throw e;
        }
}

标签: javaexcelapache-poi

解决方案


  • 问题在猕猴桃热心专业的帮助下得到了解决
  • 如果有人和我有同样的问题,你可以按照 kwiwing 在评论中的说明使用他描述的 2 个链接:

作为参考,我添加了很快将包含修复的bugzilla 条目。对于 POI 5.0.0 的用户,您可以复制 XAdESXLSignatureFacet 源并在您的用户包中提供它。对应的测试用例是TestSignatureInfo中的“createXAdES_T_65623


推荐阅读