Pular para o conteúdo principal

Using Web PKI with Rest PKI

With Rest PKI, your backend never handles the data to sign: it starts the signature on Rest PKI and gets a token, your page passes that token to Web PKI's signWithRestPki(), and Web PKI exchanges the signature data with Rest PKI directly. Your backend then finishes the signature with the same token and gets the signed document. Certificate authentication works the same way.

Rest PKI Core serves these Rest PKI APIs too, so the same page works with it once it knows where the instance is (see The Rest PKI address). Rest PKI Core also has newer APIs, which sign with Web PKI in other ways: see With Rest PKI Core's newer APIs.

note

Rest PKI is a legacy product: it still receives bug and security fixes, but new cloud integrations should use Rest PKI Core.

How it works​

#WhoWhat
1Your backend → Rest PKIStarts the signature (for instance PadesSignatureStarter.StartWithWebPkiAsync() in .NET), authenticated with your access token or API key. Rest PKI returns a token.
2Your backend → pageRenders the signature page with the token.
3PageCalls init(), lists the user's certificates with listCertificates() and, once the user picks one, calls signWithRestPki() with the token and the certificate's thumbprint.
4Web PKI → Rest PKIFrom the user's computer, gets the pending signature (GET Api/PendingSignatures/{token}) and sends the certificate (POST Api/PendingSignatures/{token}/Certificate). Rest PKI validates the certificate against the security context of the signature and returns the hash to sign.
5Web PKI → Rest PKISigns the hash with the certificate's private key and sends the signature (POST Api/PendingSignatures/{token}).
6Page → your backend → Rest PKIThe page submits the token to your backend, which finishes the signature (for instance PadesSignatureFinisher2.FinishAsync()) and gets the signed document and the signer's certificate.

This means that:

  • Your access token stays on your server. The page only sees the token of that signature, which works once.
  • The routes Web PKI calls take no access token and accept calls from any origin: the token identifies the signature.
  • The user's computer must reach Rest PKI, not only your server. See Network requirements.
  • If Rest PKI does not accept the certificate (for instance, it is not trusted by the security context), the error comes back to the page, in signWithRestPki().

The page code​

Initialize Web PKI, list the certificates and, when the user clicks Sign, call signWithRestPki() with the token your backend rendered on the page. When it succeeds, submit the token back to your backend:

var pki = new LacunaWebPKI(webPkiLicense); // not needed with Rest PKI in the cloud, see "License" below

pki.init({
restPkiUrl: restPkiUrl, // only for an on-premises Rest PKI or Rest PKI Core, see below
ready: loadCertificates,
defaultFail: onWebPkiFail
});

function loadCertificates() {
pki.listCertificates({ selectId: 'certificateSelect' });
}

function sign() {
pki.signWithRestPki({
token: token, // returned by Rest PKI when your backend started the signature
thumbprint: document.getElementById('certificateSelect').value
}).success(function () {
document.getElementById('signForm').submit(); // your backend finishes the signature with the token
});
}

function onWebPkiFail(ex) {
alert(ex.userMessage + ' (' + ex.code + ')');
}

The samples have the backend code for each language, and you can try the page in JSFiddle.

The Rest PKI address​

Web PKI needs to know which Rest PKI instance to call. Set it in the restPkiUrl option of init():

Rest PKIrestPkiUrl
Rest PKI in the cloud (https://pki.rest)Leave it out
Rest PKI on-premisesThe address of your instance, such as 'https://restpki.yourcompany.com/'
Rest PKI Core, in the cloud or on-premisesThe endpoint of your instance, such as 'https://core.pki.rest/'
pki.init({
restPkiUrl: 'https://restpki.yourcompany.com/',
ready: onWebPkiReady
});

Without restPkiUrl, Web PKI calls the cloud instance through https://restpki.lacunasoftware.com/, an alternative address of https://pki.rest that, being more conventional, is less likely to be blocked by the firewalls of the users' networks.

note

If Web PKI is not used with Rest PKI, restPkiUrl is not needed.

Network requirements​

Since Web PKI calls Rest PKI from the user's computer:

  • With Rest PKI in the cloud, the users' networks must allow the domain restpki.lacunasoftware.com over HTTPS.
  • With your own instance (Rest PKI on-premises or Rest PKI Core), it must be reachable from the users' computers, not only from your server. To avoid being blocked, its address should:
    • use a hostname, not an IP address;
    • use HTTPS with a valid SSL certificate, issued by a Certification Authority that the operating systems trust by default (with an invalid certificate, the calls fail silently);
    • use a standard port (443).

To check, open /Api/System/Info on the instance in a browser on the user's computer, such as https://restpki.lacunasoftware.com/Api/System/Info. See Error "Could not get pending signature".

License​

Rest PKIWeb PKI license
Rest PKI in the cloud (https://pki.rest)Not needed, even in production
Rest PKI on-premisesNeeded outside localhost
Rest PKI Core, including in the cloud (core.pki.rest)Needed outside localhost

See Licensing.

Try it in JSFiddle​

The example below is the page of a Rest PKI signature: paste a token, choose a certificate and sign. To get a token without writing a backend, start a CAdES signature of the text "Hello, World!" with curl, using your Rest PKI access token:

curl -X POST https://pki.rest/Api/CadesSignatures \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"contentToSign": "SGVsbG8sIFdvcmxkIQ==", "signaturePolicyId": "a4522485-c9e5-46c3-950b-0d6e951e17d1", "securityContextId": "803517ad-3bbc-4169-b085-60053a8f6dbf"}'

The response has the token. The policy is CAdES-BES, and the security context, Lacuna Test PKI, also accepts the test certificates, so you can sign with one of them. Then open the example, paste the token and click Sign with Rest PKI:

Once Web PKI has signed, finish the signature to get the CMS (.p7s file):

curl -X POST https://pki.rest/Api/CadesSignatures/THE_TOKEN/Finalize \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d ""

The response has the signature in Base64 in cms, and the signer's certificate in certificate.

The example's code is in demo.html, demo.js and demo.css. To try it with your own Rest PKI instance or with Rest PKI Core, set restPkiUrl at the top of the JavaScript, and use that instance's address and credentials (an API key, on Rest PKI Core) in the curl calls.

Errors​

Besides the other Web PKI errors, signWithRestPki() can fail with:

CodeMeaning
rest_pki_get_pending_signatureWeb PKI could not get the pending signature from Rest PKI. Usually Web PKI cannot reach the instance: check restPkiUrl and the network requirements. See Error "Could not get pending signature".
rest_pki_post_signatureWeb PKI could not send the signature to Rest PKI.
rest_pki_invalid_certificateRest PKI did not accept the selected certificate, for instance because the security context of the signature does not trust it.

A token works once: to sign again, start a new signature on your backend.

With Rest PKI Core's newer APIs​

Rest PKI Core keeps serving the Rest PKI APIs that signWithRestPki() uses, and adds newer APIs that use Web PKI differently:

  • Signature sessions: you redirect the user to a signing page hosted by Rest PKI Core, which uses Web PKI itself. Your pages have no Web PKI code.
  • Two-step signatures: your backend prepares the signature, your page signs the hash with Web PKI's signHash(), and your backend completes the signature.

See Moving from Rest PKI to Rest PKI Core.

Samples​

The Rest PKI samples, in each language below, sign with signWithRestPki(). See also Rest PKI.

See also​

View as Markdown