mirror of https://github.com/apache/poi.git
#65623 - Create XAdES-T signature with XAdESXLSignatureFacet
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1894049 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
91f423e33c
commit
60e9de813e
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
package org.apache.poi.poifs.crypt.dsig.facets;
|
package org.apache.poi.poifs.crypt.dsig.facets;
|
||||||
|
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
||||||
import static org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet.insertXChild;
|
import static org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet.insertXChild;
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
|
import org.apache.poi.poifs.crypt.dsig.SignatureConfig;
|
||||||
import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
|
import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
|
||||||
import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
|
import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
|
||||||
|
import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService;
|
||||||
import org.apache.xml.security.c14n.Canonicalizer;
|
import org.apache.xml.security.c14n.Canonicalizer;
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
import org.bouncycastle.asn1.ASN1InputStream;
|
import org.bouncycastle.asn1.ASN1InputStream;
|
||||||
|
@ -74,14 +76,12 @@ import org.w3c.dom.NodeList;
|
||||||
/**
|
/**
|
||||||
* XAdES-X-L v1.4.1 signature facet. This signature facet implementation will
|
* XAdES-X-L v1.4.1 signature facet. This signature facet implementation will
|
||||||
* upgrade a given XAdES-BES/EPES signature to XAdES-X-L.
|
* upgrade a given XAdES-BES/EPES signature to XAdES-X-L.
|
||||||
|
* If no revocation data service is set, only a XAdES-T signature is created.
|
||||||
*
|
*
|
||||||
* We don't inherit from XAdESSignatureFacet as we also want to be able to use
|
* We don't inherit from XAdESSignatureFacet as we also want to be able to use
|
||||||
* this facet out of the context of a signature creation. This signature facet
|
* this facet out of the context of a signature creation. This signature facet
|
||||||
* assumes that the signature is already XAdES-BES/EPES compliant.
|
* assumes that the signature is already XAdES-BES/EPES compliant.
|
||||||
*
|
*
|
||||||
* This implementation has been tested against an implementation that
|
|
||||||
* participated multiple ETSI XAdES plugtests.
|
|
||||||
*
|
|
||||||
* @see XAdESSignatureFacet
|
* @see XAdESSignatureFacet
|
||||||
*/
|
*/
|
||||||
public class XAdESXLSignatureFacet implements SignatureFacet {
|
public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
|
@ -104,35 +104,63 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
|
|
||||||
SignatureConfig signatureConfig = signatureInfo.getSignatureConfig();
|
SignatureConfig signatureConfig = signatureInfo.getSignatureConfig();
|
||||||
|
|
||||||
QualifyingPropertiesDocument qualDoc;
|
|
||||||
QualifyingPropertiesType qualProps;
|
|
||||||
|
|
||||||
// check for XAdES-BES
|
// check for XAdES-BES
|
||||||
NodeList qualNl = document.getElementsByTagNameNS(XADES_132_NS, "QualifyingProperties");
|
NodeList qualNl = document.getElementsByTagNameNS(XADES_132_NS, "QualifyingProperties");
|
||||||
if (qualNl.getLength() == 1) {
|
QualifyingPropertiesType qualProps = getQualProps(qualNl);
|
||||||
try {
|
|
||||||
qualDoc = QualifyingPropertiesDocument.Factory.parse(qualNl.item(0), DEFAULT_XML_OPTIONS);
|
|
||||||
} catch (XmlException e) {
|
|
||||||
throw new MarshalException(e);
|
|
||||||
}
|
|
||||||
qualProps = qualDoc.getQualifyingProperties();
|
|
||||||
} else {
|
|
||||||
throw new MarshalException("no XAdES-BES extension present");
|
|
||||||
}
|
|
||||||
|
|
||||||
// create basic XML container structure
|
// create basic XML container structure
|
||||||
UnsignedPropertiesType unsignedProps = qualProps.getUnsignedProperties();
|
UnsignedPropertiesType unsignedProps =
|
||||||
if (unsignedProps == null) {
|
ofNullable(qualProps.getUnsignedProperties()).orElseGet(qualProps::addNewUnsignedProperties);
|
||||||
unsignedProps = qualProps.addNewUnsignedProperties();
|
UnsignedSignaturePropertiesType unsignedSigProps =
|
||||||
}
|
ofNullable(unsignedProps.getUnsignedSignatureProperties()).orElseGet(unsignedProps::addNewUnsignedSignatureProperties);
|
||||||
UnsignedSignaturePropertiesType unsignedSigProps = unsignedProps.getUnsignedSignatureProperties();
|
|
||||||
if (unsignedSigProps == null) {
|
|
||||||
unsignedSigProps = unsignedProps.addNewUnsignedSignatureProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// create the XAdES-T time-stamp
|
// create the XAdES-T time-stamp
|
||||||
NodeList nlSigVal = document.getElementsByTagNameNS(XML_DIGSIG_NS, "SignatureValue");
|
NodeList nlSigVal = document.getElementsByTagNameNS(XML_DIGSIG_NS, "SignatureValue");
|
||||||
|
XAdESTimeStampType signatureTimeStamp = addTimestamp(nlSigVal, signatureInfo, unsignedSigProps);
|
||||||
|
|
||||||
|
// Without revocation data service we cannot construct the XAdES-C extension.
|
||||||
|
RevocationDataService revDataSvc = signatureConfig.getRevocationDataService();
|
||||||
|
if (revDataSvc != null) {
|
||||||
|
// XAdES-C: complete certificate refs
|
||||||
|
CompleteCertificateRefsType completeCertificateRefs = completeCertificateRefs(unsignedSigProps, signatureConfig);
|
||||||
|
|
||||||
|
// XAdES-C: complete revocation refs
|
||||||
|
RevocationData revocationData = revDataSvc.getRevocationData(signatureConfig.getSigningCertificateChain());
|
||||||
|
CompleteRevocationRefsType completeRevocationRefs = unsignedSigProps.addNewCompleteRevocationRefs();
|
||||||
|
addRevocationCRL(completeRevocationRefs, signatureConfig, revocationData);
|
||||||
|
addRevocationOCSP(completeRevocationRefs, signatureConfig, revocationData);
|
||||||
|
|
||||||
|
// XAdES-X Type 1 timestamp
|
||||||
|
addTimestampX(unsignedSigProps, signatureInfo, nlSigVal, signatureTimeStamp, completeCertificateRefs, completeRevocationRefs);
|
||||||
|
|
||||||
|
// XAdES-X-L
|
||||||
|
addCertificateValues(unsignedSigProps, signatureConfig);
|
||||||
|
|
||||||
|
RevocationValuesType revocationValues = unsignedSigProps.addNewRevocationValues();
|
||||||
|
createRevocationValues(revocationValues, revocationData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal XAdES-X-L
|
||||||
|
Node n = document.importNode(qualProps.getDomNode(), true);
|
||||||
|
qualNl.item(0).getParentNode().replaceChild(n, qualNl.item(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private QualifyingPropertiesType getQualProps(NodeList qualNl) throws MarshalException {
|
||||||
|
// check for XAdES-BES
|
||||||
|
if (qualNl.getLength() != 1) {
|
||||||
|
throw new MarshalException("no XAdES-BES extension present");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Node first = qualNl.item(0);
|
||||||
|
QualifyingPropertiesDocument qualDoc = QualifyingPropertiesDocument.Factory.parse(first, DEFAULT_XML_OPTIONS);
|
||||||
|
return qualDoc.getQualifyingProperties();
|
||||||
|
} catch (XmlException e) {
|
||||||
|
throw new MarshalException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private XAdESTimeStampType addTimestamp(NodeList nlSigVal, SignatureInfo signatureInfo, UnsignedSignaturePropertiesType unsignedSigProps) {
|
||||||
if (nlSigVal.getLength() != 1) {
|
if (nlSigVal.getLength() != 1) {
|
||||||
throw new IllegalArgumentException("SignatureValue is not set.");
|
throw new IllegalArgumentException("SignatureValue is not set.");
|
||||||
}
|
}
|
||||||
|
@ -151,17 +179,11 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
insertXChild(unsignedSigProps, validationData);
|
insertXChild(unsignedSigProps, validationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signatureConfig.getRevocationDataService() == null) {
|
return signatureTimeStamp;
|
||||||
/*
|
}
|
||||||
* Without revocation data service we cannot construct the XAdES-C
|
|
||||||
* extension.
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XAdES-C: complete certificate refs
|
private CompleteCertificateRefsType completeCertificateRefs(UnsignedSignaturePropertiesType unsignedSigProps, SignatureConfig signatureConfig) {
|
||||||
CompleteCertificateRefsType completeCertificateRefs =
|
CompleteCertificateRefsType completeCertificateRefs = unsignedSigProps.addNewCompleteCertificateRefs();
|
||||||
unsignedSigProps.addNewCompleteCertificateRefs();
|
|
||||||
|
|
||||||
CertIDListType certIdList = completeCertificateRefs.addNewCertRefs();
|
CertIDListType certIdList = completeCertificateRefs.addNewCertRefs();
|
||||||
/*
|
/*
|
||||||
|
@ -169,19 +191,14 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
* 4.4.3.2 of the XAdES 1.4.1 specification.
|
* 4.4.3.2 of the XAdES 1.4.1 specification.
|
||||||
*/
|
*/
|
||||||
List<X509Certificate> certChain = signatureConfig.getSigningCertificateChain();
|
List<X509Certificate> certChain = signatureConfig.getSigningCertificateChain();
|
||||||
int chainSize = certChain.size();
|
certChain.stream().skip(1).forEachOrdered(cert ->
|
||||||
if (chainSize > 1) {
|
XAdESSignatureFacet.setCertID(certIdList.addNewCert(), signatureConfig, false, cert)
|
||||||
for (X509Certificate cert : certChain.subList(1, chainSize)) {
|
);
|
||||||
CertIDType certId = certIdList.addNewCert();
|
|
||||||
XAdESSignatureFacet.setCertID(certId, signatureConfig, false, cert);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// XAdES-C: complete revocation refs
|
return completeCertificateRefs;
|
||||||
CompleteRevocationRefsType completeRevocationRefs =
|
}
|
||||||
unsignedSigProps.addNewCompleteRevocationRefs();
|
|
||||||
RevocationData revocationData = signatureConfig.getRevocationDataService()
|
private void addRevocationCRL(CompleteRevocationRefsType completeRevocationRefs, SignatureConfig signatureConfig, RevocationData revocationData) {
|
||||||
.getRevocationData(certChain);
|
|
||||||
if (revocationData.hasCRLs()) {
|
if (revocationData.hasCRLs()) {
|
||||||
CRLRefsType crlRefs = completeRevocationRefs.addNewCRLRefs();
|
CRLRefsType crlRefs = completeRevocationRefs.addNewCRLRefs();
|
||||||
completeRevocationRefs.setCRLRefs(crlRefs);
|
completeRevocationRefs.setCRLRefs(crlRefs);
|
||||||
|
@ -191,10 +208,9 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
X509CRL crl;
|
X509CRL crl;
|
||||||
try {
|
try {
|
||||||
crl = (X509CRL) this.certificateFactory
|
crl = (X509CRL) this.certificateFactory
|
||||||
.generateCRL(new UnsynchronizedByteArrayInputStream(encodedCrl));
|
.generateCRL(new UnsynchronizedByteArrayInputStream(encodedCrl));
|
||||||
} catch (CRLException e) {
|
} catch (CRLException e) {
|
||||||
throw new RuntimeException("CRL parse error: "
|
throw new RuntimeException("CRL parse error: " + e.getMessage(), e);
|
||||||
+ e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CRLIdentifierType crlIdentifier = crlRef.addNewCRLIdentifier();
|
CRLIdentifierType crlIdentifier = crlRef.addNewCRLIdentifier();
|
||||||
|
@ -209,6 +225,9 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, encodedCrl, signatureConfig.getDigestAlgo());
|
XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, encodedCrl, signatureConfig.getDigestAlgo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRevocationOCSP(CompleteRevocationRefsType completeRevocationRefs, SignatureConfig signatureConfig, RevocationData revocationData) {
|
||||||
if (revocationData.hasOCSPs()) {
|
if (revocationData.hasOCSPs()) {
|
||||||
OCSPRefsType ocspRefs = completeRevocationRefs.addNewOCSPRefs();
|
OCSPRefsType ocspRefs = completeRevocationRefs.addNewOCSPRefs();
|
||||||
for (byte[] ocsp : revocationData.getOCSPs()) {
|
for (byte[] ocsp : revocationData.getOCSPs()) {
|
||||||
|
@ -247,10 +266,11 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// marshal XAdES-C
|
private void addTimestampX(UnsignedSignaturePropertiesType unsignedSigProps, SignatureInfo signatureInfo, NodeList nlSigVal, XAdESTimeStampType signatureTimeStamp,
|
||||||
|
CompleteCertificateRefsType completeCertificateRefs, CompleteRevocationRefsType completeRevocationRefs) {
|
||||||
|
|
||||||
// XAdES-X Type 1 timestamp
|
|
||||||
List<Node> timeStampNodesXadesX1 = new ArrayList<>();
|
List<Node> timeStampNodesXadesX1 = new ArrayList<>();
|
||||||
timeStampNodesXadesX1.add(nlSigVal.item(0));
|
timeStampNodesXadesX1.add(nlSigVal.item(0));
|
||||||
timeStampNodesXadesX1.add(signatureTimeStamp.getDomNode());
|
timeStampNodesXadesX1.add(signatureTimeStamp.getDomNode());
|
||||||
|
@ -269,9 +289,11 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
// marshal XAdES-X
|
// marshal XAdES-X
|
||||||
unsignedSigProps.addNewSigAndRefsTimeStamp().set(timeStampXadesX1);
|
unsignedSigProps.addNewSigAndRefsTimeStamp().set(timeStampXadesX1);
|
||||||
|
|
||||||
// XAdES-X-L
|
}
|
||||||
|
|
||||||
|
private void addCertificateValues(UnsignedSignaturePropertiesType unsignedSigProps, SignatureConfig signatureConfig) {
|
||||||
CertificateValuesType certificateValues = unsignedSigProps.addNewCertificateValues();
|
CertificateValuesType certificateValues = unsignedSigProps.addNewCertificateValues();
|
||||||
for (X509Certificate certificate : certChain) {
|
for (X509Certificate certificate : signatureConfig.getSigningCertificateChain()) {
|
||||||
EncapsulatedPKIDataType encapsulatedPKIDataType = certificateValues.addNewEncapsulatedX509Certificate();
|
EncapsulatedPKIDataType encapsulatedPKIDataType = certificateValues.addNewEncapsulatedX509Certificate();
|
||||||
try {
|
try {
|
||||||
encapsulatedPKIDataType.setByteArrayValue(certificate.getEncoded());
|
encapsulatedPKIDataType.setByteArrayValue(certificate.getEncoded());
|
||||||
|
@ -279,16 +301,9 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
|
||||||
throw new RuntimeException("certificate encoding error: " + e.getMessage(), e);
|
throw new RuntimeException("certificate encoding error: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RevocationValuesType revocationValues = unsignedSigProps.addNewRevocationValues();
|
|
||||||
createRevocationValues(revocationValues, revocationData);
|
|
||||||
|
|
||||||
// marshal XAdES-X-L
|
|
||||||
Node n = document.importNode(qualProps.getDomNode(), true);
|
|
||||||
qualNl.item(0).getParentNode().replaceChild(n, qualNl.item(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] getC14nValue(List<Node> nodeList, String c14nAlgoId) {
|
private static byte[] getC14nValue(List<Node> nodeList, String c14nAlgoId) {
|
||||||
try (UnsynchronizedByteArrayOutputStream c14nValue = new UnsynchronizedByteArrayOutputStream()) {
|
try (UnsynchronizedByteArrayOutputStream c14nValue = new UnsynchronizedByteArrayOutputStream()) {
|
||||||
for (Node node : nodeList) {
|
for (Node node : nodeList) {
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -94,6 +94,8 @@ import org.apache.poi.poifs.crypt.HashAlgorithm;
|
||||||
import org.apache.poi.poifs.crypt.dsig.facets.EnvelopedSignatureFacet;
|
import org.apache.poi.poifs.crypt.dsig.facets.EnvelopedSignatureFacet;
|
||||||
import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
|
import org.apache.poi.poifs.crypt.dsig.facets.KeyInfoSignatureFacet;
|
||||||
import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
|
import org.apache.poi.poifs.crypt.dsig.facets.OOXMLSignatureFacet;
|
||||||
|
import org.apache.poi.poifs.crypt.dsig.facets.Office2010SignatureFacet;
|
||||||
|
import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet;
|
||||||
import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
|
import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet;
|
||||||
import org.apache.poi.poifs.crypt.dsig.facets.XAdESXLSignatureFacet;
|
import org.apache.poi.poifs.crypt.dsig.facets.XAdESXLSignatureFacet;
|
||||||
import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
|
import org.apache.poi.poifs.crypt.dsig.services.RevocationData;
|
||||||
|
@ -116,6 +118,7 @@ import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||||
import org.apache.poi.xwpf.usermodel.XWPFHyperlinkRun;
|
import org.apache.poi.xwpf.usermodel.XWPFHyperlinkRun;
|
||||||
import org.apache.poi.xwpf.usermodel.XWPFSignatureLine;
|
import org.apache.poi.xwpf.usermodel.XWPFSignatureLine;
|
||||||
import org.apache.xmlbeans.SystemProperties;
|
import org.apache.xmlbeans.SystemProperties;
|
||||||
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import org.bouncycastle.asn1.DEROctetString;
|
import org.bouncycastle.asn1.DEROctetString;
|
||||||
|
@ -156,7 +159,11 @@ import org.bouncycastle.operator.OperatorCreationException;
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
||||||
import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
|
import org.etsi.uri.x01903.v13.DigestAlgAndValueType;
|
||||||
|
import org.etsi.uri.x01903.v13.EncapsulatedPKIDataType;
|
||||||
import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
|
import org.etsi.uri.x01903.v13.QualifyingPropertiesType;
|
||||||
|
import org.etsi.uri.x01903.v13.UnsignedPropertiesType;
|
||||||
|
import org.etsi.uri.x01903.v13.UnsignedSignaturePropertiesType;
|
||||||
|
import org.etsi.uri.x01903.v13.XAdESTimeStampType;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
@ -164,6 +171,7 @@ import org.junit.jupiter.api.Tag;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
import org.w3.x2000.x09.xmldsig.ObjectType;
|
||||||
import org.w3.x2000.x09.xmldsig.ReferenceType;
|
import org.w3.x2000.x09.xmldsig.ReferenceType;
|
||||||
import org.w3.x2000.x09.xmldsig.SignatureDocument;
|
import org.w3.x2000.x09.xmldsig.SignatureDocument;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
@ -923,6 +931,89 @@ class TestSignatureInfo {
|
||||||
POIXMLDocument init(SignatureLine line, OPCPackage pkg) throws IOException, XmlException;
|
POIXMLDocument init(SignatureLine line, OPCPackage pkg) throws IOException, XmlException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createXAdES_T_65623() throws Exception {
|
||||||
|
initKeyPair();
|
||||||
|
|
||||||
|
UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream();
|
||||||
|
try (XSSFWorkbook wb = new XSSFWorkbook()) {
|
||||||
|
wb.createSheet().createRow(0).createCell(0).setCellValue("Test");
|
||||||
|
wb.write(bos);
|
||||||
|
}
|
||||||
|
|
||||||
|
SignatureConfig signatureConfig = new SignatureConfig();
|
||||||
|
signatureConfig.setDigestAlgo(HashAlgorithm.sha256);
|
||||||
|
signatureConfig.setKey(keyPair.getPrivate());
|
||||||
|
signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
|
||||||
|
|
||||||
|
// mock tsp
|
||||||
|
// signatureConfig.setTspUrl("http://timestamp.digicert.com");
|
||||||
|
final X509CRL crl = generateCrl(x509, keyPair.getPrivate());
|
||||||
|
TimeStampService tspService = (signatureInfo, data, revocationData) -> {
|
||||||
|
revocationData.addCRL(crl);
|
||||||
|
return "time-stamp-token".getBytes(LocaleUtil.CHARSET_1252);
|
||||||
|
};
|
||||||
|
signatureConfig.setTspService(tspService);
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
signatureConfig.setSignatureFacets(Arrays.asList(
|
||||||
|
new OOXMLSignatureFacet(),
|
||||||
|
new KeyInfoSignatureFacet(),
|
||||||
|
new XAdESSignatureFacet(),
|
||||||
|
new Office2010SignatureFacet(),
|
||||||
|
new XAdESXLSignatureFacet()
|
||||||
|
));
|
||||||
|
|
||||||
|
// create signature
|
||||||
|
try (OPCPackage pkg = OPCPackage.open(bos.toInputStream())) {
|
||||||
|
SignatureInfo si = new SignatureInfo();
|
||||||
|
si.setOpcPackage(pkg);
|
||||||
|
si.setSignatureConfig(signatureConfig);
|
||||||
|
si.confirmSignature();
|
||||||
|
|
||||||
|
bos.reset();
|
||||||
|
pkg.save(bos);
|
||||||
|
} catch (EncryptedDocumentException e) {
|
||||||
|
assumeTrue(e.getMessage().startsWith("Export Restrictions"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if timestamp node is filled
|
||||||
|
try (OPCPackage pkg = OPCPackage.open(bos.toInputStream())) {
|
||||||
|
SignatureInfo si = new SignatureInfo();
|
||||||
|
si.setOpcPackage(pkg);
|
||||||
|
si.setSignatureConfig(signatureConfig);
|
||||||
|
assertTrue(si.verifySignature());
|
||||||
|
boolean found = false;
|
||||||
|
for (SignaturePart sp : si.getSignatureParts()) {
|
||||||
|
for (ObjectType ot : sp.getSignatureDocument().getSignature().getObjectArray()) {
|
||||||
|
XmlCursor xc = ot.newCursor();
|
||||||
|
if (xc.toChild(SignatureFacet.XADES_132_NS, "QualifyingProperties")) {
|
||||||
|
QualifyingPropertiesType qpt = (QualifyingPropertiesType) xc.getObject();
|
||||||
|
assertTrue(qpt.isSetUnsignedProperties());
|
||||||
|
UnsignedPropertiesType up = qpt.getUnsignedProperties();
|
||||||
|
assertTrue(up.isSetUnsignedSignatureProperties());
|
||||||
|
UnsignedSignaturePropertiesType ups = up.getUnsignedSignatureProperties();
|
||||||
|
assertEquals(1, ups.sizeOfSignatureTimeStampArray());
|
||||||
|
XAdESTimeStampType ts = ups.getSignatureTimeStampArray(0);
|
||||||
|
assertEquals(1, ts.sizeOfEncapsulatedTimeStampArray());
|
||||||
|
EncapsulatedPKIDataType ets = ts.getEncapsulatedTimeStampArray(0);
|
||||||
|
assertFalse(ets.getStringValue().isEmpty());
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
xc.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisabledOnJreEx("1.8.0_292")
|
@DisabledOnJreEx("1.8.0_292")
|
||||||
@Tag("scratchpad.ignore")
|
@Tag("scratchpad.ignore")
|
||||||
|
|
Loading…
Reference in New Issue