123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- /* ====================================================================
- 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.
- ==================================================================== */
-
- /* ====================================================================
- This product contains an ASLv2 licensed version of the OOXML signer
- package from the eID Applet project
- http://code.google.com/p/eid-applet/source/browse/trunk/README.txt
- Copyright (C) 2008-2014 FedICT.
- ================================================================= */
-
- package org.apache.poi.poifs.crypt.dsig.facets;
-
- import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacetHelper.newReference;
- import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacetHelper.newTransform;
-
- import java.net.URI;
- import java.net.URISyntaxException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Base64;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
-
- import javax.xml.XMLConstants;
- import javax.xml.crypto.URIReference;
- import javax.xml.crypto.XMLStructure;
- import javax.xml.crypto.dom.DOMStructure;
- import javax.xml.crypto.dsig.CanonicalizationMethod;
- import javax.xml.crypto.dsig.Manifest;
- import javax.xml.crypto.dsig.Reference;
- import javax.xml.crypto.dsig.SignatureProperties;
- import javax.xml.crypto.dsig.SignatureProperty;
- import javax.xml.crypto.dsig.Transform;
- import javax.xml.crypto.dsig.XMLObject;
- import javax.xml.crypto.dsig.XMLSignatureException;
- import javax.xml.crypto.dsig.XMLSignatureFactory;
-
- import com.microsoft.schemas.office.x2006.digsig.CTSignatureInfoV1;
- import com.microsoft.schemas.office.x2006.digsig.SignatureInfoV1Document;
- import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
- import org.apache.poi.openxml4j.opc.ContentTypes;
- 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.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.SignatureConfig;
- import org.apache.poi.poifs.crypt.dsig.SignatureInfo;
- import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService;
- import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService.RelationshipTransformParameterSpec;
- import org.apache.poi.util.POILogFactory;
- import org.apache.poi.util.POILogger;
- import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.CTSignatureTime;
- import org.openxmlformats.schemas.xpackage.x2006.digitalSignature.SignatureTimeDocument;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
-
- /**
- * Office OpenXML Signature Facet implementation.
- *
- * @see <a href="http://msdn.microsoft.com/en-us/library/cc313071.aspx">[MS-OFFCRYPTO]: Office Document Cryptography Structure</a>
- */
- public class OOXMLSignatureFacet implements SignatureFacet {
-
- private static final POILogger LOG = POILogFactory.getLogger(OOXMLSignatureFacet.class);
- private static final String ID_PACKAGE_OBJECT = "idPackageObject";
-
- @Override
- public void preSign(
- SignatureInfo signatureInfo
- , Document document
- , List<Reference> references
- , List<XMLObject> objects)
- throws XMLSignatureException {
- LOG.log(POILogger.DEBUG, "pre sign");
- addManifestObject(signatureInfo, document, references, objects);
- addSignatureInfo(signatureInfo, document, references, objects);
- }
-
- protected void addManifestObject(
- SignatureInfo signatureInfo
- , Document document
- , List<Reference> references
- , List<XMLObject> objects)
- throws XMLSignatureException {
-
- final XMLSignatureFactory sigFac = signatureInfo.getSignatureFactory();
-
- List<Reference> manifestReferences = new ArrayList<>();
- addManifestReferences(signatureInfo, manifestReferences);
- Manifest manifest = sigFac.newManifest(manifestReferences);
-
- List<XMLStructure> objectContent = new ArrayList<>();
- objectContent.add(manifest);
-
- addSignatureTime(signatureInfo, document, objectContent);
-
- XMLObject xo = sigFac.newXMLObject(objectContent, ID_PACKAGE_OBJECT, null, null);
- objects.add(xo);
-
- Reference reference = newReference(signatureInfo, "#"+ID_PACKAGE_OBJECT, null, XML_DIGSIG_NS+"Object", null, null);
- references.add(reference);
- }
-
- @SuppressWarnings("resource")
- protected void addManifestReferences(SignatureInfo signatureInfo, List<Reference> manifestReferences)
- throws XMLSignatureException {
- OPCPackage opcPackage = signatureInfo.getOpcPackage();
- List<PackagePart> relsEntryNames = opcPackage.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART);
-
- Set<String> digestedPartNames = new HashSet<>();
- for (PackagePart pp : relsEntryNames) {
- final String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1");
-
- PackageRelationshipCollection prc;
- try {
- prc = new PackageRelationshipCollection(opcPackage);
- prc.parseRelationshipsPart(pp);
- } catch (InvalidFormatException e) {
- throw new XMLSignatureException("Invalid relationship descriptor: "+pp.getPartName().getName(), e);
- }
-
- RelationshipTransformParameterSpec parameterSpec = new RelationshipTransformParameterSpec();
- for (PackageRelationship relationship : prc) {
- String relationshipType = relationship.getRelationshipType();
-
- /*
- * ECMA-376 Part 2 - 3rd edition
- * 13.2.4.16 Manifest Element
- * "The producer shall not create a Manifest element that references any data outside of the package."
- */
- if (TargetMode.EXTERNAL == relationship.getTargetMode()) {
- continue;
- }
-
- if (!isSignedRelationship(relationshipType)) {
- continue;
- }
-
- parameterSpec.addRelationshipReference(relationship.getId());
-
- String partName = normalizePartName(relationship.getTargetURI(), baseUri);
-
- // We only digest a part once.
- if (digestedPartNames.contains(partName)) {
- continue;
- }
- digestedPartNames.add(partName);
-
- String contentType;
- try {
- PackagePartName relName = PackagingURIHelper.createPartName(partName);
- PackagePart pp2 = opcPackage.getPart(relName);
- contentType = pp2.getContentType();
- } catch (InvalidFormatException e) {
- throw new XMLSignatureException(e);
- }
-
- if (relationshipType.endsWith("customXml")
- && !(contentType.equals("inkml+xml") || contentType.equals("text/xml"))) {
- LOG.log(POILogger.DEBUG, "skipping customXml with content type: " + contentType);
- continue;
- }
-
- String uri = partName + "?ContentType=" + contentType;
- Reference reference = newReference(signatureInfo, uri, null, null, null, null);
- manifestReferences.add(reference);
- }
-
- if (parameterSpec.hasSourceIds()) {
- List<Transform> transforms = new ArrayList<>();
- transforms.add(newTransform(signatureInfo, RelationshipTransformService.TRANSFORM_URI, parameterSpec));
- transforms.add(newTransform(signatureInfo, CanonicalizationMethod.INCLUSIVE));
- String uri = normalizePartName(pp.getPartName().getURI(), baseUri)
- + "?ContentType=application/vnd.openxmlformats-package.relationships+xml";
- Reference reference = newReference(signatureInfo, uri, transforms, null, null, null);
- manifestReferences.add(reference);
- }
- }
-
- manifestReferences.sort(Comparator.comparing(URIReference::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;
- }
-
-
- protected void addSignatureTime(SignatureInfo signatureInfo, Document document, List<XMLStructure> objectContent) {
- SignatureConfig signatureConfig = signatureInfo.getSignatureConfig();
- XMLSignatureFactory sigFac = signatureInfo.getSignatureFactory();
- /*
- * SignatureTime
- */
- SignatureTimeDocument sigTime = SignatureTimeDocument.Factory.newInstance();
- CTSignatureTime ctTime = sigTime.addNewSignatureTime();
- ctTime.setFormat("YYYY-MM-DDThh:mm:ssTZD");
- ctTime.setValue(signatureConfig.formatExecutionTime());
- LOG.log(POILogger.DEBUG, "execution time: " + ctTime.getValue());
-
- Element n = (Element)document.importNode(ctTime.getDomNode(),true);
- List<XMLStructure> signatureTimeContent = new ArrayList<>();
- signatureTimeContent.add(new DOMStructure(n));
- SignatureProperty signatureTimeSignatureProperty = sigFac
- .newSignatureProperty(signatureTimeContent, "#" + signatureConfig.getPackageSignatureId(),
- "idSignatureTime");
- List<SignatureProperty> signaturePropertyContent = new ArrayList<>();
- signaturePropertyContent.add(signatureTimeSignatureProperty);
- SignatureProperties signatureProperties = sigFac
- .newSignatureProperties(signaturePropertyContent, null);
- objectContent.add(signatureProperties);
- }
-
- protected void addSignatureInfo(
- SignatureInfo signatureInfo
- , Document document
- , List<Reference> references
- , List<XMLObject> objects)
- throws XMLSignatureException {
- SignatureConfig signatureConfig = signatureInfo.getSignatureConfig();
- XMLSignatureFactory sigFac = signatureInfo.getSignatureFactory();
-
- List<XMLStructure> objectContent = new ArrayList<>();
-
- SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance();
- CTSignatureInfoV1 ctSigV1 = sigV1.addNewSignatureInfoV1();
- if (signatureConfig.getDigestAlgo() != HashAlgorithm.sha1) {
- ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri());
- }
-
- String desc = signatureConfig.getSignatureDescription();
- if (desc != null) {
- ctSigV1.setSignatureComments(desc);
- }
-
- byte[] image = signatureConfig.getSignatureImage();
- if (image != null) {
- ctSigV1.setSetupID(signatureConfig.getSignatureImageSetupId().toString());
- ctSigV1.setSignatureImage(image);
- ctSigV1.setSignatureType(2);
- }
-
- Element n = (Element)document.importNode(ctSigV1.getDomNode(), true);
- n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS);
-
- List<XMLStructure> signatureInfoContent = new ArrayList<>();
- signatureInfoContent.add(new DOMStructure(n));
- SignatureProperty signatureInfoSignatureProperty = sigFac
- .newSignatureProperty(signatureInfoContent, "#" + signatureConfig.getPackageSignatureId(),
- "idOfficeV1Details");
-
- List<SignatureProperty> signaturePropertyContent = new ArrayList<>();
- signaturePropertyContent.add(signatureInfoSignatureProperty);
- SignatureProperties signatureProperties = sigFac
- .newSignatureProperties(signaturePropertyContent, null);
- objectContent.add(signatureProperties);
-
- String objectId = "idOfficeObject";
- objects.add(sigFac.newXMLObject(objectContent, objectId, null, null));
-
- Reference reference = newReference(signatureInfo, "#" + objectId, null, XML_DIGSIG_NS+"Object", null, null);
- references.add(reference);
-
- Base64.Encoder enc = Base64.getEncoder();
- byte[] imageValid = signatureConfig.getSignatureImageValid();
- if (imageValid != null) {
- objectId = "idValidSigLnImg";
- DOMStructure tn = new DOMStructure(document.createTextNode(enc.encodeToString(imageValid)));
- objects.add(sigFac.newXMLObject(Collections.singletonList(tn), objectId, null, null));
-
- reference = newReference(signatureInfo, "#" + objectId, null, XML_DIGSIG_NS+"Object", null, null);
- references.add(reference);
- }
-
- byte[] imageInvalid = signatureConfig.getSignatureImageInvalid();
- if (imageInvalid != null) {
- objectId = "idInvalidSigLnImg";
- DOMStructure tn = new DOMStructure(document.createTextNode(enc.encodeToString(imageInvalid)));
- objects.add(sigFac.newXMLObject(Collections.singletonList(tn), objectId, null, null));
-
- reference = newReference(signatureInfo, "#" + objectId, null, XML_DIGSIG_NS+"Object", null, null);
- references.add(reference);
- }
- }
-
- protected static String getRelationshipReferenceURI(String zipEntryName) {
- return "/"
- + zipEntryName
- + "?ContentType=application/vnd.openxmlformats-package.relationships+xml";
- }
-
- protected static String getResourceReferenceURI(String resourceName, String contentType) {
- return "/" + resourceName + "?ContentType=" + contentType;
- }
-
- protected static boolean isSignedRelationship(String relationshipType) {
- LOG.log(POILogger.DEBUG, "relationship type: " + relationshipType);
- String rt = relationshipType.replaceFirst(".*/relationships/", "");
- return (signed.contains(rt) || rt.endsWith("customXml"));
- }
-
- /**
- * Office 2010 list of signed types (extensions).
- */
- private static final Set<String> signed = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
- "activeXControlBinary", "aFChunk", "attachedTemplate", "attachedToolbars", "audio", "calcChain", "chart", "chartColorStyle",
- "chartLayout", "chartsheet", "chartStyle", "chartUserShapes", "commentAuthors", "comments", "connections", "connectorXml",
- "control", "ctrlProp", "customData", "customData", "customProperty", "customXml", "diagram", "diagramColors",
- "diagramColorsHeader", "diagramData", "diagramDrawing", "diagramLayout", "diagramLayoutHeader", "diagramQuickStyle",
- "diagramQuickStyleHeader", "dialogsheet", "dictionary", "documentParts", "downRev", "drawing", "endnotes", "externalLink",
- "externalLinkPath", "font", "fontTable", "footer", "footnotes", "functionPrototypes", "glossaryDocument", "graphicFrameDoc",
- "groupShapeXml", "handoutMaster", "hdphoto", "header", "hyperlink", "image", "ink", "inkXml", "keyMapCustomizations",
- "legacyDiagramText", "legacyDocTextInfo", "mailMergeHeaderSource", "mailMergeRecipientData", "mailMergeSource", "media",
- "notesMaster", "notesSlide", "numbering", "officeDocument", "officeDocument", "oleObject", "package", "pictureXml",
- "pivotCacheDefinition", "pivotCacheRecords", "pivotTable", "powerPivotData", "presProps", "printerSettings", "queryTable",
- "recipientData", "settings", "shapeXml", "sharedStrings", "sheetMetadata", "slicer", "slicer", "slicerCache", "slicerCache",
- "slide", "slideLayout", "slideMaster", "slideUpdateInfo", "slideUpdateUrl", "smartTags", "styles", "stylesWithEffects",
- "table", "tableSingleCells", "tableStyles", "tags", "theme", "themeOverride", "timeline", "timelineCache", "transform",
- "ui/altText", "ui/buttonSize", "ui/controlID", "ui/description", "ui/enabled", "ui/extensibility", "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", "video", "viewProps", "vmlDrawing",
- "volatileDependencies", "webSettings", "wordVbaData", "worksheet", "wsSortMap", "xlBinaryIndex",
- "xlExternalLinkPath/xlAlternateStartup", "xlExternalLinkPath/xlLibrary", "xlExternalLinkPath/xlPathMissing",
- "xlExternalLinkPath/xlStartup", "xlIntlMacrosheet", "xlMacrosheet", "xmlMaps"
- )));
- }
|