Pular para o conteúdo principal

Certificate authentication - Rest PKI Core

Users can sign in to your application with their digital certificate. Rest PKI Core does the backend part of the certificate authentication process, and Web PKI the part that runs in the browser:

  1. Your server asks Rest PKI Core to prepare an authentication. Rest PKI Core generates a random nonce and returns the hash to sign and the authentication state.
  2. On your page, the user chooses a certificate, and Web PKI signs the hash with it. The page sends the certificate's encoding, the signature and the state to your server.
  3. Your server sends them to Rest PKI Core, which completes the authentication: it checks the signature, validates the certificate and checks that the nonce was not used before.
  4. If the authentication succeeds, your application finds the user by a field of the certificate, such as the CPF or the email address, and signs them in.
tip

From this point on we'll describe calls to Rest PKI Core. Make sure you've read the Get Started article to be able to keep up. The application's API key needs a role that allows certificate authentication, such as Worker (see Choosing roles). Outside of localhost, Web PKI needs a license.

Preparing the authentication​

On .NET, call IRestPkiService.PrepareAuthenticationAsync():

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

// Pass these to the page
var state = prepareAuthResult.State;
var toSignHash = Convert.ToBase64String(prepareAuthResult.ToSign.Hash);
var digestAlgorithm = prepareAuthResult.ToSign.SignatureAlgorithm.DigestAlgorithm.Oid;
  • securityContextId decides which certificates are trusted. If omitted, Rest PKI Core uses the subscription's default security context or, without one, the instance's.
  • ignoreRevocationStatusUnknown accepts certificates whose revocation status cannot be determined. If omitted, the subscription's setting applies or, without one, the instance's.

The result has the hash to sign in ToSign.Hash, its digest algorithm in ToSign.SignatureAlgorithm.DigestAlgorithm, and the state in State, an opaque string that Rest PKI Core needs to complete the authentication. Preparing stores nothing on Rest PKI Core, so you can prepare an authentication every time your login page is shown.

On Java, call RestPkiService.prepareAuthentication():

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

// Pass these to the page
String state = prepareAuthResult.getState();
String toSignHash = prepareAuthResult.getToSignHash().getValueAsBase64();
String digestAlgorithm = prepareAuthResult.getToSignHash().getAlgorithm().getName();

If calling the API directly, do:

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

The response has the hash to sign in toSign.hash (Base64), its digest algorithm in toSign.signatureAlgorithm.digestAlgorithmOid, and the state in state. It also repeats the hash in toSignHash, for older clients.

Signing the hash on your page​

The user's certificate never leaves their computer, so Web PKI signs the hash in the browser:

  1. List the user's certificates with Web PKI's listCertificates().
  2. When the user chooses one, read its encoding with readCertificate() and sign the hash with signHash().
  3. Send the certificate's encoding and the signature, both in Base64, and the state to your server, which completes the authentication.
pki.readCertificate({ thumbprint: thumbprint }).success(function (certificate) {
pki.signHash({
thumbprint: thumbprint, // the certificate chosen by the user
hash: toSignHash, // the hash to sign, in Base64
digestAlgorithm: digestAlgorithm // the digest algorithm, as given by your server
}).success(function (signature) {
// Send the certificate, the signature (both in Base64) and the state to your server
});
});

The state is protected by Rest PKI Core, so you can keep it in a hidden field of the page. For listCertificates(), readCertificate() and signHash(), see Web PKI's Get started.

Completing the authentication​

On .NET, call IRestPkiService.CompleteAuthenticationAsync() with the state, the certificate and the signature:

var authResult = await restPkiService.CompleteAuthenticationAsync(
state,
Convert.FromBase64String(certificate),
Convert.FromBase64String(signature)
);
if (authResult.Success) {
var userCert = authResult.Certificate;
// Find the user by a field of the certificate, such as userCert.PkiBrazil.Cpf or userCert.EmailAddress, and sign them in
} else {
// authResult.Failure says why
}

When Success is false, Failure says why:

FailureWhat happenedWhat to do
CertificateFailedValidationThe certificate is not valid under the security context, for instance it is revoked or not trustedShow the reasons, in ValidationResults
StaleSessionThe authentication expired before it was completed: by default, an authentication lasts 60 minutesPrepare a new authentication
NonceReusedThe state was already used to complete an authentication, which can mean a replay attackPrepare a new authentication

If the signature doesn't match the hash, usually an error on your page, Rest PKI Core answers with HTTP 422 and the error code BadSignature instead (see Errors).

On Java, call 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() is the user's certificate
} else if (authResult.getFailure().equals(AuthenticationFailures.CERTIFICATEFAILEDVALIDATION)) {
// authResult.getValidationResults() says why the certificate was rejected
} else {
// Prepare a new authentication
}

If calling the API directly, do:

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

The response has success, failure, the user's certificate in certificate and, when the certificate was validated, the results in validationResults.

note

Rest PKI Core also serves the authentication API of the classic Rest PKI (Api/Authentications), which eases moving an application that authenticates with Rest PKI to Rest PKI Core. See Moving from Rest PKI to Rest PKI Core.

Samples​

View as Markdown