Avec l'arrivée de TLS v1.2 dans OpenVPN >= 2.3.3, je me suis demandé si l'on pouvait changer les algos cryptos et la version de TLS utilisés sans pour autant dégager les vieux clients utilisateurs de notre VPN.
Commençons par le canal de contrôle, c'est-à-dire le canal primaire de communication entre un serveur et un client OpenVPN sur lequel sont échangées, entre autres, les clés de chiffrement symétrique. Ce canal est protégé avec toute la crypto asymétrique, TLS et les certificats x509 que l'on connaît. Que peut-on changer ?
* Si l'on utilise easy-rsa (toolkit d'OpenVPN pour simplifier la création/gestion/maintenance des clés/certificats), les clés générées sont des RSA 2048 bits (sous Debian). L'ANSSI, via son référentiel général de sécurité (RGS, voir http://www.ssi.gouv.fr/entreprise/regle … rgs-v-2-0/ document B1) indique que 2048 bits est le minimum aujourd'hui pour des clés RSA et que 3072 bits sont recommandés. On remarquera les mêmes conseils du côté de la NSA (https://www.nsa.gov/ia/programs/suiteb_ … ndex.shtml). Pour changer cela, c'est la variable « KEY_SIZE » dans le fichier « vars » d'easy-rsa. Ça se fait sans douleur pour les anciens utilisateurs du VPN qui continueront à utiliser leur matériel cryptographique actuel jusqu'à son expiration. Les nouveaux utilisateurs auront directement une clé RSA 3072 ou 4096 bits.
* On voudrait SHA-256 comme fonction de hachage cryptographique utilisée pour la signature des certificats de nos utilisateurs VPN car SHA-1, même s'elle n'est pas cassé ne répond plus aux attentes standards et n'est d'ailleurs pas conforme au RGS. De plus, c'est ce que l'on observe sur le marché des certificats x509 : Microsoft et Google ne veulent plus de certificats signés avec SHA-1 à partir de 2016-2017. Easy-rsa signe déjà les certificats avec SHA-256 donc il n'y a rien à faire. \o/
* Oui mais si on augmente la taille des clés des utilisateurs, ne devrait-on pas aussi augmenter celui de l'AC ? En effet, pour que ce soit cohérent, il faut aussi faire ça. Il faut, là aussi, changer la variable « KEY_SIZE » dans le fichier « vars » d'easy-rsa MAIS cela se fera dans la douleur puisqu'il faudra re-générer le certif' d'AC et donc resigner (ou regénérer) tous les certificats (server, utilisateurs) et transmettre les nouveaux certificats aux utilisateurs.
* Pour garantir la confidentialité persistante (perfect forward secrecy u know), il est important de ne pas avoir des paramètres de Diffie-Hellman moisis. Normalement, on génère des paramètres et on utilise la directive « dh » dans la config' OpenVPN. Il est nécessaire de le faire, surtout depuis logjam. C'est toujours la même chose : lorsqu'on parle de RSA, l'ANSSI recommande 3072 bits et la NSA indique 3072 bits minimum. On peut facilement changer cela pour 3072 ou 4096 sans impact sur les utilisateurs mais en demandant un temps de calcul plus long côté serveur lors de l'initialisation. Dans son log, le serveur indiquera « Diffie-Hellman initialized with 4096 bit key » au tout début de son initialisation.
* On voudrait utiliser TLS v1.2 au lieu de TLS v1.0. TLS v1.0 a un certain nombre d'attaques possibles en jouant sur la compression, le padding, la faiblesse des suites cryptographiques en mode bloc (CBC), les attaques par repli,... Tout cela est corrigé dans TLS v1.2. De plus, TLS v1.2 apporte de nouvelles suites cryptographiques plus balèzes. TLS v1.2 est pris en charge à aprtir d'OpenVPN 2.3.3. L'ennui, c'est que la version de TLS qui sera utilisée n'est pas négociée comme dans les autres usages de TLS (web, mail,...) : il faut préciser « tls-version-min 1.2 » dans la conf' du serveur ET du client (merci à http://www.timdoug.com/log/2014/05/30/). Les clients dont la version est inférieure à 2.3.3 auront un reset de la connexion et les logs côté serveur indiqueront « TLS_ERROR: BIO read tls_read_plaintext error: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol ». La négociation de la version de TLS revient dans OpenVPN 2.3.7 (voir https://community.openvpn.net/openvpn/w … nOpenvpn23). En attendant, j'estime qu'il n'est pas possible d'utiliser TLS v1.2 sans perdre des utilisateurs.
* On voudrait être sûr de ne pas utiliser des suites cryptographiques trouées. Par défaut, OpenVPN utilise cette liste quand il est utilisé avec OpenSSL : « DEFAULT:!EXP:!PSK:!SRP:!kRSA » (voir https://community.openvpn.net/openvpn/w … 23ManPage, paramètre « --tls-cipher »). De cette liste, il convient de virer les suites moisies qui utilisent DSS comme méthode d'authentification ou DES/3DES/RC4 comme algos de chiffrement symétrique. Nous voulons activer la confidentialité persistante donc nous devons supprimer les suites cryptos qui ne reposent pas sur Diffie Hellman Ephémaire pour l'échange des clés. OpenVPN semble de pas utiliser les courbes elliptiques (voir le contenu pointé par ce shaarli). De plus, nous utilisons des clés RSA donc l'échange de Diffie-Hellman sera forcément de type RSA donc nous pouvons virer les suites cryptos qui utilisent ECDHE comme protocole d'échange de clés éphémères. Il reste donc 9 suites répondant à nos exigences que l'on peut lister comme suit : DEFAULT:!EXP:!PSK:!SRP:!kRSA:!DSS:!DES:!3DES!RC4!ECDH. En plus court : EDH+aRSA:!DES:!3DES . Si l'on n'a pas confiance, ou parce qu'AES est le seul accéléré matériellement de nos jours, on peut ne pas utiliser CAMELLIA et SEED comme algos de chiffrement symétrique et la liste de suites cryptos devient donc : « EDH+AES+aRSA ». Il nous reste donc 6 suites : DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-SHA256 DHE-RSA-AES256-SHA DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-SHA256 et DHE-RSA-AES128-SHA. On ne peut pas virer les suites utilisant SHA-1 puisque les suites plus fortes arrivent uniquement avec TLS v1.2... qui n'est pas activable sans casse à l'heure actuelle, voir le point précédent ainsi que le contenu pointé par ce shaarli. Depuis que j'utilise OpenVPN depuis de nombreuses années, la suite cryptographique utilisée automatiquement a toujours été « DHE-RSA-AES256-SHA » qui, à part SHA-1, est clairement satisfaisante. Néanmoins, afin d'éviter tout problème, je précise désormais « tls-cipher EDH+AES+aRSA » dans mes confs client et serveur. Cette fois-ci, la liste est négociée de manière tout à fait standard donc on ne cassera très probablement aucun client qui arrivait à se connecter avant. Testé sous Debian GNU/Linux Wheezy et Android 4.2 avec OpenVPN for Android disponible sur F-Droid.
Résumons ce que nous pouvons, ou non, changer sur le canal de contrôle :
* Utiliser des clés RSA >= 3072 bits comme le recommande le RGS : possible facilement sans impact sur les utilisateurs. On peut migrer doucement chaque utilisateur (ainsi que le serveur OpenVPN lui-même) lors de l'expiration de son certificat actuel. On peut fournir des clés >= 3072 bits aux nouveaux utilisateurs. Tout ça sans douleur.
* Easy-rsa utilise déjà SHA-256 pour la signature des certificats donc nous n'avons rien à changer.
* Utiliser des clés RSA >= 3072 bits comme le recommande le RGS pour l'AC : possible mais cela nécessite de casser tous les certificats de tous les utilisateurs actuels et donc de leur communiquer leur nouveau certificat.
* Utiliser des paramètres de Diffie-Hellman >= 3072 bits comme le recommande le RGS : possible facilement sans impact sur les utilisateurs. Il suffit de générer de nouveaux paramètres.
* Utiliser TLS v1.2 : pas possible à l'heure actuelle sans impacter les utilisateurs sauf à considérer qu'ils utiliseront tous une version >= 2.3.7 d'OpenVPN. Ce qui n'est pas le cas dans Debian Jessie, par exemple.
* Être sûr de ne pas utiliser des suites cryptos trouées : possible facilement sans impact sur les utilisateurs. C'est déjà le cas par défaut mais pour être sûr qu'une mauvaise suite ne sera pas choisie, on peut toujours resteindre leur nombre.
Continuons avec le canal de données dans lequel circule le trafic à proprement parler. Ce canal est protégé par toute la crypto symétrique que l'on connaît. Que peut-on changer ?
* L'algorithme de chiffrement symétrique utilisé. Même dans OpenVPN 2.3.X, c'est encore Blowfish qui est utilisé par défaut alors que son concepteur, Schneier (oui oui, c'bien lui) a déclaré, en 2007 (!) : « There weren't enough alternatives to DES out there. I wrote Blowfish as such an alternative, but I didn't even know if it would survive a year of cryptanalysis. Writing encryption algorithms is hard, and it's always amazing if one you write actually turns out to be secure. At this point, though, I'm amazed it's still being used. If people ask, I recommend Twofish instead. ». De plus, Blowfish utilise une taille de bloc de 64 bits alors que l'ANSSI préconise 128 bits minimum. Pour voir les algos disponibles, la commande est : openvpn --show-ciphers. Une fois qu'on vire les mauvais algos et ceux plus recommandés, il reste AES, CAMELLIA et SEED. Ma confiance va dans AES qui est plus utilisé (donc plus audité, scruté, attaqué, cryptanalysé, plusieurs implémentations,...). Pour changer d'algorithme, il faut utiliser la directive de configuration « cipher » (exemple : « cipher AES-128-CBC »). Cet ajout doit être fait sur le serveur ET le client car l'algo à utiliser n'est pas négocié entre les deux parties. C'est une contrainte forte : il faut poser un flag day et dire aux utilisateurs "à partir de tel jour, on utilisera ça et ça cassera votre VPN tant que vous ne ferez pas la modif' dans votre fichier de conf'". Ça ne dégage pas les vieux clients ni les clients multiplateformes : j'ai testé sur mon ordiphone (avec OpenVPN for Android disponible sur F-Droid sur un Android 4.2) et sur un Debian GNU/Linux Wheezy.
* La fonction de condensation utilisée pour assurer l'intégrité des données transmises. Par défaut, SHA-1 est utilisée. Comme je l'ai écrit plus haut, même si elle n'est pas cassée, elle commence à être dépréciée un peu partout (l'ANSSI veut SHA256 minimum, la NSA veut du SHA384 minimum). Pour voir les algos disponibles, la commande est : openvpn --show-digests. Une fois qu'on a viré les algos troués (MD4/MD5/SHA) et les algos plus recommandés (SHA-1/RIPEMD160), il ne reste que la famille SHA-2 et whirlpool. Comme pour AES versus CAMELLIA/SEED, whirlpool étant moins utilisé, ma confiance va dans SHA-256. Pour changer de fonction de condensation, il faut utiliser la directive de configuration « auth » (exemple : « auth SHA256 »). Cet ajout doit être fait sur le serveur ET le client car l'algo à utiliser n'est pas négocié entre les deux parties. C'est une contrainte forte : il faut poser un flag day et dire aux utilisateurs "à partir de tel jour, on utilisera ça et ça cassera votre VPN tant que vous ne ferez pas la modif' dans votre fichier de conf'". Ça ne dégage pas les vieux clients ni les clients multiplateformes : j'ai testé sur mon ordiphone (avec OpenVPN for Android disponible sur F-Droid) et sur un Debian GNU/Linux Wheezy.
Résumons ce que vous pouvons ou non changer sur le canal de données :
* Ne plus utiliser Blowfish comme algo de chiffrement symétrique car il n'est plus recommandé par son auteur et ne respecte pas les préconisation de l'ANSSI sur la taille des blocs : possible facilement mais cela nécessite d'imposer un flag day aux utilisateurs existants de notre VPN puisqu'ils doivent modifier leur configuration en même temps que celle du serveur.
* Ne plus utiliser SHA-1 qui n'est pas cassée mais est dépréciée un peu partout : possible facilement mais cela nécessite d'imposer un flag day aux utilisateurs existants de notre VPN puisqu'ils doivent modifier leur configuration en même temps que celle du serveur.
Une dernière amélioration générale est de ne plus utiliser SHA-1 comme l'un des algos utilisés par OpenVPN pour générer des nombres pseudo-aléatoires. Il s'agit de la directive « prng » : « prng sha256 16 ». 16 représente le nombre d'itérations. C'est la valeur par défaut et il ne me semble pas intéressant de la changer. Ce changement s'effectue sur le client et le serveur, sans impact sur l'un comme sur l'autre.
Bon, OK, on a vu quoi changer. Mais ces algos plus sécurisés sur le canal de données ont un coût en performance (les changements sur le canal de contrôle affectent uniquement l'initialisation de la communication). Est-ce que ce coût est viable *dans la pratique* ?
Pour ce faire, j'ai monté une VM de test sur l'infra d'ARN, FAI associatif en Alsace. Même configuration : RAM, nombre de procs, Debian GNU/Linux Jessie que la VM VPN de production.
Je n'utilise pas les directives de configuration « fragment » et « mssfix » qui ont un impact sur les performances (voir https://community.openvpn.net/openvpn/w … orks_Linux). C'est sur ce dernier point que mon test n'est pas conforme à ce que nous avons déployé chez ARN : nous utilisons fragment 1300 et mssfix afin de prendre en charge les abonnés pour lesquels la découverte de la MTU ne fonctionne pas (et il y en a) et qui ne peuvent donc pas utiliser notre VPN. Le reste de la configuration OpenVPN est conforme au VPN de production.
J'ai fait trois types de tests :
* Latence aller-retour en couche 3 avec un bête ping -c 100 -i 0.2 sur l'IP de l'endpoint VPN (celle à l'intérieur du VPN hein).
* Téléchargement d'une vidéo depuis deux gros hébergeurs français (Online et OVH) en IPv4, en utilisant le protocole HTTP, une seule connexion simultanée. Pas de CDN et autres.
* Téléchargement de 25% de l'iso du premier DVD de Debian GNU/Linux Jessie amd64 en IPv4, via Bittorrent. Intérêt ? Le test HTTP dépend beaucoup de la qualité et de la saturation de l'interconnexion entre les prestataires (ici entre Online/OVH d'un côté et Cogent de l'autre car ARN est uniquement accroché sur Cogent à l'heure actuelle). Au contraire, Bittorrent suppose plein d'émetteurs du même contenu dispersés chez plein d'opérateurs réseau. On a donc plusieurs interconnexions et toutes ne sont pas mal entretenues / saturées en même temps.
J'ai effectué 2 tests de chaque (séparés de 30 minutes), depuis ma connexion Internet fixe habituelle chez NC, avec mon laptop habituel, tôt ce matin (8h-10h) pour éviter les congestions. Aucun autre trafic ne sort de ma machine durant les tests, of course (Netfilter veille au grain). J'ai changé d'IP de sortie entre chaque test Torrent. Pourquoi ? Car, lors de pré-tests, j'ai mis en évidence que les peers me reconnaissaient et ne sont pas enclins à me refiler les mêmes morceaux d'un même fichier x fois d'affilé d'où un débit artificiellement moindre.
Résultats :
* Moyenne des tests latence avec Blowfish + SHA1 : 25,6 ms ; Moyenne des maximums : 29,8 ms ;
* Moyenne des tests latence avec AES-128-CBC + SHA256 : 25,7 ms ; Moyenne des maximums : 33,9 ms ;
* Note : la variation des minimums est infime, d'où leur absence dans ce shaarli.
* Moyenne des tests HTTP avec Blowfish + SHA1 : 3,5 mo/s
* Moyenne des tests HTTP avec AES-128-CBC + SHA256 : 5,3 mo/s
* Moyenne des tests torrent avec Blowfish + SHA1 : 6,4 mo/s
* Moyenne des tests torrent avec AES-128-CBC + SHA256 : 4,2 mo/s
* Dans tous les cas, nous ne sommes pas CPU-limited. Ni sur mon laptop, ni sur la VM d'ARN. Cette dernière voit le taux d'occupation de son unique CPU virtuel passer de 40-45% avec Blowfish + SHA-1 à 25-35% (oui, c'est plus dispersé et plus faible) pour AES-128-CBC + SHA256.
Mon interprétation : AES a toujours été plus gourmand qu'AES, c'est un fait. Sur des téléchargements depuis une seule source (HTTP), la fluctuation de la qualité des interconnexions est plus couteuse que l'impact du renforcement de la crypto compte tenu des interconnexions entre ARN et les autres opérateurs. En revanche, sur Bittorent, on voit que la crypto a un coût, qui peut être perçu comme étant non négligeable, selon les points de vue.
Comment expliquer la différence entre téléchargement over HTTP ou over Bittorrent ? Je n'ai pas de réponse.
* De mes mesures (avec Wireshark, menu Statistics), à vitesse moyenne identique (rate-limite dans le client BT pour s'adapter à la vitesse de téléchargement over HTTP), le téléchargement HTTP fait une moyenne de 2065 paquets par seconde là où le téléchargement via Bittorrent fait 3094 pps. Au-delà d'un certain stade, les switchs entre userland et kerneland deviennent-ils trop consommateurs et brident-ils le débit ?
* De mes mêmes mesures, le téléchargement HTTP a une taille moyenne de paquet de 810 octets là où le téléchargement via Bittorrent a une moyenne à 655 octets par paquet. Or, la taille des paquets, a un impact sur les algos de chiffrement : « The reason behind this is that by feeding larger packets to the OpenSSL encryption and decryption routines the performance will go up. » (https://community.openvpn.net/openvpn/w … rks_Linux, encore).
Je ne suis pas inquiet pour les utilisateurs mobiles : les ordiphones/tablettes ARM disposent de l'accélération matérielle et vu les débits des connexions WiFi et mobiles, ça passera. Il faudrait faire des tests sous winwin, au cas où...
++> https://community.openvpn.net/openvpn/wiki/Hardening