Thread (8 messages) 8 messages, 2 authors, 2018-08-03

RE: Security enhancement proposal for kernel TLS

From: Vakul Garg <hidden>
Date: 2018-07-31 12:25:15

-----Original Message-----
From: Dave Watson [mailto:davejwatson@fb.com]
Sent: Tuesday, July 31, 2018 2:46 AM
To: Vakul Garg <redacted>
Cc: netdev@vger.kernel.org; Peter Doliwa <redacted>; Boris
Pismenny [off-list ref]
Subject: Re: Security enhancement proposal for kernel TLS

On 07/30/18 06:31 AM, Vakul Garg wrote:
quoted
quoted
It's not entirely clear how your TLS handshake daemon works -   Why is
it necessary to set the keys in the kernel tls socket before the
handshake is completed?
IIUC, with the upstream implementation of tls record layer in kernel,
the decryption of tls FINISHED message happens in kernel. Therefore
the keys are already being sent to kernel tls socket before handshake is
completed.

This is incorrect.  
Let us first reach a common ground on this.

 The kernel TLS implementation can decrypt only after setting the keys on the socket.
The TLS message 'finished' (which is encrypted) is received after receiving 'CCS'
message. After the user space  TLS library receives CCS message, it sets the keys
on kernel TLS socket. Therefore, the next message in the  socket receive queue
which is TLS finished gets decrypted in kernel only.

Please refer to following Boris's patch on openssl. The  commit log says:
" We choose to set this option at the earliest - just after CCS is complete".

------------------------------------------------------
commit a01dd062a32c687630b2a860b4bb053008f09ff5
Author: Boris Pismenny [off-list ref]
Date:   Sun Mar 11 16:18:27 2018 +0200

    ssl: Linux TLS Rx Offload
    
    This patch adds support for the Linux TLS Rx socket option.
    It completes the previous patch for TLS Tx offload.
    If the socket option is successful, then the receive data-path of the TCP
    socket is implemented by the kernel.
    We choose to set this option at the earliest - just after CCS is complete.
------------------------------------------------------

The  fact that keys are handed over to kernel TLS socket can also be verified
by putting a log in tls_sw_recvmsg().

I would stop here for you to confirm my observation first. 
Regards. Vakul


 > Currently the kernel TLS implementation decrypts
everything after you set the keys on the socket.  I'm suggesting that you
don't set the keys on the socket until after the FINISHED message.
quoted
quoted
Or, why do you need to hand off the fd to the client program before
the handshake is completed?
The fd is always owned by the client program..

In my proposal, the applications poll their own tcp socket using
read/recvmsg etc.
quoted
If they get handshake record, they forward it to the entity running
handshake agent.
quoted
The handshake agent could be a linux daemon or could run on a separate
security processor like 'Secure element' or say arm trustzone etc. The
applications forward any handshake message it gets backs from
handshake agent to the connected tcp socket. Therefore, the
applications act as a forwarder of the handshake messages between the
peer tls endpoint and handshake agent.
quoted
The received data messages are absorbed by the applications themselves
(bypassing ssl stack completely). Similarly, the applications tx data directly
by writing on their socket.
quoted
quoted
Waiting until after handshake solves both of these issues.
The security sensitive check which is 'Wait for handshake to finish
completely before accepting data' should not be the onus of the
application. We have enough examples in past where application
programmers made mistakes in setting up tls correctly. The idea is to
isolate tls session setting up from the applications.

It's not clear to me what you gain by putting this 'handshake finished'
notification in the kernel instead of in the client's tls library - you're already
forwarding the handshake start notification to the daemon, why can't the
daemon notify them back in userspace that
the handshake is finished?

If you did want to put the notification in the kernel, how would you handle
poll on the socket, since probably both the handshake daemon and client
might be polling the socket, but one for control messages and one for data?

The original kernel TLS RFC did split these to two separate sockets, but we
decided it was too complicated, and that's not how userspace TLS clients
function today.

Do you have an implementation of this?  There are a bunch of tricky corner
cases here, it might make more sense to have something concrete to discuss.
quoted
Further, as per tls RFC it is ok to piggyback the data records after
the finished handshake message. This is called early data. But then it
is the responsibility of applications to first complete finished message
processing before accepting the data records.
quoted
The proposal is to disallow application world seeing data records
before handshake finishes.
You're talking about the TLS 1.3 0-RTT feature, which is indeed an interesting
case.  For in-process TLS libraries, it's fairly easy to punt, and don't set the
kernel TLS keys until after the 0-RTT data + handshake message.  For an OOB
handshake daemon it might indeed make more sense to leave the data in
kernelspace ... somehow.
quoted
quoted
quoted
	- The handshake state should fallback to 'unverified' in case a
control
record is seen again by kernel TLS (e.g. in case of renegotiation,
post handshake client auth etc).

Currently kernel tls sockets return an error unless you explicitly
handle the control record for exactly this reason.
IIRC, any kind handshake message post handshake-completion is a problem
for kernel tls.
quoted
This includes renegotiation, post handshake client-auth etc.

Please correct me if I am wrong.
You are correct, but currently kernel TLS sockets return an error unless you
explicitly handle the control message.  This should be enough already to
implement your proposal.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help