be.fedict.eid.applet.service.signer.ooxml.OOXMLSignatureFacet.java Source code

Java tutorial

Introduction

Here is the source code for be.fedict.eid.applet.service.signer.ooxml.OOXMLSignatureFacet.java

Source

/*
 * eID Applet Project.
 * Copyright (C) 2009 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

/*
 * Copyright (C) 2008-2009 FedICT.
 * This file is part of the eID Applet Project.
 *
 * Licensed 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 be.fedict.eid.applet.service.signer.ooxml;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
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.XMLSignatureFactory;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xml.security.utils.Constants;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import be.fedict.eid.applet.service.signer.DigestAlgo;
import be.fedict.eid.applet.service.signer.SignatureFacet;
import be.fedict.eid.applet.service.signer.jaxb.opc.contenttypes.CTDefault;
import be.fedict.eid.applet.service.signer.jaxb.opc.contenttypes.CTOverride;
import be.fedict.eid.applet.service.signer.jaxb.opc.contenttypes.CTTypes;
import be.fedict.eid.applet.service.signer.jaxb.opc.relationships.CTRelationship;
import be.fedict.eid.applet.service.signer.jaxb.opc.relationships.CTRelationships;
import be.fedict.eid.applet.service.signer.jaxb.opc.relationships.STTargetMode;
import be.fedict.eid.applet.service.signer.time.Clock;
import be.fedict.eid.applet.service.signer.time.LocalClock;

/**
 * Office OpenXML Signature Facet implementation.
 * 
 * @author fcorneli
 * @see http://msdn.microsoft.com/en-us/library/cc313071.aspx
 */
public class OOXMLSignatureFacet implements SignatureFacet {

    private static final Log LOG = LogFactory.getLog(OOXMLSignatureFacet.class);

    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 AbstractOOXMLSignatureService signatureService;

    private final Clock clock;

    private final DigestAlgo digestAlgo;

    /**
     * Main constructor.
     */
    public OOXMLSignatureFacet(AbstractOOXMLSignatureService signatureService) {
        this(signatureService, new LocalClock(), DigestAlgo.SHA1);
    }

    /**
     * Main constructor.
     */
    public OOXMLSignatureFacet(AbstractOOXMLSignatureService signatureService, Clock clock, DigestAlgo digestAlgo) {
        this.signatureService = signatureService;
        this.clock = clock;
        this.digestAlgo = digestAlgo;
    }

    public void preSign(XMLSignatureFactory signatureFactory, Document document, String signatureId,
            List<X509Certificate> signingCertificateChain, List<Reference> references, List<XMLObject> objects)
            throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        LOG.debug("pre sign");
        addManifestObject(signatureFactory, document, signatureId, references, objects);

        addSignatureInfo(signatureFactory, document, signatureId, references, objects);
    }

    private void addManifestObject(XMLSignatureFactory signatureFactory, Document document, String signatureId,
            List<Reference> references, List<XMLObject> objects)
            throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        Manifest manifest = constructManifest(signatureFactory, document);
        String objectId = "idPackageObject"; // really has to be this value.
        List<XMLStructure> objectContent = new LinkedList<XMLStructure>();
        objectContent.add(manifest);

        addSignatureTime(signatureFactory, document, signatureId, objectContent);

        objects.add(signatureFactory.newXMLObject(objectContent, objectId, null, null));

        DigestMethod digestMethod = signatureFactory.newDigestMethod(this.digestAlgo.getXmlAlgoId(), null);
        Reference reference = signatureFactory.newReference("#" + objectId, digestMethod, null,
                "http://www.w3.org/2000/09/xmldsig#Object", null);
        references.add(reference);
    }

    private Manifest constructManifest(XMLSignatureFactory signatureFactory, Document document)
            throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        List<Reference> manifestReferences = new LinkedList<Reference>();

        try {
            addManifestReferences(signatureFactory, document, manifestReferences);
        } catch (Exception e) {
            throw new RuntimeException("error: " + e.getMessage(), e);
        }

        return signatureFactory.newManifest(manifestReferences);
    }

    private void addManifestReferences(XMLSignatureFactory signatureFactory, Document document,
            List<Reference> manifestReferences)
            throws IOException, JAXBException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        CTTypes contentTypes = getContentTypes();
        List<String> relsEntryNames = getRelsEntryNames();
        DigestMethod digestMethod = signatureFactory.newDigestMethod(this.digestAlgo.getXmlAlgoId(), null);
        Set<String> digestedPartNames = new HashSet<String>();
        for (String relsEntryName : relsEntryNames) {
            CTRelationships relationships = getRelationships(relsEntryName);
            List<CTRelationship> relationshipList = relationships.getRelationship();
            RelationshipTransformParameterSpec parameterSpec = new RelationshipTransformParameterSpec();
            for (CTRelationship relationship : relationshipList) {
                String relationshipType = relationship.getType();
                STTargetMode targetMode = relationship.getTargetMode();
                if (null != targetMode) {
                    LOG.debug("TargetMode: " + targetMode.name());
                    if (targetMode == STTargetMode.EXTERNAL) {
                        /*
                         * 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."
                         */
                        continue;
                    }
                }
                if (false == OOXMLSignatureFacet.isSignedRelationship(relationshipType)) {
                    continue;
                }
                String baseUri = "/" + relsEntryName.substring(0, relsEntryName.indexOf("_rels/"));
                String relationshipTarget = relationship.getTarget();
                String partName = FilenameUtils
                        .separatorsToUnix(FilenameUtils.normalize(baseUri + relationshipTarget));
                LOG.debug("part name: " + partName);
                String relationshipId = relationship.getId();
                parameterSpec.addRelationshipReference(relationshipId);
                String contentType = getContentType(contentTypes, partName);
                if (relationshipType.endsWith("customXml")) {
                    if (false == contentType.equals("inkml+xml") && false == contentType.equals("text/xml")) {
                        LOG.debug("skipping customXml with content type: " + contentType);
                        continue;
                    }
                }
                if (false == digestedPartNames.contains(partName)) {
                    /*
                     * We only digest a part once.
                     */
                    Reference reference = signatureFactory.newReference(partName + "?ContentType=" + contentType,
                            digestMethod);
                    manifestReferences.add(reference);
                    digestedPartNames.add(partName);
                }
            }
            if (false == parameterSpec.getSourceIds().isEmpty()) {
                List<Transform> transforms = new LinkedList<Transform>();
                transforms.add(
                        signatureFactory.newTransform(RelationshipTransformService.TRANSFORM_URI, parameterSpec));
                transforms.add(signatureFactory.newTransform(CanonicalizationMethod.INCLUSIVE,
                        (TransformParameterSpec) null));
                Reference reference = signatureFactory.newReference(
                        "/" + relsEntryName
                                + "?ContentType=application/vnd.openxmlformats-package.relationships+xml",
                        digestMethod, transforms, null, null);

                manifestReferences.add(reference);
            }
        }
    }

    /**
     * According to ECMA-376, Part 2. 10.1.2 Mapping Content Types.
     * 
     * @param contentTypes
     * @param partName
     * @return
     */
    private String getContentType(CTTypes contentTypes, String partName) {
        List<Object> defaultOrOverrideList = contentTypes.getDefaultOrOverride();
        for (Object defaultOrOverride : defaultOrOverrideList) {
            if (defaultOrOverride instanceof CTOverride) {
                CTOverride override = (CTOverride) defaultOrOverride;
                if (partName.equals(override.getPartName())) {
                    return override.getContentType();
                }
            }
        }
        for (Object defaultOrOverride : defaultOrOverrideList) {
            if (defaultOrOverride instanceof CTDefault) {
                CTDefault ctDefault = (CTDefault) defaultOrOverride;
                if (partName.endsWith(ctDefault.getExtension())) {
                    return ctDefault.getContentType();
                }
            }
        }
        return null;
    }

    private CTRelationships getRelationships(String relsEntryName) throws IOException, JAXBException {
        URL ooxmlUrl = this.signatureService.getOfficeOpenXMLDocumentURL();
        ZipInputStream zipInputStream = new ZipInputStream(ooxmlUrl.openStream());
        ZipEntry zipEntry;
        InputStream relationshipsInputStream = null;
        while (null != (zipEntry = zipInputStream.getNextEntry())) {
            if (false == relsEntryName.equals(zipEntry.getName())) {
                continue;
            }
            relationshipsInputStream = zipInputStream;
            break;
        }
        if (null == relationshipsInputStream) {
            return null;
        }
        JAXBContext jaxbContext = JAXBContext
                .newInstance(be.fedict.eid.applet.service.signer.jaxb.opc.relationships.ObjectFactory.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        JAXBElement<CTRelationships> relationshipsElement = (JAXBElement<CTRelationships>) unmarshaller
                .unmarshal(relationshipsInputStream);
        return relationshipsElement.getValue();
    }

    private CTTypes getContentTypes() throws IOException, JAXBException {
        URL ooxmlUrl = this.signatureService.getOfficeOpenXMLDocumentURL();
        ZipInputStream zipInputStream = new ZipInputStream(ooxmlUrl.openStream());
        ZipEntry zipEntry;
        InputStream contentTypesInputStream = null;
        while (null != (zipEntry = zipInputStream.getNextEntry())) {
            if (!"[Content_Types].xml".equals(zipEntry.getName())) {
                continue;
            }
            contentTypesInputStream = zipInputStream;
            break;
        }
        if (null == contentTypesInputStream) {
            return null;
        }
        JAXBContext jaxbContext = JAXBContext
                .newInstance(be.fedict.eid.applet.service.signer.jaxb.opc.contenttypes.ObjectFactory.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        JAXBElement<CTTypes> contentTypesElement = (JAXBElement<CTTypes>) unmarshaller
                .unmarshal(contentTypesInputStream);
        return contentTypesElement.getValue();
    }

    private List<String> getRelsEntryNames() throws IOException {
        List<String> relsEntryNames = new LinkedList<String>();
        URL ooxmlUrl = this.signatureService.getOfficeOpenXMLDocumentURL();
        InputStream inputStream = ooxmlUrl.openStream();
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        ZipEntry zipEntry;
        while (null != (zipEntry = zipInputStream.getNextEntry())) {
            String zipEntryName = zipEntry.getName();
            if (false == zipEntryName.endsWith(".rels")) {
                continue;
            }
            relsEntryNames.add(zipEntryName);
        }
        return relsEntryNames;
    }

    private void addSignatureTime(XMLSignatureFactory signatureFactory, Document document, String signatureId,
            List<XMLStructure> objectContent) {
        /*
         * SignatureTime
         */
        Element signatureTimeElement = document.createElementNS(OOXML_DIGSIG_NS, "mdssi:SignatureTime");
        signatureTimeElement.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:mdssi", OOXML_DIGSIG_NS);
        Element formatElement = document.createElementNS(OOXML_DIGSIG_NS, "mdssi:Format");
        formatElement.setTextContent("YYYY-MM-DDThh:mm:ssTZD");
        signatureTimeElement.appendChild(formatElement);
        Element valueElement = document.createElementNS(OOXML_DIGSIG_NS, "mdssi:Value");
        Date now = this.clock.getTime();
        DateTime dateTime = new DateTime(now.getTime(), DateTimeZone.UTC);
        DateTimeFormatter fmt = ISODateTimeFormat.dateTimeNoMillis();
        String nowStr = fmt.print(dateTime);
        LOG.debug("now: " + nowStr);
        valueElement.setTextContent(nowStr);
        signatureTimeElement.appendChild(valueElement);

        List<XMLStructure> signatureTimeContent = new LinkedList<XMLStructure>();
        signatureTimeContent.add(new DOMStructure(signatureTimeElement));
        SignatureProperty signatureTimeSignatureProperty = signatureFactory
                .newSignatureProperty(signatureTimeContent, "#" + signatureId, "idSignatureTime");
        List<SignatureProperty> signaturePropertyContent = new LinkedList<SignatureProperty>();
        signaturePropertyContent.add(signatureTimeSignatureProperty);
        SignatureProperties signatureProperties = signatureFactory.newSignatureProperties(signaturePropertyContent,
                "id-signature-time-" + UUID.randomUUID().toString());
        objectContent.add(signatureProperties);
    }

    private void addSignatureInfo(XMLSignatureFactory signatureFactory, Document document, String signatureId,
            List<Reference> references, List<XMLObject> objects)
            throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
        List<XMLStructure> objectContent = new LinkedList<XMLStructure>();

        Element signatureInfoElement = document.createElementNS(OFFICE_DIGSIG_NS, "SignatureInfoV1");
        signatureInfoElement.setAttributeNS(Constants.NamespaceSpecNS, "xmlns", OFFICE_DIGSIG_NS);

        Element setupIDElement = document.createElementNS(OFFICE_DIGSIG_NS, "SetupID");

        signatureInfoElement.appendChild(setupIDElement);

        Element signatureTextElement = document.createElementNS(OFFICE_DIGSIG_NS, "SignatureText");

        signatureInfoElement.appendChild(signatureTextElement);

        Element signatureImageElement = document.createElementNS(OFFICE_DIGSIG_NS, "SignatureImage");

        signatureInfoElement.appendChild(signatureImageElement);

        Element signatureCommentsElement = document.createElementNS(OFFICE_DIGSIG_NS, "SignatureComments");

        signatureInfoElement.appendChild(signatureCommentsElement);

        Element windowsVersionElement = document.createElementNS(OFFICE_DIGSIG_NS, "WindowsVersion");
        windowsVersionElement.setTextContent("6.1");
        signatureInfoElement.appendChild(windowsVersionElement);

        Element officeVersionElement = document.createElementNS(OFFICE_DIGSIG_NS, "OfficeVersion");
        officeVersionElement.setTextContent("15.0");
        signatureInfoElement.appendChild(officeVersionElement);

        Element applicationVersionElement = document.createElementNS(OFFICE_DIGSIG_NS, "ApplicationVersion");
        applicationVersionElement.setTextContent("15.0");
        signatureInfoElement.appendChild(applicationVersionElement);

        Element monitorsElement = document.createElementNS(OFFICE_DIGSIG_NS, "Monitors");
        monitorsElement.setTextContent("1");
        signatureInfoElement.appendChild(monitorsElement);

        Element horizontalResolutionElement = document.createElementNS(OFFICE_DIGSIG_NS, "HorizontalResolution");
        horizontalResolutionElement.setTextContent("1366");
        signatureInfoElement.appendChild(horizontalResolutionElement);

        Element verticalResolutionElement = document.createElementNS(OFFICE_DIGSIG_NS, "VerticalResolution");
        verticalResolutionElement.setTextContent("768");
        signatureInfoElement.appendChild(verticalResolutionElement);

        Element colorDepthElement = document.createElementNS(OFFICE_DIGSIG_NS, "ColorDepth");
        colorDepthElement.setTextContent("32");
        signatureInfoElement.appendChild(colorDepthElement);

        Element signatureProviderIdElement = document.createElementNS(OFFICE_DIGSIG_NS, "SignatureProviderId");
        signatureProviderIdElement.setTextContent("{00000000-0000-0000-0000-000000000000}");
        signatureInfoElement.appendChild(signatureProviderIdElement);

        Element signatureProviderUrlElement = document.createElementNS(OFFICE_DIGSIG_NS, "SignatureProviderUrl");
        signatureInfoElement.appendChild(signatureProviderUrlElement);

        Element signatureProviderDetailsElement = document.createElementNS(OFFICE_DIGSIG_NS,
                "SignatureProviderDetails");
        signatureProviderDetailsElement.setTextContent("9");
        signatureInfoElement.appendChild(signatureProviderDetailsElement);

        Element manifestHashAlgorithmElement = document.createElementNS(OFFICE_DIGSIG_NS, "ManifestHashAlgorithm");
        manifestHashAlgorithmElement.setTextContent("http://www.w3.org/2000/09/xmldsig#sha1");
        signatureInfoElement.appendChild(manifestHashAlgorithmElement);

        Element signatureTypeElement = document.createElementNS(OFFICE_DIGSIG_NS, "SignatureType");
        signatureTypeElement.setTextContent("1");
        signatureInfoElement.appendChild(signatureTypeElement);

        List<XMLStructure> signatureInfoContent = new LinkedList<XMLStructure>();
        signatureInfoContent.add(new DOMStructure(signatureInfoElement));
        SignatureProperty signatureInfoSignatureProperty = signatureFactory
                .newSignatureProperty(signatureInfoContent, "#" + signatureId, "idOfficeV1Details");

        List<SignatureProperty> signaturePropertyContent = new LinkedList<SignatureProperty>();
        signaturePropertyContent.add(signatureInfoSignatureProperty);
        SignatureProperties signatureProperties = signatureFactory.newSignatureProperties(signaturePropertyContent,
                null);
        objectContent.add(signatureProperties);

        String objectId = "idOfficeObject";
        objects.add(signatureFactory.newXMLObject(objectContent, objectId, null, null));

        DigestMethod digestMethod = signatureFactory.newDigestMethod(this.digestAlgo.getXmlAlgoId(), null);
        Reference reference = signatureFactory.newReference("#" + objectId, digestMethod, null,
                "http://www.w3.org/2000/09/xmldsig#Object", null);
        references.add(reference);
    }

    protected Document loadDocument(String zipEntryName)
            throws IOException, ParserConfigurationException, SAXException {
        Document document = findDocument(zipEntryName);
        if (null != document) {
            return document;
        }
        throw new RuntimeException("ZIP entry not found: " + zipEntryName);
    }

    protected Document findDocument(String zipEntryName)
            throws IOException, ParserConfigurationException, SAXException {
        URL ooxmlUrl = this.signatureService.getOfficeOpenXMLDocumentURL();
        InputStream inputStream = ooxmlUrl.openStream();
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        ZipEntry zipEntry;
        while (null != (zipEntry = zipInputStream.getNextEntry())) {
            if (false == zipEntryName.equals(zipEntry.getName())) {
                continue;
            }
            Document document = loadDocument(zipInputStream);
            return document;
        }
        return null;
    }

    public static Document loadDocument(InputStream documentInputStream)
            throws ParserConfigurationException, SAXException, IOException {
        InputSource inputSource = new InputSource(documentInputStream);
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setNamespaceAware(true);
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        return documentBuilder.parse(inputSource);
    }

    public void postSign(Element signatureElement, List<X509Certificate> signingCertificateChain) {
        // empty
    }

    public static String getRelationshipReferenceURI(String zipEntryName) {

        return "/" + zipEntryName + "?ContentType=application/vnd.openxmlformats-package.relationships+xml";
    }

    public static String getResourceReferenceURI(String resourceName, String contentType) {

        return "/" + resourceName + "?ContentType=" + contentType;
    }

    public static 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" };

    public static boolean isSignedRelationship(String relationshipType) {
        LOG.debug("relationship type: " + relationshipType);
        for (String signedTypeExtension : signed) {
            if (relationshipType.endsWith(signedTypeExtension)) {
                return true;
            }
        }
        if (relationshipType.endsWith("customXml")) {
            LOG.debug("customXml relationship type");
            return true;
        }
        return false;
    }

    /**
     * Office 2010 list of signed types (extensions).
     */
    public static String[] signed = { "powerPivotData", //
            "activeXControlBinary", //
            "attachedToolbars", //
            "connectorXml", //
            "downRev", //
            "functionPrototypes", //
            "graphicFrameDoc", //
            "groupShapeXml", //
            "ink", //
            "keyMapCustomizations", //
            "legacyDiagramText", //
            "legacyDocTextInfo", //
            "officeDocument", //
            "pictureXml", //
            "shapeXml", //
            "smartTags", //
            "ui/altText", //
            "ui/buttonSize", //
            "ui/controlID", //
            "ui/description", //
            "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" //
    };
}