Autenticação com certificado - PKI Express
Os usuários entram na sua aplicação com o certificado digital: o PKI Express emite um nonce (um valor aleatório), o
Web PKI o assina com o certificado do usuário no navegador, e o PKI Express valida a assinatura e o certificado.
O PKI Express acrescentou isso na 1.4.0, com os comandos start-auth e complete-auth.
O código é Java, dos samples do PKI Suite, com o com.lacunasoftware.pkiexpress:pki-express
(1.20.0); o script do navegador é o mesmo no sample em Node.js.
Para o método em si, veja Login com certificado digital no guia de soluções para certificação digital.
Fluxo
- Servidor:
start()devolve o nonce e o algoritmo de hash; a página recebe os dois em campos ocultos. - Navegador: o Web PKI lista os certificados do usuário, lê o que ele escolher e assina o nonce com
signData(); o script preenche o certificado e a assinatura e envia o formulário. - Servidor:
complete()com o nonce, o certificado e a assinatura devolve os resultados da validação e o certificado. - Servidor: se os resultados forem válidos, encontre o seu usuário por um campo do certificado e faça o login dele.
1. Iniciar a autenticação
Authentication auth = new Authentication();
Util.setPkiDefaults(auth);
AuthStartResult result = auth.start();
Util.setNoCacheHeaders(response);
model.addAttribute("nonce", result.getNonce());
model.addAttribute("digestAlgorithm", result.getDigestAlgorithm());
- O nonce vale para uma única tentativa de autenticação. O sample envia headers que impedem o navegador de guardar a página em cache
(
Cache-Control: no-cache, no-store, must-revalidate,Pragma: no-cache,Expires: -1), para que o botão voltar não mostre um nonce antigo. Util.setPkiDefaults()aplica as raízes confiáveis, que decidem quais certificados são aceitos (veja Quais certificados são confiáveis).- O PKI Express guarda os nonces que emitiu em um repositório de nonces, a
transferDataFolder(por padrão, a pasta temporária), para verificá-los nocomplete(). Para guardar os nonces no seu próprio repositório e verificá-los você mesmo, ative o armazenamento externo. A biblioteca Python (1.10.4) inverte essa opção: ela só passa o repositório de nonces quando o armazenamento externo está ativo. TODO(docs): se o PKI Express verifica a reutilização do nonce quando nenhum repositório de nonces é informado.
2. Assinar o nonce no navegador
A página coloca nonce e digestAlgorithm em campos ocultos, com campos para o certificado (certContent) e para a assinatura
(signature).
Quando o usuário entra, o script lê o certificado escolhido, assina o nonce com signData() e envia o formulário:
var selectedCertThumbprint = formElements.certificateSelect.val();
pki.readCertificate(selectedCertThumbprint).success(function (certEncoded) {
pki.signData({
thumbprint: formElements.certificateSelect.val(),
data: formElements.nonceField.val(),
digestAlgorithm: formElements.digestAlgorithmField.val()
}).success(function (signature) {
formElements.signatureField.val(signature);
formElements.certContentField.val(certEncoded);
formElements.form.submit();
});
});
- O nonce é o dado a assinar, não um hash, por isso o script usa
signData, e nãosignHash. Veja Qual é a diferença entre as funções signData e signHash?. - Antes disso, o script inicializa o Web PKI com
pki.init()e lista os certificados comlistCertificates(), marcando os vencidos.
3. Concluir a autenticação
Authentication auth = new Authentication();
Util.setPkiDefaults(auth);
auth.setNonce(nonce);
auth.setCertificateBase64(certContent);
auth.setSignature(signature);
AuthCompleteResult result = auth.complete();
ValidationResults vr = result.getValidationResults();
if (!vr.isValid()) {
String vrHtml = vr.toString()
.replaceAll("\n", "<br>")
.replaceAll("\t", " ");
model.addAttribute("vrHtml", vrHtml);
return "authentication-express/failed";
}
model.addAttribute("userCert", result.getCertificate());
- Aplique as mesmas configurações de confiança do início: o sample chama
Util.setPkiDefaults()nas duas etapas. - As outras bibliotecas dão outros nomes às entradas: Node.js
setNonce,setCertificateFromBase64(devolve uma Promise) esetSignature; PHPsetNonce,setCertificateBase64esetSignature; Python as propriedadesnonce_base64,certificate_base64esignature_base64. - Um nonce desconhecido falha com o código de retorno 28 (
NonceNotFound), e uma assinatura inválida com o 08 (BadSignature). Veja os códigos de retorno.
4. Fazer o login do usuário
Quando os resultados são válidos, procure o seu usuário por um dos campos do certificado, como getEmailAddress() ou, em certificados
ICP-Brasil, getPkiBrazil().getCpf(); qual campo usar depende da sua aplicação.
A página de sucesso do sample mostra o nome comum do titular, o e-mail, o tipo de certificado ICP-Brasil, CPF, responsável, empresa, CNPJ,
RG e OAB.
Veja também
- Validar assinaturas
- Login com certificado digital no guia de soluções para certificação digital
- Referência rápida do PKI Express