Pular para o conteúdo
getnextpdf.com

Solução de problemas: assinaturas e carimbos de tempo

Estas entradas cobrem falhas de assinatura geradas por NextPDF\Exception\SignatureException e NextPDF\Security\Signature\Exception\SignatureLevelUnreachableException. Cada entrada indica o método de fábrica ou a classe exata, para que você possa confirmar a causa pela mensagem e por getContext(), em vez de inferi-la.

Observação sobre a redação: o engine não certifica que uma assinatura seja válida nem que um documento esteja protegido. Ele relata a falha que detectou. Trate cada resolução como uma etapa para eliminar uma causa relatada.

Entrada: o nível PAdES “B-LT” ou “B-LTA” não pode ser produzido

Seção intitulada “Entrada: o nível PAdES “B-LT” ou “B-LTA” não pode ser produzido”
  • Sintoma. SignatureException com o final de mensagem nextpdf/enterprise package is required for B-LT/B-LTA signatures.
  • Causa provável. O provedor de recursos para validação de longo prazo está ausente. B-LT e B-LTA incorporam material de revogação e um carimbo de tempo de arquivamento, e esse provedor é distribuído em nextpdf/enterprise.
  • Evidência / diagnóstico. A fábrica SignatureException::ltvCapabilityMissing() gera exatamente esta mensagem. getContext() retorna signature_level definido como o nível que você tentou.
  • Resolução.
    1. Instale o provedor executando composer require nextpdf/enterprise.
    2. Execute a chamada de assinatura novamente.
    3. Se você não puder instalar o provedor, solicite B-B ou B-T, que o pacote core pode produzir.
  • Relacionado. Referência de exceções.

Entrada: o nível de assinatura é inalcançável e a chamada é rejeitada

Seção intitulada “Entrada: o nível de assinatura é inalcançável e a chamada é rejeitada”
  • Sintoma. SignatureLevelUnreachableException com uma mensagem no formato PAdES level "<x>" is unreachable (highest achievable: "<y>").
  • Causa provável. O nível de conformidade solicitado depende de uma infraestrutura que não está disponível no momento da assinatura, normalmente uma autoridade de carimbo de tempo para B-T e superiores. O engine falha de forma fechada: ele não rebaixa silenciosamente para depois anunciar o nível superior.
  • Evidência / diagnóstico. getContext() retorna requestedLevel, highestAchievableLevel e reason. O campo reason identifica a lacuna de infraestrutura. Esse é o padrão de falha fechada introduzido para evitar um documento que declare um nível que ele não atende.
  • Resolução.
    1. Consulte o campo reason para identificar a infraestrutura ausente.
    2. Forneça o componente ausente. Por exemplo, configure uma autoridade de carimbo de tempo e execute a chamada novamente.
    3. Para aceitar intencionalmente um nível inferior, passe allowDegradation: true para PadesOrchestrator. Nesse caso, a chamada produz highestAchievableLevel e relata o nível que produziu.
  • Relacionado. Criptografia e permissões.

Entrada: o cliente da autoridade de carimbo de tempo é necessário, mas está ausente

Seção intitulada “Entrada: o cliente da autoridade de carimbo de tempo é necessário, mas está ausente”
  • Sintoma. SignatureException com o final TSA client is required for level <x> but none was provided.
  • Causa provável. Uma solicitação B-T, B-LT ou B-LTA precisa de um cliente de autoridade de carimbo de tempo, e o orquestrador não recebeu nenhum.
  • Evidência / diagnóstico. A fábrica SignatureException::tsaRequired() gera esta mensagem; getContext() traz o signature_level tentado.
  • Resolução.
    1. Configure um cliente de autoridade de carimbo de tempo e passe-o para o orquestrador.
    2. Execute a chamada novamente.
    3. Para produzir um nível que não precisa de carimbo de tempo, solicite B-B.
  • Relacionado. Referência de exceções.

Entrada: a URL do endpoint da autoridade de carimbo de tempo está vazia

Seção intitulada “Entrada: a URL do endpoint da autoridade de carimbo de tempo está vazia”
  • Sintoma. SignatureException com o final TSA endpoint URL is empty.
  • Causa provável. Um cliente de autoridade de carimbo de tempo foi criado com uma URL de endpoint vazia.
  • Evidência / diagnóstico. A fábrica SignatureException::tsaUrlEmpty() gera esta mensagem. Este é um defeito de configuração, não uma falha de rede.
  • Resolução.
    1. Defina uma URL de endpoint não vazia no cliente da autoridade de carimbo de tempo, como https://timestamp.example.com/tsa.
    2. Se o nível solicitado não exigir carimbo de tempo, remova a configuração do cliente da autoridade de carimbo de tempo.
    3. Execute a chamada novamente.
  • Relacionado. Referência de exceções.

Entrada: o carimbo de tempo da assinatura não vincula a assinatura (incompatibilidade de imprint)

Seção intitulada “Entrada: o carimbo de tempo da assinatura não vincula a assinatura (incompatibilidade de imprint)”
  • Sintoma. TsaTokenVerificationException que carrega a etapa Step::ImprintBinding, com um final de mensagem como TSTInfo messageImprint does not bind the SignerInfo signature value — o token carimba bytes diferentes dos da assinatura que afirma cobrir.
  • Causa provável. O message imprint do carimbo de tempo da assinatura não é o hash do valor de assinatura do SignerInfo ao qual está anexado. A causa benigna mais comum é um documento produzido por uma versão do NextPDF anterior à correção de vinculação de imprint do RFC 3161 Appendix A: essas versões faziam o hash de uma entrada diferente, de modo que seus carimbos de tempo B-T não conseguem provar a vinculação a um verificador rigoroso. Outras causas são um token de carimbo de tempo trocado ou adulterado, ou um token cujo imprint usa SHA-1 ou um algoritmo não reconhecido (rejeitado de forma fechada nesta verificação).
  • Evidência / diagnóstico. A verificação é a etapa dedicada verifySignatureTimestamp() (Step::ImprintBinding), que recebe o valor de assinatura como uma entrada obrigatória, de modo que nunca pode ser silenciosamente ignorada. Ela falha de forma fechada diante de uma entrada vazia, de um identificador de objeto de imprint não reconhecido, de um imprint SHA-1, de um formato de imprint malformado ou de uma incompatibilidade de hash.
  • Resolução.
    1. Se o documento foi produzido por uma versão do engine anterior à correção, assine e carimbe novamente com uma versão atual. O imprint de um carimbo de tempo é uma evidência imutável e não pode ser reparado no local. Esta é uma mudança incompatível intencional e permanente (consulte a entrada “Security” do CHANGELOG referente à correção de conformidade do messageImprint do carimbo de tempo de assinatura PAdES).
    2. Se o documento for atual, trate a incompatibilidade como uma falha de vinculação genuína: o carimbo de tempo não cobre esta assinatura, portanto não confie nele para B-T.
    3. Para um algoritmo de imprint SHA-1 ou desconhecido, o carimbo de tempo não consegue provar a vinculação, independentemente da idade; obtenha um carimbo de tempo que use um digest de imprint compatível (SHA-256 por padrão).
  • Relacionado. Referência de exceções.

Entrada: o espaço reservado da assinatura está ausente do buffer

Seção intitulada “Entrada: o espaço reservado da assinatura está ausente do buffer”
  • Sintoma. SignatureException com o final no /Contents <…> field found in PDF buffer (signature placeholder missing).
  • Causa provável. O estágio de assinatura recebeu um buffer sem contêiner de assinatura reservado; portanto, não há lugar para gravar a assinatura.
  • Evidência / diagnóstico. A fábrica SignatureException::signatureContentsNotFound() gera esta mensagem.
  • Resolução.
    1. Certifique-se de que o campo de assinatura e o respectivo espaço reservado sejam gravados antes da execução do estágio de assinatura.
    2. Execute o pipeline novamente para que o espaço reservado exista quando a assinatura começar.
  • Relacionado. Referência de exceções.

Entrada: o status de revogação é desconhecido (o respondedor OCSP recusou)

Seção intitulada “Entrada: o status de revogação é desconhecido (o respondedor OCSP recusou)”
  • Sintoma. SignatureException com o final OCSP responder returned non-successful OCSPResponseStatus "<status>".
  • Causa provável. O respondedor do Online Certificate Status Protocol (OCSP) não retornou um status successful, portanto não produziu nenhuma asserção de revogação. O engine segue o RFC 6960 §4.2.1, citado no código-fonte: um corpo de resposta preenchido é permitido apenas para o status successful (0). O engine se recusa a tratar uma resposta recusada como um resultado de confiança positivo.
  • Evidência / diagnóstico. A fábrica SignatureException::nonSuccessfulOcspResponseStatus() gera esta mensagem e informa o status relatado, como tryLater ou internalError. Um byte de status reservado ou desconhecido gera, em vez disso, SignatureException::reservedOcspResponseStatus().
  • Resolução.
    1. Identifique o status na mensagem. Para um status transitório, como tryLater, tente buscar a revogação novamente mais tarde.
    2. Para unauthorized ou malformedRequest, verifique a URL da solicitação OCSP e o certificado que o respondedor espera.
    3. Não suprima a falha para obter um artefato B-LT ou B-LTA; a asserção de revogação faz parte desse nível.
  • Relacionado. Referência de exceções.

Entrada: uma entrada da cadeia de certificados falha ao decodificar

Seção intitulada “Entrada: uma entrada da cadeia de certificados falha ao decodificar”
  • Sintoma. SignatureException com o final failed to base64-decode PEM body — input is not valid PEM.
  • Causa provável. Uma entrada da cadeia de certificados não está em um formato Privacy-Enhanced Mail (PEM) válido, normalmente por truncamento, um caractere fora do lugar ou um blob binário em Distinguished Encoding Rules (DER) fornecido onde se esperava PEM.
  • Evidência / diagnóstico. A fábrica SignatureException::pemDecodingFailed() gera esta mensagem durante a montagem da cadeia.
  • Resolução.
    1. Inspecione cada certificado da cadeia em busca de caracteres fora do lugar ou truncamento.
    2. Reexporte o certificado afetado no formato PEM.
    3. Execute a chamada de assinatura novamente.
  • Relacionado. Criptografia e permissões.

Entrada: o tipo de chave privada não corresponde ao algoritmo

Seção intitulada “Entrada: o tipo de chave privada não corresponde ao algoritmo”
  • Sintoma. SignatureException com o final expected private key of type "<x>" for the configured algorithm but got "<y>".
  • Causa provável. A chave privada carregada não corresponde ao algoritmo de assinatura configurado, como uma chave Rivest-Shamir-Adleman (RSA) combinada com uma seleção de Elliptic Curve Digital Signature Algorithm (ECDSA).
  • Evidência / diagnóstico. A fábrica SignatureException::unexpectedKeyType() gera esta mensagem e informa tanto a classe de chave esperada quanto a real.
  • Resolução.
    1. Verifique se o par de certificado e chave corresponde ao algoritmo que você selecionou.
    2. Altere a seleção do algoritmo para corresponder à chave ou carregue a chave que corresponde ao algoritmo.
    3. Execute a chamada de assinatura novamente.
  • Relacionado. Referência de exceções.

Entrada: o material de chave ou de assinatura Ed25519 está malformado

Seção intitulada “Entrada: o material de chave ou de assinatura Ed25519 está malformado”
  • Sintoma. SignatureException com um final que indica uma incompatibilidade de comprimento Ed25519 — por exemplo, Ed25519 signature length <n> ≠ expected 64 bytes, ou Ed25519 round-trip self-verify failed.
  • Causa provável. A build criptográfica em tempo de execução retornou material de chave ou de assinatura com o comprimento errado, ou uma assinatura recém-produzida falhou na verificação contra sua própria chave pública. O engine cita o RFC 8032 §3.4 no código-fonte, que fixa uma assinatura Ed25519 destacada em 64 bytes. O engine aborta em vez de emitir material que não consegue verificar por conta própria.
  • Evidência / diagnóstico. As fábricas relevantes são SignatureException::ed25519SignatureMalformed(), ::ed25519RoundTripVerifyFailed(), ::ed25519KeyParseFailed(), ::ed25519SeedInvalid(), ::ed25519SecretKeyMalformed() e ::ed25519PublicKeyInvalid(). Cada uma informa o comprimento observado.
  • Resolução.
    1. Reinstale a extensão libsodium do PHP; uma build sem componentes necessários ou corrompida é a causa documentada de material com comprimento errado.
    2. Confirme que a chave é uma chave Ed25519 e que o OpenSSL está na versão 1.1.1 ou mais recente.
    3. Execute a chamada de assinatura novamente.
  • Relacionado. Referência de exceções.

Entrada: o dicionário de carimbo de tempo de arquivamento não foi emitido

Seção intitulada “Entrada: o dicionário de carimbo de tempo de arquivamento não foi emitido”
  • Sintoma. SignatureException com o final no /Type /DocTimeStamp dictionary was emitted into the PDF buffer.
  • Causa provável. O ciclo de arquivamento B-LTA foi executado, mas o dicionário de carimbo de tempo do documento nunca chegou ao buffer. O artefato seria um B-LTA gravado parcialmente, portanto o engine se recusa a retorná-lo.
  • Evidência / diagnóstico. A fábrica SignatureException::documentTimestampNotEmitted() gera esta mensagem. Esta falha de pós-condição é gerada no momento da finalização.
  • Resolução.
    1. Trate a saída como descartada; não distribua o artefato parcial.
    2. Execute o pipeline B-LTA novamente com uma autoridade de carimbo de tempo acessível.
    3. Se a falha se repetir, capture getContext() e a exceção anterior encadeada para um relatório de defeito.
  • Relacionado. Referência de exceções.
  • Essas fábricas definem cert_info como um subject ou thumbprint apenas quando algum deles está disponível; um cert_info vazio é esperado para falhas de recurso e de configuração.
  • Uma solicitação B-LT ou B-LTA sem um cliente Hypertext Transfer Protocol (HTTP) configurado gera SignatureException::httpClientMissing(); a busca de revogação exige um cliente PHP Standards Recommendation (PSR)-18 passado para o orquestrador.
  • Um certificado baseado em um hardware security module (HSM) sem uma implementação de signatário gera SignatureException::hsmSignerMissing(); conecte o signatário ao certificado antes de assinar.

Glossário: nível PAdES · asserção de revogação