Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

echoping

Ève

Ce blog n'a d'autre prétention que de me permettre de mettre à la disposition de tous des petits textes que j'écris. On y parle surtout d'informatique mais d'autres sujets apparaissent parfois.


Mon compte mojeID

Première rédaction de cet article le 23 mai 2015


Le système d'identité mojeID, auparavant réservé aux habitants de la république tchèque, est désormais ouvert au monde. J'ai donc pu me créer un compte.

À quoi sert mojeID ? C'est un système d'identité, donc un stockage sécurisé des caractéristiques (publiques et privées) d'une personne ou d'une organisation, avec des interfaces pour utiliser cette identité depuis des sites tiers. Cela permet de garder une identité constante, tout en allant sur de nombreux sites. En république tchèque, mojeID est très populaire et est utilisé par de nombreux sites Web, soit via l'API spécifique de mojeID, soit via OpenID. En outre, le registre de .cz (qui a créé mojeID) permet de gérer ses domaines via mojeID. En dehors de ce pays, on peut toujours utiliser OpenID, par exemple, mon compte sur OpenStreetMap est un compte mojeID, https://bortzmeyer.mojeid.cz/ (avec OpenID, l'identificateur est un URL.) Au sujet d'OpenID, voir également mon exposé à JRES (un peu ancien).

mojeID fournit également une page Web sommaire rassemblant les informations qu'on a choisi de rendre publiques. Dans l'interface Web de mojeID, on peut choisir d'exporter ou pas l'adresse de son blog, de son compte Twitter, etc, mais il faut bien fouiller la page de son profil pour trouver comment les indiquer : c'est le petit bouton marqué d'un plus.

Et comment s'authentifie-t-on auprès de mojeID ? Le service fournit trois méthodes, le classique mot de passe, un certificat client, et un système à deux facteurs (je n'ai testé que le mot de passe).

Une des particularités de mojeID, par rapport à tant d'autres fournisseurs (au passage, mon compte OpenID habituel est chez Stack Exchange), est de lier ce compte à des informations extérieures (un peu comme le font les places de marché bitcoin ou bien comme le fait le service Keybase). Ainsi, mojeID vérifie l'adresse de courrier donnée (simplement en envoyant un cookie, appelé PIN, qu'on doit renvoyer), le numéro de téléphone (en envoyant un SMS avec le cookie), et l'adresse postale en envoyant une jolie lettre contenant le troisième PIN :

Ce sont ces vérifications qui limitaient autrefois mojeID au pays de Jan Hus.

Comme vous le voyez dans la lettre précédente, bien que l'interface Web soit largement traduite en anglais, une bonne partie de la communication avec mojeID se fait toujours dans la langue de Karel Čapek :-)

Merci à Alix Guillard, Ondřej Surý et Ondřej Filip pour le service, et pour m'avoir encouragé à l'utiliser.


L'article seul

RFC 7565: The 'acct' URI Scheme

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : P. Saint-Andre (Cisco System)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF appsawg
Première rédaction de cet article le 23 mai 2015


Hop, encore un nouveau plan d'URI, le plan acct: (pour account) qui permet de désigner les informations qu'on peut récupérer sur un compte utilisateur. Désormais, acct:stephane@seenthis.net désignera donc mon compte à SeenThis.

Ne vous fiez pas à la ressemblance syntaxique avec les adresses de courrier : la syntaxe est la même (nom-du-compte@nom-du-service) mais les URI acct: sont indépendants du protocole d'accès. Dans l'exemple plus haut, SeenThis ne fournit pas de service de courrier, mais cela ne change rien à l'URI.

Le premier (et pour l'instant quasi-unique) demandeur de ces URI est le protocole WebFinger (RFC 7033). WebFinger permet d'accéder à des informations, via un protocole REST, en utilisant comme identificateur un URI qui, en pratique, est souvent un URI acct:. La version initiale de WebFinger utilisait uniquement des adresses de courrier électronique. Avant le plan acct:, les plans les plus proches identifiaient toujours un protocole particulier : le courrier pour les URI mailto: (RFC 6068) ou XMPP pour les xmpp:... du RFC 5122. Après moultes discussions au sein du groupe de travail sur WebFinger entre les partisans de l'ancien système (adresses de courrier seulement) et ceux d'un nouveau, fondé sur les URI (eux-même divisés entre amateurs de mailto: et fanas de http:), le choix a été fait de créer ce nouveau plan. Comme indiqué, il a l'avantage de ne pas supposer l'existence d'un protocole particulier. Ainsi, mon compte Twitter est désormais acct:bortzmeyer@twitter.com et il n'implique pas que Twitter fournisse du courrier ou de la messagerie instantanée ou quoi que ce soit d'autre.

À noter qu'un URI acct: identifie un compte, que son titulaire soit un humain ou une organisation ou un bot.

La section 4 fournit la définition rigoureuse de ces nouveaux URI (la syntaxe formelle étant repoussée en section 7). Elle rappelle qu'ils servent à l'identification et pas à l'interaction (RFC 3986, section 1.2.2). La partie gauche (à gauche du @) est le nom du compte auprès d'un fournisseur quelconque et la partie droite est un nom de domaine de ce fournisseur. Donc, acct:foobar@status.example.net, acct:user@example.com ou acct:hamlet@dk sont tous des URI valides. Si un client WebFinger cherche de l'information sur le premier de ces URI, il fera une requête HTTP à status.example.net :

GET /.well-known/webfinger?resource=acct%3Afoobar%40status.example.net HTTP/1.1

Si le nom du compte est une adresse de courrier (ce qui est fréquent sur le Web d'aujourd'hui), il faudra convertir le @ en caractères pour-cent. Par exemple, si le compte juliet@capulet.example existe chez le fournisseur shoppingsite.example, l'URI sera acct:juliet%40capulet.example@shoppingsite.example. Et si on prend mon compte au RIPE-NCC, bortzmeyer+ripe@nic.fr, l'URI sera acct:bortzmeyer%2Bripe%40nic.fr@ripe.net. C'est cet URI qui sera mis, par exemple, dans les requêtes WebFinger.

La section 5 du RFC traite des problèmes de sécurité. On ne met évidemment dans une réponse WebFinger que ce qu'on veut bien indiquer, surtout si le client HTTP n'est pas authentifié. Mais il existe un risque plus subtil : même si le client n'arrive pas à accéder aux informations derrière l'URI acct:, la seule existence de cet URI peut indiquer que le compte existe et cela peut donc être utile aux spammeurs et autres nuisibles. Bref, même si les acct: ne sont que des URI, que des identificateurs, ils peuvent en dire trop.

La section 6, elle, se penche sur l'internationalisation. Les URI acct: sont des URI comme les autres (RFC 3986) et peuvent donc contenir n'importe quel caractère Unicode. Il faut simplement qu'ils soient encodés en UTF-8 puis surencodés en pour-cent. Ainsi, un compte stéphane sur le service example.com pourra être représenté par acct:st%C3%A9phane@example.com. Quelques restrictions toutefois :

  • Le nom de compte est limité aux caractères autorisés par le RFC 7564, dans la classe IdentifierClass.
  • Le nom de domaine après le @ est limité aux caractères IDN autorisés dans le RFC 5892, et encodé en Punycode. Ainsi, le compte stéphane sur le service académie-française.fr sera acct:st%C3%A9phane@xn--acadmie-franaise-npb1a.fr.

La section 7 de notre RFC contient le formulaire d'enregistrement du nouveau plan (selon la procédure du RFC 4395), qui inclut la syntaxe formelle de ces URI, en ABNF. acct: est donc désormais dans le registre officiel des URI.

Si vous voulez voir des exemples réels, le mieux est de regarder le monde WebFinger, par exemple les exemples dans mon article sur le RFC 7033.

L'importance de ce plan d'URL acct: avait été décrite dans un article d'Eran Hammer de 2009 (c'est long, la normalisation).


Téléchargez le RFC 7565


L'article seul

RFC 7518: JSON Web Algorithms (JWA)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Jones (Microsoft)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 22 mai 2015


Ce nouveau RFC fait partie de la série des RFC JOSE (cryptographie pour JSON). Il normalise les algorithmes cryptographiques utilisables pour signer ou chiffrer des textes JSON et crée des registres IANA pour les conserver.

Comme le fait en général l'IETF en matière de cryptographie, les algorithmes cryptographiques ne sont pas inscrits « en dur » dans les RFC (rappelez-vous qu'un RFC, une fois publié, n'est jamais modifié) mais mis dans un registre IANA. En effet, la cryptanalyse progresse régulièrement et des algorithmes qui semblaient sûrs à un moment ne le sont plus par la suite. Il est plus facile et plus rapide de modifier un registre IANA que de créer un nouveau RFC.

Pour chaque registre, les algorithmes cités sont marqués Obligatoire, Recommandé ou Facultatif (cf. RFC 2119). En n'utilisant que des algorithmes marqués Obligatoire, on augmente l'interopérabilité.

Commençons par les algorithmes utilisés pour les signatures et MAC (section 3). C'est le membre alg de JWS (JSON Web Signature, cf. RFC 7515). La table complète est dans son registre IANA. Comme JOSE privilégie la concision, les termes utilisés sont plus courts que, par exemple, dans les registres prévus pour TLS. Ainsi, HS512 veut dire « HMAC avec SHA-512 ». (Pour l'algorithme HMAC, voir le RFC 2104.) Et ES256 désignera un algorithme de signature couplant ECDSA avec une courbe P-256 et SHA-256 (on peut aussi signer avec RSA mais les signatures sont plus courtes avec les courbes elliptiques).

Il y a même un algorithme none dans le registre, dont le nom indique clairement que le texte JSON n'est pas authentifié, ni protégé en intégrité. A priori, les applications qui veulent vérifier le JSON reçu vont rejeter des textes ainsi marqués (sections 3.6 et aussi 8.5), sauf cas très spécifiques, par exemple si on est absolument certain que le texte JSON est arrivé sur une connexion sécurisée (mais relire la section 8.5, sur les pièges que cela pose).

Maintenant, le chiffrement. Il faut pouvoir indiquer comment ont été chiffrées les clés ayant servi à chiffrer le contenu. La section 4 décrit les algorithmes prévus pour cela (qui sont aussi dans le même registre IANA), et qu'on met dans le membre alg d'un JWE (JSON Web Encryption, cf. RFC 7516).

Ainsi, un cas simple est celui où les deux parties chiffrent avec une clé statique symétrique, pré-échangée entre eux. On met alors dir (pour direct use of a key) comme algorithme. Si au contraire on chiffre la clé de chiffrement avec RSA, on mettra par exemple l'algorithme RSA1_5 qui veut dire « RSA avec PKCS#1 ». (On a droit aussi, bien sûr, aux échanges de clés Diffie-Hellman.)

Et le contenu lui-même, on le chiffre avec quoi ? La section 5 décrit les algorithmes de chiffrement symétriques utilisés (encore le même registre IANA). Ils se mettent dans le membre enc du JWE. Par exemple, A128CBC-HS256 est AES en mode CBC avec un HMAC sur SHA-256, alors que A256GCM est AES mais en mode GCM (qui, fournissant du chiffrement intègre, dispense d'utiliser HMAC).

À noter que le petit nouveau à l'IETF, le ChaCha20 du RFC 7539, n'est pas encore arrivé dans JOSE et ne figure pas dans ce registre, qui ne compte qu'AES.

Passons maintenant aux clés (section 6), représentés par un JWK (JSON Web Key, RFC 7517. Dans le membre kty (Key TYpe) d'un JWK, on peut trouver RSA, EC (Elliptic Curve) ou oct (octet), ce dernier désignant une clé symétrique. Les paramètres dépendent ensuite du type de clés. Par exemple, pour les courbes elliptiques, crv désigne la courbe utilisée (P-256, P-384, etc, les valeurs possibles ayant leur propre registre), pour RSA, n sera le modulo et e l'exposant. Les valeurs possibles pour ces paramètres de clés sont dans un registre IANA.

Je l'ai dit au début, les progrès de la cryptanalyse nécessitent de changer les algorithmes de temps en temps (section 8.1 sur l'« agilité cryptographique »). La section 7 fixe les règles de modification des registres. En gros, il faut avoir une spécification écrite (pas forcément un RFC) pour voir son algorithme entrer dans le registre (Specification Required, RFC 5226, section 4.1).


Téléchargez le RFC 7518


L'article seul

« Quand le DNS défaille », une infrastructure peu connue

Première rédaction de cet article le 21 mai 2015


Le 19 mai 2015, à l'Université de Bourgogne à Dijon, j'ai participé à l'atelier CNRS « Gestion d'incidents » avec un exposé sur le DNS.

Les supports de l'exposé :

Merci à Arnaud Da Costa pour l'organisation et à tous les participants pour une intéressante journée sur le terrain, avec des acteurs de la sécurité concrète.


L'article seul

JOSE, la cryptographie pour JSON

Première rédaction de cet article le 20 mai 2015


Le format JSON a largement remplacé XML dans les applications Web et sert aujourd'hui de base à plein d'applications. Il était donc logique qu'on cherche à la sécuriser par la cryptographie et c'est le rôle du groupe de travail JOSE (JavaScript Object Signing and Encryption) de l'IETF qui vient de publier une série de normes sur la signature et le chiffrement de textes JSON.

Un premier RFC avait déjà débroussaillé le terrain en expliquant les scénarios d'usage et le cahier des charges, c'était le RFC 7165. Les nouveaux RFC, eux, définissent les normes techniques. Ce sont :

  • RFC 7518 : JSON Web Algorithms (JWA) décrit les registres où sont stockés les identificateurs des algorithmes de cryptographie utilisables.
  • RFC 7517 : JSON Web Key (JWK) explique le format des clés.
  • RFC 7515 : JSON Web Signature (JWS) expose le mécanisme de signature cryptographique, qui permet d'authentifier des documents JSON.
  • RFC 7516 : JSON Web Encryption (JWE) normalise le chiffrement, grâce auquel les textes JSON peuvent rester confidentiels.
  • RFC 7520 : Examples of Protecting Content using JavaScript Object Signing and Encryption (JOSE) est simplement un recueil d'exemples.
  • En même temps que les RFC du groupe JOSE ont été publiés une autre série du groupe OAUTH décrivant notamment des utilisations de JOSE dans le contexte d'OAuth. C'est par exemple le cas du RFC 7519, JSON Web Token (JWT).

Si vous voulez une très bonne explication de JOSE, avec plein d'explications simples, il y a l'article de Jan Rusnacko.

Si vous voulez plutôt pratiquer, il existe de nombreuses mises en œuvre de JOSE :

Merci à Virgine Galindo pour sa relecture.


L'article seul

RFC 7517: JSON Web Key (JWK)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Jones (Microsoft)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 20 mai 2015


Le sigle JOSE (JavaScript Object Signing and Encryption) désigne l'utilisation de moyens cryptographiques pour sécuriser des textes JSON. JOSE permet notamment de signer (RFC 7515) et chiffrer (RFC 7516) des textes JSON. Pour cela, il faut des clés cryptographiques et ce RFC 7517 normalise la représentation de ces clés en JSON.

Une JWK (JSON Web Key) est donc une clé représentée par un objet JSON. Que les amateurs de X.509 se rassurent, il n'est pas prévu de remplacer ce format par JSON :-) Le but essentiel est de pouvoir manipuler des clés dans le contexte de JSON (transmettre la clé en même temps qu'une signature, chiffrer une clé privée pour la transporter de manière sûre, etc). Outre la JWK, notre RFC définit aussi le JWK set, un ensemble de JWK.

Commençons par un exemple simple, une clé sur une courbe elliptique :

     {"kty":"EC",
      "crv":"P-256",
      "x":"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
      "y":"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
      "kid":"Public key used in JWS A.3 example"
     }

Ici, le membre kty identifie la clé comme utilisant les courbes elliptiques, crv indique l'usage de la courbe NIST P-256, x et y sont les coordonnées de la clé sur cette courbe. kid est un identificateur de clé, dont le format est libre.

La section 4 décrit en détail tous les membres possibles de l'objet clé. Parmi les principaux :

  • kty vaut EC (courbes elliptiques) ou RSA (l'algorithme du même nom). D'autres valeurs sont possibles (cf. RFC 7518, et le registre IANA).
  • use (inutilisé dans l'exemple plus haut) indique l'utilisation prévue de la clé (sig pour signer, enc pour chiffrer...). Là encore, le RFC 7518 prévoit un registre des valeurs possibles.
  • alg désigne l'algorithme à utiliser avec cette clé, parmi ceux enregistrés à l'IANA.
  • kid (Key IDentification) sert à identifier la clé. Par exemple, lorsqu'on doit désigner une clé particulière au sein d'un ensemble de clés disponibles. Notez que son format n'est pas spécifié par notre RFC.
  • x5c est un certificat X.509 (RFC 5280), ou une chaîne de certificats. Les certificats sont une valeur en DER encodée en Base64.
  • x5u est un URL pointant vers un certificat X.509.

JWK peut servir pour la cryptographie asymétrique ou pour la symétrique. Voici un exemple de clé symétrique (le type oct signifie « suite d'octets », la clé elle-même est dans le membre k) :

{
   "kty":"oct",
   "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
   "kid":"HMAC key used in JWS A.1 example"
}

Si on veut manipuler plusieurs clés ensemble (section 5), on peut utiliser un objet JSON comportant un membre keys dont la valeur est un tableau de JWK. Ici, une clé sur une courbe elliptique et une clé RSA :

     {"keys":
       [
         {"kty":"EC",
          "crv":"P-256",
          "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
          "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
          "use":"enc",
          "kid":"1"},

         {"kty":"RSA",
          "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
          "e":"AQAB",
          "alg":"RS256",
          "kid":"2011-04-29"}
       ]
     }

Le format JWK permet de représenter des clés privées, que ce soit la partie privée d'une clé asymétrique, ou bien une clé symétrique. Si on échange ces clés, il est évidemment recommandé de les chiffrer, ce qui peut se faire avec JOSE (RFC 7516). Une JWK chiffrée est alors un JWE (contenu chiffré en JOSE) comme les autres.

Comme tous les RFC JOSE, cette norme fait une forte consommation de registres IANA. La section 8 leur est consacrée. La politique d'enregistrement dans ces registres est « description nécessaire » (cf. RFC 5226), ce qui veut dire qu'un texte stable décrivant la valeur enregistrée est nécessaire. Par exemple, si on veut enregistrer un nouvel algorithme cryptographique pour les clés, on doit indiquer un texte décrivant précisément cet algorithme. Les registres sont notamment :

  • Les paramètres des clés (comme use pour l'usage prévu, ou kid pour l'identificateur). Comme toujours dans le monde JSON, les membres inconnus d'un objet sont ignorés. Ainsi, un nouveau membre enregistré ici pourra être utilisé sans risque puisque les mises en œuvre de JOSE plus anciennes ignoreront ce nouveau membre.
  • Les utilisations des clés comme sig pour la signature ou bien enc pour le chiffrement.

Outre ces nouveaux registres, ce RFC ajoute au registre des types de média le type application/jwk+json qui identifie une clé encodée en JSON et application/jwk-set+json qui identifie un ensemble de clés.

La section 9 de notre RFC se penche sur la sécurité, évidemment un sujet important quand on manipule des clés. Les règles à suivre sont les règles classiques de la cryptographie. Par exemple, les clés privées doivent être gardées à l'abri des regards indiscrets, comme rappelé dans les RFC 3447 et RFC 6030.

Autre piège, risquer de croire que, parce qu'un texte est signé, il a davantage de valeur. Cela n'est vrai que si on peut s'assurer de l'origine de la clé. Autrement, cela ne signifie rien, n'importe qui ayant pu se créer une clé. Un des moyens de vérifier cette origine est de valider le certificat PKIX dans le membre x5c. Au passage, les exemples de certificats dans le RFC sont, comme le veut le format JWK de JOSE, du DER encodé en Base64. Pour les lire, on peut par exemple, mettre le contenu en Base64 (après avoir retiré les espaces et sauts de ligne qui se trouvent dans le RFC) dans un fichier, le décoder avec base64 puis le lire avec OpenSSL) :

% base64 -d < rfc.b64 > rfc.der              
% openssl x509 -text -inform der -in rfc.der
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            01:3c:ff:16:e2:e2
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, ST=CO, L=Denver, O=Ping Identity Corp., CN=Brian Campbell
        Validity
            Not Before: Feb 21 23:29:15 2013 GMT
            Not After : Aug 14 22:29:15 2018 GMT
        Subject: C=US, ST=CO, L=Denver, O=Ping Identity Corp., CN=Brian Campbell
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
...

Téléchargez le RFC 7517


L'article seul

RFC 7515: JSON Web Signature (JWS)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Jones (Microsoft), J. Bradley (Ping Identity), N. Sakimura (NRI)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 20 mai 2015


Dans la série des RFC JOSE, qui décrivent les possibilités de protéger des textes JSON avec la cryptographie, ce RFC 7515 normalise les signatures, qui permettent de garantir l'authenticité et l'intégrité des textes JSON.

Le format JSON, normalisé dans le RFC 7159, ne bénéficiait pas jusqu'alors d'un moyen standard pour permettre la vérification de son authenticité. Certes, on pouvait transport le JSON via un transport sécurisé comme HTTPS mais cela ne fournissait qu'une protection du canal, pas un contrôle d'intégrité de bout en bout.

Le principe de ce RFC est le suivant (section 3) : un texte JSON protégé par une signature, un JWS (JSON Web Signature), est composé de trois parties : l'en-tête JOSE (JavaScript Object Signing and Encryption), qui indique les paramètres cryptographiques, la charge utile JWS (le message d'origine), et la signature JWS. L'en-tête JOSE se sépare en un en-tête protégé (par la signature) et un en-tête non protégé. Le document rassemblant ces trois parties est ensuite sérialisé en une suite d'octets. Il y a deux sérialisations possibles. La sérialisation compacte est simplement la concaténation de l'encodage en Base64 de l'en-tête protégé, d'un point, de l'encodage en Base64 de la charge utile, un autre point et enfin l'encodage en Base64 de la signature. Un JWS ainsi sérialisé peut être utilisé dans un URL. Voici un exemple :

eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

Pas très lisible, évidemment. La deuxième sérialisation possible est dite sérialisation JSON car son résultat est un texte JSON. C'est un objet JSON comportant quatre membres (pas forcément obligatoires), payload, la charge utile, protected, l'en-tête JOSE protégé, header, l'en-tête JOSE non protégé, et signature, la signature. Les trois derniers peuvent se retrouver regroupés dans un sous-objet nommé signatures. En voici un exemple :

{
      "payload":
       "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
      "signatures":[
       {"protected":"eyJhbGciOiJSUzI1NiJ9",
        "header":
         {"kid":"2010-12-29"},
        "signature":
         "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"},
       {"protected":"eyJhbGciOiJFUzI1NiJ9",
        "header":
         {"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
        "signature":
         "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"}]
}

Si vous n'avez pas de décodeur Base64 sous la main, notez que la charge utile (le texte JSON qu'on veut protéger) était :

{"iss":"joe",
 "exp":1300819380,
 "http://example.com/is_root":true}

Après cette vision générale, les détails. D'abord, l'en-tête JOSE (section 4). On a vu qu'il indiquait les paramètres algorithmiques de la signature. Les plus importants de ces paramètres :

  • alg indique l'algorithme cryptographique utilisé. Les valeurs possibles dans le registre IANA défini par le RFC 7518. Par exemple {"alg":"ES256"} identifiera l'algorithme ECDSA avec la courbe P-256 et la condensation en SHA-256.
  • jwk est la clé de signature, formatée selon le RFC 7517.
  • jku est un URL au bout duquel on trouvera un ensemble de clés, formatées également selon le RFC 7517. La clé de signature fait partie de cet ensemble. Évidemment, il faut utiliser un transport sécurisé (comme HTTPS, avec validation de l'identité du serveur, cf. RFC 6125) pour récupérer ces clés (section 8, sur les exigences TLS).
  • kid, que vous avez vu dans l'exemple plus haut, est un identificateur de la clé de signature (cf. section 6).
  • x5c est un certificat X.509 (RFC 5280) correspondant à la clé de signature.
  • x5u est un URL pointant vers un certificat X.509 correspondant à la clé de signature.

Les étapes pour créer un JWS sont décrites en section 5 :

  • Encoder la charge utile en Base64 (RFC 4648). Notez qu'il n'existe pas de mécanisme de canonicalisation standard d'un texte JSON et qu'on n'applique donc pas une telle canonicalisation.
  • Fabriquer l'en-tête JOSE avec les paramètres cryptographiques qu'on va utiliser, puis l'encoder en Base64.
  • Signer (les détails dépendent évidemment de l'algorithme de signature utilisé), et encoder la signature en Base64.
  • Sérialiser (en JSON ou en compact).

Pour valider une signature, on fait l'inverse. Si une étape échoue, la signature est rejetée.

  • Analyser la forme sérialisée pour en extraire les différents composants (en-tête, charge utile, signature).
  • Décoder (depuis le Base64) l'en-tête protégé et vérifier qu'on obtient bien du JSON correct.
  • Vérifier qu'on comprend tous les paramètres, par exemple l'algorithme de signature utilisé.
  • Décoder (depuis le Base64) la signature et la charge utile.
  • Valider la (ou les) signature(s).

S'il y a plusieurs signatures, ce que permet JWS, doivent-elles être toutes valides ou bien une seule suffit-elle ? Ce n'est pas défini par la norme JOSE : chaque application utilisant JOSE peut décider comme elle veut. Dans tous les cas, pour que le document soit considéré comme correctement signé, il faut qu'au moins une signature soit valide. Une autre décision est du ressort de l'application : quels algorithmes de signature sont acceptables. Par exemple, une application peut décider de rejeter une signature car l'algorithme, trop faible cryptographiquement parlant, n'est pas accepté.

Notez que pas mal d'étapes de JOSE nécessitent de comparer des chaînes de caractères. Cela soulève immédiatement les problèmes de canonicalisation. Les règles JSON de comparaison pour les noms des membres d'un objet sont dans la section 8.3 du RFC 7159. Pour les valeurs, c'est plus compliqué et cela dépend de l'application. Ainsi, si une application a décidé que le membre kid (identificateur de la clé) contient un nom de domaine, elle peut faire des comparaisons insensibles à la casse.

La section 7 de notre RFC couvre les sérialisations. Comme on l'a vu plus haut, il y a deux sérialisations, la compacte et celle en JSON. Chaque application de JOSE va décider quelles sérialisations sont acceptables, la compacte, la JSON ou les deux. La sérialisation en JSON a une forme générale, où les signatures sont un tableau (éventuellement de taille 1) et une légère variante, la sérialisation en JSON aplati, où une seule signature est possible. Voici les deux cas, d'abord la forme générale, avec deux signatures :

{
      "payload":"...",
      "signatures":[
       {"protected":"...",
        "signature":"..."},
       ...
       {"protected":"...",
        "signature":"..."}]
     }

Puis la forme aplatie :

{
      "payload":"...",
      "protected":"...",
      "signature":"..."
     }

La sérialisation compacte, lorsqu'elle est envoyée via l'Internet, est étiquetée avec le type MIME application/jose. La sérialisation en JSON est application/jose+json. Ces deux types sont utilisables pour les JWS de ce RFC ou pour les JWE du RFC 7516.

La section 10 de notre RFC revient sur les exigences de sécurité, qui accompagnent tout protocole cryptographique. La plupart ne sont pas spécifiques à JOSE. Par exemple, si on laisse trainer sa clé privée n'importe où, des tas de gens pourront faire des fausses signatures. Autre cas bien connu, le générateur aléatoire utilisé pour générer les clés (et autres valeurs qui doivent être imprévisibles) doit être fiable (des tas de failles de sécurité ont été créées par des générateurs insuffisants). Mais certains problèmes sont un peu plus subtils. Par exemple, supposons qu'on valide la signature et que, cryptographiquement, tout soit au point. Mais qu'est-ce que ça nous prouve ? Ça nous prouve que le document a bien été signé par le titulaire de la clé privée utilisée. Mais, en général, on veut plus que cela. On veut que le document soit bien signé par Mme A ou par la société B. Il y a donc une étape entre la clé et l'entité à qui on fait confiance (Key Origin Authentication) qui n'est pas triviale.

Autre point qui n'est pas forcément maitrisé de tous, la différence entre signature et MAC. La section 10.5 l'explique bien : la clé utilisée pour MAC est entre les mains de plusieurs entités et l'authentification garantie par MAC est donc plus faible.

Il peut y avoir aussi des failles de sécurité dans JSON et pas dans JOSE, notamment en raison du flou de cette norme, et du laxisme de certaines mises en œuvre qui acceptent du JSON mal formé. Ainsi, le RFC 7159 n'impose pas que les membres d'un objet soient uniques. Un objet JSON :

{
  "voter": "Smith",
  "vote": "YES",
  "vote": "NO"
}

est légal (quoique très déconseillé). Si on sait qu'un utilisateur de cet objet a un analyseur qui ne garde que le dernier membre dupliqué, et qu'un autre a un analyseur qui ne garde que le premier membre dupliqué, on peut signer cet objet et faire croire au premier utilisateur que Smith a voté non, et au second que le même Smith a voté oui. Pour éviter cela, la norme JOSE durcit le RFC 7159 en interdisant les membres dupliqués (une meilleure solution aurait été d'imposer l'utilisation du sous-ensemble JSON du RFC 7493, je trouve, mais l'IETF a choisi une autre voie). Une conséquence de ce durcissement est qu'on ne peut pas signer tous les objets JSON. Les cas pathologiques sont exclus. (Ce point a été l'un des plus « chauds » dans la mise au point de JOSE à l'IETF.)

Plein d'examples de signatures se trouvent dans l'annexe A de notre RFC (mais qu'on avait aussi dans le RFC 7520).


Téléchargez le RFC 7515


L'article seul

RFC 7520: Examples of Protecting Content using JavaScript Object Signing and Encryption (JOSE)

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Miller (Cisco Systems)
Pour information
Réalisé dans le cadre du groupe de travail IETF jose
Première rédaction de cet article le 20 mai 2015


Ce RFC fait partie de l'l'ensemble des normes sur le système JOSE (JavaScript Object Signing and Encryption, opérations cryptographiques sur les textes JSON). Il présente des exemples d'utilisation de JOSE, permettant aux développeurs de voir s'ils ont bien compris les normes présentées dans les RFC 7515 et RFC 7516.

Composé essentiellement de textes JSON et de binaire, ce RFC est long : 117 pages. Je n'en décris ici qu'une toute petite partie. Il vaux mieux lire avant les autres RFC sur JOSE pour comprendre les exemples. JOSE est très riche et il existe plein d'options. Il n'est donc pas possible, malgré l'épaisseur de ce RFC, de couvrir tous les cas. Le but est d'avoir au moins un échantillon représentatif des cas les plus courants. JOSE fonctionne en deux temps : calcul des résultats cryptographiques puis sérialisation, qui est la représentation sous forme texte, de ces résultats. JOSE a trois sérialisations possibles : compacte (le résultat est une série de caractères, pas un texte JSON), générale (le résultat est lui-même du JSON) et aplatie (également du JSON). Si vous voulez vérifier les exemples vous-même, ils sont tous disponibles sur GitHub.

Normalement, le contenu du RFC suffit à reproduire l'exemple exactement : en le donnant à une mise en œuvre de JOSE, on doit trouver le même résultat. La principale exception concerne le cas des algorithmes qui utilisent en entrée des données aléatoires (comme DSA). Dans ce cas, il n'est pas possible de retrouver exactement les mêmes valeurs. En outre, pour la présentation dans le RFC, des espaces ont parfois été ajoutés, là où il n'affectait pas la sémantique des opérations cryptographiques.

Commençons par les premiers exemples (section 3), la représentation de clés en JOSE (RFC 7517). D'abord, une clé publique, sur une courbe elliptique, la P-521 :

{
     "kty": "EC",
     "kid": "bilbo.baggins@hobbiton.example",
     "use": "sig",
     "crv": "P-521",
     "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
     "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
   }

Ici, x et y sont des paramètres spécifiques des courbes elliptiques, encodés en Base64 (JSON n'a pas de moyen plus pratique de stocker du binaire). Si c'était une clé privée, on aurait également un paramètre d. kid est l'identificateur de la clé. Plus banale que les courbes elliptiques, une clé publique RSA :

   {
     "kty": "RSA",
     "kid": "bilbo.baggins@hobbiton.example",
     "use": "sig",
     "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw",
     "e": "AQAB"
   }

Ici, n et e sont des paramètres spécifiques de RSA (le module et l'exposant). Une clé privée RSA nécessiterait davantage d'informations :

   {
     "kty": "RSA",
     "kid": "bilbo.baggins@hobbiton.example",
     "use": "sig",
     "n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqVwGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuCLqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5gHdrNP5zw",
     "e": "AQAB",
     "d": "bWUC9B-EFRIo8kpGfh0ZuyGPvMNKvYWNtB_ikiH9k20eT-O1q_I78eiZkpXxXQ0UTEs2LsNRS-8uJbvQ-A1irkwMSMkK1J3XTGgdrhCku9gRldY7sNA_AKZGh-Q661_42rINLRCe8W-nZ34ui_qOfkLnK9QWDDqpaIsA-bMwWWSDFu2MUBYwkHTMEzLYGqOe04noqeq1hExBTHBOBdkMXiuFhUq1BU6l-DqEiWxqg82sXt2h-LMnT3046AOYJoRioz75tSUQfGCshWTBnP5uDjd18kKhyv07lhfSJdrPdM5Plyl21hsFf4L_mHCuoFau7gdsPfHPxxjVOcOpBrQzwQ",
     "p": "3Slxg_DwTXJcb6095RoXygQCAZ5RnAvZlno1yhHtnUex_fp7AZ_9nRaO7HX_-SFfGQeutao2TDjDAWU4Vupk8rw9JR0AzZ0N2fvuIAmr_WCsmGpeNqQnev1T7IyEsnh8UMt-n5CafhkikzhEsrmndH6LxOrvRJlsPp6Zv8bUq0k",
     "q": "uKE2dh-cTf6ERF4k4e_jy78GfPYUIaUyoSSJuBzp3Cubk3OCqs6grT8bR_cu0Dm1MZwWmtdqDyI95HrUeq3MP15vMMON8lHTeZu2lmKvwqW7anV5UzhM1iZ7z4yMkuUwFWoBvyY898EXvRD-hdqRxHlSqAZ192zB3pVFJ0s7pFc",
     "dp": "B8PVvXkvJrj2L-GYQ7v3y9r6Kw5g9SahXBwsWUzp19TVlgI-YV85q1NIb1rxQtD-IsXXR3-TanevuRPRt5OBOdiMGQp8pbt26gljYfKU_E9xn-RULHz0-ed9E9gXLKD4VGngpz-PfQ_q29pk5xWHoJp009Qf1HvChixRX59ehik",
     "dq": "CLDmDGduhylc9o7r84rEUVn7pzQ6PF83Y-iBZx5NT-TpnOZKF1pErAMVeKzFEl41DlHHqqBLSM0W1sOFbwTxYWZDm6sI6og5iTbwQGIC3gnJKbi_7k_vJgGHwHxgPaX2PnvP-zyEkDERuf-ry4c_Z11Cq9AqC2yeL6kdKT1cYF8",
     "qi": "3PiqvXQN0zwMeE-sBvZgi289XP9XCQF3VWqPzMKnIgQp7_Tugo6-NZBKCQsMf3HaEGBjTVJs_jcK8-TRXvaKe-7ZMaQj8VfBdYkssbu0NKDDhjJ-GtiseaDVWt7dcH0cfwxgFUHpQh7FoCrjFJ6h6ZEpMF6xmujs4qMpPz8aaI4"
   }

À noter que la seule indication qu'il s'agisse d'une clé privée est la présence des membres supplémentaires p, q, dp, dq et qi.

Passons maintenant à la cryptographie symétrique. Cette fois, il n'y a qu'une seule clé, stockée dans le membre k :

{
     "kty": "oct",
     "kid": "018c0ae5-4d9b-471b-bfd6-eef314bc7037",
     "use": "sig",
     "alg": "HS256",
     "k": "hJtXIZ2uSN5kbQfbtTNWbpdmhkV8FJG-Onbc6mxCcYg"
   }

Elle sera utilisée pour les signatures : on concatène la valeur de la clé au contenu et on SHA-256 le tout (non, en fait, c'est plus compliqué, voir RFC 2104). Le vérificateur fait la même opération et doit trouver le même condensat SHA-256.

Voici pour les clés. Passons aux signatures, en section 4. Un texte JSON signé est un JWS (JSON Web Signature). Le texte signé de tous les exemples est un extrait du Seigneur des anneaux, « It’s a dangerous business, Frodo, going out your door. You step onto the road, and if you don't keep your feet, there’s no knowing where you might be swept off to. ». Attention si vous recalculez les signatures vous-même, le caractère qui ressemble à une apostrophe est en fait le caractère Unicode U+2019, « RIGHT SINGLE QUOTATION MARK » (et, dans le RFC, il y a en plus remplacement de certains espaces par des sauts de ligne). Si vous voulez être sûr, l'encodage en Base64 (RFC 4648) de cette charge utile est SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4=.

Voici d'abord une bête signature RSA. L'en-tête protégé (cf. RFC 7515, sections 2 et 4) est :

{
     "alg": "RS256",
     "kid": "bilbo.baggins@hobbiton.example"
}

On signe la concaténation du Base64 de cet en-tête et du Base64 de la charge utile. Cela donne MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg. Il reste à sérialiser le résultat, c'est-à-dire à la présenter sous une forme concrète. Le RFC 7515 prévoit plusieurs sérialisations possibles. La compacte, utilisable dans les URL, serait eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4.MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg (vous reconnaissez la charge utile, la phrase de Tolkien, et la signature, séparées par des points). Avec la sérialisation aplatie, qui donne un texte JSON, ce serait :

{
     "payload": "SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4",
     "protected": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9",
     "signature": "MRjdkly7_-oTPTS3AXP41iQIGKa80A0ZmTuV5MEaHoxnW2e5CZ5NlKtainoFmKZopdHM1O2U4mwzJdQx996ivp83xuglII7PNDi84wnB-BDkoBwA78185hX-Es4JIwmDLJK3lfWRa-XtL0RnltuYv746iYTh_qHRD68BNt1uSNCrUCTJDt5aAE6x8wW1Kt9eRo4QPocSadnHXFxnt8Is9UzpERV0ePPQdLuW3IS_de3xyIrDaLGdjluPxUAhb6L2aXic1U12podGU0KLUQSE_oI-ZnmKJ3F4uOZDnd6QZWJushZ41Axf_fcIe8u9ipH84ogoree7vjbU5y18kDquDg"
   }

C'est un peu compliqué avec une signature ECDSA. En effet, cet algorithme exige des données imprévisibles (le RFC dit « aléatoires » mais il exagère, cf. RFC 6979) et donc chaque signature donnera un résultat différent. Ne vous étonnez donc pas si vous recalculez et que vous trouvez une valeur différente de celle du RFC. Ici, on réutilise la clé présentée plus haut (sur la courbe P-521), et, en sérialisation générale (qui est très proche de la sérialisation aplatie, elle donne aussi un texte JSON, mais elle a un tableau de signatures et pas une signature unique, voir la section 4.8 pour des exemples) :

{
     "payload": "SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4",
     "signatures": [
       {
          "protected": "eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhbXBsZSJ9",
          "signature": "AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9Plon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890jl8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2"
       }
     ]
   }

On peut aussi avoir des signatures « détachées », où le texte signé n'apparait pas. Le vérificateur devra récupérer le texte JSON signé, et récupérer la signature détachée, avant de vérifier. Ici, on utilise la clé symétrique montrée plus haut. L'en-tête sera donc :

{
     "alg": "HS256",
     "kid": "018c0ae5-4d9b-471b-bfd6-eef314bc7037"
   }

Et le résultat, en sérialisation aplatie :

{
     "protected": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9",
     "signature": "s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0"
}

Passons maintenant au chiffrement (section 5). Le texte utilisé pour les exemples change. Il est également tiré de « La communauté de l'anneau » et est « You can trust us to stick with you through thick and thin–to the bitter end. And you can trust us to keep any secret of yours–closer than you keep it yourself. But you cannot trust us to let you face trouble alone, and go off without a word. We are your friends, Frodo. » Le tiret est un U+2013, « EN DASH ».

Premier exemple, avec RSA pour le chiffrement asymétrique de la clé (de la CEK, Content Encryption Key), AES (en mode CBC) pour le chiffrement symétrique, et SHA-256 lorsqu'il faut condenser. Voici la clé publique :

 {
     "kty": "RSA",
     "kid": "frodo.baggins@hobbiton.example",
     "use": "enc",
     "n": "maxhbsmBtdQ3CNrKvprUE6n9lYcregDMLYNeTAWcLj8NnPU9XIYegTHVHQjxKDSHP2l-F5jS7sppG1wgdAqZyhnWvXhYNvcM7RfgKxqNx_xAHx6f3yy7s-M9PSNCwPC2lh6UAkR4I00EhV9lrypM9Pi4lBUop9t5fS9W5UNwaAllhrd-osQGPjIeI1deHTwx-ZTHu3C60Pu_LJIl6hKn9wbwaUmA4cR5Bd2pgbaY7ASgsjCUbtYJaNIHSoHXprUdJZKUMAzV0WOKPfA6OPI4oypBadjvMZ4ZAj3BnXaSYsEZhaueTXvZB4eZOAjIyh2e_VOIKVMsnDrJYAVotGlvMQ",
     "e": "AQAB"
}

L'en-tête protégé est :

{
     "alg": "RSA1_5",
     "kid": "frodo.baggins@hobbiton.example",
     "enc": "A128CBC-HS256"
}

Et on se retrouve avec, en sérialisation générale :

{
     "recipients": [
       {
         "encrypted_key": "laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw"
       }
     ],
     "protected": "eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
     "iv": "bbd5sTkYwhAIqfHsx8DayA",
     "ciphertext": "0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m",
     "tag": "kvKuFBXHe5mQr4lqgobAUg"
}

Le contenu chiffré, et donc désormais confidentiel, est dans le membre ciphertext. Attention si vous essayez de reproduire cet exemple, le résultat exact dépend du vecteur d'initialisation iv. En sérialisation compacte, on aurait :

eyJhbGciOiJSU0ExXzUiLCJraWQiOiJmcm9kby5iYWdnaW5zQGhvYmJpdG9uLmV4YW1wbGUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.laLxI0j-nLH-_BgLOXMozKxmy9gffy2gTdvqzfTihJBuuzxg0V7yk1WClnQePFvG2K-pvSlWc9BRIazDrn50RcRai__3TDON395H3c62tIouJJ4XaRvYHFjZTZ2GXfz8YAImcc91Tfk0WXC2F5Xbb71ClQ1DDH151tlpH77f2ff7xiSxh9oSewYrcGTSLUeeCt36r1Kt3OSj7EyBQXoZlN7IxbyhMAfgIe7Mv1rOTOI5I8NQqeXXW8VlzNmoxaGMny3YnGir5Wf6Qt2nBq4qDaPdnaAuuGUGEecelIO1wx1BpyIfgvfjOhMBs9M8XL223Fg47xlGsMXdfuY-4jaqVw.bbd5sTkYwhAIqfHsx8DayA.0fys_TY_na7f8dwSfXLiYdHaA2DxUjD67ieF7fcVbIR62JhJvGZ4_FNVSiGc_raa0HnLQ6s1P2sv3Xzl1p1l_o5wR_RsSzrS8Z-wnI3Jvo0mkpEEnlDmZvDu_k8OWzJv7eZVEqiWKdyVzFhPpiyQU28GLOpRc2VbVbK4dQKPdNTjPPEmRqcaGeTWZVyeSUvf5k59yJZxRuSvWFf6KrNtmRdZ8R4mDOjHSrM_s8uwIFcqt4r5GX8TKaI0zT5CbL5Qlw3sRc7u_hg0yKVOiRytEAEs3vZkcfLkP6nbXdC_PkMdNS-ohP78T2O6_7uInMGhFeX4ctHG7VelHGiT93JfWDEQi5_V9UN1rhXNrYu-0fVMkZAKX3VWi7lzA6BP430m.kvKuFBXHe5mQr4lqgobAUg

On peut aussi chiffrer et signer (section 6).

Attention, les exemples dans ce RFC sont juste... des exemples. Ils visent à permettre aux développeurs de comprendre la norme, et de tester leurs programmes (section 7). L'accent est donc mis, autant que possible, sur la reproductibilité et pas sur la sécurité. Ainsi, en violation des bonnes pratiques, tous les exemples utilisent la même clé symétrique de chiffrement (CEK, Content Encryption Key) et le même vecteur d'initialisation. Cette clé et ce vecteur doivent normalement changer à chaque opération de signature ou de chiffrement.

N'oubliez pas, si vous voulez reproduire les exemples de ce RFC, tous les résultats, sous un format lisible par vos programmes, sont dans un dépôt Github.


Téléchargez le RFC 7520


L'article seul

RFC 7540: Hypertext Transfer Protocol version 2

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : M. Belshe (Twist), R. Peon (Google), M. Thomson (Mozilla)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 16 mai 2015


Le protocole HTTP, à la base des échanges sur le Web, a connu plusieurs versions successives, la première était 0.9, la suivante 1.0 et la plus courante aujourd'hui est la 1.1. L'évolution entre ces versions était progressive. Mais HTTP 2, dont la norme vient de sortir, marque un saut plus important : s'il garde la sémantique de HTTP (ses en-têtes, ses codes de retour, etc), il a désormais un encodage binaire et un transport spécifique (binaire, multiplexé, avec possibilité de push). Fini de déboguer des serveurs HTTP avec telnet. En échange, le nouveau protocole promet d'être plus rapide, notamment en diminuant la latence lors des échanges.

C'est un groupe de travail IETF, nommé httpbis, qui a mis au point cette nouvelle version (voir son site Web). Ce groupe httpbis travaillait sur deux projets parallèles : d'abord réorganiser les normes sur HTTP 1.1 pour corriger les innombrables bogues, et mieux organiser la norme, sans changer le protocole (projet conclus en juin 2014). Et un deuxième projet, HTTP version 2, connu aussi sous le nom de code de SPDY (initialement lancé par Google). Si SPDY a changé de nom, on peut toutefois prévoir que cet acronyme apparaitra pendant encore un certain temps, dans les API, codes source, messages d'erreur...

La section 1 de notre nouveau RFC résume les griefs qu'il y avait contre HTTP 1.1, normalisé dans le RFC 7230 :

  • Une seule requête au plus en attente sur une connexion TCP donnée. Cela veut dire que, si on a deux requêtes à envoyer au même serveur, et que l'une est lente et l'autre rapide, il faudra faire deux connexions TCP (la solution la plus courante), ou bien se résigner au risque que la lente bloque la rapide. (La section 6.3.2 du RFC 7230 permettait d'envoyer la seconde requête tout de suite mais les réponses devaient être dans l'ordre des requêtes, donc pas moyen pour une requête rapide de doubler une lente.)
  • Un encodage des en-têtes inefficace, trop bavard et trop redondant.

Au contraire, HTTP 2 n'utilisera toujours qu'une seule connexion TCP, de longue durée (ce qui sera plus sympa pour le réseau). L'encodage étant entièrement binaire, le traitement par le récepteur sera plus rapide.

La section 2 de notre RFC résume l'essentiel de ce qu'il faut savoir sur HTTP 2. Il garde la sémantique de HTTP 1 (donc, par exemple, un GET de /cetteressourcenexistepas qui faisait un 404 avant le fera toujours après) mais avec une représentation sur le réseau très différente. On peut résumer en disant que HTTP 2 ne change que le transport des messages, pas les messages ou leurs réponses.

Avec HTTP 2, l'unité de base de la communication est la trame (frame, et, dans HTTP 2, vous pouvez oublier la définition traditionnelle qui en fait l'équivalent du paquet, mais pour la couche 2). Chaque trame a un type et, par exemple, les échanges HTTP traditionnels se feront avec simplement une trame HEADERS en requête et une DATA en réponse. Certains types sont spécifiques aux nouvelles fonctions de HTTP 2, comme SETTINGS ou PUSH_PROMISE.

Les trames voyagent ensuite dans des ruisseaux (streams), chaque ruisseau hébergeant un et un seul échange requête/réponse. On crée donc un ruisseau à chaque fois qu'un a un nouveau GET ou POST à faire. Les petits ruisseaux sont ensuite multiplexés dans une grande rivière, l'unique connexion TCP entre un client HTTP et un serveur. Les ruisseaux ont des mécanismes de contrôle du trafic et de prioritisation entre eux.

Les en-têtes sont comprimés, en favorisant le cas le plus courant, de manière à s'assurer, par exemple, que la plupart des requêtes HTTP tiennent dans un seul paquet de la taille des paquets Ethernet.

Bon, maintenant, les détails pratiques (le RFC fait 92 pages). D'abord, l'établissement de la connexion. HTTP 2 tourne au dessus de TCP. Comment on fait pour commencer du HTTP 2 ? On utilise un nouveau port, succédant au 80 de HTTP ? (Non. Les ports sont les mêmes, 80 et 443.) On regarde dans le DNS ou ailleurs si le serveur sait faire du HTTP 2 ? (Non plus.) Il y a deux méthodes utilisées par les clients HTTP 2. Tout dépend de si on fait du TLS ou pas. Si on fait du TLS, on va utiliser ALPN (RFC 7301), en indiquant l'identificateur h2 (HTTP 2 sur TLS). Le serveur, recevant l'extension ALPN avec h2, saura ainsi qu'on fait du HTTP 2 et on pourra tout de suite commencer l'échange de trames HTTP 2. (h2 est désormais dans le registre IANA.) Si on ne fait pas de TLS (identificateur h2c pour « HTTP 2 in clear » mais il est juste réservé pour information puisqu'on ne peut pas utiliser ALPN si on n'utilise pas TLS), on va passer par l'en-tête HTTP Upgrade: (section 6.7 du RFC 7230) :

GET / HTTP/1.1
Host: www.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: [base64url encoding of HTTP/2 SETTINGS payload]

Si le serveur est un vieux serveur qui ne gère pas HTTP 2, il ignorera le Upgrade: :

HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html

Si le serveur est d'accord pour faire de l'HTTP 2, il répondra 101 (Switching Protocols) :

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c

[Tout ce qui suit est en HTTP 2]

Dans ce dernier cas, la première trame envoyée par le serveur sera de type SETTINGS. Rappelez-vous que chaque couple requête/réponse HTTP aura lieu dans un ruisseau séparé. Ici, le ruisseau numéro 1 aura été créé implicitement, et servira à la requête Upgrade:.

Une fois qu'un client aura réussi à établir une connexion avec un serveur en HTTP 2, il sait que le serveur gère ce protocole. Il peut s'en souvenir, pour les futures connexions (mais attention, ce n'est pas une indication parfaite : un serveur peut abandonner HTTP 2, par exemple).

Maintenant, c'est parti, on s'envoie des trames. À quoi ressemblent-elles (section 4) ? Elles commencent par un en-tête indiquant leur longueur, leur type (comme SETTINGS, HEADERS, DATA... cf. section 6), des options (comme ACK qui sert aux trames de type PING à distinguer requête et réponse) et l'identificateur du ruisseau auquel la trame appartient (un nombre sur 31 bits). Le format complet est en section 4.1.

Les en-têtes HTTP sont comprimés selon la méthode normalisée dans le RFC 7541.

Les ruisseaux (streams), maintenant. Ce sont donc des suites ordonnées de trames, bi-directionnelles, à l'intérieur d'une connexion HTTP 2. Une connexion peut comporter plusieurs ruisseaux, chacun identifié par un stream ID (un entier de quatre octets, pair si le ruisseau a été créé par le serveur et impair autrement). Les ruisseaux sont ouverts et fermés dynamiquement et leur durée de vie n'est donc pas celle de la connexion HTTP 2. Contrairement à TCP, il n'y a pas de « triple poignée de mains » : l'ouverture d'un ruisseau est unilatérale et peut donc se faire très vite (rappelez-vous que chaque échange HTTP requête/réponse nécessite un ruisseau qui lui est propre ; pour vraiment diminuer la latence, il faut que leur création soit rapide).

Un mécanisme de contrôle du flot s'assure que les ruisseaux se partagent pacifiquement la connexion. C'est donc une sorte de TCP dans le TCP, réinventé pour les besoins de HTTP 2 (section 5.2 et relire aussi le RFC 1323). Le récepteur indique (dans une trame WINDOWS_UPDATE) combien d'octets il est prêt à recevoir (64 Kio par défaut) et l'émetteur s'arrête dès qu'il a rempli cette fenêtre d'envoi. (Plus exactement, s'arrête d'envoyer des trames DATA : les autres, les trames de contrôle, ne sont pas soumises au contrôle du flot).

Comme si ce système des connexions dans les connexions n'était pas assez compliqué comme cela, il y a aussi des dépendances entre ruisseaux. Un ruisseau peut indiquer qu'il dépend d'un autre et, dans ce cas, les ressources seront allouées d'abord au ruisseau dont on dépend. Par exemple, le code JavaScript ne peut en général commencer à s'exécuter que quand toute la page est chargée, et on peut donc le demander dans un ruisseau dépendant de celle qui sert à charger la page. On peut dépendre d'un ruisseau dépendant, formant ainsi un arbre de dépendances.

Il peut bien sûr y avoir des erreurs dans la communication. Certaines affectent toute la connexion, qui devra être abandonnée, mais d'autres ne concernent qu'un seul ruisseau. Dans le premier cas, celui qui détecte l'erreur envoie une trame GOAWAY (dont on ne peut pas garantir qu'elle sera reçue, puisqu'il y a une erreur) puis coupe la connexion TCP. Dans le second cas, si le problème ne concerne qu'un seul ruisseau, on envoie la trame RST_STREAM qui arrête le traitement du ruisseau.

Notre section 5 se termine avec des règles qui indiquent comment gérer des choses inconnues dans le dialogue. Ces règles permettent d'étendre HTTP 2, en s'assurant que les vieilles mises en œuvre ne pousseront pas des hurlements devant les nouveaux éléments qui circulent. Par exemple, les trames d'un type inconnu doivent être ignorées et mises à la poubelle directement, sans protestation.

On a déjà parlé plusieurs fois des trames, la section 6 du RFC détaille leur définition. Ce sont aux ruisseaux ce que les paquets sont à IP et les segments à TCP. Les trames ont un type (un entier d'un octet). Les types possibles sont enregistrés à l'IANA. Les principaux types actuels sont :

  • DATA (type 0), les trames les plus nombreuses, celles qui portent les données, comme les pages HTML,
  • HEADERS (type 1), qui portent les en-têtes HTTP, dûment comprimés selon le RFC 7541,
  • PRIORITY (type 2) indique la priorité que l'émetteur donne au ruisseau qui porte cette trame,
  • RST_STREAM (type 3), dont j'ai parlé plus haut à propos des erreurs, permet de terminer un ruisseau (filant la métaphore, on pourrait dire que cela assèche le ruisseau ?),
  • SETTINGS (type 4), permet d'envoyer des paramètres, comme SETTINGS_HEADER_TABLE_SIZE, la taille de la table utilisée pour la compression des en-têtes, SETTINGS_MAX_CONCURRENT_STREAMS pour indiquer combien de ruisseaux est-on prêt à gérer, etc (la liste des paramètres est dans un registre IANA),
  • PUSH_PROMISE (type 5) qui indique qu'on va transmettre des données non sollicitées (push), du moins si le paramètre SETTINGS_ENABLE_PUSH est à 1,
  • PING (type 6) qui permet de tester le ruisseau (le partenaire va répondre avec une autre trame PING, ayant l'option ACK à 1),
  • GOAWAY (type 7) que nous avons déjà vu plus haut, sert à mettre fin proprement (le pair est informé de ce qui va se passer) à une connexion,
  • WINDOW_UPDATE (type 8) sert à faire varier la taille de la fenêtre (le nombre d'octets qu'on peut encore accepter, cf. section 6.9.1),
  • CONTINUATION (type 9), indique la suite d'une trame précédente. Cela n'a de sens que pour certains types comme HEADERS (ils peuvent ne pas tenir dans une seule trame) ou CONTINUATION lui-même. Mais une trame CONTINUATION ne peut pas être précédée de DATA ou de PING, par exemple.

Dans le cas vu plus haut d'erreur entrainant la fin d'un ruisseau ou d'une connexion entière, il est nécessaire d'indiquer à son partenaire en quoi consistait l'erreur en question. C'est le rôle des codes d'erreur de la section 7. Stockés sur quatre octets (et enregistrés dans un registre IANA), ils sont transportés par les trames RST_STREAM ou GOAWAY qui terminent, respectivement, ruisseaux et connexions. Parmi ces codes :

  • NO_ERROR (code 0), pour les cas de terminaison normale,
  • PROTOCOL_ERROR (code 1) pour ceux où le pair a violé une des règles de HTTP 2, par exemple en envoyant une trame CONTINUATION qui n'était pas précédée de HEADERS, PUSH_PROMISE ou CONTINUATION,
  • INTERNAL_ERROR (code 2), un malheur est arrivé,
  • ENHANCE_YOUR_CALM (code 11), qui ravira les amateurs de spam et de Viagra, demande au partenaire en face de se calmer un peu, et d'envoyer moins de requêtes.

Toute cette histoire de ruisseaux, de trames, d'en-têtes comprimés et autres choses qui n'existaient pas en HTTP 1 est bien jolie mais HTTP 2 n'a pas été conçu comme un remplacement de TCP, mais comme un moyen de faire passer des dialogues HTTP. Comment met-on les traditionnelles requêtes/réponses HTTP sur une connexion HTTP 2 ? La section 8 répond à cette question. D'abord, il faut se rappeler que HTTP 2 reste du HTTP. L'essentiel des RFC « sémantiques » HTTP, à savoir les RFC 7231, RFC 7232 et les suivants s'applique toujours. Le RFC 7230 reste partiellement applicable : la sémantique est la même mais son expression change. Certains en-têtes disparaissent comme Connection: qui n'est plus utile en HTTP 2.

HTTP reste requête/réponse. Pour envoyer une requête, on utilise un nouveau ruisseau (envoi d'une trame avec un numéro de ruisseau non utilisé), sur laquelle on lira la réponse (les ruisseaux ne sont pas persistents). Dans le cas le plus fréquent, la requête sera composée d'une trame HEADERS contenant les en-têtes (comme User-Agent: ou Host:, cf. RFC 7230, section 3.2) et les « pseudo-en-têtes » comme la méthode (GET, POST, etc), avec parfois des trames DATA (cas d'un POST). La réponse comprendra une trame HEADERS avec les en-têtes (comme Content-Length:) et les pseudo-en-têtes comme le code de retour HTTP (200, 403, 500, etc) suivie de plusieurs trames DATA contenant les données (HTML, CSS, images, etc). Des variantes sont possibles (par exemple, les trames HEADERS peuvent être suivies de trames CONTINUATION). Les en-têtes ne sont pas transportés sous forme texte (ce qui était le cas en HTTP 1, où on pouvait utiliser telnet comme client HTTP) mais encodés selon le RFC 7541. À noter que cet encodage implique une mise du nom de l'en-tête en minuscules.

J'ai parlé plus haut des pseudo-en-têtes : c'est le mécanisme HTTP 2 pour traiter des informations qui ne sont pas des en-têtes HTTP 1. Ces informations sont mises dans les HEADERS HTTP 2, précédés d'un deux-points. C'est le cas de la méthode (RFC 7231, section 4), donc GET sera encodé :method get. L'URL sera éclaté dans les pseudo-en-têtes :scheme, :path, etc. Idem pour la réponse HTTP, le fameux code à trois lettres est désormais un pseudo-en-tête, :status.

Voici un exemple (mais vous ne le verrez pas ainsi si vous espionnez le réseau, en raison de la compression du RFC 7541) :

### HTTP 1, pas de corps dans la requête ###
GET /resource HTTP/1.1          
Host: example.org         
Accept: image/jpeg          

### HTTP 2 (une trame HEADERS)
:method = GET
:scheme = https
:path = /resource
host = example.org
accept = image/jpeg

Puis une réponse qui n'a pas de corps :

### HTTP 1 ###
HTTP/1.1 304 Not Modified      
ETag: "xyzzy"              
Expires: Thu, 23 Jan ... 

### HTTP 2, une trame HEADERS ###
:status = 304
etag = "xyzzy"
expires = Thu, 23 Jan ...

Une réponse plus traditionnelle, qui inclut un corps :

### HTTP 1 ###
HTTP/1.1 200 OK 
Content-Type: image/jpeg   
Content-Length: 123        

{binary data} 

### HTTP 2 ###
# trame HEADERS
:status = 200
content-type = image/jpeg
content-length = 123

# trame DATA
{binary data}

Plus compliqué, un cas où les en-têtes de la requête ont été mis dans deux trames, et où il y avait un corps dans la requête :

### HTTP 1 ###
POST /resource HTTP/1.1    
Host: example.org     
Content-Type: image/jpeg
Content-Length: 123     

{binary data}           

### HTTP 2 ###
# trame HEADERS
:method = POST
:path = /resource
:scheme = https

# trame CONTINUATION
content-type = image/jpeg
host = example.org
content-length = 123

# trame DATA
{binary data}

Nouveauté de HTTP 2, la possibilité pour le serveur de pousser (push, section 8.2 de notre RFC) du contenu non sollicité vers le client (sauf si cette possibilité a été coupée par le paramètre SETTINGS_ENABLE_PUSH). Pour cela, le serveur (et lui seul) envoie une trame de type PUSH_PROMISE au client, en utilisant le ruisseau où le client avait fait une demande originale (donc, la sémantique de PUSH_PROMISE est « je te promets que lorsque le moment sera venu, je répondrai plus longuement à ta question »). Cette trame contient une requête HTTP. Plus tard, lorsque le temps sera venu, le serveur tiendra sa promesse en envoyant la « réponse » de cette « requête » sur le ruisseau qu'il avait indiqué dans le PUSH_PROMISE.

Et enfin, à propos des méthodes HTTP 1 et de leur équivalent en HTTP 2, est-ce que CONNECT (RFC 7231, section 4.3.6) fonctionne toujours ? Oui, on peut l'utiliser pour un tunnel sur un ruisseau. (Un tunnel sur un ruisseau... Beau défi pour le génie civil.)

La section 9 de notre RFC rassemble quelques point divers. Elle rappelle que, contrairement à HTTP 1, toutes les connexions sont persistentes et que le client n'est pas censé les fermer avant d'être certain qu'il n'en a plus besoin. Tout doit passer à travers une connexion vers le serveur et les clients ne doivent plus utiliser le truc d'ouvrir plusieurs connexions HTTP avec le serveur. De même, le serveur laisse les connexions ouvertes le plus longtemps possible, mais a le droit de les fermer s'il doit économiser des ressources.

À noter qu'on peut utiliser une connexion prévue pour un autre nom, du moment que cela arrive au même serveur (même adresse IP). Le pseudo-en-tête :authority sert à départager les requêtes allant à chacun des serveurs. Mais attention si la session utilise TLS ! L'utilisation d'une connexion avec un autre :authority (host + port) n'est possible que si le certificat serveur qui a été utilisé est valable pour tous (par le biais des subjectAltName, ou bien d'un joker).

À propos de TLS (certainement un des points les plus chaudement disputés à l'IETF dans les discussions sur HTTP 2), la section 9.2 prévoit quelques règles qui n'existaient pas en HTTP 1 (et dont la violation peut entrainer la coupure de la connexion avec l'erreur INADEQUATE_SECURITY) :

  • TLS 1.2 (RFC 5246), minimum,
  • Gestion de SNI (RFC 6066) obligatoire,
  • Compression coupée (RFC 3749), comme indiqué dans le RFC 7525 (permettre la compression de données qui mêlent informations d'authentification comme les cookies, et données contrôlées par l'attaquant, permet certaines attaques comme BREACH) ce qui n'est pas grave puisque HTTP a de meilleures capacités de compression (voir aussi la section 10.6),
  • Renégociation coupée, ce qui empêche de faire une renégociation en réponse à une certaine requête (pas de solution dans ce cas) et peut conduire à couper une connexion si le mécanisme de chiffrement sous-jacent ne permet pas d'encoder plus de N octets sans commencer à faire fuiter de l'information.
  • Très sérieuse limitation du nombre d'algorithmes de chiffrement acceptés (voir l'annexe A pour une liste complète), en éliminant les algorithmes trop faibles cryptographiquement (comme les algorithmes « d'exportation » utilisés dans la faille FREAK). Peu d'algorithmes restent utilisables après avoir retiré cette liste !

TLS avait été au cœur d'un vigoureux débat : faut-il essayer systématiquement TLS, même sans authentification, même si l'URL est de plan http: et pas https: ? Ce « chiffrement opportuniste » avait été proposé à l'IETF, pour diminuer l'efficacité de la surveillance massive (RFC 7258). C'était le ticket #314 du groupe de travail, et ce fut un des plus disputés. Quelques articles sur ce sujet du « tentons TLS à tout hasard » : http://bitsup.blogspot.fr/2013/08/ssl-everywhere-for-http2-new-hope.html, http://it.slashdot.org/story/13/11/13/1938207/http-20-may-be-ssl-only, http://www.pcworld.com/article/2061189/next-gen-http-2-0-protocol-will-require-https-encryption-most-of-the-time-.html, https://www.tbray.org/ongoing/When/201x/2013/11/05/IETF-88-HTTP-Security, http://www.mnot.net/blog/2014/01/04/strengthening_http_a_personal_view ou http://lists.w3.org/Archives/Public/ietf-http-wg/2013OctDec/0625.html. Il faut préciser que l'IETF n'a pas de pouvoirs de police : même si le RFC sur HTTP 2 avait écrit en gros « le chiffrement est obligatoire », rien ne garantit que cela aurait été effectif. Finalement, la décision a été de ne pas imposer ce passage en TLS, mais la question reste en discussion à l'IETF pour le plus grand déplaisir de ceux qui voudraient espionner le trafic plus facilement.

Puisqu'on parle de sécurité, la section 10 traite un certain nombre de problèmes de sécurité de HTTP 2. Parmi ceux qui sont spécifiques à HTTP 2, on note que ce protocole demande plus de ressources que HTTP 1, ne serait-ce que parce qu'il faut maintenir un état pour la compression. Il y a donc potentiellement un risque d'attaque par déni de service. Une mise en œuvre prudente veillera donc à limiter les ressources allouées à chaque connexion.

Enfin, il y a la question de la vie privée, un sujet chaud dans le monde HTTP depuis longtemps. Les options spécifiques à HTTP 2 (changement de paramètres, gestion du contrôle de flot, traitement des innombrables variantes du protocole) peuvent permettre d'identifier une machine donnée par son comportement. HTTP 2 facilite donc le fingerprinting.

En outre, comme une seule connexion TCP est utilisée pour toute une visite sur un site donné, cela peut rendre explicite une information comme « le temps passé sur un site », information qui était implicite en HTTP 1, et qui devait être reconstruite.

Question mises en œuvre de la nouvelle version de HTTP, un bon point de départ est la liste du groupe de travail. nginx n'a pas HTTP 2 mais y travaille. Pour le cas particulier des navigateurs Web, il y a un joli tableau.

Désolé de ne pas vous montrer un joli pcap de HTTP 2 mais la plupart des sites accessibles en HTTP 2 (et parfois des clients, « Firefox will only be implementing HTTP/2 over TLS ») imposent TLS, ce qui rend un peu plus compliquée l'analyse. Je n'ai pas encore trouvé de pcap HTTP 2 sur pcapr non plus, mais il y en a à la fin de la page http://daniel.haxx.se/http2/.

Quelques articles pertinents :


Téléchargez le RFC 7540


L'article seul

RFC 7541: HPACK - Header Compression for HTTP/2

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : R. Peon (Google), H. Ruellan (Canon CRF)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF httpbis
Première rédaction de cet article le 16 mai 2015


Une des nouveautés de la version 2 de HTTP, désormais normalisée dans le RFC 7540, est de représenter les en-têtes des requêtes et des réponses, non plus sous une forme texte, mais sous une forme binaire, avec compression. Ce RFC normalise le mécanisme de compression, nommé HPACK.

Fini, donc, de taper des en-têtes HTTP à la main dans une session telnet, ou bien d'écrire un serveur HTTP qui envoie simplement ses réponses avec un fprintf. Désormais, tout se fait en binaire et sera comprimé, pour gagner quelques octets. L'encodage peu efficace des en-têtes de HTTP version 1 faisait perdre de l'espace, donc du temps, d'autant plus qu'ils sont répétés à chaque requête. Il fallait donc comprimer. Mais un algorithme de compression général, comme le DEFLATE (RFC 1951) qu'utilisait le premier prototype de HTTP 2, le protocole SPDY, avait des conséquences néfastes en terme de sécurité, lorsqu'il était combiné au chiffrement. D'où l'idée d'un algorithme spécifique à HTTP et n'ayant pas ces défauts, l'actuel HPACK. HPACK se veut simple (le RFC fait quand même 58 pages, celui de DEFLATE n'en faisait que 17), et inflexible (pas d'options à négocier).

HPACK est prévu (section 1.1 du RFC) pour comprimer des en-têtes HTTP, c'est-à-dire une suite ordonnée de doublets {nom, valeur}. La duplication des noms est autorisée.

La spécification de HPACK n'impose pas un algorithme spécifique pour le compresseur, elle décrit juste ce à quoi doivent ressembler les données comprimées, pour que le décompresseur arrive à les reconstituer.

Les données comprimées vont contenir des index, qui référencent une table, et des valeurs littérales. HPACK utilise deux tables, qui permettent d'associer un index à un en-tête. La première table est statique : définie dans ce RFC, dans l'annexe A, elle comporte les en-têtes les plus courants. Ainsi, Accept-encoding: gzip,deflate (RFC 7231, section 5.3.4), présent chez presque tous les navigateurs Web, sera représenté par l'index 16. Cette table statique a surtout des entrées qui sont des pseudo-en-têtes, c'est-à-dire des valeurs dans les requêtes ou les réponses qui n'étaient pas définies comme des en-têtes en HTTP 1 mais qui sont assimilés à des en-têtes en HTTP 2 (on les reconnait à leur nom qui commence par deux-points). Ainsi, le classique GET (:method GET pour HTTP 2) sera l'index 2 et /index.html (:path /index.html en HTTP 2) sera l'index 5.

La seconde table est dynamique : vide au début, elle se remplit au fur et à mesure de la compression ou de la décompression. Ses index commencent là où la table statique se termine (à l'index 61).

Un en-tête pourra donc être représenté par un index (cas du Accept-encoding: gzip,deflate plus haut) ou bien par une combinaison d'un nom d'en-tête et d'une valeur. Le nom d'en-tête pourra être un index (Content-type:, index 31, est un exemple dans la table statique) ou bien indiqué littéralement.

Quelles données peut-on mettre dans un flot de données HPACK ? La section 5 expose comment sont représentés entiers et chaînes de caractères. Rappelez-vous que le but est de gagner de la place et les entiers peuvent donc avoir une représentation un peu baroque, un entier pouvant commencer au beau milieu d'un octet (des exemples figurent en annexe C.1). Les chaînes de caractères peuvent être représentées telles quelles mais aussi être comprimées avec Huffman (le code Huffman utilisé est dans l'annexe B).

La section 6 décrit la représentation complète en binaire. Bon, et la table dynamique, elle est gérée comment ? Sa taille peut changer dynamiquement mais la taille maximale est déterminée par le paramètre SETTINGS_HEADER_TABLE_SIZE. Certains éléments dans les données ne changent pas la table mais d'autres ajoutent une entrée à la table dynamique. Selon les bits placés au début d'un élément (section 6), le décodeur sait si la donnée est indexée ou littérale et, si elle est littérale, s'il faut l'ajouter à la table dynamique. De nombreux exemples en annexe C permettent de se faire une meilleure idée de l'encodage.

Enfin, la section 7 se penche sur quelques problèmes de sécurité. Contrairement à DEFLATE (RFC 1951) qui permettait de deviner un préfixe du terme comprimé (ce qui, combiné avec le fait que TLS ne masque pas la longueur des données, seulement leur contenu, menait à l'attaque CRIME), HPACK oblige l'attaquant actif à tester un terme entier. Une attaque par force brute pour essayer de deviner le contenu en se basant sur la longueur observée reste donc possible, bien que nettement plus coûteuse qu'avec DEFLATE. Pour rendre plus difficile cette attaque, on peut avoir intérêt à ne pas comprimer les en-têtes les plus sensibles (comme les cookies). D'autres méthodes dépendent de l'application : par exemple, un navigateur Web ne devrait pas permettre l'utilisation de la même connexion HTTP 2 (donc du même contexte de compression/décompression) par du code issu de deux origines (RFC 6454) différentes.

Attention enfin à la consommation mémoire : compression et décompression peuvent en nécessiter beaucoup. La limite à la taille de la table dynamique est là pour empêcher les excès.

Toutes les mises en œuvre de HTTP 2 ont également HPACK, et en voici une liste.


Téléchargez le RFC 7541


L'article seul

RFC 7539: ChaCha20 and Poly1305 for IETF protocols

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : Y. Nir (Check Point), A. Langley (Google)
Pour information
Réalisé dans le cadre du groupe de recherche IRTF cfrg
Première rédaction de cet article le 15 mai 2015


Les algorithmes de cryptographie ChaCha20 et Poly1305 n'avaient jamais fait l'objet d'une spécification stable, permettant leur référencement pour les protocoles IETF. C'est désormais fait avec ce RFC, qui normalise aussi bien leur utilisation isolée (ChaCha20 seul ou Poly1305 seul) que leur combinaison, qui fournit du chiffrement intègre (AEAD).

Aujourd'hui, la référence en matière de chiffrement symétrique est AES, entre autres en raison de ses performances très élevées sur du matériel dédié. AES est quatre à dix fois plus rapide que 3DES, qui était la précédente référence. Il est donc logique que AES soit utilisé partout, et notamment qu'il chiffre la quasi-totalité des sessions TLS. Le problème alors est qu'on dépend trop d'AES : si une faille est découverte par la cryptanalyse, on est fichu (AES est par exemple vulnérable dans certains cas). Il serait plus rassurant d'avoir des alternatives sérieuses à AES (n'obligeant pas à revenir à 3DES), pour que d'éventuelles percées en cryptanalyse ne cassent pas toute la crypto d'un coup. D'autant plus qu'AES a un défaut : rapide sur du matériel spécialisé, il l'est moins sur du matériel généraliste.

D'où les algorithmes décrits formellement dans ce RFC. Inventés par Bernstein, ils ont déjà fait l'objet d'un certain nombre d'analyses de sécurité (« New Features of Latin Dances: Analysis of Salsa, ChaCha, and Rumba » et « Latin Dances Revisited: New Analytic Results of Salsa20 and ChaCha »). ChaCha20 est un algorithme de chiffrement symétrique, plus rapide qu'AES sur un matériel générique (mise en œuvre purement en logiciel), Poly1305 est un MAC, et les deux peuvent être combinés pour faire du chiffrement intègre (et cela figure désormais dans le registre sur AEAD).

La section 2 du RFC décrit les algorithmes (je ne la reprends pas ici, la crypto, c'est trop fort pour moi), et ajoute du pseudo-code, des exemples et des vecteurs de test (il y en a d'autres dans l'annexe A). À l'origine, Poly1305 était décrit comme lié à AES, pour obtenir, par chiffrement du numnique, une chaîne de bits unique et secrète. Mais, en fait, n'importe quelle fonction de chiffrement convient, pas uniquement AES. (L'article du Wikipédia anglophone sur Poly1305 continue à colporter cette erreur.)

En cryptographie, ce sont plus souvent les mises en œuvre que les algorithmes qui ont une faille. La section 3 est donc consacrée aux avis aux programmeurs, pour éviter qu'une erreur de leur part n'affaiblisse ces beaux algorithmes. Poly1305 nécessite de travailler avec des grands nombres et le RFC déconseille d'utiliser la plupart des bibliothèques existantes de gestion des grands nombres comme celle d'OpenSSL. Celles-ci sont trop souvent vulnérables à des attaques par mesure du temps écoulé et le RFC conseille d'utiliser uniquement des bibliothèques qui font leur travail en un temps constant, comme NaCl. Un exemple de mise en œuvre de Poly1305 est poly1305-donna.

La section 4, sur la sécurité, détaille les points importants à suivre pour ne pas se faire casser sa jolie crypto. Pour ChaCha20, avant tout, il faut utiliser un numnique (numnique ?) vraiment unique. On peut utiliser un compteur, on peut utiliser un LFSR, mais il doit être unique.

ChaCha20 et Poly1305 n'utilisent que des opérations simples, normalement faciles à implémenter en un temps constant, qui ne permettra pas à l'attaquant de déduire quoi que ce soit de la mesure des temps de réponse. Attention, programmeurs, certaines fonctions comme la classique memcmp() ne s'exécutent pas en un temps constant, et, si elles sont utilisées, permettent certaines attaques.

À noter que ces algorithmes ne sont pas encore dans le registre IANA des algorithmes TLS. Leur mise en œuvre dans Chrome et chez CloudFlare utilise une valeur non-standard et non interopérable pour identifier l'algorithme. Les discussions se poursuivent pour intégrer ChaCha20 à Firefox.


Téléchargez le RFC 7539


L'article seul

RFC 7535: AS112 Redirection using DNAME

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : J. Abley (Dyn), B. Dickson (Twitter), W. Kumari (Google), G. Michaelson (APNIC)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 15 mai 2015


Les serveurs DNS, notamment ceux de la racine, sont en permanence bombardés par un trafic « inutile », des demandes de résolution DNS d'origine locale, et qui n'auraient jamais dû sortir. Par exemple, dans les réseaux qui utilisent les adresses IP privées du RFC 1918, les demandes de « résolution inverse » (« quel est le nom correspondant à 192.168.24.66 ? ») devraient toujours être résolues localement (après tout, il s'agit d'adresses privées) mais souvent les gestionnaires de ces réseaux ne configurent pas correctement leurs résolveurs et paf, la requête 66.24.168.192.in-addr.arpa arrive à la racine, qui ne peut pas en faire grand'chose. Idem si un réseau local utilise (bien à tort) un TLD local comme .home ou .corp. Les requêtes pour des TLD inexistants font plus de 25 % du trafic atteignant la racine. Pour les noms correspondants aux adresses du RFC 1918, le problème a été réglé par la création d'un « puits DNS », l'AS112 (RFC 7534). Les serveurs de l'AS112 sont des machines sacrifiées, à qui on envoie toutes les requêtes pour les noms en in-addr.arpa correspondant au RFC 1918. Cela marche très bien depuis de nombreuses années. Tellement bien qu'on se dit qu'on pourrait jeter dans ce puits bien d'autres choses comme les équivalents IPv6 du RFC 1918 (d.f.ip6.arpa, par exemple, cf. RFC 4193), ou comme les TLD tel que .home. Seulement, voilà, l'AS112 n'a pas été prévu pour cela et, avec leur configuration actuelle, ses serveurs ne répondraient pas correctement à ces requêtes. Il suffit de changer cette configuration ? Plus facile à dire qu'à faire, car l'AS112 est composé de nombreux serveurs plus ou moins coordonnés. Il est probablement impossible de les reconfigurer tous. D'où la nouvelle technique, utiliser (pour la première fois en grand) les enregistrements DNAME.

La nature même de l'AS112, système très décentralisé, sans direction claire, fait qu'il est impossible de changer la configuration de tous les nœuds. Même si l'IETF, l'ARCEP, l'ICANN, la NSA, le CSA et Jean-Kevin étaient tous d'accord, on ne pourrait pas garantir qu'il ne traine pas des nœuds AS112 ayant l'ancienne liste. Et puis on ne veut pas faire juste un changement une fois. On voudrait davantage de souplesse, permettant d'ajouter (ou de retirer) des noms à l'AS112 facilement, sans passer à chaque fois des mois, voire des années, à rappeler aux gérants des serveurs AS112 qu'ils doivent changer leur configuration.

Comme toujours avec l'AS112, l'idéal serait que les administrateurs DNS fassent tous correctement leur travail et suivent le RFC 6303, qui leur impose de servir des zones comme *.168.192.in-addr.arpa localement. Mais, dans le monde réel, ça n'arrive pas et l'AS112 (nommé, j'ai oublié de le dire, d'après le numéro de système autonome qui lui a été attribué) reste indispensable.

On a vu plus haut que l'AS112 n'était que faiblement coordonné. Ses serveurs sont anycastés (RFC 4786) et composés de nombreuses machines, administrées par des personnes différentes. Si on décidait de déléguer, mettons, .home, aux serveurs de l'AS112, blackhole-1.iana.org et blackhole-2.iana.org, certaines des instances de ces deux serveurs seront correctement configurées et répondront, à juste titre, NXDOMAIN (ce domaine n'existe pas : c'est la réponse unique de l'AS112). Mais d'autres instances, administrées avec retard, ou gérées par des gens surmenés qui ont raté l'annonce faite sur la liste des gérants AS112, ne sauront pas qu'elles doivent répondre aux requêtes pour *.home. Elles seront en lame delegation, avec des résultats plus ou moins bons (selon le logiciel utilisé) tels qu'une réponse REFUSED (qui poussera les résolveurs à essayer un autre serveur de la zone, alors que l'objectif était au contraire de diminuer le trafic).

L'IETF a donc choisi une voie différente pour l'évolution de l'AS112 : créer un nouveau préfixe, qui recevra les délégations des nouveaux in-addr.arpa, ip6.arpa, TLD, etc. Les nœuds utilisant ce nouveau préfixe utiliseront une nouvelle technique, à base de DNAME (RFC 6672), pour ne pas avoir à être configuré avec la liste des domaines à servir. Cela permettra de faire évoluer cette liste, ce qui est organisationnellement impossible avec les préfixes actuels de l'AS112.

Un enregistrement DNAME dit qu'une zone est un alias d'une autre. Ainsi :

example.com.     DNAME    example.net.

va faire que tous les noms sous example.com (mais pas example.com lui-même, attention), sont les alias des noms correspondants en example.net. Si on veut trouver l'adresse IPv6 associée à foobar.example.com, le résolveur DNS, en trouvant le DNAME, fera une requête pour foobar.example.net et en transmettra le résultat à l'utilisateur.

La nouvelle zone de l'AS112 se nomme empty.as112.arpa et elle est déléguée à un seul serveur (anycasté), blackhole.as112.arpa (192.31.196.1 / 2001:4:112::1). Ce serveur n'a pas les mêmes adresses que les serveurs traditionnels de l'AS112, il y aura deux jeux de serveurs complètement différents, puisqu'ils auront une configuration distincte (une liste fixée de domaines pour les anciens serveurs, cf. RFC 6304, et une seule zone, la cible des DNAME, pour les nouveaux serveurs). Certains serveurs pourront faire partie des deux jeux à la fois (par exemple des anciens serveurs qui seraient modifiés pour gérer les nouvelles adresses en même temps que les anciennes). L'ancien AS112 continue à fonctionner comme avant. Les nouveaux préfixes anycast correspondants sont 192.31.196.0/24 et 2001:4:112::/48, qui ne servent qu'à l'AS112. (Vous pouvez les chercher dans le looking glass de votre choix. L'AS d'origine sera le 112. L'AS112 est désormais à l'origine de quatre préfixes.) Ces adresses IP du serveur du nouvel AS112 ont été enregistrées dans le registre des adresses spéciales créé par le RFC 6890.

Donc, si vous voulez rediriger une zone DNS vers le puits du nouvel AS112, il suffit d'en faire un DNAME de empty.as112.arpa. Oui, aucun besoin de prévenir qui que ce soit, ou de demander une autorisation, vous n'avez qu'à ajouter cet enregistrement.

Un petit mot pour les fanas de gouvernance : le RFC 3172 confie la gestion politique de .arpa à l'IAB et c'est donc celle-ci qui a eu à approuver, sinon ce RFC, du moins le domaine dont il avait besoin, as112.arpa.

À l'heure actuelle, je n'ai pas l'impression qu'il y ait déjà des redirections vers empty.as112.arpa (en tout cas, DNSDB n'en trouve pas). Il faut dire qu'il y a encore peu de serveurs dans le nouvel AS112. Une fois qu'il sera peuplé, et pourra donc gérer le trafic, on pourra mettre des redirections. Rappelez-vous que l'installation d'une redirection ne nécessite aucun changement dans les serveurs du nouvel AS112. Pour tester, vous pouvez utiliser ma zone sink.bortzmeyer.fr. Normalement, nimportequoi.sink.bortzmeyer.fr doit vous obtenir un NXDOMAIN de la part du serveur AS112 « le plus proche ». Voici, vu par les sondes Atlas les différentes réponses possibles pour le nouvel AS112, ce qui semble indiquer qu'il n'a que quatre serveurs :

%  python resolve-name.py -t SOA empty.as112.arpa
Measurement #2004698 for empty.as112.arpa/SOA uses 497 probes
[] : 11 occurrences
[as112.ottix.net. dns.ottix.net. 1 604800 60 604800 604800] : 2 occurrences
[blackhole.as112.arpa. dns.ripe.net. 1 604800 60 604800 604800] : 226 occurrences
[as112.hivane.net. info.hivane.net. 1 604800 60 604800 604800] : 184 occurrences
[blackhole.as112.arpa. noc.dns.icann.org. 1 604800 60 604800 604800] : 60 occurrences
Test done at 2015-05-14T10:59:36Z

Et l'ancien AS112 ? Il continue à fonctionner comme avant. Si le nouvel AS112 marche bien, s'il est largement peuplé, on pourra changer les actuelles délégations des zones RFC 1918 comme 10.in-addr.arpa et les remplacer par une redirection DNAME vers empty.as112.arpa, le nouvel AS112. Une fois que cela sera fait, l'ancien AS112 et ses serveurs blackhole-1.iana.org et blackhole-2.iana.org pourront être supprimés. Il n'y a toutefois pas de plan précis pour cela : il faut d'abord que le nouvel AS112 fasse ses preuves.

Quelles zones seront mises dans le nouvel AS112 ? Comme indiqué plus haut, n'importe quelle zone peut être déléguée au nouvel AS112 de manière unilatérale. Mais ce service est surtout utile pour les zones à fort trafic, comme celles listées dans le RFC 6303 (qui ne sont pas toutes dans l'ancien AS112, par exemple aucune zone en ip6.arpa n'y est) ou comme certains TLD (les plus importants à l'heure actuelle sont, dans l'ordre, .local, .home, .html, .localdomain et .internal). Dans le cas des TLD, toutefois, il est probable que l'incroyable bureaucratie ICANN et la mainmise du gouvernement états-unien sur le contenu de la racine ne retardent considérablement le projet.

Le choix d'utiliser DNAME n'a pas été sans mal. En effet, DNAME ne fait pas partie du DNS original, et ce n'est pas un simple type d'enregistrement pour des données passives, il nécessite un traitement spécifique dans les résolveurs (et, dans une certaine mesure, dans les serveurs faisant autorité). On ne peut donc pas compter sur 100 % de serveurs DNS gérant DNAME. Est-ce un problème ? Le RFC 6672 prévoit un mécanisme de secours, où l'enregistrement DNAME est accompagné d'un CNAME (les alias classiques) synthétisé à la demande par le serveur. En théorie, tout doit donc bien se passer, même dans un monde imparfait où tous les serveurs ne gèrent pas DNAME. Et en pratique ? L'annexe A décrit les expérimentations qui avaient été faites avant de choisir la solution DNAME (quelques autres avaient été proposées). Le test avait consisté en quatre images sur une page Web que devait charger les navigateurs. La page était distribuée sous forme d'une publicité payante, envoyée par la régie publicitaire à de nombreux navigateurs. Le premier URL, http://a.UNIQUE_STRING.dname.example.com/1x1.png?a.UNIQUE_STRING.dname utilise un domaine qui a un DNAME vers un autre domaine. Si tout l'Internet peut travailler avec des DNAME sans problème, l'image correspondante sera chargée dans 100 % des cas. (La chaîne de caractères UNIQUE_STRING est la même pour toutes les images mais varie à chaque chargement de la page. C'est donc l'identificateur d'un test donné.) Le second URL, http://b.dname.example.com/1x1.png?b.UNIQUE_STRING.dname, qui, contrairement au premier, utilise un nom de domaine qui a un DNAME, et qui n'a pas de partie unique et est donc fréquemment mis en cache. Le troisième URL, http://c.UNIQUE_STRING.target.example.net/1x1.png?c.UNIQUE_STRING.target, ressemble beaucoup au premier mais n'utilise pas du tout de DNAME. C'est du DNS on ne peut plus traditionnel, et il sert donc de contrôle : si le score est de moins de 100 % sur cette troisième image, c'est que le navigateur, la machine sur laquelle il tourne, ou bien le réseau qui l'héberge, ont d'autres problèmes que les DNAME. Un script en Flash dans la page mesure le résultat et le temps nécessaire pour l'obtenir. Enfin, une quatrième image, http://results.recorder.example.net/1x1.png? results.UNIQUE_STRING?za=FIRST_RESULT&zb=SECOND_RESULT&zc=THIRD_RESULT, sert juste à transmettre les résultats. Le journal du serveur HTTP ressemblera à :

GET /1x1.png?results.UNIQUE_STRING?za=1822&zb=1674&zc=1582

(Les chiffres sont les temps de chargement en millisecondes.)

Les résultats ? 98,1 % des tests ont permis le chargement de la première ou de la seconde image, celles qui utilisaient les DNAME. Il y a donc 1,9 % de clients qui ne peuvent pas utiliser les DNAME ? Non, car 2,8 % des tests de chargement de la troisième image (qui n'utilise pas de DNAME, que du DNS d'avant-guerre) ont également échoué. Ce qui montre que ce chiffre de 1,9 % est inférieur au pourcentage d'erreur (soubresauts du réseau, etc). Bref, les DNAME marchent très bien.

À noter que les serveurs du nouvel AS112, eux, n'ont aucun besoin de savoir gérer les DNAME. Seuls les résolveurs, et les serveurs faisant autorité pour les zones redirigées doivent le faire.

Le as112.arpa a été délégué début février 2015 :

% check-soa -i as112.arpa
a.iana-servers.net.
	199.43.132.53: OK: 2014122469 (2 ms)
	2001:500:8c::53: OK: 2014122469 (14 ms)
b.iana-servers.net.
	199.43.133.53: OK: 2014122469 (149 ms)
	2001:500:8d::53: OK: 2014122469 (156 ms)
c.iana-servers.net.
	2001:500:8e::53: OK: 2014122469 (13 ms)
	199.43.134.53: OK: 2014122469 (15 ms)

Et son fils :

% check-soa -i empty.as112.arpa
blackhole.as112.arpa.
        2001:4:112::1: OK: 1 (31 ms)
        192.31.196.1: OK: 1 (23 ms)

Voici une réponse actuelle pour le nouveau domaine :


% dig ANY empty.as112.arpa

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> ANY empty.as112.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30414
;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 1, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;empty.as112.arpa.	IN ANY

;; ANSWER SECTION:
empty.as112.arpa.	604800 IN SOA blackhole.as112.arpa. dns.ripe.net. (
				1          ; serial
				604800     ; refresh (1 week)
				60         ; retry (1 minute)
				604800     ; expire (1 week)
				604800     ; minimum (1 week)
				)
empty.as112.arpa.	3599 IN	RRSIG NSEC 8 3 3600 20150515204633 (
				20150508164936 52494 as112.arpa.
				lZf9d6oYISRAq8i6gLXXCwUoQP+qmOfAEIiY3hNr6PvD
				DE1kSeGGR3lo3fK6P/CajYv/8twZm/CNQvpAxlRLUyrY
				Hc2WHhgxCtiQx01pLrY9d/QRhiL1WqYZaMSrfNZX0H0S
				GUD1BOcVNzT/lYPz0EdZZKzEXle98ZGWwkIvewE= )
empty.as112.arpa.	3599 IN	NSEC hostname.as112.arpa. NS RRSIG NSEC
empty.as112.arpa.	3599 IN	NS blackhole.as112.arpa.

;; AUTHORITY SECTION:
empty.as112.arpa.	3599 IN	NS blackhole.as112.arpa.

;; ADDITIONAL SECTION:
blackhole.as112.arpa.	3599 IN	A 192.31.196.1
blackhole.as112.arpa.	3599 IN	AAAA 2001:4:112::1
blackhole.as112.arpa.	3599 IN	RRSIG A 8 3 3600 20150516053029 (
				20150508164936 52494 as112.arpa.
				B4eU9u5ZQVGf+Haro2CeCanWwFLeK3hvil8dIlpz1fMm
				xR8K1No4rWTV5hWME1GhFatZVgpATfat9A3rghGWB9Xm
				hcmsaE5uHTOB+56DNhiokWsVtj+WT828naDMlfvGWiP4
				cXIxF/tLcR10XYviczlKYYR/SgAVxgmwjFkBHXg= )
blackhole.as112.arpa.	3599 IN	RRSIG AAAA 8 3 3600 20150515212644 (
				20150508164936 52494 as112.arpa.
				Yk2l+kWkYbYruCNHIKZwGg8GZPDp9y5Qezqk+Ogq5rGF
				/3+R/UjPPw240zdnLi4D2DeBFwlvM8rDq0xt3sreEmdk
				jMdxGcAc8eEfM6O1heP7lgRJW4eCzwOdNX6f1IXEIerg
				XwYWu+3VjI6y4NsrYoczfo+ORAHsdUvz9rdYumk= )

;; Query time: 854 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Fri May  8 20:43:04 2015
;; MSG SIZE  rcvd: 726


Téléchargez le RFC 7535


L'article seul

RFC 7534: AS112 Nameserver Operations

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : J. Abley (Dyn), W. Sotomayor (OttIX)
Pour information
Réalisé dans le cadre du groupe de travail IETF dnsop
Première rédaction de cet article le 15 mai 2015


Le système AS112, décrit dans ce RFC, est à la fois un utile composant du DNS, améliorant les performances et reduisant la charge du réseau, un banc d'essai pour des nouvelles techniques comme l'anycast, et une expérimentation sociale, celle d'un service 100 % acentré.

Un certain nombre de sites connectés à l'Internet utilisent des adresses IP privées, tirées du RFC 1918. Bien des logiciels, lorsqu'ils voient passer un nouveau client, font une résolution DNS pour obtenir le nom du client en fonction de son adresse IP (résolution dite PTR). C'est par exemple le cas du serveur de courrier Postfix, chez qui ce comportement n'est pas débrayable. Lorsque l'adresse IP est privée, il ne sert à rien de poser la question au DNS public. Par définition, celui-ci ne peut pas savoir que MaPetiteEntreprise utilise 192.168.1.0/24 et a attribué 192.168.1.33 à posteclientX.mapetiteentreprise.example. La bonne pratique est donc que l'administrateur réseaux d'un site qui utilise ces adresses privées doit configurer des serveurs DNS pour répondre aux requêtes PTR (cf. RFC 6303). Pour voir cela, on peut utiliser l'option -x de dig, qui permet de faire automatiquement une résolution d'adresse en nom. Le domaine in-addr.arpa (RFC 5855) accueille la forme inversée des adresses (192.168.1.33 devient 33.1.168.192.in-addr.arpa). Testons ici une adresse publique :

% dig -x 192.134.4.20
...
;; ANSWER SECTION:
20.4.134.192.in-addr.arpa. 172800 IN    PTR     rigolo.nic.fr.

Mais beaucoup d'administrateurs réseaux sont négligents, surchargés de travail, incompétents ou les trois à la fois. Ils ne configurent pas ces serveurs DNS et, résultat, la requête PTR sort de leur réseau et va taper sur les serveurs DNS de la racine puis à ceux de in-addr.arpa. (Une bonne partie du trafic semble ainsi venir des réseaux 3G, où le smartphone ne reçoit qu'une adresse privée et où le résolveur DNS qui lui est indiqué ne connait pas les zones correspondantes.) Ceux-ci ont normalement autre chose à faire que de répondre à des requêtes qui sont, dès le départ, des erreurs. Ils délèguent donc à l'AS112, un ensemble de serveurs de noms qui est chargé de répondre « ce nom n'existe pas » à toutes ces requêtes parasites. L'AS112 est donc un puits où finissent les erreurs. Initialement normalisé dans le RFC 6304, il est désormais décrit par ce nouveau RFC. Le nouvel AS112 introduit une importante nouveauté, un mécanisme de délégation utilisant les enregistrements DNAME (RFC 6672) et qui permet de désigner plus facilement des zones à diriger vers le puits. Il y a donc désormais l'ancien AS112 (qui continue à fonctionner et à servir les zones du RFC 1918) et le nouvel AS112, qui servira les futures zones comme les ULA IPv6 du RFC 4193, ou comme des TLD tels que .local ou .home.

On peut voir la délégation de l'ancien AS112 (ancien mais toujours utilisé) avec dig (sauf si votre résolveur suit les recommandations du RFC 6303) :


% dig NS 168.192.in-addr.arpa

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> NS 168.192.in-addr.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56121
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;168.192.in-addr.arpa.  IN NS

;; ANSWER SECTION:
168.192.in-addr.arpa.   8726 IN NS blackhole-2.iana.org.
168.192.in-addr.arpa.   8726 IN NS blackhole-1.iana.org.

;; ADDITIONAL SECTION:
blackhole-1.iana.org.   604 IN A 192.175.48.6
blackhole-1.iana.org.   603 IN AAAA 2620:4f:8000::6
blackhole-2.iana.org.   603 IN A 192.175.48.42
blackhole-2.iana.org.   603 IN AAAA 2620:4f:8000::42

;; Query time: 2 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Fri May 15 10:28:38 2015
;; MSG SIZE  rcvd: 197

La délégation va être conservée dans les mémoires caches des résolveurs DNS et la racine ou in-addr.arpa ne seront donc plus embêtés, après la première requête.

Pour le nouvel AS112, utilisant la technique du RFC 7535, la délégation est :


% dig NS empty.as112.arpa

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> NS empty.as112.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25550
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;empty.as112.arpa.      IN NS

;; ANSWER SECTION:
empty.as112.arpa.       3595 IN NS blackhole.as112.arpa.

;; ADDITIONAL SECTION:
blackhole.as112.arpa.   3595 IN A 192.31.196.1
blackhole.as112.arpa.   3595 IN AAAA 2001:4:112::1

;; Query time: 2 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Fri May 15 10:29:25 2015
;; MSG SIZE  rcvd: 113

Mais qui sont ces machines 192.175.48.6, 192.175.48.42 et 192.31.196.1 ? Des très gros serveurs payés par un mécène et installés à un endroit bien connecté ? Pas du tout. C'est ici que rentre en jeu l'AS112. Ce dernier est composé d'un réseau informel de dizaines de machines un peu partout dans le monde et qui annoncent toutes être 192.175.48.6 et 192.175.48.42 (pour l'ancien préfixe) et 192.31.196.1 (pour le nouveau). Chacune de ces machines encaisse une partie de la charge. L'AS112 n'a pas de chef, juste un site Web et un RFC, ce RFC 7534.

L'AS112 doit son nom au numéro de système autonome qui lui a été attribué (et qui est désormais dans le registre des AS spéciaux, créé par le RFC 7249). Ses serveurs utilisent l'anycast (RFC 4786) pour distribuer la charge entre eux. Avant Global Anycast, c'était donc le premier projet d'anycast entre serveurs faiblement coordonnés. Une histoire complète de l'AS112 figure en annexe A de notre RFC.

Les détails pratiques, maintenant. La liste des zones servies par l'ancien AS112 (Direct Delegation) figure en section 3.2. (Le nouvel AS112 suit un système de délégation dynamique décrit dans le RFC 7535.) Elle comprend 10.in-addr.arpa pour le réseau 10.0.0.0/8, de 16.172.in-addr.arpa à 31.172.in-addr.arpa pour le 172.16.0.0/12, et 168.192.in-addr.arpa pour le 192.168.0.0/16, les préfixes du RFC 1918. Elle inclus aussi 254.169.in-addr.arpa pour le préfixe « local au lien » du RFC 5735. Pour aider à l'identification du nœud qui répond, les serveurs de l'AS112 servent également la zone hostname.as112.net, ici à Paris :


% dig +nsid TXT hostname.as112.net

; <<>> DiG 9.7.3 <<>> +nsid TXT hostname.as112.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1078
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 2, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hostname.as112.net.            IN      TXT

;; ANSWER SECTION:
hostname.as112.net.     267     IN      TXT     "Unicast IP: 193.17.192.194"
hostname.as112.net.     267     IN      TXT     "See http://as112.net/ for more information."
hostname.as112.net.     267     IN      TXT     "See http://noc.hivane.net/cgi-bin/dsc-grapher.pl for local information."
hostname.as112.net.     267     IN      TXT     "Paris, FR"
hostname.as112.net.     267     IN      TXT     "Hivane Networks"

;; AUTHORITY SECTION:
hostname.as112.net.     267     IN      NS      blackhole-2.iana.org.
hostname.as112.net.     267     IN      NS      blackhole-1.iana.org.

;; ADDITIONAL SECTION:
blackhole-1.iana.org.   241     IN      A       192.175.48.6
blackhole-2.iana.org.   241     IN      A       192.175.48.42

;; Query time: 1 msec
;; SERVER: 217.70.184.225#53(217.70.184.225)
;; WHEN: Wed Jul  6 12:36:14 2011
;; MSG SIZE  rcvd: 348

On note que les préfixes IPv6 n'y figurent pas. Pour le nouvel AS112, voici le même test :


% dig +nsid TXT hostname.as112.arpa

; <<>> DiG 9.9.2-P2 <<>> +nsid TXT hostname.as112.arpa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22893
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;hostname.as112.arpa.   IN TXT

;; ANSWER SECTION:
hostname.as112.arpa.    604318 IN TXT "RIPE NCC" "Amsterdam, The Netherlands"
hostname.as112.arpa.    604318 IN TXT "See http://www.as112.net/ for more information."

;; AUTHORITY SECTION:
hostname.as112.arpa.    604317 IN NS blackhole.as112.arpa.

;; Query time: 16 msec
;; SERVER: 192.168.2.254#53(192.168.2.254)
;; WHEN: Fri May 15 10:34:06 2015
;; MSG SIZE  rcvd: 180

(On peut avoir une liste des serveurs, à jour, sur le site officiel).

La section 3.3 décrit les serveurs de noms qui reçoivent la délégation, joliment (mais incorrectement, puisqu'ils répondent) nommés blackhole-1.iana.org et blackhole-2.iana.org, et blackhole.as112.arpa pour le nouvel AS (en dépit de leurs noms, les serveurs de l'AS112 ne sont pas gérés par l'IANA, cf. section 7). Dans le champ MNAME du SOA de la zone déléguée, on trouve également (pour l'ancien AS112) prisoner.iana.org dont la tâche principale est de répondre aux mises à jour dynamiques (RFC 2136) que certaines machines envoient audit MNAME. Du temps du RFC 6304, ces serveurs n'étaient accessibles qu'en IPv4 mais ils ont désormais également des adresses IPv6.

Ce RFC 7534 n'est pas seulement la description d'une technique mais également un HOWTO sur la configuration d'un serveur de l'AS112. De tels textes, prévus pour les administrateurs système, sont rares dans les RFC. La section 4 décrit ainsi tout ce que doit savoir le volontaire qui va créer un nouveau nœud. Il doit connaître BGP (RFC 4271), nécessaire pour l'anycast (RFC 4786) et la gestion d'un serveur DNS faisant autorité. Les serveurs de l'AS112 peuvent être situés n'importe où mais ils sont surtout utiles dans les endroits bien connectés, notamment les points d'échange. Ils peuvent être locaux (annonçant les routes avec la communauté BGP no-export, 0xFFFFFF01, cf. RFC 1997), ou globaux (servant le monde entier). Et naturellement, ils doivent se coordonner (via une liste de diffusion) avec les autres serveurs de l'AS112.

L'AS112 n'impose pas de système d'exploitation particulier (section 4.3) mais tous les serveurs existants semblent utiliser Unix et un grand nombre (c'est difficile à dire, puisque l'AS112 ne contrôle pas tout ce qui se passe sur les serveurs) se servent de BIND. Il est recommandé que la machine AS112 soit dédiée à cette tâche : ces serveurs reçoivent parfois un trafic intense qui pourrait perturber leurs autres activités.

Le serveur signale son existence et sa disponibilité en BGP. Il faut donc coupler le serveur de noms au serveur BGP, pour que l'arrêt du serveur DNS entraîne l'arrêt de l'annonce (le RFC ne fournit pas de script pour cela). Un exemple de comment cela peut se réaliser sur Linux, avec les adresses de l'AS112 attachées à une interface dummy, est (code utilisé sur un serveur anycast réel, quoique pas de l'AS112) :

# Load the variables (the machine is a RedHat)
. /etc/sysconfig/network-scripts/ifcfg-eth0

# Test if the name server actually works. Do not use ps: the server
may be there but unresponsive
TMP=(`dig +short +time=1 +tries=1 @${IPADDR} SOA example.`)
MASTER=${TMP[0]:=somethingwaswrong}

# Normal reply or not?
if test ${MASTER} != "nsmaster.nic.example."
then
    # Disable the interface: Quagga will stop announcing the route
    ifdown dummy0
    # Raise an alarm, send SMS, etc
fi

Le serveur BGP annonce les préfixes de l'ancien AS112, 192.175.48.0/24 et 2620:4f:8000::/48, qui couvrent les adresses de tous les serveurs et l'origine est évidemment 112 (les préfixes IP sont dans le registre des préfixes spéciaux créé par le RFC 6890). Si le serveur gère la zone du nouvel AS112, il annonce en BGP 192.31.196.0/24 et 2001:4:112::/48.

Les exemples du RFC supposent que le serveur BGP est Quagga mais cela peut évidemment marcher avec d'autres. Dans l'exemple ci-dessous, tiré du RFC (section 4.4), le router ID est 203.0.113.1 et le serveur BGP a deux pairs, 192.0.2.1 et 192.0.2.2. Voici un extrait du bgpd.conf (la version intégrale est dans le RFC) :

   hostname my-router
...
   router bgp 112
    bgp router-id 203.0.113.1
    network 192.175.48.0/24
    neighbor 192.0.2.1 remote-as 64496
    neighbor 192.0.2.1 next-hop-self
    neighbor 192.0.2.2 remote-as 64497
    neighbor 192.0.2.2 next-hop-self

En farfouillant sur le site officiel (pas très bien organisé, je trouve), on peut trouver d'autres exemples.

Le serveur AS112 a ensuite besoin d'un serveur DNS faisant autorité (section 4.5), évidemment compatible avec toutes les règles du DNS (RFC 1034). Les exemples de configuration du RFC sont fondés sur BIND. Voici un extrait du named.conf (la version intégrale est dans le RFC) :

   options {
     listen-on {
        ...
        // the following addresses correspond to AS112 addresses, and
        // are the same for all AS112 nodes
        192.175.48.1;      // prisoner.iana.org (anycast)
        192.175.48.6;      // blackhole-1.iana.org (anycast)
        192.175.48.42;     // blackhole-2.iana.org (anycast)

	// The following address is used to support DNAME redirection
        // AS112 service and is the same for all AS112 nodes.
	192.31.196.1;      // blackhole.as112.arpa (anycast)
	};

      listen-on-v6 {
       ...
       // The following addresses are used to support Direct Delegation
       // AS112 service and are the same for all AS112 nodes.
       2620:4f:8000::1;   // prisoner.iana.org (anycast)
       2620:4f:8000::6;   // blackhole-1.iana.org (anycast)
       2620:4f:8000::42;  // blackhole-2.iana.org (anycast)

       // The following address is used to support DNAME redirection
       // AS112 service and is the same for all AS112 nodes.
       2001:4:112::1;    // blackhole.as112.arpa (anycast)
       };
       
     recursion no;        // authoritative-only server
   };

   // RFC 1918
   zone "10.in-addr.arpa" { type master; file "db.empty"; };
   ...

   // RFC 5735
   zone "254.169.in-addr.arpa" { type master; file "db.empty"; };

   // DNAME redirection AS112 Service
   zone "empty.as112.arpa" { type master; file "db.dr-empty"; };

   // also answer authoritatively for the HOSTNAME.AS112.NET zone,
   // which contains data of operational relevance
   zone "hostname.as112.net" {
     type master;
     file "db.hostname.as112.net";
   };

   zone "hostname.as112.arpa" {
     type master;
     file "db.hostname.as112.arpa";
   };
   

Un exemple équivalent pour NSD (utilisé sur le nœud AS112 de Paris) est disponible en as112-nsd.conf (ancien AS112 seulement). Pour simplifier son écriture, il a été produit à partir d'un source en M4, as112-nsd.conf.m4.

Que contiennent les fichiers de zone db.empty, db-fr.empty, db.hostname.as112.net et db.hostname.as112.arpa ? Conformes à la syntaxe de la section 5 du RFC 1035, ils sont communs à BIND et NSD. Les deux premiers, comme leur nom l'indique, sont des fichiers de zone vide, puisque le serveur AS112 ne connait évidemment rien : il ne peut que répondre NXDOMAIN (ce nom n'existe pas) à toutes les requêtes. Ils ne contiennent donc que les informations obligatoires à toute zone (SOA, avec une adresse de contact appropriée) et NS. Les deux autres zones servent au déboguage de l'AS112, lorsqu'on veut obtenir des informations sur le serveur AS112 courant. Un contenu typique est juste composé d'enregistrements TXT :

           TXT     "Human AS112 server" "Minas Tirith, Gondor"
           TXT     "Forbidden to orcs and nazguls."
           TXT     "See http://www.as112.net/ for more information."

et parfois d'une localisation (cf. RFC 1876). Le résultat sur un site réel étant :


% dig ANY hostname.as112.net.

; <<>> DiG 9.7.3 <<>> ANY hostname.as112.net.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41528
;; flags: qr rd ra; QUERY: 1, ANSWER: 7, AUTHORITY: 2, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;hostname.as112.net.            IN      ANY

;; ANSWER SECTION:
hostname.as112.net.     604796  IN      LOC     37 58 22.590 N 23 44 43.890 E 100.00m 100m 10m 10m
hostname.as112.net.     604796  IN      TXT     "See http://as112.net/ for more information."
hostname.as112.net.     604796  IN      TXT     "Unicast IP: as112.grnet.gr"
hostname.as112.net.     604796  IN      TXT     "Greek Research & Technology Network" "Athens, Greece"
hostname.as112.net.     604796  IN      SOA     flo.gigafed.net. dns.ryouko.imsb.nrc.ca. 1 604800 60 604800 604800
hostname.as112.net.     604796  IN      NS      blackhole-2.iana.org.
hostname.as112.net.     604796  IN      NS      blackhole-1.iana.org.

;; AUTHORITY SECTION:
hostname.as112.net.     604796  IN      NS      blackhole-1.iana.org.
hostname.as112.net.     604796  IN      NS      blackhole-2.iana.org.

;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Jul  6 12:51:53 2011
;; MSG SIZE  rcvd: 391

(La version intégrale des quatre fichiers de zone figure dans le RFC.)

Une fois le nœud installé, il faut évidemment le tester (avec dig, par exemple). Si les réponses aux requêtes PTR sont correctes, mais pas celles aux requêtes pour le nom hostname.as112.{net,arpa}, c'est sans doute un problème de routage (on est envoyés sur un autre nœud de l'AS112) et il faut alors sortir traceroute et les looking glasses (section 4.6). Des tests dignes de ce nom doivent être faits depuis plusieurs FAI, et doivent tester les trois (ou quatre pour les nouveaux nœuds) adresses IPv4 de l'AS112, plus ses adresses IPv6.

Le bon fonctionnement de l'AS112 ne dépend pas uniquement de sa configuration initiale mais aussi de sa gestion et surveillance quotidiennes. La section 5 est consacrée aux questions opérationnelles. Le nœud doit être surveillé automatiquement, pour s'assurer qu'il répond toujours. S'il doit être arrêté (par exemple pour une maintenance prévue), il faut s'assurer que l'annonce BGP stoppe (autrement, BGP annonce un trou noir, d'où aucune réponse ne reviendra). Autre point important de la gestion opérationnelle d'un serveur de l'AS112, des statistiques, obtenues à partir d'outils comme DSC ou dnstop. Quelle est l'utilisation réelle de l'AS112 ? Ces statistiques n'étant pas consolidées globalement, c'est difficile à dire. Certains opérateurs publient leurs chiffres mais pas tous. Par exemple, le serveur d'Ottawa voit mille requêtes par seconde (cf. « AS112 Intro » par l'un des auteurs du RFC), celui géré par le RIPE-NCC dans les mille cinq cents, et celui à Paris deux fois plus (voir les graphiques), ce qui fait quand même quelques mégabits par seconde. La majorité des types demandés est évidemment du PTR mais il y a aussi un flux important de TXT, apparemment dus à la technologie SD (Service Discovery) d'Apple (voir des statistiques plus détaillées à la fin).

Le nouveau serveur peut alors être annoncé sur les listes appropriées (par exemple, chaque point d'échange a en général la sienne). Enfin, bien que chaque serveur de l'AS112 puisse fonctionner indépendemment des autres, il est évidemment préférable de se coordonner avec les petits camarades (section 6) en écrivant à la liste officielle.

Et dans le futur ? La section 7 explore l'avenir possible de l'AS112. Idéalement, il devrait disparaître petit à petit au fur et à mesure que les administrateurs réseaux prennent soin de ne pas laisser fuir les requêtes PTR pour les réseaux privés, comme recommandé dans le RFC 6303. Le déploiement de logiciels respectant ce principe dès le début pourrait aider. Toutefois, aujourd'hui, les opérateurs de l'AS112 n'observent pas de tendance à la baisse du trafic. Même des années après le déploiement de serveurs mettant en œuvre le RFC 6303, il est probable que le trafic de l'AS112 ne tombera pas à zéro et que ce service restera donc nécessaire.

Enfin, qu'en est-il de la sécurité ? Comme le rappelle la section 9, les requêtes DNS auxquelles répond l'AS112 ne devraient jamais y arriver, normalement. Elles auraient dû rester sur le réseau local. En sortant, elles exposent de l'information interne, qui était peut-être privée (qu'il y ait un serveur AS112 qui y réponde ou pas ne change guère ce risque).

Plus rigolo, comme ces requêtes sont en général involontaires (comme indiqué, elles auraient dû rester privées), les réponses sont inattendues. Plus d'un IDS a donc crié que l'AS112 essayait d'attaquer le réseau. Le RFC 6305 a été écrit pour fournir une réponse toute faite aux administrateurs incompétents qui accusaient l'IANA ou l'AS112.

Comme l'AS112 n'a pas de chef et que l'anycast ne permet pas de limiter le nombre de participants, il est tout à fait possible de fantasmer sur l'hypothèse d'un nœud AS112 voyou, qui donnerait exprès de mauvaise réponses. Ce problème (purement théorique) n'a pas vraiment de solution. Signer les zones avec DNSSEC semble franchement excessif, et difficile à réaliser de manière sûre puisqu'il faudrait distribuer la clé privée à tous les opérateurs de l'AS112.

L'annexe A du RFC expose la longue histoire de l'AS112, de ses débuts en 2002 (les adresses IP privées datent de 1996) à son état actuel, après la redélégation en 2011 de in-addr.arpa, autrefois sur les serveurs de la racine (RFC 5855). L'AS112 a été le premier déploiement massif de l'anycast et a donc joué un rôle primordial dans l'évaluation de cette technologie.

À noter que, d'après la liste officielle des sites, il existe au moins un serveur AS112 en France, chez Hivane, désormais (novembre 2011) connecté au France-IX. Malgré cela, les requêtes françaises pour les serveurs de l'AS112 voyagent souvent loin. C'est un problème banal comme le montrait l'excellente présentation « Investigating AS112 Routing and New Server Discovery ».

Voici quelques analyses sur le trafic de ce serveur français, faites avec DNSmezzo. Le fichier pcap fait 6,8 Go. Il y a 43 701 087 paquets DNS dont 21 858 845 sont des requêtes. Les données ont été prises un vendredi, de 13h40 à 15h30 (heure locale). Regardons d'abord les types de données demandés :

dnsmezzo=> SELECT (CASE WHEN type IS NULL THEN qtype::TEXT ELSE type END),
       meaning,                                                           
       count(results.id)*100/(SELECT count(id) FROM DNS_packets WHERE query) AS requests_percent FROM
             (SELECT id, qtype FROM dns_packets
                 WHERE query)  AS Results
          LEFT OUTER JOIN DNS_types ON qtype = value
              GROUP BY qtype, type, meaning ORDER BY requests_percent desc;


 type  |                meaning                 | requests_percent 
-------+----------------------------------------+------------------
 PTR   | a domain name pointer                  |               57
 TXT   | text strings                           |               35
 SOA   | marks the start of a zone of authority |                6
 CNAME | the canonical name for an alias        |                0
 MX    | mail exchange                          |                0
 AAAA  | IP6 Address                            |                0
 40    |                                        |                0
 DS    | Delegation Signer                      |                0
 ...

La première place des PTR est normale. Celle des TXT est plus surprenante. En regardant les noms utilisés (cf._dns-sd._udp.Y.X.243.10.in-addr.arpa...), on voit qu'ils sont dus à la technique Service Discovery d'Apple, un système normalement confiné au réseau local mais qui bave beaucoup à l'extérieur.

Et quels sont les domaines les plus populaires ?

dnsmezzo=> SELECT substr(registered_domain,1,46) AS domain, 
          count(id)*100/(SELECT count(id) FROM DNS_packets WHERE query) AS requests_percent  
       FROM dns_packets WHERE query GROUP BY registered_domain ORDER BY requests_percent DESC LIMIT 30;
      domain      | requests_percent 
------------------+------------------
 10.in-addr.arpa  |               78
 192.in-addr.arpa |               12
 172.in-addr.arpa |                7
 169.in-addr.arpa |                1
 151.in-addr.arpa |                0
 i~-addr.arpa     |                0
 83.in-addr.arpa  |                0
                  |                0
 gfi.private      |                0
 local.de         |                0
 grupofdez.com    |                0
....

On voit que le réseau 10.0.0.0/8 est nettement le plus populaire. On notera les trois derniers, sans doute des erreurs de configuration.

Et quels sont les résolveurs les plus actifs ? En agrégeant les préfixes IPv4 en /28 :

dnsmezzo=>  SELECT set_masklen(src_address::cidr, 28) AS client, count(id)*100/(SELECT count(id) FROM DNS_packets WHERE query) AS requests_percent                                                                  
     FROM dns_packets WHERE query GROUP BY set_masklen(src_address::cidr, 28)
           ORDER by requests_percent DESC LIMIT 30;
       client       | requests_percent 
--------------------+------------------
 CENSURE.160/28     |               29
 CENSURE.0/28       |               10
 CENSURE.16/28      |                8
 CENSURE.96/28      |                6
...

Oui, j'ai préféré ne pas donner les adresses. Je dirai simplement que ces quatre plus gros sont des opérateurs de téléphonie mobile, deux français et deux extrême-orientaux (les mystères du routage...).

Merci à Clément Cavadore, administrateur du plus gros (en nombre de requêtes) serveur AS112 du monde, pour les données et pour sa relecture.

Les principaux changements depuis le RFC 6304 :

  • Adresses IPv6 pour les serveurs de l'AS112,
  • « Nouvel AS112 », servant la zone empty.as112.arpa, vers laquelle les zones à gérer seront redirigées par un DNAME,
  • Enregistrement des préfixes à l'IANA.

Téléchargez le RFC 7534


L'article seul

RFC 7536: Large-Scale Broadband Measurement Use Cases

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : Marc Linsner (Cisco Systems), Philip Eardley, Trevor Burbridge (BT), Frode Sorensen (Nkom)
Pour information
Réalisé dans le cadre du groupe de travail IETF lmap
Première rédaction de cet article le 8 mai 2015


Mesurer les performances d'un réseau, c'est crucial. Cela permet de savoir si le réseau a bien les caractéristiques promises et cela permet de comparer les réseaux entre eux. D'où l'existence du groupe de travail LMAP de l'IETF, dont voici le premier RFC. Il décrit deux études de cas où la mesure est nécessaire : un opérateur qui veut s'assurer de la qualité du service qu'il fournit, et un régulateur des télécommunications qui veut vérifier que les opérateurs livrent bien ce qu'ils promettent, et ne discriminent pas certaines utilisations. Il y a bien sûr d'autres cas possibles (l'utilisateur final qui veut mesurer les performances de sa connexion...)

Ce RFC concerne aussi bien les mesures de l'accès fixe (ADSL, par exemple) que de l'accès par un mobile. Il n'y a aucune différence dans les problèmatiques métrologiques entre ces deux accès.

La section 2 de notre RFC décrit les deux scénarios d'usage, repris ensuite en détail dans la section 3 pour le cas du FAI et dans la section 4 pour le cas du régulateur. Commençons par le FAI. La mesure de son réseau l'aide à :

  • Identifier et isoler des problèmes (par exemple un lien saturé),
  • Vérifier que des SLA sont respectés,
  • Concevoir les extensions à son réseau (où faut-il déployer le nouveau matériel et les nouvelles fibres, en priorité),
  • Comprendre le vécu des clients (ce qu'on nomme parfois la QoE - Quality of Experience, qui ne dépend pas seulement de données brutes, comme la capacité des câbles, mais aussi de services comme les résolveurs DNS ou comme les CDN),
  • Comprendre (voire prédire) l'impact de nouvelles technologies déployées dans le réseau. (Le RFC prend l'exemple d'IPv6, pour les opérateurs attardés qui ne l'ont pas encore déployé.) Cela peut aussi concerner des problèmes bien plus triviaux comme la mise à jour du firmware d'une machine qui entraine tout à coup une chute des performances.

Il y a plein de détails techniques à prendre en compte pour ce genre de mesures et le problème est bien plus complexe que ne le croit l'amateur qui débarque dans le domaine. Par exemple, le RFC note que la mesure du vécu de l'utilisateur nécessite des mesures de bout en bout, jusqu'à la machine de M. Michu, mais que le réseau de ce dernier, dans sa maison, n'est pas sous le contrôle du FAI (le Wi-Fi peut être peu efficace en raison de problèmes radio). Le FAI tend donc plutôt à mesurer jusqu'au CPE, ce qui est plus fiable mais moins représentatif.

La meilleure façon de mesurer les caractéristiques du réseau est de faire des mesures actives, avec une machine qui envoie des requêtes et mesure le résultat. Pour ne pas interférer avec le trafic normal de l'utilisateur, il vaut mieux faire ces mesures actives lorsque l'utilisateur ne fait rien. Cela implique que le dispositif de mesure puisse savoir quand l'utilisateur est inactif (la documentation de SamKnows demande que l'engin soit placé en coupure sur le réseau local, lui permettant ainsi d'observer tout le trafic).

Des mesures actives lancées à la demande peuvent même être utilisées en réponse à une plainte d'un utilisateur. Il appelle le support en disant « Ça rame », l'employé au support clique sur un bouton sur son interface Web et cela lance des tests de performance depuis la box de cet abonné et, quelques secondes plus tard, leurs résultats s'affichent sur l'écran du support.

Une autre solution est de faire uniquement des mesures passives mais elles ne permettent d'observer que le débit, pas la capacité (qui est le débit maximum possible). Si on mesure 2 Mb/s de trafic, est-ce parce que le réseau ne permet pas plus ou bien simplement parce que c'est ce que fait l'utilisateur en ce moment ? En outre, les mesures passives soulèvent des problèmes liés à la protection de la vie privée.

Le régulateur, lui, veut évaluer les performances de plusieurs opérateurs et, typiquement, les publier (ce qui nécessite de la rigueur dans les faits et de la pédagogie dans les explications). Cela peut servir par exemple à mesurer le déploiement de l'accès Internet à « haut débit », ou bien à mesurer les pratiques de « gestion du trafic » (terme qui, dans le code des FAI, désigne les discriminations contre tel ou tel type de trafic). Dans tous les cas, vu les conséquences de la publication de ces mesures, le régulateur va devoir s'assurer qu'elles sont précises, significatives et reproductibles.

Il existe plusieurs façons de faire ces mesures : on peut utiliser par exemple un panel d'utilisateurs supposés représentatifs, et installer chez eux un équipement de mesure active, qui signale ce qu'il a obtenu à un serveur central. C'est ainsi que fonctionne SamKnows (ou bien un autre système, non utilisé par le régulateur, les sondes Atlas). Une autre solution, non mentionnée par notre RFC, est de mettre les sondes de mesure, non pas chez les utilisateurs (où il est très difficile de s'assurer qu'elles sont branchées correctement, et où elles peuvent rentrer en concurrence avec le trafic normal de l'utilisateur) mais dans des locaux spécialisés, loués à cette fin. C'est ce que fait l'ARCEP pour ses mesures de l'accès à l'Internet en France.

Une des motivations, pour le régulateur, est de déterminer les violations de la neutralité de l'Internet, afin de savoir s'il est utile de prendre des mesures légales ou autres, pour rétablir cette neutralité. Déterminer, par des mesures actives, si certains services réseau ou certaines destinations sont favorisés ou au contraire défavorisés n'est pas facile (cf. le projet Glasnost et sa publication « Enabling End Users to Detect Traffic Differentiation »). À l'inverse, détecter un blocage complet (par exemple la fermeture du port 25) est plus simple. Le sujet de la neutralité du réseau est, à juste titre, très chaud, et cette demande d'une mesure du phénomène restera sans doute élevée (cf. les règles du BEREC).

La section 5 de notre RFC se penche ensuite sur des détails pratiques dans la mise en œuvre de ces mesures. On va donc avoir N sondes qui font faire des mesures et un serveur central qui collectera les mesures (ce qui nécessitera un protocole de communication, de préférence sécurisé, entre les sondes et ce serveur). Les mesures seront répétées automatiquement et/ou pourront être activées à la demande (par exemple pour déboguer un problème précis). Une fois téléversés dans le serveur, les résultats des mesure devront être analysés (et ce sont parfois d'assez gros fichiers). L'analyse, quoique non couverte dans ce RFC, est également une source de risques. Comme dit l'adage « les chiffres, on leur fait dire ce qu'on veut ». Par exemple, le comité technique de l'ARCEP qui était chargé de superviser les décisions techniques pour le programme de mesure a eu à étudier des questions délicates comme la suppression de mesures aberrantes.

De nombreux choix pratiques vont ensuite se poser. Par exemple, la sonde active doit-elle être faite avec du matériel spécialisé (c'est le cas de SamKnows, de la mesure ARCEP, ou des RIPE Atlas) ou bien avec du logiciel que les utilisateurs téléchargeront (comme Grenouille ou Netalyzr). Ces sondes spécialisées sont plus coûteuses, compliquées à déployer (on ne peut pas en mettre partout, il faut des critères de sélection, etc) mais plus fiables que la machine de M. Michu, probablement bourrée de virus qui la ralentissent, et qui n'est pas forcément allumée en permanence. (Une autre différence vient du fait que la sonde spécialisée peut être branchée immédiatement après le routeur, s'épargnant ainsi d'utiliser un LAN peu fiable et irrégulier.) Dans les deux cas, il faudra se demander si l'échantillon est vraiment représentatif ou si l'auto-sélection plus ou moins grande des utilisateurs a trop biaisé les résultats.

Enfin, la section 7 de notre RFC se penche sur les problèmes de sécurité, notamment de protection de la vie privée (RFC 6973). Parmi les risques, si on crée une infrastructure de mesures actives, on a fabriqué un gentil botnet. Si un méchant peut en prendre le contrôle, il peut l'utiliser pour des attaques par déni de service réparties. (C'est une des raisons pour lesquelles l'exécution de mesures par les sondes Atlas, ouverte au public, est soumise à la dépense d'un certain nombre de crédits.) Toujours en cas de mesures actives, les sondes peuvent potentiellement balayer des réseaux internes qui ne seraient normalement pas accessibles de l'Internet (c'est pour cela que les Atlas ne peuvent pas tester les adresses du RFC 1918, car elles pourraient alors être utilisées pour la reconnaissance du réseau local où elles sont situées). Si les sondes ont des capacités de collecte passive, un méchant peut les utiliser comme « boîtes noires » d'espionnage des réseaux sur lesquels elles sont connectées. Il est donc nécessaire de ne pas fournir un accès illimité à ces sondes. Elle doivent n'être accessibles qu'à leur contrôleur, après authentification forte, et, si elle peuvent exécuter des mesures choisies par les utilisateurs (cas des sondes Atlas), ces mesures doivent être limitées (ainsi, les 1es Atlas ne peuvent pas lancer de téléchargement HTTP depuis un URL quelconque).

Dans le cas de mesures comparatives (« le FAI X est 20 % plus rapide que le FAI Y »), un autre risque de sécurité est celui de triche. Un attaquant qui contrôlerait, au moins partiellement, le système, risquerait de pouvoir fausser les résultats et favoriser un FAI par rapport aux autres. Là encore, de bonnes pratiques de sécurité sont nécessaires. Il y a enfin des attaques plus subtiles, comme d'identifier les lignes où des mesures sont faites, et les favoriser, obtenant ainsi de meilleurs résultats.


Téléchargez le RFC 7536


L'article seul

RFC 7525: Recommendations for Secure Use of TLS and DTLS

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : Y. Sheffer (Intuit), R. Holz (TUM), P. Saint-Andre (&yet)
Première rédaction de cet article le 6 mai 2015


Le protocole de sécurité TLS sécurise aujourd'hui, par la cryptographie, un grand nombre de communications par l'Internet. Le protocole et ses mises en œuvre dans des bibliothèques comme OpenSSL ont eu plusieurs failles, réparées au fur et à mesure. Mais les plus grosses failles restent dans l'utilisation pratique de TLS : programmeurs et administrateurs systèmes font des erreurs qui affaiblissent la sécurité de TLS. Ce RFC, le deuxième du groupe UTA (utilisation de TLS par les applications) résume les bonnes pratiques qui devraient être suivies en matière de sécurité pour que TLS atteigne complètement ses objectifs.

TLS est normalisé dans le RFC 5246. Ce RFC documente la version 1.2 et la 1.3 est en cours de normalisation. Il est surtout connu pour sa sécurisation de HTTP, nommée HTTPS. Mais il sert aussi pour sécuriser SMTP, XMPP, IMAP, etc. TLS lui-même ne marche que sur TCP mais il a un équivalent pour UDP, nommé DTLS, et normalisé dans le RFC 6347. Si un attaquant veut casser la protection qu'offre TLS (par exemple pour accéder au contenu en clair d'une communication normalement chiffrée), il peut viser (le RFC 7457 donne une bonne liste)  :

  • Le protocole lui-même. Ainsi, SSL v3, un précurseur de TLS, avait une faille de conception qui permettait l'attaque Poodle. Les failles du protocole, par définition, sont indépendantes d'une mise en œuvre particulière de TLS.
  • Les algorithmes cryptographiques utilisés. TLS a la propriété d'« agilité cryptographique » qui fait qu'il n'est pas lié à un algorithme particulier mais offre un choix. Cela permet, au fur et à mesure des progrès de la cryptanalyse, de changer d'algorithme. Par exemple, les algorithmes AES-CBC (RFC 3602) et RC4 (RFC 7465) ont tous les deux montré des faiblesses sérieuses, ce qui fait que leur utilisation dans TLS est découragée. La liste des algorithmes possibles dépend de la bibliothèque TLS utilisée mais aussi de la configuration du client et du serveur TLS. Pour retirer un algorithme désormais trop faible, comme RC4, on peut donc agir dans le logiciel (en retirant le code correspondant) ou dans la configuration, en supprimant l'algorithme de la liste acceptée.
  • TLS est mis en œuvre dans des bibliothèques logicielles qui, comme tous les logiciels, ont des bogues. Cette fois-ci la faille est spécifique à une mise en œuvre donnée et la correction est de mettre à jour le logiciel, une fois la version corrigée sortie. Ce fut le cas pour la faille Heartbleed, spécifique à OpenSSL, ou de la faille goto fail, spécifique à Apple.
  • Même si le protocole est parfait, n'utilisant que des algorithmes cryptographiques incassés, et programmé sans une bogue, des failles de sécurité peuvent quand même surgir si TLS est utilisé imprudemment. Par exemple, si une application utilise TLS en ayant débrayé (ou pas activé) la vérification du certificat, TLS peut être contourné via une attaque de l'Homme du Milieu. L'article « The most dangerous code in the world: validating SSL certificates in non-browser software » en donne plusieurs exemples.

Bref, l'analyse de sécurité de TLS est complexe et on voit pourquoi il faut se méfier comme de la peste des résumés journalistiques qui annoncent une faille TLS alors qu'il ne s'agissait que d'une bogue dans une bibliothèque.

Le RFC 7457 décrivait déjà les failles, avec plein d'exemples. Notre nouveau RFC se concentre sur les recommandations. Il définit un plancher de sécurité (pas un plafond : on peut toujours être plus strict que ce que définit le RFC). D'autre part, le RFC prévient évidemment que ces recommandations évolueront avec le temps.

Le cœur de notre RFC n'est donc pas l'analyse des risques, mais les recommandations pratiques (sections 3 et suivantes). D'abord, sur la version du protocole :

  • Ne jamais utiliser SSL, que ce soit la v2 (RFC 6176) ou la v3. Décrite dans le RFC 6101, cette dernière a encore bien trop de trous (comme celui qui permet POODLE) et ne gère pas des extensions essentielles à la sécurité comme celle du RFC 5746.
  • N'utiliser TLS 1.0 (RFC 2246) que si on n'a pas le choix. Publié il y a seize ans (!), il n'accepte pas certains algorithmes de cryptographie moderne, il n'avertit pas en cas de certaines erreurs de remplissage avec des zéros (ce qui permet des attaques ressemblant à POODLE) et il a encore d'autres faiblesses.
  • TLS 1.2 doit être privilégié. Notons que les algorithmes cryptographiques recommandés dans notre RFC ne sont disponibles qu'avec cette version 1.2.

Si un client TLS a un mécanisme de repli (on tente de se connecter avec la version N, ça échoue, on ré-essaie avec N-1, ce qui se nomme la downgrade dance), on ne doit jamais se replier vers SSL. Autrement, un Homme du Milieu aurait juste à faire échouer la connexion initiale, pour garantir l'utilisation d'un protocole faible (notez que le RFC 7507 fournit une solution contre ce repli). Aux dernières nouvelles, seuls 3 % des serveurs Web TLS/SSL de l'Internet étaient SSL-seulement.

Lorsque client et serveur essaient de se connecter avec TLS mais acceptent des connexions sans TLS, des attaques actives peuvent forcer un repli vers la connexion sans TLS, en clair et pas sécurisée du tout (la négociation de TLS n'est pas elle-même protégée par TLS). Pour éviter cela, client et serveur devraient insister sur l'utilisation de TLS et utiliser des techniques comme HSTS (RFC 6797) pour signaler qu'on sait faire du TLS et qu'il ne faut pas essayer en clair.

Plusieurs attaques sont facilitées par l'utilisation de la compression (RFC 5246, section 6.2.2), comme CRIME. Il est recommandé de la couper, sauf si on est sûr que le protocole applicatif qui utilise TLS n'est pas vulnérable à ces attaques.

L'établissement d'une session TLS nécessite d'échanger plusieurs paquets, ce qui prend du temps. Pour limiter ce problème, TLS dispose d'un mécanisme de reprise de session (RFC 5246). Ce mécanisme doit être autant protégé que le serait une session normale. Par exemple, dans le cas du RFC 5077, si on chiffrait le ticket utilisé pour la reprise de session avec un algorithme bien plus faible que celui utilisé dans la session elle-même, un attaquant pourrait choisir de tenter une « reprise » d'une session inexistante, court-circuitant ainsi l'authentification. À noter aussi que ce mécanisme de reprise de session peut annuler l'effet de la forward secrecy : si l'attaquant met la main sur les tickets, il peut déchiffrer les sessions qu'il a enregistré (cf. section 7.3 de notre RFC). Il faut donc changer ces tickets de temps en temps.

L'extension de renégociation sécurisée du RFC 5746 doit être disponible (ou, sinon, il faut couper la renégociation).

Une dernière recommandation générale porte sur SNI (RFC 6066, section 3). Bien que cela n'affecte pas directement la sécurité, cette extension est recommandée, pour des protocoles comme HTTPS, car elle permet des politiques de sécurité plus souples et donc plus implémentables (comme d'avoir un certificat par site Web).

La section 3 de notre RFC portait sur des recommandations générales. La section 4 s'attaque aux algorithmes de cryptographie (cipher suites). Ceux-ci s'usent avec le temps, quand les progrès de la cryptanalyse exposent leurs failles. Cette usure se fait à un rythme très variable : certains algorithmes durent depuis longtemps, d'autres ont été éliminés rapidement. Mais aucun algorithme n'est éternel et voilà pourquoi il est nécessaire de séparer le protocole des algorithmes, ce qu'on nomme l'« agilité cryptographique ». Notre RFC recommande donc de ne pas utiliser l'algorithme NULL, qui ne chiffre pas du tout (pas besoin de cryptanalyse pour le casser...) et n'a d'intérêt que pour les tests et le déboguage. Plus récemment, les progrès de la cryptanalyse, documentés dans le RFC 7465, ont montré que RC4 ne devait pas être utilisé non plus. Le problème des algorithmes trop faibles est aggravé par l'action des États qui veulent pouvoir espionner les communications et qui imposent, dans certains cas, l'utilisation d'algorithmes dont les faiblesses sont connues. C'est le cas aux États-Unis des algorithmes dit export (car ils étaient les seuls légalement exportables à une époque). Si ces algorithmes sont présents, l'attaque FREAK permettra à un attaquant actif de les sélectionner, flanquant en l'air toute la sécurité de TLS.

Les révélations de Snowden ont montré que la NSA (et peut-être d'autres organisations) enregistre de nombreuses communications chiffrées qu'elle ne sait pas décrypter. L'idée est que si, un jour, on met la main sur la clé privée (par perquisition physique, piratage de l'ordinateur à distance ou tout autre méthode), on pourra alors déchiffrer et certaines de ces communications seront encore intéressantes. Pour éviter cela, notre RFC conseille de privilégier les algorithmes qui mettent en œuvre la forward secrecy comme la famille DHE.

Quels algorithmes restent-ils après ces nombreuses éliminations ? Notre RFC en mentionne quatre (après une discussion longue et acharnée à l'IETF) : TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 et TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384. Ils utilisent DHE ou ECDHE, avec RSA, AES en mode GCM (voir RFC 5288 section 6, sur la sécurité de ce mode) et SHA-2. Ils font tous du chiffrement intègre (authenticated encryption, RFC 5116). Tout logiciel TLS devrait être configuré pour préferer ces algorithmes (cf. « Applied Crypto Hardening »).

Attention, notre RFC parle uniquement de préférer ces algorithmes, pas de les imposer. Pour permettre l'interopérabilité, TLS a en effet des algorithmes obligatoires, qui doivent être mis en œuvre dans chaque bibliothèque TLS. C'est le cas de TLS_RSA_WITH_AES_128_CBC_SHA, obligatoire mais pas le plus fort, loin de là. Ces algorithmes, sur lesquels on peut toujours compter (contrairement aux quatre cités plus haut, qui peuvent ne pas être présents). Il peut donc être nécessaire d'arbitrer entre interopérabilité et sécurité...

Ce RFC a également des recommandations sur les clés publiques utilisées dans les certificats : 2 048 bits au moins en RSA (ce qui est imposé par la plupart des AC depuis un certain temps, c'est le cas de CAcert, par exemple), et SHA-256 pour condenser la clé (et plus SHA-1).

Un petit mot en passant sur un point abordé dans la section 5. Celle-ci concerne l'« applicabilité » des recommandations faites ici. Cette applicabilité est très large, quasiment tous les usages de TLS sont concernés. Il existe un usage fréquent de TLS, parfois appelé « chiffrement opportuniste » (RFC 7435) où une des parties qui communiquent va essayer de faire du TLS mais, si cela ne marche pas (par exemple parce que l'autre partie ne gère pas le chiffrement), on se rabat sur une communication en clair. Dans ce contexte, certaines des recommandations du RFC peuvent être trop strictes. Par exemple, on a vu qu'il ne fallait pas utiliser RC4, trop faible cryptographiquement. Si on prend au pied de la lettre cette recommandation, qu'une des deux parties ne connait que RC4 et qu'on est dans un contexte de chiffrement opportuniste, on pourrait arriver à ce résultat paradoxal que, RC4 étant refusé, on communique en clair, ce qui est certainement bien pire que le plus mauvais des algorithmes de cryptographie. Il peut donc être nécessaire de dévier des recommandations de notre RFC 7525.

Enfin, pour terminer ce RFC déjà riche, une section 6 consacrée à divers problèmes de sécurité qui n'avaient pas été traités avant. D'abord, la nécessité, lorsqu'on vérifie un certificat, de vérifier également que le nom du serveur, dans le certificat, corespond au nom auquel on voulait se connecter. Cela parait évident mais ce n'est pas toujours fait par la bibliothèque qu'on utilise (cf. mon exposé à Devoxx - et ses transparents - pour des exemples.) Il peut donc être utile que l'application fasse la validation elle-même, sans quoi un attaquant actif peut détourner le trafic chiffré, de manière triviale. La section 3 du RFC 2818 et le RFC 6125 détaillent ce qu'il faut exactement valider. Bien sûr, pour que cette validation ait un sens, il faut que le nom du serveur ait lui-même été obtenu de manière sûre. Si on a cliqué sur un lien https://... dans un message de hameçonnage, vérifier que le nom est correct n'aide pas tellement (« oui, c'est bien secure-serious-bank.ab451e239f.ru »). Idem si le nom vient d'une requête DNS (par exemple de type MX) non sécurisée par DNSSEC.

J'ai déjà parlé plus haut de la forward secrecy, une propriété qui fait que le vol des clés privées a posteriori est inutile, même pour un attaquant qui avait enregistré les communications chiffrées. Dans la vie, ce vol peut arriver pour des tas de raisons, machines jetées à la poubelle sans les avoir effacées, et récupérées par un indiscret, clés trop faibles face à la force brute (cf. « Mining Your Ps and Qs: Detection of Widespread Weak Keys in Network Devices »), clé générée par un tiers (dans le « cloud ») et ensuite obtenue par piratage, attaque violente et/ou légale contre les administrateurs système pour obtenir la clé, et toutes les autres méthodes d'accès aux clés privées qui peuvent exister. La forward secrecy n'empêche pas ces attaques mais elle empêche l'attaquant d'exploiter son succès. Elle s'obtient en général en faisant un échange Diffie-Hellman. Dans le contexte de la sécurité de TLS, le principal problème est que beaucoup d'algorithmes utilisés ne permettent pas le forward secrecy, et que les autres, les bons, ne sont pas sélectionnés en priorité.

L'authentification du serveur TLS (on peut aussi authentifier le client mais c'est plus rare) repose presque toujours sur un certificat X.509. Si la clé privée associée au certificat est volée, le mécanisme de sécurité de X.509 est la révocation (RFC 5280, section 3.3). On sait que ce mécanisme nécessite une bonne connexion Internet, et est peu fiable : les listes de certificats révoqués, à distribuer partout, ne passent pas à l'échelle, le protocole OCSP (RFC 6960) est souvent bloqué (et il pose de toute façon des problèmes de passage à l'échelle et de vie privée), menant les clients à ignorer les échecs OCSP, etc. Il existe des solutions partielles (section 8 du RFC 6066, RFC 6961, RFC 6698) mais pas assez déployées.

Si vous voulez lire des recommandations en français sur la configuration de TLS, il y a deux guides ANSSI qui sont en rapport avec ce RFC, le RGS pour les algorithmes de cryptographie, et le guide pour la sécurité des sites Web, avec des recommandations précises pour OpenSSL (SSLCipherSuites Apache).

Et pour terminer sur une note personnelle, si vous regardez la configuration HTTPS de mon blog, elle est actuellement perturbée par deux sérieuses bogues du module GnuTLS d'Apache : #754960 et #642357.


Téléchargez le RFC 7525


L'article seul

RFC 7542: The Network Access Identifier

Date de publication du RFC : Mai 2015
Auteur(s) du RFC : DeKok, Alan (FreeRADIUS)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF radext
Première rédaction de cet article le 2 mai 2015


Ce nouveau RFC normalise le concept d'identificateur pour l'accès au réseau (NAI pour Network Access Identifier). Cet identificateur est traditionnellement utilisé lors d'un accès authentifié au réseau, pour indiquer la personne ou l'entité qui veut se connecter (avec un mot de passe, ou autre information de créance, pour s'authentifier). Le NAI a une forme qui ressemble aux adresses de courrier ou XMPP. Par exemple, un NAI peut être marie@example.com ou jean_dupont@labs.potamochère.fr. Contrairement au traditionnel login ou nom d'utilisateur, le NAI inclut l'indication d'un domaine (ou plutôt royaume) d'origine, permettant au point d'accès d'accepter des utilisateurs issus d'un autre domaine. Le NAI permet donc des accès fédérés. Ce concept, en dépit de ce nom, est désormais utilisé pour bien d'autres choses que l'accès au réseau. Notre RFC remplace la norme précédente, le RFC 4282, notamment en développant bien plus l'internationalisation (un NAI n'est pas forcément en ASCII). Bienvenue dans le monde merveilleux (et très bordélique) du AAA.

Initialement, la principale motivation pour le NAI (Network Access Identifier) était le roaming : un utilisateur abonné au FAI X se déplace dans une zone où X ne fournit pas d'accès mais a un accord avec le FAI Y qui, lui, est présent. Pour éviter de recopier la base d'utilisateurs de X dans celle de Y, l'utilisateur présente un NAI qui indique son rattachement à X (son home domain). Le point d'accès de Y sait alors qu'il doit demander l'authentification à X. Une fois que c'est fait, on peut donner l'accès via Y (le visited domain). C'est par exemple ainsi que fonctionne la fédération Eduroam. (L'auteur du RFC est d'ailleurs l'auteur et le mainteneur de FreeRADIUS, un des logiciels les plus utilisés pour cette tâche. Le protocole RADIUS est normalisé dans le RFC 2865.)

Le NAI permet donc à des FAI purement régionaux d'accueillir des clients d'autres régions du pays, à des FAI nationaux d'accueillir des clients d'autres pays, à des hotspots WiFi de servir plusieurs FAI avec la même infrastructure, etc. Une description de l'usage des NAI dans des situations de roaming est donné dans le RFC 2194.

On l'a vu, le NAI peut servir à bien d'autres choses que l'accès au réseau. Sa définition est donc indépendante du protocole qui va l'utiliser (le NAI n'est pas spécifique à RADIUS.) Par contre, son encodage effectif dépendra du protocole (par exemple, il faudra assurer l'échappement de certains caractères, le NAI sophie@internautique.fr deviendra sophie@internautique%2Efr dans un URL). À noter que le NAI, quoique répandu, n'est pas le format unique d'identificateur sur le réseau. Certains protocoles existants ont un autre format, et certains permettent le NAI et d'autres formats. Pour les protocoles futurs, notre RFC recommande qu'ils adoptent le NAI, pour uniformiser les identificateurs. C'est déjà le cas de 3GPP dont la norme « TS 23.003 Numbering, addressing, and Identification (Release 12) » précise que l'identificateur est un NAI comme 234150999999999@ims.mnc015.mcc234.3gppnetwork.org.

Attention, le but est d'uniformiser le format, pas les identificateurs. Le NAI n'implique pas que chaque utilisateur ait un identificateur et un seul ! Cela poserait, entre autres, de sérieux problèmes liés à la vie privée. Le RFC recommande d'ailleurs de permettre des identificateurs anonymes (pseudonymes, plutôt) dès qu'ils sont visibles publiquement.

Un peu de terminologie nécessaire pour comprendre le NAI figure en section 1.1. Notez le NAS (Network Access Server) qui est la première machine à laquelle les utilisateurs se connectent pour avoir un accès à l'Internet. Pour les technologies PPTP et L2TP, ce sera le concentrateur d'accès. En WiFi, ce sera le point d'accès (hotspot). Lorsque l'utilisateur envoie son NAI, c'est le NAS qui extrait le domaine de l'utilisateur et relaie (par exemple en RADIUS) la demande d'authentification à ce domaine.

Une bonne partie des changements depuis le RFC 4282 avait été motivé par l'expérience d'Eduroam. Par exemple, la section 2.1 du RFC 4282 demandait que le nom de domaine soit uniquement composé de lettres ASCII, de chiffres et de tirets. Pour les IDN, l'idée était d'utiliser la forme Punycode. Celle-ci est peu pratique, et souvent inutile puisque plusieurs protocoles utilisant les NAI (comme RADIUS ou comme l'EAP du RFC 3748) ne sont pas limités à l'ASCII et recommandent UTF-8 comme encodage des chaînes de caractères (cf. section 3.2). Le RFC 4282 avait d'autres problèmes d'internationalisation comme d'exiger une normalisation des chaînes (qui peut rentrer en conflit avec des exigences locales) ou comme d'exiger des opérations qui soient dépendantes de la langue (que le NAS et autres équipements intermédiaires ne connaissent pas forcément, et ne savent pas toujours gérer). D'autre part, le RFC 4282 interdisait l'utilisation de points de code Unicode non affectés. Cela empêchait le déploiement de toute nouvelle écriture puisque, au début, tous les équipements réseau auraient considéré ces nouveaux caractères comme non affectés ! En pratique, d'ailleurs, aucun équipement réseau n'a mis en œuvre les recommandations d'internationalisation du RFC 4282. Le roaming international se développant, il était temps de changer ces recommandations irréalistes.

La section 2 de notre RFC présente la définition formelle du NAI. Il est en UTF-8, normalisé NFC. Il est divisé en deux parties, le nom d'utilisateur, et le royaume (realm). Ces deux parties sont séparées par un @. Le nom d'utilisateur peut être composée de lettres (Unicode, pas uniquement ASCII), de chiffres et de quelques symboles. fred=?#$&*+-/^smith est donc un nom d'utilisateur valable. Le royaume ressemble à un nom de domaine, avec ses composants séparés par des points mais n'en est pas forcément un. Un exemple de NAI est donc eng%geneviève@example.neteng%geneviève est le nom d'utilisateur et le domaine (royaume) est example.net. (La grammaire formelle est en section 2.2.) Un nom de royaume ne doit pas être réduit à un seul composant donc maire@paris n'est pas un NAI même si le TLD .paris existe. En effet, certains équipements considèrent qu'un royaume d'un seul composant est un sous-royaume du royaume local (donc, chez le FAI example.net, le NAI maire@paris serait interprété maire@paris.example.net).

Le royaume peut être en Unicode, bien des protocoles AAA autorisent à la transporter nativement et il est donc désormais déconseillé d'encoder en Punycode (RFC 3492). Ainsi, le NAI faïza@café.example s'écrit bien ainsi, et pas faïza@xn--caf-dma.example. (Il semble bien que c'est ce que faisaient déjà tous les équipements qui géraient des noms de royaumes en Unicode, malgré ce que disait le RFC 4282.)

Il n'y a pas de limite de taille aux NAI, juste la recommandation de pouvoir gérer au moins 72 octets et, de préférence, 253. (Attention, en UTF-8, un caractère ne fait pas forcément un octet.) Les NAI étant utilisés dans des protocoles très différents, on a parfois des surprises. Ainsi, l'attribut User-Name de RADIUS exige d'accepter jusqu'à 63 octets mais ne dit rien au delà (RFC 2865, section 5.1). En revanche, le protocole concurrent Diameter (RFC 6733) impose à ses mises en œuvre des noms d'utilisateur jusqu'à 16 777 207 octets. Si on est sûr de toujours passer par Diameter (ce qui est très peu probable), on peut utiliser des NAI très longs.

Le nom d'utilisateur est opaque aux autres royaumes (comme pour le courrier électronique même si beaucoup d'ignorants violent cette règle). Par exemple, dans le eng%geneviève@example.net donné plus haut, on peut soupçonner que le nom d'utilisateur indique un routage interne (vers le service d'ingéniérie puis vers l'utilisatrice Geneviève) mais on ne peut pas en être sûr, chaque royaume a ses propres règles. On doit donc traiter le nom d'utilisateur comme un tout, sauf si on est le home domain. Parfois, des protocoles transmettent juste le nom de royaume, faisant passer le nom d'utilisateur dans un canal plus sûr, afin de préserver la vie privée (cf. le TTLS du RFC 5281). L'habitude dans ce cas est de remplacer le nom d'utilisateur par anonymous mais c'est désormais déconseillé, il vaut mieux un nom vide (@internautique.fr est donc un NAI valide). Avec les autres protocoles, notre RFC recommande d'utiliser des noms d'utilisateurs éphémères, pour la vie privée, mais c'est très rarement le cas aujourd'hui.

On a vu qu'on pouvait utiliser des caractères Unicode aussi bien pour le nom de royaume que pour celui de l'utilisateur. Pour les noms d'utilisateur, les règles se basent sur celles du RFC 6532. Pour le nom de royaume, on est restreint aux caractères utilisables dans un nom de domaine (RFC 5891). L'éventuelle traduction en UTF-8 (au cas où l'utilisateur ait rentré des caractères dans un autre encodage) et la normalisation en NFC doivent être faites au tout début, lorsqu'on est encore proche de l'utilisateur et qu'on sait ce qu'il veut (on connait sa langue, par exemple, ce qui n'est pas le cas des équipements réseau intermédiaires ; ces équipements intermédiaires ont tout intérêt à ne pas tripoter les NAI). Ceci dit, cette situation idéale (les terminaux normalisent, les intermédiaires ne changent rien) n'est pas respectée aujourd'hui. Il existe des terminaux qui ne normalisent pas, injectant ainsi des chaînes non-UTF8 dans le système d'authentification. Le RFC note donc que le principe « les terminaux normalisent, les intermédiaires ne changent rien » doit parfois être violé. « The suggestion in the above sentence contradicts the suggestion in the previous section. This is the reality of imperfect protocols. » Ce point a été l'un des plus disputés lors de l'écriture de ce RFC.

Une fois le NAI défini, notre RFC s'attaque au routage des requêtes (section 3). Typiquement, le système d'authentification et autorisation (AAA) extrait le royaume du NAI et s'en sert comme clé pour une table où sont stockés les royaumes qu'on connait et avec qui on a une relation d'acceptation de leurs utilisateurs. Si le royaume n'est pas trouvé dans la table, on refuse l'utilisateur. S'il est trouvé, le contenu de la table nous dira le serveur à interroger pour ce royaume (ainsi que des informations comme le secret partagé RADIUS, le port, etc). Attention, la sémantique des noms de royaume n'est pas forcément connue et, par exemple, les équipements réseau ne savent pas si on peut les consulter de manière insensible à la casse. Parfois, ça marche (rappelez-vous le paragraphe précédent : le monde de l'AAA est imparfait...) Si on ne trouve pas un nom de royaume dans la table, on peut router sur une partie du royaume, par exemple utiliser example.net si le royaume france.example.net n'a pas été trouvé. Attention, ce n'est valable que si le nom raccourci reste un nom valide (net ne le serait pas, vu la prohibition des noms d'un seul composant).

Les NAI ressemblent aux adresses de courrier électronique et certaines normes sont communes aux deux (comme le RFC 6532) mais attention, les règles ne sont pas exactement les mêmes. Toute adresse de courrier n'est donc pas forcément un NAI valide. En pratique, les deux se ressemblent suffisamment pour que beaucoup de FAI utilisent l'adresse de courrier du client comme son NAI.

On a vu que l'AAA était un monde très riche, ancien, et qui contient donc plein de choses surprenantes et de traditions historiques. La section 3.3.1 contient quelques exemples rigolos, avec les recommandations actuelles. Par exemple, les utilisateurs de RADIUS ont longtemps utilisé du routage explicite, où une partie du NAI contenait d'autres instructions de routage (chezmoi.example!utilisateur@fai.example...). Cette méthode (citée par le RFC 4282, section 2.7) s'est avérée très fragile, cassant dès qu'on change le réseau. RADIUS n'ayant pas de protocole de routage (qui diffuserait automatiquement les informations de routage), il fallait informer beaucoup de systèmes en cas de changement. (Diameter - RFC 5729 - ou 3G sont des cas différents car ils utilisent un protocole de routage.)

Le NAI étant en général utilisé dans un contexte de sécurité (point d'entrée pour une authentification), notre RFC consacre une section, la 4, à ces problèmes. Par exemple, si le protocole transporte le nom d'utilisateur en clair (c'est le cas de RADIUS), un écoutant sur le trajet peut apprendre des noms d'utilisateurs existants. Pour empêcher cela, il faut protéger (RADIUS avec IPsec, RFC 3579, Diameter avec TLS, RFC 6733). Si on utilise plusieurs protocoles qui tous se servent de NAI, et que l'utilisateur n'a qu'un seul NAI, un observateur pourra relier entre elles ces différentes utilisations. D'où l'intérêt de ne pas transporter les NAI en clair. Dans le futur, il serait encore mieux d'avoir des NAI éphémères, changés de temps en temps.

Le monde de l'accès réseau étant compliqué, il y a également des risques liés au fait qu'un identificateur peut être interprété d'une façon par un protocole et d'une autre façon par un autre protocole.

Dernier problème des NAI à régler, celui de l'avitaillement (création, maintenance, suppression) des identificateurs. Les noms de royaumes ressemblent à des noms de domaine pour éviter d'avoir à créer une nouvelle infrastructure d'avitaillement. Ainsi, si on est déjà titulaire du domaine lesrépublicains.fr, on n'a pas besoin d'autre chose pour créer des NAI comme nicolas@lesrépublicains.fr, tout en étant sûr de leur unicité, sur laquelle repose le routage. Bien qu'on puisse toujours, techniquement parlant, prendre un nom, sans l'enregistrer comme nom de domaine, pour faire des NAI, cette pratique est interdite. Par contre, l'usage du DNS n'est pas obligatoire et ces noms n'ont donc pas besoin d'être publiés. Si Diameter permet d'utiliser le DNS pour localiser un serveur d'authentification, les autres protocoles n'ont pas forcément cette possibilité : RADIUS repose sur des configurations statiques.

L'annexe A résume les (importants) changements depuis le RFC 4282, notamment :

  • UTF-8 autorisé dans le nom de royaume,
  • Abandon de Punycode.

Ces deux changements sont déjà largement déployés dans les équipements qui gèrent des NAI en Unicode.


Téléchargez le RFC 7542


L'article seul

Assez des URL spécifiques pour les clients « mobiles »

Première rédaction de cet article le 28 avril 2015


Un certain nombre de sites Web (pas tous, heureusement) redirigent les clients qui semblent être des appareils mobiles vers un autre URL, spécifique aux mobiles. C'est une très mauvaise idée.

En général, la redirection se fait dès que le serveur Web croit, à tort ou à raison, qu'il voit passer un appareil mobile, par exemple un phono sapiens. On peut le voir avec wget, en faisant varier le champ HTTP User-Agent: (RFC 7231, section 5.5.3) :

% wget --user-agent="Mozilla/5.0 (Android; Mobile; rv:37.0) Gecko/37.0 Firefox/37.0" http://fr.wikipedia.org/wiki/Virgule_d%27exclamation 
--2015-04-27 17:29:04--  http://fr.wikipedia.org/wiki/Virgule_d%27exclamation
Resolving fr.wikipedia.org (fr.wikipedia.org)... 91.198.174.192, 2620:0:862:ed1a::1
Connecting to fr.wikipedia.org (fr.wikipedia.org)|91.198.174.192|:80... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://fr.m.wikipedia.org/wiki/Virgule_d%27exclamation [following]
--2015-04-27 17:29:04--  http://fr.m.wikipedia.org/wiki/Virgule_d%27exclamation
Resolving fr.m.wikipedia.org (fr.m.wikipedia.org)... 91.198.174.204, 2620:0:862:ed1a::1:c
Connecting to fr.m.wikipedia.org (fr.m.wikipedia.org)|91.198.174.204|:80... connected.
HTTP request sent, awaiting response... 200 OK
...

On a été redirigé (code de réponse 302, RFC 7231, section 6.4) depuis le bon URL http://fr.wikipedia.org/wiki/Virgule_d%27exclamation vers http://fr.m.wikipedia.org/wiki/Virgule_d%27exclamation (le composant m dans le nom de domaine indiquant une version pour mobile). Avec un User-Agent: qui n'indiquait pas un mobile, on n'était pas redirigé :

% wget --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0 Iceweasel/31.6.0" http://fr.wikipedia.org/wiki/Virgule_d%27exclamation
--2015-04-27 17:28:31--  http://fr.wikipedia.org/wiki/Virgule_d%27exclamation
Resolving fr.wikipedia.org (fr.wikipedia.org)... 91.198.174.192, 2620:0:862:ed1a::1
Connecting to fr.wikipedia.org (fr.wikipedia.org)|91.198.174.192|:80... connected.
HTTP request sent, awaiting response... 200 OK
...

On trouve de telles redirections dans Wikipédia mais aussi les Échos, Rue89, etc.

Ces URL sont utilisés pour transmettre un contenu différent selon les clients. Les problèmes que posent ces URL spécifiques aux mobiles sont les suivants :

  • Ils violent un principe de base du Web, qui est que l'URL est la même pour tout le monde, afin qu'on puisse la transmettre, la passer à quelqu'un d'autre, et que l'affichage suive automatiquement. Le Web a été conçu pour cela. Il n'y a aucune bonne raison technique de faire du contenu spécifique pour mobile.
  • Il n'y a pas un seul type de « mobile » mais des tas de modèles, avec notamment des tailles d'écran très différentes. Même si on pense qu'il faut des contenus différents selon les machines, ces URL spécifiques ne dispensent donc pas le webmestre d'adapter le contenu à chaque écran.
  • Ces URL empêchent d'utiliser une des fonctions de base du Web, passer un URL d'un utilisateur à l'autre (par XMPP, courrier, Twitter, etc). En effet, si je consulte un site sur un smartphone, que je l'envoie en XMPP et que le destinataire est sur un ordinateur de bureau, il verra une version inadaptée. (Rue89 redirige depuis le site mobile vers le site « immobile », mais Wikipédia ne le fait pas.)
  • Si on stocke les URL dans une base de données, à des fins de documentation ou de constitution d'une base de connaissances, on aura des doublons puisque le système croira qu'il s'agit de deux ressources différentes. Ainsi, SeenThis affiche un joli petit triangle noir devant chaque URL qui a déjà été cité mais il ne peut plus le faire si on utilise l'URL « mobile » et l'URL « normal » pour la même ressource.
  • La redirection nécessite une nouvelle connexion TCP et une nouvelle requête, donc augmente la latence, alors que les mobiles ont justement souvent la plus mauvaise connexion.

Est-ce qu'au moins on peut corriger à la main l'URL qu'on voulait partager ou enregister ? Chez Wikipédia, c'est relativement facile, le schéma est évident. On retire juste le composant m du nom de domaine, et http://fr.m.wikipedia.org/wiki/Potamoch%C3%A8re redevient http://fr.wikipedia.org/wiki/Potamoch%C3%A8re. Par contre, Rue89 utilise des URL radicalement différents (http://m.rue89.nouvelobs.com/node/257496 est http://rue89.nouvelobs.com/2015/04/23/deconnectes-mal-connectes-les-pauvres-numerique-257496, excellent article, au passage) et empêche donc cette réécriture.

Terminons par un argument d'autorité avec deux excellents textes du W3C contre cette idée d'URL spécifiques aux mobiles. Ces deux articles ont été écrits dans le contexte du TLD .mobi (un échec complet et mérité) : « The ".mobi" Proposal is Inconsistent with Device Independence Principles » et « New Top Level Domains .mobi and .xxx Considered Harmful » (qui couvre en outre bien d'autres sujets et est donc plus difficile à utiliser pour ce problème des URL pour mobiles).

Et si vous voulez un point de vue différent sur ce sujet, il y a cette réflexion.


L'article seul

Qui est le numéro 1 de l'Internet ?

Première rédaction de cet article le 27 avril 2015


Le 23 avril dernier, le gouvernement français annonce qu'il a rencontré « les dirigeants d'internet ». Cela a, à juste titre, beaucoup fait rire, mais pas toujours pour de bonnes raisons. C'est que c'est compliqué de savoir qui dirige (ou pas) l'Internet.

Le communiqué du gouvernement français est en ligne mais a été modifié depuis. Le texte original disait « le Gouvernement mobilise les dirigeants d'internet » et la version modifiée suite aux rires des internautes dit « le Gouvernement mobilise les dirigeants des grands opérateurs de l'internet ». Notez que l'URL, qui reprend le titre du communiqué, n'a pas changé. C'est bien de ne pas l'avoir changé mais, désormais, le titre et l'URL ne sont plus en accord (voilà pourquoi il faut éviter de mettre trop de sémantique dans les URL).

Il y a bien des choses à critiquer dans le communiqué du gouvernement, notamment le ridicule des mouvements martiaux du menton (« le Gouvernement mobilise... ») ou surtout la gravissime faute qu'est la sous-traitance de la censure à des entreprises privées, plus soucieuses d'éviter les problèmes que de défendre la liberté d'expression. Mais les nombreuses critiques du communiqué gouvernemental se sont surtout focalisées sur le titre, comme celle de Numérama. Ce journal constate à juste titre qu'il est ridicule de parler des « dirigeants d'Internet » (et le gouvernement français doit être de cet avis puisqu'il a modifié son texte irréfléchi) car la gouvernance de l'Internet est complexe et ne se réduit pas à une poignée de « dirigeants ».

L'erreur n'est pas innocente, de la part du gouvernement. Celui-ci est en effet complètement perdu devant le mécanisme complexe qu'est l'Internet. Comme le héros du Prisonnier, les ministres passent leur temps à demander « qui est le numéro 1 ? » Ils ne peuvent en effet pas imaginer d'autres systèmes politiques que ce qu'ils ont appris à Sciences Po : un système très hiérarchique, avec une poignée d'acteurs (publics ou privés, peu importe pour eux), quelques dirigeants régnant sur une masse de « fond d'organigramme ». Rien d'étonnant que, perturbés par l'Internet, ils cherchent à toute force à le ramener au seul cas qu'ils connaissent, celui où on discute dans des bureaux feutrés, loin des rumeurs du monde, avec quelques messieurs « responsables ». Numérama a raison de pointer du doigt cette curieuse réduction de l'Internet à « Google, Facebook, Microsoft, Apple et Twitter mais aussi des responsables des principaux fournisseurs d'accès à Internet (dont les membres de l'association des fournisseurs d'accès et de services Internet comme Orange, Bouygues Telecom, SFR) ». Pourquoi ces entreprises privées particulières, et qui a décidé de leur confier l'Internet ? Personne, et surtout pas un processus démocratique. Mais ces entreprises sont toutes prêtes à suivre la voie de la censure privée (Facebook s'y est engagé depuis très longtemps). En façade, les politiciens français aiment se plaindre des GAFA (Google, Apple, Facebook, Amazon), mais ils sont très à l'aise avec cet oligopole de (pour citer Numérama) « gigantesques silos contenant des quantités inouïes de données personnelles, pour le plus grand bonheur des services de renseignement ». Bien plus à l'aise en tout cas qu'avec les millions d'acteurs de l'Internet qui le façonnent au quotidien. Il suffit de voir comment les politiciens français font tout pour détruire les échanges de contenu en pair à pair, encourageant ainsi les utilisateurs à se servir uniquement de quelques gros silos, avec lesquels on pourra ensuite parler.

Mais, si le gouvernement a tort de désigner les GAFA et les telcos comme « dirigeants d'Internet », qui sont alors les vrais dirigeants ? Numérama dérape ici en reprenant le jargon inimitable de l'ICANN et en prétendant que l'Internet serait géré par tout le monde, avec une très large participation. Ce serait en effet idéal mais, contrairement à ce que prétend l'ICANN pour essayer de faire oublier sa très faible légitimité, ce n'est pas le cas. Des entreprises comme les gros telcos, ou comme les GAFA, ont effectivement un pouvoir disproportionné. Si le terme de « dirigeants d'Internet » est exagéré, on ne peut pourtant pas nier, et c'est un gros problème de gouvernance en soi, que l'excessive concentration des échanges dans quelques silos (encouragée, comme on l'a vu, par les gouvernements successifs, que le pair à pair hérisse), entraine forcément un excès de pouvoir chez ces silos.

Et Numérama se contredit ensuite en prétendant avoir trouvé les vrais dirigeants : « ce n'est pas en direction des "GAFA" qu'il fallait se tourner, mais plutôt vers l'ICANN, le forum sur la gouvernance d'Internet (IGF), l'Internet Engineering Task Force (IETF), l'Internet Research Task Force (IRTF), l'Internet Society (ISOC), les registres Internet régionaux, l'ISO 3166 MA (Autorité de Maintenance), le W3C ou encore l'Internet Architecture Board (IAB), les forums de rencontre des opérateurs ainsi que les agences intergouvernementales ». À quelques exceptions près comme les « forums de rencontre des opérateurs », cette liste fait la part belle à des institutions clairement identifiables, justement ce que voudraient Cazeneuve et ses pareils. D'ailleurs, la liste tient du catalogue de Prévert en mêlant des organisations ayant un vrai pouvoir (RIR, ICANN, ISOC), des simples forums de bavardage (IGF), des organisations aux pouvoirs purement techniques et limités (IETF) et de mystérieuses « agences intergouvernementales » (on penserait à l'UIT si elle jouait le moindre rôle dans la gouvernance d'Internet).

Bref, il faut s'y résigner, la gouvernance de l'Internet est complexe, il n'y a pas de numéro 1 (dommage pour les ministres français), mais il n'y a pas non plus de « processus ouverts, bottom->up et multipartiesprenantes », quoi que prétende l'ICANN. Il y a beaucoup d'acteurs, avec des rôles variés et des pouvoirs très différents. Ça le rend difficile à gouverner ? Tant mieux, c'est aussi ce qui assure sa résilience face aux tentatives de contrôle.


L'article seul

RFC 7507: TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : B. Moeller, A. Langley (Google)
Chemin des normes
Réalisé dans le cadre du groupe de travail IETF tls
Première rédaction de cet article le 25 avril 2015


Le protocole TLS offre un grand nombre de choix : choix de la version, choix des algorithmes cryptographiques, plein d'options... Tous ces choix ne sont pas équivalents en terme de sécurité : les versions anciennes de TLS ont des vulnérabilités absentes des plus récentes, par exemple. Dès qu'un protocole cryptographique a des choix, il y a un risque de sécurité : que l'attaquant tente de perturber la négociation initiale entre les deux parties, pour les amener à choisir les variantes les moins sécurisées, en faisant croire à chacun que son partenaire ne peut pas gérer les meilleures variantes. C'est ce qu'on nomme une attaque par repli (downgrade attack) et c'est une plaie classique des protocoles cryptographiques (sauf de ceux qui n'offrent aucun choix, mais qui ont d'autres problèmes, notamment l'impossibilité d'évoluer). Ce RFC présente une nouvelle technique TLS pour empêcher certaines attaques par repli : annoncer un algorithme cryptographique qui n'est pas un vrai algorithme mais qui signale qu'on a effectué un repli, permettant au partenaire de détecter que quelqu'un a interféré avec la communication. Cette technique se nomme SCSV, pour Signaling Cipher Suite Value.

Normalement, un tel signalement n'est pas nécessaire (c'est très bien expliqué dans cet article sur StackExchange), les règles de négociation de TLS se chargent de tout (RFC 5246, sections 7.3 et 7.4). Mais il y a des serveurs TLS bogués qui réagissent mal avec certaines variantes. Au lieu d'indiquer proprement qu'ils ne gèrent pas ces variantes, ils coupent la communication. Un client TLS qui veut donc maximiser ses chances de se connecter va donc réessayer, en ne proposant pas les choix qui ont pu mener au précédent échec. C'est sympa du point de vue de l'interopérabilité mais cette downgrade dance est dangereuse du point de vue de la sécurité : le serveur, lors de la deuxième tentative, ne sait pas qu'il s'agit d'un repli. Prenons l'exemple d'un attaquant qui a trouvé une faille dans TLS 1.0 mais qui n'existe plus dans TLS 1.2 (celui du RFC 5246). Si Alice et Bob savent tous les deux parler 1.2, c'est cette version qu'ils choisiront, par défaut. Il faut donc les convaincre de se replier en 1.0. Un attaquant actif peut perturber la négotiation TLS (par exemple en ne transmettant pas le ServerHello, donnant au client l'impression que le serveur a ignoré son ClientHello). Certains clients vont alors se dire « zut, demander 1.2 perturbe le serveur, je vais réessayer directement en 1.0 ». Et l'attaquant aura atteint son but. Le serveur, qui sait faire du TLS 1.2, verra une demande en 1.0 et se dire juste « tiens, un vieux client qui ne sait pas faire de 1.2 ». Jusqu'à ce nouveau RFC, la seule protection contre ces attaques était de configurer le serveur pour refuser certains choix vraiment trop mauvais, question sécurité. Cette solution était trop rigide (pour reprendre l'exemple précédent, TLS 1.0 n'est pas catastrophique : il est raisonnable d'autoriser les vieux clients à se connecter en 1.0, mais on veut empêcher que les clients récents ne soient amenés à se limiter à 1.0). Au passage, un exemple d'une telle démarche est discutée dans l'article présentant la configuration TLS de mon blog (la ligne GnuTLSPriorities SECURE:-VERS-SSL3.0:-ARCFOUR-128:-ARCFOUR-40).

L'idéal serait bien sûr qu'il n'y ait pas de serveurs bogués, que la négociation TLS normale suffise, et que les clients n'aient jamais à faire de downgrade dance. Mais, dans le monde cruel où nous vivons, cela n'arrivera pas, les programmeurs ne lisent pas les normes et ne testent pas leur travail. À noter que, même en l'absence d'un attaquant actif, on voit parfois des replis malencontreux : un problème temporaire de réseau peut mener le client TLS à se dire « tiens, pas de réponse, je vais réessayer en TLS 1.0 et sans les extensions, pour voir ».

Donc, pour permettre au serveur de détecter que le client a fait un repli à tort, notre RFC introduit un nouveau pseudo-algorithme de chiffrement, TLS_FALLBACK_SCSV, valeur 0x56,0x00 (désormais dans le registre IANA). Il sera envoyé uniquement par le client, jamais par le serveur. Ce n'est pas un vrai algorithme, juste un signalement par le client qu'une première connexion a échoué et que le client tente un repli (section 4 du RFC). Si le client envoie le pseudo-algorithme TLS_FALLBACK_SCSV dans son ClientHello, et indique un protocole de version inférieure à ce que le serveur peut gérer, le serveur peut alors se rendre compte que le client a effectué un repli à tort (cf. section 3). Il peut alors répondre avec un nouveau message d'erreur, l'alerte TLS inappropriate_fallback (valeur 86). Voici ce quie ça donne avec Firefox :

Le signalement par le client qu'il s'est replié est un (pseudo-)algorithme de chiffrement, pas une extension TLS, car le but est qu'il ne pose de problème avec aucun serveur, même le plus ancien et le plus bogué. Le mécanisme d'indication des algorithmes de chiffrement date des débuts de SSL et on peut donc certainement compter dessus. Au passage, la technique de notre nouveau RFC est la deuxième utilisation de ce principe du SCSV, après la TLS_EMPTY_RENEGOTIATION_INFO_SCSV de la section 3.3 du RFC 5746.

La section 6 de notre RFC explore les cas où le client a intérêt à envoyer un TLS_FALLBACK_SCSV ou pas. Si le client n'a pas pu se connecter en TLS v1 ou supérieur, et se replie sur SSL v3, alors, le TLS_FALLBACK_SCSV est vraiment nécessaire car SSL v3 a de nombreuses faiblesses (la faille Poodle par exemple). Par contre, quand un client a une toute nouvelle version de TLS (à l'heure de la publication de ce RFC, la version 1.3 est en cours de développement), des difficultés avec les vieux serveurs sont à prévoir et il peut être préférable de ne pas envoyer TLS_FALLBACK_SCSV, et d'accepter le repli.

Des mesures faites en novembre 2014 indiquaient que 14 % des serveurs TLS sur l'Internet géraient déjà ce pseudo-algorithme TLS_FALLBACK_SCSV. Si vous voulez tester vous-même, vous pouvez par exemple vous servir d'OpenSSL en ligne de commande :

% openssl s_client -connect google.com:443 -state -fallback_scsv -tls1_1
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv3 write client hello A
SSL3 alert read:fatal:unknown
SSL_connect:failed in SSLv3 read server hello A
1077786776:error:1409443E:SSL routines:SSL3_READ_BYTES:tlsv1 alert inappropriate fallback:s3_pkt.c:1260:SSL alert number 86
1077786776:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:598:

Ici, on a tenté de se connecter à Google en envoyant le SCSV (option -fallback_scsv) et en indiquant comme numéro de version TLS 1.1 (alors que Google et OpenSSL savent tous les deux faire du 1.2). Google a donc envoyé l'alarme (le message alert inappropriate fallback). Avec un serveur qui ne gère pas SCSV, on aurait au contraire eu une connexion sans alerte. Si, au lieu du programme openssl, on veut le faire depuis une application qu'on écrit, il y a instructions et code sur le Wiki d'OpenSSL. Notez que le test des SSL Labs regarde aussi SCSV (message « This server supports TLS_FALLBACK_SCSV to prevent protocol downgrade attacks » ou bien aucune indication dans le cas contraire). Vu avec tshark, le test avec openssl montrera :

client -> serveur:

        Handshake Protocol: Client Hello
            Version: TLS 1.1 (0x0302)
                Cipher Suite: Unknown (0x5600) [version trop ancienne
		de Wireshark, qui n'affiche pas le nom de la SCSV]

serveur -> client:

    TLSv1.1 Record Layer: Encrypted Alert                                                                     
        Content Type: Alert (21)                                                                              
        Version: TLS 1.1 (0x0302)                                                                             
        Length: 2                                                                                             
        Alert Message: Encrypted Alert         

(L'alerte est chiffrée et donc pas décodée par défaut par Wireshark.)

Côté navigateurs Web, Firefox et Chrome gèrent cette technique SCSV mais il semble qu'Internet Explorer ne le fera pas.

Et, pour finir, une bonne explication de SCSV, avec des exemples Wireshark. Et merci à Florian Maury pour sa relecture.


Téléchargez le RFC 7507


L'article seul

RFC 7512: The PKCS#11 URI Scheme

Date de publication du RFC : Avril 2015
Auteur(s) du RFC : J. Pechanec, D. Moffat (Oracle Corporation)
Chemin des normes
Première rédaction de cet article le 23 avril 2015


La norme technique PKCS#11 décrit une interface d'accès à des fonctions cryptographiques. Par exemple, elle permet à un logiciel de signature de signer en utilisant une clé privée stockée dans une base de données, un HSM, une carte à puce (smart card) ou autres dépôts. Jusqu'à présent, la désignation des objets auxquels on pouvait accéder par PKCS#11 n'était pas normalisée et chaque logiciel avait sa méthode. Désormais, il existe un plan d'URI standard pour cela, spécifié dans ce RFC. Bienvenue à pkcs11:object=cle-de-machin;type=public;id=%69%95%3E%5C%F4%BD%EC%91 et à ses copains.

Prenons l'exemple de l'outil de manipulation de certificats certtool, de GnuTLS. Son option load-ca-certificate permet de charger le certificat d'une AC. La valeur de cette option peut être le nom d'un fichier local mais cela peut aussi être un URI PKCS#11, autorisant ainsi l'accès à tous les mécanismes de stockage ayant une interface PKCS#11. Le principe de ces URI PKCS#11 est de permettre l'accès à des objets (comme les certificats, les clés publiques, les clés privées, etc), en donnant une série d'attributs qui identifient l'objet (dans mon exemple au premier paragraphe, les attributs étaient object, type et id). Le but de ces URI est limité à la récupération d'objets existants, on ne s'en sert pas pour créer de nouveaux objets.

Donc, la définition formelle de ce plan d'URI (section 3 de notre RFC) : le plan est pkcs11 (et les URI commencent donc par pkcs11: et ce plan a été réservé dans le registre IANA), et l'URI est ensuite composé de paires attribut-valeur, séparées par des points-virgules. L'attribut id a une valeur binaire (et qui est donc pourcent-encodée dans l'exemple au premier paragraphe), tous les autres sont du texte en UTF-8. Voici les principaux attributs, avec leur nom dans les URI et l'équivalent dans l'API PKCS#11 :

  • id (CKA_ID) est l'identificateur d'un objet. C'est, comme on l'a vu, une valeur binaire opaque.
  • object (CKA_LABEL) est le nom d'un objet. Contrairement à l'id, c'est du texte.
  • serial (serialNumber dans CK_TOKEN_INFO) est le numéro de série du token, le dispositif de stockage des objets (un HSM, par exemple).
  • token (label dans le CK_TOKEN_INFO), le nom du dispositif de stockage.
  • type (CKA_CLASS), désigne le type d'objet stocké qu'on veut récupérer. Cela peut être cert (un certificat), public (une clé publique), private (une clé privée en cryptographie asymétrique), secret-key (une clé secrète en cryptographie symétrique).

Il est également possible d'ajouter des requêtes dans l'URI, après le point d'interrogation. Par exemple, si le dispositif de stockage réclame un PIN, on peut mettre quelque chose comme ?pin-source=file:/etc/dnssec/token_pin dans l'URI (ici, cela dit que le PIN se trouve dans le fichier /etc/dnssec/token_pin).

La section 4 contient plusieurs exemples d'URI PKCS#11, désignant :

  • Une clé publique, identifiée uniquement par son nom : pkcs11:object=my-pubkey;type=public.
  • Un certificat, en indiquant le nom du dépôt matériel (token) utilisé, et l'id du certificat : pkcs11:token=The%20Software%20PKCS%2311%20Softtoken;manufacturer=Snake%20Oil,%20Inc.;model=1.0;object=my-certificate;type=cert;id=%69%95%3E%5C%F4%BD%EC%91. Notez les attributs manufacturer et model, que je n'avais pas cité dans la liste des attributs les plus utilisés.
  • Une clé privée, en utilisant une nouvelle requête, module-name, qui permet d'indiquer la bibliothèque dynamique à charger pour parler au dépôt des clés (PKCS#11 est une API, pas un protocole, et il faut donc une bibliothèque différente par type de HSM ou smart card) : pkcs11:object=my-sign-key;type=private?module-name=snakeoil-pkcs11. Ici, sur une machine Unix, l'application PKCS#11 va donc tenter de charger la bibliothèque snakeoil-pkcs11.so.

Il existe plusieurs implémentations des URI PKCS#11, le document était en développement depuis longtemps. Ainsi, OpenConnect documente « Objects from PKCS#11 tokens are specified by a PKCS#11 URI. ». Le projet Fedora tente de standardiser tous ses logiciels qui font de la cryptographie autour de ces URI « Currently, there are many different ways to tell each application how to find the certificate. [...] where PKCS#11 objects are specified in a textual form which is visible to the user (e.g. on the command line or in a config file), objects SHOULD be specified in the form of a PKCS#11 URI as as described ». Pour un programme développé avec GnuTLS :

/* In addition the following functions can be used to load PKCS #11
key and certificates by specifying a PKCS #11 URL instead of a
filename. */
int gnutls_certificate_set_x509_trust_file (gnutls_certificate_credentials_t cred, const char * cafile, gnutls_x509_crt_fmt_t type)
...

Téléchargez le RFC 7512


L'article seul

Articles des différentes années : 2015  2014  2013  2012  2011  2010  2009  Précédentes années

Syndication : Flux Atom avec seulement les résumés et Flux Atom avec tout le contenu