Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20200323115451.GF466633@wirbelwind.zhasha.com>
Date: Mon, 23 Mar 2020 12:54:52 +0100
From: Joakim Sindholt <opensource@...sha.com>
To: tlsify@...ts.openwall.com
Subject: Interface design considerations

Yesterday we (Rich and I) had a discussion about the public interface of
tlsify, taking the first step towards a working, deployable product.
Rich suggested taking it to the list and I agree, so here are the notes:

Foreword:

Priority 1 should be designing a solid API that will allow new, as well
as existing software to adopt tlsify instead of linking in a library.

As a note to this I, if there are no objections, will be working on an
actual implementation of what's being discussed as I fear we will
otherwise devolve into one of those "we just publish a spec so other
people can implement it" groups.

I also believe we must eventually publish a high quality implementation
or the project will not be taken seriously as it is a significant
departure from what's normally considered high performance.


(1) Known protocol-specific requirements

My own needs are mostly JSON over HTTPS based and as such come with
relatively well-known requirements:
* Transparent handshake and encryption.
* The ability to specify a CA certificate or a set of CA certificates
  for services with their own PKI.
* The ability to specify a client certificate static to the host
  connected to.

Rich has recently worked on encrypted email transport, leading into DANE
and would also like tlsify to:
* Use DANE transparently.

DANE could either be implemented as a function of existing
infrastructure on the host system or done entirely within tlsify.
The former is nice both from a size perspective but also seems
architecturally more sound.
The latter might be necessary as the infrastructure is rarely present on
systems and require some pretty invasive changes if not; that
complicates testing (and adoption!)

DANE has 4 modes (this will be useful later):
0/PKIX-TA
    Specify an existing CA certificate that the presented certificate
    must validate through.
1/PKIX-EE
    Specify a certificate that must match the presented one perfectly in
    addition to validating through an existing CA.
2/DANE-TA
    Specify a certificate which the presented one must validate through
    without the requirement of it also validating to an existing CA.
3/DANE-EE
    Specify a self signed certificate that must match the presented one
    exactly.

There are protocol specific requirements for how the validation is done.
For example: HTTP requires that in all cases the CN of the presented
certificate matches the domain name that was connected to while SMTP
doesn't require a CN match for DANE-EE specifically.

It should do every validation pass under the sun by default. The API
should be that you may turn some checks off explicitly.

The CN will still be needed for SNI, so just not specifying it isn't an
option. Furthermore you might want to specify a CN for validation but
NOT use SNI.

It's probably unnecessary to have a back-and-forth with the host
process. We discussed basing the validation API on DANE, so perhaps an
option that allows you to specify for what cases of DANE the CN matching
should be turned off, eg. -x DANE-EE and -x * for turning it off
altogether.


(2) Using a different set of CAs than the system trust store

Useful in cases where you have your own PKI. I have multiple cases of
service providers using their own CA certificates that are not and
should not be part of the system-wide trust store.

My suggestion was to allow an option, say -C /path/to/ca, that specified
a directory of or a single file containing CA certificates to validate
against.
Rich suggested modeling the API on DANE, where the options are based on
DANE types, eg. -C DANE-TA /path/to/ca.crt, with the ability to specify
multiple just like real DANE logically ||'ing them.

FWIW I like Rich's idea much better than my own. Rich is concerned that
it's not sufficiently general but also notes that it constitutes a good
default model. I agree.


(3) Option format

We both agree that tlsify should take arguments in the traditional
getopt style with single character options.

I suggested that the basic format ought to be:
tlsify <ifd[,ofd]> <cn>
tlsify 3,4 host.tld
tlsify 7 host.tls
where you can specify either a pair of pipes or a single socket that
will be used for TLS communication, with cleartext being received and
sent over fds 0 and 1 respectively.

Rich suggested a more cautious approach where all options are provided
as getopt options, eg:
tlsify [-f ifd[,ofd]] [-n cn]
This has the benefit of not locking tlsify into any specific usage
pattern.

I believe that the fd or fd pair is so fundamental to tlsify that it
shouldn't require an option. The only reason for leaving it out appears
to be to let tlsify establish the connection itself.
The CN should probably be an option. It's uncertain as to whether
leaving out the CN should turn off CN validation, as it might just be
accidentally left out during development and never produce an issue
aside from possibly severely compromising security. Turning off SNI
silently sounds fine to me.

We both tentatively agree that there's no point in allowing for
overriding the cleartext fds as it can seemingly at best save a dup2
call.


(4) Error channel

There needs to be a way of communicating the error back to the host
process. If nothing else then just to display it to the user.

I, in spite of disliking the idea, suggested that you could use exit
codes to tell the host what the issue was.

Rich suggested that what you really want is a detailed error
description, eg.:
"server presented a certificate for musl.libc.org not for ewontfix.com"

As a proponent of error strings I don't have a problem with an approach
that just sends literal strings over an optional fd back to the host to
read but it's uncertain whether that's good enough. There's also the
issue of translating error strings which I'm personally happy to forego
but others might not be.


Some things that also warrant further discussion:
* Specifying a set of acceptable TLS versions, key exchange algorithms
  and ciphers.
* Having tlsify do the connecting for you.
    - I disagree with this. IMO it's unrelated to TLS and a
      feature-creep springboard for even more TLS-unrelated
      functionality.
* Specifying a client certificate.
    - Rich thinks "some degree of protocol is needed to make it
      meaningful."
* How to specify ALPN and how to communicate to the host process what
  was chosen.


What I propose so far:

tlsify [options] fd[,fd]

If only 1 fd is specified it's both the TLS input and output fd. If 2
are specified they're the TLS input and output fds respectively.

-n cn
    Specify a common name for use in validation and SNI.
-C dane-type path-to-file-or-dir
    Act as a DANE record of the specified type, with the data being
    pulled from the file or all files in the folder. This also
    deactivates the fetching of DANE records and the use of the default
    system trust store excepting dane-type=PKIX-*.
-x dane-type
    Turn off CN validation for a given DANE record type.
-x CN
    Turn off CN validation altogether.
-x SNI
    Turn off SNI.
and tentatively:
-c path-to-file
    Specify a client certificate.


And I think that covers all of it.

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.