无法使用PKCS1私钥和java密钥库进行客户端身份验证
我有公钥和私钥PKCS1:e,即将BEGIN RSA私钥作为单独的字符串输入。 这些键是使用以下命令创建的:无法使用PKCS1私钥和java密钥库进行客户端身份验证,java,keystore,private-key,java-10,pkcs#1,Java,Keystore,Private Key,Java 10,Pkcs#1,我有公钥和私钥PKCS1:e,即将BEGIN RSA私钥作为单独的字符串输入。 这些键是使用以下命令创建的: openssl req -new -x509 -keyout ca-key.pem -out ca-cert.pem -days 365 -passout pass:abcd123 -subj "/C=IN/ST=KAD/L=CAT/O=MIN/OU=OPQ/CN=*.xyz.com/emailAddress=xxx.xxxx@xyz.com" openssl genrsa -out c
openssl req -new -x509 -keyout ca-key.pem -out ca-cert.pem -days 365 -passout pass:abcd123 -subj "/C=IN/ST=KAD/L=CAT/O=MIN/OU=OPQ/CN=*.xyz.com/emailAddress=xxx.xxxx@xyz.com"
openssl genrsa -out client_private.key 2048
openssl req -new -sha256 -key client_private.key -subj "/C=IN/ST=KAD/L=CAT/O=MIN/OU=OPQ/CN=client.xyx.com" -out client.csr
openssl x509 -req -in client.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client.crt -days 365 -sha256
openssl x509 -in client.crt -out client.pem -outform PEM
其中client.csr的内容作为公钥字符串提供
并且client_private.key的内容作为私钥字符串提供
现在我必须创建java密钥库,添加这些密钥并实际导出为JKS文件。
我已经通过了多个链接,并尝试反弹城堡的例子,但我得到以下错误
javax.net.ssl.SSLProtocolException: Handshake message sequence violation, 2
我正在编写一个kafka客户端,启用了SSL和客户端身份验证,并且服务器设置了所有必需的参数。
创建信任存储和密钥存储命令行工作正常。
但使用java程序我无法做到客户端身份验证SSL工作正常。
下面是代码剪贴:
public void initClientAuthStore(String certString, String keyString)
throws GeneralSecurityException, IOException {
clientAuthStore = KeyStore.getInstance(getType());
clientAuthStore.load(null, getPassword().toCharArray());
Certificate clientCert = CertificateHandler.getCertificate(certString);
Certificate[] certificateChain = {trustStoreCertificate, clientCert};
log.debug("initClientAuthStore: Certificate is created");
// keyString.getBytes(StandardCharsets.UTF_8);
// clientAuthStore.setKeyEntry(
// keyStoreAlias, getPrivateKey(keyString), getPassword().toCharArray(), certificate);
PrivateKey privateKey = getPrivateKey(keyString);
clientAuthStore.setKeyEntry(
keyStoreAlias,
privateKey,
getPassword().toCharArray(),
certificateChain);
log.debug("initClientAuthStore: setting certificate and private key is success.");
}
public PrivateKey getPrivateKey(String key) throws IOException {
PemObject privateKeyObject;
PemReader pemReader =
new PemReader(
new InputStreamReader(
new ByteArrayInputStream(key.getBytes(Charset.forName("UTF-8"))),
StandardCharsets.UTF_8));
privateKeyObject = pemReader.readPemObject();
RSAPrivateCrtKeyParameters privateKeyParameter;
if (privateKeyObject.getType().endsWith("RSA PRIVATE KEY")) {
log.info("PRIVATE KEY TYPE: pkcs#1");
// PKCS#1 key
RSAPrivateKey rsa = RSAPrivateKey.getInstance(privateKeyObject.getContent());
privateKeyParameter =
new RSAPrivateCrtKeyParameters(
rsa.getModulus(),
rsa.getPublicExponent(),
rsa.getPrivateExponent(),
rsa.getPrime1(),
rsa.getPrime2(),
rsa.getExponent1(),
rsa.getExponent2(),
rsa.getCoefficient());
} else if (privateKeyObject.getType().endsWith("PRIVATE KEY")) {
log.info("PRIVATE KEY TYPE: pkcs#8");
// PKCS#8 key
privateKeyParameter =
(RSAPrivateCrtKeyParameters) PrivateKeyFactory.createKey(privateKeyObject.getContent());
} else {
throw new RuntimeException("Unsupported key type: " + privateKeyObject.getType());
}
JcaPEMKeyConverter jcaPemKeyConverter = new JcaPEMKeyConverter();
PrivateKey privateKey =
jcaPemKeyConverter.getPrivateKey(
PrivateKeyInfoFactory.createPrivateKeyInfo(privateKeyParameter));
log.info("PRIVATE KEY generated. {}", privateKey.getFormat());
return privateKey;
}
获取以下错误:
javax.net.ssl.SSLProtocolException: Handshake message sequence violation, 2
不确定出了什么问题,以及我是否缺少任何编码/解码等。。
我得到PKCS1私钥作为字符串输入,我必须使用bouncy castle转换为PKCS8并生成privatekey并添加到存储。
注意:私钥是客户端的内容。私钥不是答案,但对注释来说太多了 其中client.csr的内容作为公钥字符串提供 CSR不是公钥,而是CSR。但是,您显示的代码显然没有使用它。它显然使用了证书,它也不是公钥,它是一个证书,它包含一个公钥。但是,SSL/TLS身份验证使用的是证书,而不是公钥或CSR 我得到PKCS1私钥作为字符串输入,我必须使用bouncy castle转换为PKCS8并生成privatekey并添加到存储 您实际上不需要转换为PKCS8;PEMParser加上JcaPEMKeyConvertor可以将PKCS1直接转换为包含可用RSAPrivateKey的密钥对,这要简单得多。或者OpenSSL可以很容易地创建PKCS8密钥,没有BouncyCastle的标准JCE可以读取该密钥,或者PKCS12已经是一个Java密钥库,没有任何类型的转换。但你所拥有的确实有用 现在我必须创建java密钥库,添加这些密钥并实际导出为JKS文件 旁白:你的意思可能是编程,而不是实用。您的代码不导出任何密钥库文件,也不需要导出;而且您不需要使用JKS密钥库,具体来说,任何受支持的内存密钥库都应该可以工作,尽管您没有显示执行连接和使用密钥库的代码。大约两年前,Oracle开始使用Java9,建议人们停止使用JKS,改用PKCS12,尽管我怀疑他们是否会很快放弃JKS javax.net.ssl.SSLProtocolException:握手消息序列冲突,2 这是您的实际问题,它不是密钥库或密钥,也不应该是证书。即使您发送的密钥和证书不喜欢,服务器也应该通过拒绝协议内的身份验证来响应,而不是违反协议。2是ServerHello,它应该只在证书被发送或检查到任何一个方向之前出现。至少执行以下操作之一: :使用sysprop javax.net.debug=ssl运行,握手并捕获/记录输出。在Java11下面,您实际上可以只使用ssl,它自动包括握手。这将准确地显示您的系统正在发送和接收什么,并允许确定它是如何错误的,这至少有助于确定原因 使用wireshark、tcpdump或类似的网络跟踪捕获握手,并查看它。即使Java中存在不应该存在但至少有一点难以解码的严重错误,并且如果您不十分小心,在同一时间段内可能存在包括网络上其他数据在内的敏感和不可共享的风险,这种方法仍然有效 如果可能的话,尝试使用相同的密钥+证书从同一台机器连接到另一个或多个工具-这可能是一个与网络相关的问题,取决于您从何处连接。因为您已经有了openssl,并且已经有了openssl格式的文件,所以最简单的方法是使用 openssl s_客户端-connect$host:$port-key-keyfile-cert-certfile[见正文] s_client也是不同寻常的独特AFAIK,因为您可以控制是否发送SNI服务器名称指示扩展,并且现在有许多服务器可能会影响服务器的行为,可能会触发或抑制错误。Java JSSE是否发送SNI取决于您通常没有告诉我们的几个因素的组合:始终是Java的版本,通常是进行连接尝试的代码的一些细节,特别是它是否使用HttpsURLConnection、new-j11+HttpClient、第三方代码(如Apache或google)或自定义代码。对于1.1.0版本的OpenSSL,默认情况下不会发送SNI,您必须添加-servername$host才能发送SNI。对于1.1.1,默认情况下会发送,但如果添加-noservername,则不会发送 . 在本例中,我没有指定信任库。默认情况下,s_客户端将根据其默认信任库进行验证,该信任库可能对您的服务器是正确的,也可能对您的服务器是正确的,但将忽略任何错误并继续。如果您正在调试一个证书信任问题,那么将OpenSSL的信任库与Java使用的信任库相匹配是很重要的,但这并不是针对您的问题 向服务器运营商询问他们是如何看待这个问题的:他们是否认为您的握手有问题,如果有,是什么问题?它们运行的是什么软件或通常更相关的中间件,配置或选项是什么 如果您在Q中添加了一些/足够的信息,我将尝试更新此信息,使其成为实际答案