Digital signature creation, verification, and chain of trust for documents, code, and artifacts
Scope: Digital signatures, code signing, artifact verification, chain of trust, timestamping, HSM integration Lines: ~450 Last Updated: 2025-10-27 Format Version: 1.0 (Atomic)
Activate this skill when:
Digital signatures provide:
How it works:
1. Hash the data → SHA-256 hash
2. Encrypt hash with private key → Digital signature
3. Distribute data + signature + public key
Verification:
1. Hash the received data
2. Decrypt signature with public key → Original hash
3. Compare hashes → Match = authentic, Mismatch = tampered
| Algorithm | Key Type | Security | Use Case | |-----------|----------|----------|----------| | RSA-PSS | RSA (2048-4096 bit) | High | General purpose, FIPS compliance | | ECDSA | ECC (P-256, P-384) | High | Mobile, embedded, space-constrained | | EdDSA (Ed25519) | Curve25519 | Highest | Modern applications, performance | | RSA-PKCS#1 v1.5 | RSA | Moderate | Legacy (vulnerable to attacks) | | DSA | Discrete Log | Low | Deprecated (use ECDSA instead) |
Recommendations:
Standard: RFC 5652 Use case: Document signing, S/MIME email
# Sign file with PKCS#7
openssl smime -sign -in document.txt \
-out document.p7s \
-signer cert.pem \
-inkey private.key
# Verify PKCS#7 signature
openssl smime -verify -in document.p7s \
-CAfile ca-cert.pem \
-out document.txt
Standard: RFC 7515 Use case: API tokens, JSON data signing
import jwt
# Sign JSON data
payload = {"user": "alice", "role": "admin"}
token = jwt.encode(payload, private_key, algorithm='RS256')
# Verify signature
decoded = jwt.decode(token, public_key, algorithms=['RS256'])
Standard: W3C Recommendation Use case: SAML, SOAP, XML documents
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="..."/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<Reference URI="">
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>...</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>...</KeyInfo>
</Signature>
Detached (separate file):
# Create detached signature
gpg --detach-sign --armor file.tar.gz
# Produces: file.tar.gz.asc
# Verify
gpg --verify file.tar.gz.asc file.tar.gz
Embedded (within file):
# Create embedded signature
gpg --sign file.tar.gz
# Produces: file.tar.gz.gpg (contains both data and signature)
# Verify and extract
gpg file.tar.gz.gpg
Requirements:
codesign toolSign application:
# Sign app bundle
codesign --sign "Developer ID Application: Your Name" \
--deep \
--force \
--options runtime \
--timestamp \
YourApp.app
# Verify signature
codesign --verify --verbose=4 YourApp.app
# Display signature details
codesign --display --verbose=4 YourApp.app
# Notarize (required for macOS 10.15+)
xcrun notarytool submit YourApp.zip \
--apple-id "your@email.com" \
--password "app-specific-password" \
--team-id "TEAM_ID"
Requirements:
signtool.exe (Windows SDK)Sign executable:
# Sign with timestamp
signtool sign /f certificate.pfx /p password /fd SHA256 \
/tr http://timestamp.digicert.com /td SHA256 \
application.exe
# Verify signature
signtool verify /pa application.exe
# Display signature details
signtool verify /v /pa application.exe
V1 (JAR signing) - Legacy:
jarsigner -keystore my-release-key.jks \
-signedjar app-signed.apk \
app-unsigned.apk \
my-key-alias
V2/V3/V4 (APK Signature Scheme) - Modern:
# Sign with apksigner (recommended)
apksigner sign --ks my-release-key.jks \
--ks-key-alias my-key-alias \
--out app-signed.apk \
app-unsigned.apk
# Verify
apksigner verify --verbose app-signed.apk
Sigstore provides:
Install cosign:
# macOS
brew install cosign
# Linux
wget https://github.com/sigstore/cosign/releases/download/v2.2.0/cosign-linux-amd64
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
Sign container image:
# Sign with OIDC (Google, GitHub, Microsoft)
cosign sign ghcr.io/myorg/myapp:v1.0.0
# Interactive OIDC flow opens browser
# Ephemeral keys generated and certificate issued by Fulcio
# Signature recorded in Rekor transparency log
Verify:
# Verify with certificate identity
cosign verify ghcr.io/myorg/myapp:v1.0.0 \
--certificate-identity=user@example.com \
--certificate-oidc-issuer=https://accounts.google.com
Generate signing key:
# Generate key pair
cosign generate-key-pair
# Produces:
# - cosign.key (private key, encrypted)
# - cosign.pub (public key)
Sign and verify:
# Sign with key
cosign sign --key cosign.key ghcr.io/myorg/myapp:v1.0.0
# Verify with public key
cosign verify --key cosign.pub ghcr.io/myorg/myapp:v1.0.0
Sign files:
# Sign arbitrary file
cosign sign-blob --key cosign.key file.tar.gz > file.tar.gz.sig
# Verify
cosign verify-blob --key cosign.pub \
--signature file.tar.gz.sig \
file.tar.gz
Problem: Signatures become invalid when signing certificate expires.
Solution: Timestamp Authority (TSA) provides proof that signature existed at specific time.
Timestamping flow:
1. Sign document with private key
2. Send signature to TSA
3. TSA signs signature with timestamp
4. Signature valid even after certificate expires (as long as it was valid at signing time)
Request timestamp:
# Sign with timestamp (OpenSSL)
openssl ts -query -data document.txt -sha256 -cert -out request.tsq
# Send to TSA
curl -H "Content-Type: application/timestamp-query" \
--data-binary @request.tsq \
http://timestamp.digicert.com > response.tsr
# Verify timestamp
openssl ts -verify -data document.txt -in response.tsr \
-CAfile tsa-cert.pem
Popular TSAs:
http://timestamp.digicert.comhttp://timestamp.sectigo.comhttps://freetsa.org/tsr# Generate GPG key
gpg --full-generate-key
# Choose: RSA and RSA (default), 4096 bits, expires in 1 year
# List keys
gpg --list-keys
gpg --list-secret-keys
# Detached ASCII signature
gpg --detach-sign --armor file.tar.gz
# Creates: file.tar.gz.asc
# Verify
gpg --verify file.tar.gz.asc file.tar.gz
# Embedded signature
gpg --sign file.tar.gz
# Creates: file.tar.gz.gpg
# Clear-sign (text with inline signature)
gpg --clearsign message.txt
Configure Git:
# Set signing key
git config --global user.signingkey YOUR_KEY_ID
# Enable signing by default
git config --global commit.gpgsign true
git config --global tag.gpgsign true
Sign commits:
# Sign commit
git commit -S -m "Signed commit"
# Sign tag
git tag -s v1.0.0 -m "Signed release"
# Verify
git verify-commit HEAD
git verify-tag v1.0.0
┌─────────────────────┐
│ Root CA │ ← Self-signed, offline, highly trusted
└──────────┬──────────┘
│ signs
┌──────────▼──────────┐
│ Intermediate CA │ ← Operational CA
└──────────┬──────────┘
│ signs
┌──────────▼──────────┐
│ Code Signing Cert │ ← End-entity certificate
└─────────────────────┘
│
▼
Signed Code
OpenSSL:
# Verify certificate chain
openssl verify -CAfile root.pem -untrusted intermediate.pem cert.pem
# Extract certificate from signed binary
openssl pkcs7 -inform DER -in signature.p7s -print_certs -out cert.pem
# Check certificate validity
openssl x509 -in cert.pem -noout -dates
openssl x509 -in cert.pem -noout -subject -issuer
Check revocation status:
CRL (Certificate Revocation List):
# Download CRL
wget http://crl.example.com/revoked.crl
# Check if certificate is revoked
openssl crl -inform DER -in revoked.crl -noout -text | grep -A1 "Serial Number"
OCSP (Online Certificate Status Protocol):
# Query OCSP responder
openssl ocsp -issuer intermediate.pem \
-cert cert.pem \
-url http://ocsp.example.com \
-CAfile root.pem
Benefits:
Sign with HSM (PKCS#11):
from PyKCS11 import *
pkcs11 = PyKCS11Lib()
pkcs11.load('/usr/lib/softhsm/libsofthsm2.so') # HSM library
# Open session
session = pkcs11.openSession(slot)
session.login('user_pin')
# Find signing key
key = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY)])[0]
# Sign data
mechanism = Mechanism(CKM_RSA_PKCS, None)
signature = session.sign(key, data, mechanism)
session.logout()
AWS CloudHSM:
# Configure CloudHSM
/opt/cloudhsm/bin/configure -a <cluster-ip>
# Sign with pkcs11-tool
pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so \
--login --pin <user-pin> \
--sign --mechanism RSA-PKCS \
--input-file data.bin \
--output-file signature.bin
Approved algorithms:
Requirements:
Signature levels:
Requirements:
Evaluation Assurance Levels (EAL):
# ✅ Good: Modern, secure algorithms
EdDSA (Ed25519)
ECDSA P-256
RSA-PSS 3072+
# ❌ Bad: Deprecated or weak
RSA-PKCS#1 v1.5
DSA
MD5 hashing
# ✅ Good: Include timestamp
codesign --timestamp --sign "Developer ID" app.app
signtool sign /tr http://timestamp.digicert.com /td SHA256 app.exe
# ❌ Bad: No timestamp (signature expires with certificate)
codesign --sign "Developer ID" app.app
# ✅ Good: Always verify before execution
cosign verify --key cosign.pub image:tag
gpg --verify file.tar.gz.asc file.tar.gz
# ❌ Bad: Trust without verification
docker run unverified-image
tar -xzf unsigned-archive.tar.gz
# ✅ Good: Use HSM, encrypted keys, access control
- Store signing keys in HSM
- Encrypt private keys (gpg, openssl)
- Require authentication for signing
- Audit all signing operations
# ❌ Bad: Unprotected keys
- Private key in Git repository
- Unencrypted key on disk
- Shared signing credentials
Check:
# Certificate expired?
openssl x509 -in cert.pem -noout -dates
# Wrong public key?
openssl x509 -in cert.pem -pubkey -noout > pubkey.pem
# Certificate revoked?
openssl ocsp -issuer ca.pem -cert cert.pem -url http://ocsp.example.com
# Data modified after signing?
sha256sum file.tar.gz # Compare with original hash
macOS Gatekeeper:
# Check notarization status
spctl --assess --verbose=4 YourApp.app
# Check signature
codesign --verify --deep --strict --verbose=2 YourApp.app
Windows SmartScreen:
# Verify certificate chain
signtool verify /pa /v application.exe
# Check timestamp
signtool verify /pa /tw application.exe
cryptography-key-management - Managing signing keyscryptography-certificate-management - Certificate lifecyclecryptography-pki-fundamentals - PKI and trust chainscryptography-crypto-best-practices - Cryptographic guidelinesLocation: ~/.hanzo/skills/cryptography/signing-verification/resources/
This skill includes comprehensive Level 3 resources for production signing and verification implementations.
Comprehensive technical reference covering:
validate_signatures.py (650+ lines) - Multi-format signature validator
./validate_signatures.py --file document.p7s --check-revocation --jsonsign_artifacts.py (750+ lines) - Universal artifact signing tool
./sign_artifacts.py --file app.tar.gz --key signing.key --format pkcs7 --timestamp --jsonaudit_signing_keys.py (600+ lines) - Signing key lifecycle auditor
./audit_signing_keys.py --keystore ./keys --compliance FIPS --threshold-warning 90 --jsonpython/rsa_pss_signing.py - RSA-PSS document signing
python/ecdsa_signing.py - ECDSA code signing with verification
go/ed25519_artifacts.go - EdDSA artifact signing
python/sigstore_cosign.py - Sigstore cosign integration
python/hsm_signing.py - HSM-backed signing (PKCS#11)
python/timestamp_authority.py - Timestamp authority integration
docker-compose/signing-infrastructure.yml - Container signing infrastructure
config/compliance-validation.yaml - Compliance policy configuration
# Validate signature
cd ~/.hanzo/skills/cryptography/signing-verification/resources/scripts
./validate_signatures.py --file document.p7s --check-chain --check-revocation
# Sign artifact with timestamp
./sign_artifacts.py --file release.tar.gz --key signing.key --timestamp --format pkcs7
# Audit signing keys
./audit_signing_keys.py --keystore /etc/pki/signing --compliance FIPS --json
# Run Python examples
cd ../examples/python
pip install cryptography PyKCS11 jwt sigstore
python rsa_pss_signing.py sign document.txt
python ecdsa_signing.py verify signature.bin
python sigstore_cosign.py keyless-sign myimage:v1.0.0
# View comprehensive reference
cd ../
less REFERENCE.md
CI/CD Integration:
# .github/workflows/sign-release.yml
- name: Sign Release Artifacts
run: |
./scripts/sign_artifacts.py \
--batch-file artifacts.txt \
--key ${{ secrets.SIGNING_KEY }} \
--timestamp \
--json
Verification in Deployment:
# Verify signatures before deployment
./scripts/validate_signatures.py \
--batch-file production-artifacts.txt \
--check-revocation \
--compliance FIPS \
--fail-on-error
# OpenSSL signing
openssl dgst -sha256 -sign private.key -out signature.bin file.txt
openssl dgst -sha256 -verify public.key -signature signature.bin file.txt
# GPG signing
gpg --detach-sign --armor file.tar.gz
gpg --verify file.tar.gz.asc file.tar.gz
# Cosign (container)
cosign sign --key cosign.key image:tag
cosign verify --key cosign.pub image:tag
# Code signing (macOS)
codesign --sign "Developer ID" --timestamp app.app
codesign --verify --verbose=4 app.app
# Code signing (Windows)
signtool sign /f cert.pfx /p password /tr http://timestamp.digicert.com /td SHA256 app.exe
signtool verify /pa app.exe
Last Updated: 2025-10-27