"没有共享密码"在ssl_accept,为什么?

时间:2016-11-06 20:44:59

标签: encryption openssl

google了很多,没有找到以下问题的任何答案: 创建了服务器代码和客户端代码,但获取

  

错误:1408A0C1:SSL例程:SSL3_GET_CLIENT_HELLO:无共享密码

在执行SSL_connect时在服务器上

以下代码仅限于SSL /套接字相关函数调用的顺序。已应用错误处理代码,以确保SSL_accept / SSL_connect之前的调用不会返回任何失败代码。我也遗漏了初始化方法。

我不知道它是否重要,但我在localhost上运行服务器和客户端。

可能存在明显的错误,但我对OpenSSL很新。

客户端代码(inparams:hostnamecertificate_chain_fileca_certificate_file):

SSL_library_init();             // <<< To clarify my initialization
OpenSSL_add_all_algorithms();   // <<< To clarify my initialization
SSL_load_error_strings();       // <<< To clarify my initialization
ERR_load_crypto_strings();      // <<< To clarify my initialization (2)
OpenSSL_add_all_ciphers();      // <<< To clarify my initialization (2)
SSL_METHOD const * method = SSLv23_method();  // <<< Updated method
SSL_CTX * ctx = SSL_CTX_new(method);
SSL_CTX_use_certificate_chain_file(ctx, certificate_chain_file));
const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;    // <<< Added
SSL_CTX_set_options(ctx, flags);   // <<< Added
SSL_CTX_load_verify_locations(ctx, ca_certificate_file, NULL));
struct hostent * host = gethostbyname(hostname);
int client_sd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(6789);
server.sin_addr.s_addr = *(long *) (host->h_addr);
connect(client_sd, (struct sockaddr *) &server, sizeof(server));
SSL * ssl = SSL_new(ctx);
SSL_set_fd(ssl, client_sd);
const char * const preferred_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
SSL_set_cipher_list(ssl, preferred_ciphers);   // <<< Added
SSL_set_tlsext_host_name(ssl, hostname);       // <<< Added
mydata_t mydata;
mydata_index_client = SSL_get_ex_new_index(0, (void *) "mydata index", NULL, NULL, NULL);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback_client);
SSL_CTX_set_verify_depth(ctx, 1);
mydata.verify_depth = 0;
SSL_set_ex_data(ssl, mydata_index_client, &mydata);
int connection_result = SSL_connect(ssl);
if (connection_result < 0)
{
  // Comes in here and ERR_get_error indicates
  // error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
}
else if (connection_result == 0)
{
}
else if (connection_result == 1)
{
}
else
{
}

服务器代码(inparams:certificate_chain_fileca_certificate_file):

SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_METHOD const * method = SSLv23_method();
SSL_CTX * ctx = SSL_CTX_new(method);
SSL_CTX_use_certificate_chain_file(ctx, certificate_chain_file);  //Contains only root CA
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) private_key_file_password);
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
SSL_CTX_load_verify_locations(ctx, ca_certificate_file, NULL);
struct sockaddr_in addr;
int server_sd = create_socket(addr, 6789);
bind(server_sd, (struct sockaddr *) &addr, sizeof(addr));
listen(server_sd, max_nr_of_simultaneous_connections);
sockaddr_in client;
client.sin_family = AF_INET;
socklen_t c_len = sizeof(client);
int client_sd = accept(server_sd, (sockaddr *) &client, &c_len);
char remote_addr[INET_ADDRSTRLEN];
inet_ntop(client.sin_family, &(client.sin_addr), remote_addr, INET_ADDRSTRLEN);
SSL * ssl = SSL_new(ctx);
SSL_set_fd(ssl, client_sd);
const char * const preferred_ciphers = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
SSL_set_cipher_list(ssl, preferred_ciphers);   // <<< Added
STACK_OF(X509_NAME) * cert_names = SSL_load_client_CA_file(certificate_chain_file);
if (cert_names != NULL)
{
    SSL_CTX_set_client_CA_list(ctx, cert_names);
}
mydata_t mydata;
mydata_index_server = SSL_get_ex_new_index(0, (void *) "mydata index", NULL, NULL, NULL);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback_server);
SSL_CTX_set_verify_depth(ctx, 1);
mydata.verify_depth = 1;
SSL_set_ex_data(ssl, mydata_index_server, &mydata);
int accept_result = SSL_accept(ssl);
if (accept_result == 0)
{
}
else if (accept_result < 0)
{
  // Comes in here and ERR_get_error indicates
  // error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher
}

编辑: jww,我已经尝试过你在下面建议的东西。但是,没有任何进展;我仍然得到相同的错误输出。 这就是我创建证书的方式:

的OpenSSL-ca.cnf

HOME            = .
RANDFILE        = $ENV::HOME/.rnd

####################################################################
[ ca ]
default_ca  = CA_default        # The default ca section

####################################################################
[ CA_default ]
default_days     = 1000          # how long to certify for
default_crl_days = 30            # how long before next CRL
default_md       = sha256        # use public key default MD
preserve         = no            # keep passed DN ordering

x509_extensions  = ca_extensions     # The extensions to add to the cert

email_in_dn      = no            # Don't concat the email in the DN
copy_extensions  = copy          # Required to copy SANs from CSR to cert

base_dir        = .
certificate     = $base_dir/certs/ca_fromweb.cert.pem  # The CA certifcate
private_key     = $base_dir/private/ca.key.pem   # The CA private key
new_certs_dir   = $base_dir     # Location for new certs after signing
database        = $base_dir/index2.txt   # Database index file
serial          = $base_dir/serial2.txt  # The current serial number

unique_subject  = no            # Set to 'no' to allow creation of
                                # several certificates with same subject.

####################################################################
[ req ]
default_bits        = 4096
default_keyfile     = ./private/ca.key.pem
distinguished_name  = ca_distinguished_name
x509_extensions     = ca_extensions
string_mask         = utf8only

####################################################################
[ ca_distinguished_name ]
countryName         = Country Name (2 letter code)
countryName_default = SE

stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = Östergötland

localityName            = Locality Name (eg, city)
localityName_default    = 

organizationName          = Organization Name (eg, company)
organizationName_default  = 

organizationalUnitName          = Organizational Unit (eg, division)
organizationalUnitName_default  = 

commonName          = Common Name (e.g. server FQDN or YOUR name)
commonName_default  = 

emailAddress            = Email Address
emailAddress_default    = 

####################################################################
[ ca_extensions ]
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always, issuer
basicConstraints        = critical, CA:true
keyUsage                = keyCertSign, cRLSign

####################################################################
[ signing_policy ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

####################################################################
[ signing_req ]
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer

basicConstraints       = CA:FALSE
keyUsage               = digitalSignature, keyEncipherment

的OpenSSL-server.cnf

HOME            = .
RANDFILE        = $ENV::HOME/.rnd

####################################################################
[ req ]
default_bits        = 2048
default_keyfile     = ./intermediate/private/my.example.com.key.pem
distinguished_name  = server_distinguished_name
req_extensions      = server_req_extensions
string_mask         = utf8only

####################################################################
[ server_distinguished_name ]
countryName             = Country Name (2 letter code)
countryName_default     = SE

stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = Östergötland

localityName            = Locality Name (eg, city)
localityName_default    = Linköping

organizationName            = Organization Name (eg, company)
organizationName_default    = 

commonName          = Common Name (e.g. server FQDN or YOUR name)
commonName_default  = 

emailAddress            = Email Address
emailAddress_default    = 

####################################################################
[ server_req_extensions ]
subjectKeyIdentifier    = hash
basicConstraints        = CA:FALSE
keyUsage                = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names
nsComment               = "OpenSSL Generated Certificate"

####################################################################
[ alternate_names ]
DNS.1       = my.example.com

命令

 touch index.txt
 echo 1000 > serial
 openssl genrsa -aes256 -out ca.key.pem 4096
 chmod 400 private/ca.key.pem
 openssl req -config openssl-ca.cnf -key ca.key.pem -new -x509 -days 7300 -sha256 -extensions ca_extensions -out ca.cert.pem
 chmod 444 ca.cert.pem

 openssl genrsa -aes256 -out server.key.pem 4096
 openssl req -config openssl-server.cnf -new -sha256 -key server.key.pem -out my.example.com.csr.pem
 openssl ca -config openssl-ca.cnf -policy signing_policy -extensions signing_req -out my.example.com.cert.pem -infiles my.example.com.csr.pem
 chmod 444 my.example.com.cert.pem
 cat ca.cert.pem > ca_chain.cert.pem

编辑2:也尝试了

 ERR_load_crypto_strings();      // <<< To clarify my initialization (2)
 OpenSSL_add_all_ciphers();      // <<< To clarify my initialization (2)

见顶部。结果相同。

&#34;不幸的是,所有初始化函数都返回无用的值(例如,总是1)或者是void函数。无法确定是否发生了故障。 &#34; - (https://wiki.openssl.org/index.php/Library_Initialization)太糟糕了!

3 个答案:

答案 0 :(得分:2)

  在ssl_accept上“没有共享密码”,为什么?

可能有几个原因。以下是一些建议,具体取决于您遇到的问题。我怀疑一个或多个是你问题的答案。

  

<强> 客户端

SSL_METHOD const * method = SSLv3_client_method();

  

<强> 服务器

SSL_METHOD const * method = SSLv23_method();

您应该首先设置“TLS 1.0及更高版本”。您可以使用以下内容在客户端和服务器上执行此操作。它来自OpenSSL wiki和SLL/TLS Client示例。

const SSL_METHOD* method = SSLv23_method();
if(method == NULL) handleFailure();

ctx = SSL_CTX_new(method);
if(ctx == NULL) handleFailure();

...

/* Cannot fail ??? */
const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
SSL_CTX_set_options(ctx, flags);

您的客户还应使用Server Name Indication (SNI)。客户端将其与SSL_set_tlsext_host_name一起使用。 SNI是TLS扩展,这也是你想要“TLS 1.0及以上版本”的部分原因。

客户端和服务器都想使用像"HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"这样的密码套件列表。使用SSL_CTX_set_cipher_listSSL_set_cipher_list设置它们。它避免了浏览器发出的“Your connection to website is encrypted with obsolete cryptography”警告。

如果 您使用的是基于椭圆曲线的证书,则需要使用命名曲线。另请参阅Stack Overflow上的boost asio with ECDSA certificate issue和OpenSSL wiki上的Elliptic Curve Cryptography | Named Curves

确保初始化OpenSSL库。如果未正确初始化库,则不会有可用的密码,并且可能导致“no shared ciphers”。另请参阅Stack Overflow上的Openssl SSL_CTX_new(SSLv3_method()) returns NULL和OpenSSL wiki上的Library Initialization

如果您要创建自己的证书,请确保将主机名放在主题备用名称(SAN)中。主机名始终位于 SAN 中。如果它出现在 CN 中,那么它也必须出现在 SAN 中(在这种情况下你必须列出两次)。有关更多规则和原因,请参阅How do you sign Certificate Signing Request with your Certification AuthorityHow to create a self-signed certificate with openssl?

答案 1 :(得分:2)

某些较旧的OpenSSL版本(例如RHEL 7.x中的版本)需要在初始化阶段显式调用SSL_CTX_set_ecdh_auto()才能启用高级算法的协商。参见例如https://wiki.openssl.org/index.php/Simple_TLS_Server

答案 2 :(得分:1)

这个问题我迟到了几年,但我也像您一样打了它,我发现所有建议都没有奏效。

沮丧的是,我用调试符号构建了LibreSSL,并在调试器中逐步完成了ssl3_choose_cipher。我注意到它正在检查s->cert以取消所有密码的资格。 s->cert似乎主要包含一堆空指针。 OTOH我发现s->ctx->internal->cert具有我已填充的值(证书,CA链证书,私钥,所有这些都位于NULL中的s->cert)。

所以对我来说解决的是将一堆SSL_CTX_foo更改为SSL_foo,以便填充SSL*而不是SSL_CTX*

所以我建议更换:

SSL_CTX_use_certificate_chain_file(ctx, certificate_chain_file);

使用:

SSL_use_certificate_chain_file(ssl, certificate_chain_file);

对我来说,我取代了:

SSL_CTX_use_PrivateKey(ctx, key);

具有:

SSL_use_PrivateKey(ssl, key);

这似乎是荒谬的区别,但现在对我有用。