Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_card.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011 Duncan Salerno
        !             3:  *
        !             4:  * This program is free software; you can redistribute it and/or modify it
        !             5:  * under the terms of the GNU General Public License as published by the
        !             6:  * Free Software Foundation; either version 2 of the License, or (at your
        !             7:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             8:  *
        !             9:  * This program is distributed in the hope that it will be useful, but
        !            10:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            11:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            12:  * for more details.
        !            13:  */
        !            14: 
        !            15: #include "eap_sim_pcsc_card.h"
        !            16: 
        !            17: #include <PCSC/wintypes.h>
        !            18: #include <PCSC/winscard.h>
        !            19: #include <daemon.h>
        !            20: 
        !            21: typedef struct private_eap_sim_pcsc_card_t private_eap_sim_pcsc_card_t;
        !            22: 
        !            23: /**
        !            24:  * Private data of an eap_sim_pcsc_card_t object.
        !            25:  */
        !            26: struct private_eap_sim_pcsc_card_t {
        !            27: 
        !            28:        /**
        !            29:         * Public eap_sim_pcsc_card_t interface.
        !            30:         */
        !            31:        eap_sim_pcsc_card_t public;
        !            32: };
        !            33: 
        !            34: /**
        !            35:  * Maximum length for an IMSI.
        !            36:  */
        !            37: #define SIM_IMSI_MAX_LEN 15
        !            38: 
        !            39: /**
        !            40:  * Length of the status at the end of response APDUs.
        !            41:  */
        !            42: #define APDU_STATUS_LEN 2
        !            43: 
        !            44: /**
        !            45:  * First byte of status word indicating success.
        !            46:  */
        !            47: #define APDU_SW1_SUCCESS 0x90
        !            48: 
        !            49: /**
        !            50:  * First byte of status word indicating there is response data to be read.
        !            51:  */
        !            52: #define APDU_SW1_RESPONSE_DATA 0x9f
        !            53: 
        !            54: /**
        !            55:  * Decode IMSI EF (Elementary File) into an ASCII string
        !            56:  */
        !            57: static bool decode_imsi_ef(unsigned char *input, int input_len, char *output)
        !            58: {
        !            59:        /* Only digits 0-9 valid in IMSIs */
        !            60:        static const char bcd_num_digits[] = {
        !            61:                '0', '1', '2', '3', '4', '5', '6', '7',
        !            62:                '8', '9', '\0', '\0', '\0', '\0', '\0', '\0'
        !            63:        };
        !            64:        int i;
        !            65: 
        !            66:        /* Check length byte matches how many bytes we have, and that input
        !            67:         * is correct length for an IMSI */
        !            68:        if (input[0] != input_len-1 || input_len < 2 || input_len > 9)
        !            69:        {
        !            70:                return FALSE;
        !            71:        }
        !            72: 
        !            73:        /* Check type byte is IMSI (bottom 3 bits == 001) */
        !            74:        if ((input[1] & 0x07) != 0x01)
        !            75:        {
        !            76:                return FALSE;
        !            77:        }
        !            78:        *output++ = bcd_num_digits[input[1] >> 4];
        !            79: 
        !            80:        for (i = 2; i < input_len; i++)
        !            81:        {
        !            82:                *output++ = bcd_num_digits[input[i] & 0xf];
        !            83:                *output++ = bcd_num_digits[input[i] >> 4];
        !            84:        }
        !            85: 
        !            86:        *output++ = '\0';
        !            87:        return TRUE;
        !            88: }
        !            89: 
        !            90: METHOD(simaka_card_t, get_triplet, bool,
        !            91:        private_eap_sim_pcsc_card_t *this, identification_t *id,
        !            92:        char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN])
        !            93: {
        !            94:        status_t found = FALSE;
        !            95:        LONG rv;
        !            96:        SCARDCONTEXT hContext;
        !            97:        DWORD dwReaders;
        !            98:        LPSTR mszReaders;
        !            99:        char *cur_reader;
        !           100:        char full_nai[128];
        !           101:        SCARDHANDLE hCard;
        !           102:        enum { DISCONNECTED, CONNECTED, TRANSACTION } hCard_status = DISCONNECTED;
        !           103: 
        !           104:        snprintf(full_nai, sizeof(full_nai), "%Y", id);
        !           105: 
        !           106:        DBG2(DBG_IKE, "looking for triplet: %Y rand %b", id, rand, SIM_RAND_LEN);
        !           107: 
        !           108:        rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
        !           109:        if (rv != SCARD_S_SUCCESS)
        !           110:        {
        !           111:                DBG1(DBG_IKE, "SCardEstablishContext: %s", pcsc_stringify_error(rv));
        !           112:                return FALSE;
        !           113:        }
        !           114: 
        !           115:        rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
        !           116:        if (rv != SCARD_S_SUCCESS)
        !           117:        {
        !           118:                DBG1(DBG_IKE, "SCardListReaders: %s", pcsc_stringify_error(rv));
        !           119:                return FALSE;
        !           120:        }
        !           121:        mszReaders = malloc(sizeof(char)*dwReaders);
        !           122: 
        !           123:        rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
        !           124:        if (rv != SCARD_S_SUCCESS)
        !           125:        {
        !           126:                DBG1(DBG_IKE, "SCardListReaders: %s", pcsc_stringify_error(rv));
        !           127:                free(mszReaders);
        !           128:                return FALSE;
        !           129:        }
        !           130: 
        !           131:        /* mszReaders is a multi-string of readers, separated by '\0' and
        !           132:         * terminated by an additional '\0' */
        !           133:        for (cur_reader = mszReaders; *cur_reader != '\0' && found == FALSE;
        !           134:                 cur_reader += strlen(cur_reader) + 1)
        !           135:        {
        !           136:                DWORD dwActiveProtocol = -1;
        !           137:                const SCARD_IO_REQUEST *pioSendPci;
        !           138:                SCARD_IO_REQUEST pioRecvPci;
        !           139:                BYTE pbRecvBuffer[64];
        !           140:                DWORD dwRecvLength;
        !           141:                char imsi[SIM_IMSI_MAX_LEN + 1];
        !           142: 
        !           143:                /* See GSM 11.11 for SIM APDUs */
        !           144:                static const BYTE pbSelectMF[] = { 0xa0, 0xa4, 0x00, 0x00, 0x02, 0x3f, 0x00 };
        !           145:                static const BYTE pbSelectDFGSM[] = { 0xa0, 0xa4, 0x00, 0x00, 0x02, 0x7f, 0x20 };
        !           146:                static const BYTE pbSelectIMSI[] = { 0xa0, 0xa4, 0x00, 0x00, 0x02, 0x6f, 0x07 };
        !           147:                static const BYTE pbReadBinary[] = { 0xa0, 0xb0, 0x00, 0x00, 0x09 };
        !           148:                BYTE pbRunGSMAlgorithm[5 + SIM_RAND_LEN] = { 0xa0, 0x88, 0x00, 0x00, 0x10 };
        !           149:                static const BYTE pbGetResponse[] = { 0xa0, 0xc0, 0x00, 0x00, 0x0c };
        !           150: 
        !           151:                /* If on 2nd or later reader, make sure we end the transaction
        !           152:                 * and disconnect card in the previous reader */
        !           153:                switch (hCard_status)
        !           154:                {
        !           155:                        case TRANSACTION:
        !           156:                                SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
        !           157:                                /* FALLTHRU */
        !           158:                        case CONNECTED:
        !           159:                                SCardDisconnect(hCard, SCARD_LEAVE_CARD);
        !           160:                                /* FALLTHRU */
        !           161:                        case DISCONNECTED:
        !           162:                                hCard_status = DISCONNECTED;
        !           163:                }
        !           164: 
        !           165:                /* Copy RAND into APDU */
        !           166:                memcpy(pbRunGSMAlgorithm + 5, rand, SIM_RAND_LEN);
        !           167: 
        !           168:                rv = SCardConnect(hContext, cur_reader, SCARD_SHARE_SHARED,
        !           169:                        SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
        !           170:                if (rv != SCARD_S_SUCCESS)
        !           171:                {
        !           172:                        DBG1(DBG_IKE, "SCardConnect: %s", pcsc_stringify_error(rv));
        !           173:                        continue;
        !           174:                }
        !           175:                hCard_status = CONNECTED;
        !           176: 
        !           177:                switch(dwActiveProtocol)
        !           178:                {
        !           179:                        case SCARD_PROTOCOL_T0:
        !           180:                                pioSendPci = SCARD_PCI_T0;
        !           181:                                break;
        !           182:                        case SCARD_PROTOCOL_T1:
        !           183:                                pioSendPci = SCARD_PCI_T1;
        !           184:                                break;
        !           185:                        default:
        !           186:                                DBG1(DBG_IKE, "Unknown SCARD_PROTOCOL");
        !           187:                                continue;
        !           188:                }
        !           189: 
        !           190:                /* Start transaction */
        !           191:                rv = SCardBeginTransaction(hCard);
        !           192:                if (rv != SCARD_S_SUCCESS)
        !           193:                {
        !           194:                        DBG1(DBG_IKE, "SCardBeginTransaction: %s", pcsc_stringify_error(rv));
        !           195:                        continue;
        !           196:                }
        !           197:                hCard_status = TRANSACTION;
        !           198: 
        !           199:                /* APDU: Select MF */
        !           200:                dwRecvLength = sizeof(pbRecvBuffer);
        !           201:                rv = SCardTransmit(hCard, pioSendPci, pbSelectMF, sizeof(pbSelectMF),
        !           202:                                                   &pioRecvPci, pbRecvBuffer, &dwRecvLength);
        !           203:                if (rv != SCARD_S_SUCCESS)
        !           204:                {
        !           205:                        DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
        !           206:                        continue;
        !           207:                }
        !           208:                if (dwRecvLength < APDU_STATUS_LEN ||
        !           209:                        pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA)
        !           210:                {
        !           211:                        DBG1(DBG_IKE, "Select MF failed: %b", pbRecvBuffer,
        !           212:                                 (u_int)dwRecvLength);
        !           213:                        continue;
        !           214:                }
        !           215: 
        !           216:                /* APDU: Select DF GSM */
        !           217:                dwRecvLength = sizeof(pbRecvBuffer);
        !           218:                rv = SCardTransmit(hCard, pioSendPci, pbSelectDFGSM, sizeof(pbSelectDFGSM),
        !           219:                                                   &pioRecvPci, pbRecvBuffer, &dwRecvLength);
        !           220:                if (rv != SCARD_S_SUCCESS)
        !           221:                {
        !           222:                        DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
        !           223:                        continue;
        !           224:                }
        !           225:                if (dwRecvLength < APDU_STATUS_LEN ||
        !           226:                        pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA)
        !           227:                {
        !           228:                        DBG1(DBG_IKE, "Select DF GSM failed: %b", pbRecvBuffer,
        !           229:                                 (u_int)dwRecvLength);
        !           230:                        continue;
        !           231:                }
        !           232: 
        !           233:                /* APDU: Select IMSI */
        !           234:                dwRecvLength = sizeof(pbRecvBuffer);
        !           235:                rv = SCardTransmit(hCard, pioSendPci, pbSelectIMSI, sizeof(pbSelectIMSI),
        !           236:                                                   &pioRecvPci, pbRecvBuffer, &dwRecvLength);
        !           237:                if (rv != SCARD_S_SUCCESS)
        !           238:                {
        !           239:                        DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
        !           240:                        continue;
        !           241:                }
        !           242:                if (dwRecvLength < APDU_STATUS_LEN ||
        !           243:                        pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA)
        !           244:                {
        !           245:                        DBG1(DBG_IKE, "Select IMSI failed: %b", pbRecvBuffer,
        !           246:                                 (u_int)dwRecvLength);
        !           247:                        continue;
        !           248:                }
        !           249: 
        !           250:                /* APDU: Read Binary (of IMSI) */
        !           251:                dwRecvLength = sizeof(pbRecvBuffer);
        !           252:                rv = SCardTransmit(hCard, pioSendPci, pbReadBinary, sizeof(pbReadBinary),
        !           253:                                                   &pioRecvPci, pbRecvBuffer, &dwRecvLength);
        !           254:                if (rv != SCARD_S_SUCCESS)
        !           255:                {
        !           256:                        DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
        !           257:                        continue;
        !           258:                }
        !           259:                if (dwRecvLength < APDU_STATUS_LEN ||
        !           260:                        pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_SUCCESS)
        !           261:                {
        !           262:                        DBG1(DBG_IKE, "Select IMSI failed: %b", pbRecvBuffer,
        !           263:                                 (u_int)dwRecvLength);
        !           264:                        continue;
        !           265:                }
        !           266: 
        !           267:                if (!decode_imsi_ef(pbRecvBuffer, dwRecvLength-APDU_STATUS_LEN, imsi))
        !           268:                {
        !           269:                        DBG1(DBG_IKE, "Couldn't decode IMSI EF: %b",
        !           270:                                 pbRecvBuffer, (u_int)dwRecvLength);
        !           271:                        continue;
        !           272:                }
        !           273: 
        !           274:                /* The IMSI could be post/prefixed in the full NAI, so just make sure
        !           275:                 * it's in there */
        !           276:                if (!(strlen(full_nai) && strstr(full_nai, imsi)))
        !           277:                {
        !           278:                        DBG1(DBG_IKE, "Not the SIM we're looking for, IMSI: %s", imsi);
        !           279:                        continue;
        !           280:                }
        !           281: 
        !           282:                /* APDU: Run GSM Algorithm */
        !           283:                dwRecvLength = sizeof(pbRecvBuffer);
        !           284:                rv = SCardTransmit(hCard, pioSendPci,
        !           285:                                                   pbRunGSMAlgorithm, sizeof(pbRunGSMAlgorithm),
        !           286:                                                   &pioRecvPci, pbRecvBuffer, &dwRecvLength);
        !           287:                if (rv != SCARD_S_SUCCESS)
        !           288:                {
        !           289:                        DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
        !           290:                        continue;
        !           291:                }
        !           292:                if (dwRecvLength < APDU_STATUS_LEN ||
        !           293:                        pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA)
        !           294:                {
        !           295:                        DBG1(DBG_IKE, "Run GSM Algorithm failed: %b",
        !           296:                                 pbRecvBuffer, (u_int)dwRecvLength);
        !           297:                        continue;
        !           298:                }
        !           299: 
        !           300:                /* APDU: Get Response (of Run GSM Algorithm) */
        !           301:                dwRecvLength = sizeof(pbRecvBuffer);
        !           302:                rv = SCardTransmit(hCard, pioSendPci, pbGetResponse, sizeof(pbGetResponse),
        !           303:                                                   &pioRecvPci, pbRecvBuffer, &dwRecvLength);
        !           304:                if (rv != SCARD_S_SUCCESS)
        !           305:                {
        !           306:                        DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
        !           307:                        continue;
        !           308:                }
        !           309: 
        !           310:                if (dwRecvLength < APDU_STATUS_LEN ||
        !           311:                        pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_SUCCESS)
        !           312:                {
        !           313:                        DBG1(DBG_IKE, "Get Response failed: %b", pbRecvBuffer,
        !           314:                                 (u_int)dwRecvLength);
        !           315:                        continue;
        !           316:                }
        !           317: 
        !           318:                /* Extract out Kc and SRES from response */
        !           319:                if (dwRecvLength == SIM_SRES_LEN + SIM_KC_LEN + APDU_STATUS_LEN)
        !           320:                {
        !           321:                        memcpy(sres, pbRecvBuffer, SIM_SRES_LEN);
        !           322:                        memcpy(kc, pbRecvBuffer+4, SIM_KC_LEN);
        !           323:                        /* This will also cause the loop to exit */
        !           324:                        found = TRUE;
        !           325:                }
        !           326:                else
        !           327:                {
        !           328:                        DBG1(DBG_IKE, "Get Response incorrect length: %b",
        !           329:                                 pbRecvBuffer, (u_int)dwRecvLength);
        !           330:                        continue;
        !           331:                }
        !           332: 
        !           333:                /* Transaction will be ended and card disconnected at the
        !           334:                 * beginning of this loop or after this loop */
        !           335:        }
        !           336: 
        !           337:        /* Make sure we end any previous transaction and disconnect card */
        !           338:        switch (hCard_status)
        !           339:        {
        !           340:                case TRANSACTION:
        !           341:                        SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
        !           342:                        /* FALLTHRU */
        !           343:                case CONNECTED:
        !           344:                        SCardDisconnect(hCard, SCARD_LEAVE_CARD);
        !           345:                        /* FALLTHRU */
        !           346:                case DISCONNECTED:
        !           347:                        hCard_status = DISCONNECTED;
        !           348:        }
        !           349: 
        !           350:        rv = SCardReleaseContext(hContext);
        !           351:        if (rv != SCARD_S_SUCCESS)
        !           352:        {
        !           353:                DBG1(DBG_IKE, "SCardReleaseContext: %s", pcsc_stringify_error(rv));
        !           354:        }
        !           355: 
        !           356:        free(mszReaders);
        !           357:        return found;
        !           358: }
        !           359: 
        !           360: METHOD(simaka_card_t, get_quintuplet, status_t,
        !           361:        private_eap_sim_pcsc_card_t *this, identification_t *id,
        !           362:        char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN],
        !           363:        char ik[AKA_IK_LEN], char res[AKA_RES_MAX], int *res_len)
        !           364: {
        !           365:        return NOT_SUPPORTED;
        !           366: }
        !           367: 
        !           368: METHOD(eap_sim_pcsc_card_t, destroy, void,
        !           369:        private_eap_sim_pcsc_card_t *this)
        !           370: {
        !           371:        free(this);
        !           372: }
        !           373: 
        !           374: /**
        !           375:  * See header
        !           376:  */
        !           377: eap_sim_pcsc_card_t *eap_sim_pcsc_card_create()
        !           378: {
        !           379:        private_eap_sim_pcsc_card_t *this;
        !           380: 
        !           381:        INIT(this,
        !           382:                .public = {
        !           383:                        .card = {
        !           384:                                .get_triplet = _get_triplet,
        !           385:                                .get_quintuplet = _get_quintuplet,
        !           386:                                .resync = (void*)return_false,
        !           387:                                .get_pseudonym = (void*)return_null,
        !           388:                                .set_pseudonym = (void*)nop,
        !           389:                                .get_reauth = (void*)return_null,
        !           390:                                .set_reauth = (void*)nop,
        !           391:                        },
        !           392:                        .destroy = _destroy,
        !           393:                },
        !           394:        );
        !           395: 
        !           396:        return &this->public;
        !           397: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>