[ech] ECH split mode API

Tomas Mraz tomas at openssl.org
Thu Aug 31 07:53:23 UTC 2023


On Wed, 2023-08-30 at 16:11 +0100, Stephen wrote:
> 
> Hiya,
> 
> On 30/08/2023 15:42, Tomas Mraz wrote:
> > Ah, OK. Then I think the best API would be modelled as a BIO filter
> > or
> > something similar - you write the raw data into it and read the
> > decrypted/modified messages out of it to be passed to the backend
> > application.
> 
> Can you think of an example on which I could model stuff?
> Ideally something that takes an SSL_CTX and a buffer/BIO
> and spits out another buffer/BIO I guess.

One option would be to have a BIO filter that you could push onto any
BIO that receives the data from the network. You would then use some
new BIO_CTRL to set the SSL_CTX on that bio.

Or, if a BIO filter is too limiting, you could just make it a regular
BIO where you would BIO_write() the messages and BIO_read() the
modified ones. Again you would use BIO_CTRL to set the SSL_CTX.

> 
> > There seems to be no point in requiring the application to extract
> > the
> > client hello and then mangle it back into new messages for the
> > backend.
> 
> Tend to agree.
> 
> Ta,
> S.
> 
> > 
> > But again, I did not study the problem in depth.
> > 
> > Tomas Mraz, OpenSSL
> > 
> > On Wed, 2023-08-30 at 15:33 +0100, Stephen Farrell wrote:
> > > 
> > > Hiya,
> > > 
> > > On 30/08/2023 15:27, Tomas Mraz wrote:
> > > > It is not clear to me why is this SSL_CTX_ech_raw_decrypt() API
> > > > call
> > > > needed at all? Why isn't all the processing done internally as
> > > > part
> > > > of
> > > > the SSL_connect()/SSL_accept()? There are existing message
> > > > callbacks
> > > > the applications can hook into to get the messages - so these
> > > > should be
> > > > extended if needed.
> > > 
> > > It's because the application isn't terminating the TLS
> > > session at all in this split-mode case, the (frontend)
> > > application is only doing ECH decryption and then the
> > > TLS session is established between the client and the
> > > backend application. For example, with haproxy as the
> > > frontend in what it calls "tcp mode" we hit this case.
> > > 
> > > When haproxy (or other servers) do terminate the TLS
> > > session, then yes it all happens internally and this
> > > API isn't needed. In haproxy terms, that's called
> > > "http mode".
> > > 
> > > Nginx has similar capabilities and probably other
> > > servers too.
> > > 
> > > Cheers,
> > > S.
> > > 
> > > > 
> > > > But I did not study the ECH RFC so there might be some obvious
> > > > reasons
> > > > why it is needed.
> > > > 
> > > > Tomas Mraz, OpenSSL
> > > > 
> > > > On Wed, 2023-08-30 at 15:17 +0100, Stephen Farrell wrote:
> > > > > 
> > > > > Hiya,
> > > > > 
> > > > > I'm wondering about changing the API I defined to allow
> > > > > applications to support ECH split-mode, mostly due to
> > > > > having now gotten that working for nginx and haproxy,
> > > > > with the recent work including support for handling the
> > > > > second ClientHello when one hits HRR, and properly
> > > > > handling early data when that's present.
> > > > > 
> > > > > The main off-the-wire input for the existing API is an
> > > > > encoded (outer) ClientHello (including the record layer
> > > > > header) as that's what's easily available when processing
> > > > > the first client hello. When ECH decryption works, we
> > > > > return the inner ClientHello, similarly encoded.
> > > > > 
> > > > > But it turns out that it may be better to accept a
> > > > > different input, for two reasons: the 2nd ClientHello
> > > > > when one hits HRR is preceded by 6 octets of (pretend)
> > > > > ChangeCipherSuite and secondly, if the first ClientHello
> > > > > is accompanied by early data, then the buffer that the
> > > > > application has may include that after the ClientHello.
> > > > > And in the application code, when not terminating TLS,
> > > > > those all tend to be present in one buffer (when the
> > > > > client sent 'em) as they likely arrived in one packet.
> > > > > 
> > > > > I had to write basically the same code in nginx and
> > > > > haproxy to handle the wrangling of the above and, if
> > > > > ECH decryption works, to re-constitute the right buffer
> > > > > containing as appropriate the CCS, inner ClientHello and
> > > > > early data.
> > > > > 
> > > > > So, I'm thinking of changing the API to accept as input
> > > > > a sequence of catenated encoded TLS messages, with the
> > > > > success case behaviour being to return a buffer that's
> > > > > the same but with the outer ClientHello being replaced
> > > > > by the inner. That should eliminate the need to peek
> > > > > into the TLS encoding so much in the application.
> > > > > 
> > > > > The current API is below, (or at [1]) and the change
> > > > > would be to go from ``outer_ch`` as an input to
> > > > > ``tls_msgs_buf`` or some such, likely with a check
> > > > > that the input contains an optional CCS, then a CH
> > > > > and may have additional octets we don't look into
> > > > > (the early_data).
> > > > > 
> > > > > Any thoughts or ideas about potential gotchas welcome.
> > > > > (I think I recall someone possibly holding their nose
> > > > > about this API when we spoke before, so other comments
> > > > > on this are also welcome since I'm likely to be making
> > > > > these changes soonish anyway:-)
> > > > > 
> > > > > Thanks,
> > > > > S.
> > > > > 
> > > > > [1]
> > > > > https://github.com/sftcd/openssl/blob/ECH-draft-13c/include/openssl/ech.h#L117
> > > > > 
> > > > > int SSL_CTX_ech_raw_decrypt(SSL_CTX *ctx,
> > > > >           int *decrypted_ok,
> > > > >           char **inner_sni, char **outer_sni,
> > > > >           unsigned char *outer_ch, size_t outer_len,
> > > > >           unsigned char *inner_ch, size_t *inner_len,
> > > > >           unsigned char **hrrtok, size_t *toklen);
> > > > 
> > 

-- 
Tomáš Mráz, OpenSSL



More information about the ech mailing list