git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xml_signature@1625850 13f79535-47bb-0310-9956-ffa450edef68pull/11/head
@@ -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); | |||
} | |||
} |
@@ -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<X509Certificate> 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<X509Certificate> getSigners() { | |||
initXmlProvider(); | |||
List<X509Certificate> signers = new ArrayList<X509Certificate>(); | |||
@@ -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); |
@@ -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<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; | |||
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; | |||
} | |||
} |
@@ -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<PackagePart> relsEntryNames = ooxml.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART); | |||
DigestMethod digestMethod = signatureFactory.newDigestMethod(this.hashAlgo.xmlSignUri, null); | |||
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null); | |||
Set<String> digestedPartNames = new HashSet<String>(); | |||
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); |
@@ -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<String, String> dataObjectFormatMimeTypes; | |||
private Map<String, String> dataObjectFormatMimeTypes = new HashMap<String, String>(); | |||
/** | |||
* 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<String, String>(); | |||
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<Transform> transforms = new ArrayList<Transform>(); | |||
Transform exclusiveTransform = signatureFactory | |||
.newTransform(CanonicalizationMethod.INCLUSIVE, |
@@ -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 | |||
* <code>null</code> 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. | |||
* | |||
* <p> | |||
* TODO: service must be able to throw some exception on failure. | |||
* </p> | |||
* | |||
* @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<DigestInfo> digestInfos, | |||
PrivateKey privateKey, | |||
List<X509Certificate> signingCertificateChain, | |||
IdentityDTO identity, AddressDTO address, byte[] photo) | |||
throws NoSuchAlgorithmException; | |||
DigestInfo preSign(Document document, List<DigestInfo> 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<X509Certificate> signingCertificateChain) | |||
throws IOException, MarshalException, ParserConfigurationException, XmlException; | |||
void postSign(Document document, byte[] signatureValue) | |||
throws IOException, MarshalException, ParserConfigurationException, XmlException; | |||
} |
@@ -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<SignatureFacet> 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<SignatureFacet>(); | |||
public XmlSignatureService(SignatureInfoConfig signatureConfig) { | |||
this.signatureNamespacePrefix = null; | |||
this.hashAlgo = digestAlgo; | |||
this.opcPackage = opcPackage; | |||
// this.sigDoc = null; | |||
this.signatureConfig = signatureConfig; | |||
} | |||
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()); | |||
} | |||
public SignatureInfoConfig getSignatureConfig() { | |||
return signatureConfig; | |||
} | |||
/** | |||
* Sets the signature Id attribute value used to create the XML signature. A | |||
* <code>null</code> 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<DigestInfo> digestInfos, | |||
PrivateKey key, | |||
List<X509Certificate> signingCertificateChain, | |||
IdentityDTO identity, AddressDTO address, byte[] photo) | |||
public DigestInfo preSign(Document document, List<DigestInfo> 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<X509Certificate> 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<DigestInfo> digestInfos, | |||
PrivateKey privateKey, | |||
List<X509Certificate> signingCertificateChain) | |||
private byte[] getXmlSignatureDigestValue(Document document, List<DigestInfo> 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<XMLObject> objects = new ArrayList<XMLObject>(); | |||
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<String,String> namespaceMap = new HashMap<String,String>(); | |||
for (SignatureFacet sf : this.signatureFacets) { | |||
for (SignatureFacet sf : this.signatureConfig.getSignatureFacets()) { | |||
Map<String,String> 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 { |
@@ -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<X509Certificate> certificateChain = new ArrayList<X509Certificate>(); | |||
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<X509Certificate> certificateChain = new ArrayList<X509Certificate>(); | |||
/* | |||
* 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<X509Certificate> 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); |