Pular para o conteúdo

Segurança / assinatura: CMS, timestamp RFC 3161, LTV, confiança

Esta página descreve a superfície de assinatura do NextPDF Core: produzir uma assinatura Content Management Syntax (CMS), aplicar um timestamp Request for Comments (RFC) 3161, validar uma cadeia de certificados em relação ao RFC 5280 e verificar a revogação por meio do Online Certificate Status Protocol (OCSP) e de uma lista de revogação de certificados (CRL). Ela se mantém no nível do comportamento. As classes de implementação do Core são internas: o código de produção consome o contrato SignerInterface, não os tipos concretos NextPDF\Security\Signature. O verificador e suas âncoras de confiança configuradas decidem se uma assinatura produzida é verificada. Esse resultado está fora do controle do produtor, e esta página deixa isso explícito sempre que relevante.

Terminal window
composer require nextpdf/core:^3

O Core constrói uma estrutura CMS SignedData a partir do byte range e a armazena como dados codificados em Distinguished Encoding Rules (DER) na entrada Contents do dicionário de assinatura — ISO 32000-2 §12.8.1. A estrutura contém atributos assinados de SignerInfo, incluindo content-type e message-digest — RFC 5652 §5.3. Um verificador recalcula o digest do conteúdo e o compara com o atributo message-digest. A comparação precisa coincidir para que a assinatura seja válida — RFC 5652 §5.4. SignerInfo também contém o identificador do algoritmo de digest e o bloco de atributos assinados — RFC 5652 §5. O Core usa phpseclib3 nos caminhos de assinatura por software que disponibiliza: RSA, RSASSA-PSS, ECDSA e Ed25519.

Um timestamp RFC 3161 é uma troca de requisição e resposta com uma Time-Stamping Authority (TSA) que retorna uma estrutura TSTInfo — RFC 3161 §2.4.1. Cada token contém um serialNumber único para a TSA emissora — RFC 3161 §2.4.2 — e um genTime expresso em Coordinated Universal Time (UTC), o instante em que o token foi criado — RFC 3161 §2.4.2.

A validação de confiança envolve duas verificações. A validação de caminho percorre do certificado do signatário até uma âncora de confiança, verificando as restrições básicas e as entradas de construção do caminho — RFC 5280 §6.1. A verificação de revogação consulta um respondedor OCSP ou lê uma CRL: uma resposta OCSP informa good, revoked ou unknown — RFC 6960 §2.2 — e os campos thisUpdate e nextUpdate da resposta delimitam a atualidade desse status — RFC 6960 §4.2. O chamador fornece as âncoras de confiança e a política de atualidade da revogação. O motor valida em relação a essas entradas e não fornece uma lista de confiança embutida.

TipoCategoriaFunçãoEstabilidadeDesde
SignerInterfaceinterface (NextPDF\Contracts)O contrato de assinatura do qual os chamadores dependemstable1.0.0
SignatureLevelenumSeletor de nível e sonda de disponibilidade de PDF Advanced Electronic Signatures (PAdES)stable1.0.0
Rfc5280PathValidatorinterfacePonto de entrada da validação de caminho de certificação (validate(...))stable (congelado em 3.1.0)3.1.0
RevocationStatusenumResultado OCSP / CRL: good, revoked, unknownstable3.1.0
CaTrustAnchorBundletipoConjunto de âncoras de confiança fornecido pelo chamadorstable3.1.0
TstInfotipoCampos de timestamp RFC 3161 analisadosstable3.2.0

SignerInterface::sign() retorna um SignatureResult. O método toHex() produz a string hexadecimal de /Contents, e a propriedade cmsSignedData contém os bytes DER brutos. As classes concretas NextPDF\Security\Signature que implementam esse comportamento são internas (stability: internal no manifest do módulo). Elas não fazem parte da API pública e podem mudar sem incremento de versão principal. Dependa dos contratos e enums acima.

examples/contracts/signing-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/**
* Produce the CMS SignedData hex for a PDF /Contents field.
*
* @param SignerInterface $signer A Core or Premium signer.
* @param string $byteRange The PDF byte range to sign.
*
* @return string Hex-encoded CMS SignedData.
*/
function sign(SignerInterface $signer, string $byteRange): string
{
return $signer->sign($byteRange)->toHex();
}

O chamador depende do contrato. Tanto um signatário por software do Core quanto um signatário Hardware Security Module (HSM) do Premium satisfazem o SignerInterface; portanto, este código não muda entre as edições.

examples/contracts/signing-trust.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
use NextPDF\Contracts\TimestampProviderInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class TimestampedSigner
{
public function __construct(
private SignerInterface $signer,
private TimestampProviderInterface $timestamps,
private LoggerInterface $logger,
) {}
/**
* Sign a byte range, then timestamp the CMS structure.
*
* The timestamp's trust still depends on the verifier accepting the
* Time-Stamping Authority; this method only produces the structure.
*
* @param string $byteRange The PDF byte range to sign.
*
* @return array{cms: string, tst: string}
*/
public function sign(string $byteRange): array
{
try {
$signature = $this->signer->sign($byteRange);
$token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return ['cms' => $signature->toHex(), 'tst' => $token];
} catch (NextPdfException $e) {
$this->logger->error('Signing failed', ['error' => $e->getMessage()]);
throw $e;
}
}
}

O provedor de timestamp é injetado para que uma implantação possa fixar sua própria Time-Stamping Authority. O bloco catch registra e relança. Ele nunca engole a falha; portanto, o caminho de assinatura permanece fail-closed.

  • Uma assinatura produzida não é uma assinatura verificada. A validação de caminho e a revogação são executadas no verificador, usando as âncoras de confiança desse verificador. O produtor não pode afirmar o resultado.
  • O digest do byte range exclui o valor da assinatura. Um digest que cubra os octetos de Contents não pode ser verificado — ISO 32000-2 §12.8.1.
  • O status de revogação tem uma janela de atualidade. Uma resposta OCSP é atual apenas para seu intervalo thisUpdate / nextUpdate — RFC 6960 §4.2. Uma resposta desatualizada não substitui uma verificação recente no momento da validação.
  • O motor não fornece nenhuma lista de confiança embutida. CaTrustAnchorBundle é fornecido pelo chamador; um bundle vazio significa que nenhuma cadeia é validada, por design.
  • OCSP unknown não é good. Trate unknown como uma não determinação, não como uma aprovação implícita — RFC 6960 §2.2.
  • A custódia de chaves HSM, a assinatura adiada e em nuvem e o produtor PAdES B-LT / B-LTA não estão no Core. Selecionar esses caminhos na distribuição Core falha de forma fechada, com uma mensagem que nomeia o componente Enterprise ausente.

Uma assinatura por software leva poucos milissegundos. Um timestamp adiciona uma ida e volta de rede até a TSA. A validação de caminho é local depois que os certificados estão em memória; a revogação adiciona uma busca OCSP ou CRL por certificado na cadeia. O orçamento de 1500 ms de wall cobre uma assinatura com timestamp usando uma TSA remota em uma conexão aquecida. A revogação contra um endpoint lento ultrapassa esse orçamento e deve ficar fora do caminho da requisição. O perfil de reprodutibilidade é structural: um timestamp incorpora o instante da assinatura, portanto duas execuções diferem nos bytes do timestamp, enquanto a estrutura do documento é idêntica.

Este é o limite criptográfico primário do motor; portanto, o modelo de ameaças é explícito. O motor calcula o byte range e nunca o aceita do chamador. O caminho de assinatura é fail-closed: uma falha de primitiva ou uma lacuna de capacidade levanta uma exceção tipada e nunca rebaixa silenciosamente para um algoritmo mais fraco. Em um nível que exige timestamp (B-T, B-LT, B-LTA), uma Time-Stamping Authority que retorna um token vazio é uma falha terminal: a assinatura é recusada, não emitida em um estado silenciosamente sem timestamp e rebaixado de nível, a menos que um manipulador de falhas esteja conectado para autorizar uma degradação documentada. A confiança é controlada pelo chamador por design: âncoras e política de revogação são entradas, não padrões do motor, porque um produtor que afirmasse sua própria confiança afirmaria um fato que apenas o verificador pode estabelecer. A confiança no timestamp se reduz à confiança na Time-Stamping Authority, que é injetável para que uma implantação possa fixar a sua própria. Esta página está marcada como export_control_class: legal-review-required porque trata de assinatura criptográfica; toda fonte normativa é parafraseada e nenhuma é reproduzida, conforme a higiene de citação.

AfirmaçãoPadrãoCláusulaEvidência
A assinatura CMS é armazenada codificada em DER na entrada Contents do dicionário de assinatura.ISO 32000-2§12.8.1
SignerInfo contém os atributos assinados content-type e message-digest.RFC 5652§5.3
O verificador recalcula o digest do conteúdo e o compara com o atributo message-digest.RFC 5652§5.4
Um token de timestamp é produzido por uma RFC 3161 TSA e contém um serialNumber único e um genTime em UTC.RFC 3161§2.4.1, §2.4.2,,
A validação de caminho de certificação verifica as restrições básicas e as entradas de caminho do signatário até uma âncora de confiança.RFC 5280§6.1,
OCSP informa certStatus como good, revoked ou unknown, limitado por thisUpdate / nextUpdate.RFC 6960§2.2, §4.2,

Todas as cláusulas são parafraseadas. O NextPDF não reproduz texto normativo. Consulte os padrões publicados para a redação autoritativa.

O Core disponibiliza o signatário CMS por software (RSA, RSASSA-PSS, ECDSA, Ed25519), o consumo de timestamp RFC 3161, a validação de caminho RFC 5280 e a verificação de revogação OCSP / CRL. A custódia de chaves HSM e Public-Key Cryptography Standards #11 (PKCS#11), a assinatura adiada e em nuvem, o produtor PAdES B-LT e B-LTA e o perfil de política criptográfica Federal Information Processing Standards (FIPS) 140-3 são disponibilizados nas edições Pro e Enterprise. O Core resolve esses recursos em tempo de execução em relação ao contrato; portanto, o motor de código aberto não carrega nenhuma dependência comercial, e a API não muda na atualização.