This document describes the cryptographic system used to authenticate Release Files issued under the Suitefish Commercial Exception License (SCEL). It is the canonical implementation reference for Section 7 of SCEL v1.4.
This is an operational document, not a legal one. The legal terms live in
scel_1.4.md. This document explains how the authentication mechanism
described there actually works in practice.
When someone claims "I have a Suitefish commercial license," there must be a way to prove or disprove that claim without relying on a central authority.
The system described here uses standard public-key cryptography:
- The copyright holder generates a key pair and publishes the public half.
- Every Release File is signed with the private half.
- Anyone β courts, licensees, future Suitefish staff β can verify that a given Release File genuinely came from the copyright holder.
- A second check against a public registry ensures that even a leaked private key cannot produce forged licenses with arbitrary License IDs.
This is the same model used by Debian, the Linux kernel, OpenBSD, Homebrew, and essentially every reputable open-source distribution.
A modern asymmetric signature (Ed25519, the recommended algorithm) is mathematically unforgeable. Without the private key, an attacker cannot produce a signature that verifies against the public key. This is true regardless of who generated the key or where it came from β what matters is that the copyright holder controls the private half.
Under EU eIDAS regulation (Regulation 910/2014), digital signatures fall into three tiers:
- Simple electronic signature β any electronic mark of intent. GPG and Ed25519 signatures fall here.
- Advanced electronic signature β uniquely tied to the signatory and under their sole control. Self-generated keys with proper handling qualify.
- Qualified electronic signature β issued by a certified Trust Service Provider. Legally equivalent to a handwritten signature.
A self-generated signature is at least Tier 1 and, with sound key hygiene, Tier 2. Under eIDAS Article 25, such signatures cannot be denied legal effect or admissibility as evidence solely on the grounds of being electronic.
For SCEL enforcement β where the question is "did you actually issue this Release File?" β Tier 1/2 is sufficient. A court will accept a verifiable signature against a long-published public key as compelling evidence of authenticity.
This is the key practical point: the claimant must produce a verifiable Release File, not the copyright holder. If someone says they have a license but cannot show a Release File that:
- verifies against the published public key, AND
- matches an entry in the public registry,
then by Section 7(d) of SCEL, they have no rights under the exception. The burden of proof sits with whoever is invoking the exception.
Recommended: minisign
- Ed25519, ~32-byte keys
- One command to sign, one to verify
- No web-of-trust, no expiring subkeys, no confusing options
- Available on every major platform
- Created by the libsodium author
Alternatives:
| Tool | Algorithm | Notes |
|---|---|---|
signify |
Ed25519 | OpenBSD's tool, used for their releases |
ssh-keygen -Y sign |
Ed25519 | Reuses your existing SSH key infrastructure |
| GPG | RSA-4096 or Ed25519 | Universal but UX-heavy; only choose if you already use it |
All commands and examples in this document use minisign. Adapt as needed if
you choose differently.
Important: Whichever tool you choose, do not switch later without publishing a key transition document. Verifiers cache and trust your published public key β silent changes break their ability to verify.
minisign -G -p suitefish_scel.pub -s suitefish_scel.keyYou will be prompted for a passphrase. Choose a strong one β this passphrase is the last line of defense if the private key file is ever stolen.
This produces two files:
suitefish_scel.pubβ public key. Publish this.suitefish_scel.keyβ private key. Protect this with your life.
Host the public key at a stable, permanent URL under your control. For example:
https://suitefish.example/scel/pubkey.minisign
Best practices:
- Publish under HTTPS with a certificate from a reputable CA.
- Mention the URL in your README, your website footer, and in the SCEL documents you issue.
- Once published, never change the URL. Verifiers depend on it being stable across years.
- Consider mirroring the key on a second domain or a public archive (e.g. archive.org) as evidence of when it was first published.
Create an empty registry file:
{
"scel_registry_version": 1,
"issuer_pubkey_fingerprint": "RWQf6LRCGA9i...",
"issued_at": "2026-05-28T00:00:00Z",
"licenses": {}
}Host it at a stable URL:
https://suitefish.example/scel/registry.json
Sign the registry file itself:
minisign -S -s suitefish_scel.key -m registry.jsonThis produces registry.json.minisig. Host both files side by side.
The private key file suitefish_scel.key must be kept offline.
Recommended setups, in order of preference:
- YubiKey or hardware token β the key never touches a connected computer. Even malware on your daily-driver machine cannot extract it.
- Air-gapped machine β a dedicated device that never connects to the internet. Transfer Release Files in and signatures out via USB.
- Encrypted external drive stored physically separately from your main machine. Only mount when signing.
Never acceptable:
- Storing the key on your daily laptop, even encrypted.
- Storing the key in cloud storage (Dropbox, iCloud, Google Drive).
- Committing the key to any git repository, public or private.
- Storing the key in a CI/CD secret manager.
Generate at least one backup of the private key:
- Encrypted with the same passphrase
- Stored in a separate physical location (e.g. a safe deposit box, a trusted family member's safe, an encrypted USB stick locked away)
Without a backup, losing the key means you can never issue another valid Release File or update the registry β every existing license becomes permanently frozen at its current state.
For each new licensee:
Create a JSON document, for example release_SCEL-2026-0001.json:
{
"scel_version": "1.4",
"license_id": "SCEL-2026-0001",
"licensee": "ACME GmbH",
"licensee_fingerprint": "sha256:b94d27b9934d3e08...",
"approval_codename": "BLUEFIN",
"approved_project": "ACME Customer Portal",
"issued_at": "2026-05-28T12:00:00Z",
"designated_folders": [
"/_data/modules/acme_portal",
"/_data/themes/acme_theme",
"/_data/integrations/acme_sso"
]
}The folder_list_hash is a SHA-256 over the canonical form of the
designated_folders array β sorted lexicographically, each path joined
with a single \n, no trailing newline.
jq -r '.designated_folders | sort | join("\n")' release_SCEL-2026-0001.json \
| sha256sumAdd the hash into the file:
{
...,
"folder_list_hash": "sha256:a1b2c3d4..."
}minisign -S -s suitefish_scel.key -m release_SCEL-2026-0001.jsonThis produces release_SCEL-2026-0001.json.minisig.
Deliver both files to the licensee.
Add an entry to registry.json:
"SCEL-2026-0001": {
"licensee_fingerprint": "sha256:b94d27b9934d3e08...",
"folder_list_hash": "sha256:a1b2c3d4...",
"approval_codename": "BLUEFIN",
"issued_at": "2026-05-28T12:00:00Z",
"status": "active"
}Re-sign the registry:
minisign -S -s suitefish_scel.key -m registry.jsonUpload both registry.json and registry.json.minisig to the hosting
location. The registry is append-only β never remove or rewrite
entries. To deactivate a license, change its status, do not delete it.
Anyone β a licensee checking their own paperwork, a court, future Suitefish staff β can verify a Release File with three steps:
curl -O https://suitefish.example/scel/pubkey.minisign
curl -O https://suitefish.example/scel/registry.json
curl -O https://suitefish.example/scel/registry.json.minisigminisign -V -p pubkey.minisign -m registry.jsonIf this fails, the registry has been tampered with β stop.
minisign -V -p pubkey.minisign -m release_SCEL-2026-0001.jsonThen check:
- The
license_idfrom the Release File appears inregistry.json. - The
folder_list_hashin the Release File matches the registry entry. - The registry entry's
statusis"active"(not"revoked"or"suspended"). - Recompute the SHA-256 of the canonical folder list and confirm it
matches
folder_list_hash(in case the Release File was tampered with a valid signature, which is impossible if signature verification passed β but belt-and-suspenders).
If all four checks pass, the Release File is genuine and active. If any check fails, Section 7(d) of SCEL applies: the Release File is invalid and confers no rights.
When you determine misuse under Section 11(c) of SCEL:
Change the license's status:
"SCEL-2026-0001": {
...,
"status": "revoked",
"revoked_at": "2027-04-15T09:00:00Z",
"revocation_reason": "Reselling of CMS Core functionality"
}minisign -S -s suitefish_scel.key -m registry.jsonUpload the new registry.json and registry.json.minisig.
Per Section 11(c), revocation must be communicated in writing. Email is sufficient. Include:
- The License ID being revoked
- The effective date and time of revocation
- A summary of the conduct that triggered the revocation
- The URL of the registry where the revocation is publicly recorded
Keep a copy of the notification with a timestamp (e.g. send to yourself, or use a service that timestamps emails).
You may eventually want to rotate the signing key β out of habit, after a suspected exposure, or to upgrade algorithms.
minisign -G -p suitefish_scel_v2.pub -s suitefish_scel_v2.keyCreate a key_transition.json document:
{
"old_pubkey_fingerprint": "RWQf6LRCGA9i...",
"new_pubkey_fingerprint": "RWS8a1c2d3e4...",
"rotation_date": "2028-01-01T00:00:00Z",
"reason": "Routine rotation",
"old_key_status": "retired_but_valid_for_pre_rotation_files"
}Sign this statement with both the old and new keys. Publish all four artifacts (statement + both signatures) at stable URLs.
The registry going forward is signed by the new key. Old Release Files
remain verifiable using the old public key (which stays published with
status: retired).
Keep the old key in cold storage. You may need to issue an emergency signature on it (e.g. to revoke a pre-rotation license) for years to come.
If you suspect or confirm that the private key has been stolen:
- Immediately publish a revocation statement signed by the old key (if you still have access) and the new key.
- Generate a new key and publish the transition statement.
- Re-sign and re-issue every active Release File with the new key. Distribute the new signatures to all active licensees.
- Mark the old key as compromised in the registry, with the date from which signatures by the old key should no longer be trusted.
- Optionally, file a written record with a German notary timestamping the date of compromise. This is the strongest possible evidence in a future dispute over whether a given Release File predates or postdates the compromise.
The faster you publish the compromise statement, the smaller the window in which an attacker could forge plausible-looking Release Files.
| Action | Command |
|---|---|
| Generate key | minisign -G -p PUB -s KEY |
| Sign file | minisign -S -s KEY -m FILE |
| Verify file | minisign -V -p PUB -m FILE |
| SHA-256 hash | sha256sum FILE |
Public URLs you must keep stable:
- Public key:
https://suitefish.example/scel/pubkey.minisign - Registry:
https://suitefish.example/scel/registry.json - Registry signature:
https://suitefish.example/scel/registry.json.minisig
Files the licensee receives per license:
release_<LICENSE_ID>.jsonrelease_<LICENSE_ID>.json.minisig- The signed SCEL document (
scel_1.4.pdfwith the license fields filled in for that licensee)
| Threat | Mitigation |
|---|---|
| Forged Release File | Signature verification fails against published public key |
| Tampered Release File | Signature verification fails |
| Stolen License ID claimed by unauthorized party | They cannot produce a signed Release File |
| Stolen private key, attacker forges new License ID | Registry check fails β License ID not present |
| Stolen private key, attacker re-signs existing License ID with modified folders | Folder hash check fails against registry |
| Tampered registry on the hosting server | Registry signature verification fails |
| Revoked license still claimed by ex-licensee | Registry shows status: revoked |
| Lost private key | Backup; if no backup, registry can never be updated again |
The only scenario this system does not defend against is a complete and simultaneous compromise of the private key and the hosting infrastructure and the absence of any independent timestamping of the original public key publication. That scenario is implausible in practice and would constitute extraordinary circumstances in any legal proceeding.