La firma del codice ha un problema di gestione delle chiavi. La configurazione abituale copia un file .pfx, o collega un token USB, su ogni agente di build che deve firmare una release. La chiave privata finisce su macchine che eseguono script di build non attendibili, non esiste alcuna traccia di cosa sia stato firmato o da chi, e ruotare il certificato significa intervenire su ogni agente. sgcSign 2026.6 risponde a tutto questo con un nuovo server di firma: un daemon self-hosted che espone la firma tramite una API REST su TLS, così le tue pipeline e i tuoi sviluppatori firmano da remoto mentre la chiave di firma resta in un unico posto.
La chiave non lascia mai il server. Meglio ancora, il server può fare da frontend a un token hardware o a un KMS cloud, così la chiave non esiste mai come file. Ogni richiesta è autenticata con una API key, soggetta a rate limit e scritta in un registro di audit a prova di manomissione. Questo articolo illustra cosa può firmare il server, come configurarlo, un avvio rapido in cinque minuti e i due modi per richiamarlo: il semplice curl e il client a riga di comando sgcsign incluso.
Cosa firma
Un server, una API, otto formati di firma. La stessa forma di endpoint (POST /api/v1/sign/<format>) copre sia gli eseguibili sia i documenti:
- Authenticode — file PE Windows:
.exe,.dll,.sys,.msi,.cab,.ocx. Firma doppia opzionale SHA-1 + SHA-256 per le versioni Windows legacy. - PAdES — documenti PDF, con motivo, posizione, contatto e nome del firmatario.
- XAdES — XML, enveloped, enveloping o detached, con profili di fatturazione elettronica nazionali come eIDAS, FacturaE, FatturaPA, KSeF, Peppol, VeriFactu e TicketBAI.
- CAdES — PKCS#7 detached (
.p7s) su qualsiasi payload. - ClickOnce — manifest di applicazione e di distribuzione.
- NuGet — firma di pacchetti
.nupkg. - VSIX — pacchetti di estensione di Visual Studio.
- PowerShell — script
.ps1/.psm1/.psd1(Authenticode SIP).
Ogni formato accetta un URL di timestamp RFC 3161 opzionale, così le firme restano valide anche dopo la scadenza del certificato di firma. Un endpoint complementare POST /api/v1/verify verifica una firma esistente e restituisce il soggetto del firmatario, la validità e il timestamp.
Provider di chiavi collegabili
Un provider è un handle con nome verso una chiave di firma. Il chiamante indica un provider a ogni richiesta; non vede mai la chiave. Puoi registrarne quanti ne servono, e lo stesso server può combinare un PFX locale per gli strumenti interni con un certificato EV basato sul cloud per le release pubbliche. Sono supportati nove tipi di provider:
- Windows Certificate Store (
WinCertStore) — seleziona un certificato per thumbprint o per soggetto, ideale per i certificati EV registrati su un token. - PFX e PEM — file di certificato e di chiave su disco.
- PKCS#11 / HSM (
PKCS11) — token hardware come YubiKey, o un HSM di rete. - AWS KMS, Azure Trusted Signing, Google Cloud KMS, HashiCorp Vault e Certum SimplySign — la chiave privata risiede nel servizio cloud e non raggiunge mai il server.
I segreti restano fuori dal file di configurazione. Qualsiasi parametro il cui nome termina in _env viene letto da una variabile d'ambiente, così la password del PFX, il PIN del token o il segreto del cloud vengono forniti dall'ambiente del servizio, non salvati su disco.
Configurazione del server
L'intero server è gestito da un unico file JSON, sgcSignServer.conf.json (un esempio documentato è incluso come sgcSignServer.conf.sample.json). La struttura di primo livello è composta da una manciata di blocchi:
{
"server": {
"listen": "0.0.0.0",
"port": 8443,
"tls": {
"enabled": true,
"cert_file": "certs/server.crt",
"key_file": "certs/server.key"
},
"max_upload_mb": 512,
"firewall": {
"enabled": true,
"whitelist": ["10.0.0.0/8"],
"brute_force": { "enabled": true, "max_attempts": 5, "ban_duration_sec": 900 },
"rate_limit": { "enabled": true, "max_connections_per_ip": 30, "time_window_sec": 60 }
}
},
"storage": { "sqlite_path": "data/sgcsignserver.db" },
"admin": {
"initial_user": "admin",
"initial_password_env": "SGCSIGN_ADMIN_INIT_PW",
"session_timeout_minutes": 60
},
"audit": { "retention_days": 365 },
"providers": [
{
"name": "pfx-build",
"type": "PFX",
"params": { "file": "certs/build.pfx", "password_env": "SGCSIGN_PFX_PW" }
},
{
"name": "ev-release",
"type": "AzureTS",
"params": {
"tenant_id": "00000000-0000-0000-0000-000000000000",
"client_id": "00000000-0000-0000-0000-000000000000",
"client_secret_env": "SGCSIGN_AZURE_TS_SECRET",
"account": "your-account",
"certificate_profile": "your-profile",
"endpoint": "https://eus.codesigning.azure.net/"
}
}
]
}
I blocchi corrispondono direttamente alle funzionalità. server imposta l'indirizzo di bind, la porta (8443 per impostazione predefinita), il certificato TLS e il firewall integrato (liste di IP consentiti e bloccati, blocco anti brute-force, rate limiting delle connessioni, protezioni contro path traversal e payload). storage punta al database SQLite che contiene utenti, API key, il registro di audit e la coda dei webhook. admin definisce il primo utente e la durata delle sessioni. audit imposta la finestra di conservazione. providers è l'elenco riportato sopra.
La password di amministrazione iniziale non viene mai memorizzata nel file. Al primissimo avvio, quando la tabella degli utenti è vuota, il server legge la variabile d'ambiente indicata da initial_password_env (predefinita SGCSIGN_ADMIN_INIT_PW) e crea l'account amministratore. A ogni avvio successivo quella variabile viene ignorata, quindi serve soltanto a inizializzare il primo accesso.
Avvio rapido in cinque minuti
Installa il server (la procedura guidata di installazione registra il servizio Windows, oppure esegui sgcSignServer.exe --install), quindi:
1. Crea un certificato di firma del codice di prova ed esportalo come PFX. Per un deployment reale importi il tuo certificato emesso dalla CA, oppure salti questo passaggio e punti un provider al tuo token o al KMS cloud.
$cert = New-SelfSignedCertificate -Type CodeSigningCert `
-Subject "CN=sgcSign Quickstart" -KeyAlgorithm RSA -KeyLength 3072 `
-CertStoreLocation Cert:\CurrentUser\My -NotAfter (Get-Date).AddYears(1)
$pw = ConvertTo-SecureString "QuickStartPFX!" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -Password $pw `
-FilePath "C:\Program Files\sgcSign Server\certs\quickstart.pfx"
2. Imposta i segreti come variabili d'ambiente di macchina così che l'account del servizio possa leggerli:
setx /M SGCSIGN_ADMIN_INIT_PW "ChangeMeNow!"
setx /M SGCSIGN_PFX_PW "QuickStartPFX!"
3. Scrivi una configurazione minima con un solo provider PFX (TLS disattivato solo per un test in localhost):
{
"server": { "listen": "127.0.0.1", "port": 8443, "tls": { "enabled": false } },
"storage": { "sqlite_path": "data/sgcsignserver.db" },
"admin": { "initial_user": "admin", "initial_password_env": "SGCSIGN_ADMIN_INIT_PW" },
"audit": { "retention_days": 365 },
"providers": [
{ "name": "pfx-quickstart", "type": "PFX",
"params": { "file": "certs/quickstart.pfx", "password_env": "SGCSIGN_PFX_PW" } }
]
}
4. Avvia il servizio e verifica che sia in ascolto:
sc start sgcSignServer
sc query sgcSignServer
Se si arresta all'avvio, eseguilo in primo piano con sgcSignServer.exe --console --config <path> per vedere l'errore in tempo reale (una SGCSIGN_ADMIN_INIT_PW mancante o un PFX illeggibile sono le cause più comuni). Il flag --selftest-providers carica la configurazione, inizializza ogni provider ed esce, così puoi validare le chiavi prima di andare in produzione.
5. Accedi e crea una API key. Apri http://localhost:8443/admin, accedi come admin con la password iniziale e crea una API key. La chiave in chiaro viene mostrata una sola volta al momento della creazione; copiala subito. Le chiavi hanno il prefisso sgcsk_.
6. Firma un eseguibile di prova con curl:
curl -X POST http://localhost:8443/api/v1/sign/authenticode ^
-H "X-API-Key: sgcsk_..." ^
-F file=@app.exe ^
-F provider=pfx-quickstart ^
-F hash=sha256 ^
--output app-signed.exe
Questo è l'intero ciclo: configura un provider, emetti una chiave, firma. Da qui sostituisci il PFX autofirmato con un certificato reale, attivi il TLS e restringi il firewall alla tua subnet di CI.
Firma tramite REST
Ogni richiesta di firma è un POST con il file e alcuni campi di form. L'autenticazione è un solo header, X-API-Key: sgcsk_... oppure Authorization: Bearer sgcsk_.... La risposta è l'artefatto firmato come application/octet-stream, con il soggetto del firmatario e la durata della firma restituiti negli header X-Sgcsign-Signer-Subject e X-Sgcsign-Duration-Ms.
Firma di un PDF, con motivo e posizione della firma visibili:
curl -X POST https://sign.acme.local:8443/api/v1/sign/pades \
-H "X-API-Key: sgcsk_..." \
-F file=@invoice.pdf \
-F provider=qualified-eu \
-F tsa_url=http://timestamp.digicert.com \
-F reason=Approved \
-F location="Madrid, Spain" \
-F signer_name="Acme Billing" \
-o invoice-signed.pdf
Firma di una fattura XML con un profilo XAdES eIDAS:
curl -X POST https://sign.acme.local:8443/api/v1/sign/xades \
-H "X-API-Key: sgcsk_..." \
-F file=@invoice.xml \
-F provider=qualified-eu \
-F profile=eidas \
-F xades_type=enveloped \
-o invoice-signed.xml
La verifica di una firma restituisce JSON anziché un file:
curl -X POST https://sign.acme.local:8443/api/v1/verify \
-H "X-API-Key: sgcsk_..." \
-F file=@app-signed.exe \
-F format=authenticode
{ "valid": true, "status": "valid",
"subject": "CN=Acme Inc., O=Acme, C=US",
"has_timestamp": true, "timestamp_time": "2026-06-15T13:01:17.000Z" }
Il client a riga di comando sgcsign
Il server include sgcsign, una piccola CLI multi-formato con quattro verbi: sign, verify, keys e health. L'URL del server, la API key e il provider possono provenire da flag o dalle variabili d'ambiente SGCSIGN_SERVER, SGCSIGN_APIKEY e SGCSIGN_PROVIDER, che tengono i segreti fuori dalla riga di comando nella CI:
set SGCSIGN_SERVER=https://sign.acme.local:8443
set SGCSIGN_APIKEY=sgcsk_...
sgcsign sign -f authenticode -p pfx-build -o app-signed.exe app.exe ^
--tsa http://timestamp.digicert.com --desc "Acme Installer"
sgcsign verify -f authenticode app-signed.exe
Per Authenticode c'è un trucco che risparmia banda. Con la modalità pre-hash (--prehash, attiva per impostazione predefinita) la CLI calcola l'hash del PE in locale e carica solo l'hash, poche centinaia di byte invece di un binario di diversi megabyte. Il server firma l'hash e restituisce un blob PKCS#7 detached, che il client incorpora nel file. Su un agente di CI con banda limitata che firma un installer di grandi dimensioni, questo trasforma un upload di diversi megabyte in uno minuscolo.
Sicurezza e operatività
Il server è progettato per funzionare in autonomia davanti a una vera chiave di firma, quindi la superficie operativa conta tanto quanto la crittografia:
- Console di amministrazione in
/admin: dashboard, API key, provider, utenti, progetti e tracciato di audit, tutto nel browser. - API key con rate limit per chiave e quote giornaliere. Una chiave che raggiunge il proprio limite riceve
429con un headerRetry-After. - Progetti multi-tenant, così una chiave limitata a un team non può usare i provider di un altro team.
- Flusso di approvazione (opzionale): un flusso in due fasi in cui una richiesta di firma viene trattenuta finché un operatore non la approva, per certificati di release ad alto valore.
- Registro di audit a prova di manomissione: ogni firma, verifica, accesso e modifica di configurazione è concatenata con un hash, così il record non può essere alterato a posteriori.
- Metriche Prometheus in
/api/v1/metricse probe di liveness/readiness in/api/v1/health, pronte per il tuo stack di monitoraggio. - Webhook in uscita che inviano un evento JSON in POST a ogni operazione di firma, per collegare la firma a Slack, a un SIEM o a una dashboard di release.
- Specifica OpenAPI 3.1 in
/api/v1/openapi.jsoncon una Swagger UI interattiva in/api/v1/docs. - TLS 1.2+ con gestione opzionale delle challenge ACME / Let's Encrypt, più il firewall integrato per il filtraggio degli IP e la protezione dagli abusi.
Perché self-host
Lo scopo del server è ridurre una flotta di agenti di build rischiosi e portatori di chiavi a un unico endpoint blindato. La chiave di firma risiede solo sul server, o nell'HSM o nel KMS cloud a cui il server fa da frontend, mai sulle macchine che eseguono i tuoi script di build. L'accesso è regolato da token API per chiave con quote, limitati ai progetti, e ogni firma è registrata in un registro di audit che controlli tu. Ruotare un certificato, revocare la chiave di un agente compromesso o dimostrare chi ha firmato cosa diventano un unico posto da consultare invece di tanti.
Disponibilità
sgcSign Server fa parte di sgcSign 2026.6.0. Funziona come servizio Windows o come applicazione console, è configurato dall'unico file JSON mostrato sopra ed è gestito da curl, dalla CLI sgcsign inclusa o da qualsiasi client HTTP tramite la sua descrizione OpenAPI.
Domande, feedback o aiuto per la configurazione? Contattaci. Riceverai una risposta dalle persone che hanno scritto il codice.
