Internet Protocols · Protocol Design

Retiring a Protocol Version Without a Flag Day

Why old versions persist after they are known to be weak, how deprecation is staged across senders and receivers, and what actually forces a deployment off a protocol.

A protocol version is retired when the cost of supporting it exceeds the cost of the attacks it enables. That sentence describes a decision, not a mechanism, and the gap between the two is where most deprecation efforts stall. The specification can declare a version obsolete; it cannot reach into the deployed base and remove it.

The record of retirement attempts is therefore a record of indirect methods. None of them removes a version directly. Each changes the incentives of the parties who still use it, and the version disappears when enough of them have changed.

The three populations that must move

A version is used by senders, by receivers, and by the devices in between. A retirement succeeds only when all three have moved, and they move on different schedules.

Senders move when their software is updated. A client library that still offers TLS 1.0 will do so until the library is updated or the application stops calling it. The update is usually cheap for the library author and expensive for the deployer, because the deployer has to test against the servers it talks to. The cost falls on whoever is furthest from the decision.

Receivers move when they can afford to reject. A server that stops accepting TLS 1.0 will break every client that only speaks it, and the server operator has to decide whether those clients matter. For a public site the answer is usually that they do not, because the clients are old browsers and bots. For an internal service the answer may be that they do, because the clients are embedded devices that cannot be updated.

Path devices do not move at all in any organised way. A middlebox that has been deployed and forgotten will continue to behave as it did, and its behaviour becomes a constraint on what the endpoints may send. A retirement that requires the path to change is not a retirement; it is a hope.

The asymmetry between the three is the central fact of deprecation. The endpoints can be updated by their operators. The path cannot be updated by anyone, because it is owned by parties who do not know they are part of the protocol’s deployment.

Announce, then measure, then reject

The sequence that works has three stages, and the order is not negotiable.

The first stage is announcement. The specification declares the version deprecated, the reason is stated, and a target date is named. RFC 8996 does this for TLS 1.0 and TLS 1.1, stating that they must not be used and giving the security reasons: weaknesses in the CBC construction, the availability of attacks on the record layer, and the absence of the protections that later versions added. The announcement is not a mechanism, but it is the precondition for everything else, because it gives every party a shared reference point.

The second stage is measurement. The operator of a receiver measures how much traffic still uses the old version, and the measurement has to be fine-grained enough to identify who is sending it. A server that sees one percent of connections on TLS 1.0 needs to know whether that one percent is a single large customer or a thousand small ones, because the remedy differs. Measurement is the stage that most deprecation efforts skip, and skipping it is why the eventual rejection surprises people.

The third stage is rejection. The receiver stops accepting the version, and the clients that still use it fail. The failure is the forcing function, and it only works if the announcement preceded it by long enough that the senders had a chance to move. The interval is measured in years for a widely deployed version, and the length is set by the slowest population, not the fastest.

The stages can overlap between populations. A receiver can reject while a sender still offers, as long as the sender has a fallback. The fallback is what makes the receiver’s rejection survivable, and its existence is the reason the receiver can move first.

Downgrade protection is the thing that makes rejection possible

A receiver that rejects an old version is exposed to an attack that a receiver which accepts everything is not: an attacker can strip the client’s offer of a new version and present only the old one, and the server will accept the old one because it cannot tell the difference between a client that only speaks old and a client whose offer was rewritten.

This is the same downgrade problem that version negotiation has in general, and the fix is the same: the negotiation must be authenticated. In TLS 1.3 the server’s selection is covered by the handshake transcript, so a rewritten ClientHello produces a Finished message that does not verify. In a protocol without a transcript, the receiver has no way to know, and the rejection of old versions creates a new attack surface rather than closing one.

The corollary is that a version cannot be retired safely unless the newer version has authenticated negotiation. That is a design constraint on the newer version, not on the retirement, and it means the retirement schedule is bounded below by the deployment of the replacement’s protections.

A protocol that lacks authenticated negotiation can still retire a version, but the retirement has to be paired with a policy that makes downgrade unattractive: short certificate lifetimes, HSTS-style preloading, or a requirement that the client pin the expected version. Each of those is an application-layer substitute for a transport-layer guarantee, and each has its own bypass.

The fallback that keeps the old version alive

Every fallback is a reason to keep the old version. A client that can fall back to TLS 1.0 will, when it encounters a server that only speaks TLS 1.0, and the fallback is correct behaviour from the client’s perspective. The problem is that the fallback also serves an attacker, who can force it by making the newer version fail.

The design tension is that the fallback is necessary for availability and harmful for security. The resolution used by TLS is to remove the fallback at the client: a client that supports only TLS 1.2 and above cannot be downgraded, because there is nothing to downgrade to. That is a policy decision made by the client’s operator, and it works because the client’s operator bears the availability cost.

The same logic applies to protocol versions generally. The party that removes the fallback is the party that accepts the availability risk, and the party that keeps it is the party that avoids the risk. A retirement that requires the receiver to remove the fallback shifts the risk to the receiver; a retirement that requires the sender to remove it shifts the risk to the sender. Neither is free, and the choice determines who complains.

What actually changes behaviour

The mechanisms that move a deployed base are few, and they are all about making the old version visibly costly.

The first is the error message. A server that rejects a connection with a specific alert, rather than a generic close, gives the client’s operator something to search for. TLS’s protocol_version alert is the example, and its specificity is what makes the failure diagnosable. A generic failure produces a support ticket that says “the site does not work”, which is much harder to act on.

The second is the metric. A server that publishes the fraction of traffic on the old version creates pressure on the clients, because the clients’ operators can see themselves in the number. Public dashboards of protocol version usage have moved deployments faster than specifications have, because they make the cost visible to the party that pays it.

The third is the contractual requirement. A compliance framework that names the minimum version turns a recommendation into a requirement, and requirements move organisations that recommendations do not. The mechanism is not technical, and it is the one that has historically been most effective for the long tail.

The fourth is the removal of the code. A library that deletes the old version’s implementation cannot be configured to use it, and the deletion is a hard boundary. The cost is that the library can no longer serve the clients that need the old version, which is the point.

Each of these is a way of making the old version’s cost fall on the party that can move. The technical design of the protocol contributes by making the failure specific and the measurement possible; the rest is deployment work that no specification can do.

What a retirement plan should contain

A plan that has a chance of succeeding names the version, states the reason, names a date, and describes the measurement that will be used to decide whether the date holds. It also names the fallback policy: whether clients may fall back, and to what.

The plan should distinguish the receiver’s date from the sender’s date. A receiver can reject earlier, because the sender has a fallback. A sender should stop offering earlier, because the receiver’s rejection is the forcing function and the sender’s offer is what makes the rejection necessary. The two dates are usually a year or more apart.

The plan should also account for the devices that cannot be updated. Embedded systems with a decade-long service life, industrial controllers, and network equipment are the population that makes retirement slow, and the plan should identify them rather than discovering them at the rejection date. The identification is a measurement task, and it is the same measurement that the second stage requires.

Finally, the plan should state what happens if the date slips. A retirement that is announced and then postponed loses credibility, and the next announcement is discounted. The postponement is sometimes correct, but it should be a decision with a new date rather than an indefinite extension.

The pattern that emerges is that retirement is a coordination problem with a technical component, and the technical component is small: authenticated negotiation, specific errors, and a way to measure. The coordination is the hard part, and it is the reason the protocols that have retired versions successfully are the ones whose operators treated the retirement as a project rather than as a specification change. The mechanisms that keep a protocol extensible enough to avoid needing a retirement are covered in registry allocation policy and in middlebox ossification; the mechanisms that make a retirement survivable are the ones described here.

References

  1. RFC 8996: Deprecating TLS 1.0 and TLS 1.1 — IETF
  2. RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3 — IETF
  3. RFC 9170: Long-Term Viability of Protocol Extension Mechanisms — IETF
  4. RFC 8200: Internet Protocol, Version 6 (IPv6) Specification — IETF
  5. RFC 1035: Domain Names - Implementation and Specification — IETF