Pular para o conteúdo

Inspecione uma assinatura existente e entenda o limite de confiança

Use o inspetor do Core para detectar se um PDF contém assinatura e manter o limite de confiança bem definido. Detectar não é verificar. As edições premium ou um verificador externo cuidam da verificação criptográfica, da validação do caminho de confiança e da checagem de revogação.

  • Core instalado: composer require nextpdf/core:^3.
  • Um arquivo PDF para inspecionar.
  1. Leia os bytes do PDF.
  2. Crie um Inspector e chame inspect().
  3. Leia InspectResult::$hasSigned. true significa que o arquivo contém um dicionário de assinatura.
  4. Leia InspectResult::$isEncrypted e os indicadores de risco para entender o contexto ao redor.
  5. Encaminhe o arquivo a um verificador para obter a decisão criptográfica. O inspetor relata presença, não validade.

O diagrama abaixo mostra o limite: presença não é validade. Ele também mostra as checagens que um verificador de fato ainda precisa realizar.

false

true

Yes

No

Yes

No / unknown

Incoming PDF

Inspector.inspect — Quick

hasSigned?

No signature present

Signature dictionary PRESENT

NOT yet validity

Recompute byte-range digest

ISO 32000-2 §12.8.1

Validate CMS SignedData

Build & check X.509 path

to a chosen trust anchor

Check revocation OCSP / CRL

Long-term input?

Read DSS validation material

All checks evaluated

Every check passed?

Trustworthy

Not trusted — do not act

Diagram
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\Inspector;
use NextPDF\Inspect\InspectConfig;
$pdfData = file_get_contents(__DIR__ . '/incoming.pdf');
if ($pdfData === false || $pdfData === '') {
fwrite(STDERR, "Cannot read incoming.pdf\n");
exit(1);
}
$inspector = new Inspector();
// InspectConfig::quick() selects InspectDepth::Quick. This is the only
// depth that runs offline: a default Inspector has no Spectrum sidecar,
// and without a sidecar Quick is the sole path that returns a result.
// Standard and Full require the sidecar (see the SIDECAR-001 edge case).
$result = $inspector->inspect(
$pdfData,
InspectConfig::quick(),
);
// hasSigned reports the PRESENCE of a signature dictionary.
// It does NOT mean the signature verifies.
if ($result->hasSigned) {
echo "A signature is present in incoming.pdf\n";
echo "Encrypted: " . ($result->isEncrypted ? 'yes' : 'no') . "\n";
echo "Next step: run a cryptographic verifier before trusting it.\n";
} else {
echo "No signature found in incoming.pdf\n";
}

Para uma entrada assinada:

A signature is present in incoming.pdf
Encrypted: no
Next step: run a cryptographic verifier before trusting it.

Para uma entrada não assinada:

No signature found in incoming.pdf
  • Presença não é validade — o limite. InspectResult::$hasSigned informa que existe um dicionário de assinatura no arquivo. Ele não verifica a estrutura da Cryptographic Message Syntax (CMS), o digest do intervalo de bytes, o certificado de assinatura, a cadeia de certificados nem o status de revogação. Um arquivo adulterado ainda pode retornar hasSigned = true. Nunca trate a presença como prova de integridade ou autoria.
  • O que a verificação completa exige. Uma decisão completa recalcula o digest do intervalo de bytes e o compara (ISO 32000-2 §12.8.1), valida o SignedData do CMS, constrói e verifica o caminho X.509 até uma âncora confiável e checa a revogação por meio do Online Certificate Status Protocol (OCSP) ou de uma lista de certificados revogados (CRL). Para entradas de longo prazo, os dados de validação ficam no Document Security Store (DSS) (ETSI EN 319 142-2 §6.3.1). Essas operações ficam por trás dos contratos SignerInterface e LtvManagerInterface; as implementações de produção vêm nas edições Pro e Enterprise. Um validador externo é o outro caminho suportado.
  • Profundidade de inspeção e o sidecar (SIDECAR-001). Um new Inspector() padrão não vem com nenhum sidecar Spectrum configurado. Sem um sidecar, apenas InspectDepth::Quick retorna um resultado. InspectDepth::Quick usa o fallback PHP em processo. Tanto InspectDepth::Standard quanto InspectDepth::Full exigem o sidecar. Se nenhum sidecar estiver disponível, eles lançam InspectException com o código INSPECT-SIDECAR-001 (“Spectrum sidecar is required for Standard/Full depth inspection”, retryable = true). O construtor de InspectConfig tem como profundidade padrão Standard. Portanto, um new InspectConfig() simples (ou new InspectConfig(depth: InspectDepth::Standard)) não é utilizável offline. Ele lança SIDECAR-001 antes mesmo de hasSigned ser lido. Use InspectConfig::quick() para a detecção de presença offline, como nesta receita. Nenhuma profundidade realiza a verificação criptográfica de assinatura no Core.
  • Entrada vazia. Uma string vazia lança InspectException com o código INSPECT-INPUT-001. Valide a leitura do arquivo.
  • Múltiplas assinaturas. O indicador de presença não conta assinaturas nem distingue uma assinatura de aprovação de um carimbo de tempo do documento. Use um verificador dedicado quando a contagem ou o veredito por assinatura forem relevantes.
AfirmaçãoEspecificaçãoCláusulareference_id
O valor da assinatura é armazenado na entrada Contents do dicionário de assinatura.ISO 32000-2§12.8.1
A verificação recalcula o digest sobre o ByteRange, excluindo o valor da assinatura.ISO 32000-2§12.8.1
Os dados de validação de longo prazo ficam no DSS.ETSI EN 319 142-2§6.3.1

Esta receita detecta se uma assinatura está presente. Ela não afirma que qualquer assinatura seja válida, confiável ou não revogada. Essa decisão cabe a um verificador criptográfico.