Law*_*Dol 7 java ssl ibm-midrange
我正在使用旧的IBM iSeries(IBM-i,i5OS,AS/400等),在O/S版本V5R3M0上使用Java 5 JVM(Classic,而不是ITJ J9).
简而言之,这是一个场景:
这一切都按预期工作.
但是,当我运行JVM时,正确配置指向商店并提供密码(我过去使用在Portecle中创建的自签名证书进行测试),并尝试在443上启动我的Web服务器,我收到以下安全异常:
java.security.KeyStoreException: Cannot store non-PrivateKeys
Run Code Online (Sandbox Code Playgroud)
谁能告诉我哪里出错了,或者我接下来要检查什么?
小智 36
"无法存储非PrivateKeys"错误消息通常表示您正在尝试使用具有JKS密钥库类型的秘密对称密钥.JKS密钥库类型仅支持非对称(公共/私有)密钥.您必须创建一个JCEKS类型的新密钥库来支持密钥.
事实证明,这是一个微妙的问题,如果其他人有类似的东西,这里值得给出答案.
TLDR的答案是我没有检查我的密钥和证书是否为空,因此尝试将空密钥和证书添加到密钥库.更长的答案如下.
我们将Web服务器设置为使用SSL的方式,特别是支持我们用户的典型配置,其中IP地址用于配置网站侦听地址而不是DNS名称,它是将证书定位在主密钥中 - 使用别名存储,并创建一个仅包含该网站证书的临时密钥存储区,使用该密钥存储区配置SSL上下文和SSL套接字工厂,如下所示:
// CREATE EPHEMERAL KEYSTORE FOR THIS SOCKET USING THE DESIRED CERTIFICATE
try {
final char[] BLANK_PWD=new char[0];
SSLContext ctx=SSLContext.getInstance("TLS");
KeyManagerFactory kmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
Key ctfkey=mstkst.getKey(svrctfals,BLANK_PWD);
Certificate[] ctfchn=mstkst.getCertificateChain(svrctfals);
KeyStore sktkst;
sktkst=KeyStore.getInstance("jks");
sktkst.load(null,BLANK_PWD);
sktkst.setKeyEntry(svrctfals,ctfkey,BLANK_PWD,ctfchn);
kmf.init(sktkst,BLANK_PWD);
ctx.init(kmf.getKeyManagers(),null,null);
ssf=ctx.getServerSocketFactory();
}
catch(java.security.GeneralSecurityException thr) {
throw new IOException("Cannot create server socket factory using ephemeral keystore ("+thr+")",thr);
}
Run Code Online (Sandbox Code Playgroud)
请注意,它使用空密码从主密钥库中提取私钥和证书.这是我的问题 - 出于习惯使用keytool,我创建了带密码的私钥对(与密钥库相同的密码).
因为我在证书上有密码,所以没有提取密钥和证书,并且传递了null sktkst.setKeyEntry(svrctfals,ctfkey,BLANK_PWD,ctfchn); 但是,setKeyEntry检查传递的Key使用instanceof并结束(正确)null不是instanceof PrivateKey,导致我看到的误导性错误.
更正的代码检查是否找到密钥和证书并发送相应的错误:
// CREATE EPHEMERAL KEYSTORE FOR THIS SOCKET USING THE DESIRED CERTIFICATE
try {
final char[] BLANK_PWD=new char[0];
SSLContext ctx=SSLContext.getInstance("TLS");
KeyManagerFactory kmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
Key ctfkey=mstkst.getKey(svrctfals,BLANK_PWD);
Certificate[] ctfchn=mstkst.getCertificateChain(svrctfals);
KeyStore sktkst;
if(ctfkey==null) {
throw new IOException("Cannot create server socket factory: No key found for alias '"+svrctfals+"'");
}
if(ctfchn==null || ctfchn.length==0) {
throw new IOException("Cannot create server socket factory: No certificate found for alias '"+svrctfals+"'");
}
sktkst=KeyStore.getInstance("jks");
sktkst.load(null,BLANK_PWD);
sktkst.setKeyEntry(svrctfals,ctfkey,BLANK_PWD,ctfchn);
kmf.init(sktkst,BLANK_PWD);
ctx.init(kmf.getKeyManagers(),null,null);
ssf=ctx.getServerSocketFactory();
}
catch(java.security.GeneralSecurityException thr) {
throw new IOException("Cannot create server socket factory using ephemeral keystore ("+thr+")",thr);
}
Run Code Online (Sandbox Code Playgroud)
您可以在单个SSLContext.
您需要SSLContext使用自定义的初始化X509KeyManager,而不是使用默认给出的初始化KeyManagerFactory。在此X509KeyManager,chooseServerAlias(String keyType, Principal[] issuers, Socket socket)应根据从套接字获取的本地地址返回不同的别名。
这样,您就不必担心将私钥从一个密钥库复制到另一个密钥库,这甚至适用于您无法从中提取(并因此复制)而只能使用私钥的密钥库类型,例如 PKCS #11。
| 归档时间: |
|
| 查看次数: |
16669 次 |
| 最近记录: |