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:
- 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).
- 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.
- 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.
- 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.
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
securityContextIddecide 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
ignoreRevocationStatusUnknownaceita 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:
- Liste os certificados do usuário com o
listCertificates()do Web PKI. - Quando o usuário escolher um, leia a codificação dele com o
readCertificate()e assine o hash com osignHash(). - 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:
Failure | O que aconteceu | O que fazer |
|---|---|---|
CertificateFailedValidation | O certificado não é válido no contexto de segurança, por exemplo por estar revogado ou não ser confiável | Mostre os motivos, em ValidationResults |
StaleSession | A autenticação expirou antes de ser concluída: por padrão, uma autenticação dura 60 minutos | Prepare uma nova autenticação |
NonceReused | O estado já foi usado para concluir uma autenticação, o que pode indicar um ataque de replay | Prepare 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.
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.