我需要创建一个可以直接读取/写入握手数据的 OpenSSL 连接。原因是握手数据将在 UDP 连接中传输(DTLS 不是一个选项,因为数据不直接在数据报中,而是在另一个协议(protocol)数据包中,EAP 如果你好奇的话)。到目前为止,我已经创建了一个 OpenSSL 连接,但我什至无法读取客户端的握手信息以发送到服务器。
在我的研究中,我发现我需要一个 Memory BIO 来读取/写入连接,但不知道如何提取握手数据。以下是我如何初始化客户端连接:
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
ctx = SSL_CTX_new(SSLv3_client_method());
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
ssl = SSL_new(ctx);
rbio = BIO_new(BIO_s_mem());
wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
SSL_set_connect_state(ssl);
我已经尝试使用 SSL_connect
来启动握手:
int ret = SSL_connect(ssl);
但是返回 -1
,并且执行 SSL_get_error(ssl, res)
我得到一个错误代码 2
,然后我执行 ERR_error_string
与该代码并获得:
error:00000002:lib(0):func(0):system lib
此外,如果我使用 SSL_do_handshake
而不是 SSL_connect
,我会得到完全相同的错误。
我已经能够通过 TCP 设置 OpenSSL 连接,但从未使用 Memory BIO 进行过此操作,因此非常感谢对此提供任何帮助。谢谢!
最佳答案
最后我让它工作了,我的方法是正确的:
需要函数 SSL_set_connect_state(ssl)
来告知连接为握手初始化做好准备。然后,我们调用 SSL_do_handshake(ssl)
开始握手。此函数将返回 -1
因为握手尚未完成,但我们实际上可以从客户端 ssl 连接 BIO writer 读取数据并使用我们想要的协议(protocol)发送数据(在我的例子中,EAP RADIUS 数据包通过UDP)。
客户端
ctx = SSL_CTX_new(SSLv3_client_method());
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
ssl = SSL_new(ctx);
rbio = BIO_new(BIO_s_mem());
wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
SSL_set_connect_state(ssl);
SSL_do_handshake(ssl); // This will return -1 (error) as the handshake is not finished, we can ignore it.
char buf[4096];
BIO_read(wbio, buf, 4096); // Read from BIO, put data in buffer
// Then use data in buffer to send to the server
另一方面,服务器应该使用凭证和私钥进行配置。此外,我们应该使用 SSL_set_accept_state()
而不是 SSL_set_connect_state()
,因为服务器将等待客户端的握手问候。然后,我们简单地将客户端握手问候数据写入服务器 BIO 读取器:
服务器
ctx = SSL_CTX_new(SSLv3_server_method()); // This is the server!
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
ssl = SSL_new(ctx);
rbio = BIO_new(BIO_s_mem());
wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
SSL_set_accept_state(ssl); // The server uses SSL_set_accept_state
// Here we get the data from the client suppose it's in the variable buf
// and write it to the connection reader BIO.
BIO_write(rbio, buf, strlen(buf));
if (!SSL_is_init_finished(ssl)) {
SSL_do_handshake(ssl);
}
我们可以使用 SSL_is_init_finished(ssl)
函数来检查握手是否完成,如果没有完成,我们调用 SSL_do_handshake(ssl)
,然后再次从 BIO_writer 读取数据发送给客户端。
客户端和服务器之间的这个过程应该在连接完成之前完成(即 SSL_is_init_finished(ssl)
返回 true
)。
然后,握手完成后,您可以使用SSL_read
和SSL_write
函数在客户端/服务器之间发送安全 数据。希望这个简短的解释对某人有用!
关于c - 使用 Memory BIO 直接读/写握手数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22753221/