root/middleware-offline/trunk/_src/eidmw/applayer/SAM.cpp @ 271

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

First official release

Line 
1/* ****************************************************************************
2 *
3 *  PTeID Middleware Project.
4 *  Copyright(C) 2014
5 *  Andre Guerreiro <andre.guerreiro@caixamagica.pt>
6 *  Card interaction necessary for the Change Address Operation
7 *  mainly Diffie-Hellman key agreement and mutual authentication with CVC certificates
8 **/
9
10#include "APLCard.h"
11#include "APLCardPteid.h"
12#include "Reader.h"
13#include "SAM.h"
14#include <string>
15#include <cstring>
16#include <iostream>
17#include <openssl/rsa.h>
18#include <openssl/bn.h>
19#include <openssl/pkcs7.h>
20
21namespace eIDMW
22{
23       
24SAM::SAM(APL_Card *card)
25{
26        m_card = card;
27}
28
29
30void binToHex(const unsigned char *in, size_t in_len, char *out, size_t out_len)
31{
32        unsigned int        n;
33        char                *pos;
34
35        pos = out;
36        for (n = 0; n < in_len; n++) {
37                sprintf(pos, "%02x", in[n]);
38                pos += 2;
39        }
40        *pos = '\0';
41}
42
43char * SAM::_getDH_Param(char specific_byte, unsigned long offset)
44{
45                char * hex_param = NULL;
46                unsigned char apdu_dh[] = {0x00, 0xCB, 0x00, 0xFF, 0x0A, 0xA6, 0x03, 0x83, 0x01, 0x32, 0x7F, 0x49, 0x02,
47                 0x00, 0x00};
48
49                apdu_dh[13] = specific_byte;
50
51                CByteArray dh_param_ba = m_card->getCalReader()->SendAPDU(CByteArray(apdu_dh, sizeof(apdu_dh)));
52
53                //Parse the DH parameter out of the response APDU excluding also the SW12 bytes
54                CByteArray dh_param_final = dh_param_ba.GetBytes(offset);
55                dh_param_final.Chop(2);
56
57                size_t hex_len = 2 * dh_param_final.Size()+ 1;
58                hex_param = (char *)malloc(hex_len);
59                //CByteArray::ToString(bool bAddSpace, bool bOneLine, unsigned long ulOffset, unsigned long ulLen)
60
61                binToHex(dh_param_final.GetBytes(), dh_param_final.Size(), hex_param, hex_len);
62                return hex_param;
63}
64
65
66//Return DER encoding of the pubkey
67char * SAM::_getCVCPublicKey()
68{
69        const int offset_mod = 14;
70        const int offset_exp = 13;
71        unsigned char *rsa_der = NULL;
72        char *cvc_key = NULL;
73        RSA *key_tmp = RSA_new();
74        EVP_PKEY *evp_key = EVP_PKEY_new();
75
76        unsigned char apdu_cvc_pubkey_mod[] = {0x00, 0xCB, 0x00,
77        0xFF, 0x0A, 0xB6, 0x03, 0x83, 0x01, 0x44, 0x7F, 0x49, 0x02, 0x81, 0x00};
78
79        unsigned  char apdu_cvc_pubkey_exponent[] = {0x00, 0xCB, 0x00, 0xFF, 0x0A, 0xB6, 0x03,
80        0x83, 0x01, 0x44, 0x7F, 0x49, 0x02, 0x82, 0x00};
81
82        CByteArray cvc_modulus = m_card->getCalReader()->SendAPDU(
83                CByteArray(apdu_cvc_pubkey_mod, sizeof(apdu_cvc_pubkey_mod)));
84
85        CByteArray cvc_exponent = m_card->getCalReader()->SendAPDU
86          (CByteArray(apdu_cvc_pubkey_exponent, sizeof(apdu_cvc_pubkey_exponent)));
87
88        //Remove SW12 bytes from the responses
89        cvc_modulus.Chop(2);
90        cvc_exponent.Chop(2);
91
92        std::cerr << "DEBUG: _getCVCPublicKey(): modulus len=" << cvc_modulus.Size() << std::endl;
93        std::cerr << "DEBUG: _getCVCPublicKey(): exp len=" << cvc_exponent.Size() << std::endl;
94
95        unsigned char * mod_bytes = cvc_modulus.GetBytes();
96        unsigned char * exp_bytes = cvc_exponent.GetBytes();
97
98        key_tmp->n = BN_bin2bn(mod_bytes+offset_mod,
99                                 128, key_tmp->n);
100        key_tmp->e = BN_bin2bn(exp_bytes+offset_exp,
101                                 3, key_tmp->e);
102
103        EVP_PKEY_assign_RSA(evp_key, key_tmp);
104         
105        int der_len = i2d_PUBKEY(evp_key, &rsa_der);
106        size_t out_len = der_len*2 +1;
107        cvc_key = (char *)malloc(out_len);
108
109        binToHex(rsa_der, der_len, cvc_key, out_len);
110        free(rsa_der);
111
112        return cvc_key;
113}
114
115char * SAM::_getCardAuthPublicKey()
116{
117        EVP_PKEY *evp_key = EVP_PKEY_new();
118        RSA *key_tmp = RSA_new();
119        char *card_auth_pubkey = NULL;
120        unsigned char *rsa_der = NULL;
121
122        APL_EIDCard *pcard = dynamic_cast<APL_EIDCard *>(m_card);
123        APLPublicKey * key = pcard->getID().getCardAuthKeyObj();
124
125        unsigned char * mod_bytes = key->getModulus()->GetBytes();
126        unsigned char * exp_bytes = key->getExponent()->GetBytes();
127
128        key_tmp->n = BN_bin2bn(mod_bytes, key->getModulus()->Size(), key_tmp->n);
129        key_tmp->e = BN_bin2bn(exp_bytes, key->getExponent()->Size(), key_tmp->e);
130        EVP_PKEY_assign_RSA(evp_key, key_tmp);
131
132        int der_len = i2d_PUBKEY(evp_key, &rsa_der);
133        //int der_len = i2d_RSAPublicKey(key_tmp, &rsa_der);
134        size_t out_len = der_len*2 +1;
135        card_auth_pubkey = (char *)malloc(out_len);
136
137        binToHex(rsa_der, der_len, card_auth_pubkey, out_len);
138
139        free(rsa_der);
140        return card_auth_pubkey;
141}
142
143char * SAM::_getSODCert()
144{
145        char *sod_cert = NULL;
146        PKCS7 * p7 = NULL;
147        CByteArray sod_data = m_card->getRawData(APL_RAWDATA_SOD);
148        const unsigned char *temp = sod_data.GetBytes();
149        unsigned char *out = NULL; 
150        long len = sod_data.Size();
151
152        //Ignoring the first 4 bytes allows us to parse the SOD file as a PKCS7 object
153        temp += 4;
154
155        p7 = d2i_PKCS7(NULL, (const unsigned char **)&temp, len);
156
157        STACK_OF(X509) *pSigners = PKCS7_get0_signers(p7, NULL, 0);
158
159        X509 *signer_cert = sk_X509_value(pSigners, 0);
160        int der_len = i2d_X509(signer_cert, &out);
161
162        size_t hex_len = der_len*2 +1;
163        sod_cert = (char *)malloc(hex_len);
164
165        binToHex(out, der_len, sod_cert, hex_len);
166
167        return sod_cert;
168}
169
170char *SAM::getSerialNumberIAS101()
171{
172        const unsigned char apdu_serial[] = {0x00, 0xCA, 0x02, 0x5A, 0x0D};
173
174        CByteArray serial_apdu = CByteArray(apdu_serial,
175                sizeof(apdu_serial));
176
177        CByteArray serial_ba = m_card->getCalReader()->SendAPDU(serial_apdu);
178
179        serial_ba.Chop(2);
180
181        char *serial = (char *)malloc(serial_ba.Size()*2+1);
182
183        binToHex(serial_ba.GetBytes(), serial_ba.Size(), serial, serial_ba.Size()*2+1);
184
185        return serial;
186}
187
188bool checkResultSW12(CByteArray &result)
189{
190        unsigned long ulRespLen = result.Size();
191        unsigned int ulSW12 = (unsigned int)(256 * result.GetByte(ulRespLen - 2) + result.GetByte(ulRespLen - 1));
192
193        return ulSW12 == 0x9000;
194}
195
196
197bool SAM::sendKIFD(char *kifd)
198{
199        const unsigned char verify_apdu_key_agreement[] = {0x00, 0x22, 0x41, 0xA6, 0x89, 0x83, 0x01, 0x32, 0x95, 0x01, 0x80, 0x91, 0x81, 0x80}; 
200        CByteArray sendKIFD_apdu = CByteArray(verify_apdu_key_agreement,
201                        sizeof(verify_apdu_key_agreement));
202
203        //Create ByteArray from hex-encoded string
204        CByteArray kifd_ba(std::string(kifd), true);
205        sendKIFD_apdu.Append(kifd_ba);
206
207        CByteArray resp = m_card->getCalReader()->SendAPDU(sendKIFD_apdu);
208
209        if (!checkResultSW12(resp))
210        {
211                fprintf(stderr, "SendKIFD() failed!\n");
212                return false;
213        }
214
215        return true;   
216}
217
218char *SAM::getKICC()
219{
220        char *kicc_hex = NULL;
221        const int KICC_LEN = 128;
222        const int KICC_HEX_LEN = 128*2 +1;
223        const int KICC_OFFSET = 6;
224        unsigned char apdu_kicc[] = {0x00, 0xCB, 0x00, 0xFF, 0x04, 0xA6, 0x02, 0x91, 0x00};
225
226        CByteArray kicc_ba = m_card->getCalReader()->SendAPDU(CByteArray(apdu_kicc, sizeof(apdu_kicc)));
227        if (!checkResultSW12(kicc_ba))
228        {
229                fprintf(stderr, "SendKIFD() failed!\n");
230                return NULL;
231        }
232        kicc_ba.Chop(2);
233
234        kicc_hex = (char *)malloc(KICC_HEX_LEN);
235
236        binToHex(kicc_ba.GetBytes()+KICC_OFFSET, KICC_LEN, kicc_hex, KICC_HEX_LEN);
237
238        return kicc_hex;
239}
240
241
242bool SAM::verifyCert_CV_IFD(char * cv_cert)
243{
244        unsigned char ba_apdu_pso_verify[] = {0x00, 0x2A, 0x00, 0xBE, 0xD1};
245        unsigned char apdu_se_verify_cert[] = {0x00, 0x22, 0x41, 0xB6, 0x06, 0x83, 0x01, 0x44, 0x95, 0x01, 0x80};
246        CByteArray apdu_pso_verify(ba_apdu_pso_verify, sizeof(ba_apdu_pso_verify));
247
248        if (cv_cert == NULL || strlen(cv_cert) == 0)
249        {
250                fprintf(stderr, "Invalid cv_cert in SAM::VerifyCert_CV_IFD()!\n");
251                return false;
252        }
253
254        CByteArray resp = m_card->getCalReader()->SendAPDU(CByteArray(apdu_se_verify_cert, sizeof(apdu_se_verify_cert)));
255
256        if (!checkResultSW12(resp))
257        {
258                fprintf(stderr, "VerifyCert_CV_IFD() p1 failed!\n");
259                return false;
260        }
261
262        CByteArray cvcert_ba(std::string(cv_cert), true);
263        apdu_pso_verify.Append(cvcert_ba);
264
265        resp = m_card->getCalReader()->SendAPDU(apdu_pso_verify);
266        if (!checkResultSW12(resp))
267        {
268                fprintf(stderr, "VerifyCert_CV_IFD() p2 failed!\n");
269                return false;
270        }
271       
272        return true;
273}
274
275
276/*
277The parameter external_auth indicates the Security environment that's going to be used in the MSE SET command
278TODO: This should be parameterized to be reused in both cards scenarios
279*/
280char *SAM::generateChallenge()
281{
282        char *challenge = NULL;
283        //MSE SET External auth or Mutual Auth
284
285        // This includes the terminal SN associated with the server CVC cert
286        //unsigned char ba1_test[] = {0x00, 0x22, 0x41 ,0xA4 ,0x0D ,0x95 ,0x01 ,0x80 ,0x83 ,0x08 ,0x04 ,0x06 ,0x02 ,0x02 ,0x00 ,0x04 ,0x03 ,0x07};
287        unsigned char ba1_production[] = {0x00, 0x22, 0x41 ,0xA4 ,0x0D ,0x95 ,0x01, 0x80, 0x83, 0x08, 0x02, 0x06, 0x00, 0x07, 0x01, 0x07, 0x08, 0x08};
288
289        //GET CHALLENGE
290        unsigned char ba2[] = {0x80, 0x84, 0x00, 0x00, 0x08};
291
292        m_card->getCalReader()->SendAPDU(CByteArray(ba1_production, sizeof(ba1_production)));
293
294        CByteArray resp = m_card->getCalReader()->SendAPDU(CByteArray(ba2, sizeof(ba2)));
295
296        resp.Chop(2);
297
298        challenge = (char *)malloc(resp.Size()*2 +1);
299
300        binToHex(resp.GetBytes(), 8, challenge, resp.Size()*2 +1);
301
302        return challenge;
303
304}
305
306std::vector<char *> SAM::sendSequenceOfPrebuiltAPDUs(std::vector<char *> &apdu_array)
307{
308        int i = 0;
309        std::vector <char *> responses;
310        while(i != apdu_array.size())
311        {
312                char * tmp = sendPrebuiltAPDU(apdu_array.at(i));
313                fprintf(stderr, "APDU %d -> result: %s\n", i, tmp);
314                responses.push_back(tmp);
315                i++;
316        }
317        return responses;
318}
319
320char *SAM::sendPrebuiltAPDU(char *apdu_string)
321{
322        char *resp_string = NULL;
323
324        CByteArray mse_ba(std::string(apdu_string), true);
325        CByteArray resp = m_card->getCalReader()->SendAPDU(mse_ba);
326
327        resp_string = (char *)malloc(resp.Size()*2 +1);
328
329        binToHex(resp.GetBytes(), resp.Size(), resp_string, resp.Size()*2 +1);
330
331        return resp_string;
332}
333
334bool SAM::verifySignedChallenge(char *signed_challenge)
335{
336        unsigned char external_authenticate[] = {0x80, 0x82, 0x00, 0x00, 0x88};
337        CByteArray ba1(external_authenticate, sizeof(external_authenticate));
338
339        if (signed_challenge == NULL || strlen(signed_challenge) == 0)
340        {
341                fprintf(stderr, "Invalid signed_challenge in SAM::verifySignedChallenge()!\n");
342                return false;
343        }
344
345        CByteArray signed_ba(std::string(signed_challenge), true);
346        ba1.Append(signed_ba);
347
348        CByteArray resp = m_card->getCalReader()->SendAPDU(ba1);
349
350        return checkResultSW12(resp);
351}
352
353/* Fetch all the parameters needed from the card */
354bool SAM::getDHParams(DHParams *dh_struct)
355{
356
357        dh_struct->dh_g = _getDH_Param(0x88, 12);
358        dh_struct->dh_p = _getDH_Param(0x86, 12);
359        dh_struct->dh_q = _getDH_Param(0x87, 10);
360
361        dh_struct->cvc_ca_public_key = _getCVCPublicKey();
362        dh_struct->card_auth_public_key = _getCardAuthPublicKey();
363        dh_struct->certificateChain = _getSODCert();
364        dh_struct->version = m_card->getType() == APL_CARDTYPE_PTEID_IAS07 ? 1 : 2;
365
366        return true;
367}
368
369
370}
371
372
373
374
Note: See TracBrowser for help on using the browser.