root/middleware-offline/trunk/_src/eidmw/applayer/EMV-Cap-Helper.cpp @ 271

Revision 271, 7.3 KB (checked in by vsilva, 6 years ago)

First official release

Line 
1/* ****************************************************************************
2 *
3 *  PTeID Middleware Project.
4 *  Copyright (C) 2011-2012
5 *  Luis Medinas <lmedinas@gmail.com>
6 *  Andre Guerreiro <andre.guerreiro@caixamagica.pt>
7 */
8
9/*
10 *  pteid-mw-ng is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License as published by
12 *  the Free Software Foundation; either version 2 of the License, or
13 *  (at your option) any later version.
14 *
15 *  pteid-mw-ng is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU Library General Public License for more details.
19 *
20 *  You should have received a copy of the GNU General Public License
21 *  along with this program; if not, write to:
22 *      The Free Software Foundation, Inc.,
23 *      51 Franklin Street, Fifth Floor
24 *      Boston, MA  02110-1301, USA.
25 */
26
27#include <iostream>
28#include "APLCard.h"
29#include "APLReader.h"
30#include "Reader.h"
31#include "Log.h"
32
33#include "EMV-Cap-Helper.h"
34
35namespace eIDMW
36{
37
38EMVCapHelper::EMVCapHelper(APL_Card *card, const char *new_pin)
39{
40        const unsigned char a1[] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00};
41        const unsigned char a3[] = {0x80, 0xCA, 0x9F, 0x17, 0x04};
42        m_card = card;
43        m_new_pin = new_pin;
44
45        CByteArray oresp;
46        oresp.Append(0x00);
47        oresp.Append(0xA4);
48        oresp.Append(0x04);
49        oresp.Append(0x00);
50        oresp.Append(0x07);
51        oresp.Append(0x60);
52        oresp.Append(0x46);
53        oresp.Append(0x32);
54        oresp.Append(0xFF);
55        oresp.Append(0x00);
56        oresp.Append(0x00);
57        oresp.Append(0x01);
58        oresp = m_card->getCalReader()->SendAPDU(oresp);
59
60        if (!checkSW12(oresp))
61        {
62        MWLOG(LEV_ERROR, MOD_APL, L"Failed to Select EMV-CAP Applet! We're probably dealing with an unknown/unsupported card.");
63        }
64        m_card->getCalReader()->SendAPDU(CByteArray(a1, sizeof(a1)));
65        //m_card->getCalReader()->SendAPDU(CByteArray(a2, sizeof(a2)));
66        CByteArray try_counter_ba = m_card->getCalReader()->SendAPDU(CByteArray(a3, sizeof(a3)));
67
68        m_trycounter = try_counter_ba.GetByte(3);
69
70        m_pan = (char *)malloc(30);
71        m_arqc = (char *)malloc(20);
72        m_atc = (char *)malloc(10);
73
74}
75
76bool EMVCapHelper::checkSW12(CByteArray &in)
77{
78
79        unsigned long ulRespLen = in.Size();
80
81        unsigned int ulSW12 = (unsigned int)(256 * in.GetByte(ulRespLen - 2)
82                        + in.GetByte(ulRespLen - 1));
83
84        return ulSW12 == 0x9000;
85
86}
87
88
89bool EMVCapHelper::getOtpParams(OTPParams *otp_struct)
90{
91
92        //GetPan();
93        GetArqc(0x00);
94
95        otp_struct->pan = m_pan;
96        otp_struct->atc = m_atc;
97        otp_struct->arqc = m_arqc;
98       
99
100        otp_struct->cdol1 = CDOL1;
101        otp_struct->pan_seq_nr = PANSEQNUMBER;
102        otp_struct->counter = COUNTER;
103        otp_struct->pin_try_counter = m_trycounter;
104
105        if (m_pan == NULL || m_arqc == NULL || m_atc == NULL)
106                return false;
107        else 
108                return true;
109
110}
111
112EMVCapHelper::~EMVCapHelper()
113{
114
115        free(m_pan);
116        free(m_arqc); 
117        free(m_atc); 
118}
119
120void EMVCapHelper::GetPan()
121{
122        CByteArray osecpanresp;
123
124        osecpanresp.Append(0x00);
125        osecpanresp.Append(0xB2);
126        osecpanresp.Append(0x01);
127        osecpanresp.Append(0x0C);
128        osecpanresp.Append(0x5F);
129
130        CByteArray osecpanrespget = m_card->getCalReader()->SendAPDU(osecpanresp);
131
132        std::string pan_tmp = osecpanrespget.GetBytes(21,8).ToString(false);
133       
134        strcpy(m_pan, pan_tmp.c_str());
135
136}
137
138
139/*
140 * This plaintext PIN block format is documented in EMV spec
141 * book 3 - Section 6.5.12.2
142 */
143char *getEMVPinBlock(const char *pin)
144{
145        char tmp[2];
146        char * buffer = (char*)malloc(8);
147
148        int i = 0;
149
150        buffer[0] = 0x20;
151        buffer[0] |= strlen(pin);
152
153        memset(buffer+1, 0xFF, 7);
154        int digit = 0;
155        int high_nibble = 1;
156        for(; i < strlen(pin); i++)
157        {
158                tmp[0] = pin[i];
159                tmp[1] = 0;
160                digit = atoi(tmp);
161                int pos = i/2;
162
163                if (high_nibble)
164                {
165                        buffer[pos+1] &= 0x0F;
166                        buffer[pos+1] |= (digit << 4);
167                }
168                else
169                {
170                        buffer[pos +1] &= 0xF0;
171                        buffer[pos +1] |= digit;
172                }
173                high_nibble = !high_nibble;
174
175
176        }
177       
178        return buffer;
179
180}
181
182char *EMVCapHelper::changeCapPin(char * change_apdu_str)
183{
184
185        //Create APDU from hex-encoded string
186        CByteArray change_pin_apdu(std::string(change_apdu_str), true);
187        char *resp = (char *)malloc(5);
188
189        CByteArray bresp = m_card->getCalReader()->SendAPDU(change_pin_apdu);
190
191        unsigned long ulRespLen = bresp.Size();
192
193        unsigned int ulSW12 = (unsigned int)(256 * bresp.GetByte(ulRespLen - 2) + bresp.GetByte(ulRespLen - 1));
194        sprintf(resp, "%04x", ulSW12);
195
196        return resp;
197
198}
199
200char *EMVCapHelper::resetScriptCounter(char * cdol2)
201{
202        //Example: 80 AE 40 00 11 00 00 00 00 00 00 00 00 00 00 5A 33 80 00 00 00 00
203        const unsigned char apdu_header[] = {0x80, 0xAE, 0x40, 0x00, 0x11};
204        //Create APDU from hex-encoded string
205        CByteArray reset_counter_apdu;
206
207        if (cdol2 == NULL)
208        {
209                MWLOG(LEV_DEBUG, MOD_APL, L"resetScriptCounter called with cdol2 = NULL, ignoring the request...");
210                return "9000";
211
212        }
213        CByteArray body_apdu(std::string(cdol2), true);
214        char *resp = (char *)malloc(5);
215
216        reset_counter_apdu.Append(apdu_header, sizeof(apdu_header));
217        reset_counter_apdu.Append(body_apdu);
218
219        CByteArray bresp = m_card->getCalReader()->SendAPDU(reset_counter_apdu);
220
221        unsigned long ulRespLen = bresp.Size();
222
223        unsigned int ulSW12 = (unsigned int)(256 * bresp.GetByte(ulRespLen - 2) + bresp.GetByte(ulRespLen - 1));
224        sprintf(resp, "%04x", ulSW12);
225
226        return resp;
227
228}
229
230void EMVCapHelper::getOnlineTransactionParams(OTPParams *otp_struct)
231{
232
233        //Zero-out the whole struct, just in case
234        memset(otp_struct, 0, sizeof(OTPParams));
235
236        const unsigned char verify_apdu[] = {
237                0x00, 0x20, 0x00, 0x80, 0x08
238        };
239        CByteArray verify_apdu_ba(verify_apdu, sizeof(verify_apdu));
240        char * pin_block = getEMVPinBlock(m_new_pin);
241
242        verify_apdu_ba.Append((const unsigned char*)pin_block, 8);
243
244        m_card->getCalReader()->SendAPDU(verify_apdu_ba);
245        //GetPan();
246        GetArqc(0x80);
247
248        otp_struct->pan = m_pan;
249        otp_struct->atc = m_atc;
250        otp_struct->arqc = m_arqc;
251
252        otp_struct->cdol1 = CDOL1;
253        otp_struct->pan_seq_nr = PANSEQNUMBER;
254        otp_struct->counter = COUNTER;
255        otp_struct->pin_try_counter = m_trycounter;
256}
257
258void EMVCapHelper::GetArqc(unsigned char p1)
259{
260        const unsigned char apdu[] = {0x80, 0xAE, p1, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
262                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263                0x00, 0x34, 0x00, 0x00, 0x01, 0x00, 0x01};
264
265        CByteArray askarqc(apdu, sizeof(apdu));
266
267tryagain:
268
269        CByteArray arqc_response = m_card->getCalReader()->SendAPDU(askarqc);
270       
271        const unsigned char * resp = arqc_response.GetBytes();
272        int len = arqc_response.Size();
273
274        /* Not sure about this...
275        //Handle SW12=6985
276        if (resp[len-2] == 0x69 && resp[len-1] == 0x85)
277        {
278                const unsigned char verify_apdu[] = {
279                        0x00, 0x20, 0x00, 0x80, 0x08
280                };
281                CByteArray verify_apdu_ba(verify_apdu, sizeof(verify_apdu));
282                char * pin_block = getEMVPinBlock(m_old_pin);
283
284                verify_apdu_ba.Append((const unsigned char*)pin_block, 8);
285
286                fprintf(stderr, "EMV Verify PIN and then retry...\n");
287
288                CByteArray verify_resp = m_card->getCalReader()->SendAPDU(verify_apdu_ba);
289
290                if (checkSW12(verify_resp))
291                        goto tryagain;
292                else
293                {
294                        fprintf(stderr, "VERIFY Failed! \n");
295                        return;
296                }
297        }
298
299        */
300       
301        //We could try to properly parse the answer according to the scarce documentation
302        //but oh well, these offsets will never change in a million years...
303
304        std::string tmp = arqc_response.GetBytes(14, 8).ToString(false);
305        strcpy(m_arqc, tmp.c_str());
306
307        tmp = arqc_response.GetBytes(9, 2).ToString(false);
308        strcpy(m_atc, tmp.c_str());
309
310}
311
312}
Note: See TracBrowser for help on using the browser.