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.

Reply via email to