Hello I am having a problem. My application is an applet that generate a xml and sign it with PrivateKey from SmartCard. The first time, it works fine! however when i try to sign again (second time), i get this exception: java.security.InvalidKeyException: Private keys must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding The exception occurs when calling the method: DOMSignContext dsc = new DOMSignContext(pk, doc.getDocumentElement()); This method is part of the following code: Does any body know what could i do to solve this problem ? ======= code that generates the xml signature String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory fac = XMLSignatureFactory.getInstance( "DOM", (Provider) Class.forName(providerName).newInstance()); Reference ref = fac.newReference( "", fac.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList(fac.newTransform( Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); SignedInfo si = fac.newSignedInfo( fac.newCanonicalizationMethod( CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref)); KeyInfoFactory kif = fac.getKeyInfoFactory(); X509Data x509 = kif.newX509Data(Collections.singletonList(cert)); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(x509)); DOMSignContext dsc = new DOMSignContext(pk, doc.getDocumentElement()); XMLSignature signature = fac.newXMLSignature(si, ki); signature.sign(dsc); return doc; } ======= code that get de PrivateKey and Certificate from Smart Card: String configuracao = "name = SmartCard\n" + "library = c:\\windows\\system32\\aetpkss1.dll"; byte[] configuracaoBytes = configuracao.getBytes(); ByteArrayInputStream configuracaoStream = new ByteArrayInputStream(configuracaoBytes); sun.security.pkcs11.SunPKCS11 provider = new sun.security.pkcs11.SunPKCS11(configuracaoStream); Security.addProvider(provider); this.nomeProvider = provider.getName(); this.repositorio = KeyStore.getInstance("PKCS11", provider); repositorio.load(null, pin.toCharArray()); this.inicializarDados(pin); String keyEntry = null; boolean ok = false; Enumeration en = repositorio.aliases(); while(en.hasMoreElements()) { keyEntry = (String)en.nextElement(); if(repositorio.isKeyEntry(keyEntry)){ ok = true; break; } } if(ok){ certificado = (X509Certificate) repositorio.getCertificate(keyEntry); chavePrivada = (PrivateKey) repositorio.getKey(keyEntry, pin.toCharArray());
(In reply to comment #0) > Hello > > I am having a problem. My application is an applet that generate a xml and sign > it with PrivateKey from SmartCard. > > The first time, it works fine! however when i try to sign again (second time), i > get this exception: > > java.security.InvalidKeyException: Private keys must be instance of > RSAPrivate(Crt)Key or have PKCS#8 encoding This exception indicates that you are trying to use the key that is stored on the smart card with a software based crypto provider. It won't work. See http://java.sun.com/j2se/1.5.0/docs/guide/security/p11guide.html#DelayedSelect for some more information about that. However, we need to figure out why you are getting that exception. > The exception occurs when calling the method: DOMSignContext dsc = new > DOMSignContext(pk, doc.getDocumentElement()); This method is part of the > following code: > > Does any body know what could i do to solve this problem ? Can you attach the full exception stack trace?
(In reply to comment #1) > (In reply to comment #0) > > Hello > > > > I am having a problem. My application is an applet that generate a xml and sign > > it with PrivateKey from SmartCard. > > > > The first time, it works fine! however when i try to sign again (second time), i > > get this exception: > > > > java.security.InvalidKeyException: Private keys must be instance of > > RSAPrivate(Crt)Key or have PKCS#8 encoding > This exception indicates that you are trying to use the key that is > stored on the smart card with a software based crypto provider. It won't work. > See http://java.sun.com/j2se/1.5.0/docs/guide/security/p11guide.html#DelayedSelect > for some more information about that. > However, we need to figure out why you are getting that exception. > > The exception occurs when calling the method: DOMSignContext dsc = new > > DOMSignContext(pk, doc.getDocumentElement()); This method is part of the > > following code: > > > > Does any body know what could i do to solve this problem ? > Can you attach the full exception stack trace? I will try to do this: "It is recommended that applications only call getProvider() after they have called the relevant initialization method. " Im using xml signature... i) Is this my initialization method "XMLSignature signature = fac.newXMLSignature(si, ki)"; ? ii) Is my getProvider() this part? "XMLSignatureFactory fac = XMLSignatureFactory.getInstance( "DOM", (Provider) Class.forName(providerName).newInstance()); Reference ref = fac.newReference( "", fac.newDigestMethod(DigestMethod.SHA1, null), Collections.singletonList(fac.newTransform( Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); " ? The complete stack trace: AssinaturaXMLException: java.security.InvalidKeyException: Private keys must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:86) at AssinadorDigital.AssinarDados(AssinadorDigital.java:133) at AssinadorDigital.btnAssinar_actionPerformed (AssinadorDigital.java:189) at AssinadorDigital_btnAssinar_actionAdapter.actionPerformed (AssinadorDigital.java:201) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)
(In reply to comment #2) > The complete stack trace: > > AssinaturaXMLException: java.security.InvalidKeyException: Private keys must be > instance of RSAPrivate(Crt)Key or have PKCS#8 encoding > at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:86) This stack trace doesn't help. The AssinaturaXMLException is swallowing the stack trace of the cause: InvalidKeyException. I need to have that the stack trace of the InvalidKeyException to be able to help.
(In reply to comment #3) > (In reply to comment #2) > > The complete stack trace: > > > > AssinaturaXMLException: java.security.InvalidKeyException: Private keys must be > > instance of RSAPrivate(Crt)Key or have PKCS#8 encoding > > at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:86) > This stack trace doesn't help. The AssinaturaXMLException is swallowing the > stack trace of the cause: InvalidKeyException. I need to have that the stack > trace of the InvalidKeyException to be able to help. Ok. I think this may help: javax.xml.crypto.dsig.XMLSignatureException: java.security.InvalidKeyException: Private keys must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign (DOMXMLSignature.java:370) at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:80) at AssinadorDigital.AssinarDados(AssinadorDigital.java:134) at AssinadorDigital.btnAssinar_actionPerformed (AssinadorDigital.java:190) at AssinadorDigital_btnAssinar_actionAdapter.actionPerformed (AssinadorDigital.java:202) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) Caused by: java.security.InvalidKeyException: Private keys must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding at sun.security.rsa.RSAKeyFactory.translatePrivateKey(Unknown Source) at sun.security.rsa.RSAKeyFactory.engineTranslateKey(Unknown Source) at sun.security.rsa.RSAKeyFactory.toRSAKey(Unknown Source) at sun.security.rsa.RSASignature.engineInitSign(Unknown Source) at sun.security.rsa.RSASignature.engineInitSign(Unknown Source) at java.security.Signature$Delegate.init(Unknown Source) at java.security.Signature$Delegate.chooseProvider(Unknown Source) at java.security.Signature$Delegate.engineInitSign(Unknown Source) at java.security.Signature.initSign(Unknown Source) at org.jcp.xml.dsig.internal.dom.DOMRSASignatureMethod.sign (DOMRSASignatureMethod.java:134) at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign (DOMXMLSignature.java:367) ... 27 more java.security.InvalidKeyException: Private keys must be instance of RSAPrivate (Crt)Key or have PKCS#8 encoding at sun.security.rsa.RSAKeyFactory.translatePrivateKey(Unknown Source) at sun.security.rsa.RSAKeyFactory.engineTranslateKey(Unknown Source) at sun.security.rsa.RSAKeyFactory.toRSAKey(Unknown Source) at sun.security.rsa.RSASignature.engineInitSign(Unknown Source) at sun.security.rsa.RSASignature.engineInitSign(Unknown Source) at java.security.Signature$Delegate.init(Unknown Source) at java.security.Signature$Delegate.chooseProvider(Unknown Source) at java.security.Signature$Delegate.engineInitSign(Unknown Source) at java.security.Signature.initSign(Unknown Source) at org.jcp.xml.dsig.internal.dom.DOMRSASignatureMethod.sign (DOMRSASignatureMethod.java:134) at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign (DOMXMLSignature.java:367) at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:80) at AssinadorDigital.AssinarDados(AssinadorDigital.java:134) at AssinadorDigital.btnAssinar_actionPerformed (AssinadorDigital.java:190) at AssinadorDigital_btnAssinar_actionAdapter.actionPerformed (AssinadorDigital.java:202) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) java.security.InvalidKeyException: Private keys must be instance of RSAPrivate (Crt)Key or have PKCS#8 encoding at sun.security.rsa.RSAKeyFactory.translatePrivateKey(Unknown Source) at sun.security.rsa.RSAKeyFactory.engineTranslateKey(Unknown Source) at sun.security.rsa.RSAKeyFactory.toRSAKey(Unknown Source) at sun.security.rsa.RSASignature.engineInitSign(Unknown Source) at sun.security.rsa.RSASignature.engineInitSign(Unknown Source) at java.security.Signature$Delegate.init(Unknown Source) at java.security.Signature$Delegate.chooseProvider(Unknown Source) at java.security.Signature$Delegate.engineInitSign(Unknown Source) at java.security.Signature.initSign(Unknown Source) at org.jcp.xml.dsig.internal.dom.DOMRSASignatureMethod.sign (DOMRSASignatureMethod.java:134) at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign (DOMXMLSignature.java:367) at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:80) at AssinadorDigital.AssinarDados(AssinadorDigital.java:134) at AssinadorDigital.btnAssinar_actionPerformed (AssinadorDigital.java:190) at AssinadorDigital_btnAssinar_actionAdapter.actionPerformed (AssinadorDigital.java:202) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) AssinaturaXMLException: java.security.InvalidKeyException: Private keys must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:87) at AssinadorDigital.AssinarDados(AssinadorDigital.java:134) at AssinadorDigital.btnAssinar_actionPerformed (AssinadorDigital.java:190) at AssinadorDigital_btnAssinar_actionAdapter.actionPerformed (AssinadorDigital.java:202) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)
(In reply to comment #4) > (In reply to comment #3) > > (In reply to comment #2) > > > The complete stack trace: > > > > > > AssinaturaXMLException: java.security.InvalidKeyException: Private keys > must be > > > instance of RSAPrivate(Crt)Key or have PKCS#8 encoding > > > at AssinaturaXMLEnveloped.assinar(AssinaturaXMLEnveloped.java:86) > > This stack trace doesn't help. The AssinaturaXMLException is swallowing the > > stack trace of the cause: InvalidKeyException. I need to have that the stack > > trace of the InvalidKeyException to be able to help. > > Ok. I think this may help: > > javax.xml.crypto.dsig.XMLSignatureException: java.security.InvalidKeyException: > Private keys must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding Hello I solved the problem just changing the way i get the instance of the KeyStore: It was: "this.repositorio = KeyStore.getInstance("PKCS11", provider);" Now is: "this.repositorio = KeyStore.getInstance("PKCS11");" I singed the xml many times, without closing the application and it´s is working fine now. But i still have some doubts.... 1) If i use KeyStore.getInstance("PKCS11", provider) The Exception doesnt occurs at the first time and the xml document is signed normally. However, i if try to sign again, the exception occurs. why ? is it a Bug ? 2) What´s the difference between each one? When use each one ? Tks
> But i still have some doubts.... > > 1) If i use KeyStore.getInstance("PKCS11", provider) The Exception doesnt occurs > at the first time and the xml document is signed normally. However, i if try to > sign again, the exception occurs. why ? is it a Bug ? I don't think so. The only thing that makes sense to me is that the first key is software based, and then the subsequent keys are hardware based and used with a cached Signature object that is software based. Are you reusing the XMLSignature objects each time you sign? Have you tried extracting the key contents to see if it is hardware or software (ex: Key.getFormat should return "RAW" if it is hardware). > > 2) What´s the difference between each one? When use each one ? I don't think I understand the question. > > Tks
(In reply to comment #6) > > > But i still have some doubts.... > > > > 1) If i use KeyStore.getInstance("PKCS11", provider) The Exception doesnt occurs > > at the first time and the xml document is signed normally. However, i if try to > > sign again, the exception occurs. why ? is it a Bug ? > I don't think so. The only thing that makes sense to me is that the first key is > software based, and then the subsequent keys are hardware based and used with > a cached Signature object that is software based. Are you reusing > the XMLSignature objects each time you sign? Have you tried extracting the key > contents to see if it is hardware or software (ex: Key.getFormat should > return "RAW" if it is hardware). > > > > 2) What´s the difference between each one? When use each one ? > I don't think I understand the question. > > > > Tks No. I am not reusing the XMLSignature objects each time i sign. Yes. I tried extracting the key contents: "SunPKCS11-SmartCard RSA private key, 1024 bits (id 1, token object, not sensitive, unextractable) " the question 2 is: what's the difference between using KeyStore.getInstance ("PKCS11", provider) and using KeyStore.getInstance("PKCS11"). When use each one ? I know that to use KeyStore.getInstance("PKCS11") i must have to call Security.addProvider() before. but...which use ?
I'm experiencing the same kind of weird behavior when I try to sign twice. The code does something like: Document document = loadDocument(); smartCard.open(...); // registers SunPKCS11 provider PrivateKey privateKey = smartCard.getPrivateKey(); // from the keystore xmlSign(document, privateKey, ...); smartCard.close(); // removes SunPKCS11 provider smartCard.open(...); // registers SunPKCS11 provider again PrivateKey privateKey = smartCard.getPrivateKey(); xmlSign(document, privateKey, ...); The second sign operation gives me: Caused by: org.apache.xml.security.signature.XMLSignatureException: Private key must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding Original Exception was 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.signature.XMLSignature.sign(Unknown Source) In my smart card code it doesn't matter whether to use KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", this.pkcs11Provider, callbackHandlerProtection); or ...("PKCS11", null, callbackHandlerProtection); I always get the exception. The funny thing is that I can sign twice via a non-XML signature, i.e., using Signature.getInstance("SHA1withRSA"); but, when using xmlsec, it's throwing the exception.
Ok, I looked into this a little bit more and still need more details. First, if you remove the SunPKCS11 provider and create a new instance, then any PrivateKey objects from the old SunPKCS11 instance will not be usable with the new instance (and this exception will be thrown). If the privateKey object is from the new provider, it should work. Can you let me know if you are doing this?
(In reply to comment #9) > Ok, I looked into this a little bit more and still need more details. > > First, if you remove the SunPKCS11 provider and create a new instance, then any > PrivateKey objects from the old SunPKCS11 instance will not be usable with the > new instance (and this exception will be thrown). > If the privateKey object is from the new provider, it should work. > > Can you let me know if you are doing this? Each time i sign, i add the provider (Security.addProvider(p)) and create a new PrivateKey object. Im not reusing nothing.. is it correct ? or i must have to remove and add the provider each time? from what i know...when we use the addProvider, it add the provider in the available slot, but we can add in a specific slot, just using addProviderAt(p, 2) for instance.
> Each time i sign, i add the provider (Security.addProvider(p)) and create a new > PrivateKey object. Im not reusing nothing.. is it correct ? or i must have to > remove and add the provider each time? from what i know...when we use the > addProvider, it add the provider in the available slot, but we can add in a > specific slot, just using addProviderAt(p, 2) for instance. Ahh, here's what I think is happening: The first time you call Security.addProvider(p), your provider is added correctly, you create a new PrivateKey object using that same provider and the xml signing operation works ok. The next time you create a new provider and call Security.addProvider(p), I bet the provider is not added because it is already installed (from the APIs standpoint, it is the same provider even though it is a new instance). Check the return value of addProvider to see if it returns -1. *But* (and this is a major but), you then use the new provider instance to create a PrivateKey object. There's the problem. When you use this PrivateKey to sign, the xml signature cannot find the provider that you used to create it (since it is not installed, it only finds the old provider but that won't work with the new PrivateKey) and therefore the signing operation fails because it cannot find a provider that the key can be used with. Workarounds: Either, 1) explicitly remove the provider before you reinstall it each time, or 2) only create and install the provider once and always use this provider to create the PrivateKeys. Please confirm if this is the case.
(In reply to comment #11) > > Each time i sign, i add the provider (Security.addProvider(p)) and create a new > > PrivateKey object. Im not reusing nothing.. is it correct ? or i must have to > > remove and add the provider each time? from what i know...when we use the > > addProvider, it add the provider in the available slot, but we can add in a > > specific slot, just using addProviderAt(p, 2) for instance. > > Ahh, here's what I think is happening: > > The first time you call Security.addProvider(p), your provider is added > correctly, you create a new PrivateKey object using that same provider and > the xml signing operation works ok. > > The next time you create a new provider and call Security.addProvider(p), > I bet the provider is not added because it is already installed (from the APIs > standpoint, it is the same provider even though it is a new instance). Check > the return value of addProvider to see if it returns -1. > > *But* (and this is a major but), you then use the new provider instance to > create a PrivateKey object. There's the problem. When you use this PrivateKey > to sign, the xml signature cannot find the provider that you used to create it > (since it is not installed, it only finds the old provider but that won't > work with the new PrivateKey) and therefore the signing operation fails because > it cannot find a provider that the key can be used with. > > Workarounds: > > Either, 1) explicitly remove the provider before you reinstall it each > time, or 2) only create and install the provider once and always use > this provider to create the PrivateKeys. > > Please confirm if this is the case. Exactly! the addProvider is returning -1 at the second time! (the first returned a high position: 7). however i am not having problems anymore because im using like this: Security.addProvider(p); KeyStore.getInstance("PKCS11"); If i use KeyStore.getInstance("PKCS11", p), then i get the exception the second time! Sean Mullan, Thank you very much for your clarifications! i am doing this as a part of my monograph project (Information Systems course). I will put your name in the gratfulness area! :))
Closing this out, as it looks like my explanation is correct and the problem has been resolved.
As PKCS#11 has so great design, a separate instance must be instantiate for each slot of each provider. I tried to do what you requested, registered the provider to system, and passed null to KeyStore.Builder as a provider and it does work. But I don't think this is a valid solution, as there is no reason why all providers should be added to the global scope.
Thought about this again... And I don't think this solution is valid. By convention all crypto functions throughout the SDK API accept explicit provider. If you can find another exception to this rule I may understand and drop this... But if xmlsec is the only exception, than it should sync up.
(In reply to comment #15) > Thought about this again... > And I don't think this solution is valid. > By convention all crypto functions throughout the SDK API accept explicit > provider. > If you can find another exception to this rule I may understand and drop > this... > But if xmlsec is the only exception, than it should sync up. xmlsec/jsr 105 are at a higher layer than the JCE APIs. I still think there should be a workaround to your problem. Something is happening in your code that causes the PrivateKey's provider to be different than what is in the JRE's list of Providers. Have you tried the solution in this bug report, that is: Security.addProvider(p); KeyStore.getInstance("PKCS11");
I seem to be experiencing the same problem reported in this bug, but no workaround seems to be effective, apart form restarting the application altogether. The situation I have is this: my application makes use of several different types of KeyStore. The user can use a configuration window to select which one to use, and even change some properties (e.g. the .dll module for the PKCS11 provider, or the slot number). The application uses the selected provider to send SOAP requests using Axis/Rampart 1.3. I have written a replacement Crypto class for Rampart that gets the keys and certificates from the correct keystore/provider. While everything works fine with JKS keystores, the PKCS11 provider only works until it gets reconfigured. Please note that I remove the previous Provider instance entirely, discard all previously obtained keys and keystores and recreate everything anew, but only the very first instance of the PKCS11 provider works. Code excerpt: ---------------------------------------------------- StringBuilder sb = new StringBuilder(); sb.append("name = "); sb.append(providerName); sb.append("\nlibrary = "); sb.append(ConfigManager.getInstance().getConf().getDllPkcs11()); // Get the selected PKCS11 DLL sb.append("\nslot ="); sb.append(ConfigManager.getInstance().getConf().getPkcs11Slot()); // Get the selected slot sb.append("\ndisabledMechanisms = { CKM_SHA1_RSA_PKCS }\n"); String pkcs11config = sb.toString(); byte pkcs11configBytes[] = pkcs11config.getBytes(); ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes); if (Security.getProvider(fullProvName)!=null) // Provider name + SunPKCS11 prefix Security.removeProvider(fullProvName); prov = new SunPKCS11(configStream); Security.insertProviderAt(prov, 1); // This is done to have Rampart select this provider for signature operations. ks = KeyStore.getInstance("PKCS11"); ----------------------------------------------------- Any key obtained after the first ever Provider instance gets replaced leads to this exception: ----------------------------------------------------- org.apache.ws.security.WSSecurityException: Signature creation failed; nested exception is: org.apache.xml.security.signature.XMLSignatureException: Private key must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding Original Exception was 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.ws.security.message.WSSecSignature.computeSignature(WSSecSignature.java:663) at org.apache.rampart.builder.AsymmetricBindingBuilder.doSignature(AsymmetricBindingBuilder.java:611) at org.apache.rampart.builder.AsymmetricBindingBuilder.doSignBeforeEncrypt(AsymmetricBindingBuilder.java:385) at org.apache.rampart.builder.AsymmetricBindingBuilder.build(AsymmetricBindingBuilder.java:95) at org.apache.rampart.MessageBuilder.build(MessageBuilder.java:131) at org.apache.rampart.handler.RampartSender.invoke(RampartSender.java:64) at org.apache.axis2.engine.Phase.invoke(Phase.java:292) at org.apache.axis2.engine.AxisEngine.invoke(AxisEngine.java:212) at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:377) at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:374) at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:211) at org.apache.axis2.client.OperationClient.execute(OperationClient.java:163) ----------------------------------------------------- Is there any way to replace the PKCS11 provider without having to restart the application? Note that since I have to change the configuration parameters at run-time I cannot leave the first provider instance alone...
Have you tried the workaround implemented in bug 43056: In order to use a specific provider, you must pass the Provider object as a property to the XMLSignContext or XMLValidateContext, ex: signContext.setProperty ("org.jcp.xml.dsig.internal.dom.SignatureProvider", new MyProvider());
Unfortunately I do not have access to the signature contexts, as they are entirely handled by Rampart. In fact to 'encourage' Rampart to use the right provider I force it to the highest priority, by using Security.insertAt(). However from my testing it seems that Rampart does select the right provider, but the provider fails to work if it's not the first time that it has been instanced. If I don't try to remove and recreate it, it works any number of times. If I have to change any parameter (for example the slot number) I have to restart the application (and the virtual machine).
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.
I have a coworker who is experiencing this problem. The error doesn't happen in 1.3.0. Something changed in the interim. We first saw this in 1.4.1, and reproed it in 1.4.3
(In reply to comment #21) > I have a coworker who is experiencing this problem. > The error doesn't happen in 1.3.0. Something changed in the interim. We first > saw this in 1.4.1, and reproed it in 1.4.3 I am not sure if the cause of the problem is the same, but regarding my case (see comment #20) the optimization with the "SignatureAlgorithm.instancesSigning" variable was introduced in r413543 on Jun 11 2006 (as "instances" variable, later split into "instancesSigning" and "instancesVerify"). Version 1.3 was released in October 2005; Version 1.4 - in January 2007. So yes, that happened in the interim.