close

What is LicenseGuard?

A self-contained offline license verification system using Ed25519 signatures via OpenSSL, written in portable C11. It includes a full suite of hardening features beyond a basic sign/verify proof of concept — trust stores, key rotation, machine binding, anti-rollback, audit logging, and binary integrity checking.

Vendor (offline)                        Client (offline)
┌────────────────────┐                  ┌─────────────────────────┐
│ private key(s)     │                  │ embedded trust store    │
│ + signer tool      │──▶ license ──▶  │ (multiple public keys)  │
│ + root key         │                  │ + verifier              │
│ + trust update     │──▶ .trust  ──▶  │ + machine binding       │
│   tool             │                  │ + anti-rollback state   │
└────────────────────┘                  │ + audit logging         │
                                        │ + binary integrity      │
                                        └─────────────────────────┘
🐧Linux
🍎macOS
🪟Windows

Hardening Features

Every layer is designed to make offline license verification robust against tampering, replay, and unauthorized use.

Ed25519 Signatures

License payloads signed with Ed25519 via OpenSSL EVP. Fast, compact 64-byte signatures with strong security guarantees.

Trust Store & Key Rotation

Multiple versioned public keys with retirement support. V2 licenses specify issuer_key_id for trust store lookup.

Signed Trust Updates

Distribute new public keys without recompiling the client. Updates are signed by a root key for authenticity.

Machine Binding

SHA-256 of platform-specific machine ID. Supports Linux /etc/machine-id, macOS IOPlatformUUID, and Windows MachineGuid.

Anti-Rollback State

HMAC-protected per-license timestamps detect clock rollback attempts. 60-second tolerance for minor drift.

Audit Logging

Append-only log with HMAC chain. Each entry covers the previous entry's HMAC forming a tamper-evident chain.

Binary Integrity

Post-link SHA-256 self-hash detects binary patching. The verifier re-reads itself at runtime and compares hashes.

Grace Periods

Configurable grace window past license expiry. Returns LIC_GRACE status so your application can warn users.

How It Works

🔑

Generate Keys

Create Ed25519 key pairs and embed public keys into the client binary

✍️

Sign License

Vendor signs a license payload with the private key using the signer tool

📤

Distribute

Send the .lic file to the customer — no network required

Verify Offline

Client verifies signature, checks constraints, and enforces all hardening

License File Format

V1 — Basic

-----BEGIN LICENSE-----
format_version=1
license_id=LIC-2026-0001
customer_name=Example Customer
product=ExampleProduct
edition=pro
features=core,export
not_before=2026-01-01T00:00:00Z
not_after=2027-01-01T00:00:00Z
machine_id=
-----SIGNATURE-----
<base64 Ed25519 signature>
-----END LICENSE-----

V2 — With Key Versioning

-----BEGIN LICENSE-----
format_version=2
issuer_key_id=ed25519-2026-01
license_id=LIC-2026-0001
customer_name=Example Customer
product=ExampleProduct
edition=pro
features=core,export
not_before=2026-01-01T00:00:00Z
not_after=2027-01-01T00:00:00Z
machine_id=
-----SIGNATURE-----
<base64 Ed25519 signature>
-----END LICENSE-----

UTF-8 payload with one key=value per line, LF endings, deterministic order. Ed25519 signature computed over exact payload bytes between BEGIN and SIGNATURE markers.

Quick Start

Get up and running in seconds. Only requires OpenSSL 1.1.1+, a C compiler, and make.

# Full build + all 9 test suites make clean test   # Or step by step: # 1. Generate keys + embedded headers sh tools/generate_test_keys.sh . include   # 2. Build all binaries make   # 3. Issue a sample license sh tools/make_sample_license.sh ./license_sign private_key.pem sample.lic   # 4. Verify ./license_verify sample.lic ExampleProduct   # 5. Verify with all hardening enabled ./license_verify sample.lic ExampleProduct \     --state-dir ./state \     --audit-log ./audit.log \     --check-integrity

Test Suite

make test runs 9 test suites covering every hardening feature:

TestWhat it proves
test-basicV1 license sign → verify round-trip
test-tamperPayload corruption and product mismatch detected
test-v2V2 format with issuer_key_id + trust store lookup
test-machineMachine fingerprint + wrong-ID rejection
test-rollbackAnti-rollback state creation and re-verification
test-auditAudit log creation and append
test-trust-updateTrust update: reject unknown key → accept after update
test-graceExpired license rejected → accepted with grace
test-integrityUnpatched warns → patched verifies correctly

CLI Reference

license_verify

license_verify <license.lic> [product] [options...]   Options:   --grace <seconds> Grace period past expiry   --machine-required Require machine_id to match   --state-dir <path> Anti-rollback state directory   --audit-log <path> Audit log file path   --trust-update <path> Apply signed trust anchor update   --check-integrity Binary self-integrity check   --dump-machine-id Print machine fingerprint and exit   --dump-truststore Print trust store and exit

license_sign

license_sign [--key-id <id>] <privkey.pem> <payload.txt> <output.lic>

trust_update_sign

trust_update_sign <root_privkey.pem> <update_id> <output.trust> \     <key_id> <pubkey.pem> [retired <retire_after>] ...

integrity_patch

integrity_patch <binary>

Security Boundaries

Trust model: The vendor private keys are the root of trust. The root key is the ultimate trust anchor for key rotation.

What signatures protect: Integrity and authenticity of the license payload.

Explicit non-goals: This is not anti-debug, not obfuscation, not a DRM system. It protects license integrity for honest deployments, not against a determined attacker with full binary access.

Get the Source

Portable C11. No dependencies beyond OpenSSL. One make to build, one make test to verify.