具有ECDHE密钥和证书的服务器无法正常工作

时间:2015-05-05 15:32:20

标签: c openssl ca

我使用下面的server.c源代码,我生成了

sinful-host-cert.pem
sinful-host.key

如此处所述:Elliptic Curve CA Guide

运行程序时会出现以下错误:

  

140722397161136:错误:10071065:椭圆曲线例程:func(113):reason(101):ec_lib.c:995:   140722397161136:错误:0B080075:x509证书例程:func(128):reason(117):x509_cmp.c:346:

我编译使用:

  

gcc server.c -ldl -lcrypto -lssl -o Server

错误发生在我认为的这一行

  

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 */
}

1 个答案:

答案 0 :(得分:11)

  

如下所述:Elliptic Curve CA Guide ...

这个页面有很多错误和遗漏我会丢弃它。第一个红旗是白色文字和黑色背景。这告诉我一个经验不足的人正在提供页面...

  

从页面:

openssl ecparam -list-curves

这应该是-list_curves,而不是-list-curves

  

从页面:

openssl ecparam -out sinful.key -name sect283k1 -genkey

这应该是:

openssl ecparam -param_enc named_curve -out sinful.key -name sect283k1 -genkey

如果您没有使用命名曲线,那么稍后您将遇到很多问题,例如客户端尝试连接到服务器时。此处,命名曲线是secp256k1之类曲线的OID,而不是pabG等域信息。 / p>

以后出现很多问题&#34;在OpenSSL wiki Elliptic Curve Cryptography, Named Curves中有记录。以下是您将遇到的一些问题:

  • 客户:139925962778272:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1256:SSL alert number 40
  • 客户:139925962778272:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:596
  • 服务器:140339533272744:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1353

此外,对于最大互操作性,您应该使用secp256k1。紧随其后的是secp521r1

此外,在-*formopenssl ecparam命令中使用/缺少openssl req将在下面讨论。

SSL_CTX* InitServerCTX(void) { ... }

这个代码块有很多问题。最值得注意的是缺少ECDH回调。你在哪里设置SSL_CTX_set_tmp_ecdh回调(OpenSSL 1.0.1及以下版本),或者SSL_CTX_set_ecdh_auto(OpenSSL 1.0.2及以上版本)的调用在哪里?

其他包括默认协议,默认密码列表,弱密码和受伤密码,包含匿名协议和压缩。有关提供服务器上下文的代码的部分示例,请参阅'No Shared Cipher' Error with EDH-RSA-DES-CBC3-SHA

  

错误发生在我认为的这一行

if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)

我认为这会追溯到您引用的有缺陷的页面。这样:

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

应该是(注意添加-keyform

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

if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_ASN1) <= 0)

通常,始终对命令使用*form选项,无论是-keyform-certform-inform-outform等.OpenSSL不会总是把它弄好(即使它默认使用PEM)。

  

错误发生在我认为的这一行

if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)

如果 私钥有密码,则需要提供密码回拨或从文件中删除密码。

可以删除密码,因为存储明文私钥没有区别;或密钥旁边的配置文件中带密码的加密私钥。在这两种情况下,唯一有效的安全性是文件系统ACL。

相关的,这称为无人值守密钥存储问题。古特曼在他的书Engineering Security中对此进行了讨论。这是一个没有解决方案的问题。

这里有一些更完整的错误信息......看起来您使用的是旧版本的OpenSSL,并且没有提供更新的错误代码。

  

运行程序时会出现以下错误:

 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

首先,0x10071065错误:

$ /usr/local/ssl/macosx-x64/bin/openssl errstr 0x10071065
error:10071065:elliptic curve routines:EC_POINT_cmp:incompatible objects

0x10071065通常表示客户端和服务器正在使用不兼容的EC字段。在这种情况下,您应该使用secp256k1secp521r1

其次,0x0B080075错误:

$ /usr/local/ssl/macosx-x64/bin/openssl errstr 0x0B080075
error:0B080075:x509 certificate routines:X509_check_private_key:unknown key type

我猜测证书和私钥存在不匹配。但它只是一个猜测。我会(1)清除指定的曲线问题,(2)清除sect283k1问题,(3)清除下级库问题(见下文)。清除这些问题后,请查看此问题是否仍然存在。

  

看起来您使用的是旧版本的OpenSSL,并且没有提供更新的错误代码......

确保您运行的是OpenSSL 1.0.0或更高版本。 0.9.8的EC支持有限,但直到1.0.0才真正切入。更好,使用OpenSSL 1.0.2。

 OpenSSL_add_all_algorithms();  /* load & register all cryptos, etc. */
 SSL_load_error_strings();   /* load all error messages */

另请参阅OpenSSL wiki上的Library Initialization

 if (SSL_CTX_set_cipher_list(ctx, "ECDHE-ECDSA-AES128-GCM-SHA256")

由于 SecureTransport 库中的错误,这会让您在某些版本的OS X和iOS上遇到麻烦。 Apple仅在某些版本的操作系统上修复了它。

如果您计划为Apple hardwarez提供服务,那么您将需要一个额外的non-ECDHE-ECDSA密码。您需要使用服务器端上下文选项SSL_OP_SAFARI_ECDHE_ECDSA_BUG

相关,Apple对于不修复安全漏洞非常大胆。你有破碎的ECDHE-ECDSA密码套件;和宝石一样CVE-2015-1130 (Hidden Backdoor with Root)

这是我的ECDH回调在OpenSSL 1.0.1及更低版本中的样子。 OpenSSL 1.0.2应该使用SSL_CTX_set_ecdh_auto。它的C ++代码,但它很容易转换回C代码。另请参阅OpenSSL邮件列表中的SL_CTX_set_tmp_ecdh_callback semantics in 1.0.1

下面的代码可能更强大。回调应该使用SSL_get_certificate not SSL_get_peer_certificate)获取证书,查询EC字段的证书,然后在相应字段中提供临时密钥,例如{{ 1}}或secp256k1。 (它有效,因为我的证书使用secp571k1secp256使用EcdhCallback作为默认值。

secp256未记录在案。但它在SSL_get_certificate中使用。这就是&#34;自我记录&#34;代码OpenSSL是着名的。

<openssl src>/apps/s_cb.c