Subject: [TLS] Need for S->C signaling

From: Stefan Santesson <[email-masked]>
Date: Thu, 19 Nov 2009 09:45:41 +0100

Just a question to make sure we have accurately exhausted this aspect.

Is it really necessary for the Server to signal that is is patched other
than using a modified finished calculation if it is patched/upgraded.

One scenario could be:

1) Client use the magic cipher suite to signal that it is patched/upgraded.
2) Client sends a normal finished message.
3a) Un-patched server replies with normal finished message.
3b) Patched server replies with upgraded finished message.

This way the client could determine whether the server is patched or not and
act accordingly and get the security context of renegotiate from the patched
server.

There are probably reasons why this is not a good idea. I¹m just not really
sure what they are.

/Stefan

---

From: Yoav Nir <[email-masked]>
Date: Thu, 19 Nov 2009 14:12:41 +0200

On Nov 19, 2009, at 10:45 AM, Stefan Santesson wrote:

Is it really necessary for the Server to signal that is is patched other than using a modified finished calculation if it is patched/upgraded.

One scenario could be:

This way the client could determine whether the server is patched or not and act accordingly and get the security context of renegotiate from the patched server.

There are probably reasons why this is not a good idea. I’m just not really sure what they are.

That only works if you change even the initial Finished message (which I'm all for, btw)

Not a "good" reason, but vulnerability scanners want to fingerprint which servers are patched and which are not patched.

Signaling in ServerHello allows them to do it immediately, while having to determine this by the Finished message is harder.

A slightly better reason is that the logic the client has to implement is slightly more complex, and you lose one bit of security (two right answers). This is not too bad IMO

Anyway, I like this proposal just fine.

---

From: Nasko Oskov <[email-masked]>
Date: Thu, 19 Nov 2009 15:32:03 +0000

Stefan Santesson wrote:
>Is it really necessary for the Server to signal that is is patched other than 
>using a modified finished calculation if it is patched/upgraded.

Yes. If you use the finished message, the attack is still possible.

>This way the client could determine whether the server is patched or not
>and act accordingly and get the security context of renegotiate from the
>patched server.

Once the server replies with the Finished message, it would move to
connected state and the HTTP stack is clear to execute the MiTM request. As
part of developing proof of concept for our own testing, I've observed that
connecting to IIS server will send the server CCS, Finished, App data.
Even if the client were to drop the connection, the request has been
executed and attack is carried out.

>There are probably reasons why this is not a good idea. I'm just not really
>sure what they are.

---

From: Stefan Santesson <[email-masked]>
Date: Thu, 19 Nov 2009 22:09:10 +0100

Thanks Nasko,

This is indeed a good reason.

/Stefan

On 09-11-19 4:32 PM, "Nasko Oskov" <[email-masked]> wrote:

> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls

---

From: Yoav Nir <[email-masked]>
Date: Thu, 19 Nov 2009 23:42:22 +0200

> executed and attack is carried out.

I don't quite see why the attack still works.

MITM does the handshake and forwards a partial request to the server. After that, the MITM forwards the client's ClientHello. That ClientHello contains the magic cipher suite.

The server sends the ServerHello, certificate, serverKeyExchange.

The client thinks this is an initial handshake, so it sends a "normal" Finished message.
The server, however, thinks this is a re-negotiation, so it expects the modified Finished message (the normal finished is only for the initial handshake)
So the server never replies with any CCS and Finished message. 

But even if the server did send the CCS and Finished message, the Finished message does not check out, so the client does not complete the request. So where's the damage.

The other attack is where the server initiates the re-negotiation with a HelloRequest. In that case, again, the client's Finished message doesn't check out, because it's calculated as an initial handshake Finished. So the server does not execute the request.

So how does the attack still work?

Yoav

---

From: Michael D'Errico <[email-masked]>
Date: Thu, 19 Nov 2009 13:59:08 -0800

If the server is NOT patched, the attack works.  The client would be
unable to distinguish patched servers from unpatched servers if there
is not a ServerHello signal sent.  The client needs this signal to
know if it can continue all the way to Finished safely.

Earlier I had proposed a signal-less scheme with a modified Finished
even for initial handshakes, but the signaling is not difficult and
reduces complexity quite a bit.

Mike

---

From: Marsh Ray <[email-masked]>
Date: Thu, 19 Nov 2009 16:29:44 -0600

Yoav Nir wrote:
> 
> But even if the server did send the CCS and Finished message, the
> Finished message does not check out,
> so the client does not complete the request. So where's the damage.
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
http://tools.ietf.org/html/rfc4346
    Client                                               Server

      ClientHello                  -------->
                                                      ServerHello
                                                     Certificate*
                                               ServerKeyExchange*
                                              CertificateRequest*
                                   <--------      ServerHelloDone
      Certificate*
      ClientKeyExchange
      CertificateVerify*
      [ChangeCipherSpec]
      Finished                     -------->
                                               [ChangeCipherSpec]
                                   <--------             Finished
      Application Data             <------->     Application Data

             Fig. 1. Message flow for a full handshake

The client has to send his Finished message before he sees the server's.

The server executes the request when he receives Finished from the
client. There is nothing later he can wait for, really.

MitM can drop the server's Finished message before the client gets a
chance to verify it.

- Marsh

---

From: Dr Stephen Henson <[email-masked]>
Date: Fri, 20 Nov 2009 18:48:20 +0000

Just had a crazy idea for S->C signaling:

ServerHello contains the MAGIC value in the CipherSuite indicator: we know this
can never happen by accident. The real ciphersuite indicator is placed
elsewhere, e.g. part of session ID. Session ID definition slightly modified to
permit 34 bytes instead of 32.

Steve.
-- 
Dr Stephen N. Henson.
Core developer of the   OpenSSL project: http://www.openssl.org/
Freelance consultant see: http://www.drh-consultancy.co.uk/
Email: [email-masked], PGP key: via homepage.

---

From: Martin Rex <[email-masked]>
Date: Fri, 20 Nov 2009 19:53:15 +0100 (MET)

Dr Stephen Henson wrote:
> ServerHello contains the MAGIC value in the CipherSuite indicator:
> we know this can never happen by accident. The real ciphersuite
> indicator is placed elsewhere, e.g. part of session ID.
> Session ID definition slightly modified to permit 34 bytes
> instead of 32.

Signaling through ciphersuite ID in ServerHello should work.
Middle Boxes may still be confused.

But I would definitely _NOT_ touch the session ID, in particular
not make it longer.

Since the signaling through ciphersuite ID is non-ambiguous,
we could just re-purpose a part of Server.Random.

-Martin

---

From: Marsh Ray <[email-masked]>
Date: Fri, 20 Nov 2009 13:00:04 -0600

> permit 34 bytes instead of 32.

I like it.

For reference: http://tools.ietf.org/html/rfc2246
> struct {
>         ProtocolVersion server_version;
>         Random random;
>         SessionID session_id;
>         CipherSuite cipher_suite;
>         CompressionMethod compression_method;
> } ServerHello;

Is changing SessionID from
>   opaque SessionID<0..32>;

to 34 bytes any less-breaking of a change than simply changing the
length of the ServerHello to make it a proper field? Maybe, I dunno.

What if the magic cipher_suite value signals that the acutal
cipher_suite value is stored in the top two bytes of random?

If anything actually cares about the GMT, he can fill those in with his own.

- Marsh

---

From: Martin Rex <[email-masked]>
Date: Fri, 20 Nov 2009 20:21:41 +0100 (MET)

Actually we could use your idea for a more symmetric signaling!

Stephen, I REALLY like this idea!

Since there are people that didn't like the gmt_unix_time
in Random anyway, we could just re-purpose it entirely.

Add a single magic ciphersuite as first(!) in ClientHello.cipher_suites
and then the field "ClientRandom.gmt_unix_time" must be interpreted

  ClientHello.Random =
    {
      uint16   field_of_flags
      uint16   reserved
      opaque   random_bytes[28]
    }

  And when the server sees that magic cipher suite and implements
  this protocol extension, then it will return the magic cipher suite
  as negotiated ServerHello.cipher_suite and then the definition
  of the ServerHello.Random will be this:

  ServerHello.Random =
   {
     uint16       field_of_flags
     CipherSuite  cipher_suite      /* real negotiated cipher_suite */
     opaque       random_bytes[28]
   }
   
Those implementors who want to keep a gmt_unix_time in their Random
to provide uniqueness, will need to put it somewhere into random_bytes,
like in the first 4 octets of that element.

This would give us 16 free bits for bi-directional signaling in
ClientHello and ServerHello at the cost of 2 Bytes in ClientHello.

The fun part: these bit-flags are not only protected by the
handshake message hash, they actually go into the PRF for
the session keys.  Some kind of extra protection.  :)

-Martin

PS: the session ID is used by servers to manage their cache
    and may also be used by server-side load-balancers.
    the session ID is only "random"-equivalent for the client

---

From: Michael D'Errico <[email-masked]>
Date: Fri, 20 Nov 2009 12:11:25 -0800

I agree that something along these lines might be an improvement.
I found it difficult to explain how the upper bit of version is
set, but is not really a version change.

But messing with gmt_unix_time might cause trouble since it's
possible that _something_ out there might rely on it (for what
I have no idea).  So since the bottom few bytes of the random
have no restriction whatsoever, putting the actual cipher suite
there would not break anything.

I'm not convinced that we need a field of flags, though, since
we have TLS extensions.  We should point out in our spec. that
this solution is a HUGE compromise in the quest for backward
compatibility, and that future fixes MAY require extensions.
"You've been warned", etc.

Mike

---

From: Martin Rex <[email-masked]>
Date: Fri, 20 Nov 2009 21:16:12 +0100 (MET)

> "You've been warned", etc.
 
You're correct.  gmt_unix_time was first in that position,
--it should not have to move.

The following should work just as well along with the
magic ciphersuite that indicates this protocol change.

ClientHello.Random =
  {
     uint32        gmt_unix_time;
     uint16        new_protocol_flag_bits;
     uint16        reserved;
     opaque        random_bytes[24];
  }

ServerHello.Random =
  {
     uint32        gmt_unix_time;
     uint16        new_protocol_flag_bits;
     CipherSuite   cipher_suite;
     opaque        random_bytes[24];
  }

-Martin

---

From: Yoav Nir <[email-masked]>
Date: Fri, 20 Nov 2009 22:17:46 +0200

On Nov 20, 2009, at 10:11 PM, Michael D'Errico wrote:

> I have no idea).

How about: If the client has its clock set way into the future, you don't want to send it a certificate that is already expired.
That works even better the other way. If the client does have its clock set to the past, you can send it an expired certificate.
Peter Gutmann says that many implementations randomize this value for exactly that reason.
That is an important data point, because since such implementations are out there (and presumably working), it's safe to assume that we CAN mess with this field.

>  So since the bottom few bytes of the random

---

From: Yoav Nir <[email-masked]>
Date: Fri, 20 Nov 2009 22:21:58 +0200

OK. So this is the case where the MitM has already sent the entire request, and the server decided it wants client authentication, and there is no session cookie that needs to be sent.

Although for nearly all HTTPS cases this won't work, I guess it could happen.
 
On Nov 20, 2009, at 12:29 AM, Marsh Ray wrote:

> Scanned by Check Point Total Security Gateway.

---

From: Martin Rex <[email-masked]>
Date: Fri, 20 Nov 2009 22:54:39 +0100 (MET)

I was just on the phone with Nasko Oskov and he came up with another
very interesting idea about how to get the verify data into the
handshake message hash of the renegotiation.  I like that idea
even better than mine!  So combined with Steve's idea to
signal S->C through ServerHello.cipher_suite, this is the result:

And this will fit into the SSL Version 2 ClientHello
(which is still permitted by RFC-5246 Appendix E !).
TLS/SSL ClientHello.Random  maps to  V2 ClientHello.challenge,
they're both 32-bytes

So the entire new scheme looks like this:

We put the first 12 bytes of the verify_data of the finished
messages into the Hello.Random of renegotiation handshakes.
This will obviate the need to hash them manually, they will
go into the handshake message hash through the respective
Randoms.

A new (single) magic ciphersuite ID, where the client requests
to talk the updated protocol.  This must be first in the
ClientHello.cipher_suites.

ClientHello.Random

   original               new, initial HS        new, renegotiation HS
{
 uint32 gmt_unix_time   uint32 gmt_unix_time   uint32 gmt_unix_time  
 opaque random[32]      uint16 new_flags       uint16 new_flags
                        uint16 reserved        uint16 reserved
                        opaque random[12]      opaque random[12]
                        opaque random[12]      opaque cli.verify_data[12]
}
   = 32 bytes             = 32 bytes             = 32 bytes

When an updated server sees the new magic ciphersuite ID, then it
writes the magic cipher suite ID into ServerHello.cipher_suite
in order to confirm to the client the use of the changed protocol
and writes the real negotiated cipher suite ID into the new definition
of the ServerHello.Random:

ServerHello.Random

   original               new, initial HS         new, renegotiation HS

 uint32 gmt_unix_time   uint32 gmt_unix_time   uint32 gmt_unix_time  
 opaque random[32]      uint16 new_flags       uint16 new_flags
                        uint16 cipher_suite    uint16 cipher_suite
                        opaque random[12]      opaque random[12]
                        opaque random[12]      opaque srv.verify_data[12]
}
   = 32 bytes             = 32 bytes             = 32 bytes

For those wondering whether it is a good idea or safeto actually
cut into the Hello.Random that much?

I'm not a cryptographer, but I think it is safe.

The 2x 16 bit that I'm cutting with flags and relocated ciphersuite
is admittedly a loss in randomness.  But it should be bearable.

What about the 12 bytes for the verify_data in the renegotiation
handshake?  That should actually _not_ have an impact!

What are the necessary properties for Random, which serves as
a challenge for both communication peers.

   - unique ?           yes
   - non-predictable ?  yes
   - secret ?           no, it is sent in the clear

For the authentication of the previous session in the renegotiation
handshake, we actually assume for the verify_data of the finished
messages the following attributes:

  - unique
  - non-predictable

Of course, we should run this by cryptographers, but to me, it
does _not_ fundamentally flawed, but OK.

And what do I need that 16 bits of flags for?

Well, I think they do come in handy to grow a little fruit.
Those of the low hanging kind.  :)

Possible uses of that Bitfield:

#define TLS_FLAG_SECURE_RENGOTIATE           (1u<< 0)
#define TLS_FLAG_RENEGOTIATE_SAME_IDENTITY   (1u<< 1)
#define TLS_FLAG_INITIAL_HANDSHAKE           (1u<< 2)
#define TLS_FLAG_WILL_NOT_RENEGOTIATE        (1u<< 3)
#define TLS_FLAG_HAVE_NO_CERT                (1u<< 4)

-Martin

---

From: Martin Rex <[email-masked]>
Date: Fri, 20 Nov 2009 23:01:14 +0100 (MET)

What I forgot about the verify_data in the Hello.Randoms:

We only carry the initial 12 bytes -- which is the standard size
for TLSv1.0 and TLSv1.1 and the default size for TLSv1.2.

For SSLv3, where the Finished message is actually a concatenation
of two HMAs md5 and sha1 (I believe it is an HMAC-like thingy) we
would carry the first 12 bytes of the sha-1 HMAC as verify_data.

-Martin

---

From: Michael D'Errico <[email-masked]>
Date: Fri, 20 Nov 2009 14:06:49 -0800

It might be possible to truncate the verify_data to something less
than all 12 bytes, similar to how we have the option to truncate
the HMAC.  Plus for SSLv3, the verify_data is 36 bytes!  Also maybe
only one byte of flags instead of 2.

Mike

---

From: Stefan Santesson <[email-masked]>
Date: Fri, 20 Nov 2009 23:45:05 +0100

Martin,

The repurposing of basic protocol elements smells too much like an ugly hack
to me. It give me all kinds of bad vibes.

I liked the old proposal better.

/Stefan

---

From: Wan-Teh Chang <[email-masked]>
Date: Fri, 20 Nov 2009 17:07:50 -0800

Martin,

I agree.  I like your old proposal better (adding a magic cipher suite
in client hello,
turning on a bit in server_version in server hello).

Wan-Teh Chang

---

From: Martin Rex <[email-masked]>
Date: Sat, 21 Nov 2009 02:08:57 +0100 (MET)

Stefan,

Stefan Santesson wrote:
> 
> The repurposing of basic protocol elements smells too much like
> an ugly hack to me. It give me all kinds of bad vibes.
> 

Thanks for the feedback.  When I just started to describe the architecture
of storing the verify_data of the previous Finished message in the
Hello.Random, I realized that interop-testing this would not provide
any proof that an implementation was no longer vulnerable,
i.e. it's a fail UNsafe design just like TLS extension RI.

So I'm going to complete the I-D with the last design, based
on "manually" adding the verify_data to the handshake hashes
and S->C signaling through server_version.

-Martin

PS: I still like Steve's idea, though.  It would be fairly symmetric
in signaling: the Client offers a magic cipher suite for a modified
protocol first in his list of cipher_suites and the server agrees
to use it and sends it back in ServerHello.cipher_suite.

With the same symmetry, 32-bit of Hello.Random are re-purposed.
The negotiation through the ciphersuite would make this re-purposing
of the Hello.Random bits non-ambiguous and one could add
16 bidirectional signaling bits of extensibility for use by TLS WG.

If the information that you want to negotiate with your peer amounts
to essentially one bit, then a TLS extension is a pretty big
wrapping.  What would you say if your super-market would 
sell 1 quart of milk only in a box of lead that weighs 80lbs ?

---

From: Martin Rex <[email-masked]>
Date: Wed, 25 Nov 2009 03:07:05 +0100 (MET)

> But I would definitely _NOT_ touch the session ID, in particular

Although I do not like the abuse the ciphersuite ID for S->C,
that doesn't mean that I could not be convinced to use it.

Reasons why I do not like it:

 - currently at least some servers assign the session ID
   consciously, to help them in their session cache management,
   maybe even loadbalancing, or just to make it collision-safe.
   I wouldn't like to force them to repartition the 32-bytes

 - AFAIK there are loadbalancers out there (NAT-type) that
   can use the SSL session ID to balance (without opening/terminating SSL
   in a reverse-proxy fashion.  They might have a problem when
   the session ID returned from the server is > 32 bytes and does
   not match the session ID that the client sends in the ClientHello
   of parallel connection.

-Martin

---

From: Marsh Ray <[email-masked]>
Date: Tue, 24 Nov 2009 20:14:18 -0600

Martin Rex wrote:
>    consciously

Yes, that could force a major application change so it's off the table.

> They might have a problem when the session ID returned from
> the server is > 32 bytes and does

If we're going to increase the max size of the Server Hello structure,
we might as well define a new field. Or just use an extension.

Seriously, is it that big a deal to use an extension in the SERVER
Hello, if it's use was negotiated in the Client Hello?

- Marsh