Reputation: 123
I have to create PKCS10 certificate request for RSA keypair stored on cryptocard with access via PKCS11 interface. The thing is that I can't use standard RSA algorithms in PKCS10 creation process and I can't get private key from cryptocard, so crypto operations should be done on cryptocard side. How can I prepare (maybe manually) PKCS10 request using PKCS11 interface for signing?
@Edit Now I have an error like this:
Exception in thread "main" java.security.ProviderException: Initialization failed
at sun.security.pkcs11.P11Signature.initialize(P11Signature.java:310)
at sun.security.pkcs11.P11Signature.engineInitSign(P11Signature.java:391)
at java.security.Signature$Delegate.engineInitSign(Signature.java:1127)
at java.security.Signature.initSign(Signature.java:511)
at pkcs11.Main.stworzPkcs10(Main.java:65)
at pkcs11.Main.main(Main.java:53)
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_GENERAL_ERROR
at sun.security.pkcs11.wrapper.PKCS11.C_SignInit(Native Method)
at sun.security.pkcs11.P11Signature.initialize(P11Signature.java:302)
... 5 more
Java Result: 1
and code:
String zawartoscPlikuKonfiguracyjnego = new String(
"name=PKCS11\n" +
"library=" + sciezkaDoBibliotekiPkcs11);
FileOutputStream plikKonfiguracyjny = new FileOutputStream("pkcs11.cfg");
plikKonfiguracyjny.write(zawartoscPlikuKonfiguracyjnego.getBytes());
plikKonfiguracyjny.close();
File test = new File("pkcs11.cfg");
dostawcaPkcs11 = new SunPKCS11("pkcs11.cfg");
Security.addProvider(dostawcaPkcs11);
interfejsPkcs11 = KeyStore.getInstance("PKCS11",dostawcaPkcs11);
pin = new JPasswordField();
JOptionPane.showConfirmDialog(null, pin, "Podaj pin do tokena", JOptionPane.OK_CANCEL_OPTION);
interfejsPkcs11.load(null, pin.getPassword());
Key kluczPrywatny = null;
Key kluczPubliczny = null;
Enumeration<String> aliasy = interfejsPkcs11.aliases();
while(aliasy.hasMoreElements()) {
String alias = aliasy.nextElement();
if(interfejsPkcs11.isKeyEntry(alias)) {
kluczPrywatny = interfejsPkcs11.getKey(alias, pin.getPassword());
} else {
kluczPubliczny = interfejsPkcs11.getCertificate(alias).getPublicKey();
}
}
PKCS10 pkcs10 = new PKCS10((PublicKey) kluczPubliczny );
Signature sygnatura = Signature.getInstance("SHA1WithRSA", dostawcaPkcs11);
sygnatura.initSign((PrivateKey) kluczPrywatny);
X500Name nazwaX500 = new X500Name("Certyfikat testowy", "Developer", "Developer", "Warszawa", "Mazovia", "PL");
pkcs10.encodeAndSign(nazwaX500, sygnatura);
Upvotes: 3
Views: 6184
Reputation: 69410
I would recommend you try using the Sun PKCS#11 provider. You will need to follow the documentation to understand how to configure the provider to use the DLL supplied by your cryptocard supplier. (Also worth asking them their recommended approach to accessing the cryptocard from Java).
Once you have this working, you should be able to load your public and private keys from a keystore (again see the docs for how this works). Finally, you can use the JCE libraries to produce the signing request:
String CN = "Mr Foo";
String OU = "Foo Department";
String O = "Foo Ltd.";
String L = "Foosville";
String S = "Foouisiana";
String C = "GB";
PublicKey publicKey = //... load public key from keystore
PrivateKey privateKey = //... load private key from keystore
PKCS10 pkcs10 = new PKCS10(publicKey);
Signature signature = Signature.getInstance("SHA1WithRSA"); // or whatever
signature.initSign(privateKey);
X500Name x500Name = new X500Name(CN, OU, O, L, S, C);
pkcs10.encodeAndSign(new X500Signer(signature, x500Name));
try (ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs)) {
pkcs10.print(ps);
byte[] c = bs.toByteArray(); // <-- this is it! (save to disk maybe?)
}
Upvotes: 3