openssl 1.0.2j,如何强制服务器选择 ECDH* 密码

openssl 1.0.2j, how to force server to choose ECDH* ciphers

我的客户端服务器使用 opensl 1.0.2j,并使用 RSA:4096 密钥和证书,我想强制服务器仅使用以下密码。

ECDHE-RSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-SHA384
ECDH-RSA-AES128-GCM-SHA256
ECDH-RSA-AES128-SHA256
DHE-RSA-AES256-GCM-SHA384
DHE-RSA-AES256-SHA256
DHE-RSA-AES128-GCM-SHA256
DHE-RSA-AES128-SHA256

我的服务器端代码如下所示。

method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256");
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
SSL_CTX_use_certificate_file(ctx, certFilePath, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, privKeyPath, SSL_FILETYPE_PEM)
SSL_accept()

我的客户端代码如下所示

method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
SSL_CTX_set_cipher_list(ctx, "ECDH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-SHA256");
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tmp_dh(ctx, dh);
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
SSL_CTX_use_certificate_file(ctx, certFilePath, SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, privKeyPath, SSL_FILETYPE_PEM)
SSL_connect()

服务器上的最后一步 ssl_accept() 失败

err: 336027900 'error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol'

如果我在客户端使用 ECDHE*RSA*DHE*RSA* 密码,它工作正常。

你能告诉我我缺少什么吗?

编辑:服务器的证书 (certFilePath) 包含一个 RSA public 密钥而不是 ECDH public 密钥。

Meta:最多只能回答 TLS1.2; 1.3 不再有密码套件中的密钥交换和身份验证。

首先,同时调用 set_ecdh_autoset_tmp_ecdh 是没有意义的——它们是互斥的。此外,您的服务器不请求客户端身份验证,因此在客户端上配置自我证书和密钥是无用的。 OTOH 您的服务器使用的自签名证书可能不在客户端的默认信任库中,因此您可能需要配置客户端信任库(有几种方法可以做到这一点)。

其次,'static' ECDH 密码套件与 ECDHE 套件有很大不同,就像 'static' DH 套件与 DHE 套件不同一样。这两种静态形式都没有得到广泛实施,也很少使用,因为它们通常没有任何好处;特别是 OpenSSL 1.1.0 及更高版本不再实现它们,因此如果我没记错的话,您的代码将在大约一年内过时。

确切地说,DH-RSA 套件需要包含 DH 密钥的证书(允许密钥协议),对于 TLS<=1.1,证书必须由 CA 颁发使用 RSA 密钥;对于 1.2,后一个限制被删除。没有 public CA 会为 DH 密钥颁发证书,即使自己做也不容易;见 https://security.stackexchange.com/questions/44251/openssl-generate-different-type-of-self-signed-certificate and (my) https://crypto.stackexchange.com/questions/19452/static-dh-static-ecdh-certificate-using-openssl/

ECDH-RSA 套件同样需要包含允许 keyAgreement 的 ECC 密钥的证书,如果 <=1.1 则由 RSA 颁发;这稍微容易一些,因为 ECDH 的密钥(和 CSR)与 ECDSA 相同,只有 KeyUsage 需要不同。对于您自行创建和自行签名的案例,这很简单,只需生成一个 ECC 密钥和证书(使用 ECDSA 自动签名)。

但最后,这不应该导致 'unknown protocol';它会导致 'no shared cipher' 和 handshake_failure。您显示的代码不应导致 'unknown protocol',因此您可能需要先调查并修复该问题。您可以尝试使用命令行 s_client 代替,尤其是使用其 -debug-msg 挂钩,或者 -trace 如果您已将其编译到