Bug 61182 - Invalid signature created for streamed xslx file
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1800207 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4209a1b2da
commit
51b46a9e4e
@ -74,8 +74,12 @@ public final class StreamHelper {
|
|||||||
out.flush(); // only flush, don't close!
|
out.flush(); // only flush, don't close!
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// xmlContent.setXmlStandalone(true);
|
||||||
trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||||
trans.setOutputProperty(OutputKeys.INDENT, "yes");
|
// don't indent xml documents, the indent will cause errors in calculating the xml signature
|
||||||
|
// because of different handling of linebreaks in Windows/Unix
|
||||||
|
// see https://stackoverflow.com/questions/36063375
|
||||||
|
trans.setOutputProperty(OutputKeys.INDENT, "no");
|
||||||
trans.setOutputProperty(OutputKeys.STANDALONE, "yes");
|
trans.setOutputProperty(OutputKeys.STANDALONE, "yes");
|
||||||
trans.transform(xmlSource, outputTarget);
|
trans.transform(xmlSource, outputTarget);
|
||||||
} catch (TransformerException e) {
|
} catch (TransformerException e) {
|
||||||
|
@ -40,24 +40,32 @@ public class SignatureMarshalListener implements EventListener, SignatureConfigu
|
|||||||
this.target.set(target);
|
this.target.set(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void handleEvent(Event e) {
|
public void handleEvent(Event e) {
|
||||||
if (!(e instanceof MutationEvent)) return;
|
if (!(e instanceof MutationEvent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
MutationEvent mutEvt = (MutationEvent)e;
|
MutationEvent mutEvt = (MutationEvent)e;
|
||||||
EventTarget et = mutEvt.getTarget();
|
EventTarget et = mutEvt.getTarget();
|
||||||
if (!(et instanceof Element)) return;
|
if (!(et instanceof Element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
handleElement((Element)et);
|
handleElement((Element)et);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleElement(Element el) {
|
public void handleElement(Element el) {
|
||||||
EventTarget target = this.target.get();
|
EventTarget target = this.target.get();
|
||||||
String packageId = signatureConfig.getPackageSignatureId();
|
|
||||||
if (el.hasAttribute("Id")) {
|
if (el.hasAttribute("Id")) {
|
||||||
el.setIdAttribute("Id", true);
|
el.setIdAttribute("Id", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
setListener(target, this, false);
|
setListener(target, this, false);
|
||||||
if (packageId.equals(el.getAttribute("Id"))) {
|
if (OO_DIGSIG_NS.equals(el.getNamespaceURI())) {
|
||||||
el.setAttributeNS(XML_NS, "xmlns:mdssi", OO_DIGSIG_NS);
|
String parentNS = el.getParentNode().getNamespaceURI();
|
||||||
|
if (!OO_DIGSIG_NS.equals(parentNS) && !el.hasAttributeNS(XML_NS, "mdssi")) {
|
||||||
|
el.setAttributeNS(XML_NS, "xmlns:mdssi", OO_DIGSIG_NS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setPrefix(el);
|
setPrefix(el);
|
||||||
setListener(target, this, true);
|
setListener(target, this, true);
|
||||||
@ -86,6 +94,7 @@ public class SignatureMarshalListener implements EventListener, SignatureConfigu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setSignatureConfig(SignatureConfig signatureConfig) {
|
public void setSignatureConfig(SignatureConfig signatureConfig) {
|
||||||
this.signatureConfig = signatureConfig;
|
this.signatureConfig = signatureConfig;
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
This product contains an ASLv2 licensed version of the OOXML signer
|
This product contains an ASLv2 licensed version of the OOXML signer
|
||||||
package from the eID Applet project
|
package from the eID Applet project
|
||||||
http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
|
http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
|
||||||
Copyright (C) 2008-2014 FedICT.
|
Copyright (C) 2008-2014 FedICT.
|
||||||
================================================================= */
|
================================================================= */
|
||||||
|
|
||||||
package org.apache.poi.poifs.crypt.dsig.facets;
|
package org.apache.poi.poifs.crypt.dsig.facets;
|
||||||
|
|
||||||
@ -29,6 +29,9 @@ import java.net.URISyntaxException;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -70,13 +73,13 @@ import com.microsoft.schemas.office.x2006.digsig.SignatureInfoV1Document;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Office OpenXML Signature Facet implementation.
|
* Office OpenXML Signature Facet implementation.
|
||||||
*
|
*
|
||||||
* @author fcorneli
|
|
||||||
* @see <a href="http://msdn.microsoft.com/en-us/library/cc313071.aspx">[MS-OFFCRYPTO]: Office Document Cryptography Structure</a>
|
* @see <a href="http://msdn.microsoft.com/en-us/library/cc313071.aspx">[MS-OFFCRYPTO]: Office Document Cryptography Structure</a>
|
||||||
*/
|
*/
|
||||||
public class OOXMLSignatureFacet extends SignatureFacet {
|
public class OOXMLSignatureFacet extends SignatureFacet {
|
||||||
|
|
||||||
private static final POILogger LOG = POILogFactory.getLogger(OOXMLSignatureFacet.class);
|
private static final POILogger LOG = POILogFactory.getLogger(OOXMLSignatureFacet.class);
|
||||||
|
private static final String ID_PACKAGE_OBJECT = "idPackageObject";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void preSign(
|
public void preSign(
|
||||||
@ -98,17 +101,16 @@ public class OOXMLSignatureFacet extends SignatureFacet {
|
|||||||
List<Reference> manifestReferences = new ArrayList<Reference>();
|
List<Reference> manifestReferences = new ArrayList<Reference>();
|
||||||
addManifestReferences(manifestReferences);
|
addManifestReferences(manifestReferences);
|
||||||
Manifest manifest = getSignatureFactory().newManifest(manifestReferences);
|
Manifest manifest = getSignatureFactory().newManifest(manifestReferences);
|
||||||
|
|
||||||
String objectId = "idPackageObject"; // really has to be this value.
|
|
||||||
List<XMLStructure> objectContent = new ArrayList<XMLStructure>();
|
List<XMLStructure> objectContent = new ArrayList<XMLStructure>();
|
||||||
objectContent.add(manifest);
|
objectContent.add(manifest);
|
||||||
|
|
||||||
addSignatureTime(document, objectContent);
|
addSignatureTime(document, objectContent);
|
||||||
|
|
||||||
XMLObject xo = getSignatureFactory().newXMLObject(objectContent, objectId, null, null);
|
XMLObject xo = getSignatureFactory().newXMLObject(objectContent, ID_PACKAGE_OBJECT, null, null);
|
||||||
objects.add(xo);
|
objects.add(xo);
|
||||||
|
|
||||||
Reference reference = newReference("#" + objectId, null, XML_DIGSIG_NS+"Object", null, null);
|
Reference reference = newReference("#"+ID_PACKAGE_OBJECT, null, XML_DIGSIG_NS+"Object", null, null);
|
||||||
references.add(reference);
|
references.add(reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +123,7 @@ public class OOXMLSignatureFacet extends SignatureFacet {
|
|||||||
|
|
||||||
Set<String> digestedPartNames = new HashSet<String>();
|
Set<String> digestedPartNames = new HashSet<String>();
|
||||||
for (PackagePart pp : relsEntryNames) {
|
for (PackagePart pp : relsEntryNames) {
|
||||||
String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1");
|
final String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1");
|
||||||
|
|
||||||
PackageRelationshipCollection prc;
|
PackageRelationshipCollection prc;
|
||||||
try {
|
try {
|
||||||
@ -130,11 +132,11 @@ public class OOXMLSignatureFacet extends SignatureFacet {
|
|||||||
} catch (InvalidFormatException e) {
|
} catch (InvalidFormatException e) {
|
||||||
throw new XMLSignatureException("Invalid relationship descriptor: "+pp.getPartName().getName(), e);
|
throw new XMLSignatureException("Invalid relationship descriptor: "+pp.getPartName().getName(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
RelationshipTransformParameterSpec parameterSpec = new RelationshipTransformParameterSpec();
|
RelationshipTransformParameterSpec parameterSpec = new RelationshipTransformParameterSpec();
|
||||||
for (PackageRelationship relationship : prc) {
|
for (PackageRelationship relationship : prc) {
|
||||||
String relationshipType = relationship.getRelationshipType();
|
String relationshipType = relationship.getRelationshipType();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ECMA-376 Part 2 - 3rd edition
|
* ECMA-376 Part 2 - 3rd edition
|
||||||
* 13.2.4.16 Manifest Element
|
* 13.2.4.16 Manifest Element
|
||||||
@ -144,22 +146,20 @@ public class OOXMLSignatureFacet extends SignatureFacet {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSignedRelationship(relationshipType)) continue;
|
if (!isSignedRelationship(relationshipType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
parameterSpec.addRelationshipReference(relationship.getId());
|
parameterSpec.addRelationshipReference(relationship.getId());
|
||||||
|
|
||||||
// TODO: find a better way ...
|
String partName = normalizePartName(relationship.getTargetURI(), baseUri);
|
||||||
String partName = relationship.getTargetURI().toString();
|
|
||||||
if (!partName.startsWith(baseUri)) {
|
// We only digest a part once.
|
||||||
partName = baseUri + partName;
|
if (digestedPartNames.contains(partName)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
digestedPartNames.add(partName);
|
||||||
partName = new URI(partName).normalize().getPath().replace('\\', '/');
|
|
||||||
LOG.log(POILogger.DEBUG, "part name: " + partName);
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new XMLSignatureException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
String contentType;
|
String contentType;
|
||||||
try {
|
try {
|
||||||
PackagePartName relName = PackagingURIHelper.createPartName(partName);
|
PackagePartName relName = PackagingURIHelper.createPartName(partName);
|
||||||
@ -168,32 +168,52 @@ public class OOXMLSignatureFacet extends SignatureFacet {
|
|||||||
} catch (InvalidFormatException e) {
|
} catch (InvalidFormatException e) {
|
||||||
throw new XMLSignatureException(e);
|
throw new XMLSignatureException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (relationshipType.endsWith("customXml")
|
if (relationshipType.endsWith("customXml")
|
||||||
&& !(contentType.equals("inkml+xml") || contentType.equals("text/xml"))) {
|
&& !(contentType.equals("inkml+xml") || contentType.equals("text/xml"))) {
|
||||||
LOG.log(POILogger.DEBUG, "skipping customXml with content type: " + contentType);
|
LOG.log(POILogger.DEBUG, "skipping customXml with content type: " + contentType);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!digestedPartNames.contains(partName)) {
|
String uri = partName + "?ContentType=" + contentType;
|
||||||
// We only digest a part once.
|
Reference reference = newReference(uri, null, null, null, null);
|
||||||
String uri = partName + "?ContentType=" + contentType;
|
manifestReferences.add(reference);
|
||||||
Reference reference = newReference(uri, null, null, null, null);
|
|
||||||
manifestReferences.add(reference);
|
|
||||||
digestedPartNames.add(partName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameterSpec.hasSourceIds()) {
|
if (parameterSpec.hasSourceIds()) {
|
||||||
List<Transform> transforms = new ArrayList<Transform>();
|
List<Transform> transforms = new ArrayList<Transform>();
|
||||||
transforms.add(newTransform(RelationshipTransformService.TRANSFORM_URI, parameterSpec));
|
transforms.add(newTransform(RelationshipTransformService.TRANSFORM_URI, parameterSpec));
|
||||||
transforms.add(newTransform(CanonicalizationMethod.INCLUSIVE));
|
transforms.add(newTransform(CanonicalizationMethod.INCLUSIVE));
|
||||||
String uri = pp.getPartName().getName()
|
String uri = normalizePartName(pp.getPartName().getURI(), baseUri)
|
||||||
+ "?ContentType=application/vnd.openxmlformats-package.relationships+xml";
|
+ "?ContentType=application/vnd.openxmlformats-package.relationships+xml";
|
||||||
Reference reference = newReference(uri, transforms, null, null, null);
|
Reference reference = newReference(uri, transforms, null, null, null);
|
||||||
manifestReferences.add(reference);
|
manifestReferences.add(reference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collections.sort(manifestReferences, new Comparator<Reference>() {
|
||||||
|
public int compare(Reference o1, Reference o2) {
|
||||||
|
return o1.getURI().compareTo(o2.getURI());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a URI/part name
|
||||||
|
* TODO: find a better way ...
|
||||||
|
*/
|
||||||
|
private static String normalizePartName(URI partName, String baseUri) throws XMLSignatureException {
|
||||||
|
String pn = partName.toASCIIString();
|
||||||
|
if (!pn.startsWith(baseUri)) {
|
||||||
|
pn = baseUri + pn;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
pn = new URI(pn).normalize().getPath().replace('\\', '/');
|
||||||
|
LOG.log(POILogger.DEBUG, "part name: " + pn);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new XMLSignatureException(e);
|
||||||
|
}
|
||||||
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -236,7 +256,7 @@ public class OOXMLSignatureFacet extends SignatureFacet {
|
|||||||
ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri());
|
ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri());
|
||||||
Element n = (Element)document.importNode(ctSigV1.getDomNode(), true);
|
Element n = (Element)document.importNode(ctSigV1.getDomNode(), true);
|
||||||
n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS);
|
n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS);
|
||||||
|
|
||||||
List<XMLStructure> signatureInfoContent = new ArrayList<XMLStructure>();
|
List<XMLStructure> signatureInfoContent = new ArrayList<XMLStructure>();
|
||||||
signatureInfoContent.add(new DOMStructure(n));
|
signatureInfoContent.add(new DOMStructure(n));
|
||||||
SignatureProperty signatureInfoSignatureProperty = getSignatureFactory()
|
SignatureProperty signatureInfoSignatureProperty = getSignatureFactory()
|
||||||
@ -268,208 +288,33 @@ public class OOXMLSignatureFacet extends SignatureFacet {
|
|||||||
|
|
||||||
protected static boolean isSignedRelationship(String relationshipType) {
|
protected static boolean isSignedRelationship(String relationshipType) {
|
||||||
LOG.log(POILogger.DEBUG, "relationship type: " + relationshipType);
|
LOG.log(POILogger.DEBUG, "relationship type: " + relationshipType);
|
||||||
for (String signedTypeExtension : signed) {
|
String rt = relationshipType.replaceFirst(".*/relationships/", "");
|
||||||
if (relationshipType.endsWith(signedTypeExtension)) {
|
return (signed.contains(rt) || rt.endsWith("customXml"));
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (relationshipType.endsWith("customXml")) {
|
|
||||||
LOG.log(POILogger.DEBUG, "customXml relationship type");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String[] contentTypes = {
|
|
||||||
/*
|
|
||||||
* Word
|
|
||||||
*/
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.theme+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml",
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Word 2010
|
|
||||||
*/
|
|
||||||
"application/vnd.ms-word.stylesWithEffects+xml",
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Excel
|
|
||||||
*/
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Powerpoint
|
|
||||||
*/
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.slide+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml",
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Powerpoint 2010
|
|
||||||
*/
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Office 2010 list of signed types (extensions).
|
* Office 2010 list of signed types (extensions).
|
||||||
*/
|
*/
|
||||||
public static final String[] signed = {
|
private static final Set<String> signed = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||||
"powerPivotData", //
|
"activeXControlBinary","aFChunk","attachedTemplate","attachedToolbars","audio","calcChain","chart","chartColorStyle",
|
||||||
"activeXControlBinary", //
|
"chartLayout","chartsheet","chartStyle","chartUserShapes","commentAuthors","comments","connections","connectorXml",
|
||||||
"attachedToolbars", //
|
"control","ctrlProp","customData","customData","customProperty","customXml","diagram","diagramColors",
|
||||||
"connectorXml", //
|
"diagramColorsHeader","diagramData","diagramDrawing","diagramLayout","diagramLayoutHeader","diagramQuickStyle",
|
||||||
"downRev", //
|
"diagramQuickStyleHeader","dialogsheet","dictionary","documentParts","downRev","drawing","endnotes","externalLink",
|
||||||
"functionPrototypes", //
|
"externalLinkPath","font","fontTable","footer","footnotes","functionPrototypes","glossaryDocument","graphicFrameDoc",
|
||||||
"graphicFrameDoc", //
|
"groupShapeXml","handoutMaster","hdphoto","header","hyperlink","image","ink","inkXml","keyMapCustomizations",
|
||||||
"groupShapeXml", //
|
"legacyDiagramText","legacyDocTextInfo","mailMergeHeaderSource","mailMergeRecipientData","mailMergeSource","media",
|
||||||
"ink", //
|
"notesMaster","notesSlide","numbering","officeDocument","officeDocument","oleObject","package","pictureXml",
|
||||||
"keyMapCustomizations", //
|
"pivotCacheDefinition","pivotCacheRecords","pivotTable","powerPivotData","presProps","printerSettings","queryTable",
|
||||||
"legacyDiagramText", //
|
"recipientData","settings","shapeXml","sharedStrings","sheetMetadata","slicer","slicer","slicerCache","slicerCache",
|
||||||
"legacyDocTextInfo", //
|
"slide","slideLayout","slideMaster","slideUpdateInfo","slideUpdateUrl","smartTags","styles","stylesWithEffects",
|
||||||
"officeDocument", //
|
"table","tableSingleCells","tableStyles","tags","theme","themeOverride","timeline","timelineCache","transform",
|
||||||
"pictureXml", //
|
"ui/altText","ui/buttonSize","ui/controlID","ui/description","ui/enabled","ui/extensibility","ui/extensibility",
|
||||||
"shapeXml", //
|
"ui/helperText","ui/imageID","ui/imageMso","ui/keyTip","ui/label","ui/lcid","ui/loud","ui/pressed","ui/progID",
|
||||||
"smartTags", //
|
"ui/ribbonID","ui/showImage","ui/showLabel","ui/supertip","ui/target","ui/text","ui/title","ui/tooltip",
|
||||||
"ui/altText", //
|
"ui/userCustomization","ui/visible","userXmlData","vbaProject","video","viewProps","vmlDrawing",
|
||||||
"ui/buttonSize", //
|
"volatileDependencies","webSettings","wordVbaData","worksheet","wsSortMap","xlBinaryIndex",
|
||||||
"ui/controlID", //
|
"xlExternalLinkPath/xlAlternateStartup","xlExternalLinkPath/xlLibrary","xlExternalLinkPath/xlPathMissing",
|
||||||
"ui/description", //
|
"xlExternalLinkPath/xlStartup","xlIntlMacrosheet","xlMacrosheet","xmlMaps"
|
||||||
"ui/enabled", //
|
)));
|
||||||
"ui/extensibility", //
|
|
||||||
"ui/helperText", //
|
|
||||||
"ui/imageID", //
|
|
||||||
"ui/imageMso", //
|
|
||||||
"ui/keyTip", //
|
|
||||||
"ui/label", //
|
|
||||||
"ui/lcid", //
|
|
||||||
"ui/loud", //
|
|
||||||
"ui/pressed", //
|
|
||||||
"ui/progID", //
|
|
||||||
"ui/ribbonID", //
|
|
||||||
"ui/showImage", //
|
|
||||||
"ui/showLabel", //
|
|
||||||
"ui/supertip", //
|
|
||||||
"ui/target", //
|
|
||||||
"ui/text", //
|
|
||||||
"ui/title", //
|
|
||||||
"ui/tooltip", //
|
|
||||||
"ui/userCustomization", //
|
|
||||||
"ui/visible", //
|
|
||||||
"userXmlData", //
|
|
||||||
"vbaProject", //
|
|
||||||
"wordVbaData", //
|
|
||||||
"wsSortMap", //
|
|
||||||
"xlBinaryIndex", //
|
|
||||||
"xlExternalLinkPath/xlAlternateStartup", //
|
|
||||||
"xlExternalLinkPath/xlLibrary", //
|
|
||||||
"xlExternalLinkPath/xlPathMissing", //
|
|
||||||
"xlExternalLinkPath/xlStartup", //
|
|
||||||
"xlIntlMacrosheet", //
|
|
||||||
"xlMacrosheet", //
|
|
||||||
"customData", //
|
|
||||||
"diagramDrawing", //
|
|
||||||
"hdphoto", //
|
|
||||||
"inkXml", //
|
|
||||||
"media", //
|
|
||||||
"slicer", //
|
|
||||||
"slicerCache", //
|
|
||||||
"stylesWithEffects", //
|
|
||||||
"ui/extensibility", //
|
|
||||||
"chartColorStyle", //
|
|
||||||
"chartLayout", //
|
|
||||||
"chartStyle", //
|
|
||||||
"dictionary", //
|
|
||||||
"timeline", //
|
|
||||||
"timelineCache", //
|
|
||||||
"aFChunk", //
|
|
||||||
"attachedTemplate", //
|
|
||||||
"audio", //
|
|
||||||
"calcChain", //
|
|
||||||
"chart", //
|
|
||||||
"chartsheet", //
|
|
||||||
"chartUserShapes", //
|
|
||||||
"commentAuthors", //
|
|
||||||
"comments", //
|
|
||||||
"connections", //
|
|
||||||
"control", //
|
|
||||||
"customProperty", //
|
|
||||||
"customXml", //
|
|
||||||
"diagramColors", //
|
|
||||||
"diagramData", //
|
|
||||||
"diagramLayout", //
|
|
||||||
"diagramQuickStyle", //
|
|
||||||
"dialogsheet", //
|
|
||||||
"drawing", //
|
|
||||||
"endnotes", //
|
|
||||||
"externalLink", //
|
|
||||||
"externalLinkPath", //
|
|
||||||
"font", //
|
|
||||||
"fontTable", //
|
|
||||||
"footer", //
|
|
||||||
"footnotes", //
|
|
||||||
"glossaryDocument", //
|
|
||||||
"handoutMaster", //
|
|
||||||
"header", //
|
|
||||||
"hyperlink", //
|
|
||||||
"image", //
|
|
||||||
"mailMergeHeaderSource", //
|
|
||||||
"mailMergeRecipientData", //
|
|
||||||
"mailMergeSource", //
|
|
||||||
"notesMaster", //
|
|
||||||
"notesSlide", //
|
|
||||||
"numbering", //
|
|
||||||
"officeDocument", //
|
|
||||||
"oleObject", //
|
|
||||||
"package", //
|
|
||||||
"pivotCacheDefinition", //
|
|
||||||
"pivotCacheRecords", //
|
|
||||||
"pivotTable", //
|
|
||||||
"presProps", //
|
|
||||||
"printerSettings", //
|
|
||||||
"queryTable", //
|
|
||||||
"recipientData", //
|
|
||||||
"settings", //
|
|
||||||
"sharedStrings", //
|
|
||||||
"sheetMetadata", //
|
|
||||||
"slide", //
|
|
||||||
"slideLayout", //
|
|
||||||
"slideMaster", //
|
|
||||||
"slideUpdateInfo", //
|
|
||||||
"slideUpdateUrl", //
|
|
||||||
"styles", //
|
|
||||||
"table", //
|
|
||||||
"tableSingleCells", //
|
|
||||||
"tableStyles", //
|
|
||||||
"tags", //
|
|
||||||
"theme", //
|
|
||||||
"themeOverride", //
|
|
||||||
"transform", //
|
|
||||||
"video", //
|
|
||||||
"viewProps", //
|
|
||||||
"volatileDependencies", //
|
|
||||||
"webSettings", //
|
|
||||||
"worksheet", //
|
|
||||||
"xmlMaps", //
|
|
||||||
"ctrlProp", //
|
|
||||||
"customData", //
|
|
||||||
"diagram", //
|
|
||||||
"diagramColorsHeader", //
|
|
||||||
"diagramLayoutHeader", //
|
|
||||||
"diagramQuickStyleHeader", //
|
|
||||||
"documentParts", //
|
|
||||||
"slicer", //
|
|
||||||
"slicerCache", //
|
|
||||||
"vmlDrawing" //
|
|
||||||
};
|
|
||||||
}
|
}
|
@ -25,10 +25,9 @@
|
|||||||
package org.apache.poi.poifs.crypt.dsig.services;
|
package org.apache.poi.poifs.crypt.dsig.services;
|
||||||
|
|
||||||
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
|
||||||
|
import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.OO_DIGSIG_NS;
|
||||||
|
import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_NS;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
@ -36,9 +35,8 @@ import java.security.Provider;
|
|||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.spec.AlgorithmParameterSpec;
|
import java.security.spec.AlgorithmParameterSpec;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import javax.xml.crypto.Data;
|
import javax.xml.crypto.Data;
|
||||||
import javax.xml.crypto.MarshalException;
|
import javax.xml.crypto.MarshalException;
|
||||||
@ -50,23 +48,20 @@ import javax.xml.crypto.dsig.TransformException;
|
|||||||
import javax.xml.crypto.dsig.TransformService;
|
import javax.xml.crypto.dsig.TransformService;
|
||||||
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
|
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
|
||||||
|
|
||||||
|
import org.apache.jcp.xml.dsig.internal.dom.ApacheNodeSetData;
|
||||||
|
import org.apache.poi.util.DocumentHelper;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
import org.apache.poi.util.XmlSort;
|
import org.apache.xml.security.signature.XMLSignatureInput;
|
||||||
import org.apache.xmlbeans.XmlCursor;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
import org.apache.xmlbeans.XmlObject;
|
import org.apache.xmlbeans.XmlObject;
|
||||||
import org.apache.xmlbeans.XmlOptions;
|
|
||||||
import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.CTRelationshipReference;
|
import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.CTRelationshipReference;
|
||||||
import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.RelationshipReferenceDocument;
|
import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.RelationshipReferenceDocument;
|
||||||
import org.openxmlformats.schemas.xpackage.x2006.relationships.CTRelationship;
|
|
||||||
import org.openxmlformats.schemas.xpackage.x2006.relationships.CTRelationships;
|
|
||||||
import org.openxmlformats.schemas.xpackage.x2006.relationships.RelationshipsDocument;
|
|
||||||
import org.openxmlformats.schemas.xpackage.x2006.relationships.STTargetMode;
|
|
||||||
import org.w3.x2000.x09.xmldsig.TransformDocument;
|
import org.w3.x2000.x09.xmldsig.TransformDocument;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSR105 implementation of the RelationshipTransform transformation.
|
* JSR105 implementation of the RelationshipTransform transformation.
|
||||||
@ -89,7 +84,7 @@ public class RelationshipTransformService extends TransformService {
|
|||||||
public static class RelationshipTransformParameterSpec implements TransformParameterSpec {
|
public static class RelationshipTransformParameterSpec implements TransformParameterSpec {
|
||||||
List<String> sourceIds = new ArrayList<String>();
|
List<String> sourceIds = new ArrayList<String>();
|
||||||
public void addRelationshipReference(String relationshipId) {
|
public void addRelationshipReference(String relationshipId) {
|
||||||
sourceIds.add(relationshipId);
|
sourceIds.add(relationshipId);
|
||||||
}
|
}
|
||||||
public boolean hasSourceIds() {
|
public boolean hasSourceIds() {
|
||||||
return !sourceIds.isEmpty();
|
return !sourceIds.isEmpty();
|
||||||
@ -163,15 +158,13 @@ public class RelationshipTransformService extends TransformService {
|
|||||||
LOG.log(POILogger.DEBUG, "marshallParams(parent,context)");
|
LOG.log(POILogger.DEBUG, "marshallParams(parent,context)");
|
||||||
DOMStructure domParent = (DOMStructure) parent;
|
DOMStructure domParent = (DOMStructure) parent;
|
||||||
Element parentNode = (Element)domParent.getNode();
|
Element parentNode = (Element)domParent.getNode();
|
||||||
// parentNode.setAttributeNS(XML_NS, "xmlns:mdssi", XML_DIGSIG_NS);
|
|
||||||
Document doc = parentNode.getOwnerDocument();
|
Document doc = parentNode.getOwnerDocument();
|
||||||
|
|
||||||
for (String sourceId : this.sourceIds) {
|
for (String sourceId : this.sourceIds) {
|
||||||
RelationshipReferenceDocument relRef = RelationshipReferenceDocument.Factory.newInstance();
|
Element el = doc.createElementNS(OO_DIGSIG_NS, "mdssi:RelationshipReference");
|
||||||
relRef.addNewRelationshipReference().setSourceId(sourceId);
|
el.setAttributeNS(XML_NS, "xmlns:mdssi", OO_DIGSIG_NS);
|
||||||
Node n = relRef.getRelationshipReference().getDomNode();
|
el.setAttribute("SourceId", sourceId);
|
||||||
n = doc.importNode(n, true);
|
parentNode.appendChild(el);
|
||||||
parentNode.appendChild(n);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +173,13 @@ public class RelationshipTransformService extends TransformService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The relationships transform takes the XML document from the Relationships part
|
||||||
|
* and converts it to another XML document.
|
||||||
|
*
|
||||||
|
* @see <a href="https://www.ecma-international.org/activities/Office%20Open%20XML%20Formats/Draft%20ECMA-376%203rd%20edition,%20March%202011/Office%20Open%20XML%20Part%202%20-%20Open%20Packaging%20Conventions.pdf">13.2.4.24 Relationships Transform Algorithm</a>
|
||||||
|
* @see <a href="https://stackoverflow.com/questions/36063375">XML Relationship Transform Algorithm</a>
|
||||||
|
*/
|
||||||
public Data transform(Data data, XMLCryptoContext context) throws TransformException {
|
public Data transform(Data data, XMLCryptoContext context) throws TransformException {
|
||||||
LOG.log(POILogger.DEBUG, "transform(data,context)");
|
LOG.log(POILogger.DEBUG, "transform(data,context)");
|
||||||
LOG.log(POILogger.DEBUG, "data java type: " + data.getClass().getName());
|
LOG.log(POILogger.DEBUG, "data java type: " + data.getClass().getName());
|
||||||
@ -187,53 +187,40 @@ public class RelationshipTransformService extends TransformService {
|
|||||||
LOG.log(POILogger.DEBUG, "URI: " + octetStreamData.getURI());
|
LOG.log(POILogger.DEBUG, "URI: " + octetStreamData.getURI());
|
||||||
InputStream octetStream = octetStreamData.getOctetStream();
|
InputStream octetStream = octetStreamData.getOctetStream();
|
||||||
|
|
||||||
RelationshipsDocument relDoc;
|
Document doc;
|
||||||
try {
|
try {
|
||||||
relDoc = RelationshipsDocument.Factory.parse(octetStream, DEFAULT_XML_OPTIONS);
|
doc = DocumentHelper.readDocument(octetStream);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new TransformException(e.getMessage(), e);
|
throw new TransformException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
LOG.log(POILogger.DEBUG, "relationships document", relDoc);
|
|
||||||
|
|
||||||
CTRelationships rels = relDoc.getRelationships();
|
// keep only those relationships which id is registered in the sourceIds
|
||||||
List<CTRelationship> relList = rels.getRelationshipList();
|
Element root = doc.getDocumentElement();
|
||||||
Iterator<CTRelationship> relIter = rels.getRelationshipList().iterator();
|
NodeList nl = root.getChildNodes();
|
||||||
while (relIter.hasNext()) {
|
TreeMap<String,Element> rsList = new TreeMap<String,Element>();
|
||||||
CTRelationship rel = relIter.next();
|
for (int i=nl.getLength()-1; i>=0; i--) {
|
||||||
/*
|
Node n = nl.item(i);
|
||||||
* See: ISO/IEC 29500-2:2008(E) - 13.2.4.24 Relationships Transform
|
if ("Relationship".equals(n.getLocalName())) {
|
||||||
* Algorithm.
|
Element el = (Element)n;
|
||||||
*/
|
String id = el.getAttribute("Id");
|
||||||
if (!this.sourceIds.contains(rel.getId())) {
|
if (sourceIds.contains(id)) {
|
||||||
LOG.log(POILogger.DEBUG, "removing element: " + rel.getId());
|
String targetMode = el.getAttribute("TargetMode");
|
||||||
relIter.remove();
|
if ("".equals(targetMode)) {
|
||||||
} else {
|
el.setAttribute("TargetMode", "Internal");
|
||||||
if (!rel.isSetTargetMode()) {
|
}
|
||||||
rel.setTargetMode(STTargetMode.INTERNAL);
|
rsList.put(id, el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
root.removeChild(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove non element nodes ???
|
|
||||||
LOG.log(POILogger.DEBUG, "# Relationship elements", relList.size());
|
|
||||||
|
|
||||||
XmlSort.sort(rels, new Comparator<XmlCursor>(){
|
|
||||||
public int compare(XmlCursor c1, XmlCursor c2) {
|
|
||||||
String id1 = ((CTRelationship)c1.getObject()).getId();
|
|
||||||
String id2 = ((CTRelationship)c2.getObject()).getId();
|
|
||||||
return id1.compareTo(id2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
for (Element el : rsList.values()) {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
root.appendChild(el);
|
||||||
XmlOptions xo = new XmlOptions();
|
|
||||||
xo.setSaveNoXmlDecl();
|
|
||||||
relDoc.save(bos, xo);
|
|
||||||
return new OctetStreamData(new ByteArrayInputStream(bos.toByteArray()));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new TransformException(e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG.log(POILogger.DEBUG, "# Relationship elements: ", rsList.size());
|
||||||
|
|
||||||
|
return new ApacheNodeSetData(new XMLSignatureInput(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Data transform(Data data, XMLCryptoContext context, OutputStream os) throws TransformException {
|
public Data transform(Data data, XMLCryptoContext context, OutputStream os) throws TransformException {
|
||||||
|
@ -1,88 +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.util;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import org.apache.xmlbeans.XmlCursor;
|
|
||||||
import org.apache.xmlbeans.XmlObject;
|
|
||||||
|
|
||||||
public final class XmlSort {
|
|
||||||
/**
|
|
||||||
* Sorts the children of <code>element</code> according to the order indicated by the
|
|
||||||
* comparator.
|
|
||||||
* @param element the element whose content is to be sorted. Only element children are sorted,
|
|
||||||
* attributes are not touched. When elements are reordered, all the text, comments and PIs
|
|
||||||
* follow the element that they come immediately after.
|
|
||||||
* @param comp a comparator that is to be used when comparing the <code>QName</code>s of two
|
|
||||||
* elements.
|
|
||||||
* @throws IllegalArgumentException if the input <code>XmlObject</code> does not represent
|
|
||||||
* an element
|
|
||||||
*/
|
|
||||||
public static void sort(XmlObject element, Comparator<XmlCursor> comp) {
|
|
||||||
XmlCursor headCursor = element.newCursor();
|
|
||||||
if (!headCursor.isStart()) {
|
|
||||||
throw new IllegalStateException("The element parameter must point to a STARTDOC");
|
|
||||||
}
|
|
||||||
// We use insertion sort to minimize the number of swaps, because each swap means
|
|
||||||
// moving a part of the document
|
|
||||||
/* headCursor points to the beginning of the list of the already sorted items and
|
|
||||||
listCursor points to the beginning of the list of unsorted items
|
|
||||||
At the beginning, headCursor points to the first element and listCursor points to the
|
|
||||||
second element. The algorithm ends when listCursor cannot be moved to the "next"
|
|
||||||
element in the unsorted list, i.e. the unsorted list becomes empty */
|
|
||||||
boolean moved = headCursor.toFirstChild();
|
|
||||||
if (!moved) {
|
|
||||||
// Cursor was not moved, which means that the given element has no children and
|
|
||||||
// therefore there is nothing to sort
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
XmlCursor listCursor = headCursor.newCursor();
|
|
||||||
boolean moreElements = listCursor.toNextSibling();
|
|
||||||
while (moreElements) {
|
|
||||||
moved = false;
|
|
||||||
// While we can move the head of the unsorted list, it means that there are still
|
|
||||||
// items (elements) that need to be sorted
|
|
||||||
while (headCursor.comparePosition(listCursor) < 0) {
|
|
||||||
if (comp.compare(headCursor, listCursor) > 0) {
|
|
||||||
// We have found the position in the sorted list, insert the element and the
|
|
||||||
// text following the element in the current position
|
|
||||||
// Move the element
|
|
||||||
listCursor.moveXml(headCursor);
|
|
||||||
// Move the text following the element
|
|
||||||
while (!listCursor.isStart() && !listCursor.isEnd())
|
|
||||||
listCursor.moveXml(headCursor);
|
|
||||||
moreElements = listCursor.isStart();
|
|
||||||
moved = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
headCursor.toNextSibling();
|
|
||||||
}
|
|
||||||
if (!moved) {
|
|
||||||
// Because during the move of a fragment of XML, the listCursor is also moved, in
|
|
||||||
// case we didn't need to move XML (the new element to be inserted happened to
|
|
||||||
// be the last one in order), we need to move this cursor
|
|
||||||
moreElements = listCursor.toNextSibling();
|
|
||||||
}
|
|
||||||
// Reposition the head of the sorted list
|
|
||||||
headCursor.toParent();
|
|
||||||
headCursor.toFirstChild();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -72,6 +72,7 @@ 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.RevocationDataService;
|
||||||
import org.apache.poi.poifs.crypt.dsig.services.TimeStampService;
|
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.services.TimeStampServiceValidator;
|
||||||
|
import org.apache.poi.poifs.storage.RawDataUtil;
|
||||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||||
import org.apache.poi.util.DocumentHelper;
|
import org.apache.poi.util.DocumentHelper;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
@ -118,6 +119,70 @@ public class TestSignatureInfo {
|
|||||||
additionalJar == null || additionalJar.trim().length() == 0);
|
additionalJar == null || additionalJar.trim().length() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bug61182() throws Exception {
|
||||||
|
String pfxInput =
|
||||||
|
"H4sIAAAAAAAAAFXTfzzTeRwH8P2uGRmG6hKSmJh9a2HsuPy60VnHCEU6v86sieZH2Jr2qFl+s+ZHJ5tfUcfKb4uho/OjiFq1qTv5ceFyp0PqEK"+
|
||||||
|
"fH4+66++Pz+Dwer9fj8f7r9cRzEd4QMBTPRWxDIM14ZN47NfAWsJgL34Bx4at4Lvwdngvd9b8KqgbjQpGbMXzzgRGovytVFTBEzIXU47kQCd4U"+
|
||||||
|
"ofJPvHl8JwyTjRS55hbKoor3UJLDE1i/PcPKCBAIDATjQlKiK67XjVYdcnkZgD2txroiAUb8W9dtn57DvTsbM+3wIsdocXDEN7TdPKgaSl+tU1"+
|
||||||
|
"xq9oqiB5yMaZCPho8uUEbFU9U6u3N7lEMLTJGeA0RfX+5FMRrpXPFrbrlJ8uNUCE2H247P28Ckyfqlsy32yeKg/HTbH5JpqUDNw2B32+SaiRw7"+
|
||||||
|
"ofRMePUpaAoK7KYgmd5ZIc0rLLYjJBfOWCb28xlrGhbpJvdToFdqt5PXVjEz5YOJ6g7W0fskuKW9/iZP0yLEVpR9XkkHmb6tfpcE8YwCdWNCan"+
|
||||||
|
"LvAsco25JdF1j2/FLAMVU79HdOex07main90dy40511OZtTGZ+TdVd3lKZ7D3clEg9hLESHwSNnZ6239X4yLM4xYSElQ/hqSbwdmiozYG9PhF2"+
|
||||||
|
"Zf0XaZnxzTK0Iot+rJ3kYoxWTLE8DR9leV62Ywbtlg4mapYOxb3lT7fQ1x4EQ44flh2oFWSPLR8LMbsc6jzJsV6OZ3TrODjHEdw9W+8OD32vd8"+
|
||||||
|
"XQ6iCaIHcrSOn6qS0TKLr786234eeSAhvAQbEsVn7vrvc/487Be/O2e/+5Y5zRq2zAtz6pfcNyraJNDqMW1inNkgJ3t3VESbZ3pNzyl3KHILs0"+
|
||||||
|
"51dY6msDYSlWhw40TglXxj9rw95O6gFWIuN012W/vhS50jpKXcao4gc1aLaXtJXxirbRkpZ/0e7a0pD6TDa7+GxEdEEML3VGo9udD5YUKhU3y7"+
|
||||||
|
"SzWAgN6WIEIglq7LilvCjqIVLIfg8CvVGL9f5iSsCDf5hef4vMxbyvcjINuy06gZu+iPYOWNxjfrwKGYzoqqotK2aywgYVrPMh0JovfkDuN95n"+
|
||||||
|
"MdVlYHbN1Mnn4TxAwuv+u3AkBlDZvRUUCwoDMUGxeMNPhTaAgWl60xhhBgCBaEMgAACReMAav7n3x598IDYJ9GxGXRAwaPOT/kfO/1AgPqLQkp"+
|
||||||
|
"MiIVaHthnUS4v2y32e2BjdMPyIImUTBW3cV3R5tjVQm0MOm+D2C5+bBW9vHLjLR4lun4toQiY3Ls/v4bES/OJ4EmpZk5xhL9i5ClofYZNEsxFn"+
|
||||||
|
"An/q821Tg+Cq9Er4XYGQe8ogjjLJ2b7dUsJ3auFQFNUJF7Ke7yUL2EeYYxl6vz5l4q5u8704mRbFts1E1eWMp6WIy91GPrsVlRGvtuNERfrjfE"+
|
||||||
|
"YtzUI3Flcv65zJUbUBEzUnTS0fEYso2XyToAl8kb251mUY2o2lJzv5dp/1htmcjeeP2MjxC+3S45ljx7jd52Pv9XAat+ryiauFOF7YgztkoWWD"+
|
||||||
|
"h62tplPH1bzDV+d0NLdaE5AfVJ09HuUYTFS+iggtvT5Euyk+unj4N2XvzW91n+GNjtgWfKOHmkinUPvYRh70Jv+wlPJrVaT8mL7GxJLqDC9jbv"+
|
||||||
|
"Gznoiae6es+wQejnk3XjU366MrK/zXxngBYj9J6NnXc9mMiTFLX8WqQ8iTelTAFs2NJzPoDzrBUz4JFIEOa6Dja6dULc68g1jFDTeEHZyra7RZ"+
|
||||||
|
"2ElqGDEqcNRo3SNX6feMy9EF1GOyZK0Sa87KwjKw8aM68dpsIYjfLcTXaZ6atg0BKfMnl6axeUGEaIFSP7rzj9wjzumRbG3jgUVp2lX5AK/tsO"+
|
||||||
|
"7R4TQX/9/H6RiN34c9KldmPZZGANXzzTajZS9mR2OSvlJ+F4AgSko4htrMAKFTBu51/5SWNsO1vlRaaG48ZRJ+8PzuHQMdvS36gNpRPi7jhF1S"+
|
||||||
|
"H3B2ycI4y0VURv6SrqJNUY/X645ZFJQ+eBO+ptG7o8axf1dcqh2beiQk+GRTeZ37LVeUlaeo9vl1/+8tyBfyT2v5lFC5E19WdKIyCuZe7r99Px"+
|
||||||
|
"D/Od4Qj0TA92+DQnbCQTCMy/wwse9O4gsEebkkpPIP5GBV3Q0YBsj75XE0uSFQ1tCZSW8bNa9MUJZ/nPBfExohHlgGAAA=";
|
||||||
|
|
||||||
|
Calendar cal = LocaleUtil.getLocaleCalendar(LocaleUtil.TIMEZONE_UTC);
|
||||||
|
cal.clear();
|
||||||
|
cal.set(2017, 6, 1);
|
||||||
|
|
||||||
|
SignatureConfig signatureConfig = prepareConfig("test", "CN=Test", pfxInput);
|
||||||
|
signatureConfig.setExecutionTime(cal.getTime());
|
||||||
|
|
||||||
|
SignatureInfo si = new SignatureInfo();
|
||||||
|
si.setSignatureConfig(signatureConfig);
|
||||||
|
|
||||||
|
XSSFWorkbook wb1 = new XSSFWorkbook();
|
||||||
|
wb1.createSheet().createRow(1).createCell(1).setCellValue("Test");
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
|
||||||
|
wb1.write(bos);
|
||||||
|
wb1.close();
|
||||||
|
|
||||||
|
OPCPackage pkg1 = OPCPackage.open(new ByteArrayInputStream(bos.toByteArray()));
|
||||||
|
|
||||||
|
signatureConfig.setOpcPackage(pkg1);
|
||||||
|
si.confirmSignature();
|
||||||
|
assertTrue(si.verifySignature());
|
||||||
|
bos.reset();
|
||||||
|
pkg1.save(bos);
|
||||||
|
pkg1.close();
|
||||||
|
|
||||||
|
XSSFWorkbook wb2 = new XSSFWorkbook(new ByteArrayInputStream(bos.toByteArray()));
|
||||||
|
assertEquals("Test", wb2.getSheetAt(0).getRow(1).getCell(1).getStringCellValue());
|
||||||
|
OPCPackage pkg2 = wb2.getPackage();
|
||||||
|
signatureConfig.setOpcPackage(pkg2);
|
||||||
|
assertTrue(si.verifySignature());
|
||||||
|
String signExp =
|
||||||
|
"Lxp2LFa+0YWGOBL8zVdf7SWRQiNK/Tt85W+kmH1bunlua030BKbQc6yWIIk6gN6jCTtrJ1h2eMRbLwymygOUpM"+
|
||||||
|
"dd0MeQY3mMWRSO9qEW87SQvyDqBh71zXWW3ZYET+vJWr3BCNEtXCy8jZvgXqILBGk5vMJW/EYaUEhBcDGjCm0=";
|
||||||
|
String signAct = si.getSignatureParts().iterator().next().
|
||||||
|
getSignatureDocument().getSignature().getSignatureValue().getStringValue();
|
||||||
|
assertEquals(signExp, signAct);
|
||||||
|
pkg2.close();
|
||||||
|
wb2.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void office2007prettyPrintedRels() throws Exception {
|
public void office2007prettyPrintedRels() throws Exception {
|
||||||
OPCPackage pkg = OPCPackage.open(testdata.getFile("office2007prettyPrintedRels.docx"), PackageAccess.READ);
|
OPCPackage pkg = OPCPackage.open(testdata.getFile("office2007prettyPrintedRels.docx"), PackageAccess.READ);
|
||||||
@ -611,15 +676,21 @@ public class TestSignatureInfo {
|
|||||||
pkg.close();
|
pkg.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {
|
private SignatureConfig prepareConfig(String alias, String signerDn, String pfxInput) throws Exception {
|
||||||
initKeyPair(alias, signerDn);
|
initKeyPair(alias, signerDn, pfxInput);
|
||||||
|
|
||||||
SignatureConfig signatureConfig = new SignatureConfig();
|
SignatureConfig signatureConfig = new SignatureConfig();
|
||||||
signatureConfig.setKey(keyPair.getPrivate());
|
signatureConfig.setKey(keyPair.getPrivate());
|
||||||
signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
|
signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
|
||||||
signatureConfig.setExecutionTime(cal.getTime());
|
signatureConfig.setExecutionTime(cal.getTime());
|
||||||
signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
|
signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
|
||||||
|
|
||||||
|
return signatureConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {
|
||||||
|
SignatureConfig signatureConfig = prepareConfig(alias, signerDn, null);
|
||||||
signatureConfig.setOpcPackage(pkgCopy);
|
signatureConfig.setOpcPackage(pkgCopy);
|
||||||
|
|
||||||
SignatureInfo si = new SignatureInfo();
|
SignatureInfo si = new SignatureInfo();
|
||||||
@ -656,13 +727,21 @@ public class TestSignatureInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initKeyPair(String alias, String subjectDN) throws Exception {
|
private void initKeyPair(String alias, String subjectDN) throws Exception {
|
||||||
|
initKeyPair(alias, subjectDN, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initKeyPair(String alias, String subjectDN, String pfxInput) throws Exception {
|
||||||
final char password[] = "test".toCharArray();
|
final char password[] = "test".toCharArray();
|
||||||
File file = new File("build/test.pfx");
|
File file = new File("build/test.pfx");
|
||||||
|
|
||||||
KeyStore keystore = KeyStore.getInstance("PKCS12");
|
KeyStore keystore = KeyStore.getInstance("PKCS12");
|
||||||
|
|
||||||
if (file.exists()) {
|
if (pfxInput != null) {
|
||||||
FileInputStream fis = new FileInputStream(file);
|
InputStream fis = new ByteArrayInputStream(RawDataUtil.decompress(pfxInput));
|
||||||
|
keystore.load(fis, password);
|
||||||
|
fis.close();
|
||||||
|
} else if (file.exists()) {
|
||||||
|
InputStream fis = new FileInputStream(file);
|
||||||
keystore.load(fis, password);
|
keystore.load(fis, password);
|
||||||
fis.close();
|
fis.close();
|
||||||
} else {
|
} else {
|
||||||
@ -685,9 +764,12 @@ public class TestSignatureInfo {
|
|||||||
, notBefore, notAfter, null, keyPair.getPrivate(), true, 0, null, null, keyUsage);
|
, notBefore, notAfter, null, keyPair.getPrivate(), true, 0, null, null, keyUsage);
|
||||||
|
|
||||||
keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509});
|
keystore.setKeyEntry(alias, keyPair.getPrivate(), password, new Certificate[]{x509});
|
||||||
FileOutputStream fos = new FileOutputStream(file);
|
|
||||||
keystore.store(fos, password);
|
if (pfxInput == null) {
|
||||||
fos.close();
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
keystore.store(fos, password);
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,8 +783,7 @@ public class TestSignatureInfo {
|
|||||||
// in the Sonar Maven runs where we are at a different source directory
|
// in the Sonar Maven runs where we are at a different source directory
|
||||||
File buildDir = new File("build");
|
File buildDir = new File("build");
|
||||||
if(!buildDir.exists()) {
|
if(!buildDir.exists()) {
|
||||||
assertTrue("Failed to create " + buildDir.getAbsolutePath(),
|
assertTrue("Failed to create " + buildDir.getAbsolutePath(), buildDir.mkdirs());
|
||||||
buildDir.mkdirs());
|
|
||||||
}
|
}
|
||||||
File tmpFile = new File(buildDir, "sigtest"+extension);
|
File tmpFile = new File(buildDir, "sigtest"+extension);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user