Hi,

After upgrading from xmlsec (java) 1.4 to 1.5 we saw a significant drop
in signature generation performance especially when using a network
based HSM.

After some investigation it turns out that the problem is that the
hashing is done with one byte at a time which with network latencies
gives the bad performance.

Looking in the code of DOMSignedInfo.java it looks like the code intends
to use an UnsyncBufferedOutputStream however only its close method is
actually called, which as far as I can see won't have any side affect at
all when operated on a ByteArrayOutputStream.

The attached patch resolves the performance issue by actually using the
UnsyncBufferedOutputStream and that way perform the digests on a
possibly full buffer instead of byte by byte. The patch has been tested
on version 1.5.5 but also applies on 1.5.6.


Downstream ticket in SignServer:
https://jira.primekey.se/browse/DSS-698

-- 
Kind regards,
Markus Kilås
PrimeKey Solutions

diff -ur xml-security-1_5_5-orig/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMSignedInfo.java xml-security-1_5_5/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMSignedInfo.java
--- xml-security-1_5_5-orig/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMSignedInfo.java	2013-06-17 16:07:58.000000000 +0200
+++ xml-security-1_5_5/src/main/java/org/apache/jcp/xml/dsig/internal/dom/DOMSignedInfo.java	2014-06-12 11:26:24.824721521 +0200
@@ -215,37 +215,41 @@
 
         OutputStream os = new UnsyncBufferedOutputStream(bos);
         try {
-            os.close();
-        } catch (IOException e) {
-            if (log.isDebugEnabled()) {
-                log.debug(e);
+            
+
+            DOMSubTreeData subTree = new DOMSubTreeData(localSiElem, true);
+
+            try {
+                ((DOMCanonicalizationMethod) 
+                    canonicalizationMethod).canonicalize(subTree, context, os);
+            } catch (TransformException te) {
+                throw new XMLSignatureException(te);
             }
-            // Impossible
-        }
+            
+            os.flush();
 
-        DOMSubTreeData subTree = new DOMSubTreeData(localSiElem, true);
+            byte[] signedInfoBytes = bos.toByteArray();
 
-        try {
-            ((DOMCanonicalizationMethod) 
-                canonicalizationMethod).canonicalize(subTree, context, bos);
-        } catch (TransformException te) {
-            throw new XMLSignatureException(te);
-        }
+            // this whole block should only be done if logging is enabled
+            if (log.isDebugEnabled()) {
+                log.debug("Canonicalized SignedInfo:"); 
+                StringBuilder sb = new StringBuilder(signedInfoBytes.length);
+                for (int i = 0; i < signedInfoBytes.length; i++) {
+                    sb.append((char)signedInfoBytes[i]);
+                }
+                log.debug(sb.toString());
+                log.debug("Data to be signed/verified:" + Base64.encode(signedInfoBytes));
+            }
 
-        byte[] signedInfoBytes = bos.toByteArray();
+            this.canonData = new ByteArrayInputStream(signedInfoBytes);
 
-        // this whole block should only be done if logging is enabled
-        if (log.isDebugEnabled()) {
-            log.debug("Canonicalized SignedInfo:"); 
-            StringBuilder sb = new StringBuilder(signedInfoBytes.length);
-            for (int i = 0; i < signedInfoBytes.length; i++) {
-                sb.append((char)signedInfoBytes[i]);
+            os.close();
+        } catch (IOException e) {
+            if (log.isDebugEnabled()) {
+                log.debug(e);
             }
-            log.debug(sb.toString());
-            log.debug("Data to be signed/verified:" + Base64.encode(signedInfoBytes));
+            // Impossible
         }
-
-        this.canonData = new ByteArrayInputStream(signedInfoBytes);
     }
 
     public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
Only in xml-security-1_5_5: target

Reply via email to