Decisions · ADR 0009

The device trusts the two ISRG roots for what it fetches

The firmware talks to the project's Gitea over HTTPS (issue #6, and #4 after it). A TLS client has to decide whose certificates it believes. Three ways were possible:

The firmware talks to the project's Gitea over HTTPS (issue #6, and #4 after it). A TLS client has to decide whose certificates it believes. Three ways were possible:

  • The framework's bundle, about 130 certificate authorities (about 60 KB of flash). Any of them could vouch for git.twis.la.
  • Pin the server's certificate, as the Gemini App does for capsules. The server's certificate is replaced every few months, so a pin would ask the question again at every renewal.
  • Carry the roots the server's chain ends in: ISRG Root X1 (RSA 4096) and ISRG Root X2 (ECDSA P-384), the Let's Encrypt roots, about 2.7 KB of flash (src/platform/ca_roots.h).

We chose the third. The chain and the name are checked by mbedTLS during the handshake. It trusts one organisation's two roots, valid until 2035 and 2040, and a renewal changes nothing.

What it costs

  • If the server moves to another CA, the device can no longer reach it, and the next firmware, carrying that CA's root, has to come from the PC or the SD card. Both still work; they don't use TLS.
  • The roots are public data checked against the published fingerprints (listed in the file), refreshed by hand if Let's Encrypt ever changes them.

What it doesn't change

The Update File's own signature (ADR 0003) is what decides what gets installed. A hijacked connection could hide a release, or serve an older signed one, but never make the device install firmware that isn't ours. The TLS check matters more for #4, where a token will travel over it.

Measured while building it

A TLS connection to this server peaks at about 52 KB of heap, the same whether the certificate is checked or not, so skipping the check would have saved nothing. The cost is the connection itself (record buffers and handshake), not the trust decision.

This page is generated from docs/adr/0009-the-device-trusts-the-isrg-roots.md in the repository. To change it, change that file and run site/tools/gen_dev_docs.py.