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:
parent
6639a1938e
commit
ff38e12652
@ -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;
|
||||
public void setSignatureConfig(SignatureConfig signatureConfig) {
|
||||
this.signatureConfig = signatureConfig;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user