Low Entropy

Expanding what HTTPS means

So you have a device, maybe IoT, or just something that sits in a home somewhere. You want to be able to talk to it with HTTPS.

Recall Zooko’s “meaningful, unique, decentralized” naming trichotomy. HTTPS chooses to drop “decentralized”, relying on DNS as central control.

In effect, HTTPS follows a pretty narrow definition. To offer a server that works, you need to offer a TLS endpoint that has a certificate that meets a pretty extensive set of requirements. To get that certificate, you need a name that is uniquely yours, according to the DNS[1].

Unique names

It is entirely possible to assign unique names to devices. There’s an awful lot of IoT thingamabobs out there, but there are far more names we could ever use. Allocation can even be somewhat decentralized by having manufacturers manage the assignment[2].

The problem with unique names for IoT devices is that they are probably not going to be memorable (thanks Zooko). I don’t know about you, but printer.<somehash>.service-provider-cloud.example isn’t exactly convenient. Still, this is a system that is proven to work in real deployments.

It we want to make this approach work, maybe it just needs adapting. Following this approach, the problems we’d be seeking to solve are approximately:

These problems all largely look like operational challenges. Any protocol engineering toward this end would be aimed at smoothing over the bumps. Many of the questions even seem to have fairly straightforward answers.

I don’t want to completely dismiss this approach as infeasible, but it seems clear that there are some pretty serious impediments. After all, nothing has really prevented someone from deploying systems this way. Many have tried. That few have succeeded[3] is perhaps evidence in support of it being too hard.

.onion names

Tor’s solution to this problem is making names self-authenticating. You take a public key (something for which no one else can produce a valid signature) and that becomes your identity. Your server name becomes a hash of that public key. Of course, “<somelongstring>.onion” as a name is definitely not user-friendly. You won’t want to be typing that name into an address bar[4].

That use of a name that is bound to a key recognizes that the identity of the service is bound to its name. In the world of DNS names, that binding is extrinsic and validated by a CA. In Tor, that binding is intrinsic: the name itself carries the binding.

Tor requires that endpoints follow different rules to the rest of the uniquely-named servers. Those rules include a particular protocol and deployment. Being, as they are, a bit onerous, only a few systems exist that are able to resolve “.onion” names. However, this approach does suggest that maybe there is an expansion to the definition of HTTPS that can be made to work.

.local with cryptographically bound names

The same concept as Tor could be taken to local names. Using “<somehash>.local” could be an option[5]. The idea being that the name is verified differently, but still unique.

A name that is cryptographically verified means that you could maybe drop some of the requirements you might otherwise apply to “normal” names.

The trick here is that you are asking clients to change a fair bit. Maybe less than Tor demands, but they still need to recognize the difference. Servers also need to understand that their name has changed.

The biggest problem with relying on unique names remains: these aren’t going to be easy to remember and type.

Nicknames

One approach for dealing with ugly names is to add nicknames. In a browser, you might have a bookmark labeled “printer”, which navigates to your printer at “<somehash>.local”. Or maybe you edit /etc/hosts to add a name alias.

Either way, usability depends on the creation of a mapping from the friendly name to the unfriendly one. From a security perspective, the mapping becomes a critical component.

The idea that you might receive this critical information from the network – for example, the DHCP Domain Search Option – is no good. We gave to assume that the network is hostile[6].

The real challenge here is that everyone will have their own nicknames, there can no canonical mapping. My printer and your printer are (probably) different devices, but we might want to use the same nickname.

TOFU and nicknames

Of course, in most of these cases, what you get from a system like this is effectively TOFU.

That is, you visit the server the first time and give it a friendly name. If that first visit was to the correct server, you can use the nickname securely thereafter. If not, and an attacker was present for your first visit, then you could be visiting them forever after.

This model works pretty well for SSH. It can also be hardened further if you care to do the extra work.

It’s a bit rough if the server key changes, which leads to some fair criticism. For use in the home, it might be good enough.

Non-unique names, unique identities

Recognizing that the practical effect of nicknames plus cryptographically-bound names, the logical next step is to just do away with the funny name entirely.

The reason we want the long and awkward label is twofold:

Those two things don’t need to be so tightly coupled.

Finding the thing works perfectly well without a ridiculous name. I would argue that mDNS works better for people if it uses names that make sense to them.

We could use the friendly name where it makes sense and an elaborate name – or identifier – everywhere that impersonation matters.

Managing impersonation risk

If there are potentially many printers that can use “printer.local”, how do we prevent each from impersonating any other? The basic answer is that each needs to be presented distinctly.

In the browser

On the web at least, this could be relatively simple. There are two concepts that are relevant to all interactions:

Neither of these rely on having flat names for servers, which makes extending them a real possibility. For instance, “https://printer.local” might be recognized as non-unique and therefore be assigned a tuple that includes the server public key, thereby ensuring that it is distinct from all other “https://printer.local” instances.

From there, many of the reasons for impersonation can be managed. Passkeys, cookies, and any other state that a browser associates with a given “https://printer.local” are only presented to that instance, not any other. That’s a big chunk of the impersonation risk handled.

Passwords and phishing remain a challenge[7]. Outside of the use of password manager, it won’t be hard to convince people to enter a password into the wrong instance. That might be something that can be managed with UX changes, but that’s unlikely to be perfect.

Elsewhere

Outside of the browser, there are a lot of systems that do not update in quite the same fashion as browsers. Their definition of server identity is likely to be less precise than the origin/site model browsers use.

For these, it might be easier to formulate a name that includes a cryptographic binding to the public key. That name could be used in place of the short, friendly name. There are reserved names that can be used for this purpose.

Working out how to separate out places where names need to be unique and where they can be user-friendly isn’t that straightforward. A starting point might be to use an ugly name everywhere, with substitution of nicer names being done surgically.

One place that might need to be tweaked first is the protocol interactions. A printer might easily handle being known as “printer.local”, but it might be less able to handle being known as “<somehash>.whatever.example”. That would keep the changes for servers to a minimum.

Key rotation and other problems

One reasonable criticism of this approach is that no mechanisms exist to support servers changing their keys.

That’s mostly OK. Key rotation will mean a new identity, which resets existing state. Losing state is likely tolerable for cookies and passkeys. the phishing risk of having to enter a password to restore state, on the other hand, is pretty bad.

That’s a genuine problem that would need work. Of course, if the alternative is no HTTPS, it might be a good trade.

Servers in these environments probably shouldn’t be rotating keys anyway. Things like expiration of certificates largely only serve to ensure that servers are equipped to deal with change. A server at a non-unique name doesn’t have to deal with its name disappearing or having to renew it periodically. Those that want to deal with all of that can get a real name.

Of course, this highlights how this would require a distinct set of rules for non-unique names. Working out what this differences need to be is the hard part.

Conclusion

Extending the definition of HTTPS to include non-unique names is potentially a big step. However, it might mean that we can do away with the bizarre exceptions we have for unsecured HTTP in certain environments.

This post sketched out a model that requires very little of servers. Servers only need to present a certificate over TLS, with a unique key. It doesn’t care much what those certificates contain[8]. Changes are focused on clients and what they expect from devices.

Allowing a system that is obviously lesser to share the “HTTPS” scheme with the system we know (and love/hate/respect/loathe/dread) might seem dishonest or misleading. I maintain that – as long as the servers with real names are unaffected, as they would be – no harm comes from a more inclusive definition.

Expanding what it means to be an HTTPS server might help eliminate unsecured local services. After all, cleartext HTTP is not fit for deployment to the Internet.


  1. Or, maybe, a globally unique IP address. Really, you don’t want that though. ↩︎

  2. Let’s pretend that the manufacturer isn’t going to go out of business during the lifetime of the widget. OK, I can’t pretend: this is unrealistic. Even if they stay in business, there is no guarantee that they will maintain the necessary services. ↩︎

  3. With some notable exceptions. ↩︎

  4. And good luck noticing the phishing attack that replaces the name. It’s not that hard for an attacker to replace the name with one that matches a few characters at the start and end. How do you think Facebook got “facebookcorewwwi.onion”? ↩︎

  5. You might use xx--\<somehash>.local or some other reserved label to eliminate the risk, however remote, of collisions with existing names. ↩︎

  6. You hand your packets to the attacker to forward. ↩︎

  7. I should be recommending the use of passkeys here, pointing to Adam Langley’s nice book, but – to be perfectly frank – the user experience still sucks. Besides, denying that people use passwords is silly. ↩︎

  8. It might not be that simple. You probably want the server to include its name, if only to avoid unknown key share attacks. That might rule out the use of raw public keys. ↩︎