SEND
From Livre IPv6
Contents
SeND : SEcure Neighbor Discovery
Introduction
SeND (RFC 3971) est une version sécurisée de NDP (Neighbor Discovery Protocol, RFC 2461 et RFC 2462), le protocole de découverte de voisins d'IPv6.
Il est conseillé de connaitre un minimum ce protocole (voir Découverte de voisins) et posséder quelques notions de sécurité (voir Sécurité, Généralités) avant de lire ce chapitre.
Après un état des lieux des problèmes de sécurité lié à NDP (RFC 3756), les travaux ont commencés afin de répondre à chacune des menaces décrites dans ce document. IPSec avait été envisagé à l'époque de la conception de NDP pour sécuriser ce dernier, mais cela s'est révélé inapproprié en pratique.
La première innovation est l'utilisation de CGA (RFC 3972) pour Cryptographically Generated Addresses, qui permet de créer des identifiants d'interfaces à partir d'une clé publique.
Le deuxième mécanisme important de SEND est la possibilité de découvrir automatiquement un chemin de certification sur le réseau.
Une extension du protocole NDP
Le protocole SEND ajoute des fonctions de sécurité grâce à l'ajout d'options au messages NDP.
Voici la structure de tels paquets :
<------------NDP Message----------------> *-------------------------------------------------------------* | IPv6 Header | ICMPv6 | ND Message- | ND Message | | Next Header = 58 | Header | specific | Options | | (ICMPv6) | | data | | *-------------------------------------------------------------* <--NDP Message header-->
L'option CGA permet de vérifier l'identité d'une machine émettrice d'un paquet NDP. Cette option contient entre autre la clé publique de la machine émettrice, dont la cohérence avec l'adresse source utilisée est vérifiée par la machine réceptrice.
L'option RSA contient une signature du paquet, calculée avec la clé privée de la machine émettrice. Le noeud recevant le paquet peut vérifier l'intégrité et l'authenticité du paquet, grâce à la clé publique reçue conjointement ou précédemment.
La confiance dans la clé publique utilisée par les options CGA et RSA se base sur un mécanisme de certification décrit dans les chapitres suivants.
Une option d'horodatage (Timestamp) est utilisée pour protéger NDP des attaques de type 'rejeu'.
Une option unicité (NOnce) est utilisée pour protéger les associations Demande/Réponse (Solicit/Advertisement) : une réponse NDP devra contenir la même valeur NOnce que la demande correspondante pour être valide.
Enfin deux options (Certicate Path Solicitation et Certificate Path Advertisement) sont utilisées afin de permettre la découverte automatique par une machine terminal d'un chemin de certification. Ce mécanisme permet à des machines utilisant l'auto configuration sans état (RFC 2462) de vérifier la légitimité d'un routeur et celle des préfixes publiés sur le lien auprès d'un tiers de confiance sur le réseau.
Ces options sont utilisées par NDP uniquement lorsque cela est nécessaire, c'est à dire pour se protéger d'un risque d'attaque spécifique.
Adresses CGA
Une adresse CGA (Cryptographically Generated Address) est utilisée afin de prouver, en temps qu'émetteur d'un message NDP, que l'on bien le propriétaire de l'adresse source utilisée : afin prouver son identité réseau. Une paire de clé Publique/Privée est générée pour chaque noeud voulant prouver la possession d'une adresse.
Le mécanisme de génération CGA crée la partie identifiant d'interface d'une adresse IPv6, à partir d'une clé publique et d'autres paramètres, comme le mécanisme de configuration sans état. Cette adresse est ensuite utilisée comme adresse source du message NDP, auquel au ajoute également l'option CGA, qui contient les paramètres ayant servis à la génération de l'adresse. Ainsi le récepteur peut générer une adresse CGA à partir des données reçues via l'option du même nom, et comparer la CGA calculée avec la CGA utilisée comme adresse source. Elles doivent être identiques bien sûr.
La génération et la vérification d'une adresse CGA sont basés sur l'utilisation d'une fonction de hachage non réversible, SHA-1, sur la clé publique. Il est donc facile de calculer une adresse CGA à partir de la clé publique, alors que l'inverse est, grâce à SHA-1, très difficile. Ceci est conçu afin d'éviter le vol d'adresse (Spoofing): si un pirate veut s'approprier une adresse, il lui faut également fournir la clé publique qui a servi à sa génération : il lui faut donc trouver les données d'entrée de l'algorithme SHA-1 en connaissant l'adresse CGA résultante, ce qu'interdit SHA-1.
Voyons en détails les algorithmes de génération et de vérification.
Génération d'une adresse CGA
Le principe est de créer une association cryptographique (avec fonction de hachage) entre une clé publique et une adresse IPv6.
Par la suite, lorsque que l'on parlera d'adresse, il faudra comprendre les 64 bits les plus à droite : ceux de l'identifiant d'interface.
Format d'une adresse CGA
Une adresse CGA dépend d'abord d'un paramètre de sécurité, noté Sec, codé sur 3 bits. Cette valeur est encodé dans les 3 bits les plus à gauche de l'adresse. L'adresse CGA est également associée à un ensemble de paramètres dit 'Paramètres CGA', dont une clé publique. Deux valeurs sont calculés à partir de ces paramètres CGA : Hash1 (sur 64 bits) et Hash2 (sur 112 bits).
Une adresse générée cryptographiquement (CGA address) est donc définie comme une adresse IPv6 vérifiant les propriétés suivantes:
- Hash1 est égal à l'identifiant d'interface. Les bits de la valeur Sec, et les bits u et g sont ignorés dans cette comparaison.
- Les 16*Sec bits les plus à gauche de Hash2 sont nuls.
En d'autres termes, si l'on définit les valeurs Mask1 et Mask2 de la façon suivante:
* Mask1 (sur 64 bits) = 0x1cffffffffffffff * Mask2 (sur 112 bits) = 0x0000000000000000000000000000 si Sec=0, 0xffff000000000000000000000000 si Sec=1, 0xffffffff00000000000000000000 si Sec=2, 0xffffffffffff0000000000000000 si Sec=3, 0xffffffffffffffff000000000000 si Sec=4, 0xffffffffffffffffffff00000000 si Sec=5, 0xffffffffffffffffffffffff0000 si Sec=6, et 0xffffffffffffffffffffffffffff si Sec=7.
alors les propriétés définissant une adresse CGA peuvent se réécrire ainsi:
- Hash1 & Mask1 == Identifiant d'interface & Mask1
- Hash2 & Mask2 == 0x0000000000000000000000000000
Paramètres CGA et valeurs Hash1 et Hash2
Chaque adresse CGA est associée à des paramètres CGA, dont voici le format:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + Modifieur (16 octets) + | | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + Préfixe de sous-réseau (8 octets) + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Collision Count| | +-+-+-+-+-+-+-+-+ | | | ~ Clé Publique (longueur variable) ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | ~ Champs d'extension (optionel, longueur variable ~ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- Modifieur : il s'agit d'un entier sur 128 bits, non signé, qui peut contenir n'importe quelle valeur. Le modifieur est utilisé lors de la génération et permet d'introduire de l'aléa dans la valeur de l'adresse.
- Préfixe de sous réseau : préfixe de sous réseau de l'adresse CGA (64 bits)
- Compteur de collision : entier non signé sur 8 bits dont les valeurs DOIVENT être 0, 1 ou 2.
- Clé publique : c'est un champ de longueur variable qui contient la clé publique du propriétaire de l'adresse. Le format DOIT etre la forme DER du champ ASN.1 SubjectPublicKeyInfo tel que présent dans les certificats X509 (RFC 3280). SEND devrait utiliser une paire de clé RSA, avec une longueur minimale de 384 bits.
- Champs d'entension : ces champs ne sont pas encore utilisés dans la spécification, mais pourront l'être dans le futur.
Les valeurs Hash1 et Hash2 sont calculés ainsi : l'algorithme SHA-1 est appliqué sur la structure des paramètres CGA. Hash1 est obtenu en prenant les 64 bits les plus à gauche de la valeur SHA-1 de 160 bits. Hash2 est obtenu également grâce à l'application de SHA-1 sur les paramètres CGA, mais avec les champs préfixe et collision à 0, et en gardant cette fois les 112 bits de gauche de la valeur SHA-1.
Algorithme de génération
La génération d'une adresse CGA devrait s'effectuer ainsi:
- Affecter au Modifieur une valeur pseudo-aléatoire sur 128 bits
- Concaténer de gauche à droite le Modifieur, 9 octets de valeur 0, la clé publique encodée, et les éventuels champs d'extension. Appliquer l'algorithme SHA-1 sur cette concaténation. Prendre les 112 bits les plus à gauche de la valeur SHA-1. Le résultat est Hash2
- Comparer les 16*Sec bits les plus à gauche de Hash2 avec 0. S'ils sont tous nuls, alors continuer à l'étape 4. Sinon, incrémenter le Modifieur de 1 et revenir à l'étape 2.
- Affecter 0 au champ Collision.
- Concaténer de gauche à droite la valeur finale du Modifieur, le préfixe réseau, le compteur de collision, la clé publique encodée, et les éventuels champs d'extension. Appliquer l'algorithme SHA-1 sur cette concaténation. Prendre les 64 bits les plus à gauche de la valeur SHA-1. Le résultat est Hash1
- Fabriquer un identifiant d'interface à partir de Hash1 en insérant la valeur de Sec dans les 3 bits les plus à gauche, et en mettant à zero les bits u et g.
- Concaténer les 64 bits du préfixe réseau au 64 bits de l'identifiant d'interface de façon à former une adresse IPv6 standard : avec ma partie préfix à gauche et la partie interface sur la droite.
- Effectuer une détection de collision d'adresses (DAD). En cas de collision, incrementer le compteur de collision et aller à l'étape 5. Après 3 collisions, l'algorithme s'arrête et rapporte une erreur.
- Former la structure des paramètres CGA en concaténant de gauche à droite : le Modifieur final, le préfixe réseau, le compteur de collision final, la clé publique encodée, et d'éventuel champs optionnels.
En sortie, cet algorithme de génération produit une nouvelle adresse CGA et une nouvelle structure de paramètres CGA.
Plusieurs valeurs du modifieur permettent de générer plusieurs CGA sans lien direct.
Pour la valeur Sec=0, l'algorithme est déterministe et rapide. Pour des valeurs de Sec plus grandes que zero, il n'est pas garanti que l'algorithme termine après un certain nombre d'itérations. Ceci est dû au fait que l'algorithme à été concu pour résister à des attaques de type 'force brute' pour des grandes valeurs de Sec.
Des optimisations de cet algorithme de génération sont possible (surtout dans la recherche de la valeur du modifieur), pourvu que
- le format de la structure des paramètres CGA soit respectée
- l'algorithme de vérification tel que décrit plus loin réussisse, avec une version optimisée de la génération.
Algorithme de vérification
L'algorithme prend en entrée une adresse IPv6 et une structure de paramètres CGA, tel que définie plus haut. Cette adresse est l'adresse source d'une paquet NDP reçu, et la structure des paramètres CGA est reçue via l'option ND CGAde ce même paquet.
- Vérifier que le compteur de collision contienne la valeur 0, 1 ou 2. Dans le cas contraire, la vérification échoue
- Vérifier que le préfixe réseau des paramètres CGA est égal au préfixe réseau de l'adresse IPv6. Dans le cas contraire, la vérification échoue
- Appliquer l'algorithme SHA-1 sur la structure des paramètres CGA. Garder les 64 bits de gauche. Le résultat est Hash1.
- Comparer Hash1 avec l'identifiant d'interface, en ignorant les bits u et g, et les 3 bits Sec (les 3 bits les plus à gauche). Si la comparaison échoue, la vérification échoue.
- Extraire la valeur Sec (les 3 bits les plus à gauche) de l'identiant d'interface
- Concaténer, de droite à gauche, le modifieur, 9 octets vides, la clé publique et les éventuelles extensions contenues dans la structure des paramètres CGA. Appliquer SHA-1 sur cette concaténation et garder les 112 bits les plus à gauche. La valeur obtenue est Hash2.
- Comparer les 16*Sec bits les plus à gauche de Hash2 avec 0. Si un seul d'entre eux n'est pas nul, la vérification échoue, sinon elle réussit.
Si la vérification échoue à n'importe quelle étape, alors l'algorithme DOIT s'arrêter immédiatement. Par contre s'il réussi, la machine qui a exécuté avec succès cet algorithme sait que la clé publique contenue dans les paramètres CGA est la clé authentique du possesseur de l'adresse. Le vérifieur peut extraire cette clé publique en enlevant les premiers 25 octets de la structure des paramètres CGA, et en décodant la structure ASN.1 SubjectPublicKeyInfo.
Le vérifieur doit être capable de traiter les valeurs de Sec suivantes : 0, 1, 2, 3, 4, 5, 6 et 7. L'algorithme est rapide, il ne nécessite au plus que 2 calcul SHA-1. L'algorithme de vérification doit être capable de traiter les clés publiques RSA au moins entre 384 et 2048 bits.
Exemple de génération
Voici la clé publique utilisée dans l'exemple de la RFC 3972 (ici sous la forme PEM):
-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMLC8TcwVFTxC9nOo2hEtTDpIRpLJisW Rny337ofWVwBlPJ1vlpNOG8sPCOCUIdzx4Z/mzueY6Cce8SPelTr768CAwEAAQ== -----END PUBLIC KEY-----
et sous la forme DER:
305c 300d 0609 2a86 4886 f70d 0101 0105 0003 4b00 3048 0241 00c2 c2f1 3730 5454 f10b d9ce a368 44b5 30e9 211a 4b26 2b16 467c b7df ba1f 595c 0194 f275 be5a 4d38 6f2c 3c23 8250 8773 c786 7f9b 3b9e 63a0 9c7b c48f 7a54 ebef af02 0301 0001
# openssl rsa -pubin -in cga.pem -text -noout Modulus (512 bit): 00:c2:c2:f1:37:30:54:54:f1:0b:d9:ce:a3:68:44: b5:30:e9:21:1a:4b:26:2b:16:46:7c:b7:df:ba:1f: 59:5c:01:94:f2:75:be:5a:4d:38:6f:2c:3c:23:82: 50:87:73:c7:86:7f:9b:3b:9e:63:a0:9c:7b:c4:8f: 7a:54:eb:ef:af Exponent: 65537 (0x10001)
- Le modifieur a la valeur initiale : 89a8 a8b2 e858 d8b8 f263 3f44 d2d4 ce9a
- Le paramètre de sécurité Sec est : 1
- Le préfixe réseau est : fe80::0
Sans donnez tous les détails présents à l'annexe A de la RFC, voici les étapes clés:
- Il faut itérer une fois à l'étape 3 afin de respecter le critère 'les 16*Sec bits de gauche de Hash2 valent 0', pour Hash2 = 0000 01ca 680b 8388 8d09 12df fcce
- Le modifieur final vaut donc '89a8 a8b2 e858 d8b8 f263 3f44 d2d4 ce9b'.
- Hash1 = fd4a 5bf6 ffb4 ca6c
- La valeur de l'identifiant d'interface est donc 3c4a:5bf6:ffb4:ca6c.
La vérification réussit, bien entendu sur ces même données.
Option Neighbor Discovery CGA
Le format d'une option CGA est le suivant:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Longueur | Pad Length | Réservé | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . Paramètres CGA . . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . Bourrage . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- Type : octet à 11
- Longueur : longueur de l'option, tout les champs compris (de 'type' à 'padding') en unité de 8 octets
- Pad Length : longueur du champ de bourrage
- Réservé : octet à 0
- Paramètres CGA : contient la structure des paramètres CGA telle que définie précédemment
- Bourrage : octets de bourrage de façon à ce que l'option occupe une taille en octets multiple de 8.
L'option CGA DOIT être la première parmis les options SEND.
Option de signature RSA
L'option RSA est utilisée afin de véhiculer la signature numérique du paquet ND. Cette option DOIT être la dernière option du paquet, puisque la signature prend en compte les options précédentes.
Voici comment calculer cette signature.
Calcul de la signature RSA
Afin de pouvoir signer un message, un noeud a besoin :
- la CGA
- les paramètres CGA associés
- le message
- la clé privée qui correspond à la clé publique contenue dans les paramètres CGA
Voici l'algorithme:
- Concaténer de gauche à droite :
- le tag de type 'CGA Message Type' de 128 bits (cette séquence d'octets est 086f ca5e 10b2 00c9 9c8c e001 6427 7c08),
- l'adresse source de 128 bits venant de l'entête IP
- l'adresse destination de 128 venant de l'entête IP
- les champs venant de l'entête ICMP : type (8 bits), code (8 bits), checksum (16 bits)
- l'entête NDP, depuis l'octet suivant la somme de contrôle ICMP, jusqu'à sans l'inclure la première option NDP
- toutes les options NDP précédant l'option RSA.
- Générer la signature RSA avec l'algorithme de signature numérique RSASSA-PKCS1-v1_5 (RFC 3447) et l'algorithme SHA-1. Les données en entrée sont la concaténation décrite ci dessus et la clé privée.
Ici l'adresse source est une CGA, et la première option NDP est une option CGA, contenant la clé publique.
Format de l'option ND RSA
Voici le format de l'option de signature RSA:
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Longueur | Réservé | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | Key Hash | | | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . Digital Signature . . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | . . . Padding . . . | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- Type : 12 (8 bits)
- Longueur : longueur de l'option (du champ type à la zone au bourrage, inclus) par unité de 8 octets
- Réservé : 16 bits, doit être à 0
- Hachage de la clé : les 128 bits les plus à gauche du hachage de la clé publique, en utilisant l'algorithme SHA-1. L'intérêt est de pouvoir associer la signature avec une clé publique connue. En l'occurence il s'agit de celle contenue dans les paramètres CGA de l'option CGA.
- Signature numérique : champ de longueur variable qui contient la signature numérique du paquet
- Padding : octets de bourrage de façon à ce que la longueur de l'option soit multiple de 8 octets
Exemple de calcul d'une signature
Internet Protocol Version 6 Version: 6 Traffic class: 0x00 Flowlabel: 0x00000 Payload length: 272 Next header: ICMPv6 (0x3a) Hop limit: 255 Source address: fe80::344d:905e:8f86:11e7 (fe80::344d:905e:8f86:11e7) Destination address: 2001:630:13:1d3:3444:138c:5b0c:c5a4 (2001:630:13:1d3:3444:138c:5b0c:c5a4) Internet Control Message Protocol v6 Type: 135 (Neighbor solicitation) Code: 0 Checksum: 0x504a (correct) Target: 2001:630:13:1d3:3444:138c:5b0c:c5a4 (2001:630:13:1d3:3444:138c:5b0c:c5a4) ICMPv6 options Type: 1 (Source link-layer address) Length: 8 bytes (1) Link-layer address: 00:12:79:5a:86:e9 ICMPv6 options Type: 11 (CGA) Length: 128 bytes (16) CGA option: 0b 10 05 00 (type=11, len=16*8, padding=5, reserved=0) CGA parameters : Modifier : 8b 8f 4f ed b2 de cf 0e 9d 72 68 97 f8 7d 5f 72 Network prefix : fe 80 00 00 00 00 00 00 Public key (512bits in ASN.1 form) 00 30 5c 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 4b 00 30 48 02 41 00 ca cb dd fe 24 9f 0f b2 1e e8 a4 5a 99 d3 a9 1c 2d b7 24 34 46 20 d7 89 8d eb 9f 57 e2 18 4f 97 1b 62 ae 8b d8 ca e8 38 0c 31 82 ef 59 5b f8 bb 28 b3 91 6a 7b 0d 68 b3 4a e3 b0 a4 b4 d9 39 29 02 03 01 00 01 Padding 00 00 00 00 00 ICMPv6 options Type: 13 (Timestamp) Length: 16 bytes (2) Timestamp option: Reserved = 00 00 00 00 00 00 Timestamp = 00 00 44 e3 20 f3 ed d6 ICMPv6 options Type: 14 (Nonce) Length: 8 bytes (1) Nonce = 5a 28 69 e1 25 f3 ICMPv6 options Type: 12 (RSA) Length: 88 bytes (11) RSA option : 0c 0b 00 00 (type=12, len=11*8, reserved=0) Keyhash : 29 90 5d e3 3f 78 18 fc c1 92 64 50 17 eb 8f ea Signature : 9f 65 ec 6c fd 81 c6 53 d3 52 88 3c ab c4 08 81 50 1e 6b 0c ee f5 95 70 c9 37 33 75 01 86 f4 32 53 5d 67 92 b6 cd 51 40 d5 0d 1c da 5c 5e 28 43 bf cd f3 ab 81 5c c0 43 22 62 de 7a 4e 55 eb f3 Padding : 00 00 00 00