Pular para o conteúdo principal

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​

  1. Servidor: start() devolve o nonce e o algoritmo de hash; a página recebe os dois em campos ocultos.
  2. 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.
  3. Servidor: complete() com o nonce, o certificado e a assinatura devolve os resultados da validação e o certificado.
  4. 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 no complete(). 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();
});
});

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", "&nbsp;&nbsp;&nbsp;&nbsp;");
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) e setSignature; PHP setNonce, setCertificateBase64 e setSignature; Python as propriedades nonce_base64, certificate_base64 e signature_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​

Ver em Markdown