当前位置: 首页 > 知识库问答 >
问题:

无法使用PKCS#1私钥和java密钥库进行客户端身份验证

魏泰
2023-03-14

我有公钥和私钥(PKCS#1:即具有“BEGIN RSA PRIVATE KEY”)作为单独的字符串输入。这些密钥是使用以下命令创建的:

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

客户端的内容。csr是作为公钥字符串提供的,客户端的内容是私有的。密钥作为私钥字符串提供

现在我必须创建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

不确定出了什么问题,以及我是否缺少任何编码/解码等。。我得到PKCS#1私钥作为字符串输入,我必须使用bouncy castle转换为PKCS#8并生成私钥并添加到存储。注意:私钥是客户端_private的内容。钥匙

共有1个答案

东门文斌
2023-03-14

(不是答案,但评论太多了。)

客户端的内容。csr作为公钥字符串提供。。。

CSR不是公钥,它是CSR。但是您显示的代码显然没有使用它。它显然使用了证书,它也不是公钥,它是一个证书——它包含一个公钥。但是,证书,而不是公钥或CSR,是用于SSL/TLS身份验证的正确东西。

我得到PKCS#1私钥作为字符串输入,我必须使用弹跳城堡转换为PKCS#8并生成私钥并添加到商店......

你实际上不需要转换成PKCS8;PEMParser plus JcaPEMKeyConvertor可以将PKCS1直接转换为包含可用(RSA)私钥的密钥对,这要简单得多。或者OpenSSL可以轻松创建标准JCE(不带BouncyCastle)可以读取的PKCS8密钥——或者PKCS12,它已经是一个Java密钥库,没有任何类型的转换。但你所拥有的确实有用。

现在我必须创建java密钥库,添加这些密钥,并实际导出为JKS文件。

旁白:你的意思可能是编程,而不是实用。您的代码不导出任何密钥库文件,也不需要导出;您不需要特别使用JKS密钥库,任何受支持的内存密钥库都应该可以工作,尽管您没有显示执行连接和使用密钥库的代码。从Java 9(大约两年前)开始,Oracle建议人们停止使用JKS,转而使用PKCS12,尽管我怀疑他们是否真的会很快放弃JKS。

javax。网ssl。SSLProtocolException:握手消息序列冲突,2

这是您的实际问题,它不是密钥库或密钥,也不应该是证书。即使您发送了一个密钥和它不喜欢的证书,服务器也应该通过拒绝协议内的身份验证来响应,而不是违反协议。2是ServerHello,它应该只在证书向任何方向发送或检查之前出现。至少执行以下操作之一:

>

使用wireshark、tcpdump或类似的网络跟踪捕捉握手,并查看它。即使Java中存在严重错误(不应该存在),但至少有一点难以解码,而且如果您不十分小心,在同一时间段内,网络上可能存在敏感和不可共享的其他数据等风险,这种方法也会起作用。

如果可能的话,尝试使用相同的密钥证书从同一台机器连接到另一个(或多个)工具——这可能是一个与网络相关的问题,取决于您从何处连接。因为您有openssl,并且已经有了openssl格式的文件,所以最简单的方法就是使用

openssls_client-connect$host:$port-key file-cert certfile[见文本]

s_client也是不寻常的(唯一的AFAIK),因为您可以控制是否发送SNI(服务器名称指示扩展),并且现在许多服务器很可能会影响服务器的行为(可能触发或抑制错误)。Java(JSSE)是否发送SNI通常取决于您没有告诉我们的几个因素的组合:总是Java的版本,通常是进行连接尝试的代码的一些细节,特别是它是否使用HttpsURLConnection、new-j11HttpClient、Apache或google等第三方代码或自定义代码。对于1.1.0的OpenSSL版本,默认情况下不发送SNI,您必须添加-serverame$host才能发送它。对于1.1.1,默认情况下会发送,但如果您添加-noservername则不会发送。

在此示例中,我没有指定信任库。默认情况下,s_client将根据其默认信任库进行验证,这对于您的服务器可能是正确的,但会忽略任何错误并继续进行。如果您正在调试证书信任问题,那么将OpenSSL的信任库与您的Java使用的信任库匹配非常重要,但不是针对您的问题。

向服务器运营商询问他们对这个问题的看法:他们是否认为你的握手有问题,如果有,是什么问题?它们运行的是什么软件(或通常是更相关的中间件),配置或选项是什么?

如果你把(一些/足够的)这些信息添加到你的Q中,我会尝试更新它,使之成为一个实际的答案。

 类似资料:
  • 我正在尝试使用私钥和公钥对为sftp服务器设置身份验证。 我已经在本地计算机上设置了带有Bitvise SSH服务器的sftp服务器。我用SSH服务器生成了私钥和公钥。我已经在SSH服务器的主机密钥部分上设置了私钥,并且已经创建了一个虚拟帐户并将公钥设置到该帐户。 谢谢

  • 我对RSA只有一些非常基本的理论知识。 在阅读不同来源的关于如何在实践中使用它的资料时,PKCS#1 OAEP似乎是一件好事。 对于测试实现,我使用Python和PyCrypto。例如,这是一个使用PKCS#1 OAEP的示例。 使用公钥加密,然后使用私钥解密,效果很好。例如,公众可以使用私钥向X个人发送一些数据。 从我对RSA工作原理的基本理解来看,我认为我可以交换公钥/私钥,也就是说,我可以使

  • 嗨,KeyClope开发人员和大师们, 我想设置KeyClope,使用openid连接2个领域 其中 Realm1 将包含客户端应用程序 而 realm2 包含用户 然后,用户将通过 realm2 进行身份验证来访问 realm1 中的客户端应用程序。 我发现这个链接——

  • JSch日志: 的日志:

  • HTTP/REST-需要对代码/token/etc进行身份验证,以便将数据传递到keyvault,以便keyvault将使用密钥库中的密钥对数据进行签名。 Azure有很多文档介绍如何注册我的应用程序,在密钥库中为它创建凭据,然后通过OATH2对它进行身份验证(第一步是通过REST获得代码(然后是令牌?)),我一直被重定向登录。 我是不是漏掉了什么?我希望我的python脚本在无人值守的情况下运行

  • 问题内容: 我正在用TastyPie制作内部API。我有 禁用身份验证规则后,我的API效果很好。启用它后,无论尝试如何,都会收到401(未经授权)的响应。 我敢肯定,一旦你看到它的实际作用,这就是其中的一件事,但与此同时,请告知如何提出请求(GET)。 问题答案: 将用户名和api_key参数添加到你的GET变量中。确保你拥有 设置时,请确保遵循docs的其他说明: ApiKey身份验证 作为要