没有记录层,我怎样才能只获得 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 似乎是最接近的,但它仍然只有两个 wrapunwrap 方法,它们创建/读取密文和读取/生成纯文本(尽管我可能只进行握手而不传输任何实际数据)。

有没有简单的方法可以去掉记录层?或者我可以使用其他实现方式吗?

我还需要从中获取实际的密钥(或者更确切地说,是主密钥)。

【问题讨论】:

请注意,握手的身份验证部分是在握手中先前消息的串联之上。据我所知,这并没有改变。所以握手依赖于记录的结构。因此,将其抽象出来并没有多大意义,除非您明确地为这样的变化进行设计。这使得问题的答案很可能是“否”。 @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 握手?的主要内容,如果未能解决你的问题,请参考以下文章

什么是ssl,tls?两者有什么区别?

通过完全记录握手来破坏 TLS 安全性

DTLS数据包传输层安全性协议详解

tls 1.0 RFC文档 自译

git lfs 批处理响应:发布 https://../info/lfs/objects/batch: ..proxyconnect tcp: tls: 第一条记录看起来不像 TLS 握手

是否可以在 Tomcat 中进行 TLS 握手事件?