Pular para o conteúdo principal

Autenticação com certificado - Rest PKI Core

Os usuários podem entrar na sua aplicação com o certificado digital deles. O Rest PKI Core faz a parte do backend do processo de login com certificado, e o Web PKI, a parte que roda no navegador:

  1. O seu servidor pede ao Rest PKI Core que prepare uma autenticação. O Rest PKI Core gera um nonce aleatório e retorna o hash a ser assinado e o estado da autenticação (state).
  2. Na sua página, o usuário escolhe um certificado, e o Web PKI assina o hash com ele. A página envia a codificação do certificado, a assinatura e o estado ao seu servidor.
  3. O seu servidor os envia ao Rest PKI Core, que conclui a autenticação: verifica a assinatura, valida o certificado e confere se o nonce já não foi usado.
  4. Se a autenticação for bem-sucedida, a sua aplicação localiza o usuário por um campo do certificado, como o CPF ou o e-mail, e conclui o login.
dica

Desse ponto em diante estaremos descrevendo chamadas ao Rest PKI Core. Para conseguir acompanhar, certifique-se de que já fez os Primeiros passos. A chave de API da aplicação precisa de um papel que permita autenticar usuários com certificados, como o Operador (veja Escolhendo os papéis). Fora do localhost, o Web PKI precisa de uma licença.

Preparando a autenticação​

Em .NET, chame IRestPkiService.PrepareAuthenticationAsync():

var prepareAuthResult = await restPkiService.PrepareAuthenticationAsync(securityContextId: securityContextId);

// Repasse estes valores à página
var state = prepareAuthResult.State;
var toSignHash = Convert.ToBase64String(prepareAuthResult.ToSign.Hash);
var digestAlgorithm = prepareAuthResult.ToSign.SignatureAlgorithm.DigestAlgorithm.Oid;
  • O securityContextId decide em quais certificados confiar. Se omitido, o Rest PKI Core usa o contexto de segurança padrão da organização ou, na falta dele, o da instância.
  • O ignoreRevocationStatusUnknown aceita certificados cujo status de revogação não pode ser determinado. Se omitido, vale a configuração da organização ou, na falta dela, a da instância.

O resultado traz o hash a assinar em ToSign.Hash, o algoritmo de hash em ToSign.SignatureAlgorithm.DigestAlgorithm e o estado em State, uma string opaca de que o Rest PKI Core precisa para concluir a autenticação. Preparar uma autenticação não grava nada no Rest PKI Core; por isso, você pode prepará-la toda vez que a sua página de login for exibida.

Em Java, chame RestPkiService.prepareAuthentication():

PrepareAuthenticationOptions options = new PrepareAuthenticationOptions();
options.setSecurityContext(SecurityContext.pkiBrazil);
PrepareAuthenticationResult prepareAuthResult = restPkiService.prepareAuthentication(options);

// Repasse estes valores à página
String state = prepareAuthResult.getState();
String toSignHash = prepareAuthResult.getToSignHash().getValueAsBase64();
String digestAlgorithm = prepareAuthResult.getToSignHash().getAlgorithm().getName();

Caso esteja chamando a API diretamente:

POST {endpoint}/api/v2/authentication
{
"securityContextId": "...",
"ignoreRevocationStatusUnknown": false
}

A resposta traz o hash a assinar em toSign.hash (em Base64), o algoritmo de hash em toSign.signatureAlgorithm.digestAlgorithmOid e o estado em state. Ela também repete o hash em toSignHash, para clientes mais antigos.

Assinando o hash na sua página​

O certificado do usuário nunca sai do computador dele; por isso, o Web PKI assina o hash no navegador:

  1. Liste os certificados do usuário com o listCertificates() do Web PKI.
  2. Quando o usuário escolher um, leia a codificação dele com o readCertificate() e assine o hash com o signHash().
  3. Envie a codificação do certificado e a assinatura, ambas em Base64, e o estado ao seu servidor, que conclui a autenticação.
pki.readCertificate({ thumbprint: thumbprint }).success(function (certificate) {
pki.signHash({
thumbprint: thumbprint, // o certificado escolhido pelo usuário
hash: toSignHash, // o hash a assinar, em Base64
digestAlgorithm: digestAlgorithm // o algoritmo de hash, como recebido do seu servidor
}).success(function (signature) {
// Envie o certificado, a assinatura (ambos em Base64) e o estado ao seu servidor
});
});

O estado é protegido pelo Rest PKI Core; por isso, você pode guardá-lo num campo oculto da página. Para o listCertificates(), o readCertificate() e o signHash(), veja os Primeiros passos do Web PKI.

Concluindo a autenticação​

Em .NET, chame IRestPkiService.CompleteAuthenticationAsync() com o estado, o certificado e a assinatura:

var authResult = await restPkiService.CompleteAuthenticationAsync(
state,
Convert.FromBase64String(certificate),
Convert.FromBase64String(signature)
);
if (authResult.Success) {
var userCert = authResult.Certificate;
// Localize o usuário por um campo do certificado, como userCert.PkiBrazil.Cpf ou userCert.EmailAddress, e conclua o login
} else {
// authResult.Failure diz o motivo
}

Quando Success é false, Failure diz o motivo:

FailureO que aconteceuO que fazer
CertificateFailedValidationO certificado não é válido no contexto de segurança, por exemplo por estar revogado ou não ser confiávelMostre os motivos, em ValidationResults
StaleSessionA autenticação expirou antes de ser concluída: por padrão, uma autenticação dura 60 minutosPrepare uma nova autenticação
NonceReusedO estado já foi usado para concluir uma autenticação, o que pode indicar um ataque de replayPrepare uma nova autenticação

Se a assinatura não corresponder ao hash, o que costuma indicar um erro na sua página, o Rest PKI Core responde com HTTP 422 e o código de erro BadSignature (veja Erros).

Em Java, chame RestPkiService.completeAuthentication():

CompleteAuthenticationOptions request = new CompleteAuthenticationOptions();
request.setCertificateFromBase64(certificate);
request.setSignatureFromBase64(signature);
request.setState(state);

AuthenticationResult authResult = restPkiService.completeAuthentication(request);
if (authResult.isSuccess()) {
// authResult.getCertificate() é o certificado do usuário
} else if (authResult.getFailure().equals(AuthenticationFailures.CERTIFICATEFAILEDVALIDATION)) {
// authResult.getValidationResults() diz por que o certificado foi recusado
} else {
// Prepare uma nova autenticação
}

Caso esteja chamando a API diretamente:

POST {endpoint}/api/v2/authentication/completion
{
"state": "...",
"certificate": "Base64EncodedCertificate==",
"signature": "Base64EncodedSignature=="
}

A resposta traz success, failure, o certificado do usuário em certificate e, quando o certificado foi validado, os resultados em validationResults.

observação

O Rest PKI Core também atende à API de autenticação do Rest PKI clássico (Api/Authentications), o que facilita levar ao Rest PKI Core uma aplicação que autentica com o Rest PKI. Veja Migração do Rest PKI para o Rest PKI Core.

Exemplos​

Ver em Markdown