与ECDHE密钥和证书服务器无法正常工作 [英] Server with ECDHE key and cert not working
问题描述
我用下面的server.c源,我产生
罪恶宿主cert.pem
罪孽深重-host.key
如下所述:椭圆曲线CA指南
在运行程序得到以下错误:
140722397161136:错误:10071065:椭圆曲线函数:FUNC(113):原因(101):ec_lib.c:995:
140722397161136:错误:0B080075:X509证书程序:FUNC(128):原因(117):x509_cmp.c:346:
块引用>我使用编译:
GCC server.c -ldl -lcrypto -lssl -o服务器
块引用>在该行出现的错误,我认为
如果(SSL_CTX_use_PrivateKey_file(CTX,密钥文件,SSL_FILETYPE_PEM)LT; = 0)
块引用>server.c
的#include<&errno.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&malloc.h所GT;
#包括LT&;&string.h中GT;
#包括LT&; ARPA / inet.h>
#包括LT&; SYS / socket.h中>
#包括LT&; SYS / types.h中>
#包括LT&; netinet / in.h中>
#包括LT&;&resolv.h GT;
#包括为OpenSSL / ssl.h
#包括为OpenSSL / err.h#定义FAIL -1INT OpenListener(INT端口)
{诠释SD;
结构sockaddr_in的地址;
SD =插座(PF_INET,SOCK_STREAM,0);
bzero(安培;地址,的sizeof(地址)); INET_ATON(10.8.0.26,&放大器; addr.sin_addr); addr.sin_family = AF_INET;
addr.sin_port = htons(端口);
//addr.sin_addr.s_addr = INADDR_ANY; 如果(绑定(SD,(结构sockaddr *)及!地址,的sizeof(地址))= 0)
{
PERROR(不能绑定端口);
中止();
}
如果(听(SD,10)!= 0)
{
PERROR(无法配置监听端口);
中止();
}
返回SD;
}SSL_CTX * InitServerCTX(无效)
{常量SSL_METHOD *方法;
SSL_CTX * CTX; OpenSSL_add_all_algorithms(); / *负载和放大器;注册所有cryptos等。* /
SSL_load_error_strings(); / *加载所有的错误信息* / //方法= SSLv23_server_method();
方法= TLSv1_2_server_method(); / *创建新的服务器实例的方法* /
CTX = SSL_CTX_new(法); / *从方法来创建新的上下文* /
如果(CTX == NULL)
{
ERR_print_errors_fp(标准错误);
中止();
}
返回CTX;
}无效LoadCertificates(SSL_CTX * CTX,字符* CERTFILE,字符* KeyFile时)
{
//新线
如果(SSL_CTX_set_cipher_list(CTX,ECDHE-ECDSA-AES128-GCM-SHA256)!= 1)
ERR_print_errors_fp(标准错误); 如果(SSL_CTX_load_verify_locations(CTX,CERTFILE,密钥文件)!= 1)
ERR_print_errors_fp(标准错误); 如果(SSL_CTX_set_default_verify_paths(CTX)!= 1)
ERR_print_errors_fp(标准错误);
//结尾的新行 / *从CERTFILE设置本地证书* /
如果(SSL_CTX_use_certificate_file(CTX,CERTFILE,SSL_FILETYPE_PEM)下; = 0)
{
ERR_print_errors_fp(标准错误);
中止();
} 的printf(FFFF \\ n);
/ *从KeyFile中设置专用密钥(可以是相同CERTFILE)* /
如果(SSL_CTX_use_PrivateKey_file(CTX,密钥文件,SSL_FILETYPE_PEM)LT; = 0)
{
ERR_print_errors_fp(标准错误);
中止();
}
的printf(GGGG \\ n);
/ *验证私钥* /
如果(!SSL_CTX_check_private_key(CTX))
{
fprintf中(标准错误,私人密钥不匹配的公证书\\ n);
中止();
} //新行 - 强制客户端有一个证书
// SSL_CTX_set_verify(CTX,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,NULL);
// SSL_CTX_set_verify_depth(CTX,4);
//结尾的新行
}无效ShowCerts(SSL * SSL)
{X509 *证书;
字符*线; 证书= SSL_get_peer_certificate(SSL); / *获取证书(如果可用)* /
如果(CERT!= NULL)
{
的printf(服务器证书:\\ n);
行= X509_NAME_oneline(X509_get_subject_name(证书),0,0);
的printf(主题:%S \\ n,行);
免费(线);
行= X509_NAME_oneline(X509_get_issuer_name(证书),0,0);
的printf(发行人:%S \\ n,行);
免费(线);
X509_free(CERT);
}
其他
的printf(没有证书\\ n);
}无效的Servlet(SSL * SSL)/ *即成连接 - threadable * /
{字符BUF [1024];
焦炭回复[1024];
INT SD,字节,走错了路。
为const char * HTMLecho =< HTML><身体GT;< pre>%S< / pre>< /身体GT;< / HTML> \\ n \\ n; 的printf(忽忽pre \\ n); ERR = SSL_accept(SSL); 如果(ERR< = 0){/ *做SSL协议接受* /
的printf(%d个\\ N,ERR);
ERR_print_errors_fp(标准错误);
}
其他
{
的printf(XXXXXX \\ n);
// SSL_write(SSL,忽忽\\ n \\ r,即8);
ShowCerts(SSL); / *得到任何证书* /
字节= SSL_read(SSL,BUF,sizeof的(BUF)); / * get请求* /
如果(字节大于0)
{
BUF [字节] = 0;
的printf(客户信息:\\%s \\的\\ n,BUF);
sprintf的(回复,HTMLecho,BUF); / *结构答复* /
SSL_write(SSL,回复,strlen的(回复)); / *发送应答* /
}
其他
ERR_print_errors_fp(标准错误);
}
SD = SSL_get_fd(SSL); / *获取套接字连接* /
SSL_free(SSL); / *释放SSL状态* /
关闭(SD); / *关闭连接* /
}诠释的main()
{SSL_CTX * CTX;
int服务器;
CHAR端口编号[] =5000; CHAR CERTFILE [] =罪恶的宿主cert.pem
CHAR KeyFile是[] =罪恶-host.key SSL_library_init(); CTX = InitServerCTX(); / *初始化SSL * /
LoadCertificates(CTX,CERTFILE,密钥文件); / *加载证书* /
服务器= OpenListener(与atoi号(端口)); / *创建服务器套接字* / 的printf(%d个,而\\ n,服务器);
而(1)
{结构sockaddr_in的地址;
socklen_t的LEN = sizeof的(地址);
SSL * SSL; INT客户端=接受(服务器,(结构sockaddr *)及地址,和放大器; LEN); / *接受连接一样* /
的printf(连接:%s的数:%d \\ n,INET_NTOA(addr.sin_addr),ntohs和(addr.sin_port));
SSL = SSL_new(CTX); / *获得新的SSL状态,中* /
如果(SSL == NULL){ ERR_print_errors_fp(标准错误);
返回0; }
SSL_set_fd(SSL,客户端); / *设置的连接插座SSL状态* /
的servlet(SSL); / *服务连接* /
}
关闭(服务器); / *关闭服务器套接字* /
SSL_CTX_free(CTX); / *版本中* /
}
解决方案
如下所述:椭圆曲线CA指南...
块引用>本页面有这么多的错误和遗漏我会丢弃它。第一面红旗是白色文本和黑色的背景。这告诉我这样的人经验不足的是提供网页...
从页面:
OpenSSL的ecparam -list-曲线
块引用>这应该是
-list_curves
,而不是-list-曲线
。
从页面:
OpenSSL的ecparam退房手续sinful.key -name sect283k1 -genkey
块引用>这应该是:
OpenSSL的ecparam -param_enc named_curve退房手续sinful.key -name sect283k1 -genkey
如果您的不的使用命名的曲线,那么你将有很多问题后,当客户端试图连接到服务器等。在这里,命名为曲线像
secp256k1
曲线的OID,而不是域的参数,如P
,A
,b
,等 在很多问题后来的在OpenSSL的维基椭圆曲线加密文件,命名为曲线 。以下是一些您将遇到问题:
- 客户端:
139925962778272:错误:14094410:SSL例程:SSL3_READ_BYTES:SSLv3的警报握手失败:s3_pkt.c:1256:SSL警告40号
- 客户端:
139925962778272:错误:1409E0E5:SSL例程:SSL3_WRITE_BYTES:SSL握手失败:s3_pkt.c:596
- 服务器:
140339533272744:错误:1408A0C1:SSL例程:SSL3_GET_CLIENT_HELLO:没有共享密码:s3_srvr.c:1353
此外,为的最大的互操作性,你应该使用
secp256k1
。紧随其后是secp521r1
。此外,使用/缺少
- *形式
在OpenSSL的ecparam
和OpenSSL的REQ
命令将在下面讨论。SSL_CTX * InitServerCTX(无效){...}
块引用>这code座有不少问题。最值得注意的是缺乏ECDH回调。你在哪里设置
SSL_CTX_set_tmp_ecdh
回调(OpenSSL的1.0.1及以下),或者是调用SSL_CTX_set_ecdh_auto
( OpenSSL的1.0.2及以上)?其他包括<击>默认协议击>,默认的密码列表,虚弱和受伤的密码,匿名协议纳入,和COM pression。对于code的部分例如提供的服务器内,参见没有共享密码错误与EDH-RSA-DES-CBC3 -SHA 。
在该行出现的错误,我认为
如果(SSL_CTX_use_PrivateKey_file(CTX,密钥文件,SSL_FILETYPE_PEM)LT; = 0)
块引用>我认为这可以追溯到有缺陷的页面引用你。这样的:
OpenSSL的REQ -x509 -new -key sinful.key退房手续有罪,ca.pem -outform PEM -days 3650
也许应该是(注意添加
-keyform
)OpenSSL的REQ -x509 -new -key sinful.key -keyform PEM退房手续有罪,ca.pem -outform PEM - 3650天
或者
如果(SSL_CTX_use_PrivateKey_file(CTX,密钥文件,SSL_FILETYPE_ASN1)LT; = 0)
在一般情况下,始终使用
*形式
选项命令,不管是它的-keyform
,-certform
,-inform
,-outform
等OpenSSL的不总是正确(即使它应该默认使用PEM)。
在该行出现的错误,我认为
如果(SSL_CTX_use_PrivateKey_file(CTX,密钥文件,SSL_FILETYPE_PEM)LT; = 0)
块引用>如果的私钥具有密码,那么你就需要提供一个密码回调或剥去文件的密码。
其确定剥离密码,因为有一个在存储明文私钥没有什么区别;或在旁边的密钥的配置文件的密码一个加密的私有密钥。在这两种情况下,你拥有的唯一有效的安全性是文件系统访问控制列表。
相关,这就是所谓的的无人值守的密钥存储的问题。格特曼讨论它是在他的书工程安全。它没有解决的问题。
下面是一些更完整的错误信息......它看起来像您使用的是旧版本的OpenSSL,并且不提供新的错误codeS。
在运行程序得到以下错误:
140722397161136:错误:10071065:椭圆曲线函数:FUNC(113):原因(101):ec_lib.c:995
140722397161136:错误:0B080075:X509证书程序:FUNC(128):原因(117):x509_cmp.c:346
块引用>首先,
0x10071065
错误:$在/ usr /本地/ SSL / MacOSX的-64 /斌/ OpenSSL的errstr 0x10071065
错误:10071065:椭圆曲线套路:EC_POINT_cmp:不兼容对象的
0x10071065
通常意味着客户端和服务器使用的是不兼容的EC领域。在这种情况下,你应该使用secp256k1
或secp521r1
。二,
0x0B080075
错误:$在/ usr /本地/ SSL / MacOSX的-64 /斌/ OpenSSL的errstr 0x0B080075
错误:0B080075:X509证书套路:X509_check_private_key:未知的密钥类型我猜有证书和私钥不匹配。但它只是一种猜测。我将(1)清除指定的曲线问题,(2)清除
sect283k1
问题;(3)清除下级库的问题(见下文)。清除这些问题之后,再看看这个问题仍然存在。
看起来您使用的是旧版本的OpenSSL,并且不提供新的错误$ C $ ... CS
块引用>请确保您正在运行的OpenSSL 1.0.0或更高版本。 0.9.8有有限的EC支持,但它并没有真正切入有效,直至1.0.0。更好的,使用OpenSSL 1.0.2。
OpenSSL_add_all_algorithms(); / *负载和放大器;注册所有cryptos等。* /
SSL_load_error_strings(); / *加载所有的错误信息* /
块引用>也可参阅OpenSSL的维基库初始化。
如果(SSL_CTX_set_cipher_list(CTX,ECDHE-ECDSA-AES128-GCM-SHA256)
块引用>这将让你进入在OS X和iOS的某些版本的麻烦,由于在 SecureTransport 的库中的缺陷。苹果只固定在他们的操作系统的某些版本。
如果你打算维修苹果hardwarez,那么您将需要一个额外的
非ECDHE-ECDSA
密码。而你需要使用服务器端上下文选项<一个href=\"https://wiki.openssl.org/index.php/SSL_OP_SAFARI_ECDHE_ECDSA_BUG\"><$c$c>SSL_OP_SAFARI_ECDHE_ECDSA_BUG$c$c>.的相关的,苹果是pretty大胆关于未固着他们的安全漏洞。你有破ECDHE-ECDSA密码套件;和宝石如 CVE-1115至30年(隐藏后门带根)。
下面就是我的ECDH的回调看起来像OpenSSL的1.0.1及以下。 OpenSSL的1.0.2应使用
SSL_CTX_set_ecdh_auto
。它的C ++ code,但它很容易转换回至C code。另请参阅<一个href=\"http://openssl.6102.n7.nabble.com/SSL-CTX-set-tmp-ecdh-callback-semantics-in-1-0-1-td51401.html\">SL_CTX_set_tmp_ecdh_callback语义1.0.1 OpenSSL的邮件列表上。下code可能会更加强劲。回调函数应该获取与
SSL_get_certificate
证书(的不的SSL_get_peer_certificate
),查询证书EC字段,然后提供相应的字段临时密钥,如secp256k1
或secp571k1
。 (它的工作原理,因为我的证书使用secp256
和EcdhCallback
使用secp256
作为其默认值)。
SSL_get_certificate
未记录。但它在中所使用; OpenSSL的SRC&GT; /apps/s_cb.c
。这就是自我记录code OpenSSL是著名的。使用SSL_ptr =的std :: shared_ptr的&LT; SSL取代;
使用SSL_CTX_ptr =的std :: shared_ptr的&LT; SSL_CTX取代;使用EC_KEY_ptr =的std ::的unique_ptr&LT; EC_KEY,decltype(安培; :: EC_KEY_free)取代;
使用EC_GROUP_ptr =的std ::的unique_ptr&LT; EC_GROUP,decltype(安培; :: EC_GROUP_free)取代;
使用EC_POINT_ptr =的std ::的unique_ptr&LT; EC_POINT,decltype(安培; :: EC_POINT_free)取代;
使用EVP_PKEY_ptr =的std ::的unique_ptr&LT; EVP_PKEY,decltype(安培; :: EVP_PKEY_free)取代;
使用BIO_MEM_ptr =的std ::的unique_ptr&LT; BIO,decltype(安培; :: BIO_free)取代;
使用BIO_FILE_ptr =的std ::的unique_ptr&LT; BIO,decltype(安培; :: BIO_free)取代;
...SSL_CTX * CreateServerContext(常量字符串和放大器;域)
{
常量SSL_METHOD *方法= SSLv23_server_method();
ASSERT(方法!= NULL); SSL_CTX_ptr吨(SSL_CTX_new(方法):: SSL_CTX_free);
ASSERT(t.get()!= NULL); 长标志= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
标志| = SSL_OP_NO_COM preSSION;
标志| = SSL_OP_SAFARI_ECDHE_ECDSA_BUG;
标志| = SSL_OP_CIPHER_SERVER_ preFERENCE; 的SSL_CTX_set_options(t.get(),旗); 字符串密码=!!!HIGH:A零位:RC4:MD5
RC = SSL_CTX_set_cipher_list(t.get(),ciphers.c_str());
... LogDebug(GetServerContext:设置ECDH回调);
SSL_CTX_set_tmp_ecdh_callback(t.get(),EcdhCallback);
... 返回T.RELEASE();
}EC_KEY * EcdhCallback(SSL * SSL,诠释is_export,诠释keylength)
{
未使用(SSL);
未使用(is_export);
未使用(keylength); / *这个回调OK,但OpenSSL的调用它在一个破碎的方式。 * /
/ *使用1.0.1e和1.0.1f,该值为1024位。这是比较* /
/ *适用于RSA ....我们会尽力在这里重写。 * /
如果(keylength&GT; = 1024)
{
keylength = 256;
LogRelevant(EcdhCallback:字段大小是错误的,使用256位组);
}#如果定义(ALLOW_ECDH_192_PARAMS)
如果(keylength&下; = 192 + 4)
返回ECDH192();
#万一 如果(keylength&下; = 224 + 4)
返回ECDH224();
否则如果(keylength&下; = 256 + 4)
返回ECDH256();
否则如果(keylength&下; = 384 + 4)
返回ECDH384();
否则如果(keylength&下; = 521 + 4)
返回ECDH521(); 返回ECDH521();
}#如果定义(ALLOW_ECDH_192_PARAMS)
静态EC_KEY * ECDH192()
{
静态EC_KEY_ptr键(NULL,NULL);
静态once_flag标志; call_once的(标记,[]()
{
键= EC_KEY_ptr(InitEcdhkey(192):: EC_KEY_free);
ASSERT(key.get()); 如果(!key.get())
LOGERROR(ECDH192:InitEcdhkey失败);
}); 返回key.get();
}
#万一静态EC_KEY * ECDH224()
{
静态EC_KEY_ptr键(NULL,NULL);
静态once_flag标志; call_once的(标记,[]()
{
键= EC_KEY_ptr(InitEcdhkey(224):: EC_KEY_free);
ASSERT(key.get()); 如果(!key.get())
LOGERROR(ECDH224:InitEcdhkey失败);
}); 返回key.get();
}静态EC_KEY * ECDH256()
{
静态EC_KEY_ptr键(NULL,NULL);
静态once_flag标志; call_once的(标记,[]()
{
键= EC_KEY_ptr(InitEcdhkey(256):: EC_KEY_free);
ASSERT(key.get()); 如果(!key.get())
LOGERROR(ECDH256:InitEcdhkey失败);
}); 返回key.get();
}静态EC_KEY * ECDH384()
{
静态EC_KEY_ptr键(NULL,NULL);
静态once_flag标志; call_once的(标记,[]()
{
键= EC_KEY_ptr(InitEcdhkey(384):: EC_KEY_free);
ASSERT(key.get()); 如果(!key.get())
LOGERROR(ECDH384:InitEcdhkey失败);
}); 返回key.get();
}静态EC_KEY * ECDH521()
{
静态EC_KEY_ptr键(NULL,NULL);
静态once_flag标志; call_once的(标记,[]()
{
键= EC_KEY_ptr(InitEcdhkey(521):: EC_KEY_free);
ASSERT(key.get()); 如果(!key.get())
LOGERROR(ECDH521:InitEcdhkey失败);
}); 返回key.get();
}静态EC_KEY * InitEcdhkey(INT位)
{
如果(比特下; = 160 + 4)
位= 160;
否则如果(比特下; = 192 + 4)
位= 192;
否则如果(比特下; = 224 + 4)
位= 224;
否则如果(比特下; = 256 + 4)
位= 256;
否则如果(比特下; = 384 + 4)
位= 384;
否则如果(比特下; = 521 + 4)
位= 521;
其他
位= 521; EC_KEY *键= EC_KEY_new_by_curve_name(CurveToNidByBits(位));
无符号长ERR = ERR_get_error(); ASSERT(关键!= NULL);
如果(键== NULL)
{
ostringstream OSS;
OSS&LT;&LT; InitEcdhkey:EC_KEY_new_by_curve_name失败;
OSS&LT;&LT;比特&LT;&LT; 位密钥,错误&LT;&LT;犯错&LT;&LT; 0X&LT;&LT;呃;
LOGERROR(OSS);
} 返回键;
}I use the below server.c source, i generated
sinful-host-cert.pem sinful-host.keyas described here: Elliptic Curve CA Guide
When running the program get the following errors:
140722397161136:error:10071065:elliptic curve routines:func(113):reason(101):ec_lib.c:995: 140722397161136:error:0B080075:x509 certificate routines:func(128):reason(117):x509_cmp.c:346:
I compiled using:
gcc server.c -ldl -lcrypto -lssl -o Server
The error occurs at this line I think
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
server.c
#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" #define FAIL -1 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; } SSL_CTX* InitServerCTX(void) { const SSL_METHOD *method; SSL_CTX *ctx; OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ SSL_load_error_strings(); /* load all error messages */ //method = SSLv23_server_method(); method = TLSv1_2_server_method(); /* create new server-method instance */ ctx = SSL_CTX_new(method); /* create new context from method */ if ( ctx == NULL ) { ERR_print_errors_fp(stderr); abort(); } return ctx; } void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile) { //New lines if (SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES128-GCM-SHA256") != 1) ERR_print_errors_fp(stderr); if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1) ERR_print_errors_fp(stderr); if (SSL_CTX_set_default_verify_paths(ctx) != 1) ERR_print_errors_fp(stderr); //End new lines /* set the local certificate from CertFile */ if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); abort(); } printf("FFFF\n"); /* set the private key from KeyFile (may be the same as CertFile) */ if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); abort(); } printf("GGGG\n"); /* verify private key */ if (!SSL_CTX_check_private_key(ctx)) { fprintf(stderr, "Private key does not match the public certificate\n"); abort(); } //New lines - Force the client-side have a certificate //SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); //SSL_CTX_set_verify_depth(ctx, 4); //End new lines } void ShowCerts(SSL* ssl) { X509 *cert; char *line; cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */ if ( cert != NULL ) { printf("Server certificates:\n"); line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); printf("Subject: %s\n", line); free(line); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("Issuer: %s\n", line); free(line); X509_free(cert); } else printf("No certificates.\n"); } 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"; printf("huhupre\n"); err = SSL_accept(ssl); if ( err <= 0 ) { /* do SSL-protocol accept */ printf("%d\n",err); ERR_print_errors_fp(stderr); } else { printf("XXXXXX\n"); //SSL_write(ssl, "huhu\n\r", 8); ShowCerts(ssl); /* get any certificates */ 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 main() { SSL_CTX *ctx; int server; char portnum[]="5000"; char CertFile[] = "sinful-host-cert.pem"; char KeyFile[] = "sinful-host.key"; SSL_library_init(); ctx = InitServerCTX(); /* initialize SSL */ LoadCertificates(ctx, CertFile, KeyFile); /* load certs */ server = OpenListener(atoi(portnum)); /* create server socket */ printf("%d while\n", server); while (1) { 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 */ }
解决方案as described here: Elliptic Curve CA Guide...
This page has so many errors and omissions I would discard it. The first red flag is the white text and black background. That tells me someone less experienced is providing the page...
From the page:
openssl ecparam -list-curves
This should be
-list_curves
, not-list-curves
.From the page:
openssl ecparam -out sinful.key -name sect283k1 -genkey
This should be:
openssl ecparam -param_enc named_curve -out sinful.key -name sect283k1 -genkey
If you don't use a named curve, then you will have lots of problems later, like when a client attempts to connect to the server. Here, named curve is the OID for a curve like
secp256k1
, and not the domain parameters likep
,a
,b
,G
, etc.The "lots of problems later" is documented at the OpenSSL wiki Elliptic Curve Cryptography, Named Curves. Here are some of the problems you will experience:
- Client:
139925962778272:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1256:SSL alert number 40
- Client:
139925962778272:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:596
- Server:
140339533272744:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1353
Also, for maximum interoperability, you should use
secp256k1
. A close second issecp521r1
.Also, use of/lack of
-*form
in theopenssl ecparam
andopenssl req
commands are discussed below.
SSL_CTX* InitServerCTX(void) { ... }
This code block has quite a few problems. The most notable is lack of the ECDH callback. Where are you setting the
SSL_CTX_set_tmp_ecdh
callback (OpenSSL 1.0.1 and below), or where is the call toSSL_CTX_set_ecdh_auto
(OpenSSL 1.0.2 and above)?Others include the
default protocol, the default cipher list, weak and wounded ciphers, the inclusion of anonymous protocols, and compression. For a partial example of code to provide a server context, see 'No Shared Cipher' Error with EDH-RSA-DES-CBC3-SHA.
The error occurs at this line I think
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
I think that traces back to that defective page you referenced. This:
openssl req -x509 -new -key sinful.key -out sinful-ca.pem -outform PEM -days 3650
Should probably be (note the addition of
-keyform
)openssl req -x509 -new -key sinful.key -keyform PEM -out sinful-ca.pem -outform PEM -days 3650
Or
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_ASN1) <= 0)
In general, always use the
*form
option for a command, whether its-keyform
,-certform
,-inform
,-outform
, etc. OpenSSL does not always get it right (even though its supposed to use PEM by default).
The error occurs at this line I think
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
If the private key has a password, then you will need to provide a Password Callback or strip the password from the file.
Its OK to strip the password because there's no difference in storing a plaintext private key; or a encrypted private key with the passphrase in a configuration file next to the key. In both cases, the only effective security you have is the filesystem ACLs.
Related, this is known as the Unattended Key Storage problem. Guttman discusses it in his book Engineering Security. Its a problem without a solution.
Here's some more complete error information... It looks like you are using an old version of OpenSSL, and that does not provide the newer error codes.
When running the program get the following errors:
140722397161136:error:10071065:elliptic curve routines:func(113):reason(101):ec_lib.c:995 140722397161136:error:0B080075:x509 certificate routines:func(128):reason(117):x509_cmp.c:346
First, the
0x10071065
error:$ /usr/local/ssl/macosx-x64/bin/openssl errstr 0x10071065 error:10071065:elliptic curve routines:EC_POINT_cmp:incompatible objects
The
0x10071065
usually means the client and the server are using incompatible EC fields. In this case, you should use eithersecp256k1
orsecp521r1
.Second, the
0x0B080075
error:$ /usr/local/ssl/macosx-x64/bin/openssl errstr 0x0B080075 error:0B080075:x509 certificate routines:X509_check_private_key:unknown key type
I'm guessing that there's a mismatch in the certificate and private key. But its only a guess. I would (1) clear the named curve issue, (2) clear the
sect283k1
issue, and (3) clear the down level library issue (see below). After clearing those issues, then see if this issue remains.
It looks like you are using an old version of OpenSSL, and that does not provide the newer error codes...
Be sure you are running OpenSSL 1.0.0 or above. 0.9.8 had limited EC support, but it was not really cut-in in force until 1.0.0. Better, use OpenSSL 1.0.2.
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */ SSL_load_error_strings(); /* load all error messages */
Also see Library Initialization on the OpenSSL wiki.
if (SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES128-GCM-SHA256")
This will get you into trouble on some versions of OS X and iOS due to a bug in the SecureTransport library. Apple only fixed it on some versions of their operating systems.
If you plan on servicing Apple hardwarez, then you will need one additional
non-ECDHE-ECDSA
cipher. And you need to use the server side context optionSSL_OP_SAFARI_ECDHE_ECDSA_BUG
.Related, Apple is pretty bold about not fixing their security bugs. You have the broken ECDHE-ECDSA cipher suites; and gems like CVE-2015-1130 (Hidden Backdoor with Root).
Here's what my ECDH callback looks like in OpenSSL 1.0.1 and below. OpenSSL 1.0.2 should use
SSL_CTX_set_ecdh_auto
. Its C++ code, but its easy enough to convert back to C code. Also see SL_CTX_set_tmp_ecdh_callback semantics in 1.0.1 on the OpenSSL mailing list.The code below could be more robust. The callback should fetch the certificate with
SSL_get_certificate
(notSSL_get_peer_certificate
), query the certificate for the EC field, and then provide a temporary key in the appropriate field, likesecp256k1
orsecp571k1
. (It works because my certificates usesecp256
, andEcdhCallback
usessecp256
as its default).
SSL_get_certificate
is not documented. But it is used in<openssl src>/apps/s_cb.c
. That's the "self documenting" code OpenSSL is famous for.using SSL_ptr = std::shared_ptr<SSL>; using SSL_CTX_ptr = std::shared_ptr<SSL_CTX>; using EC_KEY_ptr = std::unique_ptr<EC_KEY, decltype(&::EC_KEY_free)>; using EC_GROUP_ptr = std::unique_ptr<EC_GROUP, decltype(&::EC_GROUP_free)>; using EC_POINT_ptr = std::unique_ptr<EC_POINT, decltype(&::EC_POINT_free)>; using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>; using BIO_MEM_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>; using BIO_FILE_ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>; ... SSL_CTX* CreateServerContext(const string & domain) { const SSL_METHOD* method = SSLv23_server_method(); ASSERT(method != NULL); SSL_CTX_ptr t(SSL_CTX_new(method), ::SSL_CTX_free); ASSERT(t.get() != NULL); long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; flags |= SSL_OP_NO_COMPRESSION; flags |= SSL_OP_SAFARI_ECDHE_ECDSA_BUG; flags |= SSL_OP_CIPHER_SERVER_PREFERENCE; SSL_CTX_set_options(t.get(), flags); string ciphers = "HIGH:!aNULL:!RC4:!MD5"; rc = SSL_CTX_set_cipher_list(t.get(), ciphers.c_str()); ... LogDebug("GetServerContext: setting ECDH callback"); SSL_CTX_set_tmp_ecdh_callback(t.get(), EcdhCallback); ... return t.release(); } EC_KEY* EcdhCallback(SSL *ssl, int is_export, int keylength) { UNUSED(ssl); UNUSED(is_export); UNUSED(keylength); /* This callback is OK, but OpenSSL calls it in a broken fashion. */ /* With 1.0.1e and 1.0.1f, the value is 1024-bits. That is more */ /* appropriate for RSA.... We'll try and rewrite it here. */ if (keylength >= 1024) { keylength = 256; LogRelevant("EcdhCallback: field size is wrong, using 256-bit group"); } #if defined(ALLOW_ECDH_192_PARAMS) if (keylength <= 192 + 4) return ECDH192(); #endif if (keylength <= 224 + 4) return ECDH224(); else if (keylength <= 256 + 4) return ECDH256(); else if (keylength <= 384 + 4) return ECDH384(); else if (keylength <= 521 + 4) return ECDH521(); return ECDH521(); } #if defined(ALLOW_ECDH_192_PARAMS) static EC_KEY* ECDH192() { static EC_KEY_ptr key(NULL, NULL); static once_flag flag; call_once(flag, []() { key = EC_KEY_ptr(InitEcdhkey(192), ::EC_KEY_free); ASSERT(key.get()); if(!key.get()) LogError("ECDH192: InitEcdhkey failed"); }); return key.get(); } #endif static EC_KEY* ECDH224() { static EC_KEY_ptr key(NULL, NULL); static once_flag flag; call_once(flag, []() { key = EC_KEY_ptr(InitEcdhkey(224), ::EC_KEY_free); ASSERT(key.get()); if(!key.get()) LogError("ECDH224: InitEcdhkey failed"); }); return key.get(); } static EC_KEY* ECDH256() { static EC_KEY_ptr key(NULL, NULL); static once_flag flag; call_once(flag, []() { key = EC_KEY_ptr(InitEcdhkey(256), ::EC_KEY_free); ASSERT(key.get()); if(!key.get()) LogError("ECDH256: InitEcdhkey failed"); }); return key.get(); } static EC_KEY* ECDH384() { static EC_KEY_ptr key(NULL, NULL); static once_flag flag; call_once(flag, []() { key = EC_KEY_ptr(InitEcdhkey(384), ::EC_KEY_free); ASSERT(key.get()); if(!key.get()) LogError("ECDH384: InitEcdhkey failed"); }); return key.get(); } static EC_KEY* ECDH521() { static EC_KEY_ptr key(NULL, NULL); static once_flag flag; call_once(flag, []() { key = EC_KEY_ptr(InitEcdhkey(521), ::EC_KEY_free); ASSERT(key.get()); if(!key.get()) LogError("ECDH521: InitEcdhkey failed"); }); return key.get(); } static EC_KEY* InitEcdhkey(int bits) { if (bits <= 160 + 4) bits = 160; else if (bits <= 192 + 4) bits = 192; else if (bits <= 224 + 4) bits = 224; else if (bits <= 256 + 4) bits = 256; else if (bits <= 384 + 4) bits = 384; else if (bits <= 521 + 4) bits = 521; else bits = 521; EC_KEY* key = EC_KEY_new_by_curve_name(CurveToNidByBits(bits)); unsigned long err = ERR_get_error(); ASSERT(key != NULL); if (key == NULL) { ostringstream oss; oss << "InitEcdhkey: EC_KEY_new_by_curve_name failed for "; oss << bits << "-bit key, error " << err << ", 0x" << err; LogError(oss); } return key; }
这篇关于与ECDHE密钥和证书服务器无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!