In a desperate attempt to workaround the SunMSCAPI related problem (in thread
2444737 I wrote another signed applet to perform signatures using a SunPKCS11 SmartCard implementation with the source as given below:
import java.security.*;
import javax.security.auth.callback.CallbackHandler;
import javax.swing.*;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Set;
public class TestSunPKCS11 extends JApplet {
@Override
public void init() {
log("init() OS="+System.getProperty("os.name")+", Java="+System.getProperty("java.version")+", "+this.getClass().getPackage().getImplementationVersion());
Container content = getContentPane(); JTextArea t = new JTextArea("Hello PKCS11!"); t.setLineWrap(true); content.add(t);
String pkcs11Config = "name = SmartCard"+System.getProperty("line.separator")+"library = c:\\windows\\system32\\pteidpkcs11.dll";
byte[] pkcs11configBytes = pkcs11Config.getBytes();
ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes);
final Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);
Security.addProvider(pkcs11Provider);
CallbackHandler cmdLineHdlr = new com.sun.security.auth.callback.DialogCallbackHandler();
KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", pkcs11Provider,
new KeyStore.CallbackHandlerProtection(cmdLineHdlr));
KeyStore aKeyStore;
PrivateKey privateKey;
X509Certificate certificate;
String alias = "CITIZEN SIGNATURE CERTIFICATE";
//String alias = "CITIZEN AUTHENTICATION CERTIFICATE";
char[] password = "xxxx".toCharArray(); //"password".toCharArray();
byte[] data = "Data to be signed!".getBytes();
String aliasCode = null;
try {
aKeyStore = builder.getKeyStore();
//aKeyStore = KeyStore.getInstance("PKCS11");
//aKeyStore = KeyStore.getInstance("PKCS11",pkcs11Provider);
//aKeyStore.load(null,password);
log("ks provider=" + aKeyStore.getProvider().getInfo());
Set<Service> ss = aKeyStore.getProvider().getServices();
for (Service s : ss) {
PDFSignerApplet.log("s.getType="+s.getType()+", algorithm="+s.getAlgorithm());
}
//aKeyStore.load(null);
Enumeration<String> aliases = aKeyStore.aliases();
while (aliases.hasMoreElements()) {
String a = aliases.nextElement(); log("keystore alias: " + a);
if (alias.equals(a)) {
log(" selected " + a);
aliasCode = a;
}
}
final PrivateKey key = (PrivateKey) aKeyStore.getKey(alias, null);
final java.security.cert.Certificate[] chain = aKeyStore.getCertificateChain(alias);
final Signature sign = Signature.getInstance("SHA1withRSA",aKeyStore.getProvider()); // PKCS11-SmartCard provider failed before with 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:101)...
sign.initSign(key);
sign.update(data);
byte[] ba0 = sign.sign(); // BREAKS HERE with sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ARGUMENTS_BAD
display("Sig0:",ba0);
privateKey = (PrivateKey) aKeyStore.getKey(aliasCode, password);
certificate = (X509Certificate) aKeyStore.getCertificate(aliasCode);
//privateKey = key;
//certificate = (X509Certificate)chain[0];
//aKeyStore.load(null);
Signature signature = sign;
//Signature signature = Signature.getInstance("SHA1withRSA");
//signature.initSign(privateKey);
signature.update(data);
// Sign again
byte[] ba1 = signature.sign();
display("Sig1:", ba1);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void display(String aLabel, byte[] ba) {
StringBuffer sb = new StringBuffer();
for (byte b : ba) {
sb.append(String.format("%02x", b)).append(" ");
}
log(aLabel+" "+sb);
}
public static void log(String aMsg) {
System.out.println(aMsg);
}
}
For this source I get the following console log:
init() OS=Windows 7, Java=1.7.0_07, 2.0.30.build563
ks provider=SunPKCS11-SmartCard using library c:\windows\system32\pteidpkcs11.dll
...
s.getType=Signature, algorithm=SHA1withRSA
...
s.getType=KeyStore, algorithm=PKCS11
keystore alias: CITIZEN AUTHENTICATION CERTIFICATE
keystore alias: CITIZEN SIGNATURE CERTIFICATE
selected CITIZEN SIGNATURE CERTIFICATE
java.security.ProviderException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ARGUMENTS_BAD
at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:547)
at java.security.Signature$Delegate.engineSign(Unknown Source)
at java.security.Signature.sign(Unknown Source)
at org.itij.applet.TestSunPKCS11.init(TestSunPKCS11.java:82)
at com.sun.deploy.uitoolkit.impl.awt.AWTAppletAdapter.init(Unknown Source)
at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_ARGUMENTS_BAD
at sun.security.pkcs11.wrapper.PKCS11.C_SignFinal(Native Method)
at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:509)
... 6 more
I am not sure that this problem is reproducible (as I think I have gotten a " java.security.InvalidKeyException: Private keys must be instance of RSAPrivate(Crt)Key or have PKCS#8 encoding" error before but the DLL provider documents this signing algorithm as supported), but, as I am not a PKCS#11 implementation expert, I have no clue what the current error message is, or what is wrong.
If this is a problem of the underlying DLL, how can I build a bug report to the DLL provider ? If it is with my code, I would appreciate if anyone can explain what I am doing wrong.
Joao