首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >未设置SSL routines:SSL3_READ_N:read bio

未设置SSL routines:SSL3_READ_N:read bio
EN

Stack Overflow用户
提问于 2013-01-28 10:10:05
回答 1查看 1.3K关注 0票数 2

我在C中找到了一个非常好的SSL/TLS server-client example,我想把它改编成和BIO库一起使用。除了在运行服务器时遇到的一个错误之外,我基本上成功了:

$ ./ssl-server 68671:error:140950D3:SSL routines:SSL3_READ_N:read bio not set:/SourceCache/OpenSSL098/OpenSSL098-35.1/src/ssl/s3_pkt.c:203:

我正在使用gcc -o ssl-server SSL-Server.c -lssl -lcrypto -Wall编译服务器:

代码语言:javascript
复制
//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <stdlib.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
#define PORT "2013"

SSL_CTX* InitServerCTX(void)
{
    SSL_METHOD *method;
    SSL_CTX *ctx;

    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    method = SSLv3_server_method();
    ctx = SSL_CTX_new(method);

    if( ctx == NULL )
    {
        ERR_print_errors_fp(stderr);
        abort();
    }

    return ctx;
}

void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
    if( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
    {
        ERR_print_errors_fp(stderr);
        abort();
    }

    if( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, 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();
    }
}

void ShowCerts(SSL* ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    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)
{
    char buf[1024];
    int sd, bytes;

    if( SSL_accept(ssl) == FAIL )
    {
        ERR_print_errors_fp(stderr);
    }
    else
    {
        ShowCerts(ssl);
        bytes = SSL_read(ssl, buf, sizeof(buf));

        if( bytes > 0 )
        {
            buf[bytes] = 0;
            printf("Client msg: \"%s\"\n", buf);
            SSL_write(ssl, "back message", strlen("back message"));
        }
        else
        {
            ERR_print_errors_fp(stderr);
        }
    }

    sd = SSL_get_fd(ssl);
    SSL_free(ssl);
    close(sd);
}

int main(int count, char *strings[])
{
    SSL_CTX *ctx;
    BIO *acc, *client;

    SSL_library_init();

    ctx = InitServerCTX();
    LoadCertificates(ctx, "mycert.pem", "mycert.pem");

    acc = BIO_new_accept(PORT);
    if(!acc)
    {
        printf("Error creating server socket");
    }
    while(1)
    {
        if(BIO_do_accept(acc) <= 0)
        {
            printf("Error binding server socket");
        }

        SSL *ssl;
        client = BIO_pop(acc);
        if(!(ssl = SSL_new(ctx)))
        {
            printf("Error creating SSL context");
        }
        SSL_set_bio(ssl, client, client);

            // Here should be created threads
        Servlet(ssl); 
    }

    SSL_CTX_free(ctx);
}

我正在使用gcc -o ssl-client SSL-Client.c -lssl -lcrypto -Wall编译客户端:

代码语言:javascript
复制
//SSL-Client.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>

#define FAIL -1
#define SERVER "localhost"
#define PORT "2013"

SSL_CTX* InitCTX(void)
{
    SSL_METHOD *method;
    SSL_CTX *ctx;

    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    method = SSLv3_client_method();
    ctx = SSL_CTX_new(method);

    if( ctx == NULL )
    {
        ERR_print_errors_fp(stderr);
        abort();
    }

    return ctx;
}

void ShowCerts(SSL* ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    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");
    }
}

int main(int count, char *strings[])
{
    SSL_CTX *ctx;
    SSL *ssl;
    BIO *conn;
    char buf[1024];
    int bytes;

    SSL_library_init();
    ctx = InitCTX();

    conn = BIO_new_connect(SERVER ":" PORT);
    if(!conn)
    {
        printf("Error creating connection BIO");
    }
    if(BIO_do_connect(conn) <= 0)
    {
        printf("Error connecting to remote machine");
    }

    ssl = SSL_new(ctx);
    SSL_set_bio(ssl, conn, conn);

    if( SSL_connect(ssl) <= 0 )
    {
        printf("Error connecting SSL object");
    }
    else
    {
        printf("Connected!");
        ShowCerts(ssl);
        SSL_write(ssl, "ana are mere", strlen("ana are mere") );

        bytes = SSL_read(ssl, buf, sizeof(buf));
        printf("%s\n", buf);

        SSL_free(ssl);
    }

    SSL_CTX_free(ctx);

    return 0;
}

我正在使用openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem命令生成证书。

一切运行正常,消息发送正常。请忽略错误检查的缺乏,并原谅代码中的全部混乱,这只是为了学习目的。

有人能告诉我出什么问题了吗?你能分辨出我是否在犯重大错误,我正在努力学习吗?(例如,常规呼叫顺序,重大安全问题等)

谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-01-30 05:46:48

根据manual page (底部的示例代码非常具有说明性),对BIO_do_accept()的第一个调用将设置接受的BIO,其他什么也不做。只有第二个和所有后续调用才是接受连接的实际调用。这很好地说明了为什么OpenSSL永远不会赢得“最直观的应用程序接口设计”奖。

那么在你的代码中发生了什么呢?您只需在循环内调用BIO_do_accept()。第一次通过循环时,它将设置BIO并立即返回。您的代码在不存在的连接上调用Servlet()SSL_accept()失败,返回您看到的错误。在Servlet()返回之后,您的代码愉快地循环到BIO_do_accept()的第二次调用中,这一次会阻塞,等待第一个连接,然后一切都按预期进行。

要解决这个问题,您需要在循环之前调用BIO_do_accept()一次,如下所示(为了保持一致性,使用错误处理的错误处理方式--您确实需要修复错误处理!):

代码语言:javascript
复制
[...]
acc = BIO_new_accept(PORT);
if(!acc)
{
    printf("Error creating server socket");
}
/* first call is to set up accept BIO */
if(BIO_do_accept(acc) <= 0)
{
    printf("Error calling BIO_do_accept() the first time");
}
while(1)
{
    if(BIO_do_accept(acc) <= 0)
    {
        printf("Error binding server socket");
    }
[...]
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14554514

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档