Java 将second.p12导入密钥库后握手失败且CA未知
我向密钥库添加了一个.p12证书(到目前为止还没有证书) 我在SOAPUI中使用了keyStore.p12,密码为myDestPassword,一切正常 现在,我在现有密钥库中导入了第二个.p12(参数相同): 导入成功了,但在我尝试使用更新的keyStore.p12(与之前相同的wsdl和地址)进行SOAP调用之后,我得到了 有人知道为什么吗 更新: 我还尝试在Java应用程序中使用这个密钥存储。行为是一样的。我添加了第一个证书-->它可以工作。我添加了第二个证书,但我得到了一个错误,但现在,我的错误是:Java 将second.p12导入密钥库后握手失败且CA未知,java,soap,ssl-certificate,soapui,keytool,Java,Soap,Ssl Certificate,Soapui,Keytool,我向密钥库添加了一个.p12证书(到目前为止还没有证书) 我在SOAPUI中使用了keyStore.p12,密码为myDestPassword,一切正常 现在,我在现有密钥库中导入了第二个.p12(参数相同): 导入成功了,但在我尝试使用更新的keyStore.p12(与之前相同的wsdl和地址)进行SOAP调用之后,我得到了 有人知道为什么吗 更新: 我还尝试在Java应用程序中使用这个密钥存储。行为是一样的。我添加了第一个证书-->它可以工作。我添加了第二个证书,但我得到了一个错误,但现在,
Exception in thread "main" java.lang.Exception: myService.uploadParameters call FAILED with: com.sun.xml.internal.ws.client.ClientTransportException: HTTP-Transportfehler: javax.net.ssl.SSLHandshakeException: Received fatal alert: unknown_ca
更新2
这里是我的密钥库的内容
C:\>keytool -list -keystore KeyStore.p12 -storetype PKCS12
Keystore-Kennwort eingeben:
Keystore-Typ: PKCS12
Keystore-Provider: SunJSSE
Keystore enthält 2 Einträge
muster max (btt/beat2), 23.03.2020, PrivateKeyEntry,
Zertifikat-Fingerprint (SHA1): 03:A0:3C:0F:4A:91:1A:40:2D:C3:EC:A0:23:D5:E6:44:C5:29:34:DC
client_cert_muster, 23.03.2020, PrivateKeyEntry,
Zertifikat-Fingerprint (SHA1): 06:13:A2:8A:84:E8:F9:74:50:E8:BA:D3:79:9F:FB:5F:CB:09:1E:D0
我认为问题在于您试图将两个密钥对放在同一个中。p12和客户端通常只需要密钥对的公共部分,编码为X509证书。当.p12中有多个
PrivateKeyEntry
条目时,它似乎对该做什么感到困惑
要获取仅包含证书的PKCS12文件,请尝试以下操作:
keytool -exportcert -keystore FIRSTCert.p12 -storetype PKCS12 -storepass mySrcPassword -file firstcert.cer
keytool -exportcert -keystore SECONDCert.p12 -storetype PKCS12 -storepass 12345 -file secondcert.cer
keytool -importcert -keystore keyStore.p12 -storetype PKCS12 -storepass myDestPassword -file firstcert.cer
keytool -importcert -keystore keyStore.p12 -storetype PKCS12 -storepass myDestPassword -file secondcert.cer -alias mykey2
现在,当你做一个
keytool -list -keystore keyStore.p12 -storetype PKCS12 -storepass myDestPassword
Keystore type: PKCS12
Keystore provider: SUN
Your keystore contains 2 entries
mykey, 23 march 2020, trustedCertEntry,
Certificate fingerprint (SHA-256): 26:FB:B4:8F:42:9C:48:5E:EE:8D:35:2E:A5:1C:79:EA:23:B5:36:50:47:62:4D:BC:D1:3D:26:61:04:1C:1A:32
mykey2, 23 march 2020, trustedCertEntry,
Certificate fingerprint (SHA-256): C1:06:CA:06:F1:29:80:72:16:1F:F6:72:04:39:16:17:31:E0:7A:5B:28:BB:41:4C:77:8E:94:F1:C5:8D:70:F8
它应该有2个条目,它们的类型应该是trustedCertEntry
。这是您的信任库,它应该是您的客户建立TLS连接所需的唯一信任
除非你真的知道自己在做什么,否则不要将服务器的完整密钥对移出机器;它应该只有服务器知道。我认为问题在于您试图将两个密钥对放在同一个中。p12和客户端通常只需要密钥对的公共部分,编码为X509证书。当.p12中有多个
PrivateKeyEntry
条目时,它似乎对该做什么感到困惑
要获取仅包含证书的PKCS12文件,请尝试以下操作:
keytool -exportcert -keystore FIRSTCert.p12 -storetype PKCS12 -storepass mySrcPassword -file firstcert.cer
keytool -exportcert -keystore SECONDCert.p12 -storetype PKCS12 -storepass 12345 -file secondcert.cer
keytool -importcert -keystore keyStore.p12 -storetype PKCS12 -storepass myDestPassword -file firstcert.cer
keytool -importcert -keystore keyStore.p12 -storetype PKCS12 -storepass myDestPassword -file secondcert.cer -alias mykey2
现在,当你做一个
keytool -list -keystore keyStore.p12 -storetype PKCS12 -storepass myDestPassword
Keystore type: PKCS12
Keystore provider: SUN
Your keystore contains 2 entries
mykey, 23 march 2020, trustedCertEntry,
Certificate fingerprint (SHA-256): 26:FB:B4:8F:42:9C:48:5E:EE:8D:35:2E:A5:1C:79:EA:23:B5:36:50:47:62:4D:BC:D1:3D:26:61:04:1C:1A:32
mykey2, 23 march 2020, trustedCertEntry,
Certificate fingerprint (SHA-256): C1:06:CA:06:F1:29:80:72:16:1F:F6:72:04:39:16:17:31:E0:7A:5B:28:BB:41:4C:77:8E:94:F1:C5:8D:70:F8
它应该有2个条目,它们的类型应该是trustedCertEntry
。这是您的信任库,它应该是您的客户建立TLS连接所需的唯一信任
除非你真的知道自己在做什么,否则不要将服务器的完整密钥对移出机器;它应该只被服务器知道。Thx@Daniel-alot感谢他的帮助。 我终于找到了办法。我不知道这是不是正确的,但它是有效的。回答我。 启动应用程序时,我仅使用信任库初始化TLS:
static void initTLS(String trustStore, String trustStorePW ){
System.setProperty("https.protocols", "TLSv1.2")
System.setProperty("javax.net.ssl.trustStore",trustStore)
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePW)
}
现在是新的:在每次(SOAP)调用之前,我都会创建一个initKeyStore:
static void initKeyStore( String aliasName ){
String keyStorePW = "abc..."
String keyStorePath = "path/to/keyStore"
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] pwdArray = keyStorePW.toCharArray();
keystore.load(new FileInputStream(keyStorePath), pwdArray);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, keyStorePW.toCharArray());
final X509KeyManager origKm = (X509KeyManager)kmf.getKeyManagers()[0];
X509KeyManager km = new X509KeyManager() {
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return aliasName
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return origKm.getCertificateChain(alias);
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return origKm.getClientAliases(keyType, issuers)
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return origKm.getServerAliases(keyType, issuers)
}
@Override
public PrivateKey getPrivateKey(String alias) {
return origKm.getPrivateKey(alias);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return origKm.chooseServerAlias(keyType, issuers, socket );
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManager[] kms = [km]
sslContext.init(kms, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
参数aliasName
允许我控制密钥库中的哪个.p12证书将被获取。
我认为这是相当肮脏的,我将不得不优化这段代码。但最终还是成功了。谢谢丹尼尔的帮助。 我终于找到了办法。我不知道这是不是正确的,但它是有效的。回答我。 启动应用程序时,我仅使用信任库初始化TLS:
static void initTLS(String trustStore, String trustStorePW ){
System.setProperty("https.protocols", "TLSv1.2")
System.setProperty("javax.net.ssl.trustStore",trustStore)
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePW)
}
现在是新的:在每次(SOAP)调用之前,我都会创建一个initKeyStore:
static void initKeyStore( String aliasName ){
String keyStorePW = "abc..."
String keyStorePath = "path/to/keyStore"
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] pwdArray = keyStorePW.toCharArray();
keystore.load(new FileInputStream(keyStorePath), pwdArray);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, keyStorePW.toCharArray());
final X509KeyManager origKm = (X509KeyManager)kmf.getKeyManagers()[0];
X509KeyManager km = new X509KeyManager() {
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return aliasName
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return origKm.getCertificateChain(alias);
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return origKm.getClientAliases(keyType, issuers)
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return origKm.getServerAliases(keyType, issuers)
}
@Override
public PrivateKey getPrivateKey(String alias) {
return origKm.getPrivateKey(alias);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return origKm.chooseServerAlias(keyType, issuers, socket );
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManager[] kms = [km]
sslContext.init(kms, null, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
参数aliasName
允许我控制密钥库中的哪个.p12证书将被获取。
我认为这是相当肮脏的,我将不得不优化这段代码。但最后它还是起作用了。导入密钥库时是否指定了单独的别名?默认别名为
mykey
,第二次导入可能会重写第一次导入。通常,keytool
会就此发出警告,并询问您是否要继续,但您指定了-noprompt
,因此它可能只是按照您的指示进行了操作。别名不同,我也尝试了它,但没有“-noprompt”。相同的错误OK,为什么需要导入两个完整的密钥对?服务器如何知道使用哪一个密钥?通常,您会使用一个密钥库,其中包含一个PrivateKeyEntry
,作为服务器标识和CA证书链的TrustedCertificateEntry
。如果执行-importkeystore
然后执行-importcert
,是否会发生同样的情况?我有两个.p12证书,用于两台服务器。我的应用程序必须连接到两台服务器。所以使用-importcert
我的私钥会丢失?等一下,这是给客户的吗?您是否可以执行keytool-list-keystore keystore.p12-storetype pkcs12
并将输出包含在问题中?导入keystore时是否指定了单独的别名?默认别名为mykey
,第二次导入可能会重写第一次导入。通常,keytool
会就此发出警告,并询问您是否要继续,但您指定了-noprompt
,因此它可能只是按照您的指示进行了操作。别名不同,我也尝试了它,但没有“-noprompt”。相同的错误OK,为什么需要导入两个完整的密钥对?服务器如何知道使用哪一个密钥?通常,您会使用一个密钥库,其中包含一个PrivateKeyEntry
,作为服务器标识和CA证书链的TrustedCertificateEntry
。如果执行-importkeystore
然后执行-importcert
,是否会发生同样的情况?我有两个.p12证书,用于两台服务器。我的应用程序必须连接到两台服务器。所以使用-importcert
我的私钥会丢失?等一下,这是给客户的吗?你能做一个keytool-list-keystore keystore.p12-storetype pkcs12
并在问题中包含输出吗?谢谢你的回答,但我想我需要客户端的keystore来向服务器进行身份验证。我已经有一家信托商店了。到目前为止,我们在全球范围内的常见做法是订购.p12证书,-->使用此p12证书进行身份验证并下载crt(全部通过浏览器)--->将.crt放入信任库,将.p12放入密钥库-->在AppOk中进行Java调用,但从未提及此设置。我很清楚,您是否在Java应用程序中通过TLS使用基于客户端的身份验证?是的,客户端必须进行身份验证