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

建立安全连接时没有共同的密码套件

乜业
2023-03-14

我试图在两个Java项目之间建立安全连接,但我得到了一个SSLHandshakeException(没有共同的密码套件)。这是在双方创建套接字的方法:

客户:

private SSLSocket getSocketConnection() throws SSLConnectionException {
    try {

        /* Load properties */
        String keystore = properties.getProperty("controller.keystore");
        String passphrase = properties.getProperty("controller.passphrase");
        String host = properties.getProperty("controller.host");
        int port = Integer.parseInt(properties
                .getProperty("controller.port"));

        /* Create keystore */
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(new FileInputStream(keystore), passphrase.toCharArray());

        /* Get factory for the given keystore */
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);
        SSLContext ctx = SSLContext.getInstance("SSL");
        ctx.init(null, tmf.getTrustManagers(), null);
        SSLSocketFactory factory = ctx.getSocketFactory();

        return (SSLSocket) factory.createSocket(host, port);
    } catch (Exception e) {
        throw new SSLConnectionException(
                "Problem connecting with remote controller: "
                        + e.getMessage(), e.getCause());
    }
}

服务器:

private SSLServerSocket getServerSocket() throws SSLConnectionException {
    try {

        /* Load properties */
        Properties properties = getProperties("controller.properties");

        String keystore = properties.getProperty("controller.keystore");
        String passphrase = properties.getProperty("controller.passphrase");
        int port = Integer.parseInt(properties
                .getProperty("controller.port"));

        /* Create keystore */
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(new FileInputStream(keystore), passphrase.toCharArray());

        /* Get factory for the given keystore */
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(keyStore);
        SSLContext ctx = SSLContext.getInstance("SSL");
        ctx.init(null, tmf.getTrustManagers(), null);
        SSLServerSocketFactory factory = ctx.getServerSocketFactory();

        return (SSLServerSocket) factory.createServerSocket(port);
    } catch (Exception e) {
        throw new SSLConnectionException(
                "Problem starting auth server: "
                        + e.getMessage(), e.getCause());
    }
}

我有一个使用keytool生成的RSA密钥。此代码从磁盘加载它。

我做错了什么?

更新:我用这个数组在两边添加了对setEnabledCipherSuites的a调用:

String enableThese[] =
{
    "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
    "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
    "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"
};

我得到同样的结果。

共有1个答案

刘永望
2023-03-14

在服务器端,您没有初始化密钥库/密钥管理器,只初始化了信任库/信任管理器:< code>ctx.init(null,tmf.getTrustManagers(),null)。

在服务器上,初始化密钥管理器始终是配置服务器证书所必需的。仅当要使用客户机证书认证时,才需要初始化信任库。(本问题中有更多细节说明密钥管理器和信任管理器之间的区别。

如果没有配置任何密钥管理器,就没有基于RSA或DSA的证书可用,因此没有依赖证书进行身份验证的密码套件可用(所有默认启用的都可用)。因此,在客户机和服务器之间没有共同的密码套件。

你需要这样的东西:

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, password.toCharArray()); // That's the key's password, if different.
// ...
ctx.init(kmf.getKeyManagers(), null, null);

从您的示例来看并不清楚,但是您当然不应该在客户端(作为信任库)和服务器端(作为密钥库)使用同一个密钥库:私钥应该只为服务器所知,而不需要在客户端的信任库中。

编辑:(我将尝试以不同的方式重新解释,因为并非每个人都清楚。也许它可能会有所帮助。

以下代码使用密钥管理器的< code>null数组(第一个参数)初始化< code > SSL context :< code > CTX . init(null,tmf.getTrustManagers(),null)。(没有默认的密钥管理器。)

密钥管理器是管理(私有)密钥和证书的一部分,位于代码运行的一侧。在服务器上,密钥管理器负责处理服务器证书及其私钥。密钥管理器本身通常由“密钥库密钥库”初始化。Java中的“密钥库”可以有多种含义。密钥库的含义之一是可以将密钥和证书存储到其中的实体,通常是文件。这样的密钥库可用于初始化信任管理器1(在这种情况下,它被称为信任库)或密钥管理器(在这种情况下,它被称为密钥库)。抱歉,不是我选择的名称,但这是系统属性的调用方式。

当服务器配置空密钥管理器时,在配置时不带任何证书和关联的私钥。因此,它没有任何 RSA 或 DSA 证书。因此,它将无法使用任何 *_RSA_**_DSS_* 密码套件,无论它们是否已显式启用(由于缺少与它们一起使用的证书,它们将自动禁用)。这有效地丢弃了默认情况下启用的任何密码套件(或者无论如何都显式启用的任何此类密码套件)。因此,“没有共同的密码套件”。

简而言之,服务器端的SSLContext需要配置证书及其私钥2。这是通过配置其密钥管理器来完成的。反过来,这通常是通过使用具有KeyManagerFactory(不是TrustManagerFactory)的密钥库来完成的。

< sub>1:信任管理器使用本地信任锚(例如,受信任的CA证书)来评估远程方的信任(即,服务器信任客户端证书,或者客户端信任服务器证书)。

2:JSSE 支持的某些密码套件不需要证书,但它们要么是匿名密码套件(不安全),要么是 Kerberos 密码套件(需要完全以不同的方式设置)。默认情况下,两者都处于禁用状态。

 类似资料:
  • 问题内容: 我正在尝试在两个Java项目之间建立安全连接,但是却遇到了SSLHandshakeException(没有通用密码套件)的问题。这是在两侧创建套接字的方法: 客户: 服务器: 我有一个用keytool生成的RSA密钥。此代码从磁盘加载它。 我做错了什么? 更新: 我在此数组的两侧添加了对setEnabledCipherSuites的调用: 我得到相同的结果。 问题答案: 在服务器端,你

  • 问题内容: 我正在使用SSLServerSocket接受我的openSUSE服务器上的客户端连接,但是它们都无法连接。我总是得到SSLHandshakeException的说法。我已经激活了所有可能的套件,启用了多个协议,并尝试了最新的Oracle JRE和openjdk。另外,我还关注了论坛和相关内容上的其他几篇文章,并“解锁”了Oracle jre中的所有密码套件,并像这样更改了openjdk

  • 我正在使用SSLServerSocket来接受我的openSUSE服务器上的客户端连接,但是它们都不能连接。我总是得到一个SSLHandshakeExc0019说。我已经激活了所有可能的套件,启用了多种协议,尝试了最新的oracle JRE和openjdk。我还关注了论坛上的其他几篇文章,并“解锁”了甲骨文jre中的所有密码套件,我像这样更改了openjdk jre的设置: 禁用:并启用: 以下是

  • 我创建了一个自签名CA并用它签署了两个证书(都使用了RSA密钥),一个用于服务器,一个用于客户端。之后,我将证书导入服务器的密钥存储库和客户机的另一个密钥存储库。 我想使用一个特定的密码,但显然支持的密码都不起作用。 我的客户端代码:

  • OpenSSL版本:OpenSSL 1.1.0g 要创建证书,我运行以下命令: openssl genrsa-des3-out server.key 2048 openssl x509-请求-天数365-输入server.csr-签名密钥server.key-输出server.crt ...新的TLSV1.2密码是AES256-GCM-SHA384 服务器公钥为2048位 支持安全重新协商 ...

  • 我试图通过我的groovy代码连接到我公司的Microsoft sql。使用此代码: 这会导致错误: 39m:没有这样的属性:类的连接:31m[0;39m[31m39m(31m)[0;39m[31m39m(31m)[0;39m[31m39m(31m)[0;39m[31m39m(CreateOrg: 47)[0;39m[31m31m(39m)[0;TempTestCase1555589132729.