Files
hq/04-ISSUES/014-a-key-that-is-present-and-unusable/00-report.md
T
jschoubben a6872ac099 A key that is present and unusable, and what the certificate work became
Issue 014: the node's serving key was stored in the host's own encoding, so
every check that reads the file passed and no server could start. Same shape as
013 — two halves of one mechanism designed separately, each correct about its
own half. Where a file exists so a third party can read it, the format is the
interface.
2026-08-31 00:42:13 +02:00

49 lines
2.4 KiB
Markdown

---
status: resolved
opened: 2026-08-31
located-in: [mesh-host]
fixed-by: mesh-host — a node's serving key is stored in the format a server reads
amended-design:
---
# 014 — A node's serving key was present, correct, and unusable
## Symptom
A node generates the key it serves TLS with, the mesh certifies the public half, and the
certificate arrives on the machine as an ordinary file. Everything about that worked. But the host
stored the private half in its own encoding — base64 of the raw key — and **nothing that serves
TLS can read it**: not a web server's `ssl_certificate_key`, not Go's `LoadX509KeyPair`, not
`openssl s_server -key`.
The file was there, owned by root, mode 0600, holding the right key. The certificate beside it was
valid and chained to the mesh's authority. The server would not start.
## Why this matters
**Every check that reads the file passes.** The key exists, the certificate exists, the mesh
recorded the public half, the machine reports the declaration applied. The failure surfaces only
when something connects — the worst place to find out, and the place the certificate work was
specifically designed to move away from.
It is the same shape as [013](../013-a-file-arrives-after-the-service-that-needs-it/00-report.md)
and worth naming as a class: **two halves of one mechanism designed separately, each correct
about its own half.** The control plane issues PEM because that is what a certificate is. The host
stored the key in whatever was convenient, because nothing in the host reads it back — the whole
point of the file is that *something else* does, and that something else was not in view.
**The generalisation:** where a file exists so a third party can read it, the format is not an
implementation detail of whoever writes it. It is the interface, and it needs a check that reads
it the way that third party will.
## What was done
PKCS#8 PEM, which is what every TLS server reads. A key in the old encoding is refused **by name**
rather than reported as corrupt — it is intact, and the remedy is to enrol again, which is a
different action from repairing a damaged file.
*Checked by writing a key, decoding the file as PEM, parsing it as PKCS#8, and asserting it is the
same key — and, in the lab, by a real handshake from a second machine that verifies against the
mesh's authority and nothing else. A key that parses is not a key a server can use, which is why
the lab check connects.*