12

I was looking at the recent Internet drafts for the QUIC transport protocol (transport and TLS), and wondered how that could be implemented in Java (or another JVM language), assuming I don't want to reimplement TLS 1.3 at the same time.

TLS is usually based on TCP (or some other protocol with similar service), with two layers in TLS itself:

   +--------------+--------------+--------------+
   |  Handshake   |    Alerts    |  Application |
   |    Layer     |              |     Data     |
   |              |              |              |
   +--------------+--------------+--------------+
   |                                            |
   |               Record Layer                 |
   |                                            |
   +--------------------------------------------+
   |                                            |
   |                   TCP                      |
   |                                            |
   +--------------------------------------------+
   

Diagram adapted from the internet draft, section 2.1

In Java, we can use the classes in javax.net.ssl to implement this, either using SSLEngine for just TLS without the I/O (application or a framework needs to plug in the networking, e.g. using NIO), or an SSLSocket (or SSLServerSocket) for TLS over TCP via usual InputStream/OutputStream blocking I/O.

QUIC uses only the handshake part of TLS 1.3 for negotiating the session keys, while using its own packet format and encryption ("Packet protection") instead of TLS' record layer (and the whole thing is based on UDP, not TCP):

   +--------------+--------------+ +-------------+
   |     TLS      |     TLS      | |    QUIC     |
   |  Handshake   |    Alerts    | | Applications|
   |              |              | | (h2q, etc.) |
   +--------------+--------------+-+-------------+
   |                                             |
   |                QUIC Transport               |
   |   (streams, reliability, congestion, etc.)  |
   |                                             |
   +---------------------------------------------+
   |                                             |
   |            QUIC Packet Protection           |
   |                                             |
   +---------------------------------------------+
   |                                             |
   |                   UDP                       |
   |                                             |
   +---------------------------------------------+

Diagram adapted from the internet draft, section 3

So now my problem: The given TLS implementations (from Java 11 we have TLS 1.3 included) have only TLS in a box, i.e. record + handshake + alerts together, not a handshake only version. SSLEngine seems to come nearest, but it still has just two wrap and unwrap methods which create/read ciphertext and read/produce plain text (though I might be able to do just the handshake without transferring any actual data).

Is there an easy way to strip off the record layer? Or is there a different implementation I could use?

I also would need to get the actual keys (or rather, the master secret) out of it.

Community
  • 1
  • 1
Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • Note that the authentication part of the handshake is over a concatenation over the previous messages in the handshake. This has not been changed to my knowledge. So the handshake *is dependent* on the structure of the records. It therefore doesn't make much sense to abstract this out, unless you are explicitly designing for such a change. This makes the answer to the question very likely a "NO". – Maarten Bodewes Nov 16 '18 at 14:04
  • @MaartenBodewes so how is QUIC then supposed to work? – Paŭlo Ebermann Nov 17 '18 at 12:20
  • If I read the draft correctly the handshake is the same as it ever was, it's just that the QUIC protocol takes over afterwards. But you're right, you should be able to grab the resulting session keys to make that work. Possibly that works using `SSLSession.getValue()` calls. The trick is to know the key to get the key :P Maybe you can find them out by registering a `SSLSessionBindingListener` or by enabling debug output for TLS in Java. (just thinking along here). – Maarten Bodewes Nov 17 '18 at 17:51
  • @MaartenBodewes reading the TLS RFC again, the [transcript hash is over handshake "messages", which is different than "records" (one layer above)](https://tools.ietf.org/html/rfc8446#section-4.4.1). This way QUIC can just take those messages and embed them into its own protocol, without the record headers. – Paŭlo Ebermann Nov 25 '18 at 20:47

1 Answers1

0

there is an easy way. You Write an SSLEngine that is an wrapper of the real one. Than you can remove the frame in the wrap and and the frame in the unwrap part. All other methods you simply delegate.

SkateScout
  • 815
  • 14
  • 24
  • Thanks for the suggestion. Do you have a suggestion how to get the key out? – Paŭlo Ebermann Dec 13 '18 at 23:38
  • To get the "key" if you mean the session key or pre shared master key the only way if via reflection and open-access :-( This is an dirty and not really easy way. The same could be done with SSLSocket too. – SkateScout Dec 14 '18 at 13:42