如何在没有套接字管理的情况下使用OpenSSL库?

How to use OpenSSL library without socket management?

本文关键字:情况下 OpenSSL 管理 套接字      更新时间:2023-10-16

我正在通过添加完整的加密功能来改进现有的C++通信模块。我想使用 OpenSSL 的全部功能,如握手、密钥协议、密钥生成和加密,以使服务器和客户端之间创建的通道安全。

我的问题是,我不想放弃现有的套接字管理方法,而只是使用OpenSSL来完成此任务。我的模块必须仍然控制文件描述符、套接字构造/销毁和消息发送/接收。

我最近经常阅读OpenSSL的源代码,我注意到它使用状态机。状态机启动消息的构造和发送,例如用于握手的客户端问候。我试图弄清楚如何防止状态机发送/接收这些消息,同时仍然保持其功能。

我注意到OpenSSL使用了很多函数指针,这些指针可以在存储在ssl_st结构中的ssl_method_st中找到。


/* Used to hold SSL/TLS functions */
struct ssl_method_st {
int version;
unsigned flags;
unsigned long mask;
int (*ssl_new) (SSL *s);
int (*ssl_clear) (SSL *s);
void (*ssl_free) (SSL *s);
int (*ssl_accept) (SSL *s);
int (*ssl_connect) (SSL *s);
int (*ssl_read) (SSL *s, void *buf, size_t len, size_t *readbytes);
int (*ssl_peek) (SSL *s, void *buf, size_t len, size_t *readbytes);
int (*ssl_write) (SSL *s, const void *buf, size_t len, size_t *written);
int (*ssl_shutdown) (SSL *s);
int (*ssl_renegotiate) (SSL *s);
int (*ssl_renegotiate_check) (SSL *s, int);
int (*ssl_read_bytes) (SSL *s, int type, int *recvd_type,
unsigned char *buf, size_t len, int peek,
size_t *readbytes);
int (*ssl_write_bytes) (SSL *s, int type, const void *buf_, size_t len,
size_t *written);
int (*ssl_dispatch_alert) (SSL *s);
long (*ssl_ctrl) (SSL *s, int cmd, long larg, void *parg);
long (*ssl_ctx_ctrl) (SSL_CTX *ctx, int cmd, long larg, void *parg);
const SSL_CIPHER *(*get_cipher_by_char) (const unsigned char *ptr);
int (*put_cipher_by_char) (const SSL_CIPHER *cipher, WPACKET *pkt,
size_t *len);
size_t (*ssl_pending) (const SSL *s);
int (*num_ciphers) (void);
const SSL_CIPHER *(*get_cipher) (unsigned ncipher);
long (*get_timeout) (void);
const struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
int (*ssl_version) (void);
long (*ssl_callback_ctrl) (SSL *s, int cb_id, void (*fp) (void));
long (*ssl_ctx_callback_ctrl) (SSL_CTX *s, int cb_id, void (*fp) (void));
};

也许我可以以某种方式将其中一些指针设置为我自己的函数,而无需调用SSL_set_fd使其工作?我希望 OpenSSL 在需要时构建和加密所需的消息,例如 clientHello、serverHello,但不是发送它,而是将构造的消息提供给我的模块。

我该怎么做?

我提请您注意BIO_new_bio_pair(3)手册页:

BIO 对的一个典型用途是将 TLS/SSL I/O 置于应用程序下 控制,当应用程序希望使用非 TLS/SSL 的标准传输或普通套接字例程是 不当。

BIO是OpenSSL的输入/输出源/接收器抽象层。

手册页末尾的简短示例似乎完美地描述了您想要执行的操作。总结一下:

  • 创建链接的 BIO 对

  • 使用SSL_set_BIO()将新的 SSL 会话附加到 BIO 对的一半(而不是套接字(

  • 正常使用 SSL 会话,并从其他 BIO 对读取/写入 TLS 加密数据。从这一点开始,您可以自己获取数据并处理对套接字的读取/写入,或者对它做任何您想做的事情。

BIO 对实际上形成了类似于双向管道文件描述符的东西。BIO_new_bio_pair给你的东西与你从pipe(2)得到的东西差不多,除了管道的两端都是双向的。

您必须非常小心和理解的一件事是内部"BIO 管道"中缓冲的数据的语义,以及如何正确处理它。例如,SSL 级别的例程现在大多表现得像连接到非阻塞文件描述符一样,并且在底层"BIO 管道"中没有数据或内部缓冲区已满时相应地运行。