07/06/2014: On vous dit tout ce que l’on sait du #bug2505
A l’heure où nous écrivons ces lignes, le rapport du Collège des experts n’est pas encore publié (et sera publié trop tard pour les recours). Ses membres sont d’ailleurs tenus au secret.
Les seules informations dont l’ensemble des citoyens et des candidats du pays disposent sont les explications parcellaires du Ministère de l’Intérieur.
Certains membres de bureaux principaux et témoins de partis ont eu un peu plus d’informations, qui parfois tombent dans les mains de journalistes.
Mais la plupart des candidats qui voudraient introduire un recours sont assez démunis et les informations parcimonieusement délivrées sont factuelles.
Sur base des informations disponibles et surtout sur base du code source des élections 2014, nous allons essayer de vous expliquer le bug d’une façon accessible aux non-informaticiens mais avec suffisamment de précision pour que les informaticiens puissent aller voir par eux-même.
MISES À JOUR :
- 9 JUIN 2014 7H30 - Nous avons peut-être inversé petit et grand numéro de liste dans nos explications/conclusions
- 9 JUIN 2014 10H10 - Nous avons adapté l’explication pour correspondre à l’image animée
- 10 JUIN 2014 11H30 - Nous avons eu de l’aide supplémentaire et une relecture de l’article par un chercheur en sécurité informatique. Les conclusions restent toujours les mêmes, le bug n’est pas neutre et certaines listes sont plus défavorisées que d’autres
Comme expliqué précédemment, le code source des systèmes de vote électronique est une version de Stésud pour les systèmes JITES et DIGIVOTE développée en 2006, mise à jour en 2012 et dans laquelle la présentation d’écran et la possibilité de désélection d’un vote de préférence ou d’un vote en case de tête a été reprise du code des élections de 2010.
Tel qu’annoncé, le bug s’est glissé dans cette mise à jour, et se présente lorsque l’électeur :
- sélectionne une première liste
- dans cette liste sélectionne un ou plusieurs candidats (ou suppléants) et/ou la case de tête
- désélectionne tous les candidats et le vote en case de tête (s’il y a lieu)
- change de liste en cliquant sur le bouton prévu à cet effet (bouton qui n’apparaît que lorsque l’électeur désélectionne son premier choix)
Pour être plus précis, à la lecture du code source, nous pensons que :
- dans ce cas, pour ce vote et pour ce vote uniquement, le programme n’efface pas de sa mémoire la sélection de cette liste
- si une autre liste est finalement sélectionnée, et que cette liste se trouve moins loin dans le tableau, alors, cette dernière volonté de l’électeur n’est pas enregistrée sur la carte magnétique et seule la première intention non aboutie est enregistrée de façon incohérente : en effet le nom de cette liste est enregistré mais sans vote de préférence NI vote de tête
Passons aux choses sérieuses, si vous voulez voir de vos propres yeux et si vous comprenez le langage de programmation C, il vous faut d’abord télécharger le logiciel.
- Code source du vote par carte magnétique
- http://www.verkiezingen.fgov.be/fileadmin/user_upload/Elections2014/FR/Electeurs/en_pratique/soft/jites.zip
Cette archive contient beaucoup de choses, y compris un compilateur Borland C, et au moins 4 programmes faisant partie du système JITES :
- PREP est le programme de préparation des disquettes et qui fabrique le fichier de données spécifiques à chaque bureau de vote contenant les listes et les candidats
- MAV est le programme qui nous intéresse et qui s’exécute sur les machines à voter, c’est lui qui contient le bug
- URN est le programme qui s’exécute dans l’ordinateur du président de bureau de vote et/ou l’urne électronique, et qui lit les cartes magnétiques et inscrit les votes sur une ou plusieurs disquettes
- TOT est le programme qui au niveau du bureau de totalisation reçoit les disquettes de différents bureaux de vote et totalise les votes pour obtenir le résultat final de l’élection pour ce canton
Il existe un dernier programme, nommé CODI, qui sert à transmettre les résultats au Ministère de l’Intérieur.
Le programme et le code qui nous intéressent se trouvent dans le répertoire \Jites\URN_MAV\SOURCES\C\Mav de Jites.zip.
Pour bien comprendre le bug, il faut comprendre la structure de données que l’interface utilisateur remplit :
- extern char arcMemoCandid[NB_MAX_SCRUT][NB_MAX_LISTS][NB_MAX_CANDID] ;
- extern char arcMemoList[NB_MAX_SCRUT][NB_MAX_LISTS] ;
- extern char arcMemoScrutin[NB_MAX_SCRUT] ;
Dans le code il y a donc :
- arcMemoScrutin un tableau à une dimension des scrutins
- arcMemoList un tableau à deux dimensions des listes (par scrutin)
- arcMemoCandi un tableau à trois dimensions des votes de préférence (par liste et par scrutin)
L’idée est que si pour le scrutin 1 on vote liste 3 et les candidats 5 et 7 alors voici ce que la structure de données doit contenir (tout le reste est à zéro) :
- arcMemoScrutin[1]=1 ;
- arcMemoList[1][3]=1 ;
- arcMemoCandi[1][3][5]=1 ;
- arcMemoCandi[1][3][7]=1 ;
Une fois tous les votes validés, une autre partie du logiciel se charge d’encoder le contenu de ces structures sur la carte magnétique. Et en particulier le programme parcourt l’ensemble des listes de chaque scrutin, retient celle qui n’est pas à zéro (voir ligne 302 de MOD_SCRU.C) et encode le vote en case de tête et/ou les votes de préférence de cette liste pour ce scrutin.
for(y = 0 ;y < atoi(gshScrutin[i].nbrelist_s) ;y++)
if(arcMemoList[i][y] == 1) iList = y + 1 ;
Le problème est que si l’électeur désélectionne lui-même les candidats 5 et 7 puis change de liste on obtient bien :
- arcMemoCandi[1][3][5]=0 ;
- arcMemoCandi[1][3][7]=0 ;
Mais à cause du bug, deux autres valeurs ne sont pas remises à zéro :
- arcMemoScrutin[1] <= ceci n’est pas très grave car on va choisir une autre liste
- arcMemoList[1][3] <= Là c’est grave car on peut croire que l’électeur vote pour la liste 3 alors qu’il vient justement de demander à voir l’ensemble des listes pour peut-être en choisir une autre.
S’il en choisit une autre, on se retrouve avec deux éléments du tableau arcMemoList[1] non nuls, ce qui signifie un vote pour deux listes différentes, ce qui est bien sûr impossible.
A partir de là, il y a deux scénarios principaux de part la manière dont le programme parcourt le tableau et retient le vote de l’électeur :
- L’électeur choisit une liste avec un numéro de liste plus grand, alors pas de problème, c’est bien ce choix qui sera encodé sur la carte magnétique
- L’électeur choisit une liste avec un numéro de liste plus petit et là, catastrophe, ni sa liste, ni ses votes de préférence ne sont enregistrés sur la carte magnétique
Le bug n’est pas politiquement neutre car les listes avec les plus petits numéros sont pénalisées par rapport aux autres.
En apparence, si on décide d’annuler toutes les cartes où le bug a été détecté, on annule plus de votes pour des listes avec des grands numéros.
Mais ces votes étaient de toutes manière indûs puisque l’électeur ne voulait plus voter ces listes. Le vote correct (dernière volonté de l’électeur) avec un petit numéro est quant à lui définitivement perdu.
Attention nous avons adapté de nombreux paragraphes en italique ci-dessus pour correspondre fidèlement avec la vidéo suivante et aux explications de son auteur. Nous avons en effet reçu une aide précieuse et une image au format GIF animé fabriquée à partir d’un portage sous Linux du programme JITES. Celui-ci montre pour l’élection européenne à Eupen que si on sélectionne d’abord le SP (liste 10) puis que l’on déselectionne pour changer de liste vers Ecolo (liste 9), alors ce qui est "mal" enregistré sur la carte est un vote pour le SP (sans aucune sélection, ni case de tête ni vote de préférence) et il n’y a aucun enregistrement pour Ecolo :
- Gif animé démonstration du bug
Ceci tend à indiquer que nous avions initialement inversé dans notre explication les petits et les grands numéros de liste.
Selon l’auteur du portage, un des problèmes pour qu’un citoyen puisse vérifier par lui-même le code source est que nous ne disposons pas des fichiers officiels de configuration de l’élection (par exemple machvotc.tbl machvotl.tbl et machvots.tbl) avec l’ordre des listes tel qu’utilisé (mais aussi les noms des candidats, les logos officiels, etc). Il est également difficile de compiler et d’utiliser le logiciel PREP car celui-ci est écrit dans le langage "Gupta SQLWindows Team Developer 2005". Mais quoi qu’il en soit, le bug n’est pas politiquement neutre dans les votes qu’il ne prend pas en compte, et l’annulation de ces votes n’est pas neutre non plus.
Voici finalement une toute petite ligne de code qu’un informaticien de PourEVA propose de rajouter entre les lignes 702 et 703 pour corriger le bug, cette façon de corriger de corriger le problème a été vérifiée de façon indépendante [1] :
- Cancel_Selection(giCurrentScr,giCurrentList,1) ;
Cette ligne de code est utilisée dans d’autres cas d’annulation du choix de l’électeur en ligne 664 pour les élections de 2014.
En fait ce n’est pas la fonction Cancel_Selection qui nous intéresse pour la désélection de tous les candidats... car le citoyen-utilisateur a déjà désélectionné manuellement toutes les sélections de l’écran. C’est ce qui est fait dans cette fonction aux lignes 586 et 587 pour effacer toute trace du choix que l’électeur veut annuler en changeant de liste que nous voulons réutiliser :
- arcMemoScrutin[x] = 0 ;
- arcMemoList[x][y] = 0 ;
Nous ne comprenons pas comment PwC et le Ministère de l’Intérieur n’ont pas détecté ce problème dans leurs tests.
Mais il reste à comprendre comment le programme de totalisation, puis les experts, ont bien pu détecter ce problème et s’ils ont pu identifier tous les votes "à problème".
L’animation nous montre que si l’électeur voulait réintroduire sa carte et visualiser son vote il se serait rendu compte de l’erreur d’encodage de sa carte.
Pour ce qui est de la détection, nous pensons que c’est le programme TOT de totalisation (et non comme annoncé par le Ministère le programme CODI de transfert des résultats) qui a dû détecter le problème. En effet, TOT est le programme qui lit les disquettes les unes après les autres et qui a dû en refuser l’une ou l’autre par bureau de totalisation.
Pour comprendre la détection, il faut savoir que dans le calcul de répartition des sièges, on distingue les votes en case de tête uniquement et les votes avec une ou plusieurs préférences. Un bulletin pour une liste (donc non blanc) ne peut être qu’en case de tête ou pour des candidats de préférence. La somme des bulletins en case de tête et en vote de préférence doit être égale au nombre de votes pour la liste. Avec le bug, on a des votes pour une liste qui ne sont ni l’un, ni l’autre... en fait, ils ne sont même pas pour cette liste.
Pour détecter sur les disquettes la présence de ce genre de vote, c’est assez simple et on est certain de ne pas en rater.
L’erreur aurait d’ailleurs pu être détectée bien avant TOT pour autant que les développeurs aient pris la peine d’inclure quelques routines de vérification :
- dans MAV au moment de l’écriture
- dans MAV au moment de la visualisation d’une carte réintroduite (la relecture montre un écran incohérent à l’électeur plutôt qu’une alerte)
- dans URN au moment de la lecture de la carte
Pour ce qui est des votes blanc, voter blanc revient à choisir une liste avec le plus petit numéro possible, donc voter blanc, revenir et choisir une liste n’affectera jamais le vote, par contre voter pour une liste, revenir et voter blanc déclenchera le bug et reviendra à un vote pour la liste mais mal encodé. Donc dans ce cas précis et uniquement dans ce cas, l’annulation n’est pas un problème puisque blanc et nul c’est mathématiquement la même chose.
Si vous avez trouvé notre explication utile et éclairante, vous conviendrez avec nous qu’il est regrettable que l’explication officielle du Ministère de l’Intérieur soit si peu claire sur les conséquences du bug et ne rassure pas sur sa portée. Il est également dommage que les Collèges des experts n’aient pas pu, eux aussi, rassurer ou au moins donner rapidement un avis "neutre" sur la situation.
[1] Cette correction peut-être testée dans la branche fix du portage sous Linux de JITES