Java和HTTPS中导入的私钥问题
Java的keytool不提供从私钥创建新密钥库或将私钥导入现有jks存储的功能。我有一个服务主机,它要求他们生成私钥,并将私钥交给我们客户机来调用他们的服务 私钥和证书从firefox中下载,并在windows计算机上导出为p12格式的文件。我使用openssl将pkcs12转换为PEM文件。然后,我手动将该文件分别拆分为cert.der和privateKey.der文件。然后,我编写了一个java程序,将这一对导入到我们现有的密钥库使用bouncy castle中。运行程序后,我用keytool验证密钥库是否已创建并包含我的密钥/证书,并且看起来不错 下面是我运行它时收到的程序代码和错误消息。我还注意到当I keytool-printcert的指纹签名与firefox在其查看证书菜单中显示的不同,这是一个红旗吗 非常感谢您在这里提供的任何帮助和/或想法Java和HTTPS中导入的私钥问题,java,authentication,ssl,client,Java,Authentication,Ssl,Client,Java的keytool不提供从私钥创建新密钥库或将私钥导入现有jks存储的功能。我有一个服务主机,它要求他们生成私钥,并将私钥交给我们客户机来调用他们的服务 私钥和证书从firefox中下载,并在windows计算机上导出为p12格式的文件。我使用openssl将pkcs12转换为PEM文件。然后,我手动将该文件分别拆分为cert.der和privateKey.der文件。然后,我编写了一个java程序,将这一对导入到我们现有的密钥库使用bouncy castle中。运行程序后,我用keyto
private static InputStream fullStream(String fname) throws IOException {
File f = new File(fname);
if (f == null || f.exists() == false) {
System.out.println("File " + fname + " does not exist");
System.exit(1);
}
FileInputStream fis = new FileInputStream(f);
DataInputStream dis = new DataInputStream(fis);
byte[] bytes = new byte[dis.available()];
dis.readFully(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
return bais;
}
public static void main(String args[]) {
try {
if (args.length < 6) {
System.out
.println("\nImportPrivateKeyTool Usage: \njava ImportPrivateKeyTool parameters:\n"
+ "\n<keystoreFileName> - JKS format\n"
+ "\n<keystorePassword>\n"
+ "\n<keyFileName> - PKCS12 format \n"
+ "\n<keyPwd>\n"
+ "\n<keyAlias>\n");
System.out
.println("\n\nRequires jsse for PKCS12 keystore support \n"
+ " - source storetype can be JKS or PKCS12\n"
+ " - destination storetype must be JKS type (PKCS12 write not supported)\n");
System.exit(1);
}
String keystoreFileName = args[0];
String keystorePassword = args[1];
String keyFileName = args[2];
String keyPwd = args[3];
String keyAlias = args[4];
String certFileName = args[5];
System.setProperty("javax.net.ssl.keyStore", keystoreFileName);// ie
// "C:/Dev/security/keystores/.deluxeKeyStore.jks"
System.setProperty("javax.net.ssl.keyStorePassword",
keystorePassword);
Security.addProvider(new BouncyCastleProvider());
// initializing keystore , clear it first by passing null??
KeyStore ks = KeyStore.getInstance("JKS");// second param SUN?
// "SUN", //TODO allow
// passing of PKCS12 or
// JKS?
File f = new File(keystoreFileName);
if (f == null || f.exists() == false) {
//create new
ks.load(null, keystorePassword.toCharArray());//initialize
ks.store(new FileOutputStream(keystoreFileName),keystorePassword.toCharArray());
System.out.println("Keystore file " + keystoreFileName + " did not exist so created new key store.");
}
ks.load(fullStream(keystoreFileName),keystorePassword.toCharArray());
System.out.println("Using keystore-file : " + keystoreFileName);
KeyFactory kf = KeyFactory.getInstance("RSA");
BufferedReader br = new BufferedReader(new FileReader(keyFileName));
PEMReader privateKeyPEMReader = new PEMReader(br);
KeyPair kp = (KeyPair) privateKeyPEMReader.readObject();
PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded());
PrivateKey ff = kf.generatePrivate(keysp);//keysp
System.out.println("Successfully loaded into memory private key: "+ keyFileName);
// loading CertificateChain
CertificateFactory cf = CertificateFactory.getInstance("X.509");of
BufferedReader br2 = new BufferedReader(new FileReader(certFileName));// cert?
//InputStream certstream = fullStream(certFileName);
PEMReader certPEMReader = new PEMReader(br2);
Certificate cert = (Certificate)certPEMReader.readObject(); //TODO support chain array of certs..
Certificate[] certs = new Certificate[1];
certs[0] = cert;
// storing keystore
ks.setKeyEntry(keyAlias, ff, keyPwd.toCharArray(), certs);
System.out
.println("Key and certificate successfully imported as alias:"
+ keyAlias);
ks.store(new FileOutputStream(keystoreFileName),
keystorePassword.toCharArray()); // TODO use key pass
// instead? doubt it
System.out.println("Successfully saved updated key store.");
ClientKeyExchange, RSA PreMasterSecret, TLSv1
main, WRITE: TLSv1 Handshake, length = 876
SESSION KEYGEN:
PreMaster Secret:
<removed>....
CONNECTION KEYGEN:
Client Nonce:
<remove>.....
Server Nonce:
<remove>
Master Secret:
<removed>
Client MAC write Secret:
<removed>
Server MAC write Secret:
<removed>
Client write key:
<removed>
Server write key:
<removed>
... no IV used for this cipher
*** CertificateVerify
main, WRITE: TLSv1 Handshake, length = 262
main, WRITE: TLSv1 Change Cipher Spec, length = 1
*** Finished
verify_data: { 20, 221, 183, 152, 78, 193, 208, 28, 198, 116, 172, 58 }
***
main, WRITE: TLSv1 Handshake, length = 32
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, decrypt_error
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: decrypt_error
javax.net.ssl.SSLHandshakeException: Received fatal alert: decrypt_error
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1172)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at com.oflows.seam.test.deluxechecks.DeluxeChecksOrderProTest.main(DeluxeChecksOrderProTest.java:84)
我不确定我是否理解最终目标是什么 如果要使用PKCS12文件中已经存在的cert+私钥,则无需对其进行转换:使用Java中的PKCS12密钥库类型。您没有显示正在使用的客户端代码,但使用它的方法之一是将javax.net.ssl.keyStoreType设置为PKCS12 自Java 6以来,Sun/Oracle就提供了keytool,它可以将一对cert+私钥从密钥库(包括PKCS12)导入另一个密钥库,例如:
keytool -importkeystore -srckeystore thekeystore.p12 \
-srcstoretype PKCS12 \
-destkeystore thekeystore.jks \
-deststoretype JKS
这些选项不需要BouncyCastle,也不需要通过OpenSSL导出。您似乎没有使用您的CertificateFactory。我不知道为什么您可以直接从kp.getPrivate获取新的PrivateKey实例ff。还建议正确关闭OutputStreams,特别是因为您似乎正在使用相同的文件名向两个不同的输出流写入数据。