Sécurisation d’un réseau WiFi avec IPSec

Comment sécuriser un réseau WiFi lorsque l’on ne peut, ou ne veut, pas utiliser WEP ou WPA.

Avec la démocratisation des réseaux WiFi personnels, deux problèmes majeurs se posent : la sécurisation des données qui circulent entre les noeuds du réseau et la gestion des accès aux ressources du réseau (principalement la connection web dans un cadre privé). Les constructeurs de matériels WiFi proposent maintenant des systèmes de chiffrement et d’authentification en standard, mais l’accès à un driver fonctionnel est nécessaire. Dans mon cas je ne pouvais utiliser que ndiswrapper et aucun accès n’était possible même aux fonctions de chiffrement les plus basiques (WEP).
Ce tutoriel est un guide à l’usage de ceux qui veulent utiliser des protocoles reconnus et permettant d’obtenir une forte  interopérabilité.

Introduction

Ce tutoriel aborde une gamme de techniques assez vaste (certificats x509, Netfilter, Racoon, etc.) et des erreurs ont pu se glisser à l’intérieur de certaines descriptions. Si vous en rencontrez une, que vous avez un problème non couvert par cette doc ou que vous avez une solution aux problèmes posés dans la section « Conclusion », n’hésitez surtout pas à me contacter par mail.

Avant d’attaquer, un petit menu de ce qui vous attend dans ce tutoriel :

  1. Les certificats x509
    • Création d’un certificat racine auto-signé
    • Création des demandes de certificats pour les machines du réseau
    • Signature de ces demandes par le certificat racine
  2. Racoon sur un poste client
    • Installation
    • Le fichier de configuration
    • Installation des certificats de la machine et du routeur
  3. Racoon sur le routeur
    • Installation des sources
    • Modification des sources
    • Création d’un nouveau package binaire et installation
  4. Définition des security policies
    • Sur les clients
    • Sur le routeur
  5. Utiliser iptables pour protéger l’accès
    • Patchs noyau et iptables
    • Définition des règles iptables

Certificats x509

Les certificats x509 seront utilisés par Racoon pour l’authentification des ordinateurs demandant une connection. Pour plus d’infos sur ces certificats il existe une traduction française du SSL certificates How-to (version originale disponible ici).

Avant de continuer, nous devons créer un certificat auto-signé pour la machine principale (le routeur dans notre cas) qui servira à signer les certificats des autres machines. Vérifiez que openssl est installé sur votre machine et tapez la commande suivante :

openssl req -new -x509 -newkey rsa:2048 -keyout root_key.pem -out root_cert.pem -days 3650

Une série de questions va vous être posée, puis 2 fichiers seront générés : le fichier root_key.pem qui est la clé privée de l’autorité de certification que vous venez de créer et le fichier root_cert.pem qui est le certificat de cette même autorité, valable 10 ans. Vous pouvez (et allez) distribuer sans risques le certificat de l’autorité racine, mais ne distribuez jamais la clé privée.

Maintenant nous allons créer une demande de certificat pour le routeur et les clients, qui seront signées par l’autorité de certification créé plus haut. Pourquoi procéder ainsi ? Racoon doit avoir accès à une version non protégée par mot de passe de la clé privée, aussi il est plus sécurisant de ne pas compromettre la clé privée de l’autorité de certfication racine (même si aucune vulnérabilité compromettant la clé privée n’a été découverte dans Racoon, je préfère mettre la ceinture et les bretelles).
Sur chaque machine participant au réseau sans fil (y compris le routeur donc), nous allons créer une demande de certificat et une clé privée à l’aide de cette commande :

openssl req -new -newkey rsa:2048 -keyout machine.private -out machine.request -days 365

Pour ceux qui suivent, cette commande va créer une demande de certificat valable 1 an (l’option -days 365), libre à vous de modifier cette durée.

Maintenant, nous allons envoyer les demandes de certificats à l’autorité de certification (le routeur), qui devra les signer en utilisant son propre certificat. Je vous conseille de tout transférer par ssh (en utilisant scp) ou via un support amovible. À ce point le réseau est une vraie passoire alors mieux vaut ne lui faire confiance pour rien du tout.
Une fois sur le routeur, la commande pour signer les certificats est la suivante :

openssl ca -in machine.request -out machine.public -days 3650

Vous pouvez ensuite supprimer tous les fichiers .request et donner chaque fichier .public à sa machine (ne les supprimez pas encore du routeur, vous en aurez besoin plus tard).

Prenons une pause

Arrivés à ce point de l’article, vous êtes peut-être un peu perdus dans toute cette histoire de certificats. Prenez un café, un thé, ou n’importe quoi d’autre puis revenez lire calmement le résumé de la situation.

Actuellement, nous avons sur chaque machine les certificats suivants :

Routeur :

  • le certificat de l’autorité racine, auto-signé, et la clé privée associée ;
  • le certificat à utiliser pour cette machine, signé par le certificat de l’autorité racine, et la clé privée associée. Dorénavant nous n’utiliserons plus que ces deux fichiers, aussi veillez à en conserver une copie en l’état ;
  • une copie de chaque certificat des clients qui seront amenés à se connecter sur le réseau. Encore des fichiers à conserver précieusement.

Client :

  • sur chaque client nous avons un certificat signé par l’autorité racine du routeur et la clé privée associée. Conservez aussi précieusement une copie de ces fichiers en l’état.

J’espère que tout est plus clair maintenant, et si vous ne vous trouvez pas dans la configuration décrite, alors reprenez calmement depuis le début. Maintenant, voyons comment configurer IPSec.

IPSec

Avant d’attaquer IPSec, il vous faut un noyau de la branche 2.6 ou un 2.4.x avec x>20, et les options suivantes activées dans votre noyau :

CONFIG_NET_KEY
CONFIG_INET_AH
CONFIG_INET_ESP
CONFIG_XFRM_USER
plus l'API de cryptographie et les algorithmes.

Une fois le noyau fraîchement compilé et installé, il faut installer l’interface utilisateur pour manipuler les règles IPSec. Sous Debian on utilise le package ipsec-tools. Un coup de apt-get et c’est réglé. Faisons une courte pause pour voir comment fonctionne IPSec.

IPSec se base sur deux jeux de règles : les Security Associations (SA) et les Security Policies (SP). Une SP est une manière de décrire une procédure générale pour l’établissement de SA personnalisées, et une SA est une règle qui définit la manière dont le traffic doit être chiffré et transmis entre deux hôtes précis.
Il en découle qu’il faut au moins deux SA pour une communication bidirectionnelle entre deux hôtes (une SA définit aussi un sens de communication).

Définir des SA pour tous les hôtes d’un réseau un minimum étendu devient très vite laborieux, aussi il existe un outil, Racoon, qui va définir pour nous les SA en fonction des SP déclarées lorsque deux hôtes cherchent à établir une communication. Avant d’aller plus loin dans ces histoires de SA et de SP et vu que nous comptons utiliser Racoon, installons-le et configurons-le.

Racoon

Je ne m’étendrai pas sur l’installation de Racoon vu que c’est franchement trivial pour vous si vous en êtes à vouloir configurer IPSec sur votre distribution préférée :) Alors à vos apt-get, urpmi, wget ou autres.

Avant de commencer, il faut que vous ayez installé Racoon sur tous les postes participant au réseau, sinon la négociation de clés et de SA marchera forcément moins bien. Commençons par le plus simple, Racoon sur un poste client.

Racoon sur un poste client

Voici mon fichier de configuration, avec les explications en commentaires : télécharger.

Une fois le fichier de configuration en place il reste à s’occuper des certificats. Racoon en aura besoin de trois sur un poste client : le certificat de la machine, la clé privée de la machine non protégée par mot de passe, et le certificat du routeur. Ces trois fichiers devront être placés dans le répertoire défini par l’option "path certificate" du fichier de config, et seul root doit avoir le droit de les lire et de les écrire (sinon Racoon refusera de se lancer). Donc un coup de chmod 600 sur tous les fichiers du répertoire et ça roule.

Maintenant, il faut faire sauter le mot de passe qui protège la clé privée de la machine. Vous travaillez bien sur une copie de ce fichier, n’est-ce pas ?
La commande est :

openssl rsa -in machine.private -out machine.private.

Dernier point de configuration, il faut maintenant que Openssl puisse verifier l’autorité de certification racine. Rapatriez le certificat racine créé au tout début de ce tutoriel sur le client (fichier root_cert.pem dans ce cas), rangez le quelquepart sur votre disque, puis exécutez cette commande dans le répertoire de Racoon contenant les certificats :

ln -s /chemin/vers/root_cert.pem $(openssl x509 -noout -hash < /chemin/vers/root_cert.pem).0

Racoon sur la passerelle

Dans un monde idéal, Racoon est capable de générer tout seul les SP avec l’option de configuration generate_policy positionnée à « on ». Hélas, et selon la formule consacrée, nous ne vivons pas dans un monde idéal, et l’utilisation de cette option m’a conduit à de nombreux problèmes, aussi je vous conseille de la positionner à « off » ou de ne pas la définir, ce qui revient au même.

Voici donc mon fichier de configuration pour le routeur. La définition des SP sera expliquée plus bas.

Définir les SP sur les clients

Allez, dernière ligne droite et c’est fini. Il reste maintenant à définir les SP sur chaque client pour que Racoon puisse créer les SA associées. La commande utilisée est setkey et sa syntaxe est expliquée en long, en large et en travers dans sa page man, mais voici un exemple pour bien démarrer.

Nous allons créer un fichier exécuté lors de la mise en place du réseau sur notre système. Sous Debian ce script, rendu exécutable, sera placé dans /etc/network/if-pre-up.d/. N’oubliez pas de remplacer dans ce script les valeurs A.A.A.A par l’IP de la machine sur laquelle tournera le script, et B.B.B.B par l’IP du routeur :

#!/usr/sbin/setkey -f# Nettoyage des anciennes règles
flush;
spdflush;
# SP
spdadd A.A.A.A/32[500] B.B.B.B/32[500] any -P out none
spdadd B.B.B.B/32[500] A.A.A.A/32[500] any -P in none
spdadd A.A.A.A 0.0.0.0/0 any -P out ipsec
esp/tunnel/A.A.A.A-B.B.B.B/require;
spdadd 0.0.0.0/0 A.A.A.A any -P in ipsec
esp/tunnel/B.B.B.B-A.A.A.A/require;

Dans ce script nous demandons à ce que toutes les communications qui sortent du client à destination de n’importe qui (troisième commande spdadd) soient chiffrées avec IPSec. La quatrième commande spdadd demande l’inverse, à savoir que toutes les communications en provenance de n’importe qui et à destination de cette machine soient chiffrées avec IPSec.

Les deux premières commandes spdadd demandent que le traffic à destination et en provenance du port 500 (utilisé pour l’échange de clés) ne soit pas chiffré. Logique, car les clés servent à établir une session IPSec, donc demander à ce que ce traffic soit chiffré, ce qui est impossible tant qu’aucun échange de clés n’a eu lieu.

Définir les SP sur la passerelle

Définir les SP dans chaque sens pour tous les clients peut devenir fastidieux (et c’est un euphémisme poli). Pour me faciliter la vie, j’ai écrit ce petit script qui va définir les SP quasi tout seul. Avant de passer à la suite, éditez juste les deux variables SETKEY pour qu’elles pointent vers l’utilitaire du même nom, et IP pour qu’elle soit l’adresse de l’interface à sécuriser. Rendez ce script exécutable et placez-le dans le répertoire contenant les scripts lancés juste avant le démarrage du réseau (/etc/network/if-pre-up.d/ sous Debian).

Pour l’utiliser il va vous falloir créer le dossier /etc/racoon/allowed_clients. Ce dossier contiendra un fichier par client, et le nom de ce fichier sera l’adresse IP du client. Par exemple si vous voulez autoriser 192.168.0.42 à se connecter, il vous suffira de taper la commande touch /etc/racoon/allowed_client/192.168.0.42. Exécutez ce script manuellement la première fois, et ça devrait rouler.

Soufflons un peu et admirons

Sur chaque client, lancez le script de définition des SP et Racoon. Lancez Racoon sur le routeur. Maintenant, essayez de faire un ping du routeur depuis un client. Normalement, vous devriez avoir peur car ça ne marche pas. Recommencez, et décrispez-vous. Tout devrait fonctionner maintenant. Pourquoi ce comportement ? Il s’agit d’un problème avec le noyau qui au lieu de mettre les paquets en attente le temps de l’établissement des SP et des SA les rejette tout simplement. Les développeurs sont au courant, mais certains jugent que les modifications à faire seraient trop importantes.

À partir de maintenant, tous les échanges sont chiffrés. Si vous disposez d’une machine avec une carte WiFi, installez un outil comme Kismet, qui va faire de l’écoute passive du traffic WiFi aux environs (donc c’est indétectable, mais courez lire la FAQ de Kismet et ne faites pas n’importe quoi avec cet outil). Vous allez enregistrer du traffic, puis ouvrez le fichier .dump avec Ethereal. Comme vous pourrez le constater si tout s’est bien passé, tout le traffic à l’exception des requêtes ARP, des beacon frames et des acknowledgement frames est chiffré. Magnifique ? Bof, passez à la suite.

Et maintenant, faisons-nous peur

Sur le client, changez l’adresse IP de l’interface WiFi, remettez au besoin la route par défaut en place, purgez les SA et les SP éventuellement encore en place (setkey -F && setkey -FP), arrêtez Racoon, puis faites un ping vers un site web quelconque. Eh oui, les paquets passent sans soucis le routeur et, comme vous le confirmera un tcpdump, ils ne sont pas chiffrés.

IPSec protège le traffic qui lui a été demandé de protéger, à condition que le client et le routeur (dans notre cas) le veuillent. Jamais nous n’avons dit que du traffic non chiffré devrait être interdit. Dure vie d’admin. Comme tout ce qui implique le filtrage de traffic réseau, netfilter est notre solution, mais il va falloir patcher.

Protéger l’accès aux ressources

En fonction de votre version du noyau, vous aurez peut-être besoin d’appliquer des patchs. La vérification est facile : si votre version est supérieure ou égale à 2.6.16, tout ce que vous aurez à faire, c’est compiler au besoin les modules. Sacré veinards, vous n’aurez pas à lire la section suivante sur les patches. Pour les autre, lisez bien ce qui suit.

Patcher son noyau (

<=>

ftp://ftp.netfilter.org/pub/patch-o-matic-ng/snapshot]. Les fichiers sont nommés en fonction de leur date de création, et c’est une nightly.

Téléchargez la bonne archive et décompressez-la. Dans le répertoire créé, chercher ceux qui corrrespondent aux patches mentionnés ci-dessus. En fonction de votre version du noyau, vous devrez utiliser différents fichiers, mais il n’y a rien de très violent là dedans.

Un petit souci se pose pour le patch policy : il contient deux fichiers, kernel.ladd et Makefile.ladd, qu’il faut rajouter à ceux présents (même nom mais sans l’extension .ladd) dans les bons répertoires du noyau. La méthode la plus simple pour ce patch est de copier tout le répertoire au bon emplacement dans les sources du noyau, puis d’utiliser cat pour concaténer les fichiers.

Compiler son noyau
Rien de bien méchant là dedans, vous pouvez procéder comme d’habitude, en pensant bien à rajouter les éléments netfilter dans la compilation.

Vérifier son iptables
Pour que la suite fonctionne correctement, iptables doit intégrer le support des policies. Pour le vérifier, recherchez un fichier nommé « libipt_policy.so » (placé dans /lib/iptables sous Debian par exemple). Un coup de find / -name 'libipt_policy.so' devrait le faire

Les règles iptables

Bien, passons maintenant aux règles iptables. Dans un fichier lancé au démarrage, ou mieux dans votre script qui va mettre en route votre firewall, rajoutez ces règles (l’explication des variables suit) :

iptables -A INPUT -i $WIFI_IF -p udp --dport 500 -j ACCEPT
iptables -A OUTPUT -o $WIFI_IF -p udp --dport 500 -j ACCEPT
# Bug iptables ?
iptables -A INPUT -i $WIFI_IF -p esp -j ACCEPT
iptables -A INPUT -i $WIFI_IF -m policy --dir in --pol ipsec
--mode tunnel --proto esp -j ACCEPT
iptables -A OUTPUT -o $WIFI_IF -m policy --dir out --pol ipsec
--mode tunnel --proto esp -j ACCEPT
iptables -A FORWARD -i $WIFI_IF -m policy --dir in --pol ipsec
--mode tunnel --tunnel-dst $WIFI_IP --tunnel-src $WIFI_NET
--proto esp -j ACCEPT
iptables -A FORWARD -o $WIFI_IF -m policy --dir out --pol ipsec
--mode tunnel --tunnel-src $WIFI_IP --tunnel-dst $WIFI_NET
--proto esp -j ACCEPT

$WIFI_IF est le nom de l’interface réseau wireless.
$WIFI_IP est l’adresse IP de cette interface réseau.
$WIFI_NET est l’adresse du réseau que sert cette interface avec le masque (par exemple 192.168.1.0/24).

Comme l’indique le commentaire ’# Bug iptables ?’, j’ai rencontré un souci avec une connection IPSec qui commençait à dater. Mes soupçons se portent sur un problème de renouvellement des SP non pris en compte par iptables. Cette ligne résolvant le souci, je n’ai pas poursuivi mes investigations (en plus le sommeil commençait à m’appeler).

Note importante

À cause de l’encapsulation des paquets par IPSec, la taille des paquets IP que l’on peut recevoir est limitée à 1444 octets. Or, une interface réseau a un MTU (maximum transfert unit) par défaut fixé à 1500, ce qui oblige la passerelle à émettre des paquets ICMP pour demander au correspondant de réduire la taille des paquets qu’il renvoie (MTU discovery, couvert par la RFC 2923).

Notre souci est qu’il existe de par le web des routeurs / firewalls / switch configurés n’importe comment, et surtout en désaccord avec ce que préconise cette RFC, qui bloquent ces paquets ICMP de demande (essayez sur le site de consultation d’horaires de la SNCF, vous comprendrez très vite avec un tcpdump). Bilan : le service est inaccessible. Solution : descendre sur les postes clients le MTU de l’interface WiFi à 1444, en modifiant les scripts de démarrage réseau (il suffit sous Debian de rajouter mtu 1444 dans le paramétrage de l’interface réseau (/etc/network/interfaces)).

Conclusion

J’espère que ce tutoriel vous a été utile et que vous ne rencontrerez pas tous les problèmes que j’ai essayé de résoudre et dont la synthèse se trouve dans ce tutoriel. Peut-être qu’il existe des manières plus simples de mettre en place un réseau WiFi sécurisé avec IPSec sous Linux et si vous en connaissez, n’hésitez pas à me contacter par mail. Pareil si vous avez des problèmes non-couverts par ce document.

Liens

Merci à tous ces auteurs.

Documents téléchargeables :

client_racoon.conf

routeur_racoon.conf

script_routeur