Issue from a CSR
When you make the key pair yourself, on your server or in the user's browser, you send Amplia only a certificate signing request (CSR), and it returns the certificate.
Flow
- Make the key pair and the CSR. Do it before creating the order, so that a key failure doesn't use up an order.
- Create the order. The certificate's subject comes from the order's parameters, never from the CSR.
- Issue the certificate:
POST /api/v2/certificateswith the order's id, the CSR and the key media. - Keep the private key where it was made, and the certificate with it.
The samples make the key and the CSR with PKI Express, then issue the certificate and store both on the server:
- Node.js
- Java
- PHP
- Python
const {KeyGenerator} = require('pki-express');
const {KeyMedia } = require('amplia-client/lib/enums');
const keyGenerator = new KeyGenerator({
keySize: req.body.keySize,
genCsr: true
});
let genKey = await keyGenerator.generate();
let generatedKey = genKey.getKey();
let cert = await client.issueCertificate(order.getId(), genKey.getCsr(), KeyMedia.PC);
let certId = cert.getId();
// WARNING: It is highly RECOMMENDED to ENCRYPT the key before storing
// in your database.
StorageMock.storeSync(generatedKey, certId, '.json');
StorageMock.storeSync(cert.getContentRaw(), certId, '.cer');
KeyGenerator keyGenerator = new KeyGenerator();
keyGenerator.setKeySize(2048);
keyGenerator.setKeyFormat(KeyFormats.JSON);
keyGenerator.setGenCsr(true);
KeyGenerationResult genKey = keyGenerator.generate();
Certificate cert = client.issueCertificate(order.getId(), genKey.getCsr());
// WARNING: It is highly RECOMMENDED to ENCRYPT the key before storing in your database.
StorageMock.storeKey(genKey.getKey().getBytes(), ".json", cert.getId());
StorageMock.storeKey(cert.getContent(), ".cer", cert.getId());
use Lacuna\PkiExpress\KeyGenerator;
use Lacuna\PkiExpress\SupportedKeySizes;
use Lacuna\PkiExpress\KeyFormats;
$keyGenerator = new KeyGenerator();
$keyGenerator->keySize = SupportedKeySizes::S2048;
$keyGenerator->keyFormat = KeyFormats::JSON;
$keyGenerator->genCsr = true;
$genKey = $keyGenerator->generate();
$cert = $client->issueCertificate($order->getId(), $genKey->csr);
StorageMock::storeKey($genKey->key, ".json", $cert->id);
StorageMock::storeKey($cert->getContentRaw(), ".cer", $cert->id);
from pkiexpress import KeyGenerator, Pkcs12Generator, SupportedKeySizes
key_generator = KeyGenerator()
key_generator.key_size = SupportedKeySizes.S2048
key_generator.gen_csr = True
gen_key = key_generator.generate()
cert = client.issue_certificate(order.id, gen_key.csr)
pkcs12_generator = Pkcs12Generator()
pkcs12_generator.key = gen_key.key
pkcs12_generator.set_cert_file_from_base64(cert.content_base64)
pkcs12_gen_result = pkcs12_generator.generate('1234')
- The samples warn that the private key should be encrypted before it is stored in a database.
- The Python sample then bundles the key and the certificate into a PKCS #12 file with PKI Express, to sign with it later. To have Amplia make the key and return the PKCS #12 file instead, see Issue a PKCS #12 file.
The issue call
POST /api/v2/certificates takes an IssueCertificateRequest:
| Field | Meaning |
|---|---|
orderId | Id of the order to fulfill. |
csr | The CSR. The SSL/TLS demo sends it encoded as PEM. |
keyMedia | Where the key is kept; see Key media. |
keyId | Id of a key. |
TODO(docs): what keyId refers to.
The response is a CertificateModel2 with the certificate's id, its content (Base64), dates, serial number and, in info, its
subject, issuer, CRL distribution points and OCSP URIs. POST /api/certificates takes the same body and returns the older
CertificateModel.
The e-CNPJ demo sends this body, with the enum as a number:
{
"OrderId": "00000000-0000-0000-0000-000000000000",
"Csr": "<Csr, 944 bytes>",
"KeyMedia": 1
}
To read the certificate later, use GET /api/v2/certificates/{id} (with fillContent=true to include content) or download it from
GET /api/certificates/{id}/content.
TODO(docs): the format of the file returned by GET /api/certificates/{id}/content.
Key media
keyMedia is PC, CryptoDevice, Mobile or Cloud.
- A key made on your server, or by Web PKI in the user's browser on their computer:
PC. - A key made by Web PKI on a token or smart card:
CryptoDevice.
An order's keyMediaConstraints lists the key media it accepts.
Only the Node.js client sends keyMedia: its KeyMedia enum comes from amplia-client/lib/enums, since the package's entry point
doesn't export it. The Java client sends the order id, the CSR and optionally keyId; the PHP and Python clients send only the order id
and the CSR.
TODO(docs): which key media Amplia records when the request has none.
TODO(docs): when to use Mobile and Cloud (Amplia keeps the keys of cloud certificates itself, see cloud certificate management).
Make the key in the user's browser
With Web PKI, the key can be made on the user's computer or token by your own page, and only the CSR reaches
your server. Web PKI returns the key's id with the CSR: once the certificate is issued, pass the id back to
importCertificate (or
importTokenCertificate)
to install the certificate next to its key.
The key pair itself comes from
generateSoftwareRsaKeyPair
or generateTokenRsaKeyPair.
TODO(docs): no docs page or sample shows Web PKI key generation together with Amplia; to have Amplia's own page do it, see Issue on the holder's machine.
SSL/TLS certificates
The SSL/TLS demo makes an RSA 2048 key and a CSR on its server, creates an SSL order and issues the certificate with
key media PC; visitors can also bring their own CSR.
- It checks a user's CSR before calling Amplia: at most 16 KB, PEM, Base64 or DER, an RSA key of 2048 to 4096 bits or an EC key on P-256 or P-384, and a signature that verifies. It sends Amplia the request re-encoded as PEM.
- What it hands back depends on who made the key: with a server key, a .pfx, the PEM private key and a .crt with the certificate and its issuing CA, never the root; with the user's CSR, only the .crt. It keeps keys in memory only.
Issue an e-CPF after a face check
The face e-CPF demo checks the holder's identity before issuing: Serpro's Datavalid compares their face with the photo on their CNH, through Lacuna Bio on Rest PKI Core. Once the face passes, it issues the e-CPF from a CSR, as in this page's flow, with no Amplia issue page and no return trip. For the face capture, see Rest PKI Core's biometric enrollment and biometric authentication.
- The demo runs Datavalid's
pf-basicacheck before any face capture: the name must match exactly, the birth date match, the CPF be regular, and a CNH exist. - It enrolls the face with the CPF's digits as the subject identifier and
VerifyFaceIdentityExternally = true; onBioSubjectAlreadyEnrolled, it starts a face authentication instead. - Datavalid's result is not in the completion status: the demo reads it with
GetSessionDetailsAsync(sessionId), which needs an API key allowed to view bio sessions.
TODO(docs): no call sequence has been recorded for this demo, and no docs page covers the Datavalid check.