如何使用openssl进行TLS 1.3 PSK?

3

我正在开发一款客户端/服务器软件,并尝试使用openssl建立TLS 1.3 PSK连接的设置方法。显然,与TLS 1.2(及更低版本)相比,存在不同的回调方法,但openssl文档令人困惑,我无法完全理解全部流程。

有没有人能提供样例代码,演示如何在这些回调中返回信息?

int SSL_psk_use_session_cb_func(SSL *ssl, const EVP_MD *md,const unsigned char **id,size_t *idlen,SSL_SESSION **sess);   

int (*SSL_psk_find_session_cb_func)(SSL *ssl,const unsigned char *identity,size_t identity_len,SSL_SESSION **sess);
  1. TLS1.3 中我的理解是身份提示为 NULL,那么为什么这些 TLS1.3 特定的回调函数中有身份字段?
  2. 我在某个地方看到 TLS 1.3 有不同的密码套件设置,PSK AES256 和 PSK CHACHA20 的名称是什么?
  3. 在我的情况下,服务器只会接受一个连接,即 P2P 数据链路。我是否仍然需要让一方充当服务器,即使用 find_session_cb 而非 use_session_cb?
2个回答

6

有人能提供如何在这些回调函数中返回信息的示例代码吗?

您可以在这里查看 s_client 如何实现:

https://github.com/openssl/openssl/blob/6af1b11848f000c900877f1289a42948d415f21c/apps/s_client.c#L183-L243

这就是 s_server 如何实现的:

https://github.com/openssl/openssl/blob/6af1b11848f000c900877f1289a42948d415f21c/apps/s_server.c#L185-L232

“我的理解是,在TLS1.3中,身份提示为NULL,那么为什么这些针对TLS1.3的回调函数中有身份字段呢?”
“身份提示和身份是两个不同的东西。在TLSv1.2中,服务器可以向客户端提供提示,以允许客户端选择正确的身份。在TLSv1.3中,PSK的工作方式完全不同。客户端在第一条消息中将身份发送给服务器,因此没有机会接收提示。实际上,提示通常并不那么有用。”
“在PSK的上下文中,您可以将身份视为类似于用户名的东西(实际上这有点过于简化了,但对我们的目的足够了)”
“听说TLS 1.3有不同的密码套件集,PSK AES256和PSK CHACHA20的名称是什么?”
在TLSv1.2中,您需要使用特殊的PSK密码套件。在TLSv1.3中,不再需要这样做。密码套件的工作方式有很大不同,没有特殊的PSK密码套件概念。您只需使用普通的密码套件。要注意的主要事项是,在TLSv1.3中,PSK始终与哈希(例如SHA256)相关联。您使用的任何密码套件都必须与该哈希兼容,例如对于SHA256,您可以使用TLS_CHACHA20_POLY1305_SHA256或TLS_AES_128_GCM_SHA256。

在我的情况下,服务器仅接受一个连接,即点对点数据链路。我是否仍然需要让一侧充当服务器,即使用find_session_cb而不是use_session_cb?

在TLS中,客户端被定义为启动通信的对等方,服务器是接收传入连接的对等方。因此,总会存在客户端和服务器角色。因此,是的,一侧必须使用find_session_cb,另一侧必须使用use_session_cb。

1
PSK本身并不直接用作加密消息的密钥。使用KDF(密钥派生函数)来派生一个在客户端和服务器之间共享的密钥。该KDF的输入之一是PSK值。另一个输入是(EC)DHE共享秘密,即通过使用握手中包含的数据使用密码算法派生的值。通过这种方式,实际在任何给定连接中使用的密钥每次都不同 - 即使您使用相同的PSK。为了使KDF工作,它使用哈希算法(例如SHA256)。 - Matt Caswell
1
请查看此处的文档:https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_psk_use_session_callback.html,特别是该页面上的第三段。通常,在握手过程中只会调用一次use_session_cb,但有时可能会调用两次。第一次调用cb时,传递给cb的md参数始终为NULL。在这种情况下,我们可以忽略它。如果第二次调用,则会指定一个md,并且它*必须*与与PSK关联的md兼容。因此,此if首先检查md是否非NULL,如果是,则检查md是否与PSK兼容。 - Matt Caswell
1
在OpenSSL中,PSK表示为SSL_SESSION对象。这是因为TLSv1.3对于PSK使用与恢复会话相同的机制,即如果你只需要进行普通的TLS(没有PSK),那么在第一次连接后,你将与服务器建立一个会话。当你创建一个新的连接时,你将使用原始会话的详细信息“恢复”。在TLSv1.3中,PSK和会话是无法区分的。如我所链接的文档中所述,在设置用作PSK的SSL_SESSION对象时,您需要设置3个字段:主密钥、密码套件和协议版本。 - Matt Caswell
1
从文档中得知:“仅与密码套件相关联的握手摘要对PSK有意义(服务器可以继续协商任何与摘要兼容的密码套件)”。因此,只要最终协商的密码套件与摘要(又称哈希)兼容,您可以选择任何喜欢的密码套件。 - Matt Caswell
发现了问题,原来必须使用“SSL_set_ciphersuites”明确设置加密套件,因为 OpenSSL 在服务器端默认使用“tls13_aes256_gcm_sha384”,导致出现错误。 - tunafish24
显示剩余7条评论

3
我希望你是指在TLSv1.3中使用外部建立的PSK(带有out-of-band PSK密钥和ID)。为此,您可以直接使用旧的回调函数psk_client_callbackpsk_server_callback。使用这些回调,默认情况下会使用AES_128_GCM_WITH_SHA256密码套件。
TLSv1.3 PSK 客户端, 服务器 示例在此存储库
在此示例中,ClientHello消息发送带有PSK_ID的pre_shared_key扩展。而ServerHello则响应带有所选PSK_ID索引为0的pre_shared_key扩展。

enter image description here

enter image description here

如果需要使用不同的加密套件,则需要使用 psk_use_session_cbpsk_find_session_cb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接