使用 Java 的 XLSX 和 XAdES-T 数字签名
Digital Signature with XLSX and XAdES-T using Java
我正在尝试在 office 2016 中签署 XLSX 文件并添加时间戳服务器,我使用了 apache poi 的代码但它似乎不起作用,每个签名结果 returns XAdES-EPES。我期望的结果是 XAdES-T。
这是带有时间戳服务器签名的 apache poi 的源代码:
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;
}
}
- 在 kiwiwings
[=21= 的热心和专业帮助下,问题 已解决 ]
- 如果有人遇到和我一样的问题,您可以按照 kwiwing 在评论中的说明以及他描述的 2 个链接进行操作:
As a reference, I add the bugzilla entry which will contain the fix soon. for users of POI 5.0.0, you can copy the XAdESXLSignatureFacet source and provide it in your user packages. The corresponding test case is "createXAdES_T_65623" in TestSignatureInfo
我正在尝试在 office 2016 中签署 XLSX 文件并添加时间戳服务器,我使用了 apache poi 的代码但它似乎不起作用,每个签名结果 returns XAdES-EPES。我期望的结果是 XAdES-T。 这是带有时间戳服务器签名的 apache poi 的源代码:
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;
}
}
- 在 kiwiwings
[=21= 的热心和专业帮助下,问题 已解决 ] - 如果有人遇到和我一样的问题,您可以按照 kwiwing 在评论中的说明以及他描述的 2 个链接进行操作:
As a reference, I add the bugzilla entry which will contain the fix soon. for users of POI 5.0.0, you can copy the XAdESXLSignatureFacet source and provide it in your user packages. The corresponding test case is "createXAdES_T_65623" in TestSignatureInfo