When signing XML files with Xades4j (which uses Apache Santuario underneath) using a smart card the latter will be reset by Windows when the signing process takes more than 5 seconds. This issue exists only on Windows 8+.

The problem is that the key store gets initialized before the digest values are computed. If this calculation takes more than 5 seconds Windows resets the smart card because of an inactive transaction. (See the attached screen shot of the log of that event). After the calculations are done and the actual signing process starts the smartcard is no more available and the task fails.

This behavior is documented here https://msdn.microsoft.com/en-us/library/windows/desktop/aa379469%28v=vs.85%29.aspx

The solution is quite simple. The order of calculating the digest values and initializing the key store has to be changed. I located this in org.apache.xml.security.signature.XmlSignature on line 628 in method

public void sign(Key signingKey) throws XMLSignatureException {
...
 try {
            //Create a SignatureAlgorithm object
            SignedInfo si = this.getSignedInfo();
            SignatureAlgorithm sa = si.getSignatureAlgorithm();
            OutputStream so = null;
            try {
*                // initialize SignatureAlgorithm for signing**
**                sa.initSign(signingKey);**
****
** // generate digest values for all References in this SignedInfo**
**                si.generateDigestValues(); *

so = new UnsyncBufferedOutputStream(new SignerOutputStream(sa));
                // get the canonicalized bytes from SignedInfo
                si.signInOctetStream(so);
            } catch (XMLSecurityException ex) {
                throw ex;
            } finally {
...

To solve the problem it should be

public void sign(Key signingKey) throws XMLSignatureException {
...
 try {
            //Create a SignatureAlgorithm object
            SignedInfo si = this.getSignedInfo();
            SignatureAlgorithm sa = si.getSignatureAlgorithm();
            OutputStream so = null;
            try {
* // generate digest values for all References in this SignedInfo**
**                si.generateDigestValues();**
****
**                // initialize SignatureAlgorithm for signing**
**                sa.initSign(signingKey); *

so = new UnsyncBufferedOutputStream(new SignerOutputStream(sa));
                // get the canonicalized bytes from SignedInfo
                si.signInOctetStream(so);
            } catch (XMLSecurityException ex) {
                throw ex;
            } finally {
...

This code works for this particular setup and is able to sign an XML of 60GB on a Windows 10 machine. This task takes more than a minute and doesn't fail since Windows doesn't reset the smart card transaction.


Kind regards

Adrian Greiler


--
Adrian Greiler
Software Engineer

Glue Software Engineering AG | Schwarztorstrasse 31 | CH-3007 Bern | www.glue.ch
[email protected] | Office : +41 31 385 30 11 | Direkt: +41 31 385 30 34

Reply via email to