【问题标题】:Integrating SSL into a program which uses BSD sockets将 SSL 集成到使用 BSD 套接字的程序中
【发布时间】:2012-05-04 20:38:20
【问题描述】:

我有一个 TCP 网络库,它实现了一堆协议(redis、http 等),它们是使用 BSD 套接字实现的。

很多代码使用 select() 和其他用于 BSD 套接字的函数。我是否正确假设这不适用于 SSL 套接字?还是他们会按原样工作?

我只是想知道 SSL 和 BSD 套接字是否如此不同以至于它们需要完全不同的实现方法。

【问题讨论】:

  • SSL 通信使用普通的“BSD”套接字,它只是另一个协议级别,例如TCP。

标签: c sockets ssl openssl


【解决方案1】:

想到的一件事是,您不应该在运行 ssl 连接的 fd 上进行选择。那是因为它可能会说你可以在 ssl_read 阻塞时读取它。例如,这是由于 SSL 进行密钥重新协商而不是应用程序数据变得可用而导致的。这是陷阱之一。

【讨论】:

  • 其实 select() 还在使用,但协议逻辑应该检查的不是 select() 而是缓冲区中解码数据的可用性。
【解决方案2】:

假设您指的是 OpenSSL,它位于套接字的顶部,不会取代它。所以所有直接套接字操作,如select(),仍然有效。但是,不同之处在于 OpenSSL 会为您处理读写操作,因此您可以将 recv() 替换为 ssl_read() 并将 send() 替换为 ssl_write(),但您仍然可以(并且在某些情况下需要)使用 select()直接地。但是,您不能随时调用它,您必须等到 OpenSSL 告诉您调用它。因此,例如,如果您有一个读取循环首先调用select(),然后仅当select() 报告可读性时才调用recv(),则您必须交换该逻辑。先调用ssl_read(),只有当ssl_read()返回SSL_ERROR_WANT_READSSL_ERROR_WANT_WRITE时才调用select()(注意ssl_read()可以在内部进行写操作,ssl_write()可以在内部进行读操作) .

【讨论】:

    【解决方案3】:

    这可能会迟到,但可能会为未来的用户提供很好的参考。在 url http://developerweb.net/viewtopic.php?id=6824 上使用 select() 函数有一个很好的线程。举一个例子如下

    int sslsock_handle_nbio (ssl, ret, totv)
        void            *ssl;           /* -> the SSL info                      */
        int             ret;            /* the SSL I/O function return value    */
        struct timeval  *totv;          /* -> timeout info, or NULL             */
    {
        int     sfd, i;
        fd_set  rset, wset;
    
        sfd = SSL_get_fd (ssl);
        i = SSL_get_error (ssl, ret);
    
        if (i == SSL_ERROR_WANT_READ) {
        do {
            FD_ZERO (&rset);
            FD_SET (sfd, &rset);
            i = select (sfd + 1, &rset, NULL, NULL, totv);
        } while ((i < 0) && (errno == EINTR));
        if (i == 0) {
            /* the select() timed out */
            ret = -2;
            errno = ETIMEDOUT;
        } else {
            /* either an error, or it's readable */
            ret = i;
        }
        } else if (i == SSL_ERROR_WANT_WRITE) {
        do {
            FD_ZERO (&wset);
            FD_SET (sfd, &wset);
            i = select (sfd + 1, NULL, &wset, NULL, totv);
        } while ((i < 0) && (errno == EINTR));
        if (i == 0) {
            /* the select() timed out */
            ret = -2;
            errno = ETIMEDOUT;
        } else {
            /* either an error, or it's writable */
            ret = i;
        }
        }
        /* else, leave "ret" alone, and return it as-is */
    
        return (ret);
    }
    

    这仅在执行SSL_read()SSL_write() 之后。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多