diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java index 53b2d9fe3..e5700e079 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/OOXMLURIDereferencer.java @@ -37,7 +37,6 @@ import javax.xml.crypto.XMLCryptoContext; import javax.xml.crypto.dsig.XMLSignatureFactory; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackagingURIHelper; @@ -51,18 +50,17 @@ public class OOXMLURIDereferencer implements URIDereferencer { private static final POILogger LOG = POILogFactory.getLogger(OOXMLURIDereferencer.class); - private final OPCPackage pkg; + private SignatureInfoConfig signatureConfig; + private URIDereferencer baseUriDereferencer; - private final URIDereferencer baseUriDereferencer; - - public OOXMLURIDereferencer(OPCPackage pkg) { - if (null == pkg) { - throw new IllegalArgumentException("OPCPackage is null"); - } - this.pkg = pkg; + public OOXMLURIDereferencer() { XMLSignatureFactory xmlSignatureFactory = SignatureInfo.getSignatureFactory(); this.baseUriDereferencer = xmlSignatureFactory.getURIDereferencer(); } + + public void setSignatureConfig(SignatureInfoConfig signatureConfig) { + this.signatureConfig = signatureConfig; + } public Data dereference(URIReference uriReference, XMLCryptoContext context) throws URIReferenceException { if (null == uriReference) { @@ -109,6 +107,6 @@ public class OOXMLURIDereferencer implements URIDereferencer { return null; } - return pkg.getPart(ppn); + return signatureConfig.getOpcPackage().getPart(ppn); } } diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java index d5dc363e7..963d023c4 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java @@ -32,7 +32,6 @@ import java.security.Provider; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.List; import javax.crypto.Cipher; @@ -125,19 +124,24 @@ public class SignatureInfo { public void confirmSignature(PrivateKey key, X509Certificate x509, HashAlgorithm hashAlgo) throws NoSuchAlgorithmException, IOException, MarshalException, ParserConfigurationException, XmlException { - XmlSignatureService signatureService = createSignatureService(hashAlgo, pkg); + SignatureInfoConfig signatureConfig = new SignatureInfoConfig(); + signatureConfig.setOpcPackage(pkg); + signatureConfig.setDigestAlgo(hashAlgo); + signatureConfig.setSigningCertificateChain(Collections.singletonList(x509)); + signatureConfig.setKey(key); + signatureConfig.addDefaultFacets(); + XmlSignatureService signatureService = new XmlSignatureService(signatureConfig); Document document = DocumentHelper.createDocument(); // operate - List x509Chain = Collections.singletonList(x509); - DigestInfo digestInfo = signatureService.preSign(document, null, key, x509Chain, null, null, null); + DigestInfo digestInfo = signatureService.preSign(document, null); // setup: key material, signature value byte[] signatureValue = signDigest(key, hashAlgo, digestInfo.digestValue); // operate: postSign - signatureService.postSign(document, signatureValue, Collections.singletonList(x509)); + signatureService.postSign(document, signatureValue); } public static byte[] signDigest(PrivateKey key, HashAlgorithm hashAlgo, byte digest[]) { @@ -156,12 +160,6 @@ public class SignatureInfo { } } - public XmlSignatureService createSignatureService(HashAlgorithm hashAlgo, OPCPackage pkg) { - XmlSignatureService signatureService = new XmlSignatureService(hashAlgo, pkg); - signatureService.initFacets(new Date()); - return signatureService; - } - public List getSigners() { initXmlProvider(); List signers = new ArrayList(); @@ -176,19 +174,20 @@ public class SignatureInfo { LOG.log(POILogger.DEBUG, "no signature resources"); allValid = false; } + + SignatureInfoConfig signatureConfig = new SignatureInfoConfig(); + signatureConfig.setOpcPackage(pkg); for (PackagePart signaturePart : signatureParts) { KeyInfoKeySelector keySelector = new KeyInfoKeySelector(); try { Document doc = DocumentHelper.readDocument(signaturePart.getInputStream()); - // dummy call to createSignatureService to tweak document afterwards - createSignatureService(HashAlgorithm.sha1, pkg).registerIds(doc); + XmlSignatureService.registerIds(doc); DOMValidateContext domValidateContext = new DOMValidateContext(keySelector, doc); domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", Boolean.TRUE); - OOXMLURIDereferencer dereferencer = new OOXMLURIDereferencer(pkg); - domValidateContext.setURIDereferencer(dereferencer); + domValidateContext.setURIDereferencer(signatureConfig.getUriDereferencer()); XMLSignatureFactory xmlSignatureFactory = getSignatureFactory(); XMLSignature xmlSignature = xmlSignatureFactory.unmarshalXMLSignature(domValidateContext); diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfoConfig.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfoConfig.java new file mode 100644 index 000000000..9468720bf --- /dev/null +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfoConfig.java @@ -0,0 +1,163 @@ +/* ==================================================================== + 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 javax.xml.crypto.URIDereferencer; + +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.SignaturePolicyService; +import org.apache.poi.poifs.crypt.dsig.facets.XAdESSignatureFacet; +import org.apache.poi.poifs.crypt.dsig.spi.AddressDTO; +import org.apache.poi.poifs.crypt.dsig.spi.IdentityDTO; + +public class SignatureInfoConfig { + + private List signatureFacets = new ArrayList(); + private HashAlgorithm digestAlgo = HashAlgorithm.sha1; + private Date executionTime = new Date(); + private OPCPackage opcPackage; + private PrivateKey key; + private List signingCertificateChain; + private IdentityDTO identity; + private AddressDTO address; + private byte[] photo; + private SignaturePolicyService signaturePolicyService; + private URIDereferencer uriDereferencer; + + 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 getSignatureFacets() { + return signatureFacets; + } + public void setSignatureFacets(List 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 getSigningCertificateChain() { + return signingCertificateChain; + } + public void setSigningCertificateChain( + List 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; + } + + +} diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java index 751328f3d..fbaf0e53f 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java @@ -37,7 +37,6 @@ import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -68,10 +67,9 @@ 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.HashAlgorithm; +import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig; import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService; import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService.RelationshipTransformParameterSpec; -import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; import org.apache.xmlbeans.XmlException; @@ -96,19 +94,13 @@ 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 XmlSignatureService signatureService; - - private final Date clock; - - private final HashAlgorithm hashAlgo; + private final SignatureInfoConfig signatureConfig; /** * Main constructor. */ - public OOXMLSignatureFacet(XmlSignatureService signatureService, Date clock, HashAlgorithm hashAlgo) { - this.signatureService = signatureService; - this.clock = (clock == null ? new Date() : clock); - this.hashAlgo = (hashAlgo == null ? HashAlgorithm.sha1 : hashAlgo); + public OOXMLSignatureFacet(SignatureInfoConfig signatureConfig) { + this.signatureConfig = signatureConfig; } @Override @@ -142,7 +134,7 @@ public class OOXMLSignatureFacet implements SignatureFacet { XMLObject xo = signatureFactory.newXMLObject(objectContent, objectId, null, null); objects.add(xo); - DigestMethod digestMethod = signatureFactory.newDigestMethod(this.hashAlgo.xmlSignUri, null); + DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null); Reference reference = signatureFactory.newReference ("#" + objectId, digestMethod, null, XmlDSigNS+"Object", null); references.add(reference); @@ -152,11 +144,11 @@ public class OOXMLSignatureFacet implements SignatureFacet { throws IOException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, URISyntaxException, XmlException { - OPCPackage ooxml = this.signatureService.getOfficeOpenXMLDocument(); + OPCPackage ooxml = this.signatureConfig.getOpcPackage(); List relsEntryNames = ooxml.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART); - DigestMethod digestMethod = signatureFactory.newDigestMethod(this.hashAlgo.xmlSignUri, null); + DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null); Set digestedPartNames = new HashSet(); for (PackagePart pp : relsEntryNames) { String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1"); @@ -240,7 +232,7 @@ public class OOXMLSignatureFacet implements SignatureFacet { */ DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); fmt.setTimeZone(TimeZone.getTimeZone("UTC")); - String nowStr = fmt.format(this.clock); + String nowStr = fmt.format(this.signatureConfig.getExecutionTime()); LOG.log(POILogger.DEBUG, "now: " + nowStr); SignatureTimeDocument sigTime = SignatureTimeDocument.Factory.newInstance(); @@ -261,7 +253,7 @@ public class OOXMLSignatureFacet implements SignatureFacet { signaturePropertyContent.add(signatureTimeSignatureProperty); SignatureProperties signatureProperties = signatureFactory .newSignatureProperties(signaturePropertyContent, - "id-signature-time-" + this.clock.getTime()); + "id-signature-time-" + signatureConfig.getExecutionTime()); objectContent.add(signatureProperties); } @@ -274,7 +266,7 @@ public class OOXMLSignatureFacet implements SignatureFacet { SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance(); CTSignatureInfoV1 ctSigV1 = sigV1.addNewSignatureInfoV1(); - ctSigV1.setManifestHashAlgorithm(hashAlgo.xmlSignUri); + ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestAlgo().xmlSignUri); Element n = (Element)document.importNode(ctSigV1.getDomNode(), true); n.setAttributeNS(XmlNS, "xmlns", "http://schemas.microsoft.com/office/2006/digsig"); @@ -293,7 +285,7 @@ public class OOXMLSignatureFacet implements SignatureFacet { String objectId = "idOfficeObject"; objects.add(signatureFactory.newXMLObject(objectContent, objectId, null, null)); - DigestMethod digestMethod = signatureFactory.newDigestMethod(this.hashAlgo.xmlSignUri, null); + DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null); Reference reference = signatureFactory.newReference ("#" + objectId, digestMethod, null, XmlDSigNS+"Object", null); references.add(reference); diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java index a85ed33cb..a93f199e7 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java @@ -34,7 +34,6 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Calendar; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -53,6 +52,7 @@ 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.SignatureInfo; +import org.apache.poi.poifs.crypt.dsig.SignatureInfoConfig; import org.apache.poi.poifs.crypt.dsig.services.XmlSignatureService; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -97,12 +97,8 @@ public class XAdESSignatureFacet implements SignatureFacet { private static final String XADES_TYPE = "http://uri.etsi.org/01903#SignedProperties"; - private final Date clock; - - private final HashAlgorithm hashAlgo; - - private final SignaturePolicyService signaturePolicyService; - + private SignatureInfoConfig signatureConfig; + private String idSignedProperties; private boolean signaturePolicyImplied; @@ -111,7 +107,7 @@ public class XAdESSignatureFacet implements SignatureFacet { private boolean issuerNameNoReverseOrder = false; - private Map dataObjectFormatMimeTypes; + private Map dataObjectFormatMimeTypes = new HashMap(); /** * Main constructor. @@ -126,12 +122,8 @@ public class XAdESSignatureFacet implements SignatureFacet { * @param signaturePolicyService * the optional signature policy service used for XAdES-EPES. */ - public XAdESSignatureFacet(Date clock, HashAlgorithm hashAlgo, - SignaturePolicyService signaturePolicyService) { - this.clock = (clock == null ? new Date() : clock); - this.hashAlgo = (hashAlgo == null ? HashAlgorithm.sha1 : hashAlgo); - this.signaturePolicyService = signaturePolicyService; - this.dataObjectFormatMimeTypes = new HashMap(); + public XAdESSignatureFacet(SignatureInfoConfig signatureConfig) { + this.signatureConfig = signatureConfig; } @Override @@ -167,7 +159,7 @@ public class XAdESSignatureFacet implements SignatureFacet { // SigningTime Calendar xmlGregorianCalendar = Calendar.getInstance(); xmlGregorianCalendar.setTimeZone(TimeZone.getTimeZone("Z")); - xmlGregorianCalendar.setTime(this.clock); + xmlGregorianCalendar.setTime(this.signatureConfig.getExecutionTime()); xmlGregorianCalendar.clear(Calendar.MILLISECOND); signedSignatureProperties.setSigningTime(xmlGregorianCalendar); @@ -179,7 +171,7 @@ public class XAdESSignatureFacet implements SignatureFacet { CertIDListType signingCertificates = signedSignatureProperties.addNewSigningCertificate(); CertIDType certId = signingCertificates.addNewCert(); X509Certificate signingCertificate = signingCertificateChain.get(0); - setCertID(certId, signingCertificate, this.hashAlgo, this.issuerNameNoReverseOrder); + setCertID(certId, signingCertificate, this.signatureConfig.getDigestAlgo(), this.issuerNameNoReverseOrder); // ClaimedRole if (null != this.role && false == this.role.isEmpty()) { @@ -193,24 +185,24 @@ public class XAdESSignatureFacet implements SignatureFacet { } // XAdES-EPES - if (null != this.signaturePolicyService) { + SignaturePolicyService policyService = this.signatureConfig.getSignaturePolicyService(); + if (policyService != null) { SignaturePolicyIdentifierType signaturePolicyIdentifier = signedSignatureProperties.addNewSignaturePolicyIdentifier(); SignaturePolicyIdType signaturePolicyId = signaturePolicyIdentifier.addNewSignaturePolicyId(); ObjectIdentifierType objectIdentifier = signaturePolicyId.addNewSigPolicyId(); - objectIdentifier.setDescription(this.signaturePolicyService.getSignaturePolicyDescription()); + objectIdentifier.setDescription(policyService.getSignaturePolicyDescription()); IdentifierType identifier = objectIdentifier.addNewIdentifier(); - identifier.setStringValue(this.signaturePolicyService.getSignaturePolicyIdentifier()); + identifier.setStringValue(policyService.getSignaturePolicyIdentifier()); - byte[] signaturePolicyDocumentData = this.signaturePolicyService.getSignaturePolicyDocument(); + byte[] signaturePolicyDocumentData = policyService.getSignaturePolicyDocument(); DigestAlgAndValueType sigPolicyHash = signaturePolicyId.addNewSigPolicyHash(); - setDigestAlgAndValue(sigPolicyHash, signaturePolicyDocumentData, this.hashAlgo); + setDigestAlgAndValue(sigPolicyHash, signaturePolicyDocumentData, this.signatureConfig.getDigestAlgo()); - String signaturePolicyDownloadUrl = this.signaturePolicyService - .getSignaturePolicyDownloadUrl(); + String signaturePolicyDownloadUrl = policyService.getSignaturePolicyDownloadUrl(); if (null != signaturePolicyDownloadUrl) { SigPolicyQualifiersListType sigPolicyQualifiers = signaturePolicyId.addNewSigPolicyQualifiers(); AnyType sigPolicyQualifier = sigPolicyQualifiers.addNewSigPolicyQualifier(); @@ -254,7 +246,7 @@ public class XAdESSignatureFacet implements SignatureFacet { objects.add(xadesObject); // add XAdES ds:Reference - DigestMethod digestMethod = signatureFactory.newDigestMethod(hashAlgo.xmlSignUri, null); + DigestMethod digestMethod = signatureFactory.newDigestMethod(this.signatureConfig.getDigestAlgo().xmlSignUri, null); List transforms = new ArrayList(); Transform exclusiveTransform = signatureFactory .newTransform(CanonicalizationMethod.INCLUSIVE, diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/SignatureService.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/SignatureService.java index e35c0d0de..addeff930 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/SignatureService.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/SignatureService.java @@ -26,16 +26,12 @@ package org.apache.poi.poifs.crypt.dsig.services; import java.io.IOException; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; import java.util.List; import javax.xml.crypto.MarshalException; import javax.xml.parsers.ParserConfigurationException; -import org.apache.poi.poifs.crypt.dsig.spi.AddressDTO; import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; -import org.apache.poi.poifs.crypt.dsig.spi.IdentityDTO; import org.apache.xmlbeans.XmlException; import org.w3c.dom.Document; @@ -47,45 +43,17 @@ import org.w3c.dom.Document; */ public interface SignatureService { - /** - * Gives back the digest algorithm to be used for construction of the digest - * infos of the preSign method. Return a digest algorithm here if you want - * to let the client sign some locally stored files. Return - * null if no pre-sign digest infos are required. - * - * @return the digest algorithm to be used when digesting local files. - * @see #preSign(List, List) - */ - String getFilesDigestAlgorithm(); - /** * Pre-sign callback method. Depending on the configuration some parameters * are passed. The returned value will be signed by the eID Applet. * - *

- * TODO: service must be able to throw some exception on failure. - *

- * * @param digestInfos * the optional list of digest infos. - * @param signingCertificateChain - * the optional list of certificates. - * @param identity - * the optional identity. - * @param address - * the optional identity address. - * @param photo - * the optional identity photo. - * @param timestamp - * the optional timestamp, defaults to now * @return the digest to be signed. * @throws NoSuchAlgorithmException */ - DigestInfo preSign(Document document, List digestInfos, - PrivateKey privateKey, - List signingCertificateChain, - IdentityDTO identity, AddressDTO address, byte[] photo) - throws NoSuchAlgorithmException; + DigestInfo preSign(Document document, List digestInfos) + throws NoSuchAlgorithmException; /** * Post-sign callback method. Received the signature value. Depending on the @@ -95,7 +63,6 @@ public interface SignatureService { * @param signingCertificateChain * the optional chain of signing certificates. */ - void postSign(Document document, byte[] signatureValue, - List signingCertificateChain) - throws IOException, MarshalException, ParserConfigurationException, XmlException; + void postSign(Document document, byte[] signatureValue) + throws IOException, MarshalException, ParserConfigurationException, XmlException; } diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java index c034a5dca..0501c4775 100644 --- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java +++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/services/XmlSignatureService.java @@ -37,11 +37,8 @@ import java.security.InvalidAlgorithmParameterException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -79,16 +76,10 @@ import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.poifs.crypt.HashAlgorithm; -import org.apache.poi.poifs.crypt.dsig.OOXMLURIDereferencer; import org.apache.poi.poifs.crypt.dsig.SignatureInfo; -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.SignatureInfoConfig; 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.spi.AddressDTO; import org.apache.poi.poifs.crypt.dsig.spi.DigestInfo; -import org.apache.poi.poifs.crypt.dsig.spi.IdentityDTO; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; import org.apache.xml.security.signature.XMLSignature; @@ -112,43 +103,23 @@ import org.xml.sax.SAXException; public class XmlSignatureService implements SignatureService { private static final POILogger LOG = POILogFactory.getLogger(XmlSignatureService.class); - protected final List signatureFacets; - + protected SignatureInfoConfig signatureConfig; + private String signatureNamespacePrefix; private String signatureId = "idPackageSignature"; - private final HashAlgorithm hashAlgo; - private final OPCPackage opcPackage; - // private SignatureDocument sigDoc; - private XAdESSignatureFacet xadesSignatureFacet; /** * Main constructor. */ - public XmlSignatureService(HashAlgorithm digestAlgo, OPCPackage opcPackage) { - this.signatureFacets = new ArrayList(); + public XmlSignatureService(SignatureInfoConfig signatureConfig) { this.signatureNamespacePrefix = null; - this.hashAlgo = digestAlgo; - this.opcPackage = opcPackage; - // this.sigDoc = null; - } - - public void initFacets(Date clock) { - if (clock == null) clock = new Date(); - addSignatureFacet(new OOXMLSignatureFacet(this, clock, hashAlgo)); - addSignatureFacet(new KeyInfoSignatureFacet(true, false, false)); - - this.xadesSignatureFacet = new XAdESSignatureFacet(clock, hashAlgo, null); - this.xadesSignatureFacet.setIdSignedProperties("idSignedProperties"); - this.xadesSignatureFacet.setSignaturePolicyImplied(true); - /* - * Work-around for Office 2010. - */ - this.xadesSignatureFacet.setIssuerNameNoReverseOrder(true); - addSignatureFacet(this.xadesSignatureFacet); - addSignatureFacet(new Office2010SignatureFacet()); + this.signatureConfig = signatureConfig; } - + public SignatureInfoConfig getSignatureConfig() { + return signatureConfig; + } + /** * Sets the signature Id attribute value used to create the XML signature. A * null value will trigger an automatically generated signature @@ -170,39 +141,6 @@ public class XmlSignatureService implements SignatureService { this.signatureNamespacePrefix = signatureNamespacePrefix; } - /** - * Adds a signature facet to this XML signature service. - * - * @param signatureFacet - */ - public void addSignatureFacet(SignatureFacet... signatureFacets) { - for (SignatureFacet sf : signatureFacets) { - this.signatureFacets.add(sf); - } - } - - /** - * Gives back the signature digest algorithm. Allowed values are SHA-1, - * SHA-256, SHA-384, SHA-512, RIPEND160. The default algorithm is SHA-1. - * Override this method to select another signature digest algorithm. - * - * @return - */ - protected HashAlgorithm getSignatureDigestAlgorithm() { - return null != this.hashAlgo ? this.hashAlgo : HashAlgorithm.sha1; - } - - /** - * Override this method to change the URI dereferener used by the signing - * engine. - * - * @return - */ - protected URIDereferencer getURIDereferencer() { - OPCPackage ooxmlDocument = getOfficeOpenXMLDocument(); - return new OOXMLURIDereferencer(ooxmlDocument); - } - /** * Gives back the human-readable description of what the citizen will be * signing. The default value is "XML Document". Override this method to @@ -214,17 +152,6 @@ public class XmlSignatureService implements SignatureService { return "Office OpenXML Document"; } - /** - * Gives back the URL of the OOXML to be signed. - * - * @return - */ - public OPCPackage getOfficeOpenXMLDocument() { - return opcPackage; - } - - - /** * Gives back the output stream to which to write the signed XML document. * @@ -232,19 +159,16 @@ public class XmlSignatureService implements SignatureService { */ // protected abstract OutputStream getSignedDocumentOutputStream(); @Override - public DigestInfo preSign(Document document, List digestInfos, - PrivateKey key, - List signingCertificateChain, - IdentityDTO identity, AddressDTO address, byte[] photo) + public DigestInfo preSign(Document document, List digestInfos) throws NoSuchAlgorithmException { SignatureInfo.initXmlProvider(); LOG.log(POILogger.DEBUG, "preSign"); - HashAlgorithm hashAlgo = getSignatureDigestAlgorithm(); + HashAlgorithm hashAlgo = this.signatureConfig.getDigestAlgo(); byte[] digestValue; try { - digestValue = getXmlSignatureDigestValue(document, hashAlgo, digestInfos, key, signingCertificateChain); + digestValue = getXmlSignatureDigestValue(document, digestInfos); } catch (Exception e) { throw new RuntimeException("XML signature error: " + e.getMessage(), e); } @@ -254,7 +178,7 @@ public class XmlSignatureService implements SignatureService { } @Override - public void postSign(Document document, byte[] signatureValue, List signingCertificateChain) + public void postSign(Document document, byte[] signatureValue) throws IOException, MarshalException, ParserConfigurationException, XmlException { LOG.log(POILogger.DEBUG, "postSign"); SignatureInfo.initXmlProvider(); @@ -278,8 +202,8 @@ public class XmlSignatureService implements SignatureService { /* * Allow signature facets to inject their own stuff. */ - for (SignatureFacet signatureFacet : this.signatureFacets) { - signatureFacet.postSign(document, signingCertificateChain); + for (SignatureFacet signatureFacet : this.signatureConfig.getSignatureFacets()) { + signatureFacet.postSign(document, this.signatureConfig.getSigningCertificateChain()); } registerIds(document); @@ -287,10 +211,7 @@ public class XmlSignatureService implements SignatureService { } @SuppressWarnings("unchecked") - private byte[] getXmlSignatureDigestValue(Document document, HashAlgorithm hashAlgo, - List digestInfos, - PrivateKey privateKey, - List signingCertificateChain) + private byte[] getXmlSignatureDigestValue(Document document, List digestInfos) throws ParserConfigurationException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, MarshalException, javax.xml.crypto.dsig.XMLSignatureException, @@ -321,8 +242,8 @@ public class XmlSignatureService implements SignatureService { /* * Signature context construction. */ - XMLSignContext xmlSignContext = new DOMSignContext(privateKey, document); - URIDereferencer uriDereferencer = getURIDereferencer(); + XMLSignContext xmlSignContext = new DOMSignContext(this.signatureConfig.getKey(), document); + URIDereferencer uriDereferencer = this.signatureConfig.getUriDereferencer(); if (null != uriDereferencer) { xmlSignContext.setURIDereferencer(uriDereferencer); } @@ -354,15 +275,15 @@ public class XmlSignatureService implements SignatureService { localSignatureId = "xmldsig-" + UUID.randomUUID().toString(); } List objects = new ArrayList(); - for (SignatureFacet signatureFacet : this.signatureFacets) { + for (SignatureFacet signatureFacet : this.signatureConfig.getSignatureFacets()) { LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName()); - signatureFacet.preSign(document, signatureFactory, localSignatureId, signingCertificateChain, references, objects); + signatureFacet.preSign(document, signatureFactory, localSignatureId, this.signatureConfig.getSigningCertificateChain(), references, objects); } /* * ds:SignedInfo */ - SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(getSignatureMethod(hashAlgo), null); + SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(getSignatureMethod(this.signatureConfig.getDigestAlgo()), null); CanonicalizationMethod canonicalizationMethod = signatureFactory .newCanonicalizationMethod(getCanonicalizationMethod(), (C14NMethodParameterSpec) null); @@ -432,7 +353,7 @@ public class XmlSignatureService implements SignatureService { * usage. */ - MessageDigest jcaMessageDigest = CryptoFunctions.getMessageDigest(hashAlgo); + MessageDigest jcaMessageDigest = CryptoFunctions.getMessageDigest(this.signatureConfig.getDigestAlgo()); byte[] digestValue = jcaMessageDigest.digest(octets); return digestValue; } @@ -443,7 +364,7 @@ public class XmlSignatureService implements SignatureService { * * @param doc */ - public void registerIds(Document doc) { + public static void registerIds(Document doc) { NodeList nl = doc.getElementsByTagNameNS(XmlDSigNS, "Object"); registerIdAttribute(nl); nl = doc.getElementsByTagNameNS("http://uri.etsi.org/01903/v1.3.2#", "SignedProperties"); @@ -492,19 +413,6 @@ public class XmlSignatureService implements SignatureService { throw new RuntimeException("unsupported sign algo: " + hashAlgo); } - /** - * Gives back the used XAdES signature facet. - * - * @return - */ - protected XAdESSignatureFacet getXAdESSignatureFacet() { - return this.xadesSignatureFacet; - } - - public String getFilesDigestAlgorithm() { - return null; - } - protected String getCanonicalizationMethod() { return CanonicalizationMethod.INCLUSIVE; } @@ -512,7 +420,7 @@ public class XmlSignatureService implements SignatureService { protected void writeDocument(Document document) throws IOException, XmlException { XmlOptions xo = new XmlOptions(); Map namespaceMap = new HashMap(); - for (SignatureFacet sf : this.signatureFacets) { + for (SignatureFacet sf : this.signatureConfig.getSignatureFacets()) { Map sfm = sf.getNamespacePrefixMapping(); if (sfm != null) { namespaceMap.putAll(sfm); @@ -527,7 +435,7 @@ public class XmlSignatureService implements SignatureService { * Copy the original OOXML content to the signed OOXML package. During * copying some files need to changed. */ - OPCPackage pkg = this.getOfficeOpenXMLDocument(); + OPCPackage pkg = this.signatureConfig.getOpcPackage(); PackagePartName sigPartName, sigsPartName; try { diff --git a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java index fe5e4d30c..4dfc0f46b 100644 --- a/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java +++ b/src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java @@ -52,15 +52,14 @@ import javax.xml.crypto.KeySelector; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMValidateContext; -import javax.xml.parsers.DocumentBuilderFactory; 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.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.SignaturePolicyService; 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; @@ -208,13 +207,26 @@ public class TestSignatureInfo { OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE); initKeyPair("Test", "CN=Test"); + final X509CRL crl = PkiTestUtils.generateCrl(x509, keyPair.getPrivate()); // setup - EnvelopedSignatureFacet envelopedSignatureFacet = new EnvelopedSignatureFacet(); - KeyInfoSignatureFacet keyInfoSignatureFacet = new KeyInfoSignatureFacet(true, false, false); - SignaturePolicyService signaturePolicyService = null; - XAdESSignatureFacet xadesSignatureFacet = new XAdESSignatureFacet(null, null, signaturePolicyService); - final X509CRL crl = PkiTestUtils.generateCrl(x509, keyPair.getPrivate()); + SignatureInfoConfig signatureConfig = new SignatureInfoConfig(); + signatureConfig.setOpcPackage(pkg); + signatureConfig.setKey(keyPair.getPrivate()); + + /* + * We need at least 2 certificates for the XAdES-C complete certificate + * refs construction. + */ + List certificateChain = new ArrayList(); + certificateChain.add(x509); + certificateChain.add(x509); + signatureConfig.setSigningCertificateChain(certificateChain); + + signatureConfig.addSignatureFacet(new EnvelopedSignatureFacet()); + signatureConfig.addSignatureFacet(new KeyInfoSignatureFacet(true, false, false)); + signatureConfig.addSignatureFacet(new XAdESSignatureFacet(signatureConfig)); + // http://timestamping.edelweb.fr/service/tsp // http://tsa.belgium.be/connect @@ -248,14 +260,6 @@ public class TestSignatureInfo { timeStampService = tspService; } - List certificateChain = new ArrayList(); - /* - * We need at least 2 certificates for the XAdES-C complete certificate - * refs construction. - */ - certificateChain.add(x509); - certificateChain.add(x509); - final RevocationData revocationData = new RevocationData(); revocationData.addCRL(crl); OCSPResp ocspResp = PkiTestUtils.createOcspResp(x509, false, @@ -270,17 +274,12 @@ public class TestSignatureInfo { XAdESXLSignatureFacet xadesXLSignatureFacet = new XAdESXLSignatureFacet( timeStampService, revocationDataService); - XmlSignatureService testedInstance = new XmlSignatureService(HashAlgorithm.sha1, pkg); - testedInstance.addSignatureFacet(envelopedSignatureFacet, keyInfoSignatureFacet, - xadesSignatureFacet, xadesXLSignatureFacet); + XmlSignatureService testedInstance = new XmlSignatureService(signatureConfig); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - Document document = dbf.newDocumentBuilder().newDocument(); + Document document = DocumentHelper.createDocument(); // operate - DigestInfo digestInfo = testedInstance.preSign(document, null, keyPair.getPrivate(), certificateChain, null, null, null); + DigestInfo digestInfo = testedInstance.preSign(document, null); // verify assertNotNull(digestInfo); @@ -301,7 +300,7 @@ public class TestSignatureInfo { byte[] signatureValue = SignatureInfo.signDigest(keyPair.getPrivate(), HashAlgorithm.sha1, digestInfo.digestValue); // Operate: postSign - testedInstance.postSign(document, signatureValue, certificateChain); + testedInstance.postSign(document, signatureValue); DOMValidateContext domValidateContext = new DOMValidateContext( KeySelector.singletonKeySelector(keyPair.getPublic()), @@ -332,15 +331,22 @@ public class TestSignatureInfo { } private OPCPackage sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception { - XmlSignatureService signatureService = new XmlSignatureService(HashAlgorithm.sha1, pkgCopy); - signatureService.initFacets(cal.getTime()); initKeyPair(alias, signerDn); + SignatureInfoConfig signatureConfig = new SignatureInfoConfig(); + signatureConfig.setKey(keyPair.getPrivate()); + signatureConfig.setSigningCertificateChain(Collections.singletonList(x509)); + signatureConfig.setExecutionTime(cal.getTime()); + signatureConfig.setDigestAlgo(HashAlgorithm.sha1); + signatureConfig.setOpcPackage(pkgCopy); + signatureConfig.addDefaultFacets(); + + XmlSignatureService signatureService = new XmlSignatureService(signatureConfig); + Document document = DocumentHelper.createDocument(); // operate - List x509Chain = Collections.singletonList(x509); - DigestInfo digestInfo = signatureService.preSign(document, null, keyPair.getPrivate(), x509Chain, null, null, null); + DigestInfo digestInfo = signatureService.preSign(document, null); // verify assertNotNull(digestInfo); @@ -354,7 +360,7 @@ public class TestSignatureInfo { byte[] signatureValue = SignatureInfo.signDigest(keyPair.getPrivate(), HashAlgorithm.sha1, digestInfo.digestValue); // operate: postSign - signatureService.postSign(document, signatureValue, Collections.singletonList(x509)); + signatureService.postSign(document, signatureValue); // verify: signature SignatureInfo si = new SignatureInfo(pkgCopy);