Sécurité logicielle des cartes à puce

Un article de Wikipédia, l'encyclopédie libre.

Les cartes à puces présentent comme tout système informatiques nombre de failles de sécurité. La majorité d'entre elles étant basée sur une architecture java, elles peuvent présenter des failles de sécurité aussi bien au niveau de la protection cryptographique des données que de l'architecture logicielle de la machine Java utilisée.

En effet, un certain nombre de données doivent être protégées de l'extérieur via des mécanismes de cryptographie. C'est pourquoi les constructeurs et les chercheurs ont imaginé diverses parades contre les attaques qui peuvent être portées contre ces cartes à puces. Ces attaques peuvent être de types divers et attaquer aussi bien la donnée cryptée frontalement qu'en essayant de dévoyer le fonctionnement de la carte pour contourner ces mesures de protections.

Les cartes à puces reposant sur une architecture logicielle, il peut exister certaines failles dans le code des applications intégrées à la carte. Là encore des séries de mesures de protections sont ou peuvent être intégrées afin de combler les failles pouvant être exploitées par des utilisateurs mal intentionnés. En exploitant ces différentes failles, il est possible par exemple de dérober des données, de détourner le fonctionnement normal de la carte, voire de la rendre inopérante.

Il est donc fondamental de connaître et de corriger les différentes failles, afin de protéger au mieux les données sensibles et de garantir le bon fonctionnement de ces cartes à puces.

Problématique de sécurité logicielle[modifier | modifier le code]

Carte bancaire, carte d’identité[1], passeport, carte SIM … la liste est grande mais toutes ont un point commun, celui de contenir des données sensibles qui ne doivent être fournies par la puce qu’à des personnes et/ou logiciels autorisés. Ces cartes doivent donc être sécurisées aussi bien d’un point de vue physique que d’un point de vue logiciel. C’est ce dernier point que nous allons explorer ici.

Attaques cryptographiques[modifier | modifier le code]

Les attaques cryptographiques consistent à essayer de décrypter les mots de passe, les instructions et les processus contenus dans la carte à puce en exploitant soit des algorithmes de déchiffrage, soit les répercussions matérielles de ces données[2].

Analyse de consommation simple ou différentielle[modifier | modifier le code]

Selon l'instruction exécutée, le microprocesseur de la carte à puce peut dissiper différentes quantités d’énergies. Une analyse de consommation simple permet donc de donner des informations sur les algorithmes utilisés dans la carte à puce comme une séquence d’instructions. Le SPA est utilisé pour déduire l’implémentation de l’algorithme cryptographique utilisé dans la carte à puce. Dans une attaque SPA, un attaquant observe directement la consommation électrique du système. La quantité d’énergie consommée varie selon l’instruction exécutée dans le microprocesseur. Grâce à cette variation, les grandes fonctions comme les itérations de DES, les opérations de RSA, … peuvent être identifiées. Non seulement les séquences d’instructions peuvent être identifiées mais aussi les instructions individuelles. Dans le cadre d'un algorithme RSA, une attaque SPA peut faire la différence entre une multiplication et une quadrature. De même, dans quelques implémentations de DES, il y a une différence visible entre une permutation et un décalage[3].

Une analyse différentielle de la consommation est encore plus efficace qu'une analyse de consommation simple, car elle permet en plus d'identifier les bits individuels utilisés dans l’algorithme exécuté. Le fait de révéler chaque bit utilisé donne la possibilité de déduire l’ensemble de clé de chiffrement de l’algorithme. Cette déduction est faite via une analyse statistique de la consommation électrique mesurée pour un grand nombre de calculs avec la même clé de chiffrement[4]. Cette attaque est possible du fait de 3 raisons :

  • L’encodage binaire des données peut avoir pour conséquence que la consommation électrique soit proportionnel au nombre de changements d’états.
  • La transmission des données dans le bus dissipe la chaleur due à la capacité du fil conducteur.
  • L’activité du bus est mesurée par le poids de Hamming des changements d'états.

En l’utilisant sur les cartes à puces, l’analyse différentielle de consommation permet d’extraire facilement les clés de chiffrements tels que ceux de DES (Data Encryption Standard), AES (Advanced Encryption Standard) ou chiffrement à clé publique. Cette facilité ou efficacité d’extraction repose sur la capacité de l’attaquant à générer correctement la différence de signal qui permet la déduction de la clé de chiffrement [5].

Cette attaque utilise les matériels physiques pour exploiter le fonctionnement logique de la carte à puce mais elle ne laisse pas de trace sur la carte. Pour cette raison, elle est classée parmi les attaques non invasives [6]. La mesure statistique peut être effectué à l’aide d’un oscilloscope branché sur le lecteur de carte qui va mesurer la différence de consommation électrique lors du chiffrement d’un message[7].

Attaque par analyse de temps[modifier | modifier le code]

L'attaque par analyse de temps est basée sur la mesure du temps qu’un algorithme peut prendre pour effectuer une opération. Cette mesure peut être faite par un oscilloscope et peut révéler des informations sur la clé secrète. Par exemple, en mesurant soigneusement le temps sur les opérations de chiffrement, un attaquant peut trouver l’exposant fixe de Diffie-Hellman, la factorisation de RSA ou casser les autres systèmes de chiffrement. Si une unité de cryptographie dans la carte est vulnérable, cette attaque est assez simple et nécessite souvent un cryptogramme connu.

Le temps de traitement d’un système cryptographique se différencie légèrement selon les différentes données en entrée. Cette performance dépend généralement à la fois de la clé de chiffrement et des données en entrée. Un attaquant peut exploiter la mesure de temps pour trouver l’ensemble de la clé secrète[8].

Dans le système de RSA ou un système de type Diffie-Hellman, comme pour chaque bit à 0 dans le secret exposant, l’ensemble du processus effectue un modulo supplémentaire qui dépend de quelques valeurs intermédiaires, une corrélation peut être observée entre la variation du temps de mesure dans un groupe d’échantillons et le fait qu’un bit dans l’exposant soit à 0 ou non. En appliquant ce processus plusieurs fois, de plus en plus de bits dans l’exposant peuvent être révélés et finalement l’ensemble de la clé est connu. Dans un système à clé symétrique, cette attaque devient plus compliquée mais reste faisable[9].

Attaques logicielles[modifier | modifier le code]

Les attaques logicielles tentent de déchiffrer les programmes contenus sur la carte à puce en utilisant des failles dans l'architecture logicielle de celle-ci[10].

Introduction de code malveillant[modifier | modifier le code]

Le plus simple moyen d’introduire du code malveillant sur une carte est de créer une application introduisant une faille dans le code et d’installer celle-ci sur la carte[11]. Bien entendu, cette méthode ne marche que sur les cartes ne possédant pas de vérificateur de code[12].

Le mécanisme d’interface échangeable de la carte est une autre manière d’introduire du code. Ce mécanisme autorise les communications entre les applications, c’est-à-dire qu’il référence les différentes instances des interfaces qui peuvent traverser le pare-feu en toute légalité[13]. Pour l’abuser, il suffit de laisser deux applications communiquer entre elles, mais en générant deux définitions différentes de cette interface de communication. Ainsi, une application malicieuse peut réussir à transférer ou à accéder à des données différentes de celles qui lui étaient initialement autorisées.

Par exemple une application “A” partage un tableau d’entier, alors que l’application “B” partage un tableau de binaires. Dans cette configuration, l’application A peut envoyer des entiers dans le tableau de B, ce qui peut générer des comportements aléatoires sur la carte, ou pour une utilisation plus ciblée d'accéder à des données cachées[14].

Le mécanisme de transaction permet la transformation des multiples instructions des différents codes en des opérations atomiques, ce qui permet de revenir au point de départ si jamais l’opération est abandonnée.

short[] array1, array2; // instance fields
...
short[] localArray = null; // local variable
JCSystem.beginTransaction();
array1 = new short[1];
array2 = localArray = array1;
JCSystem.abortTransaction();

Dans cet exemple, il est possible que sur certaines cartes les variables array1 et array2 soit effectivement vides, mais que la variable localArray soit toujours utilisable. Il est ainsi possible en multipliant les opérations de faire perdre la trace de ces opérations par le mécanisme. Et donc après le retour en arrière, des références qui auraient dû être nulles ne sont pas effacées. Donc il est possible de rendre égales des variables de types différents[15].

Détournement de l'utilisation normale d'un tableau[modifier | modifier le code]

La première utilisation est de convaincre l'application via les méthodes décrites précédemment qu'un tableau de binaires est en réalité un tableau d'entiers. Cela permet d’accéder à des cases de tableau deux fois plus grandes.

Read as byte[] 00 01 02 03 04 05 06 07 ...
Read as short[] 0001 0203 0405 0607 ...

Ainsi la case no 1 du tableau d'entiers contiendra les cases no 1 et no 2 du tableau de binaires, et ainsi de suite jusqu’à ce que toutes les valeurs du tableau de binaires soient épuisées, ce qui permettra finalement d’accéder à des binaires appartenant potentiellement à une autre application[16].


Au lieu de tenter de créer une confusion sur le type des tableaux, on peut tenter de décrire des objets en tableau. Ainsi, n'importe quel objet créé par les développeurs peut être décrypté octet par octet et ainsi être modifié le cas échéant. Il est aussi possible d'intervertir les références de deux objets différents, ce qui peut permettre par exemple de donner l'accès a un objet d'une application à une autre comme si c'était un objet de son propre contexte. Beaucoup plus grave, il est aussi possible d'accéder à l'AID (Applet IDentifier) de chaque application[17]. Ce numéro sert à identifier les applications et doit donc rester fixe. Or si une application malveillante accède à ces numéros, elle peut les corrompre et rendre toutes les applications présentes sur la carte inopérantes[18].

Problématique du simulateur[modifier | modifier le code]

Le développement d’application embarquée repose sur l’utilisation de simulateur. En effet ceux-ci s’avèrent très utile pour des développeurs afin de tester leurs codes avant de les déployer sur la plate-forme d’utilisation. Mais ces simulateurs peuvent aussi servir à installer des applications d’un fournisseur sans que celui-ci ne sache que son application est installée sur un tel simulateur, or dans le cas des cartes à puces, une application est censée représenter l’identité de l’utilisateur, spécialement quand la carte à puce est un mécanisme de sécurité permettant d’accéder à des services (financier par exemple), ce qui peut la différer des applications téléphoniques.

De plus ces simulateurs ne peuvent fonctionner que dans le cas d’un fonctionnement dit UCOM, pour User Centric Ownership Model (Modèle de possession centrée sur l’utilisateur). En effet ce modèle est opposé à l’ICOM, Issuer Centric Smart Card Ownership Model (Centrée sur l'émetteur) et qui donc ne délègue la tâche d’installation des applications à l’entreprise distribuant la carte, modèle largement représenté dans le domaine bancaire par exemple. Ce modèle délègue donc la tâche d’installation à l’utilisateur, il ne peut donc s’assurer correctement de la bonne utilisation de ses services, d’autant plus que des problématiques de protection des données des utilisateurs peuvent se poser dans ce cas.

Grâce à de tel types de simulateur, il est possible de procéder à trois types d’attaques différentes[19] :

  • Simulation complète : Dans cette configuration, un utilisateur malicieux possède un simulateur autonome. Il peut donc récupérer et installer une application d’un fournisseur dans le but d’entamer une opération de “reverse engineering”, une opération qui tente de comprendre les secrets d’un produit en partant du produit fini.
  • Simulation partielle : L’utilisateur malveillant utilise la carte physique originale et simule un environnement partiel qui comprend le stockage de l’application et l’environnement d’exécution. Le but de cette simulation est de fournir la garantie au fournisseur de service qu’une carte physique est bel et bien utilisée. Mais une fois cette requête envoyée, l’application est détournée vers le simulateur.
  • Simulation-in-the-Middle : Le simulateur intercepte les communications entre le fournisseur de service et la carte à puce. Pour cela il se présente au fournisseur comme étant une carte à puce, et inversement comme un fournisseur à la carte. Dans ce scénario, l’utilisateur observe simplement le trafic entre les deux et installe une application sur l’environnement simulé sans que la carte et le fournisseur ne soit alerté.

Contre mesure[modifier | modifier le code]

Il existe néanmoins différents types de contre mesure, qui permettent de bloquer partiellement ou totalement certaines attaques sur les cartes à puces. Certains mécanismes de défense sont assignés à la protection d'un seul type d'attaque, alors que d'autres sont plus généralistes et tentent de prodiguer une protection large des cartes à puces.

Cryptographique[modifier | modifier le code]

Analyse de la consommation[modifier | modifier le code]

Pour contrer les attaques par analyse du courant il existe diverses techniques. Il est possible par exemple de dessiner des algorithmes qui ne font pas varier la consommation d’énergie lors de leur exécution. Néanmoins cette méthode est difficile à mettre en place, car ces variations ne peuvent être réduites à néant. Une autre méthode est donc au contraire, d’intégrer du bruit dans la mesure de la consommation. Ainsi les relevés ne peuvent être reliés directement à un algorithme ce qui rend ce type d’attaque plus compliqué à exécuter[20]. Une des manières de faire est donc de ne pas déchiffrer directement le mot de passe, mais de déchiffrer sa localisation dans la mémoire, avant de le comparer au mot de passe indiqué par l’utilisateur. Ainsi une attaque de ce type ne peut identifier uniquement la localisation du mot de passe, et est incapable de le déchiffrer sans posséder physiquement la carte[21].

Camouflage des clés[modifier | modifier le code]

La cryptographie asymétrique repose sur l’utilisation de paires de clés publiques et privées. L’expéditeur peut utiliser la clé publique du destinataire pour coder un message que seul le destinataire, qui possède la clé privée, peut décoder pour en lire son contenu. Il n’y a que la clé publique qui est échangée entre 2 nœuds de communication, la clé privée est gardée en secret chez le destinataire. Même si une troisième personne arrive à obtenir la clé publique, le décodage reste impossible sans la clé privée[22].

La sécurité de la clé privée reste encore un problème, une menace essentielle consiste à voler la clé privée stockée sur le disque dur. Normalement, cette clé est stockée dans un conteneur de clés : un fichier protégé par un mot de passe. Un attaquant, qui réussit à voler le conteneur de clés, peut trouver le mot de passe en utilisant soit par une attaque par dictionnaire, soit par une attaque par force brute. La seule défense pour la clé privée est de rendre le mot de passe suffisamment grand pour ralentir le processus de vérification du mot de passe. Une autre approche est d’enregistrer la clé privée dans le matériel de la carte à puce et de bloquer l’accès à la carte après un certain nombre d’échecs dans la tentative d’authentification. Cette méthode est très sécurisée mais elle rend le coût de fabrication de la carte très élevé.

Une méthode logicielle pour mieux sécuriser la clé privée est le camouflage cryptographique dans lequel la clé privée est implantée avec plusieurs autres clés dans le même conteneur. Un attaquant, en essayant de forcer le conteneur va obtenir plusieurs clés plausibles parmi lesquels se trouve la vraie clé mais qui ne peut pas être distinguée des autres clés. Pour pouvoir la trouver, il doit tester tous les clés plausibles auprès du serveur d’authentification qui va pouvoir suspendre l’accès après plusieurs tentatives d'authentification.

Les données cryptées sont faites selon une certaine structure, cette structure va permettre à un cryptanalyste de savoir si la clé de déchiffrement utilisée est correcte ou non. Si la clé est correcte, le message déchiffré va suivre une certaine structure mais pas simplement une chaîne aléatoire de byte. Un attaquant peut de ce fait trouver la clé correcte en essayant toutes les combinaisons possibles même s’il n’a aucune d’information sur le message clair. En utilisant le camouflage cryptographique, les déchiffrés vont avoir tous les mêmes structures que le message original, l’attaquant ne pourra pas distinguer le vrai message déchiffré de ceux qui semblent vrais[23].

Software[modifier | modifier le code]

Sécurité par contrat[modifier | modifier le code]

Pour éviter des applications malicieuse s'exécutant sur la carte à puce on peut mettre en place un système de sécurisation des applications basé sur un contrat. Le contrat se décompose en deux parties :

  • Le “claim” décrit ce que l’application fournit comme services, et ceux qu’elle peut appeler.
  • Le “AppPolicy” donné par le fournisseur de l’application décrit ce qu’elle est autorisée à partager, et les services nécessaires à son fonctionnement

Ainsi grâce à ces informations, on peut empêcher une application de s'exécuter si jamais son environnement de fonctionnement n’est pas complet; et éviter ainsi des bugs de fonctionnement. De plus on peut aussi vérifier les accès à une application critique et prévenir des intrusions d’application malveillantes[24].

Anti-Simulator Protocol[modifier | modifier le code]

Il existe des moyens d'éviter le problème des simulateurs de carte, détaillé précédemment, il est nécessaire de mettre en place des mesures de protections. Un protocole de validation marchant sur le principe suivant a été mis en place. Dans un premier temps, la carte émet une demande de téléchargement d'application au fournisseur de service, et celui-ci demande donc en retour une clef de validation qui lui est fournie par une plate-forme dite "de confiance" qui est située sur la carte physique. Cette TPM (Trusted Plate-forme Module) génère donc une clef unique qui est renvoyée au fournisseur. Une fois en possession de cette clef, le fournisseur peut donc commencer à générer un certificat, et pour cela il va contacter une autorité tierce et lui transmettre les informations nécessaires, dont la clef de validation. Ce certificat généré, le fournisseur peut commencer le transfert de l'application encore cryptée, et du certificat attenant. La carte va donc demander à nouveau à la TPM de générer la clef de validation, et va devoir la comparer à celle contenue dans le certificat pour pouvoir décrypter l'application[25].

Cette phase de validation permet donc de s'assurer que c'est bien la même carte qui a émis la demande et qui a reçu l'application. En effet, si un intermédiaire intercepte la réponse du fournisseur, il ne sera pas en mesure de générer la clef de validation permettant de décrypter l'application.

Vérification du code[modifier | modifier le code]

La vérification du code permet de garantir l’exactitude du code qui a été transféré sur la carte, ce qui permet de garantir la fiabilité de l’application. En temps normal, le code est vérifié lors de son exécution, mais pour les cartes qui ne peuvent charger dynamiquement du code, il est vérifié lors de l’installation. Néanmoins beaucoup de cartes Java ne possèdent pas de BCV (byte-code checker), et doivent donc se reposer sur une entité tierce de confiance, qui va donc effectuer cette vérification et ajouter sa signature sur celle-ci afin d'indiquer que le code présenté a été vérifié. Or si la carte embarque un BCV, elle peut donc vérifier dynamiquement le code et se prémunir contre les erreurs induites par un code malveillant, comme le dépassement de tableau par exemple[26]

Pare-feu[modifier | modifier le code]

Le pare-feu est un mécanisme de défense implémenté sur tous les cartes Java. Le rôle de celui-ci est de surveiller et empêcher les applications d’accéder, en écriture ou en lecture, aux données des autres applications pendant leur fonctionnement. Dans la pratique, chaque application est définie dans un contexte de sécurité, et chaque méthode est vérifiée en fonction des droits qui lui sont octroyés. De base, une application n’a le droit d'accéder qu’à son propre contexte.

Le pare-feu a donc un rôle complémentaire vis-à-vis de la vérification de code. Là où cette dernière vérifiera que l’application ne s’expose pas à des erreurs exploitables, le pare-feu vérifiera lui que ses données sont bien protégées de l’extérieur. Ainsi le pare-feu garantit qu’une application ne peut être influencée par une autre[27]

Références[modifier | modifier le code]

Bibliographie[modifier | modifier le code]

Sources bibliographiques référencées dans le texte[modifier | modifier le code]

  • (en) N. Dragoni, E. Lostal, O. Gadyatskaya, F. Massacci et F. Paci, « A Load Time Policy Checker for Open Multi-application Smart Cards », 2011 IEEE International Symposium on Policies for Distributed Systems and Networks, Washington, DC, USA, IEEE Computer Society,‎ , p. 153-156
  • (en) H. Mahmoud et K. Alghathbar, « Novel algorithmic countermeasures for Differential Power Analysis attacks on smart cards », Information Assurance and Security (IAS), 2010 Sixth International Conference, IEEE Computer Society,‎ , p. 23-25
  • (en) X. Leng, « Smart card applications and security », Information Security Technical Report, IEEE Computer Society,‎ , p. 36-45
  • (en) R.N. Akram, K. Markantonakis et K. Mayes, « Simulator Problem in User Centric Smart Card Ownership Model », Embedded and Ubiquitous Computing (EUC), 2010 IEEE/IFIP 8th International Conference, IEEE Computer Society,‎ , p. 679-686
  • (en) H. Bar-El, « Known Attacks Against Smartcards », Information Assurance and Security,‎ , p. 1-19
  • (en) S Moore, R. Anderson, P. Cunningham et T. Mullins, « Improving Smart Card Security using Self-timed Circuits », Proceedings of the Eighth International Symposium on Asynchronous Circuits and Systems,‎ , p. 1-8
  • (en) G McGraw et E. W. Felten, Securing Java,
  • (en) H. Handschuh et H.M. Heys, « A Timing Attack on RC5 », Selected areas in cryptography,‎ , p. 306-318
  • (en) W. Mostowski et E. Poll, « Malicious Code on Java Card Smartcards: Attacks and Countermeasures », Security of Systems (SoS) group,‎ , p. 1-16
  • (en) D. N. Hoover et B. N. Kausik, « Software Smart Cards via Cryptographic Camouflage », Security and Privacy,‎ , p. 208-215
  • (en) I. El Farissi et M. Azizi, « Classification of smartcard attacks », Multimedia Computing and Systems (ICMCS),‎ , p. 1-5
  • (en) Yuchuan Wu et Yaqin Sun, « Analysis and Research of Securing from Attack for Java Card », E-Business and E-Government (ICEE),‎ , p. 1296 -1298
  • (en) K. Anup, « Security risks of java cards », In Proceedings of the Twelfth IFIP WG 11.3 Working Conference on Database Security,‎ , p. 1-6

Voir aussi[modifier | modifier le code]

Articles connexes[modifier | modifier le code]

Liens externes[modifier | modifier le code]