← Tüm yazılar
securityengineeringlicense20.05.2026

The Ed25519 license signing model

How RaxBoard signs license verify, update, and webhook responses with Ed25519 detached signatures, and why we picked it over HMAC.

Every RaxBoard install talks to a central licensing service for two things: verifying that the installed license is still valid, and downloading signed update packages. Both of those interactions need to be tamper-proof, because a man-in-the-middle that can replace the license verify response can either grant unauthorized access or revoke a paying customer.

We sign every license verify, update, and webhook payload with Ed25519. This post explains why, and what the wire format looks like.

Why not HMAC

HMAC-SHA256 with a shared secret would work, but it has a sharp downside: every forum install needs the secret to verify, and a leaked secret on one forum compromises every other forum on the same key. With asymmetric signing the SaaS holds the private key, every forum holds only the public key, and a single forum getting popped does not compromise the verify path for anyone else.

Why Ed25519 specifically

RSA-PSS works, but the keys are 4x larger and the operations are 10x slower. ECDSA over P-256 works, but the signature format has historically had implementation pitfalls (deterministic vs. randomized, RFC 6979). Ed25519 is fast, has small keys (32 bytes public, 64 bytes signature), and the canonical implementation is in libsodium which ships with every modern PHP. It is also the algorithm Cloudflare, Tor, and most modern protocols default to in 2026.

Wire format

We use a JWS-shaped compact format: base64url(header).base64url(payload).base64url(signature). The header is { "alg": "EdDSA", "kid": "k1", "typ": "raxboard/license+jws" }. The payload is the full verify response body. The signature is detached over the concatenated header.payload bytes.

The forum side verifies with sodium_crypto_sign_verify_detached($signature, $headerPayload, $publicKey). The public key is pinned at install time from the LICENSE_SIGNING_PIN_PUB_B64 environment variable; the live pubkey bundle is refreshed daily from /api/license/pubkeys so we can rotate keys without breaking installs.

Webhook signing

Outbound webhooks (license suspended, revoked, unsuspended) carry both an Ed25519 JWS in X-Raxboard-Signature-Ed and a legacy HMAC in X-Raxboard-Signature during the migration window. New forums verify Ed25519 only; older forums on pre-Sprint-11 builds fall back to HMAC. Once every forum has pulled the latest pubkeys, the HMAC header gets removed.

Anti-replay

Every response includes a Unix timestamp. The forum rejects any payload with a clock skew larger than 300 seconds. For verify requests, the forum also generates a nonce that the SaaS echoes back inside the signed payload; replaying an old signed response fails the nonce check.

The net effect: the SaaS can suspend a leaked license and the forum applies the kill-switch within seconds, without ever trusting a shared secret over the network.

Güncel kal.

Önemli sürümler, topluluk öne çıkanları ve mühendislik hikayeleri — doğrudan e-postanda.