A assinatura de código tem um problema de gerenciamento de chaves. A configuração habitual copia um arquivo .pfx, ou conecta um token USB, em cada agente de build que precisa assinar uma release. A chave privada acaba em máquinas que executam scripts de build não confiáveis, não há registro do que foi assinado ou por quem, e rotacionar o certificado significa mexer em cada agente. O sgcSign 2026.6 responde a isso com um novo servidor de assinatura: um daemon auto-hospedado que expõe a assinatura por meio de uma API REST TLS, para que seus pipelines e desenvolvedores assinem remotamente enquanto a chave de assinatura permanece em exatamente um lugar.
A chave nunca sai do servidor. Melhor ainda, o servidor pode estar à frente de um token de hardware ou de um KMS na nuvem, de modo que a chave nunca exista como arquivo. Toda requisição é autenticada com uma chave de API, tem limite de taxa e é gravada em um log de auditoria à prova de adulteração. Este post aborda o que o servidor pode assinar, como configurá-lo, um início rápido de cinco minutos e as duas formas de chamá-lo: curl simples e o cliente de linha de comando sgcsign incluído.
O que ele assina
Um servidor, uma API, oito formatos de assinatura. O mesmo formato de endpoint (POST /api/v1/sign/<format>) cobre tanto executáveis quanto documentos:
- Authenticode — arquivos PE do Windows:
.exe,.dll,.sys,.msi,.cab,.ocx. Assinatura dupla opcional SHA-1 + SHA-256 para Windows legado. - PAdES — documentos PDF, com motivo, localização, contato e nome do signatário.
- XAdES — XML, enveloped, enveloping ou detached, com perfis de faturamento eletrônico de cada país, como eIDAS, FacturaE, FatturaPA, KSeF, Peppol, VeriFactu e TicketBAI.
- CAdES — PKCS#7 detached (
.p7s) sobre qualquer payload. - ClickOnce — manifestos de aplicação e de implantação.
- NuGet — assinatura de pacotes
.nupkg. - VSIX — pacotes de extensão do Visual Studio.
- PowerShell — scripts
.ps1/.psm1/.psd1(Authenticode SIP).
Todo formato aceita uma URL de timestamp RFC 3161 opcional, de modo que as assinaturas permaneçam válidas após o certificado de assinatura expirar. Um endpoint complementar POST /api/v1/verify verifica uma assinatura existente e retorna o subject do signatário, a validade e o timestamp.
Provedores de chave plugáveis
Um provedor é um handle nomeado para uma chave de assinatura. O chamador nomeia um provedor em cada requisição; ele nunca vê a chave. Você pode registrar quantos precisar, e o mesmo servidor pode combinar um PFX local para ferramentas internas com um certificado EV respaldado pela nuvem para releases públicas. São suportados nove tipos de provedor:
- Windows Certificate Store (
WinCertStore) — seleciona um certificado por thumbprint ou subject, ideal para certificados EV registrados em um token. - PFX e PEM — arquivos de certificado e chave em disco.
- PKCS#11 / HSM (
PKCS11) — tokens de hardware como o YubiKey, ou um HSM de rede. - AWS KMS, Azure Trusted Signing, Google Cloud KMS, HashiCorp Vault e Certum SimplySign — a chave privada reside no serviço de nuvem e nunca chega ao servidor.
Os segredos ficam fora do arquivo de configuração. Qualquer parâmetro cujo nome termina em _env é lido de uma variável de ambiente, de modo que a senha do PFX, o PIN do token ou o segredo da nuvem é fornecido pelo ambiente do serviço, não gravado em disco.
Configurando o servidor
Todo o servidor é controlado por um único arquivo JSON, sgcSignServer.conf.json (um exemplo documentado é fornecido como sgcSignServer.conf.sample.json). A estrutura de nível superior é um punhado de blocos:
{
"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/"
}
}
]
}
Os blocos mapeiam diretamente para os recursos. server define o endereço de bind, a porta (8443 por padrão), o certificado TLS e o firewall integrado (listas de permissão e negação de IP, bloqueio por força bruta, limitação de taxa de conexões, proteções contra path-traversal e payload). storage aponta para o banco de dados SQLite que armazena usuários, chaves de API, o log de auditoria e a fila de webhooks. admin define o primeiro usuário e quanto tempo as sessões duram. audit define a janela de retenção. providers é a lista acima.
A senha de administrador de bootstrap nunca é armazenada no arquivo. Na primeira inicialização, quando a tabela de usuários está vazia, o servidor lê a variável de ambiente indicada por initial_password_env (padrão SGCSIGN_ADMIN_INIT_PW) e cria a conta de administrador. Em cada inicialização posterior, essa variável é ignorada, de modo que ela só semeia o primeiro login.
Início rápido em cinco minutos
Instale o servidor (o assistente de instalação registra o serviço do Windows, ou execute sgcSignServer.exe --install) e então:
1. Crie um certificado de assinatura de código de teste e exporte-o como um PFX. Para uma implantação real, você importa seu certificado emitido pela CA, ou pula esta etapa e aponta um provedor para o seu token ou KMS na nuvem.
$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. Defina os segredos como variáveis de ambiente da máquina para que a conta de serviço possa lê-los:
setx /M SGCSIGN_ADMIN_INIT_PW "ChangeMeNow!"
setx /M SGCSIGN_PFX_PW "QuickStartPFX!"
3. Escreva uma configuração mínima com um provedor PFX (TLS desligado apenas para um teste em 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. Inicie o serviço e confirme que ele está escutando:
sc start sgcSignServer
sc query sgcSignServer
Se ele parar na inicialização, execute-o em primeiro plano com sgcSignServer.exe --console --config <path> para ver o erro ao vivo (uma SGCSIGN_ADMIN_INIT_PW ausente ou um PFX ilegível são as causas usuais). A flag --selftest-providers carrega a configuração, inicializa todos os provedores e sai, para que você possa validar as chaves antes de entrar em produção.
5. Faça login e crie uma chave de API. Abra http://localhost:8443/admin, entre como admin com a senha de bootstrap e crie uma chave de API. A chave em texto puro é exibida uma única vez na criação; copie-a imediatamente. As chaves carregam o prefixo sgcsk_.
6. Assine um executável de teste com 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
Esse é o ciclo completo: configurar um provedor, emitir uma chave, assinar. Daqui você troca o PFX autoassinado por um certificado real, liga o TLS e tranca o firewall na sub-rede do seu CI.
Assinatura via REST
Toda requisição de assinatura é um POST com o arquivo e alguns campos de formulário. A autenticação é um único header, seja X-API-Key: sgcsk_... ou Authorization: Bearer sgcsk_.... A resposta é o artefato assinado como application/octet-stream, com o subject do signatário e a duração da assinatura retornados nos headers X-Sgcsign-Signer-Subject e X-Sgcsign-Duration-Ms.
Assinando um PDF, com motivo e localização de assinatura visíveis:
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
Assinando uma fatura XML com um perfil 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
Verificar uma assinatura retorna JSON em vez de um arquivo:
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" }
O cliente de linha de comando sgcsign
O servidor vem com sgcsign, uma pequena CLI multiformato com quatro verbos: sign, verify, keys e health. A URL do servidor, a chave de API e o provedor podem vir de flags ou das variáveis de ambiente SGCSIGN_SERVER, SGCSIGN_APIKEY e SGCSIGN_PROVIDER, o que mantém os segredos fora da linha de comando no 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
Para o Authenticode há um truque que economiza largura de banda. Com o modo pré-hash (--prehash, ativado por padrão) a CLI calcula o hash do PE localmente e envia apenas o hash, algumas centenas de bytes em vez de um binário de vários megabytes. O servidor assina o hash e retorna um blob PKCS#7 detached, que o cliente incorpora no arquivo. Em um agente de CI com largura de banda limitada assinando um instalador grande, isso transforma um upload de vários megabytes em um minúsculo.
Segurança e operações
O servidor foi construído para rodar sem supervisão à frente de uma chave de assinatura real, então a superfície operacional importa tanto quanto a criptografia:
- Console de administração em
/admin: dashboard, chaves de API, provedores, usuários, projetos e a trilha de auditoria, tudo no navegador. - Chaves de API com limites de taxa por chave e cotas diárias. Uma chave que atinge seu limite recebe
429com um headerRetry-After. - Projetos multi-tenant, de modo que uma chave restrita a uma equipe não pode usar os provedores de outra equipe.
- Fluxo de aprovação (opcional): um fluxo de duas etapas em que uma requisição de assinatura fica retida até que um operador a aprove, para certificados de release de alto valor.
- Log de auditoria à prova de adulteração: cada assinatura, verificação, login e alteração de configuração é encadeada com um hash, de modo que o registro não pode ser alterado posteriormente.
- Métricas Prometheus em
/api/v1/metricse probes de liveness/readiness em/api/v1/health, prontas para a sua stack de monitoramento. - Webhooks de saída que fazem POST de um evento JSON em cada operação de assinatura, para integrar a assinatura ao Slack, a um SIEM ou a um dashboard de release.
- Especificação OpenAPI 3.1 em
/api/v1/openapi.jsoncom uma Swagger UI interativa em/api/v1/docs. - TLS 1.2+ com serviço opcional de challenge ACME / Let's Encrypt, além do firewall integrado para filtragem de IP e proteção contra abuso.
Por que auto-hospedar
O propósito do servidor é reduzir uma frota de agentes de build arriscados, portadores de chaves, a um único endpoint endurecido. A chave de assinatura reside apenas no servidor, ou no HSM ou KMS na nuvem que o servidor representa, nunca nas máquinas que executam seus scripts de build. O acesso é controlado por tokens de API por chave com cotas, restritos a projetos, e cada assinatura é registrada em um log de auditoria que você controla. Rotacionar um certificado, revogar a chave de um agente comprometido ou provar quem assinou o quê passam a ser um único lugar para verificar, em vez de muitos.
Disponibilidade
O sgcSign Server faz parte do sgcSign 2026.6.0. Ele roda como um serviço do Windows ou como uma aplicação de console, é configurado pelo único arquivo JSON mostrado acima e é controlado a partir do curl, da CLI sgcsign incluída, ou de qualquer cliente HTTP por meio de sua descrição OpenAPI.
Dúvidas, feedback ou ajuda para colocá-lo em funcionamento? Entre em contato. Você receberá uma resposta das pessoas que escreveram o código.
