centralized configs

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xml_signature@1626646 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2014-09-21 22:48:20 +00:00
parent 6639a1938e
commit ff38e12652
14 changed files with 600 additions and 620 deletions

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}
target.addEventListener("DOMSubtreeModified", creationListener, false);
}
}
}
};
et.addEventListener("DOMSubtreeModified", myModificationListener, false);
/*
* Signature context construction.

View File

@ -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();
}
}

View File

@ -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,9 +26,9 @@ 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;
}

View File

@ -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;
@ -67,24 +68,10 @@ public class KeyInfoSignatureFacet implements SignatureFacet {
private static final POILogger LOG = POILogFactory.getLogger(KeyInfoSignatureFacet.class);
private final boolean includeEntireCertificateChain;
SignatureConfig signatureConfig;
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);

View File

@ -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,12 +94,9 @@ 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;
}

View File

@ -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

View File

@ -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

View File

@ -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 String idSignedProperties;
private boolean signaturePolicyImplied;
private String role;
private boolean issuerNameNoReverseOrder = false;
private SignatureConfig signatureConfig;
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#");

View File

@ -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;
@ -118,15 +116,17 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
public static final String XADES141_NAMESPACE = "http://uri.etsi.org/01903/v1.4.1#";
private final TimeStampService timeStampService;
private SignatureConfig signatureConfig;
private String c14nAlgoId;
private final RevocationDataService revocationDataService;
private String c14nAlgoId = CanonicalizationMethod.EXCLUSIVE;
private final CertificateFactory certificateFactory;
private final HashAlgorithm hashAlgo;
public void setSignatureConfig(SignatureConfig signatureConfig) {
this.signatureConfig = signatureConfig;
}
/**
* Convenience constructor.
@ -134,36 +134,8 @@ public class XAdESXLSignatureFacet implements SignatureFacet {
* @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);
}
/**
* Main 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,20 +209,22 @@ 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);
int chainSize = signingCertificateChain.size();
if (chainSize > 1) {
for (X509Certificate cert : signingCertificateChain.subList(1, chainSize)) {
CertIDType certId = certIdList.addNewCert();
XAdESSignatureFacet.setCertID(certId, certificate, this.hashAlgo, false);
XAdESSignatureFacet.setCertID(certId, signatureConfig, false, cert);
}
}
// XAdES-C: complete revocation refs
CompleteRevocationRefsType completeRevocationRefs =
unsignedSigProps.addNewCompleteRevocationRefs();
RevocationData revocationData = this.revocationDataService
RevocationData revocationData = signatureConfig.getRevocationDataService()
.getRevocationData(signingCertificateChain);
if (revocationData.hasCRLs()) {
CRLRefsType crlRefs = completeRevocationRefs.addNewCRLRefs();
@ -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);

View File

@ -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);
}
private SignatureConfig signatureConfig;
/**
* 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.
* Maps the digest algorithm to corresponding OID 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;
}
/**
* Sets the digest algorithm used for time-stamping data. Example value:
* "SHA-1".
*
* @param digestAlgo
*/
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)));
}
if (null != this.username) {
String userPassword = this.username + ":" + this.password;
HttpURLConnection huc = (HttpURLConnection)new URL(signatureConfig.getTspUrl()).openConnection(proxy);
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;
}
}

View File

@ -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

View File

@ -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;
@ -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);