https://issues.apache.org/bugzilla/show_bug.cgi?id=40826
--- Comment #20 from Giedrius Noreikis <giedrius.norei...@gmail.com> 2010-02-18 23:26:32 UTC --- Hi, I am experiencing the same problem. My application uses org.apache.xml.security.signature.XMLSignature for signing with software and hardware based keys. Each time when signing with PKCS#11 hardware, the appropriate security provider is created, added and then removed after the signing. The first time everyting works fine. However, if I try to sign again, the org.apache.xml.security.signature.XMLSignatureException with message "Private key must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding" is thrown: org.apache.xml.security.signature.XMLSignatureException: Private key must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding Original Exception was java.security.InvalidKeyException: Private key must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding at org.apache.xml.security.algorithms.implementations.SignatureBaseRSA.engineInitSign(SignatureBaseRSA.java:181) at org.apache.xml.security.algorithms.SignatureAlgorithm.initSign(SignatureAlgorithm.java:276) at org.apache.xml.security.signature.XMLSignature.sign(XMLSignature.java:497) ... java.security.InvalidKeyException: Private key must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding at sun.security.pkcs11.P11RSAKeyFactory.implTranslatePrivateKey(P11RSAKeyFactory.java:84) at sun.security.pkcs11.P11KeyFactory.engineTranslateKey(P11KeyFactory.java:115) at sun.security.pkcs11.P11KeyFactory.convertKey(P11KeyFactory.java:48) at sun.security.pkcs11.P11Signature.engineInitSign(P11Signature.java:375) at java.security.Signature$Delegate.engineInitSign(Unknown Source) at java.security.Signature.initSign(Unknown Source) at org.apache.xml.security.algorithms.implementations.SignatureBaseRSA.engineInitSign(SignatureBaseRSA.java:179) at org.apache.xml.security.algorithms.SignatureAlgorithm.initSign(SignatureAlgorithm.java:276) at org.apache.xml.security.signature.XMLSignature.sign(XMLSignature.java:497) ... The interesting thing is, if I retry the signing after catching the exception, it succeeds. I found out that this "recovery" is caused by the "cache cleanup" (XMLSignature:510): try { // initialize SignatureAlgorithm for signing sa.initSign(signingKey); ... } catch (XMLSecurityException ex) { sa.clearSignatureCache(); throw ex; } And the problem itself is caused by the "cache" ("SignatureAlgorithm.instancesSigning" variable). This map holds instances of SignatureAlgorithmSpi descendants. SignatureBaseRSA, which extends SignatureAlgorithmSpi, has "private java.security.Signature _signatureAlgorithm" variable, which, obviously, is initialised only once, and later gets associated with the first "suitable" security provider. During the second invocation, this provider (which is already removed BTW, but it doesn't matter - instance of java.security.Signature still holds a reference to it) is fed with a PrivateKey obtained from the newly added provider. This leads to futile attempts to "convert" the key and finally the InvalidKeyException. There are several possible workarounds (tested and confirmed to work): 1. try-catch and then retry, letting the "recovery" magic to do the work :) 2. Manual "cache cleanup" before the signing, for example: new SignatureAlgorithm(doc, signature.getSignedInfo().getSignatureMethodURI()).clearSignatureCache(); (actually, clearSignatureCache() should be static, if it is intended for a "public" use - creating an instance of the SignatureAlgorithm is pointless here) Or, the "instancesSigning" can be cleared directly, using the reflection (this is for research only, of course): Field f = SignatureAlgorithm.class.getDeclaredField("instancesSigning"); f.setAccessible(true); ThreadLocal t = (ThreadLocal)f.get(null); Map instancesMap = (Map)t.get(); instancesMap.clear(); 3. Since the "cache" is implemented per-thread, the problem can be avoided by calling the sign() from a newly-created thread. Thinking of the possible fixes, one solution could be implementing SignatureBaseRSA.reset() (like in IntegrityHmac), which would assing a new instance to the _signatureAlgorithm. If it's worth having such a "cache" at all. -- Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug.