Sigil.Sign
0.5.0
See the version list below for details.
dotnet tool install --global Sigil.Sign --version 0.5.0
dotnet new tool-manifest
dotnet tool install --local Sigil.Sign --version 0.5.0
#tool dotnet:?package=Sigil.Sign&version=0.5.0
nuke :add-package Sigil.Sign --version 0.5.0
Sigil
Cryptographic signing and verification for any file. No cloud, no accounts, no dependencies beyond the .NET BCL.
Table of contents
- What it does
- Why not just use Sigstore/PGP/X.509?
- Quick start
- Ephemeral vs persistent vs vault
- Envelope format
- Multiple signatures
- How it works
- Trust bundles
- Vault-backed signing
- Discovery
- CLI reference
- Dotnet tool reference
- What's coming
- Install
- License
What it does
Sigil lets you sign files and verify signatures. That's it.
- Sign a file — Sigil produces a small
.sig.jsonfile next to it - Anyone can verify the file hasn't been tampered with — the public key is embedded in the envelope
- No key store, no import/export, no hidden state
It works with any file: binaries, SBOMs, container images, config files, tarballs — anything. When signing a CycloneDX or SPDX JSON file, Sigil automatically detects the format and embeds SBOM metadata in the signature envelope.
Why not just use Sigstore/PGP/X.509?
| Sigil | Sigstore | PGP | X.509 | |
|---|---|---|---|---|
| Needs an account | No | Yes (OIDC) | No | Yes (CA) |
| Needs internet | No | Yes | No | Depends |
| Stores your email | No | Yes (public log) | Optional | Yes |
| External dependencies | Zero | Many | Many | Many |
| Key management | None (ephemeral), PEM files, or vault/KMS | Ephemeral | Complex | Complex |
| Vault/KMS support | Yes (4 providers) | No | No | Partial |
| Works offline | Yes | No | Yes | Partial |
| Hidden state on disk | None | None | ~/.gnupg/ |
Varies |
| Post-quantum ready | Yes (ML-DSA-65) | No | No | Partial |
Sigil is for people who want to sign things without asking permission from a cloud service.
Quick start
Sign a file (ephemeral — zero setup)
sigil sign my-app.tar.gz
That's it. No key generation needed. A key pair is created in memory, the file is signed, and the private key is discarded. This proves the file hasn't been tampered with since signing.
Output:
Signed: my-app.tar.gz
Algorithm: ecdsa-p256
Key: sha256:9c8b0e1d9d9c...
Mode: ephemeral (key not persisted)
Signature: my-app.tar.gz.sig.json
Verify a file
sigil verify my-app.tar.gz
Output:
Artifact: my-app.tar.gz
Digests: MATCH
[VERIFIED] sha256:9c8b0e1d...
All signatures VERIFIED.
No key import needed — the public key is embedded in the .sig.json envelope.
If someone tampers with the file:
FAILED: Artifact digest mismatch — file has been modified.
Sign with a persistent key (for identity)
When you need a stable identity across signatures:
sigil generate -o mykey
sigil sign my-app.tar.gz --key mykey.pem
Same fingerprint every time. This enables trust — others can verify that you (specifically) signed something.
Choose your algorithm
sigil generate -o mykey --algorithm ecdsa-p384
sigil generate -o mykey --algorithm rsa-pss-sha256
sigil generate -o mykey --algorithm ml-dsa-65
When signing with a PEM file, the algorithm is auto-detected — no need to specify it:
sigil sign my-app.tar.gz --key rsa-key.pem # auto-detects RSA
sigil sign my-app.tar.gz --key ec-key.pem # auto-detects P-256 or P-384
For ephemeral signing with a non-default algorithm:
sigil sign my-app.tar.gz --algorithm ml-dsa-65
Sign an SBOM
When signing a CycloneDX or SPDX JSON file, Sigil automatically detects the format and embeds metadata:
sigil sign sbom.cdx.json --key mykey.pem
Signed: sbom.cdx.json
Algorithm: ecdsa-p256
Key: sha256:c017446b9040d...
Format: CycloneDX (application/vnd.cyclonedx+json)
Signature: sbom.cdx.json.sig.json
Verification shows the SBOM metadata:
sigil verify sbom.cdx.json
Artifact: sbom.cdx.json
Digests: MATCH
SBOM Format: CycloneDX
Spec Version: 1.6
Name: my-app
Version: 3.0.0
Supplier: Acme Corp
Components: 3
[VERIFIED] sha256:c017446b9040d...
All signatures VERIFIED.
The metadata is embedded in the signed subject, so it is tamper-proof. Non-SBOM files are signed without metadata — no behavior changes for regular files.
Sign with a vault key
When your private key lives in a cloud KMS or HashiCorp Vault:
sigil sign my-app.tar.gz --vault aws --vault-key alias/my-signing-key
Signed: my-app.tar.gz
Algorithm: ecdsa-p256
Key: sha256:7f2a3b...
Mode: vault (aws)
Signature: my-app.tar.gz.sig.json
The private key never leaves the vault — only the signature is returned. Verification works identically (the public key is embedded in the envelope). See Vault-backed signing for setup details.
Ephemeral vs persistent vs vault
| Ephemeral (default) | Persistent (--key) |
Vault (--vault) |
|
|---|---|---|---|
| Setup | None | sigil generate -o keyname |
Configure vault + auth |
| Identity proof | No (different key each time) | Yes (stable fingerprint) | Yes (stable fingerprint) |
| Integrity proof | Yes | Yes | Yes |
| MITM protection | No (attacker can re-sign) | Yes (with trusted fingerprint) | Yes (with trusted fingerprint) |
| Key management | None | User manages PEM file | Vault manages key |
| Private key exposure | In memory (discarded) | On disk (PEM file) | Never leaves vault |
| CI/CD | Just works | Mount PEM file | IAM roles / service accounts |
| Trust bundles | Not useful | Yes | Yes |
Envelope format
The .sig.json envelope is a self-contained, detached signature:
{
"version": "1.0",
"subject": {
"digests": {
"sha256": "abc123...",
"sha512": "def456..."
},
"name": "my-app.tar.gz",
"mediaType": "application/vnd.cyclonedx+json",
"metadata": {
"sbom.format": "CycloneDX",
"sbom.specVersion": "1.6",
"sbom.name": "my-app",
"sbom.version": "3.0.0",
"sbom.supplier": "Acme Corp",
"sbom.componentCount": "3"
}
},
"signatures": [
{
"keyId": "sha256:9c8b0e1d...",
"algorithm": "ecdsa-p256",
"publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...",
"value": "base64...",
"timestamp": "2026-02-07T14:30:00Z",
"label": "ci-pipeline"
}
]
}
The publicKey field contains the base64-encoded SPKI public key. During verification, Sigil computes the fingerprint of this key and checks it matches keyId — preventing public key substitution.
The mediaType and metadata fields are only present for detected SBOM files. They are null/absent for regular files.
Multiple signatures
Multiple parties can independently sign the same file. A build system signs it, then an auditor signs it — both signatures live in the same envelope. They can even use different algorithms:
sigil sign release.tar.gz --key build-key.pem --label "ci-pipeline"
# Later, someone else with a different key type:
sigil sign release.tar.gz --key audit-rsa-key.pem --label "security-review"
Verification shows all signatures:
Artifact: release.tar.gz
Digests: MATCH
[VERIFIED] sha256:a1b2c3... (ci-pipeline)
[VERIFIED] sha256:d4e5f6... (security-review)
All signatures VERIFIED.
How it works
Identity = Key pair. Your key fingerprint (SHA-256 of the public key) is your identity. No email, no username, no account.
Signatures are detached. Sigil never modifies your files. It produces a separate .sig.json envelope containing the file's digests, the public key, and the cryptographic signature.
Signing payload. What actually gets signed is:
JCS-canonicalized(subject metadata) + SHA-256(file bytes) + JCS-canonicalized(signed attributes)
This binds the signature to the file content, its metadata (name, digests, SBOM metadata if present), and all signature entry fields (algorithm, keyId, timestamp, label) — preventing substitution and replay attacks.
Crypto. All crypto comes from .NET's built-in System.Security.Cryptography — zero external dependencies.
| Algorithm | Name | Use case |
|---|---|---|
| ECDSA P-256 | ecdsa-p256 |
Default. Fast, compact signatures, widely supported. |
| ECDSA P-384 | ecdsa-p384 |
CNSA suite compliance, enterprise/government requirements. |
| RSA-PSS | rsa-pss-sha256 |
Legacy interop, 3072-bit keys. |
| ML-DSA-65 | ml-dsa-65 |
Post-quantum (FIPS 204). Requires platform support. |
| Ed25519 | ed25519 |
Planned — waiting for .NET SDK to ship the native API. |
PEM auto-detection means you never need to tell Sigil what algorithm a key uses — it parses the key's OID from the DER encoding and dispatches to the correct implementation.
SBOM detection. When a file is signed, Sigil tries to parse it as JSON and checks for CycloneDX (bomFormat: "CycloneDX") or SPDX (spdxVersion: "SPDX-...") markers. Detection never throws — if the file isn't a recognized SBOM, it's signed as a plain file with no metadata.
Trust bundles
Verifying a signature tells you the file hasn't been tampered with, but it doesn't tell you if you should trust the key that signed it. Trust bundles solve this.
A trust bundle is a signed JSON file that says: "I trust these specific keys, for these purposes, until these dates." Think of it like a browser's list of trusted certificate authorities — except you create your own, for your own keys, without any third party involved.
The problem trust bundles solve
Without a trust bundle, sigil verify answers one question:
"Was this file signed by the key in the envelope?"
With a trust bundle, it answers a more useful question:
"Was this file signed by a key I actually trust?"
Creating a trust bundle
Start by generating keys — one "authority" key that signs the bundle itself, and one or more "signer" keys that sign your actual files:
sigil generate -o authority
sigil generate -o ci-key
Create an empty bundle:
sigil trust create --name "my-project" -o trust.json
Add the CI key as a trusted key:
sigil trust add trust.json \
--fingerprint sha256:abc123... \
--name "CI Pipeline Key"
Sign the bundle with the authority key. This locks the bundle — nobody can add or remove keys without the authority's private key:
sigil trust sign trust.json --key authority.pem -o trust-signed.json
Verifying with trust
Now when you verify a file, you can pass the trust bundle and tell Sigil which authority you trust:
sigil verify release.tar.gz \
--trust-bundle trust-signed.json \
--authority sha256:def456...
If the file was signed by a key that's in the bundle, you'll see:
Artifact: release.tar.gz
Digests: MATCH
[TRUSTED] sha256:abc123... (CI Pipeline Key)
Key is directly trusted.
All signatures TRUSTED.
If the signing key isn't in the bundle:
[UNTRUSTED] sha256:999888...
Key not found in trust bundle.
Without --trust-bundle, Sigil behaves exactly as before — pure cryptographic verification, no trust decisions.
Scopes
You can restrict what a key is trusted to do. Scopes are optional — without them, a key is trusted for everything.
sigil trust add trust.json \
--fingerprint sha256:abc123... \
--name "CI Key" \
--scope-names "*.tar.gz" "*.zip" \
--scope-labels "ci-pipeline" \
--scope-algorithms "ecdsa-p256" \
--not-after 2027-01-01T00:00:00Z
This says: trust this key only for signing .tar.gz and .zip files, only when labeled ci-pipeline, only with ECDSA P-256, and only until January 2027. If any of those conditions aren't met, you'll see [SCOPE_MISMATCH] or [EXPIRED] instead of [TRUSTED].
Endorsements
Sometimes you want to say "I trust Key A, and Key A vouches for Key B." Endorsements let you do this without adding Key B directly to the bundle.
sigil trust endorse trust.json \
--endorser sha256:aaa... \
--endorsed sha256:bbb... \
--statement "Authorized build key for CI"
When Sigil evaluates trust, if it finds a matching endorsement from a key that's directly in the bundle, the endorsed key is treated as trusted:
[TRUSTED] sha256:bbb...
Endorsed by CI Pipeline Key.
Endorsements are non-transitive: if Key A endorses Key B, and Key B endorses Key C, Key C is not trusted. Only the bundle authority decides which endorsements to include, and only direct bundle keys can be endorsers.
Endorsements can also have scopes and expiry dates, further restricting what the endorsed key is trusted for.
Viewing a bundle
sigil trust show trust-signed.json
Trust Bundle: my-project
Version: 1.0
Created: 2026-02-08T12:00:00Z
Keys (2):
sha256:abc123... (CI Pipeline Key)
Expires: 2027-01-01T00:00:00Z
Names: *.tar.gz, *.zip
sha256:def456... (Release Manager)
Endorsements (1):
sha256:abc123... -> sha256:bbb888...
Statement: Authorized build key for CI
Signature: PRESENT
Signed by: sha256:def456...
Algorithm: ecdsa-p256
Timestamp: 2026-02-08T12:00:00Z
How trust evaluation works
When you pass --trust-bundle and --authority to sigil verify, here's what happens for each signature:
- Verify the bundle — Check that the bundle is signed by the authority you specified. If not, the bundle is rejected entirely.
- Check the crypto — If the cryptographic signature is invalid, the key is
Untrustedregardless of what the bundle says. Crypto trumps trust. - Look up the key — Search for the signing key's fingerprint in the bundle's key list.
- If found — Check expiry, then check scopes. If everything passes:
Trusted. - If not found — Search endorsements where this key is endorsed by a key that is in the bundle (and that endorser isn't expired, and the endorsement isn't expired, and the scopes match). If found:
TrustedViaEndorsement. Otherwise:Untrusted.
Trust bundle format
{
"version": "1.0",
"kind": "trust-bundle",
"metadata": {
"name": "my-project",
"created": "2026-02-08T12:00:00Z"
},
"keys": [
{
"fingerprint": "sha256:abc123...",
"displayName": "CI Pipeline Key",
"scopes": {
"namePatterns": ["*.tar.gz"],
"labels": ["ci-pipeline"],
"algorithms": ["ecdsa-p256"]
},
"notAfter": "2027-01-01T00:00:00Z"
}
],
"endorsements": [
{
"endorser": "sha256:aaa...",
"endorsed": "sha256:bbb...",
"statement": "Authorized build key",
"timestamp": "2026-02-08T12:00:00Z"
}
],
"signature": {
"keyId": "sha256:def456...",
"algorithm": "ecdsa-p256",
"publicKey": "base64-SPKI...",
"value": "base64-signature...",
"timestamp": "2026-02-08T12:00:00Z"
}
}
The signature field covers everything above it. When the bundle is signed, Sigil computes the JCS-canonicalized JSON of everything except signature, then signs that with the authority key.
Discovery
Trust bundles are useful, but you still need to distribute them — copy files, share paths, configure CI. Discovery automates this. Organizations publish trust bundles at standard locations, and Sigil fetches them automatically.
Three discovery methods are supported, all using BCL only (zero external dependencies):
Well-known URLs
Publish your trust bundle at https://example.com/.well-known/sigil/trust.json. Anyone can discover it:
sigil discover well-known example.com
Bundle: my-project
Keys: 3
Signature: SIGNED
Save it locally with -o:
sigil discover well-known example.com -o trust.json
DNS TXT records
Add a TXT record at _sigil.example.com:
_sigil.example.com. IN TXT "v=sigil1 bundle=https://example.com/.well-known/sigil/trust.json"
Then discover via DNS:
sigil discover dns example.com
Sigil sends a raw UDP DNS query (no external resolver library), parses the TXT record, and fetches the bundle from the URL.
Git repositories
Store your trust bundle in a git repository at .sigil/trust.json or trust.json in the repo root:
sigil discover git https://github.com/org/trust-bundles.git
Use a URL fragment to specify a branch or tag:
sigil discover git https://github.com/org/trust-bundles.git#v2
Sigil performs a shallow clone (--depth 1), reads the bundle, and cleans up the temporary directory.
Verify with discovery
Instead of manually downloading a trust bundle, you can pass --discover directly to sigil verify:
sigil verify release.tar.gz --discover example.com
This is equivalent to downloading the bundle and passing --trust-bundle, but without the manual step. The authority fingerprint is auto-extracted from the bundle's signature — if the bundle is signed, you don't need to specify --authority.
You can still override the authority if needed:
sigil verify release.tar.gz --discover example.com --authority sha256:def456...
--discover and --trust-bundle are mutually exclusive — you pick one or the other. If discovery fails, Sigil reports the error and exits (it doesn't fall back to no-trust mode, since you explicitly asked for trust evaluation).
The --discover option supports all three schemes:
| Input | Method |
|---|---|
example.com |
Well-known URL |
https://example.com/trust.json |
Direct HTTPS fetch |
dns:example.com |
DNS TXT lookup |
git:https://github.com/org/repo.git |
Git clone |
Vault-backed signing
When private keys must never leave a hardware security module or cloud KMS, Sigil delegates signing to the vault. The private key is never exposed to the signing tool — Sigil sends a hash to the vault, receives the signature, and embeds it in the envelope. Authentication uses environment variables — no hardcoded secrets. All vault API calls have a 30-second timeout.
Supported providers
| Provider | --vault value |
Key reference format | Auth mechanism |
|---|---|---|---|
| HashiCorp Vault | hashicorp |
transit/<keyname> or kv/<path> |
VAULT_TOKEN or AppRole |
| Azure Key Vault | azure |
Key name or full key URL | DefaultAzureCredential |
| AWS KMS | aws |
ARN, key ID, or alias/<name> |
AWS credential chain |
| Google Cloud KMS | gcp |
Full resource name | Application Default Credentials |
HashiCorp Vault
HashiCorp Vault supports two backends: Transit (sign-in-vault) and KV (retrieve PEM key).
Key reference formats:
transit/my-signing-key # Transit engine (recommended)
my-signing-key # Transit engine (shorthand)
kv/sigil/my-key # KV v2 engine (expects "pem" field)
Environment variables:
| Variable | Required | Description |
|---|---|---|
VAULT_ADDR |
Yes | Vault server URL (HTTPS required except localhost) |
VAULT_TOKEN |
One of | Direct token authentication |
VAULT_ROLE_ID |
One of | AppRole authentication (with VAULT_SECRET_ID) |
VAULT_SECRET_ID |
One of | AppRole authentication (with VAULT_ROLE_ID) |
VAULT_NAMESPACE |
No | Vault namespace |
VAULT_MOUNT_PATH |
No | Transit mount path (default: transit) |
If neither VAULT_TOKEN nor AppRole credentials are set, Sigil falls back to ~/.vault-token.
Example:
# Linux / macOS
export VAULT_ADDR=https://vault.example.com
export VAULT_TOKEN=hvs.CAES...
# Windows (PowerShell)
$env:VAULT_ADDR = "https://vault.example.com"
$env:VAULT_TOKEN = "hvs.CAES..."
# Windows (cmd)
set VAULT_ADDR=https://vault.example.com
set VAULT_TOKEN=hvs.CAES...
sigil sign release.tar.gz --vault hashicorp --vault-key transit/my-signing-key
sigil trust sign trust.json --vault hashicorp --vault-key transit/my-signing-key -o trust-signed.json
Azure Key Vault
Key reference formats:
my-key # Key name (uses AZURE_KEY_VAULT_URL)
https://myvault.vault.azure.net/keys/my-key # Full URL (latest version)
https://myvault.vault.azure.net/keys/my-key/abc123... # Full URL (specific version)
Environment variables:
| Variable | Required | Description |
|---|---|---|
AZURE_KEY_VAULT_URL |
Yes | Vault URL (e.g., https://myvault.vault.azure.net) |
Authentication uses DefaultAzureCredential, which tries (in order): environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID), managed identity, workload identity, Azure CLI.
Example:
# Linux / macOS
export AZURE_KEY_VAULT_URL=https://myvault.vault.azure.net
# Windows (PowerShell)
$env:AZURE_KEY_VAULT_URL = "https://myvault.vault.azure.net"
# Windows (cmd)
set AZURE_KEY_VAULT_URL=https://myvault.vault.azure.net
sigil sign release.tar.gz --vault azure --vault-key my-key
AWS KMS
Key reference formats:
alias/my-signing-key # Key alias
arn:aws:kms:us-east-1:123456789:key/abcd-1234-efgh # Full ARN
abcd-1234-efgh-5678 # Key ID
Environment variables:
| Variable | Required | Description |
|---|---|---|
AWS_REGION |
Yes | AWS region (e.g., us-east-1) |
Authentication uses the standard AWS credential chain: environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), EC2/ECS instance roles, web identity (IRSA), ~/.aws/credentials.
Example:
# Linux / macOS
export AWS_REGION=us-east-1
# Windows (PowerShell)
$env:AWS_REGION = "us-east-1"
# Windows (cmd)
set AWS_REGION=us-east-1
sigil sign release.tar.gz --vault aws --vault-key alias/my-signing-key
Google Cloud KMS
Key reference format:
projects/my-project/locations/us/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1
Authentication uses Application Default Credentials: GOOGLE_APPLICATION_CREDENTIALS (service account JSON), gcloud auth application-default login, Compute Engine / Cloud Run service account.
Example:
sigil sign release.tar.gz --vault gcp \
--vault-key projects/my-project/locations/us/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1
CLI reference
sigil generate [-o prefix] [--passphrase "pass"] [--algorithm name]
sigil sign <file> [--key <private.pem>] [--vault <provider>] [--vault-key <reference>] [--output path] [--label "name"] [--passphrase "pass"] [--algorithm name]
sigil verify <file> [--signature path] [--trust-bundle path] [--authority fingerprint] [--discover uri]
sigil trust create --name <name> [-o path] [--description "text"]
sigil trust add <bundle> --fingerprint <fp> [--name "display name"] [--not-after date] [--scope-names patterns...] [--scope-labels labels...] [--scope-algorithms algs...]
sigil trust remove <bundle> --fingerprint <fp>
sigil trust endorse <bundle> --endorser <fp> --endorsed <fp> [--statement "text"] [--not-after date] [--scope-names patterns...] [--scope-labels labels...]
sigil trust sign <bundle> --key <private.pem> | --vault <provider> --vault-key <reference> [-o path] [--passphrase "pass"]
sigil trust show <bundle>
sigil discover well-known <domain> [-o path]
sigil discover dns <domain> [-o path]
sigil discover git <url> [-o path]
generate: Create a key pair for persistent signing.
-o prefixwritesprefix.pem(private) andprefix.pub.pem(public)- Without
-o, prints private key PEM to stdout --passphraseencrypts the private key--algorithmselects the signing algorithm (default:ecdsa-p256)
sign: Sign a file. Three signing modes:
- Without
--keyor--vault: ephemeral mode (key generated in memory, discarded after signing) - With
--key: persistent mode (loads private key from PEM file, algorithm auto-detected) - With
--vaultand--vault-key: vault mode (private key never leaves the vault) --vaultand--keyare mutually exclusive--algorithmonly applies to ephemeral mode (default:ecdsa-p256)- SBOM format is auto-detected for CycloneDX and SPDX JSON files
verify: Verify a file's signature.
- Public key is extracted from the
.sig.json— no key import needed - Algorithm is read from the envelope — works with any supported algorithm
- SBOM metadata is displayed when present in the envelope
--trust-bundleand--authorityenable trust evaluation on top of crypto verification--discoverfetches a trust bundle via well-known URL, DNS, or git (mutually exclusive with--trust-bundle)- When using
--discover, authority is auto-extracted from the bundle's signature if--authorityis omitted
trust create: Create an empty unsigned trust bundle.
trust add / remove: Add or remove trusted keys from an unsigned bundle.
trust endorse: Add an endorsement ("Key A vouches for Key B") to an unsigned bundle.
trust sign: Sign a bundle with an authority key. Either --key or --vault/--vault-key is required (mutually exclusive). This locks the bundle — modifications require re-signing.
trust show: Display the contents of a trust bundle (keys, endorsements, signature status).
discover well-known: Fetch a trust bundle from https://domain/.well-known/sigil/trust.json.
discover dns: Look up _sigil.domain TXT records for a bundle URL, then fetch it.
discover git: Shallow-clone a git repository and read .sigil/trust.json or trust.json. Use #branch in the URL for a specific branch or tag.
Dotnet tool reference
Sigil is distributed as a .NET tool. The NuGet package is Sigil.Sign.
dotnet tool install --global Sigil.Sign
Install globally — available as sigil from any directory:
dotnet tool install --global Sigil.Sign
Install as a local tool — scoped to a repository, tracked in a manifest file:
dotnet new tool-manifest # creates .config/dotnet-tools.json (once per repo)
dotnet tool install Sigil.Sign # adds sigil to the manifest
dotnet tool restore # restores tools on a fresh clone
dotnet sigil sign my-app.tar.gz # run via 'dotnet sigil' instead of 'sigil'
Update to the latest version:
dotnet tool update --global Sigil.Sign # global
dotnet tool update Sigil.Sign # local
Uninstall:
dotnet tool uninstall --global Sigil.Sign # global
dotnet tool uninstall Sigil.Sign # local
Check installed version:
dotnet tool list --global # shows all global tools
dotnet tool list # shows local tools for current repo
| Global | Local | |
|---|---|---|
| Command | sigil |
dotnet sigil |
| Scope | Machine-wide | Per-repository |
| Tracked in source | No | Yes (.config/dotnet-tools.json) |
| CI/CD restore | Not needed | dotnet tool restore |
| Multiple versions | No | Yes (different repos, different versions) |
Usage examples (local tool)
When installed as a local tool, prefix all commands with dotnet. The arguments are identical to the CLI reference above.
Sign and verify:
dotnet sigil sign my-app.tar.gz
dotnet sigil verify my-app.tar.gz
Generate keys and sign with a persistent key:
dotnet sigil generate -o mykey
dotnet sigil sign my-app.tar.gz --key mykey.pem
Sign with a vault key:
dotnet sigil sign my-app.tar.gz --vault aws --vault-key alias/my-signing-key
Trust bundles:
dotnet sigil trust create --name "my-project" -o trust.json
dotnet sigil trust add trust.json --fingerprint sha256:abc123... --name "CI Key"
dotnet sigil trust sign trust.json --key authority.pem -o trust-signed.json
dotnet sigil verify release.tar.gz --trust-bundle trust-signed.json --authority sha256:def456...
Discovery:
dotnet sigil discover well-known example.com -o trust.json
dotnet sigil verify release.tar.gz --discover example.com
CI/CD example
A typical GitHub Actions workflow using the local tool:
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- run: dotnet tool restore
- run: dotnet sigil sign my-app.tar.gz --key ${{ runner.temp }}/signing-key.pem --label "ci-pipeline"
- run: dotnet sigil verify my-app.tar.gz
What's coming
- Ed25519 — When the .NET SDK ships the native API.
Install
Requires .NET 10 SDK.
Install as a global dotnet tool from NuGet:
dotnet tool install --global Sigil.Sign
Update to the latest version:
dotnet tool update --global Sigil.Sign
Or build from source:
git clone <repo-url>
cd <repo-name>
dotnet build Sigil.slnx
dotnet test Sigil.slnx
dotnet run --project src/Sigil.Cli -- sign somefile.txt
License
AGPL-3.0 — free to use, modify, and distribute. If you distribute a modified version, you must release your source under the same license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.