Guia de Implementação da SES GO - Segurança
0.0.2 - draft Brazil flag

Guia de Implementação da SES GO - Segurança - Local Development build (v0.0.2) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

Criar assinatura digital

Define o processo de criação de assinatura digital avançada na qual o signatário produz uma assinatura que permite a qualquer outro ator, com acesso ao conteúdo assinado, atestar, de forma inequívoca, a autoria, a integridade, a autenticidade e o não-repúdio da informação registrada digitalmente. A validação de assinatura é definida em caso de uso próprio.

Objetivo

Este caso de uso detalha o processo de criação de assinatura digital em conformidade com a Política de Assinatura Digital Avançada definida no presente guia.

Entradas

  1. Uma instância do recurso Bundle (FHIR versão 4.0.1), serializada em JSON, contendo o conjunto de instâncias a ser assinado. O conjunto deve possuir pelo menos uma instância. Ou seja, a instância do Bundle deve conter pelo menos uma entrada (Bundle.entry).

  2. Uma instância do recurso Provenance (FHIR versão 4.0.1), serializada em JSON, contendo uma entrada em Provenance.target para cada instância do conjunto a ser assinado. Cada entrada deste array referencia uma instância disponível em uma entrada da instância do Bundle (item anterior). As instâncias a serem assinadas serão consideradas na ordem em que são referenciadas em Provenance.target e esta ordem terá que ser preservada.

  3. Material criptográfico do signatário (objeto JSON): chave privada e informações de acesso necessárias para operação de assinatura digital. Este material criptográfico será utilizado durante as etapas 10.3 (acesso à chave privada) e 10.4 (operação criptográfica) do processo de assinatura. Uma única das opções abaixo é esperada:
    • PEM (Privacy-Enhanced Mail):
      • Chave privada no formato PKCS#8 empacotada no formato PEM.
      • Senha (opcional): se fornecida, a chave privada no formato PKCS#8 empacotada no formato PEM estará criptografada.
    • PKCS#12:
      • Conteúdo: sequência de bytes no formato PKCS#12 codificada em base64.
      • Senha: string obrigatória para descriptografia do conteúdo.
      • Alias (obrigatório): string que localiza unicamente a chave privada no conteúdo.
    • SMARTCARD (PKCS#11):
      • PIN: string para autenticação no cartão inteligente.
      • Identificador: string para seleção da chave privada específica no cartão.
      • Slot ID (opcional): inteiro não negativo para identificação do slot onde o cartão está inserido, se não especificado será usado descoberta automática.
      • Token label (opcional): string até 32 caracteres para identificação específica do token, útil quando múltiplos cartões estão disponíveis.
    • TOKEN (PKCS#11):
      • PIN: string para autenticação no token criptográfico.
      • Identificador: string para seleção da chave privada específica no token.
      • Slot ID (opcional): inteiro não negativo para identificação do slot onde o token está conectado, se não especificado será usado descoberta automática.
      • Token label (opcional): string até 32 caracteres para identificação específica do token, útil quando múltiplos dispositivos estão presentes.

    Nota
    Os protocolos de transporte, métodos de comunicação com dispositivos criptográficos, drivers específicos de hardware e detalhes de descoberta automática de dispositivos são considerações de implementação que não fazem parte desta política de assinatura digital. As configurações operacionais de middleware (item 8) definem parâmetros técnicos necessários para garantir interoperabilidade e segurança, mas a implementação específica desses mecanismos permanece fora do escopo normativo da política.

  4. Cadeia de certificados (array JSON): array ordenado de certificados digitais desde o certificado do signatário (folha) até a raiz ICP-Brasil (inclusive). A cadeia de certificados será validada durante as etapas 2.1 a 2.9 do processo e incorporada na propriedade x5c do protected header JWS durante a etapa 7.3. Cada elemento do array da cadeia é uma string contendo um certificado X.509v3 no formato DER (Distinguished Encoding Rules) codificado em base64 padrão. A ordenação deve formar uma cadeia de confiança válida. A cadeia deve possuir pelo menos dois certificados. Observe que:
    • Na posição 0 está o certificado do signatário (certificado folha/end-entity).
    • Nas demais posições, exceto a última, estão os certificados das Autoridades Certificadoras intermediárias, ordenados hierarquicamente onde cada certificado na posição i é assinado pelo certificado na posição i+1. Observe que pode não existir certificado intermediário.
    • Na última posição está o certificado da Autoridade Certificadora Raiz (AC-Raiz ICP-Brasil).
    • A chave pública do certificado na posição i deve validar a assinatura do certificado na posição i-1.
    • O campo subject do certificado i+1 deve corresponder ao campo issuer do certificado i
    • Todos os certificados devem conter a extensão Certificate Policies com OID iniciado por 2.16.76.1 (ICP-Brasil).
  5. Timestamp de referência: valor inteiro Unix UTC (segundos desde 1970-01-01T00:00:00Z) fornecido pelo cliente como referência temporal para o processo de assinatura. Este timestamp será usado para:
    • Validações de validade temporal dos certificados (notBefore ≤ timestamp ≤ notAfter).
    • Geração do claim iat (quando estratégia iat).
    • Verificações de revogação baseadas em tempo.

    Requisitos obrigatórios:

    • Formato: número inteiro sem frações (conforme NumericDate do RFC 7519).
    • Intervalo válido: [1751328000, 4102444800] (1º julho 2025 a 31 dezembro 2099).
    • Qualidade temporal: recomenda-se que o cliente obtenha o timestamp de fonte sincronizada (NTP) com desvio máximo de ±5 minutos do UTC real.
  6. Estratégia (string) que determina a fonte do instante temporal da assinatura. Valores permitidos:
    • iat: usa o timestamp de referência (item 5) como instante da assinatura (estratégia padrão). A compatibilidade temporal com o certificado signatário será verificada durante o processo de validação.
    • tsa: solicita carimbo de tempo de uma TSA (Timestamping Authority) externa conforme RFC 3161. Fornece prova criptográfica independente do momento da assinatura. A configuração da TSA é fornecida no item 8.
  7. Identificação da política de assinatura digital (string): URI canônica que identifica de forma única a versão específica da política de assinatura aplicável ao processo. Esta URI será incorporada no atributo sigPId (Signature Policy Identifier) do JAdES durante a etapa 7.5 do processo. Formato obrigatório:
    • Base URI: https://fhir.saude.go.gov.br/r4/seguranca/ImplementationGuide/br.go.ses.seguranca
    • Separador: | (pipe character)
    • Versão: string no formato semântico major.minor.patch (ex: 0.0.2)
    • URI completa: {baseUri}|{versão}

    Exemplo: https://fhir.saude.go.gov.br/r4/seguranca/ImplementationGuide/br.go.ses.seguranca|0.0.2

  8. Configurações operacionais: parâmetros estruturados para controle do processo de assinatura. Estas configurações são fornecidas por um objeto JSON cujas propriedades identificam domínios funcionais (também detalhados por objetos JSON):

    • Configurações de verificação (verification):
      • ocspCacheTtl: valor positivo em segundos, padrão 3600 (1 hora), intervalo válido [300, 86400], define tempo de vida para respostas OCSP em cache. Implementação: usar timestamp Unix UTC para controle de expiração.
      • crlCacheTtl: valor positivo em segundos, padrão 3600 (1 hora), intervalo [300, 86400], define tempo de vida para listas CRL em cache. Implementação: usar timestamp Unix UTC para controle de expiração.
      • ocspTimeout: valor positivo em segundos, padrão 20, intervalo [5, 120]. Note: em ambiente browser pode ser limitado por políticas CORS.
      • crlTimeout: valor positivo em segundos, padrão 20, intervalo [5, 120]. Note: em ambiente browser pode ser limitado por políticas CORS.
      • tsaTimeout: valor positivo em segundos, padrão 20, intervalo [5, 120].
      • maxRetries: inteiro positivo, padrão 3, intervalo [1, 5], define número máximo de tentativas para consultas OCSP/CRL/TSA em caso de falha de rede.
      • retryInterval: valor positivo em segundos, padrão 2, intervalo [1, 10], define intervalo entre tentativas de retry para consultas OCSP/CRL/TSA.
      • tsaUrl: string não vazia iniciada por https:// exigida quando a estratégia é tsa (item 6 da entrada), deve ser uma URL válida conforme RFC 3986 para serviços TSA RFC 3161. Validação: usar regex ^https://[^\s]+$ ou parser de URL nativo da linguagem.
      • tsaUsername: (opcional) string UTF-8 para autenticação HTTP Basic na TSA, se requerida pelo servidor TSA. Implementação: codificar como Base64(usuario:senha) no header Authorization: Basic <base64>.
      • tsaPassword: (opcional) string UTF-8 para autenticação HTTP Basic na TSA, se requerida pelo servidor TSA. Implementação: usar junto com usuário para formar credencial Base64.
    • Configurações de trust store (trustStore):
      • rootCertificates: array não vazio de strings, cada elemento contendo um certificado AC-Raiz ICP-Brasil completo em formato PEM (incluindo delimitadores -----BEGIN CERTIFICATE----- e -----END CERTIFICATE-----)
      • Identificação por hash: localização de certificados pode ser feita calculando o hash SHA-256 do certificado em formato DER (64 caracteres hexadecimais)
      • Validação criptográfica: utilizar a chave pública do certificado raiz correspondente para validar a assinatura do certificado imediatamente inferior na cadeia
    • Configurações de política temporal (temporalPolicy):
      • minCertificateDate: timestamp Unix UTC (inteiro positivo), padrão 1751328000 (1º julho 2025), define a data mínima para aceitação de certificados signatários emitidos após esta data
    • Configurações de limites de segurança (security):
      • maxEntriesBundle: número máximo de entradas na instância do Bundle definido por um inteiro positivo, padrão 1000, intervalo [100, 10000]
      • maxBundleSize: tamanho máximo da instância do Bundle definido por um inteiro positivo, padrão 52428800 (50MB), intervalo [1048576, 209715200] (1MB-200MB).
      • timoutVerificationBundle: timeout de verificação do Bundle em segundos definido por um inteiro positivo, padrão 10, intervalo [5, 300].
    • Configurações de middleware criptográfico aplicável para SMARTCARD/TOKEN (middlewareCrypto):
      • Biblioteca:
        • Caminho: string não vazia com caminho absoluto para biblioteca PKCS#11 (.dll/.so), deve ser um arquivo existente e acessível
        • Arquitetura: especificação de 32/64 bits se necessário para compatibilidade
      • PKCS#11:
        • Slot ID: inteiro não negativo para identificação do slot (opcional, padrão: descoberta automática)
        • Token label: string até 32 caracteres UTF-8 para identificação do token (opcional, usado quando múltiplos tokens estão presentes)
        • Mecanismos: array não vazio de strings com mecanismos PKCS#11 suportados, valores válidos: ['CKM_RSA_PKCS', 'CKM_ECDSA']
      • Sessão:
        • Modo: enumeração exata ['read-only', 'read-write'], padrão 'read-only', define o tipo de acesso à sessão PKCS#11
        • Timeout de inatividade: valor positivo em segundos, padrão 300, intervalo [60, 3600]
        • Tentativas de autenticação: inteiro positivo, padrão 3, intervalo [1, 10]
      • Conectividade:
        • Timeout de conexão: valor positivo em segundos, padrão 10, intervalo [3, 60]
        • Intervalo de retry: valor positivo em segundos, padrão 2, intervalo [1, 30]
        • Máximo de retries: inteiro não negativo, padrão 3, intervalo [0, 10]

Saída

  1. A assinatura digital em conformidade com a Política de Assinatura Digital Avançada conforme a versão da política identificada na entrada. A assinatura é registrada em uma instância do tipo de dados Signature em conformidade com o perfil assinatura avançada.

  2. A instância de Signature é retornada apenas em caso de sucesso. Em caso de falha é retornada uma instância do recurso OperationOutcome contendo detalhes da situação excepcional que impede a produção da assinatura. Para garantir consistência e interoperabilidade, implementações devem utilizar o perfil Falha de Assinatura Digital e os códigos padronizados definidos no CodeSystem Situações Excepcionais.

  3. Registros de auditoria devem ser realizados, conforme caso de uso de auditoria, para garantir rastreabilidade e capacidade de investigação de incidentes de segurança.

Processo

A saída é produzida a partir das entradas por um processo dividido em 14 etapas que agrupam dezenas de ações. Muitas delas podem resultar em falhas. Todas as falhas são identificadas ao longo do processo e a ocorrência de qualquer uma delas interrompe o processo sem que a assinatura seja criada. Toda falha resulta em um instância de OperationOutcome retornada com um código específico.

Abaixo segue um diagrama com as dependências de dados entre as várias ações.

Instância doBundle (E1)Instância doProvenance (E2)Material criptográfico (E3)Cadeia de certificados (E4)Timestamp de referência (E5)Estratégia (E6)Política de assinatura (E7)Configuraçõesoperacionais (E8)1 Verificar as entradas2 Validaros certificados3 Remover oselementos não assinados4 Canonicalizar as cópias5 Gerar a impressão digitaldo conteúdo assinado6 Codificar na base64Url7 Definir oprotected header8 Definir o payload9 Criar a string para a assinatura10 Criar a assinatura11 Montar o JWS preliminar12 Gerar o carimbo de tempo13 Montar o JWS final14 Encapsular o JWS no tipo de dados SignatureConfiguraçõesCópiasCópiascanonicalizadasHash SHA-256Hash na base64UrlCadeia validadaPolíticaverificadaTimestampverificadoEstratégiaverificadaprotectedheaderpayloadstring de assinaturachave privadaAssinatura JWSJWS preliminarConfig TSAJWS comcarimbo de tempoJWS final

1 Verificar as entradas

Todos os itens da entrada serão rigorosamente verificados quanto à conformidade com os requisitos da versão da política de assinatura digital avançada (uma das entradas).

1.1 Verificação da política de assinatura:

  • Obtenha a URI da política fornecida na entrada (item 7 das entradas).
  • Verificação de formato da URI:
    • Confirme que inicia com https://fhir.saude.go.gov.br/r4/seguranca/ImplementationGuide/br.go.ses.seguranca|
    • Verifique se contém exatamente um separador | (pipe character)
    • Confirme que a versão após o | segue o formato semântico major.minor.patch (ex: 0.0.2)
    • Se o formato for inválido, retorne código POLICY.URI-INVALID
  • Verificação de suporte: confirme se a implementação atual oferece suporte para a versão da política especificada na URI.
  • Se não for oferecido suporte para a versão da política indicada, retorne um OperationOutcome com código POLICY.VERSION-UNSUPPORTED, detalhando:
    • A versão solicitada da política
    • As versões contempladas pela implementação atual
    • Orientação para uso de versão compatível
  • Esta verificação deve ocorrer antes de qualquer processamento criptográfico (evitando eventual desperdício de recursos computacionais).

Nota
A verificação prévia da política garante que toda a operação de assinatura seja executada conforme regras conhecidas e testadas pela implementação.

1.2 Verificação do timestamp de referência:

  • Obtenha o timestamp de referência fornecido na entrada (item 5 das entradas).
  • Verificação de formato: confirme se é um número inteiro válido sem frações.
  • Verificação de intervalo: confirme se está no intervalo [1751328000, 4102444800] (1º julho 2025 a 31 dezembro 2099).
  • Se o formato for inválido, retorne OperationOutcome com código CONFIG.INVALID-TIMESTAMP-FORMAT.
  • Se estiver fora do intervalo, retorne OperationOutcome com código CONFIG.TIMESTAMP-OUT-OF-RANGE.

1.3 Verificação da estratégia de timestamp:

  • Obtenha a estratégia fornecida na entrada (item 6 das entradas).
  • Verificação de valor: confirme se o valor é exatamente iat ou tsa.
  • Se o valor for diferente de iat ou tsa, retorne OperationOutcome com código CONFIG.INVALID-STRATEGY.
  • Para estratégia tsa: verifique se as configurações de TSA estão presentes no item 8 (URL da TSA, timeout para solicitações TSA). Se alguma configuração obrigatória estiver ausente, retorne código CONFIG.TSA-CONFIG-MISSING.

1.4 Verificação estrutural da instância do Bundle:

  • Conformidade FHIR: verifique se a instância do Bundle está em conformidade com a especificação FHIR R4. Se não estiver conforme, retorne OperationOutcome com código FORMAT.BUNDLE-MALFORMED.
  • A instância do Bundle deve conter pelo menos uma entrada em Bundle.entry. Caso contrário, retorne código FORMAT.BUNDLE-EMPTY.
  • Verificação de fullUrl. Para cada Bundle.entry, verifique se:
    • entry.fullUrl está presente e não vazio.
    • entry.fullUrl segue o formato UUID válido (urn:uuid: seguido de UUID RFC 4122).
    • A instância do Bundle não contém fullUrl duplicado.
    • Se alguma verificação falhar, retorne código FORMAT.BUNDLE-MALFORMED com detalhes específicos em diagnostics.
  • Limites de segurança (aplique os seguintes limites para prevenir ataques de negação de serviço):
    • Máximo de entradas em Bundle.entry: use o valor configurado nas configurações operacionais. Se superior, retorne SECURITY.BUNDLE-SIZE-LIMIT-EXCEEDED.
    • Tamanho máximo do JSON serializado: use o valor configurado nas configurações operacionais. Se superior, retorne SECURITY.BUNDLE-MEMORY-LIMIT-EXCEEDED.
    • Timeout de verificação do Bundle: use o valor configurado nas configurações operacionais. Se superior, retorne SECURITY.BUNDLE-TIMEOUT-EXCEEDED.

1.5 Verificação estrutural da instância do Provenance:

  • Conformidade FHIR: verifique se a instância do Provenance está em conformidade com a especificação FHIR R4. Se não estiver conforme, retorne OperationOutcome com código FORMAT.PROVENANCE-INVALID.
  • A instância do Provenance deve conter pelo menos uma referência em Provenance.target. Se vazio, retorne código FORMAT.PROVENANCE-INVALID.
  • Cada referência em Provenance.target deve ser do tipo uuid, ou seja, urn:uuid: seguido de UUID RFC 4122. Se o tipo é inválido, retorne FORMAT.PROVENANCE-TARGET-INVALID.
  • A instância do Provenance não contém Provenance.target duplicado. Se conter, retorne FORMAT.PROVENANCE-TARGET-DUPLICATE.
  • Em Provenance.target deve existir um limite máximo conforme configurado nas configurações operacionais. Se superior, retorne SECURITY.PROVENANCE-SIZE-LIMIT-EXCEEDED.

1.6 Verificação da disponibilidade na instância do Bundle das referências em Provenance.target. Para cada referência em Provenance.target deve existir exatamente uma única entrada (Bundle.entry) correspondente na instância do Bundle:

  • Se nenhuma entrada Bundle.entry.fullUrl possui o mesmo valor da referência em Provenance.target, retorne FORMAT.TARGET-REFERENCE-MISSING.
  • Se mais de uma entrada Bundle.entry.fullUrl possui o mesmo valor da referência em Provenance.target, retorne FORMAT.BUNDLE-DUPLICATE-ENTRY.

1.7 Verificação da disponibilidade das instâncias referenciadas:

  • Para cada entrada da instância do Bundle, Bundle.entry, correspondente a uma instância referenciada, Provenance.target, o elemento Bundle.entry.resource deve estar presente. Caso contrário, retorne FORMAT.BUNDLE-RESOURCE-MISSING.

1.8 Verificação do conteúdo das instâncias referenciadas:

  • Para cada entrada da instância do Bundle, Bundle.entry, correspondente a uma instância referenciada, Provenance.target, verifique se a instância contida em Bundle.entry.resource está em conformidade com o padrão FHIR. Caso contrário, retorne FORMAT.BUNDLE-MALFORMED. Não é feita nenhuma verificação de conformidade da instância com eventuais perfis declarados em meta.profile. A verificação apenas garante que se trata de uma instância FHIR em conformidade com a versão 4.0.1, sem incluir perfis específicos.

Nota
A não verificação de conformidade com perfis específicos declarados em meta.profile pode representar riscos que estão além do escopo da assinatura digital.

1.9 Verificação de referências do conteúdo assinado:

  • Para cada instância referenciada em Provenance.target, examine todos os elementos do tipo Reference presentes na instância.
  • Verifique se cada elemento Reference utiliza exatamente uma das seguintes opções mutuamente exclusivas:
    • Identificador lógico: Reference.identifier está presente e Reference.reference está ausente.
    • Referência UUID: Reference.reference no formato urn:uuid: seguido de UUID RFC 4122 válido e Reference.identifier está ausente.
    • Referência contained: Reference.reference com fragmento #id para recurso incorporado na mesma instância e Reference.identifier está ausente.
    • Referência container: Reference.reference com valor # (usado quando instância contida referencia sua instância container) e Reference.identifier está ausente.
  • Se algum elemento Reference não satisfizer uma dessas opções ou utilizar múltiplas opções simultaneamente, retorne código FORMAT.REFERENCE-INVALID especificando a instância e o elemento problemático.
  • Para referências UUID, verifique se existe uma entrada no Bundle com fullUrl igual ao valor da referência. Se não existir, retorne código FORMAT.REFERENCE-MISSING.
  • Para referências contained, verifique se o recurso com o ID especificado existe no array contained da mesma instância. Se não existir, retorne código FORMAT.REFERENCE-MISSING.

1.10 Verificação do instante de tempo:

  • Obtenha o instante de tempo Unix UTC fornecido na entrada (item 5 das entradas).
  • Verificação de formato: confirme que o valor é um inteiro positivo representando segundos desde 1970-01-01T00:00:00Z.
  • Verifique se o instante está dentro de uma janela aceitável:
    • Não deve ser anterior à data mínima configurada nas configurações operacionais (item 8 das entradas).
    • Não deve ser posterior ao instante atual + margem de tolerância (máximo 1 minuto para compensar diferenças de relógio).
    • Se o instante estiver fora da janela aceitável, retorne código FORMAT.INVALID-TIMESTAMP.

1.11 Verificação das configurações operacionais (item 8 das entradas):

  • Configurações de cache e TSA:
    • TTL de cache: confirme que está entre 300 segundos (5 minutos) e 86400 segundos (24 horas). Se fora da faixa, retorne código CONFIG.TTL-OUT-OF-RANGE.
    • Timeouts: confirme que todos os valores estão entre 5 segundos e 120 segundos. Se algum valor estiver fora da faixa, retorne código CONFIG.TIMEOUT-OUT-OF-RANGE.
    • URL da TSA (quando estratégia tsa):
      • Verifique se a URL usa protocolo HTTPS.
      • Confirme que o formato da URL é válido.
      • Se a URL for inválida ou não usar HTTPS, retorne código CONFIG.TSA-URL-INVALID.
      • Opcional: teste de conectividade básica (ping/DNS resolution).
  • Configurações de trust store:
    • Verifique se o array de certificados não está vazio. Se vazio, retorne código CONFIG.TRUST-STORE-EMPTY.
    • Para cada certificado no array:
      • Confirme que é uma string PEM válida com delimitadores corretos. Se inválido, retorne código FORMAT.CERT-PEM-INVALID.
      • Decodifique o certificado de PEM para DER e valide o formato X.509. Se inválido, retorne código CERT.INVALID-FORMAT.
      • Calcule o hash SHA-256 e compare com hashes conhecidos da ICP-Brasil. Se não corresponder, retorne código CONFIG.TRUST-STORE-NOT-ICP-BRASIL.
  • Configurações de política temporal:
    • Data mínima para certificados: confirme que é um timestamp Unix UTC válido (inteiro positivo). Se inválido, retorne código CONFIG.CERT-MIN-DATE-INVALID.
    • Verifique se a data mínima está no intervalo razoável [1609459200, 4102444800] (2021-2100). Se fora da faixa, retorne código CONFIG.CERT-MIN-DATE-OUT-OF-RANGE.
  • Configurações de limites de segurança:
    • Máximo de entradas no Bundle: confirme que está entre 100 e 10000. Se fora da faixa, retorne código CONFIG.BUNDLE-SIZE-LIMIT-OUT-OF-RANGE.
    • Tamanho máximo do JSON: confirme que está entre 1048576 bytes (1MB) e 209715200 bytes (200MB). Se fora da faixa, retorne código CONFIG.BUNDLE-MEMORY-LIMIT-OUT-OF-RANGE.
    • Timeout de verificação: confirme que está entre 5 segundos e 300 segundos. Se fora da faixa, retorne código CONFIG.BUNDLE-TIMEOUT-OUT-OF-RANGE.
  • Material criptográfico (validação baseada no tipo fornecido na entrada 3):
    • Material criptográfico PKCS#12:
      • Alias: se especificado, confirme que é uma string não vazia com máximo 64 caracteres. Se inválido, retorne código MIDDLEWARE.TOKEN-LABEL-INVALID.
      • Senha: confirme que é uma string não vazia. Se ausente ou vazia, retorne código CONFIG.MISSING-PARAMETER.
      • Conteúdo PKCS#12: verifique se é uma string base64 válida. Se inválido, retorne código FORMAT.BASE64-INVALID.
  • Configurações de middleware criptográfico (aplicável apenas quando a chave privada for do tipo SMARTCARD ou TOKEN):
    • Biblioteca de middleware:
      • Verifique se o caminho da biblioteca existe e é acessível. Se não existir, retorne código MIDDLEWARE.LIBRARY-PATH-INVALID.
      • Confirme que o arquivo é uma biblioteca dinâmica válida (.dll/.so). Se formato inválido, retorne código MIDDLEWARE.LIBRARY-INVALID-FORMAT.
      • Teste de carregamento da biblioteca (dlopen/LoadLibrary).
      • Se a biblioteca não puder ser carregada, retorne código MIDDLEWARE.LIBRARY-NOT-FOUND.
    • Configurações PKCS#11:
      • Slot ID: se especificado, confirme que é um valor numérico não negativo. Se inválido, retorne código MIDDLEWARE.SLOT-ID-INVALID.
      • Token label: se especificado, confirme que é uma string não vazia com máximo 32 caracteres. Se inválido, retorne código MIDDLEWARE.TOKEN-LABEL-INVALID.
      • Mecanismos: verifique se pelo menos um mecanismo suportado está listado (CKM_RSA_PKCS, CKM_ECDSA). Se nenhum suportado, retorne código MIDDLEWARE.UNSUPPORTED-MECHANISMS.
    • Configurações de sessão:
      • Modo de sessão: confirme que é 'read-only' ou 'read-write'. Se inválido, retorne código MIDDLEWARE.SESSION-MODE-INVALID.
      • Timeout de inatividade: confirme que está entre 60 segundos e 3600 segundos. Se fora da faixa, retorne código MIDDLEWARE.TIMEOUT-OUT-OF-RANGE.
      • Tentativas de autenticação: confirme que está entre 1 e 10. Se fora da faixa, retorne código MIDDLEWARE.AUTH-ATTEMPTS-OUT-OF-RANGE.
    • Configurações de conectividade:
      • Timeout de conexão: confirme que está entre 3 segundos e 60 segundos. Se fora da faixa, retorne código MIDDLEWARE.TIMEOUT-OUT-OF-RANGE.
      • Intervalo de retry: confirme que está entre 1 segundo e 30 segundos. Se fora da faixa, retorne código MIDDLEWARE.RETRY-CONFIG-INVALID.
      • Máximo de retries: confirme que está entre 0 e 10. Se fora da faixa, retorne código MIDDLEWARE.RETRY-CONFIG-INVALID.
  • Se alguma configuração for inválida, retorne o código específico correspondente conforme especificado acima. Para casos não cobertos pelos códigos específicos, use CONFIG.INVALID-PARAMETER ou MIDDLEWARE.INVALID-CONFIG especificando o parâmetro problemático.
  • Se alguma das configurações não estiver presente, então deve retornar CONFIG.MISSING-PARAMETER.

2 Validar os certificados

2.1 Obtenha a cadeia de certificados X.509 fornecida na entrada (item 4 das entradas).

2.2 Verifique se a cadeia possui pelo menos 2 certificados (signatário/folha + pelo menos um certificado adicional de uma AC). Se contiver menos de 2 certificados, retorne código CERT.CHAIN-INCOMPLETE.

2.3 Verifique o formato de cada certificado da cadeia de certificados:

  • Decodifique cada certificado da cadeia para o formato binário (DER). Se não for possível, retorne código FORMAT.BASE64-INVALID.
  • Verifique se o formato resultante (DER) é válido. Se inválido, retorne código CERT.INVALID-FORMAT.

2.4 Validação da raiz ICP-Brasil:

  • Obtenha os certificados raiz ICP-Brasil confiáveis das configurações operacionais (item 8 das entradas).
  • Obtenha o certificado raiz (último da cadeia de certificados fornecida).
  • Calcule o hash SHA-256 do certificado raiz fornecido em formato DER.
  • Converta o hash calculado para formato hexadecimal (64 caracteres).
  • Para cada certificado no trust store:
    • Calcule o hash SHA-256 do certificado do trust store em formato DER.
    • Compare com o hash do certificado raiz fornecido.
    • Se encontrar correspondência, prossiga para validação criptográfica.
  • Se nenhuma correspondência for encontrada, retorne código CERT.NOT-ICP-BRASIL.
  • Validação criptográfica adicional: Use a chave pública do certificado raiz correspondente para verificar a assinatura do certificado imediatamente inferior na cadeia.

2.5 Verificação de elegibilidade ICP-Brasil:

  • Obtenha o certificado folha (primeiro certificado da cadeia de certificados).
  • Examine a extensão Certificate Policies (OID 2.5.29.32) do certificado folha:
    • Verifique se existe pelo menos uma política com OID iniciada por 2.16.76.1 (raiz da árvore de políticas ICP-Brasil).
    • Se nenhuma política ICP-Brasil for encontrada, retorne OperationOutcome com código CERT.NOT-ICP-BRASIL informando que o certificado não é elegível para assinatura digital avançada.
    • Esta verificação prévia evita processamento desnecessário de certificados auto-assinados ou de outras PKI.

2.6 Validação do certificado do signatário:

  • Obtenha o timestamp de referência fornecido na entrada (item 5 das entradas).
  • Obtenha a data mínima para certificados das configurações operacionais (item 8 das entradas).
  • Verifique se a data de emissão (notBefore) é posterior ou igual à data mínima configurada. Se anterior, retorne código CERT.ISSUE-DATE-TOO-OLD.
  • Confirme que o certificado está temporalmente válido usando o timestamp de referência: notBefore ≤ timestamp de referência ≤ notAfter. Se inválido, retorne código CERT.EXPIRED ou CERT.NOT-YET-VALID conforme aplicável.

Nota
Certificados ICP-Brasil emitidos a partir da data mínima configurada garantem conformidade com as normas técnicas de segurança vigentes, incluindo algoritmos criptográficos e tamanhos de chave adequados aos padrões atuais. A data mínima padrão (1º julho 2025) reflete os requisitos de segurança desta versão da política de assinatura.

2.7 Validação da cadeia de certificados. Para cada certificado da cadeia na posição i (de 0 a n-2, onde n é o total de certificados):

2.7.1 Validação criptográfica:

  • Verifique a assinatura digital do certificado i usando a chave pública do certificado i+1.
  • Se a verificação falhar, retorne OperationOutcome com código CERT.CHAIN-VALIDATION-FAILED.

2.7.2 Validação da hierarquia:

  • Confirme que o subject do certificado i+1 corresponde ao issuer do certificado i. Esta validação garante a continuidade da cadeia de confiança.
  • Se a correspondência falhar, retorne código CERT.CHAIN-VALIDATION-FAILED.

2.7.3 Validação temporal:

  • Obtenha o timestamp de referência fornecido na entrada (item 5 das entradas).
  • Verifique se o certificado está temporalmente válido usando este timestamp: notBefore ≤ timestamp de referência ≤ notAfter.
  • Se o timestamp de referência > notAfter, retorne código CERT.EXPIRED.
  • Se o timestamp de referência < notBefore, retorne código CERT.NOT-YET-VALID.

2.8.4 Validação de revogação: Obtenha as configurações operacionais da entrada (item 8) para TTL de cache e timeouts. Se for empregado cache, consulte o cache antes da consulta online usando o TTL configurado.

  • Extração de informações de revogação do certificado:
    • OCSP: extraia a URL do serviço OCSP da extensão Authority Information Access (AIA) do certificado (OID 1.3.6.1.5.5.7.48.1).
    • CRL: extraia as URLs de distribuição CRL da extensão CRL Distribution Points (CDP) do certificado (OID 2.5.29.31).
    • Se qualquer uma das extensões estiver ausente ou contiver URLs inválidas, retorne código REVOCATION.NO-DISTRIBUTION-POINTS. Não será utilizada nenhuma fonte alternativa para identificação de revogação.
  • Consulte o serviço de revogação, OCSP (preferencial) e CRL (fallback).
    • Timeout: use o valor configurado nas configurações operacionais (item 8), padrão 30 segundos.
  • Tratamento de falhas:
    • Inacessibilidade: retorne código REVOCATION.OCSP-UNAVAILABLE ou REVOCATION.CRL-UNAVAILABLE.
    • Sem conectividade: retorne código REVOCATION.NO-CONNECTIVITY.
    • Certificado revogado: retorne código CERT.REVOKED com detalhes da fonte (OCSP/CRL).
    • Se a resposta OCSP ou CRL for malformada ou incompleta, retornar REVOCATION.RESPONSE-MALFORMED.
    • Se o status for 'unknown', tratar como revogado e retornar CERT.REVOKED com detalhes.
  • Armazenar a resposta para auditoria.
    • Armazenamento LTV: preserve evidências de revogação para validação futura conforme JAdES:
    • Respostas OCSP: armazene a resposta OCSP completa no formato DER codificada em base64. Calcule o hash SHA-512 da resposta DER para inclusão nas referências de revogação.
    • Dados CRL: armazene a CRL completa no formato DER codificada em base64. Calcule o hash SHA-512 da CRL DER para inclusão nas referências de revogação.
    • As evidências e seus hashes SHA-512 serão incluídos no unprotected header JWS na propriedade rRefs durante a etapa 12.2 ou 13.1.

3 Remover os elementos não assinados

3.1 Identifique as instâncias a serem assinadas:

  • Percorra cada uma das referências em Provenance.target, na ordem fornecida, e recupere a instância correspondente contida na instância do Bundle.
  • Esta etapa prepara o conjunto ordenado de instâncias que serão processadas nas etapas subsequentes de remoção de elementos, canonicalização e assinatura.

3.2 Crie uma cópia de cada instância a ser assinada: para cada instância recuperada na etapa anterior, crie uma cópia onde os elementos id, meta.versionId, meta.lastUpdated, meta.source e meta.tag são removidos (caso existam). Observe que a remoção não inclui os elementos meta.profile e meta.security. Todos os demais elementos na cópia devem ser rigorosamente idênticos àqueles da instância original.

3.3 A partir deste ponto, todas as operações subsequentes serão realizadas exclusivamente sobre estas cópias com a alteração realizada no item anterior. As instâncias originais não são mais utilizadas no processo de assinatura.

Nota
Os elementos id, meta.versionId, meta.lastUpdated, meta.source e meta.tag são ignorados no processo de geração e validação da assinatura. Isso significa que valores destes elementos podem ser alterados sem invalidar a assinatura ou afetar sua validação.

4 Canonicalizar as cópias

4.1 Para cada uma das cópias das instâncias a serem assinadas (obtidas na etapa 3), aplique o processo de canonicalização JSON conforme especificado na RFC 8785 (JSON Canonicalization Scheme - JCS).

4.2 A canonicalização produz uma representação padronizada e determinística de cada instância JSON, eliminando variações irrelevantes da representação como:

  • Ordem dos elementos/propriedades nos objetos JSON.
  • Espaços em branco desnecessários.
  • Diferentes formas de representar números.
  • Escape de caracteres Unicode.

4.3 O resultado da canonicalização para cada instância é uma sequência de bytes UTF-8 que representa de forma única e determinística o conteúdo da instância, independentemente de como o JSON original foi formatado.

4.4 Mantenha a ordem das instâncias canonicalizadas conforme definido pelas referências em Provenance.target.

5 Gerar a impressão digital do conteúdo assinado

5.1 Obtenha as sequências de bytes UTF-8 canonicalizadas de cada instância (resultado da etapa 4).

5.2 Concatene as sequências de bytes das instâncias canonicalizadas na ordem exata definida pelas referências em Provenance.target. A concatenação deve ser realizada byte a byte, sem separadores, delimitadores ou caracteres adicionais entre as instâncias.

5.3 Calcule o hash SHA-256 da sequência de bytes resultante da concatenação. O resultado será uma sequência de 32 bytes (256 bits) que representa a impressão digital única do conjunto de instâncias assinadas.

5.4 Esta impressão digital garante a integridade do conjunto de dados: qualquer alteração em qualquer uma das instâncias ou mudança na ordem resultará em um hash completamente diferente.

Nota
A ordem de concatenação é crucial para a integridade da assinatura. A mesma ordem definida em Provenance.target deve ser preservada em todas as etapas.

6 Codificar na base64Url

6.1 Obtenha a impressão digital SHA-256 (sequência de 32 bytes) produzida na etapa 5.

6.2 Aplique a codificação base64Url à sequência de bytes do hash SHA-256.

6.3 O resultado será uma sequência de exatamente 43 caracteres (não 44 como no formato base64 padrão, pois o base64Url remove o padding).

6.4 Esta sequência de 43 caracteres base64Url representa de forma compacta a impressão digital do conjunto de instâncias assinadas, adequada para uso em estruturas JWS.

Nota
A codificação base64Url é especificada na RFC 4648 seção 5 e é o padrão para uso em JWS/JWT conforme RFC 7515.

7 Definir o protected header

7.1 Crie um objeto JSON que servirá como protected header do JWS JSON Serialization contendo as seguintes propriedades obrigatórias: alg, x5c e sigPId. A propriedade iat depende da estratégia de indicação do instante de tempo (entrada 5). Estas propriedades e os valores admitidos são documentados nesta seção.

7.2 Defina a propriedade alg (algoritmo de assinatura):

  • Somente após validação completa bem-sucedida, analise o tipo de chave pública contida no certificado do signatário validado.
  • Use RS256 para chaves RSA (RSA com SHA-256).
  • Use ES256 para chaves ECC (ECDSA com SHA-256).
  • O algoritmo deve ser determinado automaticamente pelo tipo de chave pública identificado.
  • O sistema deve oferecer suporte para ambos os algoritmos para criação e validação.
  • Verificação de tamanho de chave: verifique se o tamanho da chave atende aos requisitos mínimos:
    • Chaves RSA: mínimo 2048 bits (recomendado 3072 bits ou superior).
    • Chaves ECC: mínimo 256 bits (curva P-256/secp256r1).
    • Se o tamanho da chave for insuficiente, retorne código CERT.WEAK-KEY.
  • Verificação de algoritmo: confirme que o algoritmo da chave pública do certificado é compatível:
    • Para RSA: algoritmo deve ser rsaEncryption (OID 1.2.840.113549.1.1.1).
    • Para ECC: algoritmo deve ser id-ecPublicKey (OID 1.2.840.10045.2.1) com curva P-256.
    • Algoritmos não suportados devem retornar código CERT.UNSUPPORTED-ALGORITHM.

Nota:
O algoritmo de assinatura e o tamanho da chave devem estar de acordo com as normas técnicas vigentes da ICP-Brasil e com a política de assinatura digital vigente.

7.3 Defina a propriedade x5c com o valor da cadeia de certificados fornecida na entrada (item 4 das entradas).

7.4 Se a estratégia para indicação do instante de tempo (entrada 5) é para o instante auto-declarado, então defina a propriedade iat com o valor fornecido na entrada 7 (instante auto-declarado) se e somente se:

  • O iat deve ser maior ou igual ao notBefore do certificado folha (data de início da validade).
  • O iat deve ser menor ou igual ao notAfter do certificado folha (data de expiração).
  • Se o iat estiver fora do intervalo de validade do certificado folha, o certificado do signatário, retorne OperationOutcome com código TEMPORAL.IAT-OUT-OF-CERT-PERIOD.

Nota
Estratégia iat: timestamp auto-declarado pelo signatário, limitado ao período de validade do certificado. Mitiga riscos de backdating e uso de certificados expirados, mas baseado na confiança no signatário.

Estratégia tsa: Carimbo de tempo fornecido por TSA externa. Inclui prova verificável do momento da assinatura através de terceira parte confiável. A propriedade sigTst será inserida no unprotected header durante a etapa 12.2.

7.5 Defina a propriedade sigPId (Signature Policy Identifier):

  • Crie um objeto JSON com a propriedade id.
  • O valor deve ser a URI da política de assinatura fornecida na entrada (item 7 das entradas).
  • Exemplo: {"id": "https://fhir.saude.go.gov.br/r4/seguranca/ImplementationGuide/br.go.ses.seguranca|0.0.2"}.

Nota
Este atributo identifica unicamente a política de assinatura vigente no momento da geração, permitindo que cada assinatura seja validada conforme as regras específicas da versão da política utilizada. Garante rastreabilidade e evolução normativa do guia.

7.6 Codifique o objeto JSON do protected header em base64Url:

  • Para estratégia iat: o protected header deve conter {"alg": "RS256|ES256", "x5c": [...], "iat": timestamp, "sigPId": {"id": "URI"}}.
  • Para estratégia tsa: o protected header deve conter {"alg": "RS256|ES256", "x5c": [...], "sigPId": {"id": "URI"}}.
  • Serialize o objeto JSON do protected header usando serialização JSON padrão.
  • Codifique o resultado diretamente em base64Url (RFC 4648 seção 5).
  • Não aplique canonicalização JSON - o JWS usa serialização JSON padrão para o protected header.
  • Este protected header codificado será usado na construção da string de assinatura.

Nota
As propriedades alg e x5c são definidas no padrão JWS (RFC 7515) e utilizadas pelo JAdES. As propriedades sigPId e iat são definidas pelo padrão JAdES (JSON Advanced Electronic Signatures). O iat especifica o tempo alegado pelo signatário para a execução do processo de assinatura. O sigTst (quando presente) é colocado no unprotected header e contém o timestamp criptográfico verificável fornecido por uma TSA (Timestamping Authority). Consulte seção 12.2 para detalhes.

8 Definir o payload

8.1 Obtenha a sequência de caracteres base64Url produzida na etapa 6 (impressão digital SHA-256 codificada em base64Url).

8.2 Use diretamente esta sequência de caracteres base64Url como payload do JWS. Não aplique uma nova codificação base64Url, pois o conteúdo já está no formato correto.

8.3 O payload final é exatamente a string base64Url de 43 caracteres obtida na etapa 6, sem modificações adicionais.

8.4 Este payload representa a impressão digital do conteúdo assinado, pronta para ser utilizada na construção do JWS.

Nota
A assinatura é produzida para o valor de hash do conteúdo original. O conteúdo original não acompanha a assinatura JWS - apenas seu hash está presente no payload. Isso permite que a assinatura seja gerada e verificada sem transmitir o conteúdo completo, mas exige que o conteúdo original seja preservado separadamente para permitir a validação posterior.

9 Criar a string para a assinatura

9.1 Obtenha o protected header base64Url produzido na etapa 7.6 e o payload base64Url da etapa 8.

9.2 Crie a string de assinatura (signing input):

  • Concatene protected header e payload com ponto como separador.
  • Formato: protected_header.payload (note o ponto . como separador obrigatório).
  • Exemplo: eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UifQ.
  • Esta string será utilizada para a operação criptográfica de assinatura.

9.3 Codifique a string de assinatura em UTF-8:

  • A string protected_header.payload deve ser codificada usando a codificação UTF-8.
  • Como a string contém apenas caracteres base64Url válidos (A-Z, a-z, 0-9, -, _, .), a codificação UTF-8 produz os mesmos bytes que ASCII.
  • O resultado será um array de bytes que servirá como input para o algoritmo de assinatura criptográfica.

10 Criar a assinatura

10.1 Carregue os bytes produzidos na etapa 9.3 para a criação da assinatura JWS.

10.2 Determine o algoritmo de assinatura:

  • O algoritmo deve corresponder ao valor definido na propriedade alg do header JWS (etapa 7.2).
  • Para RS256 (chaves RSA): aplique assinatura RSA com SHA-256 aos bytes UTF-8.
  • Para ES256 (chaves ECC): aplique ECDSA usando SHA-256 aos bytes UTF-8.

10.3 Acesse a chave privada conforme o tipo fornecido na entrada (item 3 das entradas):

  • PEM: carregue a chave privada diretamente da string PEM. Se a chave estiver protegida por senha, use a senha fornecida.
  • PKCS12:
    • Decodifique o arquivo base64 para obter os bytes do PKCS#12.
    • Abra o arquivo PKCS#12 com a senha fornecida.
    • Se um alias for especificado, localize a chave privada associada ao alias fornecido.
    • Se o alias não for encontrado, retorne código DEVICE.CERTIFICATE-NOT-FOUND.
    • Se o alias for encontrado mas não possuir chave privada associada, retorne código DEVICE.KEY-ACCESS-DENIED.
    • Se nenhum alias for especificado, use a primeira chave privada disponível no arquivo.
    • Extraia a chave privada correspondente.
  • SMARTCARD:
    • Conecte via middleware conforme configurações operacionais da entrada (item 8 das entradas).
    • Autentique com PIN do usuário.
    • Identifique o slot/leitor e o certificado/chave especificados.
    • Prepare para operação de assinatura no dispositivo.
  • TOKEN:
    • Conecte via middleware conforme configurações operacionais da entrada (item 8 das entradas).
    • Autentique com PIN do usuário.
    • Identifique o dispositivo e o certificado/chave especificados.
    • Prepare para operação de assinatura no dispositivo.
  • Se o PIN for inválido, retornar CRYPTO.PIN-INVALID após o número máximo de tentativas configurado (entrada 8). Se o dispositivo estiver bloqueado, retornar CRYPTO.DEVICE-BLOCKED. Se a chave não puder ser acessada, retornar CRYPTO.KEY-INACCESSIBLE.

10.4 Execute a operação criptográfica:

  • Para chaves em software (PEM/PKCS12): execute a operação de assinatura localmente.
  • Para dispositivos seguros (SMARTCARD/TOKEN): envie os dados para assinatura no dispositivo.
  • O resultado será uma sequência de bytes representando a assinatura digital.

10.5 Codifique a sequência de bytes da assinatura digital obtida no passo 10.4 na base64Url. O valor codificado é a assinatura JWS.

Nota
RS256 e ES256 são algoritmos aprovados pela ICP-Brasil e atendem aos requisitos de segurança.

11 Montar o JWS preliminar

11.1 Crie a estrutura JWS JSON preliminar:

  • Protected header: use o protected header base64Url da etapa 7.6.
  • Payload: use o payload base64Url da etapa 8.
  • Signature: use a assinatura criptográfica base64Url da etapa 10.5.
  • Monte estrutura JSON preliminar sem unprotected header.

12 Gerar o carimbo de tempo

Esta seção é exclusiva para o cenário em que a estratégia para indicação do instante de tempo em que a assinatura é gerada deve usar carimbo de tempo (tsa) conforme a entrada (item 5). Se a estratégia, conforme a entrada é iat, então prossiga diretamente para a seção 13, neste caso, nenhuma ação da seção 12 será realizada.

12.1 Solicite carimbo de tempo da TSA:

  • Obtenha a assinatura criptográfica base64Url da etapa 10.5.
  • Decodifique a assinatura base64Url para obter os bytes da assinatura criptográfica.
  • Calcule o hash SHA-256 dos bytes da assinatura criptográfica.
  • Obtenha a URL da TSA e timeout das configurações operacionais (item 8 das entradas).
  • Envie solicitação de carimbo de tempo à TSA especificada na URL com o hash SHA-256 calculado. A solicitação deve adotar uma política de retry para contemplar falhas intermitentes.
  • Timeout: use o valor configurado nas configurações operacionais (item 8), padrão 30 segundos.
  • Valide a resposta da TSA conforme RFC 3161: verifique assinatura do token, hash submetido e certificado da TSA. Para detalhes de implementação, consulte RFC 3161 seções 2.4.2 e 3.2.
  • Se a TSA não responder nesse período retorne TSA.UNAVAILABLE.
  • Se a resposta da TSA indica falha da operação, retorne TSA.INVALID-RESPONSE.
  • Se a validação criptográfica falhar, retorne TSA.VALIDATION-FAILED.
  • Verificar se o timestamp retornado pela TSA está dentro de ±5 minutos do timestamp de referência (entrada 7) e no intervalo de validade do certificado. Se inválido, retornar TEMPORAL.TSA-TIMESTAMP-OUT-OF-BOUNDS.

12.2 Crie o unprotected header com carimbo de tempo TSA e evidências LTV:

  • Crie objeto JSON com propriedade sigTst contendo o token TSA (RFC 3161 codificado em base64).
  • Adicione a propriedade rRefs com referências de revogação coletadas na etapa 2.8.4:
    • ocspRefs: array de objetos contendo referências das respostas OCSP, cada objeto com:
      • digestAlg: algoritmo de hash, obrigatoriamente "http://www.w3.org/2001/04/xmlenc#sha512"
      • digestValue: hash SHA-512 da resposta OCSP em base64
    • crlRefs: array de objetos contendo referências das CRLs, cada objeto com:
      • digestAlg: algoritmo de hash, obrigatoriamente "http://www.w3.org/2001/04/xmlenc#sha512"
      • digestValue: hash SHA-512 da CRL em base64
  • Exemplo: {"sigTst": "token_tsa_base64", "rRefs": {"ocspRefs": [{"digestAlg": "http://www.w3.org/2001/04/xmlenc#sha512", "digestValue": "hash_base64"}], "crlRefs": [{"digestAlg": "http://www.w3.org/2001/04/xmlenc#sha512", "digestValue": "hash_base64"}]}}.
  • Importante: O unprotected header não é codificado em base64Url - permanece como objeto JSON.

Nota
Para estratégia tsa, o carimbo de tempo é aplicado à assinatura criptográfica, garantindo prova verificável do momento em que a assinatura foi gerada. O uso de unprotected header permite adicionar o carimbo de tempo TSA e as evidências de revogação LTV sem invalidar a assinatura criptográfica já criada, conforme especificação JAdES.

Nota A ação 12.2 armazena a CRL/OCSP para cada assinatura, o que pode ser oneroso em termos de espaço de armazenamento.

13 Montar o JWS final

13.1 Finalize a estrutura JWS JSON conforme a estratégia de timestamp:

Para estratégia iat:

  • Obtenha a estrutura JWS JSON preliminar da etapa 11.1.
  • Crie unprotected header apenas com referências de revogação coletadas na etapa 2.8.4:
    • rRefs: objeto contendo referências de revogação:
      • ocspRefs: array de objetos contendo referências das respostas OCSP, cada objeto com:
        • digestAlg: algoritmo de hash, obrigatoriamente "http://www.w3.org/2001/04/xmlenc#sha512"
        • digestValue: hash SHA-512 da resposta OCSP em base64
      • crlRefs: array de objetos contendo referências das CRLs, cada objeto com:
        • digestAlg: algoritmo de hash, obrigatoriamente "http://www.w3.org/2001/04/xmlenc#sha512"
        • digestValue: hash SHA-512 da CRL em base64
    • Exemplo: {"rRefs": {"ocspRefs": [{"digestAlg": "http://www.w3.org/2001/04/xmlenc#sha512", "digestValue": "hash_base64"}], "crlRefs": [{"digestAlg": "http://www.w3.org/2001/04/xmlenc#sha512", "digestValue": "hash_base64"}]}}.
  • Adicione o unprotected header à estrutura inserindo a propriedade header no elemento signatures[0].

Para estratégia tsa:

  • Obtenha a estrutura JWS JSON preliminar da etapa 11.1.
  • Adicione o unprotected header da etapa 12.2 à estrutura (já contém sigTst e rRefs).
  • Insira a propriedade header contendo o objeto JSON no elemento signatures[0].

13.2 Serialize a estrutura JSON final:

  • Use serialização JSON padrão (não canônica).
  • Não adicione espaços em branco ou formatação.
  • O resultado é uma string JSON válida representando a assinatura JWS conforme RFC 7515 seção 3.2.

Estruturas resultantes:

Para estratégia iat (exemplo com ambas as evidências disponíveis):

{
  "payload": "payload_base64url",
  "signatures": [
    {
      "protected": "protected_header_base64url",
      "header": {
        "rRefs": {
          "ocspRefs": [
            {
              "digestAlg": "http://www.w3.org/2001/04/xmlenc#sha512",
              "digestValue": "3mK8xVeRjP7nQw9mF2kLqX1z5vH8tN4sE7dU6oC9bA2yI0rM5jL3xW8kQ7vP1nZ4fG6hJ9sT2eR5uY0aS3iO8"
            }
          ],
          "crlRefs": [
            {
              "digestAlg": "http://www.w3.org/2001/04/xmlenc#sha512",
              "digestValue": "7qZ9mL2xV5eP8nR3fK6jH4tS1oC0bA9yI7rM8xW2kQ4vP6nZ5fG1hJ0sT9eR8uY3aS2iO7dU5oC6bA3yI4rM1"
            }
          ]
        }
      },
      "signature": "signature_base64url"
    }
  ]
}

Para estratégia tsa (exemplo com apenas OCSP disponível):

{
  "payload": "payload_base64url",
  "signatures": [
    {
      "protected": "protected_header_base64url",
      "header": {
        "sigTst": "token_tsa_base64",
        "rRefs": {
          "ocspRefs": [
            {
              "digestAlg": "http://www.w3.org/2001/04/xmlenc#sha512",
              "digestValue": "9sL4xW2eQ8pN7fM5kJ3hG6tR0oD1cB8yI5rP9xV4kL7vN2nX6fH3hK0sU8eT9uY1aQ4iP7dV5oD6cB3yJ4sM2"
            }
          ]
        }
      },
      "signature": "signature_base64url"
    }
  ]
}

Nota sobre evidências de revogação
As evidências LTV em rRefs incluem apenas os tipos de evidência disponíveis conforme determinado na etapa 2.8.4:

  • Se apenas OCSP estiver disponível: inclua apenas ocspRefs
  • Se apenas CRL estiver disponível: inclua apenas crlRefs
  • Se ambos estiverem disponíveis: inclua ocspRefs e crlRefs
  • Os valores digestValue contêm hashes SHA-512 reais das evidências DER codificados em base64 (88 caracteres)

14 Encapsular o JWS no tipo de dados Signature

Nota
A estrutura JWS criada nas etapas anteriores atende aos requisitos de conformidade JAdES (JSON Advanced Electronic Signatures). Os elementos obrigatórios alg, x5c, sigPId no protected header (etapa 7), as evidências LTV rRefs no unprotected header (etapas 12.2/13.1), e o carimbo de tempo sigTst quando aplicável (etapa 12.2) garantem plena conformidade com a especificação JAdES para assinaturas digitais avançadas.

14.1 Serialize o JWS JSON para o formato FHIR Signature:

  • Obtenha a string JWS JSON completa produzida na etapa 13 (formato JWS JSON Serialization).
  • Converta a string JWS JSON para bytes usando codificação UTF-8.
  • Aplique codificação base64 padrão (RFC 4648) aos bytes UTF-8 - não base64Url.
  • O resultado será o valor para o elemento Signature.data.

14.2 Extraia metadados do certificado digital:

  • Acesse o certificado do signatário (primeiro elemento da cadeia fornecida na entrada).
  • Extraia o CNPJ ou CPF do subject do certificado para identificação do signatário:
    • CNPJ: extraia do campo subject o atributo com OID 2.16.76.1.3.3 (CNPJ da pessoa jurídica titular do certificado).
    • CPF: extraia do campo subject o atributo com OID 2.16.76.1.3.1 (CPF da pessoa física titular do certificado).
    • Verifique se exatamente um dos dois OIDs está presente no certificado. Se nenhum ou ambos estiverem presentes, retorne código CERT.MISSING-IDENTIFICATION.
    • O valor extraído deve ser uma string numérica de 11 dígitos (CPF) ou 14 dígitos (CNPJ), sem formatação adicional (pontos, traços ou barras).
  • Determine o tipo de assinatura baseado no contexto de uso (autor vs validador).

14.3 Instancie o tipo de dados Signature conforme especificação FHIR R4:

  • Signature.data (obrigatório): valor base64 da string JWS produzida na etapa 14.1.

  • Signature.sigFormat (obrigatório): application/jose - identifica o formato JWS/JAdES.

  • Signature.targetFormat (obrigatório): application/octet-stream - especifica que o conteúdo efetivamente assinado são bytes de hash SHA-256, não os dados FHIR JSON originais dos quais o hash foi obtido.

  • Signature.type (obrigatório): especifica o propósito da assinatura.
    • system: urn:iso-astm:E1762-95:2013.
    • code: valor do ValueSet signature-type.
      • 1.2.840.10065.1.12.1.1 para assinatura de autoria (autor do conteúdo).
      • 1.2.840.10065.1.12.1.6 para assinatura de validação/aprovação.
      • Outros códigos conforme contexto específico.
  • Signature.who (obrigatório): identifica o signatário.
    • Use Reference.identifier para identificação por CNPJ/CPF.
    • O valor deve corresponder ao CNPJ ou CPF extraído do certificado digital na etapa 14.2.
    • Formato: {"identifier": {"system": "urn:brasil:cnpj|urn:brasil:cpf", "value": "documento"}}.

14.4 Verificação da instância criada:

  • Verifique se todos os elementos obrigatórios estão presentes.
  • Confirme que Signature.data contém uma string base64 válida.
  • Verifique que Signature.who.identifier corresponde ao certificado utilizado.
  • Assegure conformidade com o perfil assinatura avançada.

Nota
O encapsulamento transforma a assinatura JWS JSON Serialization (formato JSON RFC 7515 seção 3.2) para o tipo de dados FHIR Signature, preservando toda a informação criptográfica dentro do elemento data enquanto fornece metadados estruturados nos demais elementos para interoperabilidade no ecossistema FHIR.

Nota
O targetFormat especifica o formato do conteúdo que foi efetivamente submetido à operação criptográfica de assinatura. Neste caso, são os bytes do hash SHA-256 (application/octet-stream), não os dados FHIR JSON originais. Os dados FHIR JSON são o conteúdo semântico preservado para validação, mas o target criptográfico é sua impressão digital SHA-256.

Nota
As evidências LTV (Long Term Validation) incluídas no unprotected header JWS (rRefs) garantem que a assinatura possa ser validada no futuro, mesmo quando os serviços OCSP/CRL originais não estiverem mais disponíveis. Estas evidências seguem o padrão JAdES e contêm provas criptográficas do status de revogação dos certificados no momento da criação da assinatura.

Nota
Esta etapa conclui o processo de criação da assinatura digital. A instância Signature resultante contém toda a informação necessária para validação posterior e deve ser tratada como um artefato criptográfico íntegro.

Não atualização de Provenance.signature

O processo de criação de assinatura digital é determinístico e livre de efeitos colaterais (side-effect free) para um determinado contexto temporal. Isso significa que:

  • Não modifica nenhuma das instâncias fornecidas como entrada (Bundle, Provenance, certificados).

  • Produz resultado consistente quando executado com as mesmas entradas no mesmo contexto temporal.

  • Retorna como saída principal uma instância do tipo de dados Signature (em caso de sucesso) ou uma instância de OperationOutcome (em caso de falha).

  • Produz registros de auditoria conforme especificado no caso de uso de auditoria, independentemente do resultado da operação.

O processo não é idempotente no sentido clássico, pois depende de fatores temporais implícitos:

  • Timestamp de referência: verificações de validade temporal dos certificados (notBefore ≤ timestamp de referência ≤ notAfter) baseadas no timestamp fornecido na entrada.
  • Estado de revogação: consultas OCSP/CRL podem retornar resultados diferentes ao longo do tempo.
  • Disponibilidade de TSA: para estratégia tsa, a disponibilidade da autoridade de carimbo de tempo.
  • Políticas de segurança: atualizações no trust store ICP-Brasil.

Executar o mesmo processo com as mesmas entradas explícitas em momentos diferentes pode produzir:

  • Sucesso vs. Falha: certificado pode expirar ou ser revogado.
  • Códigos de erro diferentes: CERT.EXPIRED, CERT.REVOKED, TSA.UNAVAILABLE.
  • Timestamps diferentes: para estratégia iat, reflete o instante fornecido na entrada.

Validação da assinatura

A validação é tratada em caso de uso próprio. Adicionalmente, a expectativa é que o próprio signatário, ao produzir uma assinatura, faça a validação correspondente conforme esse caso de uso. Desta forma, garantindo que toda a cadeia de certificados será verificada, dentre outras operações. Naturalmente, o próprio signatário deveria evitar o uso de um certificado expirado ou regovado, ao produzir uma assinatura.