【问题标题】:SSL_Accept fails, SSL_get_error returns 1SSL_Accept 失败,SSL_get_error 返回 1
【发布时间】:2016-11-09 11:28:33
【问题描述】:

我是 SSL 套接字编程的新手,我的首要任务是让 SSL 服务器客户端正常工作和理解。

我已经获得了漂浮在网络上的服务器和客户端源代码,并针对我的 openssl 库进行了编译(从源代码编译)。

当我启动服务器时,我可以使用 accept 系统调用创建一个普通的 clientfd,但是 SSL_accept 失败。

clientsocketfd = accept(serversocketfd, NULL, 0);
serverssl = SSL_new(ssl_server_ctx);
if(!serverssl)
{
    printf("Error SSL_new\n");
    return -1;
}
SSL_set_fd(serverssl, clientsocketfd);

if((ret = SSL_accept(serverssl))!= 1)
{
    printf("Handshake Error %d\n", SSL_get_error(serverssl, ret));
    return -1;
}

SSL_accept 无法打印 Handshake error 1

为什么SSL_accept 失败并出现错误 1?


服务器来源:

/*---------------------------------------------------------------------*/
/*--- main - create SSL socket server.                              ---*/
/*---------------------------------------------------------------------*/
int main(int count, char *strings[])
{   SSL_CTX *ctx;
    int server;
    char *portnum;

    if ( count != 2 )
    {
        printf("Usage: %s <portnum>\n", strings[0]);
        exit(0);
    }
    portnum = strings[1];
    SSL_library_init();
    ctx = InitServerCTX();                                                              /* initialize SSL */
    LoadCertificates(ctx, "newreq.pem", "newreq.pem");  /* load certs */
    server = OpenListener(atoi(portnum));                               /* create server socket */
    while (1)
    {   struct sockaddr_in addr;
        int 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 */
        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 */
}

/*---------------------------------------------------------------------*/
/*--- InitServerCTX - initialize SSL server  and create context     ---*/
/*---------------------------------------------------------------------*/
SSL_CTX* InitServerCTX(void)
{   SSL_METHOD *method;
    SSL_CTX *ctx;

    OpenSSL_add_all_algorithms();               /* load & register all cryptos, etc. */
    SSL_load_error_strings();                   /* load all error messages */
    method = SSLv3_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;
}

OpenSSL版本和编译选项如下:

/usr/bin/openssl version -a
OpenSSL 1.0.2g  1 Mar 2016
built on: reproducible build, date unspecified
platform: debian-amd64
options:  bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx) 
compiler: cc -I. -I.. -I../include  -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT 
-DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -g -O2 -fstack-protector-strong 
-Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -Wl,
-Bsymbolic-functions -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int 
-DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT 
-DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM 
-DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM 
-DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
OPENSSLDIR: "/usr/lib/ssl"

【问题讨论】:

  • 检查所有返回值。将 cmets 放在代码右侧的这种注释风格有多大用处?你能看到那些cmets而不用玩滚动条吗?像这样评论是个坏主意。你花了多少时间来创建那些漂亮的 ASCII 艺术盒子 cmets?

标签: c linux security ssl openssl


【解决方案1】:

显然,某些 Linux 发行版(例如 Ubuntu 16.04)分发的软件包中已禁用 SSLv3:

openssl (1.0.2g-1ubuntu1) xenial;紧急=中等

  • 与 Debian 合并,其余更改。
    • 在不更改 ABI 的情况下禁用 SSLv3:
      • debian/patches/no-sslv3.patch:禁用 SSLv3 而不使用 无 ssl3 方法选项
      • debian/rules:不要使用 no-ssl3-method,不要碰 soname
      • debian/patches/engines-path.patch:不要碰 soname
      • debian/patches/version-script.patch:不要碰 soname
      • debian/patches/soname.patch:已移除
      • debian/lib*:不要碰 soname

因此你需要使用另一种方法:

method = SSLv3_server_method();

【讨论】:

  • 您好,谢谢,我使用的是 ubuntu 14.04,代码在创建方法时出现错误。我在 SSL_accept 期间收到错误,虽然正常接受通过并且正在创建客户端连接 fd,但我该如何解决这个问题。
  • 不管你使用的是哪个 Ubuntu 版本,它在你使用的 Ubuntu 的 SSL v1.0.2g 包中被禁用,因此你可以回到 Ubuntu 16.04 并降级如果你愿意,你的包裹。或者更改 SSL 服务器方法。
【解决方案2】:

SSL_accept 的手册页指出:

如果底层 BIO 是非阻塞的,SSL_accept() 也会返回 当底层 BIO 不能满足 SSL_accept() 的需要时 继续握手,返回值-1表示问题。 在这种情况下,调用 SSL_get_error() 并返回值为 SSL_accept() 将产生 SSL_ERROR_WANT_READ 或 SSL_ERROR_WANT_WRITE。 然后调用过程必须在适当的情况下重复调用 满足 SSL_accept() 需求的操作...

我相信这意味着您的代码应该类似于:

while (1)
{
    int acc = SSL_accept(ssl);
    if (acc == 0)
    {
        /* Hard error */
        exit(-1);
    }
    else if (acc == -1)
    {
        int err = SSL_get_error(ssl, ret);
        if (err == SSL_ERROR_WANT_READ)
        {
            /* Wait for data to be read */
        }
        else if (err == SSL_ERROR_WANT_WRITE)
        {
            /* Write data to continue */
        }
        else if (err == SSL_ERROR_SYSCALL || err == SSL_ERROR_SSL)
        {
            /* Hard error */
            exit(-1);
        }
        else if (err == SSL_ERROR_ZERO_RETURN)
        {
            /* Same as error */
            exit(-1);
        }
    }
    else
    {
        /* Continue */
        break;
    }
}

OpenSSL 在&lt;openssl src&gt;/apps/s_client.c&lt;openssl src&gt;/apps/s_server.c 中有示例代码

【讨论】:

  • s_client 是开始了解 SSL 错误发生了什么的好地方
猜你喜欢
  • 2017-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-27
  • 2017-10-15
相关资源
最近更新 更多