[HN Gopher] Why TLS is better without STARTTLS (2021)
       ___________________________________________________________________
        
       Why TLS is better without STARTTLS (2021)
        
       Author : Tomte
       Score  : 68 points
       Date   : 2023-02-10 06:41 UTC (16 hours ago)
        
 (HTM) web link (nostarttls.secvuln.info)
 (TXT) w3m dump (nostarttls.secvuln.info)
        
       | dlandau wrote:
       | "Meddler-in-the-middle", I hope this catches on.
        
       | markonen wrote:
       | I've been trying to shoehorn mTLS into existing infrastructure of
       | Postgres clients and servers. This would be trivial if Postgres
       | used straight-up TLS; as it is, though, you need sidecars that
       | understand the Postgres wire protocol and that limits your
       | choices to things like pgbouncer (which will add not-
       | insignificant overhead) or Envoy (where the Postgres wire
       | protocol support seems alpha quality or so).
        
         | philsnow wrote:
         | > This would be trivial if Postgres used straight-up TLS
         | 
         | ... does it not? (I really don't know, I've never had to admin
         | postgres myself)
         | 
         | from https://www.postgresql.org/docs/current/ssl-tcp.html#SSL-
         | SET...
         | 
         | > With SSL support compiled in, the PostgreSQL server can be
         | started with support for encrypted connections using TLS
         | protocols enabled by setting the parameter ssl to on in
         | postgresql.conf. The server will listen for both normal and SSL
         | connections on the same TCP port, and will negotiate with any
         | connecting client on whether to use SSL. _By default, this is
         | at the client 's option_
         | 
         | wait so.. if it uses the same port for TLS, does it use
         | STARTTLS?
         | 
         | from https://www.postgresql.org/docs/current/protocol-
         | flow.html#i...
         | 
         | > To initiate an SSL-encrypted connection, the frontend
         | initially sends an SSLRequest message rather than a
         | StartupMessage. The server then responds with a single byte
         | containing S or N, indicating that it is willing or unwilling
         | to perform SSL, respectively. The frontend might close the
         | connection at this point if it is dissatisfied with the
         | response. To continue after S, perform an SSL startup handshake
         | (not described here, part of the SSL specification) with the
         | server. If this is successful, continue with sending the usual
         | StartupMessage. In this case the StartupMessage and all
         | subsequent data will be SSL-encrypted. To continue after N,
         | send the usual StartupMessage and proceed without encryption.
         | 
         | and also from that section
         | 
         | > While the protocol itself does not provide a way for the
         | server to force SSL encryption, the administrator can configure
         | the server to reject unencrypted sessions as a byproduct of
         | authentication checking.
         | 
         | .... that is not great. I mean _zero_ disrespect to the
         | postgres dev team, but why do this? I know (m)TLS has issues,
         | but why would anybody want to have to trust /verify two
         | codebases (the postgres bits before the handoff to
         | openssl/boringssl/whatever) instead of just one (only
         | openssl/boringssl), just to bootstrap to a secure client-server
         | connection?
         | 
         | (this is my complaint about _all_ upgrade-to-TLS schemes)
        
           | tinus_hn wrote:
           | This is like DECT where they are all about the 'thousands of
           | security codes', but if the base station (or an imposter)
           | suddenly says 'I don't do encryption' the handset just stops
           | doing encryption.
        
         | gmac wrote:
         | The Postgres devs are discussing eliminating that speedbump,
         | and having an encrypted connection start with an ordinary TLS
         | Client Hello: https://www.postgresql.org/message-
         | id/flat/CAM-w4HOEAzxyY01Z...
        
       | rbut wrote:
       | We run an LDAP service attached to our SaaS application.
       | 
       | A couple of years ago we were alerted to the fact that iOS
       | devices no longer connected to our LDAPS server running on port
       | 636. macOS still seemed to connect fine..
       | 
       | After some digging, it seemed Apple updated iOS to only accept
       | connecting over STARTTLS on port 389. So we had to run a STARTTLS
       | server also to make iOS devices work.
       | 
       | At the time, it seemed STARTTLS over 389 was the "standard",
       | maybe that's why Apple changed it, but looking just now it seems
       | that is being challenged [1][2], and rightly so.
       | 
       | [1] https://unix.stackexchange.com/questions/607560/why-is-
       | ldap-...
       | 
       | [2] https://lists.openldap.org/hyperkitty/list/openldap-
       | technica...
        
       | billpg wrote:
       | I'm writing a POP3 service (http://billpg.com/POP3/) and I
       | stumbled upon this as a bit of a forehead-slapping moment.
       | 
       | Once I read about it, I tried attacking my own server by sending
       | in "STLS\r\nCAPA\r\n" in a single TCP package and it responded to
       | CAPA after the encrypted channel had been established because
       | those bytes were still in the buffer.
       | 
       | One hasty bugfix to clear the buffers after establishing TLS
       | later and I thought about how to exploit this bug. The only thing
       | you can do at this point is log in and an attacker isn't going to
       | know the user's credentials. (If they do, you don't need to
       | exploit the bug.)
       | 
       | Despite this, I wonder about what what if HTTP had a STARTTLS
       | command instead of using port 443 and handing over directly to
       | TLS. SNI (identifying the names host the client wishes to connect
       | to prior to certificate exchange) took years to get established,
       | mostly (I think) because it was inside the black-box of TLS. If
       | the certificate exchange happened with HTTP before handing over
       | to TLS, the request might have looked like:                   GET
       | /.well-known/tls-cert HTTP/1.1         Host: the-actual-hostname
       | Accept: certificate/format, et/c
       | 
       | When the hand-over to TLS (in this parallel universe) takes
       | place, the certificate exchange has already happened. TLS's job
       | is now to confirm the cert is valid (or not) and exchange session
       | keys.
        
         | tsimionescu wrote:
         | That needlessly ties the session layer (TLS) with the
         | application layer (HTTP). The much better solution is the one
         | taken by QUIC, moving encryption itself at the transport layer
         | (well, or it would be if QUIC itself weren't piggybacking on
         | UDP).
         | 
         | It's an unfortunate accident of history that encryption was
         | tied to some application protocols, and is not part of the
         | standard TCP/IP stack provided at the OS level entirely. This
         | same accident led to bad ideas like STARTTLS, unfortunately.
        
         | daneel_w wrote:
         | I never could understand why POP3 service providers don't just
         | insist on enforcing POP3S. We're no longer in the early 2000s.
         | 
         | https://github.com/stolendata/little-peepo/blob/master/littl...
        
           | lbriner wrote:
           | My understanding is that it is always historical. There are
           | still people out there who are "I built my own email tools"
           | or "this was setup in 1992 and still works" etc. These aren't
           | a tiny fringe group but asizeable number of sometimes very
           | influential people.
           | 
           | As soon as you make a serious breaking change, it brings out
           | all the complaints of "centralisation" of "being forced into
           | something" into "I don't need tls whatever you say" etc.
           | 
           | Google try these sorts of things occasionally but although in
           | most cases it is short-term pain for long-term gain, it
           | rarely goes that way.
        
             | daneel_w wrote:
             | The case of POP3 and STARTTLS vs POP3S is different,
             | because practically all POP3 providers these days _require_
             | encryption before the e-mail client is allowed to transact.
             | It 's the same encryption method/protocol and the same
             | requirement, it's just that POP3S goes straight for the TLS
             | handshake while STARTTLS (with the security concerns
             | detailed in the article) begins talking on an unencrypted
             | channel before getting on with the mandatory handshake.
        
         | hannob wrote:
         | How to exploit: For imap or smtp one can construct commands
         | that will lead to a mail with the login credentials being sent
         | to the attacker (assuming the attacker has an account on the
         | same server). For POP3 we were unable to come up with such an
         | attack, as it has no way of storing or sending mails.
        
           | billpg wrote:
           | Yep. While I did fix the bug as soon as I found it, I
           | consider myself fortunate I chose POP3 to write my first
           | server.
        
         | [deleted]
        
         | knome wrote:
         | >One hasty bugfix to clear the buffers after establishing TLS
         | 
         | Discarding bytes seems like the wrong thing to do as well. If
         | your starttls just takes the socket and no "initial bytes", as
         | I would expect, you would need to either read off the socket a
         | byte at a time til then or better to use MSG_PEEK to not read
         | past the next \r\n.
        
           | billpg wrote:
           | I thought about that but I didn't want to be stuffing bytes
           | back into the incoming stream and I didn't want to be reading
           | the stream byte-by-byte either unless I really had to. I had
           | a nice bit of code that read blocks of bytes and looked for
           | the CRLF separating lines - even handling the case where the
           | CR is one block and the LF is in the next one - and I didn't
           | want to dismantle that.
           | 
           | I read the relevant RFC and there was a clear exception to
           | the rules of PIPELINING that meant a conforming client
           | doesn't send the "ClientHello" until the server has responded
           | to the STLS command. I felt justified in clearing the buffer
           | at that point.
        
       | hannob wrote:
       | Hi, one of the authors here. Happy to answer any questions.
        
         | billpg wrote:
         | I'm writing (as a side project) a game with a client-server
         | system.
         | 
         | For the server, I'm using dot-net's SslStream (in TLS mode) and
         | it needs to know which TLS cert to use prior to handing over
         | control of the connection.
         | 
         | For this reason, I've designed the protocol for the client to
         | announce who they are and what they want as a single line of
         | JSON before letting SslStream negotiate TLS. Once the
         | connection is secured, the client repeats that first line of
         | JSON. If the server detects any difference between the two it
         | closes down the connection. (I also made sure to clear the
         | buffers after reading that first line of JSON.)
         | 
         | I don't like doing that but the only other way is to "roll my
         | own crypto" which I understand is a bad thing.
        
           | d-z-m wrote:
           | Sniffing the SNI from the underlying TCP connection is the
           | proper way to do this.
           | 
           | a couple examples I know of(only know go ones of the top of
           | my head):
           | 
           | https://github.com/fabiolb/fabio/blob/master/proxy/tcp/tls_c.
           | .. https://github.com/FiloSottile/mostly-
           | harmless/blob/main/tal...
           | 
           | > I don't like doing that but the only other way is to "roll
           | my own crypto" which I understand is a bad thing.
           | 
           | You would not be rolling your own cryptographic primitive, or
           | combining existing ones in strange and speculative ways. This
           | is what most people, most of the time mean when they admonish
           | against rolling your own crypto.
           | 
           | All you'd have to do is parse the ClientHello to retrieve the
           | SNI. you're in a memory safe language, so parsing bugs result
           | in a crash, not a buffer overflow. I'd say you're on pretty
           | firm ground.
        
           | hannob wrote:
           | > it needs to know which TLS cert to use prior to handing
           | over control of the connection
           | 
           | It is a bit unclear here what that means. I mean TLS has a
           | mechanism to choose the certificate based on the hostname
           | (SNI). Other than that - why would a different user get a
           | different certificate? After all the certificate's job is to
           | identify the server.
        
             | billpg wrote:
             | That's a flaw in dot-net's SslStream library. You don't get
             | an opportunity to know what host the client is expecting
             | before selecting the cert for this session. Reading
             | discussions around this issue usually settle on reading and
             | parsing the "ClientHello" to extract the SNI name, and then
             | hacking the ClientHello back into the incoming stream so
             | TLS code can read it.
        
               | hannob wrote:
               | According to this
               | https://github.com/dotnet/corefx/pull/28278 SNI support
               | has been added in 2018.
        
               | billpg wrote:
               | It is very possible my information is out of date or I
               | was using an older version of dot-net. Thank you!
        
       | ttul wrote:
       | The proper long term solution to this problem is DANE [2], but
       | since migrating everyone to DNSSEC will take a long time, Google
       | and a few others in the email ecosystem created MTA-STS, which is
       | far better than nothing [1].
       | 
       | All this being said, another idea (not standardized yet as far as
       | I know) would be to publish a new DNS record, MXS (for example),
       | that would imply the use of the SSL email port 465. I think it
       | would be a worthy standardization effort to go in this direction
       | and finally banish STARTTLS.
       | 
       | [1] https://dmarcian.com/mta-sts/ [2] https://www.rfc-
       | editor.org/rfc/rfc7671.html
        
         | tsimionescu wrote:
         | How would any of these fix vulnerabilities in the handling of
         | STARTTLS? And why is any of them required in place of just
         | using TLS as part of the initial connection, HTTPS style?
        
           | ttul wrote:
           | You can't fix STARTTLS unless receivers stop advertising it.
           | That will take until the end of time. Meanwhile, DANE can
           | assure that domains can assert their SSL certificate in the
           | DNS securely. And MTA-STS can allow DNS to do so, just
           | without the assurance of DNSSEC, which implies that
           | sophisticated man-in-the-middle attacks can still occur, if
           | DNS can be intercepted and modified.
        
       ___________________________________________________________________
       (page generated 2023-02-10 23:02 UTC)