我必须为存储在cryptocard上的RSA密钥对创建PKCS10证书请求,并通过PKCS11接口进行访问。问题是我不能在PKCS10创建过程中使用标准的RSA算法而且我无法从密码卡中获取私钥,因此应该在密码卡方面进行加密操作。如何使用PKCS11接口准备(可能手动)PKCS10请求进行签名?
@Edit 现在我有这样的错误:
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
和代码:
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);
答案 0 :(得分:3)
我建议您尝试使用Sun PKCS#11提供程序。您需要按照the documentation了解如何配置提供程序以使用您的cryptocard供应商提供的DLL。 (另外值得向他们询问他们推荐的从Java访问密码卡的方法)。
一旦你有了这个工作,你应该能够从密钥库加载你的公钥和私钥(再次参见文档,了解它的工作原理)。最后,您可以使用JCE库来生成签名请求:
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?)
}