You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by on...@apache.org on 2016/07/02 05:01:43 UTC

svn commit: r1751022 - /poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java

Author: onealj
Date: Sat Jul  2 05:01:43 2016
New Revision: 1751022

URL: http://svn.apache.org/viewvc?rev=1751022&view=rev
Log:
+svn:eol-style=native

Modified:
    poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java   (contents, props changed)

Modified: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java?rev=1751022&r1=1751021&r2=1751022&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java Sat Jul  2 05:01:43 2016
@@ -1,50 +1,50 @@
-/* ====================================================================
-   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;
-
+/* ====================================================================
+   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;
+
 import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
 import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_DIGSIG_NS;
 
 import javax.crypto.Cipher;
 import javax.xml.crypto.MarshalException;
 import javax.xml.crypto.URIDereferencer;
-import javax.xml.crypto.XMLStructure;
-import javax.xml.crypto.dsig.CanonicalizationMethod;
-import javax.xml.crypto.dsig.Manifest;
-import javax.xml.crypto.dsig.Reference;
-import javax.xml.crypto.dsig.SignatureMethod;
-import javax.xml.crypto.dsig.SignedInfo;
-import javax.xml.crypto.dsig.XMLObject;
-import javax.xml.crypto.dsig.XMLSignContext;
-import javax.xml.crypto.dsig.XMLSignature;
-import javax.xml.crypto.dsig.XMLSignatureException;
-import javax.xml.crypto.dsig.XMLSignatureFactory;
-import javax.xml.crypto.dsig.XMLValidateContext;
-import javax.xml.crypto.dsig.dom.DOMSignContext;
-import javax.xml.crypto.dsig.dom.DOMValidateContext;
-import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
+import javax.xml.crypto.XMLStructure;
+import javax.xml.crypto.dsig.CanonicalizationMethod;
+import javax.xml.crypto.dsig.Manifest;
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.SignatureMethod;
+import javax.xml.crypto.dsig.SignedInfo;
+import javax.xml.crypto.dsig.XMLObject;
+import javax.xml.crypto.dsig.XMLSignContext;
+import javax.xml.crypto.dsig.XMLSignature;
+import javax.xml.crypto.dsig.XMLSignatureException;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.XMLValidateContext;
+import javax.xml.crypto.dsig.dom.DOMSignContext;
+import javax.xml.crypto.dsig.dom.DOMValidateContext;
+import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathFactory;
@@ -67,97 +67,97 @@ import java.util.NoSuchElementException;
 
 import org.apache.jcp.xml.dsig.internal.dom.DOMReference;
 import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
-import org.apache.poi.EncryptedDocumentException;
-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.PackageRelationshipTypes;
-import org.apache.poi.openxml4j.opc.PackagingURIHelper;
-import org.apache.poi.openxml4j.opc.TargetMode;
-import org.apache.poi.poifs.crypt.ChainingMode;
-import org.apache.poi.poifs.crypt.CipherAlgorithm;
-import org.apache.poi.poifs.crypt.CryptoFunctions;
-import org.apache.poi.poifs.crypt.dsig.SignatureConfig.SignatureConfigurable;
-import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet;
-import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService;
-import org.apache.poi.util.DocumentHelper;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
-import org.apache.xml.security.Init;
-import org.apache.xml.security.utils.Base64;
-import org.apache.xmlbeans.XmlException;
-import org.apache.xmlbeans.XmlOptions;
-import org.w3.x2000.x09.xmldsig.SignatureDocument;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.w3c.dom.events.EventListener;
-import org.w3c.dom.events.EventTarget;
-
-
-/**
- * <p>This class is the default entry point for XML signatures and can be used for
- * validating an existing signed office document and signing a office document.</p>
- * 
- * <p><b>Validating a signed office document</b></p>
- * 
- * <pre>
- * OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ);
- * SignatureConfig sic = new SignatureConfig();
- * sic.setOpcPackage(pkg);
- * SignatureInfo si = new SignatureInfo();
- * si.setSignatureConfig(sic);
- * boolean isValid = si.validate();
- * ...
- * </pre>
- * 
- * <p><b>Signing an office document</b></p>
- * 
- * <pre>
- * // loading the keystore - pkcs12 is used here, but of course jks &amp; co are also valid
- * // the keystore needs to contain a private key and it's certificate having a
- * // 'digitalSignature' key usage
- * char password[] = "test".toCharArray();
- * File file = new File("test.pfx");
- * KeyStore keystore = KeyStore.getInstance("PKCS12");
- * FileInputStream fis = new FileInputStream(file);
- * keystore.load(fis, password);
- * fis.close();
- * 
- * // extracting private key and certificate
- * String alias = "xyz"; // alias of the keystore entry
- * Key key = keystore.getKey(alias, password);
- * X509Certificate x509 = (X509Certificate)keystore.getCertificate(alias);
- * 
- * // filling the SignatureConfig entries (minimum fields, more options are available ...)
- * SignatureConfig signatureConfig = new SignatureConfig();
- * signatureConfig.setKey(keyPair.getPrivate());
- * signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
- * OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ_WRITE);
- * signatureConfig.setOpcPackage(pkg);
- * 
- * // adding the signature document to the package
- * SignatureInfo si = new SignatureInfo();
- * si.setSignatureConfig(signatureConfig);
- * si.confirmSignature();
- * // optionally verify the generated signature
- * boolean b = si.verifySignature();
- * assert (b);
- * // write the changes back to disc
- * pkg.close();
- * </pre>
- * 
- * <p><b>Implementation notes:</b></p>
- * 
- * <p>Although there's a XML signature implementation in the Oracle JDKs 6 and higher,
- * compatibility with IBM JDKs is also in focus (... but maybe not thoroughly tested ...).
- * Therefore we are using the Apache Santuario libs (xmlsec) instead of the built-in classes,
- * as the compatibility seems to be provided there.</p>
- * 
+import org.apache.poi.EncryptedDocumentException;
+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.PackageRelationshipTypes;
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;
+import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.poifs.crypt.ChainingMode;
+import org.apache.poi.poifs.crypt.CipherAlgorithm;
+import org.apache.poi.poifs.crypt.CryptoFunctions;
+import org.apache.poi.poifs.crypt.dsig.SignatureConfig.SignatureConfigurable;
+import org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet;
+import org.apache.poi.poifs.crypt.dsig.services.RelationshipTransformService;
+import org.apache.poi.util.DocumentHelper;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.xml.security.Init;
+import org.apache.xml.security.utils.Base64;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlOptions;
+import org.w3.x2000.x09.xmldsig.SignatureDocument;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.events.EventListener;
+import org.w3c.dom.events.EventTarget;
+
+
+/**
+ * <p>This class is the default entry point for XML signatures and can be used for
+ * validating an existing signed office document and signing a office document.</p>
+ * 
+ * <p><b>Validating a signed office document</b></p>
+ * 
+ * <pre>
+ * OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ);
+ * SignatureConfig sic = new SignatureConfig();
+ * sic.setOpcPackage(pkg);
+ * SignatureInfo si = new SignatureInfo();
+ * si.setSignatureConfig(sic);
+ * boolean isValid = si.validate();
+ * ...
+ * </pre>
+ * 
+ * <p><b>Signing an office document</b></p>
+ * 
+ * <pre>
+ * // loading the keystore - pkcs12 is used here, but of course jks &amp; co are also valid
+ * // the keystore needs to contain a private key and it's certificate having a
+ * // 'digitalSignature' key usage
+ * char password[] = "test".toCharArray();
+ * File file = new File("test.pfx");
+ * KeyStore keystore = KeyStore.getInstance("PKCS12");
+ * FileInputStream fis = new FileInputStream(file);
+ * keystore.load(fis, password);
+ * fis.close();
+ * 
+ * // extracting private key and certificate
+ * String alias = "xyz"; // alias of the keystore entry
+ * Key key = keystore.getKey(alias, password);
+ * X509Certificate x509 = (X509Certificate)keystore.getCertificate(alias);
+ * 
+ * // filling the SignatureConfig entries (minimum fields, more options are available ...)
+ * SignatureConfig signatureConfig = new SignatureConfig();
+ * signatureConfig.setKey(keyPair.getPrivate());
+ * signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
+ * OPCPackage pkg = OPCPackage.open(..., PackageAccess.READ_WRITE);
+ * signatureConfig.setOpcPackage(pkg);
+ * 
+ * // adding the signature document to the package
+ * SignatureInfo si = new SignatureInfo();
+ * si.setSignatureConfig(signatureConfig);
+ * si.confirmSignature();
+ * // optionally verify the generated signature
+ * boolean b = si.verifySignature();
+ * assert (b);
+ * // write the changes back to disc
+ * pkg.close();
+ * </pre>
+ * 
+ * <p><b>Implementation notes:</b></p>
+ * 
+ * <p>Although there's a XML signature implementation in the Oracle JDKs 6 and higher,
+ * compatibility with IBM JDKs is also in focus (... but maybe not thoroughly tested ...).
+ * Therefore we are using the Apache Santuario libs (xmlsec) instead of the built-in classes,
+ * as the compatibility seems to be provided there.</p>
+ * 
  * <p>To use SignatureInfo and its sibling classes, you'll need to have the following libs
  * in the classpath:</p>
  * <ul>
@@ -165,517 +165,517 @@ import org.w3c.dom.events.EventTarget;
  * <li>Apache Santuario "xmlsec" (tested against 2.0.5)</li>
  * <li>and slf4j-api (tested against 1.7.12)</li>
  * </ul>
- */
-public class SignatureInfo implements SignatureConfigurable {
-
-    private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class);
-    private static boolean isInitialized = false;
-    
-    private SignatureConfig signatureConfig;
-
-    public class SignaturePart {
-        private final PackagePart signaturePart;
-        private X509Certificate signer;
-        private List<X509Certificate> certChain;
-        
-        private SignaturePart(PackagePart signaturePart) {
-            this.signaturePart = signaturePart;
-        }
-        
-        /**
-         * @return the package part containing the signature
-         */
-        public PackagePart getPackagePart() {
-            return signaturePart;
-        }
-        
-        /**
-         * @return the signer certificate
-         */
-        public X509Certificate getSigner() {
-            return signer;
-        }
-        
-        /**
-         * @return the certificate chain of the signer
-         */
-        public List<X509Certificate> getCertChain() {
-            return certChain;
-        }
-        
-        /**
-         * Helper method for examining the xml signature
-         *
-         * @return the xml signature document
-         * @throws IOException if the xml signature doesn't exist or can't be read
-         * @throws XmlException if the xml signature is malformed
-         */
-        public SignatureDocument getSignatureDocument() throws IOException, XmlException {
-            // TODO: check for XXE
-            return SignatureDocument.Factory.parse(signaturePart.getInputStream(), DEFAULT_XML_OPTIONS);
-        }
-        
-        /**
-         * @return true, when the xml signature is valid, false otherwise
-         * 
-         * @throws EncryptedDocumentException if the signature can't be extracted or if its malformed
-         */
-        @SuppressWarnings("unchecked")
-        public boolean validate() {
-            KeyInfoKeySelector keySelector = new KeyInfoKeySelector();
-            try {
-                Document doc = DocumentHelper.readDocument(signaturePart.getInputStream());
-                XPath xpath = XPathFactory.newInstance().newXPath();
-                NodeList nl = (NodeList)xpath.compile("//*[@Id]").evaluate(doc, XPathConstants.NODESET);
-                for (int i=0; i<nl.getLength(); i++) {
-                    ((Element)nl.item(i)).setIdAttribute("Id", true);
-                }
-                
-                DOMValidateContext domValidateContext = new DOMValidateContext(keySelector, doc);
-                domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", Boolean.TRUE);
-                domValidateContext.setURIDereferencer(signatureConfig.getUriDereferencer());
-                brokenJvmWorkaround(domValidateContext);
-    
-                XMLSignatureFactory xmlSignatureFactory = signatureConfig.getSignatureFactory();
-                XMLSignature xmlSignature = xmlSignatureFactory.unmarshalXMLSignature(domValidateContext);
-                
-                // TODO: replace with property when xml-sec patch is applied
-                for (Reference ref : (List<Reference>)xmlSignature.getSignedInfo().getReferences()) {
-                    SignatureFacet.brokenJvmWorkaround(ref);
-                }
-                for (XMLObject xo : (List<XMLObject>)xmlSignature.getObjects()) {
-                    for (XMLStructure xs : (List<XMLStructure>)xo.getContent()) {
-                        if (xs instanceof Manifest) {
-                           for (Reference ref : (List<Reference>)((Manifest)xs).getReferences()) {
-                               SignatureFacet.brokenJvmWorkaround(ref);
-                           }
-                        }
-                    }
-                }
-                
-                boolean valid = xmlSignature.validate(domValidateContext);
-
-                if (valid) {
-                    signer = keySelector.getSigner();
-                    certChain = keySelector.getCertChain();
-                }
-                
-                return valid;
-            } catch (Exception e) {
-                String s = "error in marshalling and validating the signature";
-                LOG.log(POILogger.ERROR, s, e);
-                throw new EncryptedDocumentException(s, e);
-            }
-        }
-    }
-    
-    /**
-     * Constructor initializes xml signature environment, if it hasn't been initialized before
-     */
-    public SignatureInfo() {
-        initXmlProvider();        
-    }
-    
-    /**
-     * @return the signature config
-     */
-    public SignatureConfig getSignatureConfig() {
-        return signatureConfig;
-    }
-
-    /**
-     * @param signatureConfig the signature config, needs to be set before a SignatureInfo object is used
-     */
-    public void setSignatureConfig(SignatureConfig signatureConfig) {
-        this.signatureConfig = signatureConfig;
-    }
-
-    /**
-     * @return true, if first signature part is valid
-     */
-    public boolean verifySignature() {
-        // http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
-        for (SignaturePart sp : getSignatureParts()){
-            // only validate first part
-            return sp.validate();
-        }
-        return false;
-    }
-
-    /**
-     * add the xml signature to the document
-     *
-     * @throws XMLSignatureException
-     * @throws MarshalException
-     */
-    public void confirmSignature() throws XMLSignatureException, MarshalException {
-        Document document = DocumentHelper.createDocument();
-        
-        // operate
-        DigestInfo digestInfo = preSign(document, null);
-
-        // setup: key material, signature value
-        byte[] signatureValue = signDigest(digestInfo.digestValue);
-        
-        // operate: postSign
-        postSign(document, signatureValue);
-    }
-
-    /**
-     * Sign (encrypt) the digest with the private key.
-     * Currently only rsa is supported.
-     *
-     * @param digest the hashed input
-     * @return the encrypted hash
-     */
-    public byte[] signDigest(byte digest[]) {
-        Cipher cipher = CryptoFunctions.getCipher(signatureConfig.getKey(), CipherAlgorithm.rsa
-            , ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding");
-            
-        try {
-            ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();
-            digestInfoValueBuf.write(signatureConfig.getHashMagic());
-            digestInfoValueBuf.write(digest);
-            byte[] digestInfoValue = digestInfoValueBuf.toByteArray();
-            byte[] signatureValue = cipher.doFinal(digestInfoValue);
-            return signatureValue;
-        } catch (Exception e) {
-            throw new EncryptedDocumentException(e);
-        }
-    }
-    
-    /**
-     * @return a signature part for each signature document.
-     * the parts can be validated independently.
-     */
-    public Iterable<SignaturePart> getSignatureParts() {
-        signatureConfig.init(true);
-        return new Iterable<SignaturePart>() {
-            public Iterator<SignaturePart> iterator() {
-                return new Iterator<SignaturePart>() {
-                    OPCPackage pkg = signatureConfig.getOpcPackage();
-                    Iterator<PackageRelationship> sigOrigRels = 
-                        pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN).iterator();
-                    Iterator<PackageRelationship> sigRels = null;
-                    PackagePart sigPart = null;
-                    
-                    public boolean hasNext() {
-                        while (sigRels == null || !sigRels.hasNext()) {
-                            if (!sigOrigRels.hasNext()) return false;
-                            sigPart = pkg.getPart(sigOrigRels.next());
-                            LOG.log(POILogger.DEBUG, "Digital Signature Origin part", sigPart);
-                            try {
-                                sigRels = sigPart.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE).iterator();
-                            } catch (InvalidFormatException e) {
-                                LOG.log(POILogger.WARN, "Reference to signature is invalid.", e);
-                            }
-                        }
-                        return true;
-                    }
-                    
-                    public SignaturePart next() {
-                        PackagePart sigRelPart = null;
-                        do {
-                            try {
-                                if (!hasNext()) throw new NoSuchElementException();
-                                sigRelPart = sigPart.getRelatedPart(sigRels.next()); 
-                                LOG.log(POILogger.DEBUG, "XML Signature part", sigRelPart);
-                            } catch (InvalidFormatException e) {
-                                LOG.log(POILogger.WARN, "Reference to signature is invalid.", e);
-                            }
-                        } while (sigPart == null);
-                        return new SignaturePart(sigRelPart);
-                    }
-                    
-                    public void remove() {
-                        throw new UnsupportedOperationException();
-                    }
-                };
-            }
-        };
-    }
-    
-    /**
-     * Initialize the xml signing environment and the bouncycastle provider 
-     */
-    protected static synchronized void initXmlProvider() {
-        if (isInitialized) return;
-        isInitialized = true;
-        
-        try {
-            Init.init();
-            RelationshipTransformService.registerDsigProvider();
-            CryptoFunctions.registerBouncyCastle();
-        } catch (Exception e) {
-            throw new RuntimeException("Xml & BouncyCastle-Provider initialization failed", e);
-        }
-    }
-    
-    /**
-     * Helper method for adding informations before the signing.
-     * Normally {@link #confirmSignature()} is sufficient to be used.
-     */
-    @SuppressWarnings("unchecked")
-    public DigestInfo preSign(Document document, List<DigestInfo> digestInfos)
-    throws XMLSignatureException, MarshalException {
-        signatureConfig.init(false);
-        
-        // it's necessary to explicitly set the mdssi namespace, but the sign() method has no
-        // normal way to interfere with, so we need to add the namespace under the hand ...
-        EventTarget target = (EventTarget)document;
-        EventListener creationListener = signatureConfig.getSignatureMarshalListener();
-        if (creationListener != null) {
-            if (creationListener instanceof SignatureMarshalListener) {
-                ((SignatureMarshalListener)creationListener).setEventTarget(target);
-            }
-            SignatureMarshalListener.setListener(target, creationListener, true);
-        }
-        
-        /*
-         * Signature context construction.
-         */
-        XMLSignContext xmlSignContext = new DOMSignContext(signatureConfig.getKey(), document);
-        URIDereferencer uriDereferencer = signatureConfig.getUriDereferencer();
-        if (null != uriDereferencer) {
-            xmlSignContext.setURIDereferencer(uriDereferencer);
-        }
-
-        for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {
-            xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());
-        }
-        xmlSignContext.setDefaultNamespacePrefix("");
-        // signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));
-        
-        brokenJvmWorkaround(xmlSignContext);
-        
-        XMLSignatureFactory signatureFactory = signatureConfig.getSignatureFactory();
-
-        /*
-         * Add ds:References that come from signing client local files.
-         */
-        List<Reference> references = new ArrayList<Reference>();
-        for (DigestInfo digestInfo : safe(digestInfos)) {
-            byte[] documentDigestValue = digestInfo.digestValue;
-
-            String uri = new File(digestInfo.description).getName();
-            Reference reference = SignatureFacet.newReference
-                (uri, null, null, null, documentDigestValue, signatureConfig);
-            references.add(reference);
-        }
-
-        /*
-         * Invoke the signature facets.
-         */
-        List<XMLObject> objects = new ArrayList<XMLObject>();
-        for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
-            LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName());
-            signatureFacet.preSign(document, references, objects);
-        }
-
-        /*
-         * ds:SignedInfo
-         */
-        SignedInfo signedInfo;
-        try {
-            SignatureMethod signatureMethod = signatureFactory.newSignatureMethod
-                (signatureConfig.getSignatureMethodUri(), null);
-            CanonicalizationMethod canonicalizationMethod = signatureFactory
-                .newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),
-                (C14NMethodParameterSpec) null);
-            signedInfo = signatureFactory.newSignedInfo(
-                canonicalizationMethod, signatureMethod, references);
-        } catch (GeneralSecurityException e) {
-            throw new XMLSignatureException(e);
-        }
-
-        /*
-         * JSR105 ds:Signature creation
-         */
-        String signatureValueId = signatureConfig.getPackageSignatureId() + "-signature-value";
-        javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory
-            .newXMLSignature(signedInfo, null, objects, signatureConfig.getPackageSignatureId(),
-            signatureValueId);
-
-        /*
-         * ds:Signature Marshalling.
-         */
-        xmlSignature.sign(xmlSignContext);
-
-        /*
-         * Completion of undigested ds:References in the ds:Manifests.
-         */
-        for (XMLObject object : objects) {
-            LOG.log(POILogger.DEBUG, "object java type: " + object.getClass().getName());
-            List<XMLStructure> objectContentList = object.getContent();
-            for (XMLStructure objectContent : objectContentList) {
-                LOG.log(POILogger.DEBUG, "object content java type: " + objectContent.getClass().getName());
-                if (!(objectContent instanceof Manifest)) continue;
-                Manifest manifest = (Manifest) objectContent;
-                List<Reference> manifestReferences = manifest.getReferences();
-                for (Reference manifestReference : manifestReferences) {
-                    if (manifestReference.getDigestValue() != null) continue;
-
-                    DOMReference manifestDOMReference = (DOMReference)manifestReference;
-                    manifestDOMReference.digest(xmlSignContext);
-                }
-            }
-        }
-
-        /*
-         * Completion of undigested ds:References.
-         */
-        List<Reference> signedInfoReferences = signedInfo.getReferences();
-        for (Reference signedInfoReference : signedInfoReferences) {
-            DOMReference domReference = (DOMReference)signedInfoReference;
-
-            // ds:Reference with external digest value
-            if (domReference.getDigestValue() != null) continue;
-            
-            domReference.digest(xmlSignContext);
-        }
-
-        /*
-         * Calculation of XML signature digest value.
-         */
-        DOMSignedInfo domSignedInfo = (DOMSignedInfo)signedInfo;
-        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
-        domSignedInfo.canonicalize(xmlSignContext, dataStream);
-        byte[] octets = dataStream.toByteArray();
-
-        /*
-         * TODO: we could be using DigestOutputStream here to optimize memory
-         * usage.
-         */
-
-        MessageDigest md = CryptoFunctions.getMessageDigest(signatureConfig.getDigestAlgo());
-        byte[] digestValue = md.digest(octets);
-        
-        
-        String description = signatureConfig.getSignatureDescription();
-        return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);
-    }
-
-    /**
-     * Helper method for adding informations after the signing.
-     * Normally {@link #confirmSignature()} is sufficient to be used.
-     */
-    public void postSign(Document document, byte[] signatureValue)
-    throws MarshalException {
-        LOG.log(POILogger.DEBUG, "postSign");
-
-        /*
-         * Check ds:Signature node.
-         */
-        String signatureId = signatureConfig.getPackageSignatureId();
-        if (!signatureId.equals(document.getDocumentElement().getAttribute("Id"))) {
-            throw new RuntimeException("ds:Signature not found for @Id: " + signatureId);
-        }
-
-        /*
-         * Insert signature value into the ds:SignatureValue element
-         */
-        NodeList sigValNl = document.getElementsByTagNameNS(XML_DIGSIG_NS, "SignatureValue");
-        if (sigValNl.getLength() != 1) {
-            throw new RuntimeException("preSign has to be called before postSign");
-        }
-        sigValNl.item(0).setTextContent(Base64.encode(signatureValue));
-
-        /*
-         * Allow signature facets to inject their own stuff.
-         */
-        for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
-            signatureFacet.postSign(document);
-        }
-
-        writeDocument(document);
-    }
-
-    /**
-     * Write XML signature into the OPC package
-     *
-     * @param document the xml signature document
-     * @throws MarshalException
-     */
-    protected void writeDocument(Document document) throws MarshalException {
-        XmlOptions xo = new XmlOptions();
-        Map<String,String> namespaceMap = new HashMap<String,String>();
-        for(Map.Entry<String,String> entry : signatureConfig.getNamespacePrefixes().entrySet()){
-            namespaceMap.put(entry.getValue(), entry.getKey());
-        }        
-        xo.setSaveSuggestedPrefixes(namespaceMap);
-        xo.setUseDefaultNamespace();
-
-        LOG.log(POILogger.DEBUG, "output signed Office OpenXML document");
-
-        /*
-         * Copy the original OOXML content to the signed OOXML package. During
-         * copying some files need to changed.
-         */
-        OPCPackage pkg = signatureConfig.getOpcPackage();
-
-        PackagePartName sigPartName, sigsPartName;
-        try {
-            // <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
-            sigPartName = PackagingURIHelper.createPartName("/_xmlsignatures/sig1.xml");
-            // <Default Extension="sigs" ContentType="application/vnd.openxmlformats-package.digital-signature-origin"/>
-            sigsPartName = PackagingURIHelper.createPartName("/_xmlsignatures/origin.sigs");
-        } catch (InvalidFormatException e) {
-            throw new MarshalException(e);
-        }
-        
-        PackagePart sigPart = pkg.getPart(sigPartName);
-        if (sigPart == null) {
-            sigPart = pkg.createPart(sigPartName, ContentTypes.DIGITAL_SIGNATURE_XML_SIGNATURE_PART);
-        }
-        
-        try {
-            OutputStream os = sigPart.getOutputStream();
-            SignatureDocument sigDoc = SignatureDocument.Factory.parse(document, DEFAULT_XML_OPTIONS);
-            sigDoc.save(os, xo);
-            os.close();
-        } catch (Exception e) {
-            throw new MarshalException("Unable to write signature document", e);
-        }
-        
-        PackagePart sigsPart = pkg.getPart(sigsPartName);
-        if (sigsPart == null) {
-            // touch empty marker file
-            sigsPart = pkg.createPart(sigsPartName, ContentTypes.DIGITAL_SIGNATURE_ORIGIN_PART);
-        }
-        
-        PackageRelationshipCollection relCol = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
-        for (PackageRelationship pr : relCol) {
-            pkg.removeRelationship(pr.getId());
-        }
-        pkg.addRelationship(sigsPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
-        
-        sigsPart.addRelationship(sigPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE);
-    }
-    
-    /**
-     * Helper method for null lists, which are converted to empty lists
-     *
-     * @param other the reference to wrap, if null
-     * @return if other is null, an empty lists is returned, otherwise other is returned
-     */
-    private static <T> List<T> safe(List<T> other) {
-        List<T> emptyList = Collections.emptyList();
-        return other == null ? emptyList : other;
-    }
-
-    private void brokenJvmWorkaround(XMLSignContext context) {
-        // workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
-        Provider bcProv = Security.getProvider("BC");
-        if (bcProv != null) {
-            context.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);
-        }        
-    }
-
-    private void brokenJvmWorkaround(XMLValidateContext context) {
-        // workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
-        Provider bcProv = Security.getProvider("BC");
-        if (bcProv != null) {
-            context.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);
-        }        
-    }
-}
+ */
+public class SignatureInfo implements SignatureConfigurable {
+
+    private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class);
+    private static boolean isInitialized = false;
+    
+    private SignatureConfig signatureConfig;
+
+    public class SignaturePart {
+        private final PackagePart signaturePart;
+        private X509Certificate signer;
+        private List<X509Certificate> certChain;
+        
+        private SignaturePart(PackagePart signaturePart) {
+            this.signaturePart = signaturePart;
+        }
+        
+        /**
+         * @return the package part containing the signature
+         */
+        public PackagePart getPackagePart() {
+            return signaturePart;
+        }
+        
+        /**
+         * @return the signer certificate
+         */
+        public X509Certificate getSigner() {
+            return signer;
+        }
+        
+        /**
+         * @return the certificate chain of the signer
+         */
+        public List<X509Certificate> getCertChain() {
+            return certChain;
+        }
+        
+        /**
+         * Helper method for examining the xml signature
+         *
+         * @return the xml signature document
+         * @throws IOException if the xml signature doesn't exist or can't be read
+         * @throws XmlException if the xml signature is malformed
+         */
+        public SignatureDocument getSignatureDocument() throws IOException, XmlException {
+            // TODO: check for XXE
+            return SignatureDocument.Factory.parse(signaturePart.getInputStream(), DEFAULT_XML_OPTIONS);
+        }
+        
+        /**
+         * @return true, when the xml signature is valid, false otherwise
+         * 
+         * @throws EncryptedDocumentException if the signature can't be extracted or if its malformed
+         */
+        @SuppressWarnings("unchecked")
+        public boolean validate() {
+            KeyInfoKeySelector keySelector = new KeyInfoKeySelector();
+            try {
+                Document doc = DocumentHelper.readDocument(signaturePart.getInputStream());
+                XPath xpath = XPathFactory.newInstance().newXPath();
+                NodeList nl = (NodeList)xpath.compile("//*[@Id]").evaluate(doc, XPathConstants.NODESET);
+                for (int i=0; i<nl.getLength(); i++) {
+                    ((Element)nl.item(i)).setIdAttribute("Id", true);
+                }
+                
+                DOMValidateContext domValidateContext = new DOMValidateContext(keySelector, doc);
+                domValidateContext.setProperty("org.jcp.xml.dsig.validateManifests", Boolean.TRUE);
+                domValidateContext.setURIDereferencer(signatureConfig.getUriDereferencer());
+                brokenJvmWorkaround(domValidateContext);
+    
+                XMLSignatureFactory xmlSignatureFactory = signatureConfig.getSignatureFactory();
+                XMLSignature xmlSignature = xmlSignatureFactory.unmarshalXMLSignature(domValidateContext);
+                
+                // TODO: replace with property when xml-sec patch is applied
+                for (Reference ref : (List<Reference>)xmlSignature.getSignedInfo().getReferences()) {
+                    SignatureFacet.brokenJvmWorkaround(ref);
+                }
+                for (XMLObject xo : (List<XMLObject>)xmlSignature.getObjects()) {
+                    for (XMLStructure xs : (List<XMLStructure>)xo.getContent()) {
+                        if (xs instanceof Manifest) {
+                           for (Reference ref : (List<Reference>)((Manifest)xs).getReferences()) {
+                               SignatureFacet.brokenJvmWorkaround(ref);
+                           }
+                        }
+                    }
+                }
+                
+                boolean valid = xmlSignature.validate(domValidateContext);
+
+                if (valid) {
+                    signer = keySelector.getSigner();
+                    certChain = keySelector.getCertChain();
+                }
+                
+                return valid;
+            } catch (Exception e) {
+                String s = "error in marshalling and validating the signature";
+                LOG.log(POILogger.ERROR, s, e);
+                throw new EncryptedDocumentException(s, e);
+            }
+        }
+    }
+    
+    /**
+     * Constructor initializes xml signature environment, if it hasn't been initialized before
+     */
+    public SignatureInfo() {
+        initXmlProvider();        
+    }
+    
+    /**
+     * @return the signature config
+     */
+    public SignatureConfig getSignatureConfig() {
+        return signatureConfig;
+    }
+
+    /**
+     * @param signatureConfig the signature config, needs to be set before a SignatureInfo object is used
+     */
+    public void setSignatureConfig(SignatureConfig signatureConfig) {
+        this.signatureConfig = signatureConfig;
+    }
+
+    /**
+     * @return true, if first signature part is valid
+     */
+    public boolean verifySignature() {
+        // http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
+        for (SignaturePart sp : getSignatureParts()){
+            // only validate first part
+            return sp.validate();
+        }
+        return false;
+    }
+
+    /**
+     * add the xml signature to the document
+     *
+     * @throws XMLSignatureException
+     * @throws MarshalException
+     */
+    public void confirmSignature() throws XMLSignatureException, MarshalException {
+        Document document = DocumentHelper.createDocument();
+        
+        // operate
+        DigestInfo digestInfo = preSign(document, null);
+
+        // setup: key material, signature value
+        byte[] signatureValue = signDigest(digestInfo.digestValue);
+        
+        // operate: postSign
+        postSign(document, signatureValue);
+    }
+
+    /**
+     * Sign (encrypt) the digest with the private key.
+     * Currently only rsa is supported.
+     *
+     * @param digest the hashed input
+     * @return the encrypted hash
+     */
+    public byte[] signDigest(byte digest[]) {
+        Cipher cipher = CryptoFunctions.getCipher(signatureConfig.getKey(), CipherAlgorithm.rsa
+            , ChainingMode.ecb, null, Cipher.ENCRYPT_MODE, "PKCS1Padding");
+            
+        try {
+            ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();
+            digestInfoValueBuf.write(signatureConfig.getHashMagic());
+            digestInfoValueBuf.write(digest);
+            byte[] digestInfoValue = digestInfoValueBuf.toByteArray();
+            byte[] signatureValue = cipher.doFinal(digestInfoValue);
+            return signatureValue;
+        } catch (Exception e) {
+            throw new EncryptedDocumentException(e);
+        }
+    }
+    
+    /**
+     * @return a signature part for each signature document.
+     * the parts can be validated independently.
+     */
+    public Iterable<SignaturePart> getSignatureParts() {
+        signatureConfig.init(true);
+        return new Iterable<SignaturePart>() {
+            public Iterator<SignaturePart> iterator() {
+                return new Iterator<SignaturePart>() {
+                    OPCPackage pkg = signatureConfig.getOpcPackage();
+                    Iterator<PackageRelationship> sigOrigRels = 
+                        pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN).iterator();
+                    Iterator<PackageRelationship> sigRels = null;
+                    PackagePart sigPart = null;
+                    
+                    public boolean hasNext() {
+                        while (sigRels == null || !sigRels.hasNext()) {
+                            if (!sigOrigRels.hasNext()) return false;
+                            sigPart = pkg.getPart(sigOrigRels.next());
+                            LOG.log(POILogger.DEBUG, "Digital Signature Origin part", sigPart);
+                            try {
+                                sigRels = sigPart.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE).iterator();
+                            } catch (InvalidFormatException e) {
+                                LOG.log(POILogger.WARN, "Reference to signature is invalid.", e);
+                            }
+                        }
+                        return true;
+                    }
+                    
+                    public SignaturePart next() {
+                        PackagePart sigRelPart = null;
+                        do {
+                            try {
+                                if (!hasNext()) throw new NoSuchElementException();
+                                sigRelPart = sigPart.getRelatedPart(sigRels.next()); 
+                                LOG.log(POILogger.DEBUG, "XML Signature part", sigRelPart);
+                            } catch (InvalidFormatException e) {
+                                LOG.log(POILogger.WARN, "Reference to signature is invalid.", e);
+                            }
+                        } while (sigPart == null);
+                        return new SignaturePart(sigRelPart);
+                    }
+                    
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+    
+    /**
+     * Initialize the xml signing environment and the bouncycastle provider 
+     */
+    protected static synchronized void initXmlProvider() {
+        if (isInitialized) return;
+        isInitialized = true;
+        
+        try {
+            Init.init();
+            RelationshipTransformService.registerDsigProvider();
+            CryptoFunctions.registerBouncyCastle();
+        } catch (Exception e) {
+            throw new RuntimeException("Xml & BouncyCastle-Provider initialization failed", e);
+        }
+    }
+    
+    /**
+     * Helper method for adding informations before the signing.
+     * Normally {@link #confirmSignature()} is sufficient to be used.
+     */
+    @SuppressWarnings("unchecked")
+    public DigestInfo preSign(Document document, List<DigestInfo> digestInfos)
+    throws XMLSignatureException, MarshalException {
+        signatureConfig.init(false);
+        
+        // it's necessary to explicitly set the mdssi namespace, but the sign() method has no
+        // normal way to interfere with, so we need to add the namespace under the hand ...
+        EventTarget target = (EventTarget)document;
+        EventListener creationListener = signatureConfig.getSignatureMarshalListener();
+        if (creationListener != null) {
+            if (creationListener instanceof SignatureMarshalListener) {
+                ((SignatureMarshalListener)creationListener).setEventTarget(target);
+            }
+            SignatureMarshalListener.setListener(target, creationListener, true);
+        }
+        
+        /*
+         * Signature context construction.
+         */
+        XMLSignContext xmlSignContext = new DOMSignContext(signatureConfig.getKey(), document);
+        URIDereferencer uriDereferencer = signatureConfig.getUriDereferencer();
+        if (null != uriDereferencer) {
+            xmlSignContext.setURIDereferencer(uriDereferencer);
+        }
+
+        for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {
+            xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());
+        }
+        xmlSignContext.setDefaultNamespacePrefix("");
+        // signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));
+        
+        brokenJvmWorkaround(xmlSignContext);
+        
+        XMLSignatureFactory signatureFactory = signatureConfig.getSignatureFactory();
+
+        /*
+         * Add ds:References that come from signing client local files.
+         */
+        List<Reference> references = new ArrayList<Reference>();
+        for (DigestInfo digestInfo : safe(digestInfos)) {
+            byte[] documentDigestValue = digestInfo.digestValue;
+
+            String uri = new File(digestInfo.description).getName();
+            Reference reference = SignatureFacet.newReference
+                (uri, null, null, null, documentDigestValue, signatureConfig);
+            references.add(reference);
+        }
+
+        /*
+         * Invoke the signature facets.
+         */
+        List<XMLObject> objects = new ArrayList<XMLObject>();
+        for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
+            LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName());
+            signatureFacet.preSign(document, references, objects);
+        }
+
+        /*
+         * ds:SignedInfo
+         */
+        SignedInfo signedInfo;
+        try {
+            SignatureMethod signatureMethod = signatureFactory.newSignatureMethod
+                (signatureConfig.getSignatureMethodUri(), null);
+            CanonicalizationMethod canonicalizationMethod = signatureFactory
+                .newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),
+                (C14NMethodParameterSpec) null);
+            signedInfo = signatureFactory.newSignedInfo(
+                canonicalizationMethod, signatureMethod, references);
+        } catch (GeneralSecurityException e) {
+            throw new XMLSignatureException(e);
+        }
+
+        /*
+         * JSR105 ds:Signature creation
+         */
+        String signatureValueId = signatureConfig.getPackageSignatureId() + "-signature-value";
+        javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory
+            .newXMLSignature(signedInfo, null, objects, signatureConfig.getPackageSignatureId(),
+            signatureValueId);
+
+        /*
+         * ds:Signature Marshalling.
+         */
+        xmlSignature.sign(xmlSignContext);
+
+        /*
+         * Completion of undigested ds:References in the ds:Manifests.
+         */
+        for (XMLObject object : objects) {
+            LOG.log(POILogger.DEBUG, "object java type: " + object.getClass().getName());
+            List<XMLStructure> objectContentList = object.getContent();
+            for (XMLStructure objectContent : objectContentList) {
+                LOG.log(POILogger.DEBUG, "object content java type: " + objectContent.getClass().getName());
+                if (!(objectContent instanceof Manifest)) continue;
+                Manifest manifest = (Manifest) objectContent;
+                List<Reference> manifestReferences = manifest.getReferences();
+                for (Reference manifestReference : manifestReferences) {
+                    if (manifestReference.getDigestValue() != null) continue;
+
+                    DOMReference manifestDOMReference = (DOMReference)manifestReference;
+                    manifestDOMReference.digest(xmlSignContext);
+                }
+            }
+        }
+
+        /*
+         * Completion of undigested ds:References.
+         */
+        List<Reference> signedInfoReferences = signedInfo.getReferences();
+        for (Reference signedInfoReference : signedInfoReferences) {
+            DOMReference domReference = (DOMReference)signedInfoReference;
+
+            // ds:Reference with external digest value
+            if (domReference.getDigestValue() != null) continue;
+            
+            domReference.digest(xmlSignContext);
+        }
+
+        /*
+         * Calculation of XML signature digest value.
+         */
+        DOMSignedInfo domSignedInfo = (DOMSignedInfo)signedInfo;
+        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
+        domSignedInfo.canonicalize(xmlSignContext, dataStream);
+        byte[] octets = dataStream.toByteArray();
+
+        /*
+         * TODO: we could be using DigestOutputStream here to optimize memory
+         * usage.
+         */
+
+        MessageDigest md = CryptoFunctions.getMessageDigest(signatureConfig.getDigestAlgo());
+        byte[] digestValue = md.digest(octets);
+        
+        
+        String description = signatureConfig.getSignatureDescription();
+        return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);
+    }
+
+    /**
+     * Helper method for adding informations after the signing.
+     * Normally {@link #confirmSignature()} is sufficient to be used.
+     */
+    public void postSign(Document document, byte[] signatureValue)
+    throws MarshalException {
+        LOG.log(POILogger.DEBUG, "postSign");
+
+        /*
+         * Check ds:Signature node.
+         */
+        String signatureId = signatureConfig.getPackageSignatureId();
+        if (!signatureId.equals(document.getDocumentElement().getAttribute("Id"))) {
+            throw new RuntimeException("ds:Signature not found for @Id: " + signatureId);
+        }
+
+        /*
+         * Insert signature value into the ds:SignatureValue element
+         */
+        NodeList sigValNl = document.getElementsByTagNameNS(XML_DIGSIG_NS, "SignatureValue");
+        if (sigValNl.getLength() != 1) {
+            throw new RuntimeException("preSign has to be called before postSign");
+        }
+        sigValNl.item(0).setTextContent(Base64.encode(signatureValue));
+
+        /*
+         * Allow signature facets to inject their own stuff.
+         */
+        for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {
+            signatureFacet.postSign(document);
+        }
+
+        writeDocument(document);
+    }
+
+    /**
+     * Write XML signature into the OPC package
+     *
+     * @param document the xml signature document
+     * @throws MarshalException
+     */
+    protected void writeDocument(Document document) throws MarshalException {
+        XmlOptions xo = new XmlOptions();
+        Map<String,String> namespaceMap = new HashMap<String,String>();
+        for(Map.Entry<String,String> entry : signatureConfig.getNamespacePrefixes().entrySet()){
+            namespaceMap.put(entry.getValue(), entry.getKey());
+        }        
+        xo.setSaveSuggestedPrefixes(namespaceMap);
+        xo.setUseDefaultNamespace();
+
+        LOG.log(POILogger.DEBUG, "output signed Office OpenXML document");
+
+        /*
+         * Copy the original OOXML content to the signed OOXML package. During
+         * copying some files need to changed.
+         */
+        OPCPackage pkg = signatureConfig.getOpcPackage();
+
+        PackagePartName sigPartName, sigsPartName;
+        try {
+            // <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
+            sigPartName = PackagingURIHelper.createPartName("/_xmlsignatures/sig1.xml");
+            // <Default Extension="sigs" ContentType="application/vnd.openxmlformats-package.digital-signature-origin"/>
+            sigsPartName = PackagingURIHelper.createPartName("/_xmlsignatures/origin.sigs");
+        } catch (InvalidFormatException e) {
+            throw new MarshalException(e);
+        }
+        
+        PackagePart sigPart = pkg.getPart(sigPartName);
+        if (sigPart == null) {
+            sigPart = pkg.createPart(sigPartName, ContentTypes.DIGITAL_SIGNATURE_XML_SIGNATURE_PART);
+        }
+        
+        try {
+            OutputStream os = sigPart.getOutputStream();
+            SignatureDocument sigDoc = SignatureDocument.Factory.parse(document, DEFAULT_XML_OPTIONS);
+            sigDoc.save(os, xo);
+            os.close();
+        } catch (Exception e) {
+            throw new MarshalException("Unable to write signature document", e);
+        }
+        
+        PackagePart sigsPart = pkg.getPart(sigsPartName);
+        if (sigsPart == null) {
+            // touch empty marker file
+            sigsPart = pkg.createPart(sigsPartName, ContentTypes.DIGITAL_SIGNATURE_ORIGIN_PART);
+        }
+        
+        PackageRelationshipCollection relCol = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
+        for (PackageRelationship pr : relCol) {
+            pkg.removeRelationship(pr.getId());
+        }
+        pkg.addRelationship(sigsPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
+        
+        sigsPart.addRelationship(sigPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE);
+    }
+    
+    /**
+     * Helper method for null lists, which are converted to empty lists
+     *
+     * @param other the reference to wrap, if null
+     * @return if other is null, an empty lists is returned, otherwise other is returned
+     */
+    private static <T> List<T> safe(List<T> other) {
+        List<T> emptyList = Collections.emptyList();
+        return other == null ? emptyList : other;
+    }
+
+    private void brokenJvmWorkaround(XMLSignContext context) {
+        // workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
+        Provider bcProv = Security.getProvider("BC");
+        if (bcProv != null) {
+            context.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);
+        }        
+    }
+
+    private void brokenJvmWorkaround(XMLValidateContext context) {
+        // workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012
+        Provider bcProv = Security.getProvider("BC");
+        if (bcProv != null) {
+            context.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);
+        }        
+    }
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org