Resumo

  • A RFC 3076 não canonizava um arquivo intocado. Um processador XML primeiro convertia os octetos em um conjunto de nós XPath, normalizando e expandindo dados antes da serialização canônica.
  • Bytes canônicos iguais eram um recibo preciso para aquele modelo, escolha de comentários e algoritmo; não reconstruíam a origem nem preservavam automaticamente DTD, URI base ou semântica do aplicativo.

A saída estável começava no meio da cadeia

Em março de 2001, a RFC 3076 e a Recomendação do W3C Canonical XML Version 1.0 responderam a um problema prático. XML permitia várias representações físicas daquilo que muitas aplicações tratavam como a mesma informação. Ordem de atributos, encoding, forma curta de elemento vazio e uso de referências podiam variar. Assinaturas e comparações precisavam de uma representação repetível.

O método emitia UTF-8, removia a declaração XML e o DTD, expandia elementos vazios, fixava aspas, escapava caracteres definidos, eliminava declarações de namespace supérfluas e ordenava namespaces e atributos. Incluir comentários era uma escolha explícita. Reaplicar o mesmo método a uma forma canônica bem-formada não a alterava.

Mas o objeto formal era um conjunto de nós XPath. Quando a entrada vinha em octetos, um parser tinha de criar esse modelo primeiro. A canonicalização encontrava o documento depois da análise.

O parser já havia criado o objeto

O processador normalizava quebras de linha e valores de atributos, substituía CDATA pelo conteúdo, resolvia referências de caracteres e entidades analisadas e podia acrescentar atributos padrão do DTD. Namespaces viravam nós; caracteres consecutivos, nós de texto.

Assim, fontes diferentes convergiam legitimamente. Um caractere literal e sua referência numérica, uma entidade interna e seu texto substituto, ou <e/> e <e></e> podiam gerar o mesmo modelo. Essa convergência era a função da norma.

Também tornava impossível recuperar toda a escrita original. O encoding inicial desaparecia no UTF-8; declaração XML e DTD eram removidos; limites de entidade e CDATA sumiam; a ordem original dos atributos dava lugar à ordem definida. A forma canônica respondia como serializar o modelo, não quais bytes, recursos e políticas o haviam produzido.

O recibo precisa começar antes: hash dos octetos recebidos, URI e instante da coleta, encoding, versão e opções do parser, validação, política para subconjunto externo e entidades, bytes de cada dependência, URI base e atributos adicionados por padrão. O hash final não recria esses dados.

A representação podia permanecer igual e perder comportamento

A RFC apontou informações ausentes do modelo XPath: URI base, sobretudo em conteúdo vindo de entidade externa analisada; notações e entidades externas não analisadas; e tipos de atributo declarados no DTD.

Uma entidade externa pode conter URI relativa. Quando seu texto é inserido no documento principal, a referência pode passar a resolver contra outro local se a base original se perder. Os bytes canônicos continuam estáveis, mas o recurso aberto depois muda. A RFC recomendava xml:base adequado ou resolução prévia para URI absoluta.

O DTD cria outra assimetria. Um atributo padrão já pode estar no nó e aparecer na saída, enquanto a declaração que o forneceu é descartada. Tipos como ID, IDREF, enumeração e NOTATION deixam de acompanhar o arquivo. Um processamento posterior lê o valor, mas não necessariamente seu contrato original.

Notações e entidades não analisadas também podiam ligar dados externos à aplicação. O modelo não preservava todas essas relações. Casos raros continuam relevantes quando o sistema depende deles.

Um conjunto de nós não era uma subárvore automática

Para subconjuntos, XPath entregava nós individuais. Escolher um elemento não escolhia automaticamente atributos, texto e descendentes. Um nó excluído não era emitido por ter pai incluído. Ao mesmo tempo, ancestrais omitidos podiam fornecer namespace ou atributos XML herdáveis.

A RFC responsabilizava o criador do conjunto por preservar o que fosse necessário à semântica. A saída do subconjunto podia nem ser XML bem-formado. “Canônico” não significava completo ou autônomo.

Essa é uma fronteira anterior à da RFC 3075. Ela discute quais referências e transformações uma assinatura cobre. A RFC 3076 discute qual objeto o parser entregou antes dos bytes. Uma assinatura correta não recompõe a origem de análise que não foi guardada.

Canônico não significava toda equivalência possível

A RFC recusou transformar a forma canônica em teste “se e somente se” para todo significado. Uma aplicação pode ignorar espaços ou tratar black e rgb(0,0,0) como a mesma cor. Outras especificações podem acrescentar regras. Formas distintas ainda podem equivaler em um contexto.

Também não havia normalização geral do modelo de caracteres Unicode. Prefixos de namespace eram mantidos porque reescrevê-los poderia quebrar XPath ou valores parecidos com QName dentro de texto ou atributos. Era um contrato limitado e executável, não um motor universal de semântica.

A evolução posterior recolocou o contexto em evidência

Uma nota do W3C de 2006 mostrou que C14N 1.0 podia copiar um xml:base relativo para um descendente sem recompor o caminho dos ancestrais, alterando a URI efetiva. A chegada de xml:id também mostrou que um identificador não deveria ser herdado como atributo XML comum.

Canonical XML 1.1 corrigiu esses pontos em 2008: não herdou xml:id e tratou xml:base de modo especial. Isso comprova evolução, não falha de toda implantação anterior. Exclusive XML Canonicalization abordou o contexto de namespaces de fragmentos movidos. A RFC 3275 levou C14N 1.0 ao ambiente de XML Signature. Nenhuma delas transformou o resultado em prova dos bytes originais ou da autorização.

O que preservar

Guarde octetos, origem, encoding e hash; parser e configurações; validação; DTD, catálogos e entidades usados; URI base; atributos padrão; seleção e resultado XPath; comentários; método e versão de canonicalização; e saída final. Depois registre comparação ou assinatura, regra semântica do aplicativo, decisão e efeito observado.

As ideias posteriores de Lu Heng sobre código em execução e camadas de realidade servem como lente declarada. Reproduzir bytes é mais forte que repetir um rótulo. Ainda assim, o recibo de execução não toma para si a história da fonte, a autoridade ou o resultado.

Fontes