Every copy of Horvarn Edu Coaching checks two things before it trusts anything from us: that its licence is really ours, and that every file of an update is exactly the file we published. Here is how, and where it stops.
Two keys, one rule each
We use two signing keys, both ES256 (ECDSA on the P-256 curve).
- The release key lives on one computer that is never online. It signs licences and update manifests, and nothing else.
- The status key lives on the server. It signs status answers and the revocation list, and nothing else.
The app checks licences and update manifests only with the release key, and status and revocations only with the status key. So even someone who took over the server could not extend a licence, add a domain to it or push code. The most they could sign is a status.
The key that can change what runs on your computers has never touched the internet.
What a signed document looks like
Every signed answer has the same shape: the payload, the signature, the algorithm and which key made it.
{"payload": "<base64url JSON>", "sig": "<base64url r‖s, 64 bytes>", "alg": "ES256", "kid": "…"}
Every file, checked
An update arrives as a signed manifest that lists each file with its SHA-256. The app downloads the files and checks each one against the manifest before using it. A package that is unsigned, or a file that does not match, is refused.

When our server is down
If the app cannot reach our server, it keeps working on its signed licence and tells the admins. It locks only for two reasons: a signed revocation, or real expiry of the signed licence.
The honest limit: a centre that blocks our server can delay a revocation until its licence expires. For centres we host, real enforcement happens on our servers.
Read more on the Platform page