没有记录层,我怎样才能只获得 TLS 握手?
Posted
技术标签:
【中文标题】没有记录层,我怎样才能只获得 TLS 握手?【英文标题】:How can I get just the TLS handshake, without the record layer? 【发布时间】:2019-03-18 19:03:39 【问题描述】:我正在查看 QUIC 传输协议(transport 和 TLS)的最新 Internet 草案,并想知道如何在 Java(或其他 JVM 语言)中实现它,假设我不想重新实现同时支持 TLS 1.3。
TLS 通常基于 TCP(或其他具有类似服务的协议),TLS 本身有两层:
+--------------+--------------+--------------+
| Handshake | Alerts | Application |
| Layer | | Data |
| | | |
+--------------+--------------+--------------+
| |
| Record Layer |
| |
+--------------------------------------------+
| |
| TCP |
| |
+--------------------------------------------+
图改编自internet draft, section 2.1
在 Java 中,我们可以使用 javax.net.ssl 中的类来实现这一点,或者使用 SSLEngine 仅用于没有 I/O 的 TLS(应用程序或框架需要插入网络,例如使用 NIO) ,或SSLSocket(或 SSLServerSocket),用于通过通常的 InputStream/OutputStream 阻塞 I/O 进行 TCP 上的 TLS。
QUIC 仅使用 TLS 1.3 的握手部分来协商会话密钥,同时使用其自己的数据包格式和加密(“数据包保护”)而不是 TLS 的记录层(以及整个事情是基于 UDP,而不是 TCP):
+--------------+--------------+ +-------------+
| TLS | TLS | | QUIC |
| Handshake | Alerts | | Applications|
| | | | (h2q, etc.) |
+--------------+--------------+-+-------------+
| |
| QUIC Transport |
| (streams, reliability, congestion, etc.) |
| |
+---------------------------------------------+
| |
| QUIC Packet Protection |
| |
+---------------------------------------------+
| |
| UDP |
| |
+---------------------------------------------+
图改编自internet draft, section 3
所以现在我的问题是:给定的 TLS 实现(从 Java 11 开始,我们包含 TLS 1.3)只有 TLS in a box,即一起记录 + 握手 + 警报,而不是 握手只有 版本。 SSLEngine 似乎是最接近的,但它仍然只有两个 wrap
和 unwrap
方法,它们创建/读取密文和读取/生成纯文本(尽管我可能只进行握手而不传输任何实际数据)。
有没有简单的方法可以去掉记录层?或者我可以使用其他实现方式吗?
我还需要从中获取实际的密钥(或者更确切地说,是主密钥)。
【问题讨论】:
请注意,握手的身份验证部分是在握手中先前消息的串联之上。据我所知,这并没有改变。所以握手依赖于记录的结构。因此,将其抽象出来并没有多大意义,除非您明确地为这样的变化进行设计。这使得问题的答案很可能是“否”。 @MaartenBodewes 那么 QUIC 应该如何工作? 如果我正确阅读了草稿,握手和以前一样,只是之后 QUIC 协议接管了。但你是对的,你应该能够获取生成的会话密钥来完成这项工作。可能使用SSLSession.getValue()
调用有效。诀窍是知道获取密钥的密钥:P 也许您可以通过注册SSLSessionBindingListener
或通过在 Java 中启用 TLS 的调试输出来找到它们。 (只是在这里思考)。
@MaartenBodewes 再次阅读 TLS RFC,transcript hash is over handshake "messages", which is different than "records" (one layer above)。这样 QUIC 就可以只接收这些消息并将它们嵌入到自己的协议中,而无需记录头。
【参考方案1】:
有一个简单的方法。您编写一个 SSLEngine,它是真实的包装器。 比您可以删除包装中的框架和展开部分中的框架。您只需委托的所有其他方法。
【讨论】:
感谢您的建议。您对如何取出钥匙有什么建议吗? 如果您的意思是会话密钥或预共享主密钥,则获取“密钥”是通过反射和开放访问的唯一方法:-( 这是一种肮脏且不容易的方法。同样也可以用 SSLSocket 完成。以上是关于没有记录层,我怎样才能只获得 TLS 握手?的主要内容,如果未能解决你的问题,请参考以下文章
git lfs 批处理响应:发布 https://../info/lfs/objects/batch: ..proxyconnect tcp: tls: 第一条记录看起来不像 TLS 握手