ShieldSign PKIDocumentação

Identidade do certificado

Ler o CPF/CNPJ do certificado, recusar antes do PIN e restringir quem pode assinar.

Antes de o usuário digitar o PIN, a API já validou o certificado e devolveu a identidade dele. Este guia mostra como usar essa identidade, recusar o certificado errado antes do PIN e restringir quem pode assinar.

O que a API valida no prepare#

No prepare, a API confere a cadeia até uma raiz do contexto de segurança escolhido, a validade e o uso da chave (o certificado precisa poder assinar). Se algo falhar, o erro vem antes do PIN, e nada é gasto. Nos perfis AD-RC e AD-RA ela também consulta a revogação (LCR e OCSP).

A resposta traz a identidade em certificate:

{
  "thumbprint": "…",
  "subjectDn": "CN=MARIA DA SILVA:12345678909,OU=…,O=ICP-Brasil,C=BR",
  "issuerDn": "CN=AC Exemplo,OU=…,O=ICP-Brasil,C=BR",
  "subjectCn": "MARIA DA SILVA",
  "issuerCn": "AC Exemplo",
  "serialNumber": "…",
  "pkiBrazil": { "kind": "pf", "cpf": "12345678909", "cnpj": null, "…": "…" }
}

CPF, CNPJ e demais dados: pkiBrazil#

O bloco pkiBrazil é lido pelo servidor dos campos ICP-Brasil do certificado. Sempre existe: fora da ICP-Brasil, todos os campos são null.

Campo Observação
kind "pf" = e-CPF (tem cpf), "pj" = e-CNPJ (tem cnpj), null = sem campos ICP-Brasil.
cpf, birthDate, rg, rgIssuer, nis Só do titular pessoa física. Em e-CNPJ, cpf é null (não confunda com o do responsável).
cnpj 14 dígitos.
companyName Razão social do e-CNPJ, já sem o :CNPJ do nome. null se não for e-CNPJ.
responsibleName, responsibleCpf, responsibleBirthDate Dados do responsável, no e-CNPJ.
email O e-mail do certificado.
  • Os valores vêm só com dígitos, sem máscara ("12345678909"). Campo ausente, zerado ou de tamanho errado vira null: nunca vem lixo.
  • Os dígitos verificadores não são conferidos: cabe ao seu formulário, se quiser.

Use o que a API devolve, não o que o navegador mostra

O navegador também lista pkiBrazil na tela de escolha, mas isso só organiza a interface: não é controle de acesso. Para auditoria e regra de negócio use o bloco devolvido pela API no prepare e no complete, lido do certificado que de fato assinou e já validado até a raiz.

Recusar antes do PIN#

O padrão para garantir que a pessoa certa assina: compare o CPF ou CNPJ do certificado com o que o seu cadastro espera, no prepare, e descarte a sessão se não bater.

$p  = $api->prepare($token, $certificadoDerBase64);
$pk = $p['certificate']['pkiBrazil'];

$daAssinatura = array_filter([$pk['cpf'], $pk['cnpj'], $pk['responsibleCpf']]);
if (!in_array($cpfOuCnpjEsperado, $daAssinatura, true)) {   // só dígitos nos dois lados
    $api->discard($token);                                  // nada foi assinado, nada foi gasto
    throw new DomainException('certificado de outra pessoa');
}

Para um e-CNPJ, aceite o CNPJ da empresa ou o CPF do responsável, conforme a sua regra. Em JavaScript (Node), a opção beforeSign de signPades faz o mesmo: ela roda depois do prepare e antes do PIN, e lançar um erro descarta a sessão.

Restringir a AC emissora: acceptableIssuers#

No início da assinatura, acceptableIssuers limita o certificado a ACs específicas. A restrição é imposta no servidor, no prepare, antes do PIN:

$api->startMultipart($arquivos, 'pades-icpbrasil-ad-rb', 'icp-brasil', null,
    ['CN=AC SOLUTI Multipla v5', 'a3f1…64 caracteres hexadecimais da impressão digital de uma AC']);   // até 20 itens

Cada item é o DN (RFC 4514, em qualquer ordem, sem diferenciar maiúsculas) ou a impressão digital SHA-256 de uma AC da cadeia validada do certificado (intermediária ou raiz; o certificado final não conta). Basta um item casar. A conferência acontece depois de a cadeia ser validada contra as raízes do contexto: uma AC de mesmo nome que não esteja na cadeia não passa. Sem casar, a API responde 422 certificate_issuer_not_allowed.

Por que o certificado foi recusado: error.reason#

As recusas de certificado (certificate_not_trusted, invalid_certificate e certificate_issuer_not_allowed) trazem um subcódigo estável, sem dados pessoais, para a sua tela explicar sem adivinhar:

reason Significa Mensagem sugerida ao usuário
expired O certificado (ou uma AC da cadeia) está vencido. "Este certificado venceu. Use outro ou renove-o."
not_yet_valid Ainda não começou a valer. "Este certificado ainda não está válido (confira a data do computador)."
chain A cadeia não fecha numa raiz do contexto (AC desconhecida, autoassinado). "Este certificado não é aceito aqui (AC não reconhecida)."
key_usage O certificado não serve para assinar. "Este certificado não permite assinar documentos."
revoked Revogado (AD-RC e AD-RA). "Este certificado foi revogado."
revocation_unavailable Não foi possível consultar a revogação. "Não foi possível conferir a revogação agora; tente de novo."
algorithm Algoritmo de chave ou de assinatura não aceito. "Tipo de certificado não suportado."
malformed O arquivo enviado não é um certificado X.509. (erro de integração)
issuer_not_allowed A AC não está em acceptableIssuers. "Use um certificado de uma das ACs aceitas."
other Qualquer outra falha de validação (veja message). Mensagem genérica.
try {
    $api->prepare($token, $der);
} catch (ApiException $e) {
    if ($e->errorCode === 'certificate_not_trusted') {
        $motivo = $e->reason;   // 'expired' | 'chain' | 'key_usage' | ...
    }
}
ShieldSign PKI · Shield Certificadora · contato@shieldcertificadora.com.br · Privacidade