Integração do Web PKI com o Rest PKI
Com o Rest PKI, o seu backend nunca lida com os dados a assinar: ele inicia a assinatura no Rest PKI e
recebe um token, a sua página passa esse token ao signWithRestPki() do Web PKI, e o Web PKI troca os dados da assinatura
diretamente com o Rest PKI. Depois, o seu backend finaliza a assinatura com o mesmo token e recebe o documento assinado. A
autenticação com certificado funciona da mesma forma.
O Rest PKI Core também atende essas APIs do Rest PKI, então a mesma página funciona com ele, desde que saiba onde está a instância (veja O endereço do Rest PKI). O Rest PKI Core tem ainda APIs mais novas, que assinam com o Web PKI de outras formas: veja Com as APIs mais novas do Rest PKI Core.
O Rest PKI é um produto legado: continua recebendo correções de bugs e de segurança, mas novas integrações em nuvem devem usar o Rest PKI Core.
Como funciona
| # | Quem | O quê |
|---|---|---|
| 1 | Seu backend → Rest PKI | Inicia a assinatura (por exemplo, PadesSignatureStarter.StartWithWebPkiAsync() em .NET), autenticado com o seu access token ou API key. O Rest PKI devolve um token. |
| 2 | Seu backend → página | Mostra a página de assinatura com o token. |
| 3 | Página | Chama o init(), lista os certificados do usuário com o listCertificates() e, quando o usuário escolhe um, chama o signWithRestPki() com o token e o thumbprint do certificado. |
| 4 | Web PKI → Rest PKI | A partir do computador do usuário, obtém a assinatura pendente (GET Api/PendingSignatures/{token}) e envia o certificado (POST Api/PendingSignatures/{token}/Certificate). O Rest PKI valida o certificado com o contexto de segurança da assinatura e devolve o hash a assinar. |
| 5 | Web PKI → Rest PKI | Assina o hash com a chave privada do certificado e envia a assinatura (POST Api/PendingSignatures/{token}). |
| 6 | Página → seu backend → Rest PKI | A página envia o token ao seu backend, que finaliza a assinatura (por exemplo, PadesSignatureFinisher2.FinishAsync()) e recebe o documento assinado e o certificado do signatário. |
Ou seja:
- O seu access token fica no seu servidor. A página só vê o token daquela assinatura, que vale uma única vez.
- As rotas que o Web PKI chama não exigem access token e aceitam chamadas de qualquer origem: o token identifica a assinatura.
- O computador do usuário precisa acessar o Rest PKI, não só o seu servidor. Veja Requisitos de rede.
- Se o Rest PKI não aceitar o certificado (por exemplo, porque o contexto de segurança não confia nele), o erro volta para a
página, no
signWithRestPki().
O código da página
Inicialize o Web PKI, liste os certificados e, quando o usuário clicar em Assinar, chame o signWithRestPki() com o token
que o seu backend colocou na página. Quando a chamada terminar, envie o token de volta ao seu backend:
var pki = new LacunaWebPKI(webPkiLicense); // dispensável com o Rest PKI em nuvem, veja "Licença" abaixo
pki.init({
restPkiUrl: restPkiUrl, // só para um Rest PKI on-premises ou o Rest PKI Core, veja abaixo
ready: loadCertificates,
defaultFail: onWebPkiFail
});
function loadCertificates() {
pki.listCertificates({ selectId: 'certificateSelect' });
}
function sign() {
pki.signWithRestPki({
token: token, // devolvido pelo Rest PKI quando o seu backend iniciou a assinatura
thumbprint: document.getElementById('certificateSelect').value
}).success(function () {
document.getElementById('signForm').submit(); // o seu backend finaliza a assinatura com o token
});
}
function onWebPkiFail(ex) {
alert(ex.userMessage + ' (' + ex.code + ')');
}
Os exemplos têm o código do backend em cada linguagem, e você pode testar a página no JSFiddle.
O endereço do Rest PKI
O Web PKI precisa saber qual instância do Rest PKI chamar. Informe-a na opção restPkiUrl do
init():
| Rest PKI | restPkiUrl |
|---|---|
| Rest PKI em nuvem (https://pki.rest) | Não informe |
| Rest PKI on-premises | O endereço da sua instância, como 'https://restpki.suaempresa.com.br/' |
| Rest PKI Core, em nuvem ou on-premises | O endpoint da sua instância, como 'https://core.pki.rest/' |
pki.init({
restPkiUrl: 'https://restpki.suaempresa.com.br/',
ready: onWebPkiReady
});
Sem o restPkiUrl, o Web PKI acessa a instância em nuvem pela URL https://restpki.lacunasoftware.com/, um endereço
alternativo de https://pki.rest que, por ser mais convencional, tem uma chance menor de ser bloqueado pelos firewalls das
redes dos usuários.
Se o Web PKI não for utilizado com o Rest PKI, o restPkiUrl é desnecessário.
Requisitos de rede
Como o Web PKI chama o Rest PKI a partir do computador do usuário:
- Com o Rest PKI em nuvem, as redes dos usuários precisam liberar o domínio
restpki.lacunasoftware.comem HTTPS. - Com uma instância própria (Rest PKI on-premises ou Rest PKI Core), ela precisa ser acessível a partir dos computadores dos
usuários, não só do seu servidor. Para evitar bloqueios, o endereço dela deve:
- usar um nome de host, não um endereço IP;
- usar HTTPS com um certificado SSL válido, emitido por uma Autoridade Certificadora em que os sistemas operacionais confiam por padrão (com um certificado inválido, as chamadas falham sem mensagem de erro);
- usar uma porta padrão (443).
Para verificar, abra /Api/System/Info da instância em um navegador no computador do usuário, como
https://restpki.lacunasoftware.com/Api/System/Info. Veja Erro "Could not get pending signature".
Licença
| Rest PKI | Licença do Web PKI |
|---|---|
| Rest PKI em nuvem (https://pki.rest) | Não é necessária, nem em produção |
| Rest PKI on-premises | Necessária fora do localhost |
Rest PKI Core, inclusive em nuvem (core.pki.rest) | Necessária fora do localhost |
Veja Licenciamento.
Teste no JSFiddle
O exemplo abaixo é a página de uma assinatura do Rest PKI: cole um token, escolha um certificado e assine. Para obter um token
sem escrever um backend, inicie uma assinatura CAdES do texto "Hello, World!" com o curl, usando o seu access token do Rest PKI:
curl -X POST https://pki.rest/Api/CadesSignatures \
-H "Authorization: Bearer SEU_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"contentToSign": "SGVsbG8sIFdvcmxkIQ==", "signaturePolicyId": "a4522485-c9e5-46c3-950b-0d6e951e17d1", "securityContextId": "803517ad-3bbc-4169-b085-60053a8f6dbf"}'
A resposta traz o token. A política é a CAdES-BES, e o contexto de segurança, Lacuna Test PKI, aceita também os
certificados de teste, então você pode assinar com um deles. Em seguida, abra o exemplo,
cole o token e clique em Sign with Rest PKI:
Depois que o Web PKI assinar, finalize a assinatura para obter o CMS (arquivo .p7s):
curl -X POST https://pki.rest/Api/CadesSignatures/O_TOKEN/Finalize \
-H "Authorization: Bearer SEU_ACCESS_TOKEN" \
-d ""
A resposta traz a assinatura em Base64 em cms e o certificado do signatário em certificate.
O código do exemplo está em demo.html,
demo.js e demo.css. Para
testá-lo com a sua própria instância do Rest PKI ou com o Rest PKI Core, defina o restPkiUrl no início do JavaScript e use o
endereço e as credenciais dessa instância (uma API key, no Rest PKI Core) nas chamadas do curl.
Erros
Além dos outros erros do Web PKI, o signWithRestPki() pode falhar com:
| Código | Significado |
|---|---|
rest_pki_get_pending_signature | O Web PKI não conseguiu obter a assinatura pendente do Rest PKI. Em geral, o Web PKI não consegue acessar a instância: verifique o restPkiUrl e os requisitos de rede. Veja Erro "Could not get pending signature". |
rest_pki_post_signature | O Web PKI não conseguiu enviar a assinatura ao Rest PKI. |
rest_pki_invalid_certificate | O Rest PKI não aceitou o certificado escolhido, por exemplo porque o contexto de segurança da assinatura não confia nele. |
Um token vale uma única vez: para assinar de novo, inicie uma nova assinatura no seu backend.
Com as APIs mais novas do Rest PKI Core
O Rest PKI Core continua atendendo as APIs do Rest PKI que o signWithRestPki() usa e acrescenta APIs mais novas, que usam o
Web PKI de outra forma:
- Sessões de assinatura: você redireciona o usuário para uma página de assinatura hospedada pelo Rest PKI Core, que usa o próprio Web PKI. As suas páginas não têm código do Web PKI.
- Assinaturas em duas etapas: o seu backend prepara a assinatura, a sua
página assina o hash com o
signHash()do Web PKI, e o seu backend conclui a assinatura.
Veja Migração do Rest PKI para o Rest PKI Core.
Exemplos
Os exemplos do Rest PKI, em cada linguagem abaixo, assinam com o signWithRestPki(). Veja também o Rest PKI.