Smartcard

 druide

Smartcard

Ma carte de crédit arrive à échéance. La banque m'en envoi une nouvelle rapidement pour que je puisse continuer de consommer ☺. Vient la question « mais que vais-je faire de la vieille carte ? »

Je pourrais la jeter ! ou alors, je pourrais m'amuser avec. En bon geek, je choisi bien sûr la seconde option.

Avec cette carte je vais :

  • Lire les informations qu'elle contient
  • Utiliser les méthodes de chiffrement liés à la carte
  • Valider mon PIN
  • Finalement, peut-être en faire un module PAM pour l'authentification sur ma machine


Let's go.

Muscle et PCSCLite

La première étape consiste à réaliser un programme capable d'établir un dialogue entre l'application et la carte via le lecteur de carte.

Sur Linux, c'est PCSCLite qui fait la liaison entre le lecteur et l'application.

╒═══════════════╕ ╮
│  Application  │ ├ C++
╘═══════╤═══════╛ ╯
        ╿      
╒═══════╧═══════╕ ╮
│  PCSC library │ │
╘═══════╤═══════╛ │
        ╿         ├  pcscd / libpcsclite
╒═══════╧═══════╕ │  
│  PCSC daemon  │ │
╘═══════╤═══════╛ ╯
        ╿  
╒═══════╧═══════╕ ╮
│     Reader    │ ├ SCM Microsystems, Inc. SCR3340 - ExpressCard54 Smart Card Reader
╘═══════╤═══════╛ ╯
        ╿
╒═══════╧═══════╕ ╮
│   Smartcard   │ ├ Mastercard M-CUMULUS
╘═══════╤═══════╛ ╯
        ╿
╒═══════╧═══════╕
│ Smartcard API │
╘═══════════════╛
Je commence par compiler un programme « clé en main » fournit par le développeur de la libpscsc : PCSC sample in C. Tout fonctionne bien. Le programme dialogue avec la carte, la carte répond. Je prend le temps de comprendre ce code, de me l'approprier et de mettre tout ça dans une
class C++
. J'y ajoute quelques fonctionnalités comme, en autre, un « gestionnaire d’événement » WaitForCard qui me permet d'attendre l'insertion d'une carte dans le lecteur.




Je peux maintenant faire un programme simple tel que:


pcsc reader;

vector<string> mszReaders = reader.getReaders();

reader.setReader(mszReaders[0]);

fprintf(stdout, "Waiting for reader insertion...\n");
reader.waitForCard();

reader.connect();

unsigned long status = reader.getStatus() & 0x0000FFFF;

vector<unsigned char> atr = reader.getATR();

util::printResponse(atr);
Me voilà en possession de l'Answer To Reset (ATR).

ATR: 3B6500002063CBAA20
Avec un peu de chance, on peut en apprendre un peu plus sur la carte grâce à l'ATR, notamment en utilisant un parser tel que celui-ci

Dialoguons avec la carte ou le standard EMV

Europay, MasterCard et Visa, abrégé EMV est un standard qui définit la manière de relier l'IC de la carte à puce (ICC) aux terminaux de payement (ceux dans lesquels on a tous glissé notre carte une fois). Tout est décrit dans 4 livres téléchargeables sur le site emvco. Chaque livre traite d'une partie précise.
  • Book 1 - Application Independent ICC to Terminal Interface Requirements
  • Book 2 - Security and Key Management
  • Book 3 - Application Specification
  • Book 4 - Cardholder, Attendant, and Acquirer Interface Requirements


Après quelques heures passés dans ces livres, je dois admettre qu'ils sont particulièrement indigestes. Ils se font d’incessants renvois et proposent une lecture plutôt ardue. Ajouter à cela que tout est de la découverte pour moi et on obtient des lectures identiques au surf sur Internet, c'est-à-dire qu'après une dizaine de renvois, on se retrouve en train de lire un texte et on ne sait plus quelle était notre question de départ.

Le dialogue

EMV définit le dialogue avec la carte de la manière suivante. On envoi des commandes qui ont cette forme (Book III, pg 41):

╒════╤══════╤══════╤═════╤════════╤══════════╤════════╕
│CLA │ INS  │  P1  │  P2 │   Lc   │   Data   │   Le   │
╞════╧══════╧══════╧═════╪════════╧══════════╧════════╡
│← Mandatory Header 2 →  │ ←    Conditional Body    → │
  • CLA = Class Byte of the Command Message
  • INS = Instruction Byte of Command Message
  • P1 = Parameter 1
  • P2 = Parameter 2


La carte nous retourne une réponse qui prend cette forme:

╒═══════════╤══════╤══════╕
│   Data    │ SW1  │ SW2  │
╞═══════════╪══════╧══════╡
│ ← Body →  │ ← Trailer → │
La liste complète des codes de retour (SW1, SW2) se trouve sur le site d'eftlab


Par exemple:

  • si SW1=61, SW2=XX alors il y a encore XX bytes à lire dans la carte pour compléter la réponse. On peut les lire avec la commande GET RESPONSE
  • si SW1=90, SW2=00 alors la commande c'est déroulée sans erreur

Tag Length Value (TLV)

Si la réponse contient des valeurs à exploiter tel que le nom du propriétaire de la carte, le numéro de compte etc. alors ces données sont placées dans un TLV. Un TLV est composé d'un Tag sur un ou plusieurs octets, d'une longueur Length qui indique le nombre d'octets contenu dans la Value. On trouve des TLV « simple data object » et des TLV « constructed data object ». S'ils sont « constructed », cela signifie que le champ Value contiendra un ou plusieurs autres TLV.



Pour décoder un TLV, il faut connaître la manière dont il est encodé et donc savoir s'il est « constructed » ou pas. On trouve cette information dans le Book III, pg 156 [B1] et suivante.


Si le bit 6 (ATTENTION le premier bit est à 1 et pas 0) du premier octet est à 1, on a affaire à un « constructed data object », donc un TLV contenant d'autre(s) TLV, sinon c'est un « primitive data object ». A la section [B2] on trouve l'encodage pour la longueur et en [B3] pour la valeur. Il ne reste plus qu'à créer une
class
utilitaire pour décortiquer tout ça...




Je peux maintenant faire quelque chose comme


vector<unsigned char> response = reader.getResponse(apdu);
allTags = tlv::parseAll(response);

/* Cherche le (ou les) TAG 0x77 */
tags = tlv::findAll(0x77, allTags);
if (tags.size() > 0)
{
  ...
A partir de maintenant, je suis prêt à entamer le dialogue avec la carte. Je peux envoyer des commandes grâce à ma
class pcsc
et lire les réponse grâce à ma
class tlv
.



Une
class
de « stockage »

Au fur et à mesure de l'avancement du dialogue avec la carte, je vais devoir récolter et stocker beaucoup d'informations tel que le nom du propriétaire, le numéro de la carte, des certificats, des clés de chiffrements etc. J'ajoute donc une
class
de stockage. Cette classe ne contient que des propriétés
public
.




Let's go

C'est parti pour le dialogue avec cette carte. Le but, authentifier l'utilisateur grâce à son code PIN. Le code PIN devra être chiffré pour transiter de l'application à la carte, évitant ainsi l'attaque de l'homme du milieu (Man in the Middle).

Voici l'organigramme simplifié:


La première étape consiste à obtenir le PSE 1PAY.SYS.DDF01. En réalité, il s'agit d'un point d'entrée simplifié pour trouver la ou les applications présentent dans la carte. On peut en trouver une définition dans le Book I, chap 12.3.2 (page 141) ainsi qu'un organigramme de fonctionnement Book I, figure 17 (page 143). Remarque: le PSE est facultatif. Cette méthode ne fonctionne donc pas forcément avec toutes les cartes.


Pour obtenir le PSE, on utilise la commande SELECT suivante (Book I, chap 11.3.2) :

CLA: 00
INS: A4
P1 : 04 (Select by name)
P2 : 00 (First or only occurrence)
Lc : 0E (14 octets de long y.c Le)
Data: 315041592E5359532E4444463031 (La chaîne 1PAY.SYS.DDF01 en hexa)
Le : 00


On reçoit en retour un TLV représenté ci-dessous en hexadécimale sous ça forme « brut »

6f1a840e315041592e5359532e4444463031a5088801015f2d026672


Une fois décortiqué

6F File Control Information (FCI) Template
  	84 Dedicated File (DF) Name
  	  	315041592E5359532E4444463031
  	A5 File Control Information (FCI) Proprietary Template
  	  	88 Short File Identifier (SFI)
  	  	  	01
  	  	5F2D Language Preference
  	  	  	f r 


Ce qui est intéressent dans ce TLV, c'est le Tag 88 Short File Identifier (SFI). Avec sa valeur 01 on va pouvoir lire le record correspondant et obtenir l'Application Identifier (AID) de la carte. Ça sera utile, entre autre, pour trouver le modulus de la clé publique. La commande utilisée ici sera READ RECORD (Book 3, chap 6.5.11).

Avant de pouvoir utiliser la valeur du SFI, il faut effectuer un décalage de 3 octets contre la gauche selon la documentation:

╒══╤══╤══╤══╤══╤══╤══╤══╤══════════════════════╕
│b8│b7│b6│b5│b4│b3│b2│b1│        Meaning       │
╞══╪══╪══╪══╪══╪══╪══╪══╪══════════════════════╡
│ x│ x│ x│ x│ x│  │  │  │SFI                   │
╞══╪══╪══╪══╪══╪══╪══╪══╪══════════════════════╡
│  │  │  │  │  │ 1│ 0│ 0│P1 is a record number │
╘══╧══╧══╧══╧══╧══╧══╧══╧══════════════════════╛



SFI = (SFI << 3) | 0x04;
CLA: 00
INS: B2
P1 : 01 (Record number n° 1)
P2 : 0C (SFI provenant du Tag 88)
Lc : Not present
Data: Not present
Le : 00

TLV Brut: 701a61184f07d7560000300101500a43554d554c5553204d43870101

70 EMV Proprietary Template
  	61 Application Template
  	  	4F Application Identifier (AID) – card
  	  	  	D7560000300101
  	  	50 Application Label
  	  	  	C U M U L U S M C
  	  	87 Application Priority Indicator
  	  	  	01


Dans cette carte, il n'y a qu'une seule application mais il peut y en avoir plusieurs (c'est le cas des postcard). Dans ce cas, le choix de l'application se fera grâce au Tag 87 Application Priority Indicator comme c'est décrit dans le Book I, point 5 (page 148).

Exemple de la postcard:

70 EMV Proprietary Template
     61 Application Template
         4F Application Identifier (AID) – card
             A0000001110101
         50 Application Label
             P o s t F i n a n c e C a r d
         87 Application Priority Indicator
             01
     61 Application Template
         4F Application Identifier (AID) – card
             A0000000038010
         50 Application Label
             V I S A P L U S
         87 Application Priority Indicator
             06
     61 Application Template
         4F Application Identifier (AID) – card
             A0000000038002
         50 Application Label
             P o s t F i n a n c e I D
         87 Application Priority Indicator
             07


Après avoir fait le choix de l'application, il faut en faire part à la carte. Pour ce faire, on utilise à nouveau la commande SELECT

CLA: 00
INS: A4
P1 : 04 (Select by name)
P2 : 00 (First or only occurrence)
Lc : 07 (7 octets de long y.c Le)
Data: D7560000300101 (AID)
Le : 00

TLV Brut: 6f278407d7560000300101a51c500a43554d554c5553204d438701015f2d026672bf0c059f4d020b0a

6F File Control Information (FCI) Template
  	84 Dedicated File (DF) Name
  	  	D7560000300101
  	A5 File Control Information (FCI) Proprietary Template
  	  	50 Application Label
  	  	  	C U M U L U S M C
  	  	87 Application Priority Indicator
  	  	  	01
  	  	5F2D Language Preference
  	  	  	f r
  	  	BF0C File Control Information (FCI) Issuer Discretionary Data
  	  	  	9F4D Log Entry
  	  	  	  	0B0A
Il est temps maintenant de récupérer l'Application Interchange Profile (AIP) et l'Application File Locator (AFL). Comme dans le TLV en retour de la sélection de l'application il n'y avait pas de PDOL, on pourra mettre une valeur fixe à la place et fixer la longueur à '0'. Pour réaliser ce travail, on va utiliser la commande GET PROCESSING OPTIONS (Book III, chap 6.5.8) :
CLA: 80
INS: A8
P1 : 00
P2 : 00
Lc : 02
Data: 8300 (voir remarque*)
Le : 00

TLV Brut: 771282023900940C280102013001020038010200

77 Response Message Template Format 2
  	82 Application Interchange Profile (AIP)
  	  	3900
  	94 Application File Locator (AFL)
  	  	280102013001020038010200
*The data field of the command message is a data object coded according to the PDOL provided by the ICC, as defined in section 5.4, and is introduced by the tag '83'. When the data object list is not provided by the ICC, the terminal sets the length field of the template to zero.


Le tag 82 Application Interchange Profile (AIP) nous informe sur les "capacités" d'authentifications supportées par la carte. On utilise pour cela le MSB (39) et on le lit ainsi:

╒══╤══╤══╤══╤══╤══╤══╤══╤═══════════════════════════════════════════╕
│b8│b7│b6│b5│b4│b3│b2│b1│        Meaning                            │
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ 0│ x│ x│ x│ x│ x│ x│ x│RFU                                        │
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ x│ 1│ x│ x│ x│ x│ x│ x│SDA supported                              │
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ x│ x│ 1│ x│ x│ x│ x│ x│DDA supported                              │
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ x│ x│ x│ 1│ x│ x│ x│ x│Cardholder verification is supported       │
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ x│ x│ x│ x│ 1│ x│ x│ x│Terminal risk management is to be performed│
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ x│ x│ x│ x│ x│ 1│ x│ x│Issuer authentication is supported 19      │
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ x│ x│ x│ x│ x│ x│ 0│ x│RFU                                        │
╞══╪══╪══╪══╪══╪══╪══╪══╪═══════════════════════════════════════════╡
│ x│ x│ x│ x│ x│ x│ x│ 1│CDA supported                              │
╘══╧══╧══╧══╧══╧══╧══╧══╧═══════════════════════════════════════════╛


Ce qui donne pour cette carte

 ✔ DDA supported
 ✔ Cardholder verification is supported
 ✔ Terminal risk management is to be performed
 ✔ CDA supported


Dans le Tag 94, on trouve l'Application File Locator (AFL). L'AFL nous donne une liste d'Application Elementary File (AEF) présentent dans la carte et fournie par l'application. Cette valeur doit être lue par bloc de 4 octets.

  1. SFI déjà décallé de 3 bit contre la gauche
  2. Numéro du premier record
  3. Numéro du dernier record (y.c)
  4. Le nombre de record faisant partie de l'authentification offline, en commençant du record dont le numéro se trouve au point 2
╒═══╤════════════╤══════════╤═════════════════╕
│SFI│Start record│End record│ Record for Auth │
╞═══╪════════════╪══════════╪═════════════════╡
│ 28│     01     │    02    │       01        │
╞═══╪════════════╪══════════╪═════════════════╡
│ 30│     01     │    02    │       00        │
╞═══╪════════════╪══════════╪═════════════════╡
│ 38│     01     │    02    │       00        │
╘═══╧════════════╧══════════╧═════════════════╛


On va à nouveau utiliser la commande READ RECORD pour lire les valeurs contenues dans la carte. Comme il y a plusieurs valeurs à lire, on utilise une boucle tel que


byte sfi = afl[0] | 4;
byte startRecord = afl[1];
byte endRecord = afl[2];
byte offlineDataAuthentication = afl[3];
for (; startRecord <= endRecord; startRecord++)
{
  ...
}



En parcourant tous les AFL et en lisant tous les AEF on obtient toutes les informations nécessaires pour pouvoir chiffrer le code PIN par la suite. Les tags sauvegardés sont les suivants:

╒══════╤═════════════════════════════════════════════════════╕
│ TAG  │ Name                                                │ 
╞══════╪═════════════════════════════════════════════════════╡
│ 9F4A │ Static Data Authentication Tag List                 │
╞══════╪═════════════════════════════════════════════════════╡
│ 9F47 │ Integrated Circuit Card (ICC) Public Key Exponent   │
╞══════╪═════════════════════════════════════════════════════╡
│ 9F46 │ Integrated Circuit Card (ICC) Public Key Certificate│
╞══════╪═════════════════════════════════════════════════════╡
│ 9F32 │ Issuer Public Key Exponent                          │
╞══════╪═════════════════════════════════════════════════════╡
│ 90   │ Issuer Public Key Certificate                       │
╞══════╪═════════════════════════════════════════════════════╡
│ 92   │ Issuer Public Key Remainder                         │
╘══════╧═════════════════════════════════════════════════════╛



Comme on souhaite faire un chiffrement du PIN par la suite, on va ajouter dans la boucle, la concaténation des valeurs requises pour l'authentification Static Data to be Authenticated (SDA).
L'authentification offline est décrite dans le Book III, chap. 10.3 (partie Description). On y apprend que les données nécessaires pour le SDA sont les celles indiquées dans les AFL (voir ci-dessus) et qu'elles devront être concaténées en fonction de la valeur du SFI.

  • Pour les records avec un SFI compris entre 1 et 10, le Tag ('70') et la longueur ne font pas partie de la concaténation. On concatène donc que V.
  • Pour les records avec un SFI compris entre 11 et 30, le Tag ('70') et la longueur font partie de la concaténation. On concatène donc tout le TLV.
Ce qui donne quelque chose comme (ajout dans la boucle
for
)

if (offlineDataAuthentication != 0)
{
	if (startRecord <= offlineDataAuthentication)
	{
		tags = tlv::findAll(0x70, allTags);
		if (tags.size() > 0)
		{
			byte sfiToTest = sfi >> 3;
			if (sfiToTest >= 1 && sfiToTest <= 10)
			{
				scard.staticDataToBeAuthenticated.insert(scard.staticDataToBeAuthenticated.end(),
													 tags.front().V.begin(),
													 tags.front().V.end());
			}
			if (sfiToTest >= 11 && sfiToTest <= 30)
			{
				scard.staticDataToBeAuthenticated.push_back(0x70);
				scard.staticDataToBeAuthenticated.push_back(tags.front().T);
				scard.staticDataToBeAuthenticated.insert(scard.staticDataToBeAuthenticated.end(),
													 tags.front().V.begin(),
													 tags.front().V.end());
			}
		}
	}
}

Les certificats et les clés publiques

Il peut y avoir une confusion dans la terminologie quand on compare la terminologie RSA et EMV. Tous les termes ci-dessous sont tirés de la terminologie EMV.

Dans un chiffrement asymétrique, on trouve:

  • une clé publique constituée d'un modulus noté 𝒏 et d'un exponent noté 𝒆. On peut donc noté la clé publique: public key (𝒏, 𝒆).
  • une clé privée constituée d'un modulus noté 𝒏 et d'un exponent noté 𝒅. On peut donc noté la clé privée: private key (𝒏, 𝒅).


Selon le principe du chiffrement asymétrique :

  • Les clés privées et publiques sont générées par paire. Une clé publique possède une clé privée associée
  • une entité peut chiffrer un agrégat binaire en utilisant sa clé privée. Toute personne en possession de la clé publique pourra alors déchiffrer le contenu. On parle alors de signature
  • une personne peut chiffrer un agrégat binaire en utilisant la clé publique. Seule l'entité en possession de la clé privée pourra alors déchiffrer le contenu. On parle alors de chiffrement

La clé publique Mastercard

Dans la carte on trouve le Issuer Public Key Certificate (Tag 90). Il s'agit d'un certificat qui a été signé par l’émetteur de la carte (issuer). Pour le déchiffrer, il nous faut la clé publique de Mastercard. Toutes les clés publiques se trouvent dans le Public key repository. Pour trouver la bonne, il nous faut l'AID et l'index. Ces deux valeurs ont étés trouvées lors de la lecture des AFL.


Pour ma Mastercard :

Modulus:
B8048ABC30C90D976336543E3FD7091C8FE4800DF820ED55E7E94813
ED00555B573FECA3D84AF6131A651D66CFF4284FB13B635EDD0EE401
76D8BF04B7FD1C7BACF9AC7327DFAA8AA72D10DB3B8E70B2DDD811CB
4196525EA386ACC33C0D9D4575916469C4E4F53E8E1C912CC618CB22
DDE7C3568E90022E6BBA770202E4522A2DD623D180E215BD1D1507FE
3DC90CA310D27B3EFCCD8F83DE3052CAD1E48938C68D095AAC91B5F3
7E28BB49EC7ED597

Exponent:
03


Maintenant que je possède cette clé publique, je suis capable de déchiffrer ce certificat. Pour faire cette tâche, il faut faire le calcul suivant 𝒓 = 𝒂^𝒑 % 𝒎. Dans ce calcul :
𝒓 correspond au certificat déchiffré
𝒂 correspond à l'agrégat chiffrer (le certificat chiffré [Tag 90])
𝒑 correspond à l'exposant (noté 𝒆 plus haut)
𝒎 correspond au modulus (noté 𝒏 plus haut)

Le choix des lettres, qui peut prêter à confusion, correspond à la notation que l'on trouve dans la documentation EMV (𝒏, 𝒆) et dans la documentation OpenSSL (𝒓 = 𝒂^𝒑 % 𝒎). En effet, pour faire « le travail » de déchiffrement, j'ai utilisé la fonction
BN_mod_exp
de la librairie OpenSSL.


Une fois l'agrégat déchiffrer, on obtient un Issuer Public Key Certificate tel que décrit dans le Book II, Table 6 (page 46). On peut alors commencer les vérifications à savoir:

  1. le premier byte commence par 0x6A
  2. le second byte est 0x02
  3. la date de validité est inférieur à « aujourd'hui »
  4. le dernier byte correspond à 0xBC
  5. on concatène de gauche à droite les valeurs allant du second élément du certificat jusqu'au dixième, soit depuis Certificat Format jusqu'à Issuer Public Key auquel s'ajoute encore Issuer Public Key Remainder s'il existe et Issuer Public Key Exponent
  6. on applique le Hash correspondant au Hash Algorithm Indicator, soit SHA1 au résultat de la concaténation
  7. on compare le Hash obtenu avec le Hash présent dans le certificat. Si les deux correspondent, cela signifie que le certificat présent dans la carte est bien le même que celui généré par Issuer
Si tout ces tests sont réussi, on peut alors concaténer Issuer Public Key et Issuer Public Key Remainder (s'il existe) pour obtenir le modulus de la clé publique final.


Pour me simplifier un peu le code, j'ai crée des structures permettant un accès plus aisé aux différentes valeurs du certificat. « Entre les deux » se trouve le modulus (ou une partie du).


struct ISSUER_PUBKEY_CERTIFICAT_HEADER
{
    byte    recoveredDataHeader;
    byte    certificateFormat;
    byte    issuerIdentifier[4];
    byte    certificateExpirationDate[2];
    byte    certificateSerialNumber[3];
    byte    hashAlgorithmIndicator;
    byte    issuerPublicKeyAlgorithmIndicator;
    byte    issuerPublicKeyLength;
    byte    issuerPublicKeyExponentLength;
};

// issuerPublicKeyModulus

struct ISSUER_PUBKEY_CERTIFICAT_FOOTER
{
    byte    hashResult[20];
    byte    recoveredDataTrailer;
};
Maintenant que le modulus est connu, on peut déchiffrer le Integrated Circuit Card (ICC) Public Key Certificate (tag 9F46). C'est dans ce certificat que se trouve le modulus de la clé publique de ICC. Comme c'est ICC qui devra déchiffrer le PIN que l'on va chiffrer, c'est bien cette clé publique qu'il nous faut. Le cheminement est le même que pour le précédent certificat. Les informations contenues dans le certificat une fois déchiffré, les tests, le hash etc.


Les valeurs pour le calcul du hash sont (dans l'ordre) :

  • les octets allant de Certificat Format à Issuer Public Key
  • la valeur du ICC Public Key Exponent
  • le Static Data Authentication Tag List (calculer lors de la boucle
    for
    )
  • la valeur du Tag 82 Application Interchange Profile car ce tag est présent dans Static Data Authentication Tag List (9F4A)


Toutes les informations se trouve dans le Book II, chap 6.4 (page 63 et suivantes).

Si tous les tests sont réussi, on obtient alors le modulus de la clé publique de ICC. L'exposant se trouve lui dans le tag 9F47, Integrated Circuit Card (ICC) Public Key Exponent.


On peut maintenant passer au chiffrement du code PIN.

Chiffrement du code PIN

Le chiffrement du code PIN se fera de la même manière, avec la même formule mathématique, que le déchiffrement des certificats. Cependant, avec de pouvoir chiffrer le PIN, il faut préparer les données nécessaires, à savoir

  • le PIN im-self formé de 4 à 12 chiffres, par exemple 9465 mis en forme de « PINBlock » tel que décrit dans le Book III, Table 24 (page 69)
  • le ICC unpredictable number. C'est un nombre aléatoire généré par la puce de la carte à puce. Ce nombre est là pour éviter l'attaque par rejeu
  • un nombre d'octets aléatoire de taille égale à NIC - 17, soit la taille du modulus de la clé publique de ICC - 17 octets. Ces octets aléatoires évitent le découverte aisée du PIN si seul celui-ci était chiffrer. En effet, imaginons un PIN sur 4 chiffres. Si je suis en train de réaliser une attaque de l'homme du milieu, j'ai pu voir transiter le ICC unpredictable number, je vois passer en retour un agrégat binaire comprenant ce ICC unpredictable number et le code PIN chiffré. Je ne connais pas le code PIN. Comme il n'y a que 10'000 possibilités avec un PIN sur 4 chiffres, je peux rapidement générer les 10'000 combinaisons de chiffrement, les comparer avec celle que je « viens de voir passer » et en déduire le code PIN. Par contre, avec un nombre d'octets aléatoire de taille égale à NIC - 17 en plus du code PIN et de l'ICC unpredictable number, même si je connais l'ICC unpredictable number, il devient impossible d'utiliser une force brut car le nombre de combinaison possible est beaucoup trop grand

PinBlock

Le PinBlock se compose ainsi

C N P P P P P/F P/F P/F P/F P/F P/F P/F P/F F F
where (8 bytes PINBlock):

C    Control field       4 bit binary number with value of 0010 (Hex '2')
N    PIN length          4 bit binary number with permissible values of 0100 to 1100 (Hex '4' to 'C')
P    PIN digit           4 bit binary number with permissible values of 0000 to 1001 (Hex '0' to '9')
P/F  PIN/filler          Determined by PIN length
F    Filler              4 bit binary number with a value of 1111 (Hex 'F')


Si on souhaite coder le PIN 9465, on va composer le PinBlock suivant

         *            ╒════╤════╤════╤════╤════╤════╤════╤════╤════╤════╤════╤════╤════╤════╤════╤════╕
         *            │  C │  N │  9 │  4 │  6 │  5 │ P/F│ P/F│ P/F│ P/F│ P/F│ P/F│ P/F│ P/F│  F │  F │
         * PIN Block =╞════╪════╪════╪════╪════╪════╪════╪════╪════╪════╪════╪════╪════╪════╪════╪════╡
         *            │0010│0100│1001│0100│0110│0101│1111│1111│1111│1111│1111│1111│1111│1111│1111│1111│
         *            ╘════╧════╧════╧════╧════╧════╧════╧════╧════╧════╧════╧════╧════╧════╧════╧════╛



ICC unpredictable number

Pour obtenir ce nombre aléatoire, on exécute la commande GET CHALLENGE tel que décrite dans le Book III, chap 6.5.6.2 (page 57). Cette commande nous retourne UNIQUEMENT 8 bytes aléatoires.

Random pad pattern

Pour le bourrage aléatoire, j'ai utilisé la fonction RAND_bytes d'OpenSSL

Chiffrement

Une fois en possession de tout les éléments, il faut les concaténer dans cet ordre

  1. Data header: 1 byte with value 7Fh
  2. PIN block: 8 bytes
  3. ICC unpredictable number
  4. Random pad pattern


On peut ensuite chiffrer cet agrégat binaire avec la clé publique de ICC puis exécuter la commande VERIFY tel que décrite dans le Book III, chap 6.5.12 (page 67)

CLA: 00
INS: 20
P1 : 00
P2 : 88 (selon Table 23)
Lc : Var. (taille de l'agrégat chiffré)
Data: Agrégat
Le : Not present
La commande va transférer l'agrégat binaire à la puce ICC. Cette dernière va déchiffrer l'agrégat grâce à sa clé privée. La puce supprimera les ICC Length - 17 octets de fin. Elle pourra alors comparer le ICC unpredictable number qu'elle a elle même généré (8 LSB). Elle prendra ensuite le PINBlock (8 MSB) dont elle extraira le code PIN qu'elle pourra finalement comparer avec le PIN qu'elle conserve dans un espace mémoire protégé. En fonction de la comparaison, la puce renverra un message dont les 2 octets d'états SW1, SW2 auront différentes valeurs reflétant le résultat de la vérification.


Si tout se passe bien, les deux octets d'états de la réponse devrait être SW1=0x90, SW2=0x00.

Conclusion

Le programme est fonctionnel, il n'est pas utilisable pour n'importe quelle carte à puce. Il a été réalisé pour ma carte MCUMULUS (MasterCard) mais les bases sont les mêmes pour les autres cartes. Ce programme est un programme de laboratoire et ne doit en aucun cas être utilisé en production.

Source code

Le code source de cette application version pre-alpha est disponible sur demande...

Liens

javaemvreader openscdp pcsclite Muscle Bible I, II, III, IV Ludovic Rousseau TLV online ATR Parser online GMP OpenSSL

Tags: smartcard mastercard emv tlv pin enciphered rsa muscle

  • 4 years 5 months before
  • |