Referência rápida do PKI Express
O essencial do PKI Express em uma página, com links para as páginas completas.
Para que serve
O PKI Express cria assinaturas digitais CMS/CAdES, PDF/PAdES e XmlDSig/XAdES a partir de praticamente qualquer linguagem de programação, nos seus próprios servidores Windows ou Linux. Você o instala no servidor e o aciona por uma biblioteca cliente para Java, Node.js, PHP, Python ou Ruby; para assinar com o certificado do usuário numa página web, ele trabalha junto com o Web PKI.
| Alternativa | Quando é a melhor escolha |
|---|---|
| PKI SDK | Sua aplicação é .NET: o PKI SDK é uma biblioteca para aplicações .NET, e o guia de certificação digital o recomenda para assinaturas no servidor em .NET |
| Rest PKI Core | Você prefere chamar uma API REST a instalar software nos seus servidores: use-o como serviço em core.pki.rest ou numa instância própria; ele também hospeda a página em que o usuário assina |
| Web PKI | Você precisa da parte do navegador: listar os certificados do usuário e assinar com eles numa página web. Ele complementa o PKI Express, em vez de substituí-lo |
| Signer | Você quer enviar documentos para pessoas e colher as assinaturas delas com um fluxo pronto, como SaaS ou on-premises, em vez de construir o fluxo |
Instalação
Duas partes: o próprio PKI Express, em cada servidor que executa a sua aplicação, e o pacote cliente da sua linguagem.
| Linguagem | Pacote | Major atual | Registro |
|---|---|---|---|
| PKI Express, Windows Server 2008 R2+ / Windows 7+ (requer o .NET Framework 4.6.1) | Instalador pkie-1.38.0-x64.msi; pacotes x86 e zip na página de instalação | 1 (1.38.0) | cdn.lacunasoftware.com |
| PKI Express, Linux (Ubuntu/Mint, RHEL, CentOS/Oracle Linux/Fedora) | pkie-1.38.0.tar.gz (instalação) | 1 (1.38.0) | cdn.lacunasoftware.com |
| Java | com.lacunasoftware.pkiexpress:pki-express | 1 (1.23.1) | Maven Central |
| Node.js | pki-express | 1 (1.16.2) | npm |
| PHP 5.5+ | lacuna/pki-express | 1 (1.17.0) | Packagist |
| Python | pkiexpress | 1 (1.10.4) | PyPI |
| Ruby | pki_express | 1 (1.3.2) | RubyGems |
No Linux, extraia o pacote em /usr/share/pkie, crie um link para /usr/share/pkie/pkie em /usr/local/bin, configure a pasta de logs e execute sudo pkie activate LacunaPkiLicense.config; as páginas de Ubuntu, RHEL e CentOS trazem os comandos. Para atualizar, execute o novo instalador (Windows) ou substitua o conteúdo de /usr/share/pkie pelo novo pacote (Linux).
Configuração e autenticação
Licença, sem chave de API. O PKI Express precisa de um arquivo de licença, LacunaPkiLicense.config; peça à Lacuna uma licença de testes gratuita. Ative-a uma vez em cada máquina: com pkie activate no Linux (ativação manual se a ativação pela rede falhar) e com o PKI Express Configuration Manager (pkiemgr.exe, na pasta de instalação) no Windows. A sua aplicação não lê a licença, e não há URL de serviço: a biblioteca cliente executa o PKI Express instalado na mesma máquina.
As configurações do servidor são definidas com pkie config --set name=value (com privilégios de administrador); pkie config --effective mostra os valores em uso.
| Configuração | Chaves | Página |
|---|---|---|
| Pasta e nível mínimo de log | logDir, logLevel | Logs |
| Pasta temporária (cache de LCRs e de certificados de AC) | tempDir | Pasta temporária |
| Proxy | proxyHost, proxyPort, proxyUsername, proxyPassword | Proxy |
LAPP, para obter LCRs e certificados de AC por meio de *.lacunasoftware.com (o suporte também precisa autorizar o acesso) | lappEnabled | LAPP |
| Chaves no Azure Key Vault | azureAppId, azureAppSecret, azureKeyVaultEndpoint | Azure |
| Certificados em nuvem (BirdID, NeoID, RemoteID, SafeID, VIDaaS e outros) | trustServices:<service>:clientId, trustServices:<service>:clientSecret, trustServices:<service>:endpoint | Certificados em nuvem |
| Chaves em tokens e HSMs PKCS#11 | pkcs11LibraryPath | Histórico de versões, 1.38.0 |
TODO(docs): o pkcs11LibraryPath (PKI Express 1.38.0) não tem página de configuração; só o histórico de versões o cita, e nem as bibliotecas cliente nem um texto de ajuda publicado o descrevem.
No seu código, toda classe de operação herda de PkiExpressOperator, cujas configurações os exemplos aplicam num único helper, Util.setPkiDefaults(), chamado por todos os blocos abaixo:
- em que confiar: por padrão, só em certificados ICP-Brasil; adicione raízes com
addTrustedRootSync(), ou a raiz de teste da Lacuna comtrustLacunaTestRoot(confiando em certificados que não sejam da ICP-Brasil); timestampAuthority, umTimestampAuthoritypara as políticas que exigem carimbo de tempo: os exemplos usam o do REST PKI,https://pki.rest/tsp/a402df41-8559-47b2-a05c-be555bf66310, com um token de acesso do REST PKI (setOAuthTokenAuthentication()); usuário e senha, e SSL mútuo, também funcionam (autoridade de carimbo de tempo);offline, para executar sem acesso à rede.
Cada classe também aceita um PkiExpressConfig opcional (pasta do PKI Express, pasta temporária, pasta dos arquivos de transfer data): sem ele, as bibliotecas procuram o PKI Express nas pastas de instalação padrão do Windows e executam o pkie do PATH no Linux. No Linux, só a biblioteca de Java consegue executar o PKI Express 1.31.0 ou posterior a partir de uma pasta personalizada; veja configurações da biblioteca cliente.
Operações principais
Os blocos são trechos dos exemplos em Node.js (nodejs/expressmvc/routes/ no PkiSuiteSamples), a linguagem com mais exemplos do PKI Express. Os nomes das políticas vêm de StandardSignaturePolicies e diferem dos do Rest PKI: veja a tabela de equivalência.
TODO(docs): além do passo a passo em Java (como funciona) e do mapa do projeto PHP (exemplos em PHP), nenhuma página documenta estas operações; o código abaixo vem dos exemplos.
Assinar um PDF com o certificado do usuário
PAdES com a chave no computador do usuário, em duas etapas no servidor: PadesSignatureStarter.start() retorna o hash que o Web PKI assina no navegador (signHash()), e SignatureFinisher.complete() grava o PDF assinado. Passo a passo em Java: como funciona; aparência da assinatura: representação visual.
// POST /start: certContent is the user's certificate, read by Web PKI
const signatureStarter = new PadesSignatureStarter();
Util.setPkiDefaults(signatureStarter);
signatureStarter.signaturePolicy = StandardSignaturePolicies.PADES_BASIC_WITH_LTV;
signatureStarter.setPdfToSignFromPathSync(StorageMock.getDataPath(fileId));
signatureStarter.setCertificateFromBase64Sync(certContent);
signatureStarter.start().then((response) => { /* toSignHash, digestAlgorithm, transferFile */ });
// POST /complete: signature is the result of Web PKI's signHash()
const signatureFinisher = new SignatureFinisher();
Util.setPkiDefaults(signatureFinisher);
signatureFinisher.setFileToSignFromPathSync(StorageMock.getDataPath(fileId));
signatureFinisher.setTransferFileFromPathSync(transferFile);
signatureFinisher.signature = signature;
signatureFinisher.outputFile = path.join(APP_ROOT, 'app-data', outputFile);
signatureFinisher.complete(true).then((result) => { /* signed PDF at outputFile */ });
Assinar um PDF com uma chave no servidor
Uma etapa, sem navegador: PadesSigner.sign() assina com um arquivo PKCS #12 no servidor.
const signer = new PadesSigner();
Util.setPkiDefaults(signer);
signer.signaturePolicy = StandardSignaturePolicies.PADES_BASIC_WITH_LTV;
await signer.setPdfToSignFromPath(StorageMock.getDataPath(fileId));
await signer.setPkcs12FromPath(StorageMock.getSamplePkcs12Path());
signer.certPassword = '1234';
signer.outputFile = path.join(APP_ROOT, 'app-data', outputFile);
let signerCert = await signer.sign(true);
Assinar um arquivo com CAdES
O CadesSignatureStarter segue o mesmo fluxo de início e conclusão, finalizado pelo SignatureFinisher (saída .p7s); se o arquivo já for um CMS, o PKI Express o coassina.
const signatureStarter = new CadesSignatureStarter();
Util.setPkiDefaults(signatureStarter);
signatureStarter.signaturePolicy = StandardSignaturePolicies.PKI_BRAZIL_CADES_ADR_BASICA;
signatureStarter.setFileToSignFromPathSync(StorageMock.getDataPath(fileId));
signatureStarter.setCertificateFromBase64Sync(certContent);
signatureStarter.start().then((response) => { /* same as the PDF flow */ });
Assinar um documento XML
XmlSigner.sign() assina com uma chave no servidor; com o certificado do usuário, use XmlSignatureStarter e SignatureFinisher, como no fluxo do PDF.
const signer = new XmlSigner();
Util.setPkiDefaults(signer);
signer.signaturePolicy = StandardSignaturePolicies.XADES_BES;
await signer.setXmlToSignFromPath(StorageMock.getSampleDocPath(SampleDocs.SAMPLE_XML));
await signer.setPkcs12FromPath(StorageMock.getSamplePkcs12Path());
signer.certPassword = '1234';
signer.outputFile = path.join(APP_ROOT, 'app-data', outputFile);
let signerCert = await signer.sign(true);
Validar um PDF assinado
PadesSignatureExplorer.open() retorna as assinaturas do arquivo e, com validate = true, as valida; o CadesSignatureExplorer faz o mesmo para CMS/CAdES.
const sigExplorer = new PadesSignatureExplorer();
Util.setPkiDefaults(sigExplorer);
sigExplorer.validate = true;
sigExplorer.setSignatureFileFromPathSync(filePath);
sigExplorer.signaturePolicy = StandardSignaturePolicies.PADES_BASIC;
sigExplorer.open().then((r) => res.render('open-pades-express', { signature: r }));
Aplicar carimbo de tempo a um PDF
PadesTimestamper.stamp() aplica um carimbo de tempo a um PDF, usando a autoridade de carimbo de tempo do operador.
const stamper = new PadesTimestamper();
Util.setPkiDefaults(stamper);
stamper.setPdfFromPath(pdfPath).then(() => {
stamper.setOutputFilePath(outputFilePath);
stamper.stamp().then(() => { /* timestamped PDF at outputFilePath */ });
});
Gerar uma versão para impressão
Depois de abrir as assinaturas com o PadesSignatureExplorer, PdfMarker.apply() aplica ao PDF textos e imagens montados com o PdfHelper, como os nomes dos signatários e um código de verificação.
const pdfMarker = new PdfMarker();
Util.setPkiDefaults(pdfMarker);
pdfMarker.setFileFromPathSync(pdfPath);
const pdf = new PdfHelper();
pdfMarker.marks.push(pdf.mark().onAllPages()
.onContainer(pdf.container().width(1).anchorRight(1).height(1).anchorBottom(1))
.addElement(pdf.imageElement().withOpacity(75).withImageContent(Util.getIcpBrasilLogoContent(), 'image/png')));
pdfMarker.outputFile = path.join(APP_ROOT, 'app-data', outputFile);
pdfMarker.apply();
Autenticar com um certificado
Authentication.start() retorna um nonce e um algoritmo de digest para o Web PKI assinar; complete() verifica a assinatura e valida o certificado.
const auth = new Authentication();
Util.setPkiDefaults(auth);
auth.setNonce(nonce); // from auth.start(), signed in the browser by Web PKI
await auth.setCertificateFromBase64(certContent);
auth.setSignature(signature);
const result = await auth.complete();
if (result.validationResults.isValid()) { const userCert = result.certificate; }
Erros
Toda operação do PKI Express termina com um código de retorno, 00 - Ok ou um erro de 01 a 43; assinaturas, autenticações e inspeções com validação também informam erros de validação, como CertificateChainRootNotTrusted. Lista completa: códigos de retorno.
Em Node.js, uma operação que falha rejeita a sua promise com um CommandError cujo code é o código de retorno (ValidationError para o código 14, InstallationNotFoundError quando o PKI Express não é encontrado); os exemplos o repassam para next(err). O PHP lança CommandException ($e->returnCode), o Ruby PkiExpress::CommandError (e.code.exitstatus); Java e Python lançam uma exceção simples, com a saída na mensagem: veja códigos de retorno nas bibliotecas cliente.
| Erro | Significado | O que fazer |
|---|---|---|
17 - NotActivated | O PKI Express não está ativado nesta máquina | Ative-o com a licença (instalação) |
14 - ValidationFailed com CertificateChainRootNotTrusted | A raiz do certificado não é confiável; por padrão, só a ICP-Brasil é | Confie na raiz: trustLacunaTestRoot ou addTrustedRootSync() (confiando em certificados que não sejam da ICP-Brasil) |
CertificateRevocationStatusUnknown | O PKI Express não conseguiu acessar as LCRs do certificado | Configure o proxy ou o LAPP |
32 - TimestampOptionsRequired | Nenhuma autoridade de carimbo de tempo foi informada, e a política exige carimbo de tempo | Defina o timestampAuthority do operador (autoridade de carimbo de tempo) |
Certificados e credenciais de teste
- Certificados de teste: arquivos PKCS #12 da ICP de testes da Lacuna, senha
1234; nunca confie nessa ICP em produção. - O PKI Express só os aceita depois que você confia na raiz de teste da Lacuna:
trustLacunaTestRoot(Node.js, Java, PHP) outrust_lacuna_test_root(Python, Ruby). - Licença: solicite uma licença de testes gratuita e ative-a como em Configuração e autenticação.
Experimente
Rode as demos ou comece por um exemplo na sua linguagem: