]> source.dussan.org Git - poi.git/commitdiff
Added a catch and another workaround for the OpenJDK SHA2 AIOOBE bug
authorAndreas Beeker <kiwiwings@apache.org>
Wed, 5 Nov 2014 22:56:31 +0000 (22:56 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Wed, 5 Nov 2014 22:56:31 +0000 (22:56 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1637001 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java

index 41e52b33db504e63066290552c4c6bb093b3d8ce..8be5797d621691fffcdf8ef935311b4a24ec6e6d 100644 (file)
@@ -32,6 +32,8 @@ import java.io.IOException;
 import java.io.OutputStream;\r
 import java.security.GeneralSecurityException;\r
 import java.security.MessageDigest;\r
+import java.security.Provider;\r
+import java.security.Security;\r
 import java.security.cert.X509Certificate;\r
 import java.util.ArrayList;\r
 import java.util.Collections;\r
@@ -395,138 +397,149 @@ public class SignatureInfo implements SignatureConfigurable {
     @SuppressWarnings("unchecked")\r
     public DigestInfo preSign(Document document, List<DigestInfo> digestInfos)\r
     throws XMLSignatureException, MarshalException {\r
-        signatureConfig.init(false);\r
-        \r
-        // it's necessary to explicitly set the mdssi namespace, but the sign() method has no\r
-        // normal way to interfere with, so we need to add the namespace under the hand ...\r
-        EventTarget target = (EventTarget)document;\r
-        EventListener creationListener = signatureConfig.getSignatureMarshalListener();\r
-        if (creationListener != null) {\r
-            if (creationListener instanceof SignatureMarshalListener) {\r
-                ((SignatureMarshalListener)creationListener).setEventTarget(target);\r
-            }\r
-            SignatureMarshalListener.setListener(target, creationListener, true);\r
-        }\r
-        \r
-        /*\r
-         * Signature context construction.\r
-         */\r
-        XMLSignContext xmlSignContext = new DOMSignContext(signatureConfig.getKey(), document);\r
-        URIDereferencer uriDereferencer = signatureConfig.getUriDereferencer();\r
-        if (null != uriDereferencer) {\r
-            xmlSignContext.setURIDereferencer(uriDereferencer);\r
-        }\r
-\r
-        for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {\r
-            xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());\r
-        }\r
-        xmlSignContext.setDefaultNamespacePrefix(""); // signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));\r
-        \r
-        XMLSignatureFactory signatureFactory = signatureConfig.getSignatureFactory();\r
-\r
-        /*\r
-         * Add ds:References that come from signing client local files.\r
-         */\r
-        List<Reference> references = new ArrayList<Reference>();\r
-        for (DigestInfo digestInfo : safe(digestInfos)) {\r
-            byte[] documentDigestValue = digestInfo.digestValue;\r
-\r
-            String uri = new File(digestInfo.description).getName();\r
-            Reference reference = SignatureFacet.newReference\r
-                (uri, null, null, null, documentDigestValue, signatureConfig);\r
-            references.add(reference);\r
-        }\r
-\r
-        /*\r
-         * Invoke the signature facets.\r
-         */\r
-        List<XMLObject> objects = new ArrayList<XMLObject>();\r
-        for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {\r
-            LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName());\r
-            signatureFacet.preSign(document, references, objects);\r
-        }\r
-\r
-        /*\r
-         * ds:SignedInfo\r
-         */\r
-        SignedInfo signedInfo;\r
         try {\r
-            SignatureMethod signatureMethod = signatureFactory.newSignatureMethod\r
-                (signatureConfig.getSignatureMethodUri(), null);\r
-            CanonicalizationMethod canonicalizationMethod = signatureFactory\r
-                .newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),\r
-                (C14NMethodParameterSpec) null);\r
-            signedInfo = signatureFactory.newSignedInfo(\r
-                canonicalizationMethod, signatureMethod, references);\r
-        } catch (GeneralSecurityException e) {\r
-            throw new XMLSignatureException(e);\r
-        }\r
-\r
-        /*\r
-         * JSR105 ds:Signature creation\r
-         */\r
-        String signatureValueId = signatureConfig.getPackageSignatureId() + "-signature-value";\r
-        javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory\r
-            .newXMLSignature(signedInfo, null, objects, signatureConfig.getPackageSignatureId(),\r
-            signatureValueId);\r
-\r
-        /*\r
-         * ds:Signature Marshalling.\r
-         */\r
-        xmlSignature.sign(xmlSignContext);\r
-\r
-        /*\r
-         * Completion of undigested ds:References in the ds:Manifests.\r
-         */\r
-        for (XMLObject object : objects) {\r
-            LOG.log(POILogger.DEBUG, "object java type: " + object.getClass().getName());\r
-            List<XMLStructure> objectContentList = object.getContent();\r
-            for (XMLStructure objectContent : objectContentList) {\r
-                LOG.log(POILogger.DEBUG, "object content java type: " + objectContent.getClass().getName());\r
-                if (!(objectContent instanceof Manifest)) continue;\r
-                Manifest manifest = (Manifest) objectContent;\r
-                List<Reference> manifestReferences = manifest.getReferences();\r
-                for (Reference manifestReference : manifestReferences) {\r
-                    if (manifestReference.getDigestValue() != null) continue;\r
-\r
-                    DOMReference manifestDOMReference = (DOMReference)manifestReference;\r
-                    manifestDOMReference.digest(xmlSignContext);\r
+            signatureConfig.init(false);\r
+            \r
+            // it's necessary to explicitly set the mdssi namespace, but the sign() method has no\r
+            // normal way to interfere with, so we need to add the namespace under the hand ...\r
+            EventTarget target = (EventTarget)document;\r
+            EventListener creationListener = signatureConfig.getSignatureMarshalListener();\r
+            if (creationListener != null) {\r
+                if (creationListener instanceof SignatureMarshalListener) {\r
+                    ((SignatureMarshalListener)creationListener).setEventTarget(target);\r
                 }\r
+                SignatureMarshalListener.setListener(target, creationListener, true);\r
             }\r
-        }\r
-\r
-        /*\r
-         * Completion of undigested ds:References.\r
-         */\r
-        List<Reference> signedInfoReferences = signedInfo.getReferences();\r
-        for (Reference signedInfoReference : signedInfoReferences) {\r
-            DOMReference domReference = (DOMReference)signedInfoReference;\r
-\r
-            // ds:Reference with external digest value\r
-            if (domReference.getDigestValue() != null) continue;\r
             \r
-            domReference.digest(xmlSignContext);\r
+            /*\r
+             * Signature context construction.\r
+             */\r
+            XMLSignContext xmlSignContext = new DOMSignContext(signatureConfig.getKey(), document);\r
+            URIDereferencer uriDereferencer = signatureConfig.getUriDereferencer();\r
+            if (null != uriDereferencer) {\r
+                xmlSignContext.setURIDereferencer(uriDereferencer);\r
+            }\r
+    \r
+            for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {\r
+                xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());\r
+            }\r
+            xmlSignContext.setDefaultNamespacePrefix("");\r
+            // signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));\r
+            \r
+            // workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1155012\r
+            Provider bcProv = Security.getProvider("BC");\r
+            if (bcProv != null) {\r
+                xmlSignContext.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", bcProv);\r
+            }            \r
+            \r
+            XMLSignatureFactory signatureFactory = signatureConfig.getSignatureFactory();\r
+    \r
+            /*\r
+             * Add ds:References that come from signing client local files.\r
+             */\r
+            List<Reference> references = new ArrayList<Reference>();\r
+            for (DigestInfo digestInfo : safe(digestInfos)) {\r
+                byte[] documentDigestValue = digestInfo.digestValue;\r
+    \r
+                String uri = new File(digestInfo.description).getName();\r
+                Reference reference = SignatureFacet.newReference\r
+                    (uri, null, null, null, documentDigestValue, signatureConfig);\r
+                references.add(reference);\r
+            }\r
+    \r
+            /*\r
+             * Invoke the signature facets.\r
+             */\r
+            List<XMLObject> objects = new ArrayList<XMLObject>();\r
+            for (SignatureFacet signatureFacet : signatureConfig.getSignatureFacets()) {\r
+                LOG.log(POILogger.DEBUG, "invoking signature facet: " + signatureFacet.getClass().getSimpleName());\r
+                signatureFacet.preSign(document, references, objects);\r
+            }\r
+    \r
+            /*\r
+             * ds:SignedInfo\r
+             */\r
+            SignedInfo signedInfo;\r
+            try {\r
+                SignatureMethod signatureMethod = signatureFactory.newSignatureMethod\r
+                    (signatureConfig.getSignatureMethodUri(), null);\r
+                CanonicalizationMethod canonicalizationMethod = signatureFactory\r
+                    .newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),\r
+                    (C14NMethodParameterSpec) null);\r
+                signedInfo = signatureFactory.newSignedInfo(\r
+                    canonicalizationMethod, signatureMethod, references);\r
+            } catch (GeneralSecurityException e) {\r
+                throw new XMLSignatureException(e);\r
+            }\r
+    \r
+            /*\r
+             * JSR105 ds:Signature creation\r
+             */\r
+            String signatureValueId = signatureConfig.getPackageSignatureId() + "-signature-value";\r
+            javax.xml.crypto.dsig.XMLSignature xmlSignature = signatureFactory\r
+                .newXMLSignature(signedInfo, null, objects, signatureConfig.getPackageSignatureId(),\r
+                signatureValueId);\r
+    \r
+            /*\r
+             * ds:Signature Marshalling.\r
+             */\r
+            xmlSignature.sign(xmlSignContext);\r
+    \r
+            /*\r
+             * Completion of undigested ds:References in the ds:Manifests.\r
+             */\r
+            for (XMLObject object : objects) {\r
+                LOG.log(POILogger.DEBUG, "object java type: " + object.getClass().getName());\r
+                List<XMLStructure> objectContentList = object.getContent();\r
+                for (XMLStructure objectContent : objectContentList) {\r
+                    LOG.log(POILogger.DEBUG, "object content java type: " + objectContent.getClass().getName());\r
+                    if (!(objectContent instanceof Manifest)) continue;\r
+                    Manifest manifest = (Manifest) objectContent;\r
+                    List<Reference> manifestReferences = manifest.getReferences();\r
+                    for (Reference manifestReference : manifestReferences) {\r
+                        if (manifestReference.getDigestValue() != null) continue;\r
+    \r
+                        DOMReference manifestDOMReference = (DOMReference)manifestReference;\r
+                        manifestDOMReference.digest(xmlSignContext);\r
+                    }\r
+                }\r
+            }\r
+    \r
+            /*\r
+             * Completion of undigested ds:References.\r
+             */\r
+            List<Reference> signedInfoReferences = signedInfo.getReferences();\r
+            for (Reference signedInfoReference : signedInfoReferences) {\r
+                DOMReference domReference = (DOMReference)signedInfoReference;\r
+    \r
+                // ds:Reference with external digest value\r
+                if (domReference.getDigestValue() != null) continue;\r
+                \r
+                domReference.digest(xmlSignContext);\r
+            }\r
+    \r
+            /*\r
+             * Calculation of XML signature digest value.\r
+             */\r
+            DOMSignedInfo domSignedInfo = (DOMSignedInfo)signedInfo;\r
+            ByteArrayOutputStream dataStream = new ByteArrayOutputStream();\r
+            domSignedInfo.canonicalize(xmlSignContext, dataStream);\r
+            byte[] octets = dataStream.toByteArray();\r
+    \r
+            /*\r
+             * TODO: we could be using DigestOutputStream here to optimize memory\r
+             * usage.\r
+             */\r
+    \r
+            MessageDigest md = CryptoFunctions.getMessageDigest(signatureConfig.getDigestAlgo());\r
+            byte[] digestValue = md.digest(octets);\r
+            \r
+            \r
+            String description = signatureConfig.getSignatureDescription();\r
+            return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);\r
+        } catch (ArrayIndexOutOfBoundsException e) {\r
+            throw new EncryptedDocumentException("\"your JVM is just too broken\" - check https://bugzilla.redhat.com/show_bug.cgi?id=1155012 if this applies to the stacktrace ...", e);\r
         }\r
-\r
-        /*\r
-         * Calculation of XML signature digest value.\r
-         */\r
-        DOMSignedInfo domSignedInfo = (DOMSignedInfo)signedInfo;\r
-        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();\r
-        domSignedInfo.canonicalize(xmlSignContext, dataStream);\r
-        byte[] octets = dataStream.toByteArray();\r
-\r
-        /*\r
-         * TODO: we could be using DigestOutputStream here to optimize memory\r
-         * usage.\r
-         */\r
-\r
-        MessageDigest md = CryptoFunctions.getMessageDigest(signatureConfig.getDigestAlgo());\r
-        byte[] digestValue = md.digest(octets);\r
-        \r
-        \r
-        String description = signatureConfig.getSignatureDescription();\r
-        return new DigestInfo(digestValue, signatureConfig.getDigestAlgo(), description);\r
     }\r
 \r
     /**\r
index 301aea8b9317106bc705b2bc3e80c4da2bd3b786..c0aa39f536cd4d7ab5037a7f1fbc5c1404de6c3e 100644 (file)
    ================================================================= */ \r
 package org.apache.poi.poifs.crypt;\r
 \r
-import static org.junit.Assert.*;\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertFalse;\r
+import static org.junit.Assert.assertNotNull;\r
+import static org.junit.Assert.assertTrue;\r
 \r
 import java.io.File;\r
 import java.io.FileInputStream;\r
@@ -47,6 +50,7 @@ import java.util.Iterator;
 import java.util.List;\r
 import java.util.TimeZone;\r
 \r
+import org.apache.poi.EncryptedDocumentException;\r
 import org.apache.poi.POIDataSamples;\r
 import org.apache.poi.openxml4j.opc.OPCPackage;\r
 import org.apache.poi.openxml4j.opc.PackageAccess;\r
@@ -455,18 +459,29 @@ public class TestSignatureInfo {
             , HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160 }; \r
         \r
         for (HashAlgorithm ha : testAlgo) {\r
-            signatureConfig.setDigestAlgo(ha);\r
-            OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
-            signatureConfig.setOpcPackage(pkg);\r
-            \r
-            SignatureInfo si = new SignatureInfo();\r
-            si.setSignatureConfig(signatureConfig);\r
-    \r
-            si.confirmSignature();\r
-            boolean b = si.verifySignature();\r
-            pkg.close();\r
-    \r
-            assertTrue(b);\r
+            OPCPackage pkg = null;\r
+            try {\r
+                signatureConfig.setDigestAlgo(ha);\r
+                pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
+                signatureConfig.setOpcPackage(pkg);\r
+                \r
+                SignatureInfo si = new SignatureInfo();\r
+                si.setSignatureConfig(signatureConfig);\r
+        \r
+                si.confirmSignature();\r
+                boolean b = si.verifySignature();\r
+                assertTrue(b);\r
+            } catch (EncryptedDocumentException e) {\r
+                // see http://apache-poi.1045710.n5.nabble.com/org-apache-poi-poifs-crypt-TestSignatureInfo-failing-on-trunk-on-Java-6-tp5717032.html\r
+                Throwable cause = e.getCause();\r
+                if (cause instanceof ArrayIndexOutOfBoundsException) {\r
+                    LOG.log(POILogger.ERROR, "ignoring AIOOBE - hopefully a SHA2 bug ...", e);\r
+                } else {\r
+                    throw e;\r
+                }\r
+            } finally {\r
+                if (pkg != null) pkg.close();\r
+            }\r
         }\r
     }\r
     \r