git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xml_signature@1626646 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_11_BETA3
@@ -40,17 +40,18 @@ import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackagePartName; | |||
import org.apache.poi.openxml4j.opc.PackagingURIHelper; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig.SignatureConfigurable; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
/** | |||
* JSR105 URI dereferencer for Office Open XML documents. | |||
*/ | |||
public class OOXMLURIDereferencer implements URIDereferencer { | |||
public class OOXMLURIDereferencer implements URIDereferencer, SignatureConfigurable { | |||
private static final POILogger LOG = POILogFactory.getLogger(OOXMLURIDereferencer.class); | |||
private SignatureInfoConfig signatureConfig; | |||
private SignatureConfig signatureConfig; | |||
private URIDereferencer baseUriDereferencer; | |||
public OOXMLURIDereferencer() { | |||
@@ -58,7 +59,7 @@ public class OOXMLURIDereferencer implements URIDereferencer { | |||
this.baseUriDereferencer = xmlSignatureFactory.getURIDereferencer(); | |||
} | |||
public void setSignatureConfig(SignatureInfoConfig signatureConfig) { | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
@@ -0,0 +1,406 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.poifs.crypt.dsig; | |||
import java.security.PrivateKey; | |||
import java.security.cert.X509Certificate; | |||
import java.util.ArrayList; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.UUID; | |||
import javax.xml.crypto.URIDereferencer; | |||
import javax.xml.crypto.dsig.CanonicalizationMethod; | |||
import org.apache.poi.EncryptedDocumentException; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.poifs.crypt.HashAlgorithm; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfo.SignCreationListener; | |||
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.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.services.RevocationDataService; | |||
import org.apache.poi.poifs.crypt.dsig.services.SignaturePolicyService; | |||
import org.apache.poi.poifs.crypt.dsig.services.TSPTimeStampService; | |||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService; | |||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator; | |||
import org.apache.poi.poifs.crypt.dsig.spi.AddressDTO; | |||
import org.apache.poi.poifs.crypt.dsig.spi.IdentityDTO; | |||
import org.w3c.dom.events.EventListener; | |||
/** | |||
* This class bundles the configuration options used for the existing | |||
* signature facets. | |||
* Apart of the opc-package (thread local) most values will probably be constant, so | |||
* it might be configured centrally (e.g. by spring) | |||
*/ | |||
public class SignatureConfig { | |||
public static interface SignatureConfigurable { | |||
void setSignatureConfig(SignatureConfig signatureConfig); | |||
} | |||
private ThreadLocal<OPCPackage> opcPackage = new ThreadLocal<OPCPackage>(); | |||
private List<SignatureFacet> signatureFacets = new ArrayList<SignatureFacet>(); | |||
private HashAlgorithm digestAlgo = HashAlgorithm.sha1; | |||
private Date executionTime = new Date(); | |||
private PrivateKey key; | |||
private List<X509Certificate> signingCertificateChain; | |||
private IdentityDTO identity; | |||
private AddressDTO address; | |||
private byte[] photo; | |||
/** | |||
* the optional signature policy service used for XAdES-EPES. | |||
*/ | |||
private SignaturePolicyService signaturePolicyService; | |||
private URIDereferencer uriDereferencer = new OOXMLURIDereferencer(); | |||
private String signatureNamespacePrefix; | |||
private String canonicalizationMethod = CanonicalizationMethod.INCLUSIVE; | |||
private boolean includeEntireCertificateChain = true; | |||
private boolean includeIssuerSerial = false; | |||
private boolean includeKeyValue = false; | |||
private TimeStampService tspService = new TSPTimeStampService(); | |||
// timestamp service provider URL | |||
private String tspUrl; | |||
private boolean tspOldProtocol = false; | |||
private HashAlgorithm tspDigestAlgo = HashAlgorithm.sha1; | |||
private String tspUser; | |||
private String tspPass; | |||
private TimeStampServiceValidator tspValidator; | |||
/** | |||
* the optional TSP request policy OID. | |||
*/ | |||
private String tspRequestPolicy = "1.3.6.1.4.1.13762.3"; | |||
private String userAgent = "POI XmlSign Service TSP Client"; | |||
private String proxyUrl; | |||
/** | |||
* the optional revocation data service used for XAdES-C and XAdES-X-L. | |||
* When <code>null</code> the signature will be limited to XAdES-T only. | |||
*/ | |||
private RevocationDataService revocationDataService; | |||
private HashAlgorithm xadesDigestAlgo = HashAlgorithm.sha1; | |||
private String xadesRole = null; | |||
private String xadesSignatureId = null; | |||
private boolean xadesSignaturePolicyImplied = true; | |||
/** | |||
* Work-around for Office 2010 IssuerName encoding. | |||
*/ | |||
private boolean xadesIssuerNameNoReverseOrder = true; | |||
/** | |||
* The signature Id attribute value used to create the XML signature. A | |||
* <code>null</code> value will trigger an automatically generated signature Id. | |||
*/ | |||
private String packageSignatureId = "idPackageSignature"; | |||
/** | |||
* Gives back the human-readable description of what the citizen will be | |||
* signing. The default value is "Office OpenXML Document". | |||
*/ | |||
private String signatureDescription = "Office OpenXML Document"; | |||
/** | |||
* The process of signing includes the marshalling of xml structures. | |||
* This also includes the canonicalization. Currently this leads to problems | |||
* with certain namespaces, so this EventListener is used to interfere | |||
* with the marshalling process. | |||
*/ | |||
EventListener signCreationListener = null; | |||
protected void init(boolean onlyValidation) { | |||
if (uriDereferencer == null) { | |||
throw new EncryptedDocumentException("uriDereferencer is null"); | |||
} | |||
if (opcPackage == null) { | |||
throw new EncryptedDocumentException("opcPackage is null"); | |||
} | |||
if (uriDereferencer instanceof SignatureConfigurable) { | |||
((SignatureConfigurable)uriDereferencer).setSignatureConfig(this); | |||
} | |||
if (onlyValidation) return; | |||
if (signCreationListener == null) { | |||
signCreationListener = new SignCreationListener(); | |||
} | |||
if (signCreationListener instanceof SignatureConfigurable) { | |||
((SignatureConfigurable)signCreationListener).setSignatureConfig(this); | |||
} | |||
if (tspService != null) { | |||
tspService.setSignatureConfig(this); | |||
} | |||
if (xadesSignatureId == null || xadesSignatureId.isEmpty()) { | |||
xadesSignatureId = "idSignedProperties"; | |||
} | |||
if (signatureFacets.isEmpty()) { | |||
addSignatureFacet(new OOXMLSignatureFacet()); | |||
addSignatureFacet(new KeyInfoSignatureFacet()); | |||
addSignatureFacet(new XAdESSignatureFacet()); | |||
addSignatureFacet(new Office2010SignatureFacet()); | |||
} | |||
for (SignatureFacet sf : signatureFacets) { | |||
sf.setSignatureConfig(this); | |||
} | |||
} | |||
public void addSignatureFacet(SignatureFacet sf) { | |||
signatureFacets.add(sf); | |||
} | |||
/** | |||
* Gives back the used XAdES signature facet. | |||
* | |||
* @return | |||
*/ | |||
public XAdESSignatureFacet getXAdESSignatureFacet() { | |||
for (SignatureFacet sf : getSignatureFacets()) { | |||
if (sf instanceof XAdESSignatureFacet) { | |||
return (XAdESSignatureFacet)sf; | |||
} | |||
} | |||
return null; | |||
} | |||
public List<SignatureFacet> getSignatureFacets() { | |||
return signatureFacets; | |||
} | |||
public void setSignatureFacets(List<SignatureFacet> signatureFacets) { | |||
this.signatureFacets = signatureFacets; | |||
} | |||
public HashAlgorithm getDigestAlgo() { | |||
return digestAlgo; | |||
} | |||
public void setDigestAlgo(HashAlgorithm digestAlgo) { | |||
this.digestAlgo = digestAlgo; | |||
} | |||
public OPCPackage getOpcPackage() { | |||
return opcPackage.get(); | |||
} | |||
public void setOpcPackage(OPCPackage opcPackage) { | |||
this.opcPackage.set(opcPackage); | |||
} | |||
public PrivateKey getKey() { | |||
return key; | |||
} | |||
public void setKey(PrivateKey key) { | |||
this.key = key; | |||
} | |||
public List<X509Certificate> getSigningCertificateChain() { | |||
return signingCertificateChain; | |||
} | |||
public void setSigningCertificateChain( | |||
List<X509Certificate> signingCertificateChain) { | |||
this.signingCertificateChain = signingCertificateChain; | |||
} | |||
public IdentityDTO getIdentity() { | |||
return identity; | |||
} | |||
public void setIdentity(IdentityDTO identity) { | |||
this.identity = identity; | |||
} | |||
public AddressDTO getAddress() { | |||
return address; | |||
} | |||
public void setAddress(AddressDTO address) { | |||
this.address = address; | |||
} | |||
public byte[] getPhoto() { | |||
return photo; | |||
} | |||
public void setPhoto(byte[] photo) { | |||
this.photo = photo; | |||
} | |||
public Date getExecutionTime() { | |||
return executionTime; | |||
} | |||
public void setExecutionTime(Date executionTime) { | |||
this.executionTime = executionTime; | |||
} | |||
public SignaturePolicyService getSignaturePolicyService() { | |||
return signaturePolicyService; | |||
} | |||
public void setSignaturePolicyService(SignaturePolicyService signaturePolicyService) { | |||
this.signaturePolicyService = signaturePolicyService; | |||
} | |||
public URIDereferencer getUriDereferencer() { | |||
return uriDereferencer; | |||
} | |||
public void setUriDereferencer(URIDereferencer uriDereferencer) { | |||
this.uriDereferencer = uriDereferencer; | |||
} | |||
public String getSignatureDescription() { | |||
return signatureDescription; | |||
} | |||
public void setSignatureDescription(String signatureDescription) { | |||
this.signatureDescription = signatureDescription; | |||
} | |||
public String getSignatureNamespacePrefix() { | |||
return signatureNamespacePrefix; | |||
} | |||
public void setSignatureNamespacePrefix(String signatureNamespacePrefix) { | |||
this.signatureNamespacePrefix = signatureNamespacePrefix; | |||
} | |||
public String getCanonicalizationMethod() { | |||
return canonicalizationMethod; | |||
} | |||
public void setCanonicalizationMethod(String canonicalizationMethod) { | |||
this.canonicalizationMethod = canonicalizationMethod; | |||
} | |||
public String getPackageSignatureId() { | |||
return packageSignatureId; | |||
} | |||
public void setPackageSignatureId(String packageSignatureId) { | |||
this.packageSignatureId = (packageSignatureId != null) | |||
? packageSignatureId | |||
: "xmldsig-" + UUID.randomUUID(); | |||
} | |||
public String getTspUrl() { | |||
return tspUrl; | |||
} | |||
public void setTspUrl(String tspUrl) { | |||
this.tspUrl = tspUrl; | |||
} | |||
public boolean isTspOldProtocol() { | |||
return tspOldProtocol; | |||
} | |||
public void setTspOldProtocol(boolean tspOldProtocol) { | |||
this.tspOldProtocol = tspOldProtocol; | |||
} | |||
public HashAlgorithm getTspDigestAlgo() { | |||
return tspDigestAlgo; | |||
} | |||
public void setTspDigestAlgo(HashAlgorithm tspDigestAlgo) { | |||
this.tspDigestAlgo = tspDigestAlgo; | |||
} | |||
public String getProxyUrl() { | |||
return proxyUrl; | |||
} | |||
public void setProxyUrl(String proxyUrl) { | |||
this.proxyUrl = proxyUrl; | |||
} | |||
public TimeStampService getTspService() { | |||
return tspService; | |||
} | |||
public void setTspService(TimeStampService tspService) { | |||
this.tspService = tspService; | |||
} | |||
public String getTspUser() { | |||
return tspUser; | |||
} | |||
public void setTspUser(String tspUser) { | |||
this.tspUser = tspUser; | |||
} | |||
public String getTspPass() { | |||
return tspPass; | |||
} | |||
public void setTspPass(String tspPass) { | |||
this.tspPass = tspPass; | |||
} | |||
public TimeStampServiceValidator getTspValidator() { | |||
return tspValidator; | |||
} | |||
public void setTspValidator(TimeStampServiceValidator tspValidator) { | |||
this.tspValidator = tspValidator; | |||
} | |||
public RevocationDataService getRevocationDataService() { | |||
return revocationDataService; | |||
} | |||
public void setRevocationDataService(RevocationDataService revocationDataService) { | |||
this.revocationDataService = revocationDataService; | |||
} | |||
public HashAlgorithm getXadesDigestAlgo() { | |||
return xadesDigestAlgo; | |||
} | |||
public void setXadesDigestAlgo(HashAlgorithm xadesDigestAlgo) { | |||
this.xadesDigestAlgo = xadesDigestAlgo; | |||
} | |||
public String getUserAgent() { | |||
return userAgent; | |||
} | |||
public void setUserAgent(String userAgent) { | |||
this.userAgent = userAgent; | |||
} | |||
public String getTspRequestPolicy() { | |||
return tspRequestPolicy; | |||
} | |||
public void setTspRequestPolicy(String tspRequestPolicy) { | |||
this.tspRequestPolicy = tspRequestPolicy; | |||
} | |||
public boolean isIncludeEntireCertificateChain() { | |||
return includeEntireCertificateChain; | |||
} | |||
public void setIncludeEntireCertificateChain(boolean includeEntireCertificateChain) { | |||
this.includeEntireCertificateChain = includeEntireCertificateChain; | |||
} | |||
public boolean isIncludeIssuerSerial() { | |||
return includeIssuerSerial; | |||
} | |||
public void setIncludeIssuerSerial(boolean includeIssuerSerial) { | |||
this.includeIssuerSerial = includeIssuerSerial; | |||
} | |||
public boolean isIncludeKeyValue() { | |||
return includeKeyValue; | |||
} | |||
public void setIncludeKeyValue(boolean includeKeyValue) { | |||
this.includeKeyValue = includeKeyValue; | |||
} | |||
public String getXadesRole() { | |||
return xadesRole; | |||
} | |||
public void setXadesRole(String xadesRole) { | |||
this.xadesRole = xadesRole; | |||
} | |||
public String getXadesSignatureId() { | |||
return xadesSignatureId; | |||
} | |||
public void setXadesSignatureId(String xadesSignatureId) { | |||
this.xadesSignatureId = xadesSignatureId; | |||
} | |||
public boolean isXadesSignaturePolicyImplied() { | |||
return xadesSignaturePolicyImplied; | |||
} | |||
public void setXadesSignaturePolicyImplied(boolean xadesSignaturePolicyImplied) { | |||
this.xadesSignaturePolicyImplied = xadesSignaturePolicyImplied; | |||
} | |||
public boolean isXadesIssuerNameNoReverseOrder() { | |||
return xadesIssuerNameNoReverseOrder; | |||
} | |||
public void setXadesIssuerNameNoReverseOrder(boolean xadesIssuerNameNoReverseOrder) { | |||
this.xadesIssuerNameNoReverseOrder = xadesIssuerNameNoReverseOrder; | |||
} | |||
public EventListener getSignCreationListener() { | |||
return signCreationListener; | |||
} | |||
public void setSignCreationListener(EventListener signCreationListener) { | |||
this.signCreationListener = signCreationListener; | |||
} | |||
} |
@@ -86,6 +86,7 @@ import org.apache.poi.openxml4j.opc.TargetMode; | |||
import org.apache.poi.poifs.crypt.ChainingMode; | |||
import org.apache.poi.poifs.crypt.CipherAlgorithm; | |||
import org.apache.poi.poifs.crypt.CryptoFunctions; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig.SignatureConfigurable; | |||
import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet; | |||
import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService; | |||
import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; | |||
@@ -107,11 +108,13 @@ import org.w3c.dom.events.EventTarget; | |||
import org.w3c.dom.events.MutationEvent; | |||
import org.xml.sax.SAXException; | |||
public class SignatureInfo { | |||
public class SignatureInfo implements SignatureConfigurable { | |||
public static final String XmlNS = "http://www.w3.org/2000/xmlns/"; | |||
public static final String XmlDSigNS = XMLSignature.XMLNS; | |||
// see https://www.ietf.org/rfc/rfc3110.txt | |||
// RSA/SHA1 SIG Resource Records | |||
public static final byte[] SHA1_DIGEST_INFO_PREFIX = new byte[] | |||
{ 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14 }; | |||
@@ -140,17 +143,41 @@ public class SignatureInfo { | |||
public static final byte[] RIPEMD256_DIGEST_INFO_PREFIX = new byte[] | |||
{ 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x03, 0x04, 0x20 }; | |||
protected static class SignCreationListener implements EventListener, SignatureConfigurable { | |||
ThreadLocal<EventTarget> target = new ThreadLocal<EventTarget>(); | |||
SignatureConfig signatureConfig; | |||
public void setEventTarget(EventTarget target) { | |||
this.target.set(target); | |||
} | |||
public void handleEvent(Event e) { | |||
if (e instanceof MutationEvent) { | |||
MutationEvent mutEvt = (MutationEvent)e; | |||
if (mutEvt.getTarget() instanceof Element) { | |||
Element el = (Element)mutEvt.getTarget(); | |||
String packageId = signatureConfig.getPackageSignatureId(); | |||
if (packageId.equals(el.getAttribute("Id"))) { | |||
target.get().removeEventListener("DOMSubtreeModified", this, false); | |||
el.setAttributeNS(XmlNS, "xmlns:mdssi", PackageNamespaces.DIGITAL_SIGNATURE); | |||
} | |||
} | |||
} | |||
} | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
} | |||
private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class); | |||
private static boolean isInitialized = false; | |||
private SignatureInfoConfig signatureConfig; | |||
private SignatureConfig signatureConfig; | |||
public SignatureInfoConfig getSignatureConfig() { | |||
public SignatureConfig getSignatureConfig() { | |||
return signatureConfig; | |||
} | |||
public void setSignatureConfig(SignatureInfoConfig signatureConfig) { | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
@@ -199,6 +226,8 @@ public class SignatureInfo { | |||
} | |||
protected boolean getSignersAndValidate(List<X509Certificate> signers, boolean onlyFirst) { | |||
signatureConfig.init(true); | |||
boolean allValid = true; | |||
List<PackagePart> signatureParts = getSignatureParts(onlyFirst); | |||
if (signatureParts.isEmpty()) { | |||
@@ -345,27 +374,18 @@ public class SignatureInfo { | |||
TransformerFactoryConfigurationError, TransformerException, | |||
IOException, SAXException, NoSuchProviderException, XmlException, URISyntaxException { | |||
SignatureInfo.initXmlProvider(); | |||
signatureConfig.init(false); | |||
// it's necessary to explicitly set the mdssi namespace, but the sign() method has no | |||
// normal way to interfere with, so we need to add the namespace under the hand ... | |||
final EventTarget et = (EventTarget)document; | |||
EventListener myModificationListener = new EventListener() { | |||
@Override | |||
public void handleEvent(Event e) { | |||
if (e instanceof MutationEvent) { | |||
MutationEvent mutEvt = (MutationEvent)e; | |||
if (mutEvt.getTarget() instanceof Element) { | |||
Element el = (Element)mutEvt.getTarget(); | |||
if ("idPackageObject".equals(el.getAttribute("Id"))) { | |||
et.removeEventListener("DOMSubtreeModified", this, false); | |||
el.setAttributeNS(XmlNS, "xmlns:mdssi", PackageNamespaces.DIGITAL_SIGNATURE); | |||
} | |||
} | |||
} | |||
EventTarget target = (EventTarget)document; | |||
EventListener creationListener = signatureConfig.getSignCreationListener(); | |||
if (creationListener != null) { | |||
if (creationListener instanceof SignCreationListener) { | |||
((SignCreationListener)creationListener).setEventTarget(target); | |||
} | |||
}; | |||
et.addEventListener("DOMSubtreeModified", myModificationListener, false); | |||
target.addEventListener("DOMSubtreeModified", creationListener, false); | |||
} | |||
/* | |||
* Signature context construction. |
@@ -1,202 +0,0 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.poifs.crypt.dsig; | |||
import java.security.PrivateKey; | |||
import java.security.cert.X509Certificate; | |||
import java.util.ArrayList; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.UUID; | |||
import javax.xml.crypto.URIDereferencer; | |||
import javax.xml.crypto.dsig.CanonicalizationMethod; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.poifs.crypt.HashAlgorithm; | |||
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.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.services.SignaturePolicyService; | |||
import org.apache.poi.poifs.crypt.dsig.spi.AddressDTO; | |||
import org.apache.poi.poifs.crypt.dsig.spi.IdentityDTO; | |||
public class SignatureInfoConfig { | |||
private List<SignatureFacet> signatureFacets = new ArrayList<SignatureFacet>(); | |||
private HashAlgorithm digestAlgo = HashAlgorithm.sha1; | |||
private Date executionTime = new Date(); | |||
private OPCPackage opcPackage; | |||
private PrivateKey key; | |||
private List<X509Certificate> signingCertificateChain; | |||
private IdentityDTO identity; | |||
private AddressDTO address; | |||
private byte[] photo; | |||
private SignaturePolicyService signaturePolicyService; | |||
private URIDereferencer uriDereferencer; | |||
private String signatureNamespacePrefix; | |||
private String canonicalizationMethod = CanonicalizationMethod.INCLUSIVE; | |||
/** | |||
* The signature Id attribute value used to create the XML signature. A | |||
* <code>null</code> value will trigger an automatically generated signature Id. | |||
*/ | |||
private String packageSignatureId = "idPackageSignature"; | |||
/** | |||
* Gives back the human-readable description of what the citizen will be | |||
* signing. The default value is "Office OpenXML Document". | |||
*/ | |||
private String signatureDescription = "Office OpenXML Document"; | |||
public SignatureInfoConfig() { | |||
OOXMLURIDereferencer uriDereferencer = new OOXMLURIDereferencer(); | |||
uriDereferencer.setSignatureConfig(this); | |||
this.uriDereferencer = uriDereferencer; | |||
} | |||
public void addSignatureFacet(SignatureFacet sf) { | |||
signatureFacets.add(sf); | |||
} | |||
public void addDefaultFacets() { | |||
addSignatureFacet(new OOXMLSignatureFacet(this)); | |||
addSignatureFacet(new KeyInfoSignatureFacet(true, false, false)); | |||
XAdESSignatureFacet xadesSignatureFacet = new XAdESSignatureFacet(this); | |||
xadesSignatureFacet.setIdSignedProperties("idSignedProperties"); | |||
xadesSignatureFacet.setSignaturePolicyImplied(true); | |||
/* | |||
* Work-around for Office 2010. | |||
*/ | |||
xadesSignatureFacet.setIssuerNameNoReverseOrder(true); | |||
addSignatureFacet(xadesSignatureFacet); | |||
addSignatureFacet(new Office2010SignatureFacet()); | |||
} | |||
/** | |||
* Gives back the used XAdES signature facet. | |||
* | |||
* @return | |||
*/ | |||
public XAdESSignatureFacet getXAdESSignatureFacet() { | |||
for (SignatureFacet sf : getSignatureFacets()) { | |||
if (sf instanceof XAdESSignatureFacet) { | |||
return (XAdESSignatureFacet)sf; | |||
} | |||
} | |||
return null; | |||
} | |||
public List<SignatureFacet> getSignatureFacets() { | |||
return signatureFacets; | |||
} | |||
public void setSignatureFacets(List<SignatureFacet> signatureFacets) { | |||
this.signatureFacets = signatureFacets; | |||
} | |||
public HashAlgorithm getDigestAlgo() { | |||
return digestAlgo; | |||
} | |||
public void setDigestAlgo(HashAlgorithm digestAlgo) { | |||
this.digestAlgo = digestAlgo; | |||
} | |||
public OPCPackage getOpcPackage() { | |||
return opcPackage; | |||
} | |||
public void setOpcPackage(OPCPackage opcPackage) { | |||
this.opcPackage = opcPackage; | |||
} | |||
public PrivateKey getKey() { | |||
return key; | |||
} | |||
public void setKey(PrivateKey key) { | |||
this.key = key; | |||
} | |||
public List<X509Certificate> getSigningCertificateChain() { | |||
return signingCertificateChain; | |||
} | |||
public void setSigningCertificateChain( | |||
List<X509Certificate> signingCertificateChain) { | |||
this.signingCertificateChain = signingCertificateChain; | |||
} | |||
public IdentityDTO getIdentity() { | |||
return identity; | |||
} | |||
public void setIdentity(IdentityDTO identity) { | |||
this.identity = identity; | |||
} | |||
public AddressDTO getAddress() { | |||
return address; | |||
} | |||
public void setAddress(AddressDTO address) { | |||
this.address = address; | |||
} | |||
public byte[] getPhoto() { | |||
return photo; | |||
} | |||
public void setPhoto(byte[] photo) { | |||
this.photo = photo; | |||
} | |||
public Date getExecutionTime() { | |||
return executionTime; | |||
} | |||
public void setExecutionTime(Date executionTime) { | |||
this.executionTime = executionTime; | |||
} | |||
public SignaturePolicyService getSignaturePolicyService() { | |||
return signaturePolicyService; | |||
} | |||
public void setSignaturePolicyService(SignaturePolicyService signaturePolicyService) { | |||
this.signaturePolicyService = signaturePolicyService; | |||
} | |||
public URIDereferencer getUriDereferencer() { | |||
return uriDereferencer; | |||
} | |||
public void setUriDereferencer(URIDereferencer uriDereferencer) { | |||
this.uriDereferencer = uriDereferencer; | |||
} | |||
public String getSignatureDescription() { | |||
return signatureDescription; | |||
} | |||
public void setSignatureDescription(String signatureDescription) { | |||
this.signatureDescription = signatureDescription; | |||
} | |||
public String getSignatureNamespacePrefix() { | |||
return signatureNamespacePrefix; | |||
} | |||
public void setSignatureNamespacePrefix(String signatureNamespacePrefix) { | |||
this.signatureNamespacePrefix = signatureNamespacePrefix; | |||
} | |||
public String getCanonicalizationMethod() { | |||
return canonicalizationMethod; | |||
} | |||
public void setCanonicalizationMethod(String canonicalizationMethod) { | |||
this.canonicalizationMethod = canonicalizationMethod; | |||
} | |||
public String getPackageSignatureId() { | |||
return packageSignatureId; | |||
} | |||
public void setPackageSignatureId(String packageSignatureId) { | |||
this.packageSignatureId = (packageSignatureId != null) | |||
? packageSignatureId | |||
: "xmldsig-" + UUID.randomUUID(); | |||
} | |||
} |
@@ -15,7 +15,7 @@ import javax.xml.crypto.dsig.XMLObject; | |||
import javax.xml.crypto.dsig.XMLSignatureFactory; | |||
import javax.xml.crypto.dsig.spec.TransformParameterSpec; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.w3c.dom.Document; | |||
/** | |||
@@ -26,12 +26,12 @@ import org.w3c.dom.Document; | |||
*/ | |||
public class EnvelopedSignatureFacet implements SignatureFacet { | |||
private SignatureInfoConfig signatureConfig; | |||
private SignatureConfig signatureConfig; | |||
public EnvelopedSignatureFacet(SignatureInfoConfig signatureConfig) { | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
@Override | |||
public void postSign(Document document, List<X509Certificate> signingCertificateChain) { | |||
// empty |
@@ -49,6 +49,7 @@ import javax.xml.crypto.dsig.keyinfo.KeyValue; | |||
import javax.xml.crypto.dsig.keyinfo.X509Data; | |||
import org.apache.jcp.xml.dsig.internal.dom.DOMKeyInfo; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfo; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
@@ -66,25 +67,11 @@ import org.w3c.dom.NodeList; | |||
public class KeyInfoSignatureFacet implements SignatureFacet { | |||
private static final POILogger LOG = POILogFactory.getLogger(KeyInfoSignatureFacet.class); | |||
SignatureConfig signatureConfig; | |||
private final boolean includeEntireCertificateChain; | |||
private final boolean includeIssuerSerial; | |||
private final boolean includeKeyValue; | |||
/** | |||
* Main constructor. | |||
* | |||
* @param includeEntireCertificateChain | |||
* @param includeIssuerSerial | |||
* @param includeKeyValue | |||
*/ | |||
public KeyInfoSignatureFacet(boolean includeEntireCertificateChain, | |||
boolean includeIssuerSerial, boolean includeKeyValue) { | |||
this.includeEntireCertificateChain = includeEntireCertificateChain; | |||
this.includeIssuerSerial = includeIssuerSerial; | |||
this.includeKeyValue = includeKeyValue; | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
@Override | |||
@@ -109,7 +96,7 @@ public class KeyInfoSignatureFacet implements SignatureFacet { | |||
List<Object> keyInfoContent = new ArrayList<Object>(); | |||
if (this.includeKeyValue) { | |||
if (signatureConfig.isIncludeKeyValue()) { | |||
KeyValue keyValue; | |||
try { | |||
keyValue = keyInfoFactory.newKeyValue(signingCertificate.getPublicKey()); | |||
@@ -119,13 +106,13 @@ public class KeyInfoSignatureFacet implements SignatureFacet { | |||
keyInfoContent.add(keyValue); | |||
} | |||
if (this.includeIssuerSerial) { | |||
if (signatureConfig.isIncludeIssuerSerial()) { | |||
x509DataObjects.add(keyInfoFactory.newX509IssuerSerial( | |||
signingCertificate.getIssuerX500Principal().toString(), | |||
signingCertificate.getSerialNumber())); | |||
} | |||
if (this.includeEntireCertificateChain) { | |||
if (signatureConfig.isIncludeEntireCertificateChain()) { | |||
x509DataObjects.addAll(signingCertificateChain); | |||
} else { | |||
x509DataObjects.add(signingCertificate); |
@@ -67,7 +67,7 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; | |||
import org.apache.poi.openxml4j.opc.PackagingURIHelper; | |||
import org.apache.poi.openxml4j.opc.TargetMode; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService; | |||
import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService.RelationshipTransformParameterSpec; | |||
import org.apache.poi.util.POILogFactory; | |||
@@ -94,15 +94,12 @@ public class OOXMLSignatureFacet implements SignatureFacet { | |||
public static final String OOXML_DIGSIG_NS = "http://schemas.openxmlformats.org/package/2006/digital-signature"; | |||
public static final String OFFICE_DIGSIG_NS = "http://schemas.microsoft.com/office/2006/digsig"; | |||
private final SignatureInfoConfig signatureConfig; | |||
private SignatureConfig signatureConfig; | |||
/** | |||
* Main constructor. | |||
*/ | |||
public OOXMLSignatureFacet(SignatureInfoConfig signatureConfig) { | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
@Override | |||
public void preSign( | |||
Document document |
@@ -34,6 +34,7 @@ import javax.xml.crypto.dsig.Reference; | |||
import javax.xml.crypto.dsig.XMLObject; | |||
import javax.xml.crypto.dsig.XMLSignatureFactory; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.etsi.uri.x01903.v13.QualifyingPropertiesType; | |||
import org.etsi.uri.x01903.v13.UnsignedPropertiesType; | |||
@@ -53,6 +54,10 @@ import org.w3c.dom.NodeList; | |||
*/ | |||
public class Office2010SignatureFacet implements SignatureFacet { | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
// this.signatureConfig = signatureConfig; | |||
} | |||
@Override | |||
public void preSign( | |||
Document document |
@@ -37,6 +37,7 @@ import javax.xml.crypto.dsig.Reference; | |||
import javax.xml.crypto.dsig.XMLObject; | |||
import javax.xml.crypto.dsig.XMLSignatureFactory; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig.SignatureConfigurable; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.w3c.dom.Document; | |||
@@ -46,7 +47,7 @@ import org.w3c.dom.Document; | |||
* @author Frank Cornelis | |||
* | |||
*/ | |||
public interface SignatureFacet { | |||
public interface SignatureFacet extends SignatureConfigurable { | |||
/** | |||
* This method is being invoked by the XML signature service engine during |
@@ -51,8 +51,8 @@ import javax.xml.crypto.dsig.spec.TransformParameterSpec; | |||
import org.apache.poi.poifs.crypt.CryptoFunctions; | |||
import org.apache.poi.poifs.crypt.HashAlgorithm; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfo; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig; | |||
import org.apache.poi.poifs.crypt.dsig.services.SignaturePolicyService; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
@@ -99,32 +99,11 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
private static final String XADES_TYPE = "http://uri.etsi.org/01903#SignedProperties"; | |||
private SignatureInfoConfig signatureConfig; | |||
private SignatureConfig signatureConfig; | |||
private String idSignedProperties; | |||
private boolean signaturePolicyImplied; | |||
private String role; | |||
private boolean issuerNameNoReverseOrder = false; | |||
private Map<String, String> dataObjectFormatMimeTypes = new HashMap<String, String>(); | |||
/** | |||
* Main constructor. | |||
* | |||
* @param clock | |||
* the clock to be used for determining the xades:SigningTime, | |||
* defaults to now when null | |||
* @param hashAlgo | |||
* the digest algorithm to be used for all required XAdES digest | |||
* operations. Possible values: "SHA-1", "SHA-256", or "SHA-512", | |||
* defaults to SHA-1 when null | |||
* @param signaturePolicyService | |||
* the optional signature policy service used for XAdES-EPES. | |||
*/ | |||
public XAdESSignatureFacet(SignatureInfoConfig signatureConfig) { | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
@@ -147,11 +126,7 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
// SignedProperties | |||
SignedPropertiesType signedProperties = qualifyingProperties.addNewSignedProperties(); | |||
String signedPropertiesId = this.idSignedProperties; | |||
if (this.idSignedProperties == null) { | |||
signedPropertiesId = signatureConfig.getPackageSignatureId() + "-xades"; | |||
} | |||
signedProperties.setId(signedPropertiesId); | |||
signedProperties.setId(signatureConfig.getXadesSignatureId()); | |||
// SignedSignatureProperties | |||
SignedSignaturePropertiesType signedSignatureProperties = signedProperties.addNewSignedSignatureProperties(); | |||
@@ -159,7 +134,7 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
// SigningTime | |||
Calendar xmlGregorianCalendar = Calendar.getInstance(); | |||
xmlGregorianCalendar.setTimeZone(TimeZone.getTimeZone("Z")); | |||
xmlGregorianCalendar.setTime(this.signatureConfig.getExecutionTime()); | |||
xmlGregorianCalendar.setTime(signatureConfig.getExecutionTime()); | |||
xmlGregorianCalendar.clear(Calendar.MILLISECOND); | |||
signedSignatureProperties.setSigningTime(xmlGregorianCalendar); | |||
@@ -170,22 +145,23 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
} | |||
CertIDListType signingCertificates = signedSignatureProperties.addNewSigningCertificate(); | |||
CertIDType certId = signingCertificates.addNewCert(); | |||
X509Certificate signingCertificate = signatureConfig.getSigningCertificateChain().get(0); | |||
setCertID(certId, signingCertificate, this.signatureConfig.getDigestAlgo(), this.issuerNameNoReverseOrder); | |||
X509Certificate certificate = signatureConfig.getSigningCertificateChain().get(0); | |||
setCertID(certId, signatureConfig, signatureConfig.isXadesIssuerNameNoReverseOrder(), certificate); | |||
// ClaimedRole | |||
if (null != this.role && false == this.role.isEmpty()) { | |||
String role = signatureConfig.getXadesRole(); | |||
if (role != null && !role.isEmpty()) { | |||
SignerRoleType signerRole = signedSignatureProperties.addNewSignerRole(); | |||
signedSignatureProperties.setSignerRole(signerRole); | |||
ClaimedRolesListType claimedRolesList = signerRole.addNewClaimedRoles(); | |||
AnyType claimedRole = claimedRolesList.addNewClaimedRole(); | |||
XmlString roleString = XmlString.Factory.newInstance(); | |||
roleString.setStringValue(this.role); | |||
roleString.setStringValue(role); | |||
insertXChild(claimedRole, roleString); | |||
} | |||
// XAdES-EPES | |||
SignaturePolicyService policyService = this.signatureConfig.getSignaturePolicyService(); | |||
SignaturePolicyService policyService = signatureConfig.getSignaturePolicyService(); | |||
if (policyService != null) { | |||
SignaturePolicyIdentifierType signaturePolicyIdentifier = | |||
signedSignatureProperties.addNewSignaturePolicyIdentifier(); | |||
@@ -200,7 +176,7 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
byte[] signaturePolicyDocumentData = policyService.getSignaturePolicyDocument(); | |||
DigestAlgAndValueType sigPolicyHash = signaturePolicyId.addNewSigPolicyHash(); | |||
setDigestAlgAndValue(sigPolicyHash, signaturePolicyDocumentData, this.signatureConfig.getDigestAlgo()); | |||
setDigestAlgAndValue(sigPolicyHash, signaturePolicyDocumentData, signatureConfig.getDigestAlgo()); | |||
String signaturePolicyDownloadUrl = policyService.getSignaturePolicyDownloadUrl(); | |||
if (null != signaturePolicyDownloadUrl) { | |||
@@ -210,14 +186,14 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
spUriElement.setStringValue(signaturePolicyDownloadUrl); | |||
insertXChild(sigPolicyQualifier, spUriElement); | |||
} | |||
} else if (this.signaturePolicyImplied) { | |||
} else if (signatureConfig.isXadesSignaturePolicyImplied()) { | |||
SignaturePolicyIdentifierType signaturePolicyIdentifier = | |||
signedSignatureProperties.addNewSignaturePolicyIdentifier(); | |||
signaturePolicyIdentifier.addNewSignaturePolicyImplied(); | |||
} | |||
// DataObjectFormat | |||
if (false == this.dataObjectFormatMimeTypes.isEmpty()) { | |||
if (!dataObjectFormatMimeTypes.isEmpty()) { | |||
SignedDataObjectPropertiesType signedDataObjectProperties = | |||
signedProperties.addNewSignedDataObjectProperties(); | |||
@@ -246,15 +222,14 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
objects.add(xadesObject); | |||
// add XAdES ds:Reference | |||
DigestMethod digestMethod = signatureFactory.newDigestMethod(this.signatureConfig.getDigestAlgo().xmlSignUri, null); | |||
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null); | |||
List<Transform> transforms = new ArrayList<Transform>(); | |||
Transform exclusiveTransform = signatureFactory | |||
.newTransform(CanonicalizationMethod.INCLUSIVE, | |||
(TransformParameterSpec) null); | |||
transforms.add(exclusiveTransform); | |||
Reference reference = signatureFactory.newReference("#" | |||
+ signedPropertiesId, digestMethod, transforms, XADES_TYPE, | |||
null); | |||
Reference reference = signatureFactory.newReference | |||
("#"+signatureConfig.getXadesSignatureId(), digestMethod, transforms, XADES_TYPE, null); | |||
references.add(reference); | |||
} | |||
@@ -281,17 +256,9 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
/** | |||
* Gives back the JAXB CertID data structure. | |||
* | |||
* @param certificate | |||
* @param xadesObjectFactory | |||
* @param xmldsigObjectFactory | |||
* @param digestAlgorithm | |||
* @return | |||
*/ | |||
protected static void setCertID( | |||
CertIDType certId, | |||
X509Certificate certificate, | |||
HashAlgorithm digestAlgorithm, boolean issuerNameNoReverseOrder) { | |||
protected static void setCertID | |||
(CertIDType certId, SignatureConfig signatureConfig, boolean issuerNameNoReverseOrder, X509Certificate certificate) { | |||
X509IssuerSerialType issuerSerial = certId.addNewIssuerSerial(); | |||
String issuerName; | |||
if (issuerNameNoReverseOrder) { | |||
@@ -319,7 +286,7 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
+ e.getMessage(), e); | |||
} | |||
DigestAlgAndValueType certDigest = certId.addNewCertDigest(); | |||
setDigestAlgAndValue(certDigest, encodedCertificate, digestAlgorithm); | |||
setDigestAlgAndValue(certDigest, encodedCertificate, signatureConfig.getXadesDigestAlgo()); | |||
} | |||
/** | |||
@@ -333,43 +300,6 @@ public class XAdESSignatureFacet implements SignatureFacet { | |||
this.dataObjectFormatMimeTypes.put(dsReferenceUri, mimetype); | |||
} | |||
/** | |||
* Sets the Id that will be used on the SignedProperties element; | |||
* | |||
* @param idSignedProperties | |||
*/ | |||
public void setIdSignedProperties(String idSignedProperties) { | |||
this.idSignedProperties = idSignedProperties; | |||
} | |||
/** | |||
* Sets the signature policy to implied. | |||
* | |||
* @param signaturePolicyImplied | |||
*/ | |||
public void setSignaturePolicyImplied(boolean signaturePolicyImplied) { | |||
this.signaturePolicyImplied = signaturePolicyImplied; | |||
} | |||
/** | |||
* Sets the XAdES claimed role. | |||
* | |||
* @param role | |||
*/ | |||
public void setRole(String role) { | |||
this.role = role; | |||
} | |||
/** | |||
* Work-around for Office 2010 IssuerName encoding. | |||
* | |||
* @param reverseOrder | |||
*/ | |||
public void setIssuerNameNoReverseOrder(boolean reverseOrder) { | |||
this.issuerNameNoReverseOrder = reverseOrder; | |||
} | |||
public Map<String,String> getNamespacePrefixMapping() { | |||
Map<String,String> map = new HashMap<String,String>(); | |||
map.put("xd", "http://uri.etsi.org/01903/v1.3.2#"); |
@@ -50,10 +50,8 @@ import javax.xml.crypto.dsig.Reference; | |||
import javax.xml.crypto.dsig.XMLObject; | |||
import javax.xml.crypto.dsig.XMLSignatureFactory; | |||
import org.apache.poi.poifs.crypt.HashAlgorithm; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.apache.poi.poifs.crypt.dsig.services.RevocationData; | |||
import org.apache.poi.poifs.crypt.dsig.services.RevocationDataService; | |||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
import org.apache.xml.security.c14n.Canonicalizer; | |||
@@ -117,53 +115,27 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
public static final String XADES_NAMESPACE = "http://uri.etsi.org/01903/v1.3.2#"; | |||
public static final String XADES141_NAMESPACE = "http://uri.etsi.org/01903/v1.4.1#"; | |||
private SignatureConfig signatureConfig; | |||
private final TimeStampService timeStampService; | |||
private String c14nAlgoId; | |||
private final RevocationDataService revocationDataService; | |||
private String c14nAlgoId = CanonicalizationMethod.EXCLUSIVE; | |||
private final CertificateFactory certificateFactory; | |||
private final HashAlgorithm hashAlgo; | |||
/** | |||
* Convenience constructor. | |||
* | |||
* @param timeStampService | |||
* the time-stamp service used for XAdES-T and XAdES-X. | |||
* @param revocationDataService | |||
* the optional revocation data service used for XAdES-C and | |||
* XAdES-X-L. When <code>null</code> the signature will be | |||
* limited to XAdES-T only. | |||
*/ | |||
public XAdESXLSignatureFacet(TimeStampService timeStampService, | |||
RevocationDataService revocationDataService) { | |||
this(timeStampService, revocationDataService, HashAlgorithm.sha1); | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
/** | |||
* Main constructor. | |||
* Convenience constructor. | |||
* | |||
* @param timeStampService | |||
* the time-stamp service used for XAdES-T and XAdES-X. | |||
* @param revocationDataService | |||
* the optional revocation data service used for XAdES-C and | |||
* XAdES-X-L. When <code>null</code> the signature will be | |||
* limited to XAdES-T only. | |||
* @param digestAlgorithm | |||
* the digest algorithm to be used for construction of the | |||
* XAdES-X-L elements. | |||
*/ | |||
public XAdESXLSignatureFacet(TimeStampService timeStampService, | |||
RevocationDataService revocationDataService, | |||
HashAlgorithm digestAlgorithm) { | |||
this.c14nAlgoId = CanonicalizationMethod.EXCLUSIVE; | |||
this.hashAlgo = digestAlgorithm; | |||
this.timeStampService = timeStampService; | |||
this.revocationDataService = revocationDataService; | |||
public XAdESXLSignatureFacet() { | |||
try { | |||
this.certificateFactory = CertificateFactory.getInstance("X.509"); | |||
} catch (CertificateException e) { | |||
@@ -212,8 +184,8 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
RevocationData tsaRevocationDataXadesT = new RevocationData(); | |||
LOG.log(POILogger.DEBUG, "creating XAdES-T time-stamp"); | |||
XAdESTimeStampType signatureTimeStamp = createXAdESTimeStamp( | |||
Collections.singletonList(nlSigVal.item(0)), tsaRevocationDataXadesT, this.c14nAlgoId, this.timeStampService); | |||
XAdESTimeStampType signatureTimeStamp = createXAdESTimeStamp | |||
(Collections.singletonList(nlSigVal.item(0)), tsaRevocationDataXadesT); | |||
// marshal the XAdES-T extension | |||
unsignedSigProps.addNewSignatureTimeStamp().set(signatureTimeStamp); | |||
@@ -224,7 +196,7 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
insertXChild(unsignedSigProps, validationData); | |||
} | |||
if (null == this.revocationDataService) { | |||
if (signatureConfig.getRevocationDataService() == null) { | |||
/* | |||
* Without revocation data service we cannot construct the XAdES-C | |||
* extension. | |||
@@ -237,21 +209,23 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
unsignedSigProps.addNewCompleteCertificateRefs(); | |||
CertIDListType certIdList = completeCertificateRefs.addNewCertRefs(); | |||
for (int certIdx = 1; certIdx < signingCertificateChain.size(); certIdx++) { | |||
/* | |||
* We skip the signing certificate itself according to section | |||
* 4.4.3.2 of the XAdES 1.4.1 specification. | |||
*/ | |||
X509Certificate certificate = signingCertificateChain.get(certIdx); | |||
CertIDType certId = certIdList.addNewCert(); | |||
XAdESSignatureFacet.setCertID(certId, certificate, this.hashAlgo, false); | |||
/* | |||
* We skip the signing certificate itself according to section | |||
* 4.4.3.2 of the XAdES 1.4.1 specification. | |||
*/ | |||
int chainSize = signingCertificateChain.size(); | |||
if (chainSize > 1) { | |||
for (X509Certificate cert : signingCertificateChain.subList(1, chainSize)) { | |||
CertIDType certId = certIdList.addNewCert(); | |||
XAdESSignatureFacet.setCertID(certId, signatureConfig, false, cert); | |||
} | |||
} | |||
// XAdES-C: complete revocation refs | |||
CompleteRevocationRefsType completeRevocationRefs = | |||
unsignedSigProps.addNewCompleteRevocationRefs(); | |||
RevocationData revocationData = this.revocationDataService | |||
.getRevocationData(signingCertificateChain); | |||
RevocationData revocationData = signatureConfig.getRevocationDataService() | |||
.getRevocationData(signingCertificateChain); | |||
if (revocationData.hasCRLs()) { | |||
CRLRefsType crlRefs = completeRevocationRefs.addNewCRLRefs(); | |||
completeRevocationRefs.setCRLRefs(crlRefs); | |||
@@ -276,7 +250,7 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
crlIdentifier.setNumber(getCrlNumber(crl)); | |||
DigestAlgAndValueType digestAlgAndValue = crlRef.addNewDigestAlgAndValue(); | |||
XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, encodedCrl, this.hashAlgo); | |||
XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, encodedCrl, signatureConfig.getDigestAlgo()); | |||
} | |||
} | |||
if (revocationData.hasOCSPs()) { | |||
@@ -286,7 +260,7 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
OCSPRefType ocspRef = ocspRefs.addNewOCSPRef(); | |||
DigestAlgAndValueType digestAlgAndValue = ocspRef.addNewDigestAlgAndValue(); | |||
XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, ocsp, this.hashAlgo); | |||
XAdESSignatureFacet.setDigestAlgAndValue(digestAlgAndValue, ocsp, signatureConfig.getDigestAlgo()); | |||
OCSPIdentifierType ocspIdentifier = ocspRef.addNewOCSPIdentifier(); | |||
@@ -329,9 +303,8 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
RevocationData tsaRevocationDataXadesX1 = new RevocationData(); | |||
LOG.log(POILogger.DEBUG, "creating XAdES-X time-stamp"); | |||
XAdESTimeStampType timeStampXadesX1 = createXAdESTimeStamp( | |||
timeStampNodesXadesX1, tsaRevocationDataXadesX1, | |||
this.c14nAlgoId, this.timeStampService); | |||
XAdESTimeStampType timeStampXadesX1 = createXAdESTimeStamp | |||
(timeStampNodesXadesX1, tsaRevocationDataXadesX1); | |||
if (tsaRevocationDataXadesX1.hasRevocationDataEntries()) { | |||
ValidationDataType timeStampXadesX1ValidationData = createValidationData(tsaRevocationDataXadesX1); | |||
insertXChild(unsignedSigProps, timeStampXadesX1ValidationData); | |||
@@ -406,26 +379,19 @@ public class XAdESXLSignatureFacet implements SignatureFacet { | |||
} | |||
} | |||
public static XAdESTimeStampType createXAdESTimeStamp( | |||
private XAdESTimeStampType createXAdESTimeStamp( | |||
List<Node> nodeList, | |||
RevocationData revocationData, | |||
String c14nAlgoId, | |||
TimeStampService timeStampService) { | |||
RevocationData revocationData) { | |||
byte[] c14nSignatureValueElement = getC14nValue(nodeList, c14nAlgoId); | |||
return createXAdESTimeStamp(c14nSignatureValueElement, revocationData, | |||
c14nAlgoId, timeStampService); | |||
return createXAdESTimeStamp(c14nSignatureValueElement, revocationData); | |||
} | |||
public static XAdESTimeStampType createXAdESTimeStamp( | |||
byte[] data, | |||
RevocationData revocationData, | |||
String c14nAlgoId, | |||
TimeStampService timeStampService) { | |||
private XAdESTimeStampType createXAdESTimeStamp(byte[] data, RevocationData revocationData) { | |||
// create the time-stamp | |||
byte[] timeStampToken; | |||
try { | |||
timeStampToken = timeStampService.timeStamp(data, revocationData); | |||
timeStampToken = signatureConfig.getTspService().timeStamp(data, revocationData); | |||
} catch (Exception e) { | |||
throw new RuntimeException("error while creating a time-stamp: " | |||
+ e.getMessage(), e); |
@@ -25,6 +25,7 @@ | |||
package org.apache.poi.poifs.crypt.dsig.services; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.math.BigInteger; | |||
import java.net.HttpURLConnection; | |||
@@ -45,14 +46,17 @@ import javax.xml.bind.DatatypeConverter; | |||
import org.apache.poi.poifs.crypt.CryptoFunctions; | |||
import org.apache.poi.poifs.crypt.HashAlgorithm; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.apache.poi.util.IOUtils; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
import org.bouncycastle.asn1.ASN1ObjectIdentifier; | |||
import org.bouncycastle.asn1.cmp.PKIFailureInfo; | |||
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; | |||
import org.bouncycastle.asn1.x500.X500Name; | |||
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; | |||
import org.bouncycastle.cert.X509CertificateHolder; | |||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; | |||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; | |||
import org.bouncycastle.cms.DefaultCMSSignatureAlgorithmNameGenerator; | |||
import org.bouncycastle.cms.SignerId; | |||
import org.bouncycastle.cms.SignerInformationVerifier; | |||
@@ -75,185 +79,63 @@ public class TSPTimeStampService implements TimeStampService { | |||
private static final POILogger LOG = POILogFactory.getLogger(TSPTimeStampService.class); | |||
static { | |||
CryptoFunctions.registerBouncyCastle(); | |||
} | |||
public static final String DEFAULT_USER_AGENT = "POI XmlSign Service TSP Client"; | |||
private final String tspServiceUrl; | |||
private String requestPolicy; | |||
private final String userAgent; | |||
private final TimeStampServiceValidator validator; | |||
private String username; | |||
private String password; | |||
private String proxyHost; | |||
private int proxyPort; | |||
private HashAlgorithm digestAlgo; | |||
private String digestAlgoOid; | |||
private String requestContentType = "application/timestamp-query;charset=ISO-8859-1"; | |||
private String responseContentType = "application/timestamp-reply"; | |||
public TSPTimeStampService(String tspServiceUrl, | |||
TimeStampServiceValidator validator) { | |||
this(tspServiceUrl, validator, null, null); | |||
} | |||
/** | |||
* Main constructor. | |||
* | |||
* @param tspServiceUrl | |||
* the URL of the TSP service. | |||
* @param validator | |||
* the trust validator used to validate incoming TSP response | |||
* signatures. | |||
* @param requestPolicy | |||
* the optional TSP request policy. | |||
* @param userAgent | |||
* the optional User-Agent TSP request header value. | |||
*/ | |||
public TSPTimeStampService(String tspServiceUrl, | |||
TimeStampServiceValidator validator, String requestPolicy, | |||
String userAgent) { | |||
if (null == tspServiceUrl) { | |||
throw new IllegalArgumentException("TSP service URL required"); | |||
} | |||
this.tspServiceUrl = tspServiceUrl; | |||
if (null == validator) { | |||
throw new IllegalArgumentException("TSP validator required"); | |||
} | |||
this.validator = validator; | |||
this.requestPolicy = requestPolicy; | |||
if (null != userAgent) { | |||
this.userAgent = userAgent; | |||
} else { | |||
this.userAgent = DEFAULT_USER_AGENT; | |||
} | |||
setDigestAlgo(HashAlgorithm.sha1); | |||
} | |||
/** | |||
* Sets the request policy OID. | |||
* | |||
* @param policyOid | |||
*/ | |||
public void setRequestPolicy(String policyOid) { | |||
this.requestPolicy = policyOid; | |||
} | |||
/** | |||
* Sets the credentials used in case the TSP service requires | |||
* authentication. | |||
* | |||
* @param username | |||
* @param password | |||
*/ | |||
public void setAuthenticationCredentials(String username, String password) { | |||
this.username = username; | |||
this.password = password; | |||
} | |||
/** | |||
* Resets the authentication credentials. | |||
*/ | |||
public void resetAuthenticationCredentials() { | |||
this.username = null; | |||
this.password = null; | |||
} | |||
private SignatureConfig signatureConfig; | |||
/** | |||
* Sets the digest algorithm used for time-stamping data. Example value: | |||
* "SHA-1". | |||
* | |||
* @param digestAlgo | |||
* Maps the digest algorithm to corresponding OID value. | |||
*/ | |||
public void setDigestAlgo(HashAlgorithm digestAlgo) { | |||
public ASN1ObjectIdentifier mapDigestAlgoToOID(HashAlgorithm digestAlgo) { | |||
switch (digestAlgo) { | |||
case sha1: | |||
digestAlgoOid = "1.3.14.3.2.26"; | |||
break; | |||
case sha256: | |||
digestAlgoOid = "2.16.840.1.101.3.4.2.1"; | |||
break; | |||
case sha384: | |||
digestAlgoOid = "2.16.840.1.101.3.4.2.2"; | |||
break; | |||
case sha512: | |||
digestAlgoOid = "2.16.840.1.101.3.4.2.3"; | |||
break; | |||
case sha1: return X509ObjectIdentifiers.id_SHA1; | |||
case sha256: return NISTObjectIdentifiers.id_sha256; | |||
case sha384: return NISTObjectIdentifiers.id_sha384; | |||
case sha512: return NISTObjectIdentifiers.id_sha512; | |||
default: | |||
throw new IllegalArgumentException("unsupported digest algo: " + digestAlgo); | |||
} | |||
this.digestAlgo = digestAlgo; | |||
} | |||
/** | |||
* Configures the HTTP proxy settings to be used to connect to the TSP | |||
* service. | |||
* | |||
* @param proxyHost | |||
* @param proxyPort | |||
*/ | |||
public void setProxy(String proxyHost, int proxyPort) { | |||
this.proxyHost = proxyHost; | |||
this.proxyPort = proxyPort; | |||
} | |||
/** | |||
* Resets the HTTP proxy settings. | |||
*/ | |||
public void resetProxy() { | |||
this.proxyHost = null; | |||
this.proxyPort = 0; | |||
} | |||
@SuppressWarnings("unchecked") | |||
public byte[] timeStamp(byte[] data, RevocationData revocationData) | |||
throws Exception { | |||
// digest the message | |||
MessageDigest messageDigest = CryptoFunctions.getMessageDigest(this.digestAlgo); | |||
MessageDigest messageDigest = CryptoFunctions.getMessageDigest(signatureConfig.getTspDigestAlgo()); | |||
byte[] digest = messageDigest.digest(data); | |||
// generate the TSP request | |||
BigInteger nonce = new BigInteger(128, new SecureRandom()); | |||
TimeStampRequestGenerator requestGenerator = new TimeStampRequestGenerator(); | |||
requestGenerator.setCertReq(true); | |||
if (null != this.requestPolicy) { | |||
requestGenerator.setReqPolicy(this.requestPolicy); | |||
String requestPolicy = signatureConfig.getTspRequestPolicy(); | |||
if (requestPolicy != null) { | |||
requestGenerator.setReqPolicy(new ASN1ObjectIdentifier(requestPolicy)); | |||
} | |||
TimeStampRequest request = requestGenerator.generate(this.digestAlgoOid, digest, nonce); | |||
ASN1ObjectIdentifier digestAlgoOid = mapDigestAlgoToOID(signatureConfig.getTspDigestAlgo()); | |||
TimeStampRequest request = requestGenerator.generate(digestAlgoOid, digest, nonce); | |||
byte[] encodedRequest = request.getEncoded(); | |||
// create the HTTP POST request | |||
Proxy proxy = (this.proxyHost != null) | |||
? new Proxy(Proxy.Type.HTTP, new InetSocketAddress(this.proxyHost, this.proxyPort)) | |||
: Proxy.NO_PROXY; | |||
HttpURLConnection huc = (HttpURLConnection)new URL(this.tspServiceUrl).openConnection(proxy); | |||
Proxy proxy = Proxy.NO_PROXY; | |||
if (signatureConfig.getProxyUrl() != null) { | |||
URL proxyUrl = new URL(signatureConfig.getProxyUrl()); | |||
String host = proxyUrl.getHost(); | |||
int port = proxyUrl.getPort(); | |||
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, (port == -1 ? 80 : port))); | |||
} | |||
HttpURLConnection huc = (HttpURLConnection)new URL(signatureConfig.getTspUrl()).openConnection(proxy); | |||
if (null != this.username) { | |||
String userPassword = this.username + ":" + this.password; | |||
if (signatureConfig.getTspUser() != null) { | |||
String userPassword = signatureConfig.getTspUser() + ":" + signatureConfig.getTspPass(); | |||
String encoding = DatatypeConverter.printBase64Binary(userPassword.getBytes(Charset.forName("iso-8859-1"))); | |||
huc.setRequestProperty("Authorization", "Basic " + encoding); | |||
} | |||
huc.setDoOutput(true); // also sets method to POST. | |||
huc.setRequestProperty("User-Agent", this.userAgent); | |||
huc.setRequestProperty("Content-Type", requestContentType); | |||
huc.setRequestProperty("User-Agent", signatureConfig.getUserAgent()); | |||
huc.setRequestProperty("Content-Type", signatureConfig.isTspOldProtocol() | |||
? "application/timestamp-request" | |||
: "application/timestamp-query;charset=ISO-8859-1"); | |||
OutputStream hucOut = huc.getOutputStream(); | |||
hucOut.write(encodedRequest); | |||
@@ -263,8 +145,8 @@ public class TSPTimeStampService implements TimeStampService { | |||
int statusCode = huc.getResponseCode(); | |||
if (statusCode != 200) { | |||
LOG.log(POILogger.ERROR, "Error contacting TSP server ", this.tspServiceUrl); | |||
throw new Exception("Error contacting TSP server " + this.tspServiceUrl); | |||
LOG.log(POILogger.ERROR, "Error contacting TSP server ", signatureConfig.getTspUrl()); | |||
throw new IOException("Error contacting TSP server " + signatureConfig.getTspUrl()); | |||
} | |||
// HTTP input validation | |||
@@ -277,7 +159,10 @@ public class TSPTimeStampService implements TimeStampService { | |||
IOUtils.copy(huc.getInputStream(), bos); | |||
LOG.log(POILogger.DEBUG, "response content: ", bos.toString()); | |||
if (!contentType.startsWith(responseContentType)) { | |||
if (!contentType.startsWith(signatureConfig.isTspOldProtocol() | |||
? "application/timestamp-response" | |||
: "application/timestamp-reply" | |||
)) { | |||
throw new RuntimeException("invalid Content-Type: " + contentType); | |||
} | |||
@@ -311,7 +196,6 @@ public class TSPTimeStampService implements TimeStampService { | |||
// TSP signer certificates retrieval | |||
Collection<X509CertificateHolder> certificates = timeStampToken.getCertificates().getMatches(null); | |||
JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils(); | |||
X509CertificateHolder signerCert = null; | |||
Map<X500Name, X509CertificateHolder> certificateMap = new HashMap<X500Name, X509CertificateHolder>(); | |||
@@ -324,9 +208,8 @@ public class TSPTimeStampService implements TimeStampService { | |||
} | |||
// TSP signer cert path building | |||
if (null == signerCert) { | |||
throw new RuntimeException( | |||
"TSP response token has no signer certificate"); | |||
if (signerCert == null) { | |||
throw new RuntimeException("TSP response token has no signer certificate"); | |||
} | |||
List<X509Certificate> tspCertificateChain = new ArrayList<X509Certificate>(); | |||
JcaX509CertificateConverter x509converter = new JcaX509CertificateConverter(); | |||
@@ -353,7 +236,9 @@ public class TSPTimeStampService implements TimeStampService { | |||
timeStampToken.validate(verifier); | |||
// verify TSP signer certificate | |||
this.validator.validate(tspCertificateChain, revocationData); | |||
if (signatureConfig.getTspValidator() != null) { | |||
signatureConfig.getTspValidator().validate(tspCertificateChain, revocationData); | |||
} | |||
LOG.log(POILogger.DEBUG, "time-stamp token time: " | |||
+ timeStampToken.getTimeStampInfo().getGenTime()); | |||
@@ -362,19 +247,7 @@ public class TSPTimeStampService implements TimeStampService { | |||
return timestamp; | |||
} | |||
/** | |||
* usually the request content type is "application/timestamp-query;charset=ISO-8859-1", | |||
* but some timestamp server use a different content type | |||
*/ | |||
public void setRequestContentType(String requestContentType) { | |||
this.requestContentType = requestContentType; | |||
} | |||
/** | |||
* usually the response content type is "application/timestamp-reply", | |||
* but some timestamp server use a different content type | |||
*/ | |||
public void setResponseContentType(String responseContentType) { | |||
this.responseContentType = responseContentType; | |||
public void setSignatureConfig(SignatureConfig signatureConfig) { | |||
this.signatureConfig = signatureConfig; | |||
} | |||
} |
@@ -24,6 +24,8 @@ | |||
package org.apache.poi.poifs.crypt.dsig.services; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig.SignatureConfigurable; | |||
/** | |||
* Interface for a time-stamp service. | |||
@@ -31,7 +33,7 @@ package org.apache.poi.poifs.crypt.dsig.services; | |||
* @author Frank Cornelis | |||
* | |||
*/ | |||
public interface TimeStampService { | |||
public interface TimeStampService extends SignatureConfigurable { | |||
/** | |||
* Gives back the encoded time-stamp token for the given array of data |
@@ -56,15 +56,14 @@ import javax.xml.crypto.dsig.dom.DOMValidateContext; | |||
import org.apache.poi.POIDataSamples; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.openxml4j.opc.PackageAccess; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureConfig; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfo; | |||
import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig; | |||
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.XAdESSignatureFacet; | |||
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.RevocationDataService; | |||
import org.apache.poi.poifs.crypt.dsig.services.TSPTimeStampService; | |||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService; | |||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampServiceValidator; | |||
import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; | |||
@@ -107,7 +106,7 @@ public class TestSignatureInfo { | |||
cal.setTimeZone(TimeZone.getTimeZone("UTC")); | |||
cal.set(2014, 7, 6, 21, 42, 12); | |||
} | |||
@Test | |||
public void getSignerUnsigned() throws Exception { | |||
String testFiles[] = { | |||
@@ -119,7 +118,7 @@ public class TestSignatureInfo { | |||
for (String testFile : testFiles) { | |||
OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ); | |||
SignatureInfoConfig sic = new SignatureInfoConfig(); | |||
SignatureConfig sic = new SignatureConfig(); | |||
sic.setOpcPackage(pkg); | |||
SignatureInfo si = new SignatureInfo(); | |||
si.setSignatureConfig(sic); | |||
@@ -148,7 +147,7 @@ public class TestSignatureInfo { | |||
for (String testFile : testFiles) { | |||
OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ); | |||
SignatureInfoConfig sic = new SignatureInfoConfig(); | |||
SignatureConfig sic = new SignatureConfig(); | |||
sic.setOpcPackage(pkg); | |||
SignatureInfo si = new SignatureInfo(); | |||
si.setSignatureConfig(sic); | |||
@@ -169,7 +168,7 @@ public class TestSignatureInfo { | |||
public void getMultiSigners() throws Exception { | |||
String testFile = "hello-world-signed-twice.docx"; | |||
OPCPackage pkg = OPCPackage.open(testdata.getFile(testFile), PackageAccess.READ); | |||
SignatureInfoConfig sic = new SignatureInfoConfig(); | |||
SignatureConfig sic = new SignatureConfig(); | |||
sic.setOpcPackage(pkg); | |||
SignatureInfo si = new SignatureInfo(); | |||
si.setSignatureConfig(sic); | |||
@@ -200,11 +199,10 @@ public class TestSignatureInfo { | |||
initKeyPair("Test", "CN=Test"); | |||
String testFile = "hello-world-unsigned.xlsx"; | |||
OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE); | |||
SignatureInfoConfig sic = new SignatureInfoConfig(); | |||
SignatureConfig sic = new SignatureConfig(); | |||
sic.setOpcPackage(pkg); | |||
sic.setKey(keyPair.getPrivate()); | |||
sic.setSigningCertificateChain(Collections.singletonList(x509)); | |||
sic.addDefaultFacets(); | |||
SignatureInfo si = new SignatureInfo(); | |||
si.setSignatureConfig(sic); | |||
// hash > sha1 doesn't work in excel viewer ... | |||
@@ -224,7 +222,7 @@ public class TestSignatureInfo { | |||
final X509CRL crl = PkiTestUtils.generateCrl(x509, keyPair.getPrivate()); | |||
// setup | |||
SignatureInfoConfig signatureConfig = new SignatureInfoConfig(); | |||
SignatureConfig signatureConfig = new SignatureConfig(); | |||
signatureConfig.setOpcPackage(pkg); | |||
signatureConfig.setKey(keyPair.getPrivate()); | |||
@@ -237,23 +235,26 @@ public class TestSignatureInfo { | |||
certificateChain.add(x509); | |||
signatureConfig.setSigningCertificateChain(certificateChain); | |||
signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet(signatureConfig)); | |||
signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet(true, false, false)); | |||
signatureConfig.addSignatureFacet(new XAdESSignatureFacet(signatureConfig)); | |||
signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet()); | |||
signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet()); | |||
signatureConfig.addSignatureFacet(new XAdESSignatureFacet()); | |||
signatureConfig.addSignatureFacet(new XAdESXLSignatureFacet()); | |||
boolean mockTsp = false; | |||
// http://timestamping.edelweb.fr/service/tsp | |||
// http://tsa.belgium.be/connect | |||
String tspServiceUrl = "http://timestamping.edelweb.fr/service/tsp"; | |||
signatureConfig.setTspUrl("http://timestamping.edelweb.fr/service/tsp"); | |||
signatureConfig.setTspOldProtocol(true); | |||
TimeStampService timeStampService; | |||
if (tspServiceUrl == null) { | |||
timeStampService = new TimeStampService(){ | |||
if (mockTsp) { | |||
TimeStampService tspService = new TimeStampService(){ | |||
public byte[] timeStamp(byte[] data, RevocationData revocationData) throws Exception { | |||
revocationData.addCRL(crl); | |||
return "time-stamp-token".getBytes(); | |||
} | |||
public void setSignatureConfig(SignatureConfig config) {} | |||
}; | |||
signatureConfig.setTspService(tspService); | |||
} else { | |||
TimeStampServiceValidator tspValidator = new TimeStampServiceValidator() { | |||
@Override | |||
@@ -265,13 +266,8 @@ public class TestSignatureInfo { | |||
} | |||
} | |||
}; | |||
TSPTimeStampService tspService = new TSPTimeStampService(tspServiceUrl, tspValidator); | |||
if (tspServiceUrl.contains("edelweb")) { | |||
tspService.setRequestContentType("application/timestamp-request"); | |||
tspService.setResponseContentType("application/timestamp-response"); | |||
} | |||
timeStampService = tspService; | |||
signatureConfig.setTspValidator(tspValidator); | |||
signatureConfig.setTspOldProtocol(signatureConfig.getTspUrl().contains("edelweb")); | |||
} | |||
final RevocationData revocationData = new RevocationData(); | |||
@@ -285,9 +281,8 @@ public class TestSignatureInfo { | |||
return revocationData; | |||
} | |||
}; | |||
signatureConfig.setRevocationDataService(revocationDataService); | |||
XAdESXLSignatureFacet xadesXLSignatureFacet = new XAdESXLSignatureFacet( | |||
timeStampService, revocationDataService); | |||
SignatureInfo si = new SignatureInfo(); | |||
si.setSignatureConfig(signatureConfig); | |||
@@ -348,13 +343,12 @@ public class TestSignatureInfo { | |||
private OPCPackage sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception { | |||
initKeyPair(alias, signerDn); | |||
SignatureInfoConfig signatureConfig = new SignatureInfoConfig(); | |||
SignatureConfig signatureConfig = new SignatureConfig(); | |||
signatureConfig.setKey(keyPair.getPrivate()); | |||
signatureConfig.setSigningCertificateChain(Collections.singletonList(x509)); | |||
signatureConfig.setExecutionTime(cal.getTime()); | |||
signatureConfig.setDigestAlgo(HashAlgorithm.sha1); | |||
signatureConfig.setOpcPackage(pkgCopy); | |||
signatureConfig.addDefaultFacets(); | |||
SignatureInfo si = new SignatureInfo(); | |||
si.setSignatureConfig(signatureConfig); |