【问题标题】:Wrong cipher suite or no connection with OpenSSL server密码套件错误或与 OpenSSL 服务器没有连接
【发布时间】:2015-08-07 09:53:26
【问题描述】:

生成的密钥

openssl ecparam -param_enc named_curve -name secp521r1 -genkey -outform PEM -out key.pem

生成的证书

openssl req -x509 -new -key key.pem -keyform PEM -out ca.pem -outform PEM -days 3650

当我使用时

openssl s_server -accept 5000 -key key.pem -cert ca.pem -tls1_2 -www

我可以正常使用

openssl s_client -host 10.8.0.26 -port 5000

客户告诉我它使用

协议:TLSv1.2 密码:ECDHE-ECDSA-AES256-GCM-SHA384

正是我想要的

当我编译并使用以下c代码启动服务器时

编译

g++ Main2.cpp -ldl -lcrypto -lssl -o Main)

#include <iostream>
#include <string>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>

#include "openssl/ssl.h"
#include "openssl/err.h"

using namespace std;

void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{   char buf[1024];
    char reply[1024];
    int sd, bytes, err;
    const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";

	err = SSL_accept(ssl);

    if ( err <= 0 ) {    /* do SSL-protocol accept */
        printf("%d\n",err);
		ERR_print_errors_fp(stderr);
	}
    else
    {
        bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
        if ( bytes > 0 )
        {
            buf[bytes] = 0;
            printf("Client msg: \"%s\"\n", buf);
            sprintf(reply, HTMLecho, buf);   /* construct reply */
            SSL_write(ssl, reply, strlen(reply)); /* send reply */
        }
        else
            ERR_print_errors_fp(stderr);
    }
    sd = SSL_get_fd(ssl);       /* get socket connection */
    SSL_free(ssl);         /* release SSL state */
    close(sd);          /* close connection */
}


int OpenListener(int port)
{   int sd;
    struct sockaddr_in addr;
	

    sd = socket(PF_INET, SOCK_STREAM, 0);
    bzero(&addr, sizeof(addr));

	inet_aton("10.8.0.26", &addr.sin_addr);

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    //addr.sin_addr.s_addr = INADDR_ANY;
    
	if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
    {
        perror("can't bind port");
        abort();
    }
    if ( listen(sd, 10) != 0 )
    {
        perror("Can't configure listening port");
        abort();
    }
    return sd;
}

int main(int argc, const char* argv[]) {

	//SSL_library_init();
	SSL_load_error_strings();
    OpenSSL_add_ssl_algorithms(); 

	cout << SSLeay_version(SSLEAY_VERSION) << endl;

	SSL_CTX *ctx;
	const SSL_METHOD *method;

	method = TLSv1_2_server_method();
	//method = SSLv23_server_method();

	ctx = SSL_CTX_new(method);   /* create new context from method */
    if ( ctx == NULL )
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
	        
	if (SSL_CTX_set_ecdh_auto(ctx, 1) != 1)
		ERR_print_errors_fp(stderr);

	//if (SSL_CTX_set_cipher_list(ctx, "ECDH-ECDSA-AES256-GCM-SHA384") != 1)
		// ERR_print_errors_fp(stderr);

	if (SSL_CTX_load_verify_locations(ctx, "ca.pem", "key.pem") != 1)
        ERR_print_errors_fp(stderr);

	if (SSL_CTX_set_default_verify_paths(ctx) != 1)
        ERR_print_errors_fp(stderr);

	if (SSL_CTX_use_certificate_file(ctx, "ca.pem", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }

	if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }

	if (!SSL_CTX_check_private_key(ctx))
    {
        fprintf(stderr, "Private key does not match the public certificate\n");
        abort();
    }



	int server;

	server = OpenListener(5000);

	struct sockaddr_in addr;
        socklen_t len = sizeof(addr);
        SSL *ssl;

        int client = accept(server, (struct sockaddr*)&addr, &len);  /* accept connection as usual */
        printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        ssl = SSL_new(ctx);              /* get new SSL state with context */
		if (ssl == NULL) {
		
			ERR_print_errors_fp(stderr);
			return 0;
		
		}

		  SSL_set_fd(ssl, client);      /* set connection socket to SSL state */
        Servlet(ssl);         /* service connection */
  
    close(server);          /* close server socket */
    SSL_CTX_free(ctx);         /* release context */

    return 0;

}

当我现在像上面一样使用 openssl s_client 连接时

协议:TLSv1.2 密码:ECDH-ECDSA-AES256-GCM-SHA384

不是ECDHE!为什么?

当我使用 chrome/firefox 连接到 openssl s_server 或我的服务器代码时,我得到:

140675163166384:error:1408A0C1:SSL 例程:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1396:

为什么完全没有连接?

【问题讨论】:

标签: c++ openssl server


【解决方案1】:

当我现在使用 openssl s_client 连接时,就像上面一样 Protocol : TLSv1.2 Cipher : ECDH-ECDSA-AES256-GCM-SHA384

不是ECDHE!为什么?

ECDHECDHE 是两个不同的 Diffie-Hellman。 ECDH 使用固定的服务器密钥。 ECDHE 是短暂的,它使用临时密钥。你应该使用ECDHE

对于ECDHE,您没有使用SSL_CTX_set_tmp_ecdh_callback 设置ECDHE 回调。

详情请见Server with ECDHE key and cert not working


相关,这里是基于 EC 的 DH 密码:

openssl ciphers -v 'ALL:!aNULL' | grep ECDH
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
ECDHE-RSA-AES256-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA1
ECDHE-ECDSA-AES256-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA1
ECDH-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
ECDH-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
ECDH-RSA-AES256-SHA384  TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(256)  Mac=SHA384
ECDH-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256)  Mac=SHA384
ECDH-RSA-AES256-SHA     SSLv3 Kx=ECDH/RSA Au=ECDH Enc=AES(256)  Mac=SHA1
ECDH-ECDSA-AES256-SHA   SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=AES(256)  Mac=SHA1
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA256
ECDHE-RSA-AES128-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA1
ECDHE-ECDSA-AES128-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA1
ECDH-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
ECDH-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
ECDH-RSA-AES128-SHA256  TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AES(128)  Mac=SHA256
ECDH-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128)  Mac=SHA256
ECDH-RSA-AES128-SHA     SSLv3 Kx=ECDH/RSA Au=ECDH Enc=AES(128)  Mac=SHA1
ECDH-ECDSA-AES128-SHA   SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=AES(128)  Mac=SHA1
ECDHE-RSA-RC4-SHA       SSLv3 Kx=ECDH     Au=RSA  Enc=RC4(128)  Mac=SHA1
ECDHE-ECDSA-RC4-SHA     SSLv3 Kx=ECDH     Au=ECDSA Enc=RC4(128)  Mac=SHA1
ECDH-RSA-RC4-SHA        SSLv3 Kx=ECDH/RSA Au=ECDH Enc=RC4(128)  Mac=SHA1
ECDH-ECDSA-RC4-SHA      SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=RC4(128)  Mac=SHA1
ECDHE-RSA-DES-CBC3-SHA  SSLv3 Kx=ECDH     Au=RSA  Enc=3DES(168) Mac=SHA1
ECDHE-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH     Au=ECDSA Enc=3DES(168) Mac=SHA1
ECDH-RSA-DES-CBC3-SHA   SSLv3 Kx=ECDH/RSA Au=ECDH Enc=3DES(168) Mac=SHA1
ECDH-ECDSA-DES-CBC3-SHA SSLv3 Kx=ECDH/ECDSA Au=ECDH Enc=3DES(168) Mac=SHA1

当我使用 chrome/firefox 连接到 openssl s_server 或 我得到的服务器代码:140675163166384:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1396

为什么完全没有连接?

您使用了 P-521。它应该被支持,但它可能会引起麻烦。要获得最大的互操作性,请使用 P-256:... -param_enc named_curve -name secp256k1


椭圆曲线齿轮在 TLS 1.0 及更高版本中可用。来自RFC 4492, Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)

本文档描述了对 TLS 的添加以支持 ECC,适用于 TLS 版本 1.0 [2] 和 TLS 版本 1.1 [3]...

你应该改变这个:

method = TLSv1_2_server_method();

收件人:

method = SSLv23_method();
ctx = SSL_CTX_new(method);
...

const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
SSL_CTX_set_options(ctx, flags);

这会让您获得“TLS 1.0 及更高版本”,并且它会删除会泄露信息的压缩。您还应该考虑其他服务器端选项,例如 SSL_OP_SAFARI_ECDHE_ECDSA_BUG

TLS 1.2 是唯一提供 Authenticated Encryption 的协议版本,如 AES/GCM。但是您通常会在密码套件列表字符串中处理该详细信息。


为了完整起见,您还应该使用以下密码列表字符串和SSL_CTX_set_cipher_list

HIGH:!aNULL:!kRSA:!RC4:!MD5

详情另见Obsolete cryptography warning from Browser


最终,您可能会遇到更多浏览器问题。浏览器已针对自签名服务器证书进行了移动。要解决这个问题,请参阅How do you sign Certificate Signing Request with your Certification Authority?

修复自签名证书后,您的服务器证书可能会因公共名称 (CN) 中的服务器名称而出现问题。服务器名称​​必须列在主题备用名称 (SAN) 中。要解决此问题,请参阅 How to create a self-signed certificate with openssl?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-16
    • 2014-03-02
    相关资源
    最近更新 更多