To Home page

Protocol Negotiation

Once a protocol is in use, it becomes very hard to change. If one person updates the server, and the client is not updated, everything breaks.

And so, we are stuck with a lot of frozen protocols, many of which are in urgent need of change, but to change, requires wide consensus, which requires a big bunch of people showing up at a meeting, but at such meetings very little gets done, and what gets done is stupid.

If a standard is successful, more and more people want to be in the committee, many of whom represent business profit centers and government special interests, and who really do not understand much about the technology, except that any change might be adverse to the very important people who sent them there.

As the committee gets larger, it gets more unworkable, and as it represents more and more special interests, it gets more unworkable

In order to have to have a system where the internet’s protocols can be upgraded, and new protocols introduced, without central coordination, protocol negotiation, where client and server first discuss what protocol version they will be using, has to be part of every protocol, all the way down to the level of TCP and UDP.

These days everyone builds in protocol negotiation, often on top of SSL, which is on top of TCP, resulting in three additional round trips.

And then a widely distributed client or server breaks the protocol negotiation, which no one notices because it interorperates with all existing implementations, until someone tries to introduce a new protocol, whereupon the new code implementing the new protocol is blamed for its failure to interoperate with the existing clients and/or servers, and then we get another layer of protocol negotiation on top of all the existing layers of protocol negotiation.

TCP has built in protocol negotiation, eight bits worth, which turned out, unsurprisingly, to be inadequate.

For the content of the internet to be free from central control, we need to ensure that the address spaces and protocols are free from central control.

When an old protocol is broken, clients and servers that have not upgraded to a new improved protocol will remain forever, so the old defective protocol has to be supported forever – without, however, allowing an attacker a downgrade attack.

To prevent a downgrade attack, there has to be some way of disabling protocols in the field, where the signed ban on certain protocols flood fills from one program to the next.

Often, it is impossible to support the old clients, because protocol negotiation was never adequately designed in, or because it was designed in but was designed vulnerable to a downgrade attack.

But let us suppose the protocol negotiation was well designed:  The committee has to assign a code.  And of course, they will only assign this code to a protocol that they agree is right – and nothing gets done, for there is always some vested interest that for some strange and obscure reason does not want this protocol to exist.

One solution is to have quite large protocol identifiers, or arbitrarily large variable length protocol identifiers, so that anyone can whip up a protocol and assign it an identifier, and hack a client and server to use it, without having to walk it past three dozen members of the committee.

But then, of course, we would probably wind up with a lot of protocols.  This could potentially lead to a lot of protocol negotiation round trips

Do you speak protocol A? No.

Do you speak protocol B? No.

Do you speak protocol C? No.

Do you speak protocol D? No.

Do you speak protocol E? Yes.

One solution to this problem is to have complete lists of protocols, call it a protocol dictionary, which dictionary maps the long probabilistically globally unique protocol names to short deterministically unique local protocol names, and gives an order of preference.  If the client names a dictionary that it supports, and/or the server names a dictionary that it supports, then they can usually come to immediate agreement.

If, for example, the client wants to talk protocol X, it proposes one or more dictionaries of updates to protocol X, implying that it can talk all the updates listed in each dictionary, and an order of preference among dictionaries

If the server recognizes one or more of the dictionaries, it then responds with one of the protocols listed in the first dictionary that it recognizes, by its short dictionary name, and the conversation proceeds.

An ordered list of dictionaries is identified by a public key and a short human readable type name.  The typename is only unique with respect to the dictionaries signed by this public key, thus ftp version 1, ftp version 2, ftp version 4 ...

The globally unique identifier of a dictionary is the hash of the rule identifying its public key, plus its typename and version number.

If the server recognizes the hash of the rule identifying the dictionary public key, but not the version number, it responds with the highest version number that it does recognize, and the most favored protocol in that dictionary.  Thus if the client requests a protocol of dictionary version n, it has to know dictionaries versions 1 to n, and be able to deal with all protocols in versions 1 to n, if only to the extent that it is able to fail the protocol gracefully.

The one true ciphersuite

Why would you want multiple ciphers?

In case one turns out to be weak.

OK, suppose one turns out to be weak.  Oops, Malloc can now launch a downgrade attack.

So, if supporting multiple ciphers, you need a floodfill mechanism where you can disable the bad ciphersuite in the field.

Each program supporting a set of ciphersuits has a set of signatures it recognizes as authoritative.  If another program that it talks to has a revocation of ciphersuite, and it recognizes one of the signatures on the revocation, the revocation floodfills.

So, ideally you should support multiple ciphersuites – but if you do, have a mechanism for field revocation.

These documents are licensed under the Creative Commons Attribution-Share Alike 3.0 License