OpenSSL:无需 SSL_read() / SSL_write() 即可执行加密/解密

发布于 2024-12-29 02:08:12 字数 364 浏览 0 评论 0原文

我已经用 C 语言编写了一个基于事件的网络库,现在我想通过 OpenSSL 添加 SSL/TLS 支持。我不想使用 SSL_read()SSL_write(),我宁愿让 OpenSSL 只执行传出/传入数据的加密/解密,让我传输/接收我自己的数据。

我是 SSL/TLS 和 OpenSSL 的新手,所以:

有没有办法让 OpenSSL 执行 char 数组的加密/解密?

size_t SSL_encrypt(const char *buf_in, size_t size_in, char *buf_out) 这样的东西会很棒。

I've written an event-based networking library in C and now I want to add SSL/TLS support via OpenSSL. Instead of using SSL_read() and SSL_write(), I'd rather like to have OpenSSL only perform the encryption/decryption of outgoing/incoming data, letting me transmit/receive the data myself.

I'm new to SSL/TLS and OpenSSL, so:

Is there a way to have OpenSSL only perform encryption/decryption of char arrays?

Something like size_t SSL_encrypt(const char *buf_in, size_t size_in, char *buf_out) would be great.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你的笑 2025-01-05 02:08:12

您所要求的正是不可能的,因为使用 TLS,在应用程序层发送内容和在网络套接字上发送内容之间不存在一对一的对应关系。重新协商等事件意味着有时 SSL 需要从网络读取数据才能继续发送数据,反之亦然。

但是,您仍然可以使用 OpenSSL 来执行 SSL,但需要自行处理网络的读写操作。您可以通过在 SSL 指针上调用 SSL_set_bio()(而不是 SSL_set_fd())来完成此操作:

  1. 使用 BIO_new_bio_pair() 创建连接的 BIO 对。 SSL 例程将读取和写入一个 BIO,您的应用程序将读取和写入另一个 BIO(允许它通过所需的任何方法将数据传递到另一端)。

  2. 在新的 SSL 对象将读取和写入 BIO 设置为生成的 BIO 对中的一个。

  3. 在该对中的另一个 BIO 上使用 BIO_read()BIO_write() 来读取和写入 SSL 协议数据。

  4. 照常使用 SSL_accept()SSL_connect()SSL_read()SSL_write() SSL 对象。

(不过,目前还不清楚这会给您的应用程序带来什么好处:在这种情况下,除了准确地读取和写入 OpenSSL 传递给您的内容之外,您实际上无法做任何其他事情,因此您不妨让它也进行读取和写入) 。

Exactly what you've asked for isn't possible, because with TLS there isn't a 1-to-1 correspondence between sending something at the application layer and sending something on the network socket. Events like renegotiations mean that sometimes SSL needs to read data from the network in order to make progress sending data, and vice-versa.

However, you can still use OpenSSL to perform SSL but take care of the reading and writing from the network yourself. You do this by calling SSL_set_bio() on the SSL pointer instead of SSL_set_fd():

  1. Use BIO_new_bio_pair() to create a connected BIO pair. One BIO will be read from and written to by the SSL routines, and the other BIO will be read from and written to by your application (allowing it to pass the data to the other end by whatever method it desires).

  2. Use SSL_set_bio() on a new SSL object to set both the read and write BIO to one of the BIOs in the pair generated.

  3. Use BIO_read() and BIO_write() on the other BIO in the pair to read and write the SSL protocol data.

  4. Use SSL_accept(), SSL_connect(), SSL_read() and SSL_write() as normal on the SSL object.

(It's not clear what advantage this would give in your application, though: in this case you can't really do anything other than read and write exactly what OpenSSL passes you, so you might as well let it do the reading and writing too).

与他有关 2025-01-05 02:08:12

我想做同样的事情,但找不到任何文档,因此深入研究了 OpenSSL 代码。看起来 BIO 的处理很简单,因为它们基本上是带有读/写函数指针的对象以及我们想要替换的类似函数。感兴趣的主要结构是 bio_method_st,遗憾的是 OpenSSL 仅在内部定义它。

在下面的代码中,我复制了相关定义并提供了我自己的写入函数。

您通常会调用的地方

SSL_set_fd(ssl, clientfd);

改为:

// Provide definitions for some openssl internal structs
struct BIO_MSG;
struct bio_method_st {
    int type;
    char *name;
    int (*bwrite) (BIO *, const char *, size_t, size_t *);
    int (*bwrite_old) (BIO *, const char *, int);
    int (*bread) (BIO *, char *, size_t, size_t *);
    int (*bread_old) (BIO *, char *, int);
    int (*bputs) (BIO *, const char *);
    int (*bgets) (BIO *, char *, int);
    long (*ctrl) (BIO *, int, long, void *);
    int (*create) (BIO *);
    int (*destroy) (BIO *);
    long (*callback_ctrl) (BIO *, int, BIO_info_cb *);
    int (*bsendmmsg) (BIO *, BIO_MSG *, size_t, size_t, uint64_t, size_t *);
    int (*brecvmmsg) (BIO *, BIO_MSG *, size_t, size_t, uint64_t, size_t *);
};

// Get methods for 'socket'
const BIO_METHOD *methods = BIO_s_socket();

// Clone them
BIO_METHOD *my_methods = (BIO_METHOD*)malloc(sizeof(bio_method_st));
memcpy(my_methods, methods, sizeof(bio_method_st));

// Replace the ones where you want to provide your own definition
((bio_method_st*)my_methods)->bwrite = [](BIO *bio, const char *data, size_t size, size_t *written) -> int
{
    int fd = BIO_get_fd(bio, nullptr); // Get original fd from the BIO object
    ssize_t res = write(fd, data, size);

    // Return data in the way openssl wants
    if (res > 0)
    {
        *written = res;
        return 1;
    }
    else
    {
        *written = 0;
        return res;
    }
};

// Create new BIO with our methods
BIO *bio = BIO_new(my_methods);
BIO_set_fd(bio, clientfd, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);

注意:由于这取决于内部 OpenSSL 布局,任何 OpenSSL 版本更改等都可能会破坏您的代码,因此请小心使用。

I wanted to do the same and could not find any documentation, so digged into OpenSSL code. Looks like it is trivial to do with BIOs, as they are basically objects with function pointers to read/write and similar functions that we want to replace. Main struct of interest is bio_method_st, sadly OpenSSL only defines it only internally.

In the below code, I copy relevant definition and provide my own write function.

Where you would normally call

SSL_set_fd(ssl, clientfd);

instead do:

// Provide definitions for some openssl internal structs
struct BIO_MSG;
struct bio_method_st {
    int type;
    char *name;
    int (*bwrite) (BIO *, const char *, size_t, size_t *);
    int (*bwrite_old) (BIO *, const char *, int);
    int (*bread) (BIO *, char *, size_t, size_t *);
    int (*bread_old) (BIO *, char *, int);
    int (*bputs) (BIO *, const char *);
    int (*bgets) (BIO *, char *, int);
    long (*ctrl) (BIO *, int, long, void *);
    int (*create) (BIO *);
    int (*destroy) (BIO *);
    long (*callback_ctrl) (BIO *, int, BIO_info_cb *);
    int (*bsendmmsg) (BIO *, BIO_MSG *, size_t, size_t, uint64_t, size_t *);
    int (*brecvmmsg) (BIO *, BIO_MSG *, size_t, size_t, uint64_t, size_t *);
};

// Get methods for 'socket'
const BIO_METHOD *methods = BIO_s_socket();

// Clone them
BIO_METHOD *my_methods = (BIO_METHOD*)malloc(sizeof(bio_method_st));
memcpy(my_methods, methods, sizeof(bio_method_st));

// Replace the ones where you want to provide your own definition
((bio_method_st*)my_methods)->bwrite = [](BIO *bio, const char *data, size_t size, size_t *written) -> int
{
    int fd = BIO_get_fd(bio, nullptr); // Get original fd from the BIO object
    ssize_t res = write(fd, data, size);

    // Return data in the way openssl wants
    if (res > 0)
    {
        *written = res;
        return 1;
    }
    else
    {
        *written = 0;
        return res;
    }
};

// Create new BIO with our methods
BIO *bio = BIO_new(my_methods);
BIO_set_fd(bio, clientfd, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);

Note: since this depends on internal OpenSSL layout, any OpenSSL version change etc might break your code, so use it with care.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文