Résumé

  • La RFC 3076 ne transformait pas directement un fichier intact : un processeur XML construisait d’abord un jeu de nœuds XPath, après normalisation des lignes et attributs, remplacement des CDATA et résolution des entités analysées.
  • Des octets canoniques identiques prouvaient une représentation reproductible selon un modèle, une option de commentaires et un algorithme donnés ; ils ne restituaient ni le fichier d’origine, ni tout le contexte DTD et URI, ni le sens métier.

Une sortie stable dont l’histoire commençait plus tôt

En mars 2001, la RFC 3076 et la Recommandation W3C Canonical XML Version 1.0 ont résolu un problème concret. XML autorisait plusieurs graphies physiques pour une information que de nombreuses applications traitaient comme identique. L’ordre des attributs, l’encodage, l’écriture d’un élément vide ou l’emploi d’une référence d’entité pouvaient varier. Une signature ou une comparaison d’intégrité avait besoin d’une représentation commune.

La méthode imposait donc une sortie UTF-8, supprimait la déclaration XML et le DTD, développait les éléments vides, fixait les guillemets des attributs, échappait certains caractères, éliminait les déclarations d’espace de noms superflues et triait espaces de noms et attributs. Les commentaires relevaient d’un choix explicite. Une forme canonique bien formée repassée par la même méthode restait inchangée.

Mais l’entrée formelle n’était pas seulement un fichier. C’était un jeu de nœuds XPath. Lorsqu’un flux d’octets arrivait, un processeur XML devait d’abord produire ce modèle. La canonicalisation commençait au milieu de la chaîne.

L’analyseur avait déjà décidé la matière à sérialiser

Avant l’émission du premier octet canonique, le processeur avait normalisé les fins de ligne et les valeurs d’attribut. Il avait remplacé les sections CDATA par leur contenu, résolu les références de caractères et les entités analysées, et pouvait ajouter des attributs par défaut déclarés dans un DTD. Les espaces de noms devenaient des nœuds ; les caractères consécutifs devenaient des nœuds texte.

Deux sources physiquement différentes pouvaient ainsi converger. Un caractère littéral et sa référence numérique, une entité interne et son texte de remplacement, <x/> et <x></x> pouvaient conduire au même modèle puis aux mêmes octets canoniques. C’était le but de la norme.

Cette convergence interdisait toutefois de présenter la sortie comme une archive réversible. L’encodage d’origine avait disparu au profit d’UTF-8. La déclaration XML et le DTD n’étaient plus présents. Les frontières des entités et des CDATA avaient disparu. L’ordre initial des attributs avait été remplacé. La forme canonique répondait à « quelle représentation déterministe de ce modèle ? », non à « quels octets et quelles ressources ont fabriqué ce modèle ? ».

Un reçu sérieux doit donc commencer avant l’algorithme : hachage des octets reçus, URI de récupération, encodage annoncé, identité et réglages de l’analyseur, validation, politique d’accès aux sous-ensembles externes et aux entités, contenu effectivement récupéré, URI de base et attributs ajoutés par défaut. Le condensat canonique ne reconstitue aucun de ces éléments.

Une même forme pouvait perdre un comportement

La RFC exposait elle-même trois pertes du modèle XPath : l’URI de base, surtout pour du contenu provenant d’une entité analysée externe ; les notations et entités externes non analysées ; les types d’attribut définis dans le DTD.

Le cas de l’URI de base est décisif. Une entité externe peut contenir une URI relative. Une fois son texte inséré dans le document hôte, cette URI peut être résolue par rapport à un autre emplacement si le contexte originel n’est pas conservé. La suite canonique demeure stable tandis que la ressource atteinte change. La RFC recommandait de fournir un xml:base approprié ou de rendre les URI absolues avant canonicalisation.

Le DTD produisait une asymétrie analogue. Un attribut par défaut pouvait déjà figurer dans le jeu de nœuds, alors que la déclaration qui l’avait créé était retirée. Les contraintes ID, IDREF, énumération ou NOTATION ne voyageaient plus avec le fichier canonique. Une lecture ultérieure retrouvait les caractères, pas nécessairement le contrat de type.

Qualifier ces cas d’inhabituels ne les annule pas. Dès qu’une application dépend d’une entité, d’une notation, d’un type ou d’une URI relative, la provenance de l’entrée devient une partie de la preuve.

Un jeu de nœuds n’était pas un sous-arbre implicite

Pour un sous-ensemble de document, XPath fournissait un ensemble de nœuds individuels. Sélectionner un élément n’incluait pas automatiquement tous ses attributs, textes et descendants. Un nœud exclu n’était pas rendu parce que son parent l’était. Pourtant, un ancêtre omis pouvait encore fournir un contexte d’espace de noms ou un attribut XML héritable.

La RFC attribuait donc au créateur du jeu de nœuds la responsabilité de préserver l’information nécessaire à la sémantique des membres. La sortie d’un sous-ensemble pouvait même ne pas être un document XML bien formé. Son statut canonique ne prouvait ni exhaustivité ni autonomie.

Cette frontière diffère de celle de la RFC 3075. Celle-ci porte sur les références et transformations couvertes par une signature. La RFC 3076 porte sur la constitution de l’objet avant la sérialisation. Une signature parfaite hérite toujours des choix de l’analyseur et du jeu de nœuds.

Canonique ne signifiait pas équivalent dans tous les mondes

La RFC 3076 ne cherchait pas une équivalence « si et seulement si ». Une application pouvait ignorer certains blancs, traiter black et rgb(0,0,0) comme la même couleur, ou appliquer une règle provenant d’une autre spécification. Deux formes canoniques différentes pouvaient donc rester équivalentes pour elle.

Inversement, la méthode ne réalisait pas une normalisation générale des caractères Unicode. Elle conservait les préfixes d’espace de noms, car les réécrire pouvait casser un XPath ou un QName écrit comme texte dans un attribut ou un élément. Le résultat était un contrat précis sur le modèle XPath, non un moteur universel de sens.

Les corrections ultérieures ont confirmé l’importance du contexte

Une note W3C de 2006 a documenté un défaut des règles de sous-ensemble de C14N 1.0 : recopier un xml:base relatif sans recomposer le chemin des ancêtres pouvait changer l’URI effective. L’apparition de xml:id a aussi montré que cet identifiant ne devait pas être hérité comme un attribut ordinaire de l’espace XML.

Canonical XML 1.1, Recommandation W3C de 2008, a introduit un traitement particulier de xml:base et interdit l’héritage de xml:id. Cela prouve une évolution de la spécification, pas l’échec de chaque déploiement antérieur. Exclusive XML Canonicalization a traité un autre problème voisin, celui du contexte d’espace de noms d’un fragment déplacé. La RFC 3275 a rendu C14N 1.0 indispensable dans XML Signature. Aucun de ces textes ne transforme la sortie canonique en preuve du fichier originel ou de l’autorisation applicative.

Les reçus à conserver

Il faut garder le flux source, son origine et son hachage ; le type de média et l’encodage ; la version et la configuration de l’analyseur ; le mode de validation ; tous les DTD, catalogues et entités réellement consommés ; l’URI de base ; les espaces de noms et attributs ajoutés ; l’expression et le résultat XPath ; le choix des commentaires ; l’URI et la version de canonicalisation ; puis les octets canoniques.

Après cette étape viennent encore la comparaison ou la signature, la règle d’équivalence métier, la décision et l’effet observé. La lecture ultérieure de Lu Heng sur la primauté du code exécutable et les couches de réalité aide à nommer cette discipline : une sortie reproductible est une preuve forte de son propre niveau, pas un passeport vers tous les autres.

Sources