Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Sun, 27 Sep 2015 22:20:03 -0400
From: Rich Felker <>
Subject: Introduction & summary of tlsify discussions, part 2

The following are excerpts from notes by Daniel Kahn Gillmor (dkg),
who was part of the CII-Madrid tlsify discussions, originally sent to
me by email before the tlsify list was setup, and my replies. Reposted
with permission. The original notes from the workshop were a lot more
sparse than the expanded version I just sent to the tlsify list, so
some of the questions below are probably already answered, but I think
it's still useful discussion.


On Fri, Jul 17, 2015 at 09:18:21PM +0200, Daniel Kahn Gillmor wrote:
> Choice of data channels
> -----------------------
> I'm a little bit confused that it seems to suggest the data channel
> should be stdin/stdout.  i thought we'd talked about a single forwarded
> socket, not pipes, since that should have less of an impedance mismatch
> with the outbound connection.  or is the thought that stdin/stdout would
> be the comms socket?

C callers wanting to use the socket directly as a primitive would want
to pass the same socket as both stdin and stdout, but a caller not
constrained by those requirements could instead use two pipes or could
even attach one or both to a regular file.

> Peer Cert Verification
> ----------------------
> references for specific examples of SRV-ID:
> RFC 6120 specifies the use of SRV-IDs in X.509 certs for XMPP.
> RFC 6764 specifies the use of SRV-IDs in X.509 certs for
> WebDAV/CalDAV/CardDAV.
> the upcoming tzdist draft should also use SRV-IDs, iirc.
> Also, the list of initialization/configuration parameters doesn't
> include any mention of a selected list of root CAs or any additional
> constraints on peer cert verification.  Is the assumption that every
> tlsify parent should be willing to accept the same set of root CAs?
> Here's an example where i think that might not be the case: consider an
> operating system installer that wants to fetch data from the public web
> (e.g. to show the user some news feed to read during installation), but
> also wants to fetch software packages and sensitive configuration
> information from a repository that it knows is certified by an
> organizational CA X.  The second connection would ideally *only* accept
> connections from the organizational CA,

You're completely right that this was an omission. The set of root CAs
is certainly an input, but most callers will probably want to use a
default set or a named set of some sort. The exact nature such "named
sets" might have is unclear to me, but could allow an application to
say something like "no locally-added root CAs" or "restricted root CA
set based on zero-tolerance for breaches of trust". Obviously directly
providing a single organizational CA is another usage case, one which
should be a lot easier to deal with.

> pinning
> -------
> the only cert pinning that's currently in active use that i know about
> is HPKP.  HPKP pins the public key material (not the cert), but it pins
> it any key (or keys) in the chain, and multiple pins can be present for
> a given host.
> To support that, i see two options:
>  0) parent process maintains pinning database (this is what you've
>     specified in the etherpad): at initialization/configuration, the
>     parent process hands pinned key fingerprints to the child process,
>     so that the child process knows to reject before the TLS handshake
>     is completed.  when the parent process receives pinning information
>     over the data channel (e.g. in an HTTPS header), it must validate it
>     by retrieving the full certificate chain from the client via the
>     control channel.
>  1) child process maintains its own key-pinning storage.  To make this
>     work, you'd need to have the parent process send the control channel
>     pinning information when it learns it from the data stream.  This
>     requires stored state on the part of the child process, but we
>     probably need stored state anyway for TLS session resumption.
> The advantage of (1) is that the pinning database is now automatically
> shared across all users of tlsify, so a pin learned by parent process A
> will be respected by parent process B.

It's not clear to me whether this last property is desirable. In
general every piece of shared/global state is a liability to the
reliability and security of a system. There is also an option for some
middle ground where the caller would request a particular
pinning-store that could be shared or private.

> Client-side certs
> -----------------
> The initialization/configuration is going to need to include not only
> the client side cert offered, but also the secret key material.  It's
> also possible that we want to be able to handle this via the control
> channel: when the server sends a CertificateRequest message, it includes
> a hint about what kinds of certificates are acceptable, and which
> certificate authorities are acceptable:
> For clients that have zero or one secret key+certificate available to
> offer, the initialization/configuration mechanism you've proposed is the
> simplest possible approach.  but for clients that may have multiple
> secret keys+certs to decide between, the control channel mechanism may
> be necessary.  (maybe this is an advanced feature not implemented in
> version 0?)

Yes, I'm not sure. One thing I wanted to do in the session on
Thursday, which we didn't get to, was go over a number of example
applications and what their needs would be, to start assessing what
features are the most important to support early and make easy-to-use.

> session resumption
> ------------------
> We may need to think through the logic about session resumption and what
> security/privacy risks it presents to users.  TLS sessions are nominally
> used for simple acceleration, but they do imply replayed state of the
> TLS session.  So, for example, if tlsify parent process A uses client
> cert X to connect to server S, and the tlsify child stores session
> resumption info T (a ticket or a session id), then when tlsify parent
> process B makes a connection to server S, T should only be reused if
> process B also offers client cert X.
> session resumption also presents a privacy risk because resumed sessions
> are passed in the handshake in the clear, visible to anyone observing
> the network.  This means that individual TLS connections can be linked
> to one another by a network monitor, even when the IP addresses of the
> involved peers change.  Perhaps part of initialization/configuration is
> indicating whether the tlsify parent is willing to resume a session if
> the child knows about an appropriate one (potentially getting faster
> connection setup), or whether it's willing to accept the delay a
> standard handshake to avoid linkability. 
> Aside from surveillance by network operators, resumed sessions are also
> potentially cookie-like mechanisms that the server can use to track the
> client itself.  Some clients may be fine having this happen (e.g. an
> HTTP client that is already sending cookies), but other clients may
> prefer to remain unlinked to their previous traffic.
> Another risk session resumption presents is storage: if the session
> ticket/id db is written to non-volatile storage, and a session is
> resumed from the ticket, it's possible that forensic analysis of the
> disk could permit decryption of the network traffic.
> TLS 1.3 will probably change the session-resumption arrangement in
> subtle ways i can go into if you like, but i think a simple "session
> resumption OK or not" flag should be sufficient for
> initialization/configuration at the moment. (1.3 will permit a client
> using session resumption to accept linkability by the server while
> avoiding linkability by network-based surveillance, so it's possible
> that the flag would become a tri-state once that mechanism is in place).

Do you think it's prohibitive (from a usability standpoint or
otherwise) to just have the caller be responsible for getting the
session token and passing it in when making new sessions if it wants
to use session resuming? I suppose it's a matter of whether the caller
mishandling the token is a greater or lesser risk than the tlsify
implementation mishandling it. Whichever approach we take, simply not
using session resuming by default is probably the safest, most correct
approach. (And with keepalive connections, I'm skeptical that resuming
even has much value for https.)

> multiplexing
> ------------
> fork/exec is an expensive step, esp. for complex code that needs to load
> dynamic libraries/etc.
> What if a tlsify parent process could ask an existing tlsify child
> process (via the control channel, i guess) to "tlsify" another file
> descriptor?  Many OSes have fd-passing capabilities across sockets these
> days.  it seems like the tlsify child process in this case would be able
> to handle multiple sockets in its select loop without a problem, and you
> could avoid the fork/exec overhead for all connections but the first.
> The simple one-fork-per-connection arrangement would still work for
> tlsify parents that prefer simplicity (don't want to deal with a
> control channel) and are willing to accept the performance hit.

This is a large part of why I want the "phase 2" to take place: fixing
the internal TLS implementation not to have so much ridiculous runtime
overhead. Using static const tables mapped from the executable file on
disk rather than dynamically initializing tables used for crypto can
theoretically get the size of the process down to a few pages. The
base time for posix_spawn is roughly 250-500 us even on slower
systems, which is negligible in comparison to TLS connection setup if
I'm not mistaken. So while I think there's possibly some value to
using a shared process, I question whether it's worth the complexity;
efforts might be better spent just making the process-per-connection
more efficient, at least early on.

> If we were able to do this, we'd need to be able to map the
> initialization/configuration options to something that could be sent
> over the control channel as well, right?

Yes, that would be needed.

> having this multiplexed arrangment also makes it possible for the tlsify
> child to have a session-resumption database that stays in RAM (though it
> would go away when the tlsify process terminates).  it does raise a
> question of when the tlsify process should shut itself down, though,
> since it is no longer responsible for only a single connection.  Maybe
> it could shut itself down when the control channel is closed?

Yes, that would be reasonable behavior I think.

> More radically, with this arrangement it's conceivable that you could
> have a single tlsify process that runs in the background and performs
> this work for a number of clients.  this offers a nice, easy way to do
> privsep (no process needs to drop privileges, they just need to be able
> to talk to the tlsify peer process's control socket).  Maybe that's too
> fancy?

This has been considered before, with no definitive conclusion

> control channel formats
> -----------------------
> this seems like the big question: how can we structure this in a
> friendly/simple way without needing to pull in json libraries or
> other scary/dangerous/complex parsers.  My big fear is that there will
> be control channel data that is large and possibly complex.
> examples of large data: full certificate chains -- these can be quite
> long.  i don't think there is a functional limit on their length,
> actually, and the size of any one certificate can be huge.  Similarly
> large are the hints provided by servers during CertificateRequest
> messages.
> examples of complex data: session initialization/configuration is
> starting to sound possibly complex, though if it's just command-line
> arguments, we should be able to get away with line-at-a-time reads
> (maybe with embedded NULs between args so that the same command-line
> parser can be used?).  what do you think is the most complex part you've
> seen?

Embedded NULs aren't possible; arguments to exec are C strings. Of
course it's possible to have multiple arguments. But since the command
line is usually public (via ps, etc.) any potentially-private input
needs to be via the environment or an active control-channel.

I'm really not sure what the most complex part is. I think we need to
get some examples going with a complete inventory of inputs that would
need to be passed.

Powered by blists - more mailing lists

Your e-mail address:

Powered by Openwall GNU/*/Linux - Powered by OpenVZ