pcsc_funcs.c

Go to the documentation of this file.
00001 
00020 #include "includes.h"
00021 #include <winscard.h>
00022 
00023 #include "common.h"
00024 #include "pcsc_funcs.h"
00025 
00026 
00027 /* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
00028  * SIM commands:
00029  * Command APDU: CLA INS P1 P2 P3 Data
00030  *   CLA (class of instruction): A0 for GSM, 00 for USIM
00031  *   INS (instruction)
00032  *   P1 P2 P3 (parameters, P3 = length of Data)
00033  * Response APDU: Data SW1 SW2
00034  *   SW1 SW2 (Status words)
00035  * Commands (INS P1 P2 P3):
00036  *   SELECT: A4 00 00 02 <file_id, 2 bytes>
00037  *   GET RESPONSE: C0 00 00 <len>
00038  *   RUN GSM ALG: 88 00 00 00 <RAND len = 10>
00039  *   RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
00040  *      P1 = ID of alg in card
00041  *      P2 = ID of secret key
00042  *   READ BINARY: B0 <offset high> <offset low> <len>
00043  *   READ RECORD: B2 <record number> <mode> <len>
00044  *      P2 (mode) = '02' (next record), '03' (previous record),
00045  *                  '04' (absolute mode)
00046  *   VERIFY CHV: 20 00 <CHV number> 08
00047  *   CHANGE CHV: 24 00 <CHV number> 10
00048  *   DISABLE CHV: 26 00 01 08
00049  *   ENABLE CHV: 28 00 01 08
00050  *   UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
00051  *   SLEEP: FA 00 00 00
00052  */
00053 
00054 /* GSM SIM commands */
00055 #define SIM_CMD_SELECT                  0xa0, 0xa4, 0x00, 0x00, 0x02
00056 #define SIM_CMD_RUN_GSM_ALG             0xa0, 0x88, 0x00, 0x00, 0x10
00057 #define SIM_CMD_GET_RESPONSE            0xa0, 0xc0, 0x00, 0x00
00058 #define SIM_CMD_READ_BIN                0xa0, 0xb0, 0x00, 0x00
00059 #define SIM_CMD_READ_RECORD             0xa0, 0xb2, 0x00, 0x00
00060 #define SIM_CMD_VERIFY_CHV1             0xa0, 0x20, 0x00, 0x01, 0x08
00061 
00062 /* USIM commands */
00063 #define USIM_CLA                        0x00
00064 #define USIM_CMD_RUN_UMTS_ALG           0x00, 0x88, 0x00, 0x81, 0x22
00065 #define USIM_CMD_GET_RESPONSE           0x00, 0xc0, 0x00, 0x00
00066 
00067 #define SIM_RECORD_MODE_ABSOLUTE 0x04
00068 
00069 #define USIM_FSP_TEMPL_TAG              0x62
00070 
00071 #define USIM_TLV_FILE_DESC              0x82
00072 #define USIM_TLV_FILE_ID                0x83
00073 #define USIM_TLV_DF_NAME                0x84
00074 #define USIM_TLV_PROPR_INFO             0xA5
00075 #define USIM_TLV_LIFE_CYCLE_STATUS      0x8A
00076 #define USIM_TLV_FILE_SIZE              0x80
00077 #define USIM_TLV_TOTAL_FILE_SIZE        0x81
00078 #define USIM_TLV_PIN_STATUS_TEMPLATE    0xC6
00079 #define USIM_TLV_SHORT_FILE_ID          0x88
00080 
00081 #define USIM_PS_DO_TAG                  0x90
00082 
00083 #define AKA_RAND_LEN 16
00084 #define AKA_AUTN_LEN 16
00085 #define AKA_AUTS_LEN 14
00086 #define RES_MAX_LEN 16
00087 #define IK_LEN 16
00088 #define CK_LEN 16
00089 
00090 
00091 typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
00092 
00093 struct scard_data {
00094         SCARDCONTEXT ctx;
00095         SCARDHANDLE card;
00096         DWORD protocol;
00097         sim_types sim_type;
00098         int pin1_required;
00099 };
00100 
00101 #ifdef __MINGW32_VERSION
00102 /* MinGW does not yet support WinScard, so load the needed functions
00103  * dynamically from winscard.dll for now. */
00104 
00105 static HINSTANCE dll = NULL; /* winscard.dll */
00106 
00107 static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
00108 #undef SCARD_PCI_T0
00109 #define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
00110 #undef SCARD_PCI_T1
00111 #define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
00112 
00113 
00114 static WINSCARDAPI LONG WINAPI
00115 (*dll_SCardEstablishContext)(IN DWORD dwScope,
00116                              IN LPCVOID pvReserved1,
00117                              IN LPCVOID pvReserved2,
00118                              OUT LPSCARDCONTEXT phContext);
00119 #define SCardEstablishContext dll_SCardEstablishContext
00120 
00121 static long (*dll_SCardReleaseContext)(long hContext);
00122 #define SCardReleaseContext dll_SCardReleaseContext
00123 
00124 static WINSCARDAPI LONG WINAPI
00125 (*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
00126                          IN LPCSTR mszGroups,
00127                          OUT LPSTR mszReaders,
00128                          IN OUT LPDWORD pcchReaders);
00129 #undef SCardListReaders
00130 #define SCardListReaders dll_SCardListReadersA
00131 
00132 static WINSCARDAPI LONG WINAPI
00133 (*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
00134                      IN LPCSTR szReader,
00135                      IN DWORD dwShareMode,
00136                      IN DWORD dwPreferredProtocols,
00137                      OUT LPSCARDHANDLE phCard,
00138                      OUT LPDWORD pdwActiveProtocol);
00139 #undef SCardConnect
00140 #define SCardConnect dll_SCardConnectA
00141 
00142 static WINSCARDAPI LONG WINAPI
00143 (*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
00144                        IN DWORD dwDisposition);
00145 #define SCardDisconnect dll_SCardDisconnect
00146 
00147 static WINSCARDAPI LONG WINAPI
00148 (*dll_SCardTransmit)(IN SCARDHANDLE hCard,
00149                      IN LPCSCARD_IO_REQUEST pioSendPci,
00150                      IN LPCBYTE pbSendBuffer,
00151                      IN DWORD cbSendLength,
00152                      IN OUT LPSCARD_IO_REQUEST pioRecvPci,
00153                      OUT LPBYTE pbRecvBuffer,
00154                      IN OUT LPDWORD pcbRecvLength);
00155 #define SCardTransmit dll_SCardTransmit
00156 
00157 static WINSCARDAPI LONG WINAPI
00158 (*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
00159 #define SCardBeginTransaction dll_SCardBeginTransaction
00160 
00161 static WINSCARDAPI LONG WINAPI
00162 (*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
00163 #define SCardEndTransaction dll_SCardEndTransaction
00164 
00165 
00166 static int mingw_load_symbols(void)
00167 {
00168         char *sym;
00169 
00170         if (dll)
00171                 return 0;
00172 
00173         dll = LoadLibrary("winscard");
00174         if (dll == NULL) {
00175                 wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
00176                            "library");
00177                 return -1;
00178         }
00179 
00180 #define LOADSYM(s) \
00181         sym = #s; \
00182         dll_ ## s = (void *) GetProcAddress(dll, sym); \
00183         if (dll_ ## s == NULL) \
00184                 goto fail;
00185 
00186         LOADSYM(SCardEstablishContext);
00187         LOADSYM(SCardReleaseContext);
00188         LOADSYM(SCardListReadersA);
00189         LOADSYM(SCardConnectA);
00190         LOADSYM(SCardDisconnect);
00191         LOADSYM(SCardTransmit);
00192         LOADSYM(SCardBeginTransaction);
00193         LOADSYM(SCardEndTransaction);
00194         LOADSYM(g_rgSCardT0Pci);
00195         LOADSYM(g_rgSCardT1Pci);
00196 
00197 #undef LOADSYM
00198 
00199         return 0;
00200 
00201 fail:
00202         wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
00203                    "winscard.dll", sym);
00204         FreeLibrary(dll);
00205         dll = NULL;
00206         return -1;
00207 }
00208 
00209 
00210 static void mingw_unload_symbols(void)
00211 {
00212         if (dll == NULL)
00213                 return;
00214 
00215         FreeLibrary(dll);
00216         dll = NULL;
00217 }
00218 
00219 #else /* __MINGW32_VERSION */
00220 
00221 #define mingw_load_symbols() 0
00222 #define mingw_unload_symbols() do { } while (0)
00223 
00224 #endif /* __MINGW32_VERSION */
00225 
00226 
00227 static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
00228                               unsigned char *buf, size_t *buf_len,
00229                               sim_types sim_type, unsigned char *aid,
00230                               size_t aidlen);
00231 static int scard_select_file(struct scard_data *scard, unsigned short file_id,
00232                              unsigned char *buf, size_t *buf_len);
00233 static int scard_verify_pin(struct scard_data *scard, const char *pin);
00234 static int scard_get_record_len(struct scard_data *scard,
00235                                 unsigned char recnum, unsigned char mode);
00236 static int scard_read_record(struct scard_data *scard,
00237                              unsigned char *data, size_t len,
00238                              unsigned char recnum, unsigned char mode);
00239 
00240 
00241 static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
00242                                  int *ps_do, int *file_len)
00243 {
00244                 unsigned char *pos, *end;
00245 
00246                 if (ps_do)
00247                         *ps_do = -1;
00248                 if (file_len)
00249                         *file_len = -1;
00250 
00251                 pos = buf;
00252                 end = pos + buf_len;
00253                 if (*pos != USIM_FSP_TEMPL_TAG) {
00254                         wpa_printf(MSG_DEBUG, "SCARD: file header did not "
00255                                    "start with FSP template tag");
00256                         return -1;
00257                 }
00258                 pos++;
00259                 if (pos >= end)
00260                         return -1;
00261                 if ((pos + pos[0]) < end)
00262                         end = pos + 1 + pos[0];
00263                 pos++;
00264                 wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
00265                             pos, end - pos);
00266 
00267                 while (pos + 1 < end) {
00268                         wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
00269                                    "0x%02x len=%d", pos[0], pos[1]);
00270                         if (pos + 2 + pos[1] > end)
00271                                 break;
00272 
00273                         if (pos[0] == USIM_TLV_FILE_SIZE &&
00274                             (pos[1] == 1 || pos[1] == 2) && file_len) {
00275                                 if (pos[1] == 1)
00276                                         *file_len = (int) pos[2];
00277                                 else
00278                                         *file_len = ((int) pos[2] << 8) |
00279                                                 (int) pos[3];
00280                                 wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
00281                                            *file_len);
00282                         }
00283 
00284                         if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
00285                             pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
00286                             pos[3] >= 1 && ps_do) {
00287                                 wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
00288                                            pos[4]);
00289                                 *ps_do = (int) pos[4];
00290                         }
00291 
00292                         pos += 2 + pos[1];
00293 
00294                         if (pos == end)
00295                                 return 0;
00296                 }
00297                 return -1;
00298 }
00299 
00300 
00301 static int scard_pin_needed(struct scard_data *scard,
00302                             unsigned char *hdr, size_t hlen)
00303 {
00304         if (scard->sim_type == SCARD_GSM_SIM) {
00305                 if (hlen > SCARD_CHV1_OFFSET &&
00306                     !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
00307                         return 1;
00308                 return 0;
00309         }
00310 
00311         if (scard->sim_type == SCARD_USIM) {
00312                 int ps_do;
00313                 if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
00314                         return -1;
00315                 /* TODO: there could be more than one PS_DO entry because of
00316                  * multiple PINs in key reference.. */
00317                 if (ps_do > 0 && (ps_do & 0x80))
00318                         return 1;
00319                 return 0;
00320         }
00321 
00322         return -1;
00323 }
00324 
00325 
00326 static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
00327                          size_t maxlen)
00328 {
00329         int rlen, rec;
00330         struct efdir {
00331                 unsigned char appl_template_tag; /* 0x61 */
00332                 unsigned char appl_template_len;
00333                 unsigned char appl_id_tag; /* 0x4f */
00334                 unsigned char aid_len;
00335                 unsigned char rid[5];
00336                 unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
00337         } *efdir;
00338         unsigned char buf[100];
00339         size_t blen;
00340 
00341         efdir = (struct efdir *) buf;
00342         blen = sizeof(buf);
00343         if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
00344                 wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
00345                 return -1;
00346         }
00347         wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
00348 
00349         for (rec = 1; rec < 10; rec++) {
00350                 rlen = scard_get_record_len(scard, rec,
00351                                             SIM_RECORD_MODE_ABSOLUTE);
00352                 if (rlen < 0) {
00353                         wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
00354                                    "record length");
00355                         return -1;
00356                 }
00357                 blen = sizeof(buf);
00358                 if (rlen > (int) blen) {
00359                         wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
00360                         return -1;
00361                 }
00362                 if (scard_read_record(scard, buf, rlen, rec,
00363                                       SIM_RECORD_MODE_ABSOLUTE) < 0) {
00364                         wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
00365                                    "EF_DIR record %d", rec);
00366                         return -1;
00367                 }
00368                 wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
00369 
00370                 if (efdir->appl_template_tag != 0x61) {
00371                         wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
00372                                    "template tag 0x%x",
00373                                    efdir->appl_template_tag);
00374                         continue;
00375                 }
00376 
00377                 if (efdir->appl_template_len > rlen - 2) {
00378                         wpa_printf(MSG_DEBUG, "SCARD: Too long application "
00379                                    "template (len=%d rlen=%d)",
00380                                    efdir->appl_template_len, rlen);
00381                         continue;
00382                 }
00383 
00384                 if (efdir->appl_id_tag != 0x4f) {
00385                         wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
00386                                    "identifier tag 0x%x", efdir->appl_id_tag);
00387                         continue;
00388                 }
00389 
00390                 if (efdir->aid_len < 1 || efdir->aid_len > 16) {
00391                         wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
00392                                    efdir->aid_len);
00393                         continue;
00394                 }
00395 
00396                 wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
00397                             efdir->rid, efdir->aid_len);
00398 
00399                 if (efdir->appl_code[0] == 0x10 &&
00400                     efdir->appl_code[1] == 0x02) {
00401                         wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
00402                                    "EF_DIR record %d", rec);
00403                         break;
00404                 }
00405         }
00406 
00407         if (rec >= 10) {
00408                 wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
00409                            "from EF_DIR records");
00410                 return -1;
00411         }
00412 
00413         if (efdir->aid_len > maxlen) {
00414                 wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
00415                 return -1;
00416         }
00417 
00418         os_memcpy(aid, efdir->rid, efdir->aid_len);
00419 
00420         return efdir->aid_len;
00421 }
00422 
00423 
00436 struct scard_data * scard_init(scard_sim_type sim_type)
00437 {
00438         long ret;
00439         unsigned long len;
00440         struct scard_data *scard;
00441 #ifdef CONFIG_NATIVE_WINDOWS
00442         TCHAR *readers = NULL;
00443 #else /* CONFIG_NATIVE_WINDOWS */
00444         char *readers = NULL;
00445 #endif /* CONFIG_NATIVE_WINDOWS */
00446         unsigned char buf[100];
00447         size_t blen;
00448         int transaction = 0;
00449         int pin_needed;
00450 
00451         wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
00452         if (mingw_load_symbols())
00453                 return NULL;
00454         scard = os_zalloc(sizeof(*scard));
00455         if (scard == NULL)
00456                 return NULL;
00457 
00458         ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
00459                                     &scard->ctx);
00460         if (ret != SCARD_S_SUCCESS) {
00461                 wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
00462                            "context (err=%ld)", ret);
00463                 goto failed;
00464         }
00465 
00466         ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
00467         if (ret != SCARD_S_SUCCESS) {
00468                 wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
00469                            "(err=%ld)", ret);
00470                 goto failed;
00471         }
00472 
00473 #ifdef UNICODE
00474         len *= 2;
00475 #endif /* UNICODE */
00476         readers = os_malloc(len);
00477         if (readers == NULL) {
00478                 wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
00479                 goto failed;
00480         }
00481 
00482         ret = SCardListReaders(scard->ctx, NULL, readers, &len);
00483         if (ret != SCARD_S_SUCCESS) {
00484                 wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
00485                            "(err=%ld)", ret);
00486                 goto failed;
00487         }
00488         if (len < 3) {
00489                 wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
00490                            "available.");
00491                 goto failed;
00492         }
00493         /* readers is a list of available reader. Last entry is terminated with
00494          * double NUL.
00495          * TODO: add support for selecting the reader; now just use the first
00496          * one.. */
00497 #ifdef UNICODE
00498         wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
00499 #else /* UNICODE */
00500         wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
00501 #endif /* UNICODE */
00502 
00503         ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
00504                            SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
00505         if (ret != SCARD_S_SUCCESS) {
00506                 if (ret == (long) SCARD_E_NO_SMARTCARD)
00507                         wpa_printf(MSG_INFO, "No smart card inserted.");
00508                 else
00509                         wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
00510                 goto failed;
00511         }
00512 
00513         os_free(readers);
00514         readers = NULL;
00515 
00516         wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
00517                    (unsigned int) scard->card, scard->protocol,
00518                    scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
00519 
00520         ret = SCardBeginTransaction(scard->card);
00521         if (ret != SCARD_S_SUCCESS) {
00522                 wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
00523                            "0x%x", (unsigned int) ret);
00524                 goto failed;
00525         }
00526         transaction = 1;
00527 
00528         blen = sizeof(buf);
00529 
00530         scard->sim_type = SCARD_GSM_SIM;
00531         if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
00532                 wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
00533                 if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
00534                                        SCARD_USIM, NULL, 0)) {
00535                         wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
00536                         if (sim_type == SCARD_USIM_ONLY)
00537                                 goto failed;
00538                         wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
00539                         scard->sim_type = SCARD_GSM_SIM;
00540                 } else {
00541                         wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
00542                         scard->sim_type = SCARD_USIM;
00543                 }
00544         }
00545 
00546         if (scard->sim_type == SCARD_GSM_SIM) {
00547                 blen = sizeof(buf);
00548                 if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
00549                         wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
00550                         goto failed;
00551                 }
00552 
00553                 blen = sizeof(buf);
00554                 if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
00555                         wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
00556                         goto failed;
00557                 }
00558         } else {
00559                 unsigned char aid[32];
00560                 int aid_len;
00561 
00562                 aid_len = scard_get_aid(scard, aid, sizeof(aid));
00563                 if (aid_len < 0) {
00564                         wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
00565                                    "3G USIM app - try to use standard 3G RID");
00566                         os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
00567                         aid_len = 5;
00568                 }
00569                 wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
00570 
00571                 /* Select based on AID = 3G RID from EF_DIR. This is usually
00572                  * starting with A0 00 00 00 87. */
00573                 blen = sizeof(buf);
00574                 if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
00575                                        aid, aid_len)) {
00576                         wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
00577                                    "app");
00578                         wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
00579                                     aid, aid_len);
00580                         goto failed;
00581                 }
00582         }
00583 
00584         /* Verify whether CHV1 (PIN1) is needed to access the card. */
00585         pin_needed = scard_pin_needed(scard, buf, blen);
00586         if (pin_needed < 0) {
00587                 wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
00588                            "is needed");
00589                 goto failed;
00590         }
00591         if (pin_needed) {
00592                 scard->pin1_required = 1;
00593                 wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
00594         }
00595 
00596         ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
00597         if (ret != SCARD_S_SUCCESS) {
00598                 wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
00599                            "0x%x", (unsigned int) ret);
00600         }
00601 
00602         return scard;
00603 
00604 failed:
00605         if (transaction)
00606                 SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
00607         os_free(readers);
00608         scard_deinit(scard);
00609         return NULL;
00610 }
00611 
00612 
00620 int scard_set_pin(struct scard_data *scard, const char *pin)
00621 {
00622         if (scard == NULL)
00623                 return -1;
00624 
00625         /* Verify whether CHV1 (PIN1) is needed to access the card. */
00626         if (scard->pin1_required) {
00627                 if (pin == NULL) {
00628                         wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
00629                                    "access");
00630                         return -1;
00631                 }
00632                 if (scard_verify_pin(scard, pin)) {
00633                         wpa_printf(MSG_INFO, "PIN verification failed for "
00634                                 "SIM access");
00635                         return -1;
00636                 }
00637         }
00638 
00639         return 0;
00640 }
00641 
00642 
00650 void scard_deinit(struct scard_data *scard)
00651 {
00652         long ret;
00653 
00654         if (scard == NULL)
00655                 return;
00656 
00657         wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
00658         if (scard->card) {
00659                 ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
00660                 if (ret != SCARD_S_SUCCESS) {
00661                         wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
00662                                    "smart card (err=%ld)", ret);
00663                 }
00664         }
00665 
00666         if (scard->ctx) {
00667                 ret = SCardReleaseContext(scard->ctx);
00668                 if (ret != SCARD_S_SUCCESS) {
00669                         wpa_printf(MSG_DEBUG, "Failed to release smart card "
00670                                    "context (err=%ld)", ret);
00671                 }
00672         }
00673         os_free(scard);
00674         mingw_unload_symbols();
00675 }
00676 
00677 
00678 static long scard_transmit(struct scard_data *scard,
00679                            unsigned char *_send, size_t send_len,
00680                            unsigned char *_recv, size_t *recv_len)
00681 {
00682         long ret;
00683         unsigned long rlen;
00684 
00685         wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
00686                         _send, send_len);
00687         rlen = *recv_len;
00688         ret = SCardTransmit(scard->card,
00689                             scard->protocol == SCARD_PROTOCOL_T1 ?
00690                             SCARD_PCI_T1 : SCARD_PCI_T0,
00691                             _send, (unsigned long) send_len,
00692                             NULL, _recv, &rlen);
00693         *recv_len = rlen;
00694         if (ret == SCARD_S_SUCCESS) {
00695                 wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
00696                             _recv, rlen);
00697         } else {
00698                 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
00699                            "(err=0x%lx)", ret);
00700         }
00701         return ret;
00702 }
00703 
00704 
00705 static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
00706                               unsigned char *buf, size_t *buf_len,
00707                               sim_types sim_type, unsigned char *aid,
00708                               size_t aidlen)
00709 {
00710         long ret;
00711         unsigned char resp[3];
00712         unsigned char cmd[50] = { SIM_CMD_SELECT };
00713         int cmdlen;
00714         unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
00715         size_t len, rlen;
00716 
00717         if (sim_type == SCARD_USIM) {
00718                 cmd[0] = USIM_CLA;
00719                 cmd[3] = 0x04;
00720                 get_resp[0] = USIM_CLA;
00721         }
00722 
00723         wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
00724         if (aid) {
00725                 wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
00726                             aid, aidlen);
00727                 if (5 + aidlen > sizeof(cmd))
00728                         return -1;
00729                 cmd[2] = 0x04; /* Select by AID */
00730                 cmd[4] = aidlen; /* len */
00731                 os_memcpy(cmd + 5, aid, aidlen);
00732                 cmdlen = 5 + aidlen;
00733         } else {
00734                 cmd[5] = file_id >> 8;
00735                 cmd[6] = file_id & 0xff;
00736                 cmdlen = 7;
00737         }
00738         len = sizeof(resp);
00739         ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
00740         if (ret != SCARD_S_SUCCESS) {
00741                 wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
00742                            "(err=0x%lx)", ret);
00743                 return -1;
00744         }
00745 
00746         if (len != 2) {
00747                 wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
00748                            "%d (expected 2)", (int) len);
00749                 return -1;
00750         }
00751 
00752         if (resp[0] == 0x98 && resp[1] == 0x04) {
00753                 /* Security status not satisfied (PIN_WLAN) */
00754                 wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
00755                            "(PIN_WLAN)");
00756                 return -1;
00757         }
00758 
00759         if (resp[0] == 0x6e) {
00760                 wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
00761                 return -1;
00762         }
00763 
00764         if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
00765                 wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
00766                            "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
00767                 return -1;
00768         }
00769         /* Normal ending of command; resp[1] bytes available */
00770         get_resp[4] = resp[1];
00771         wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
00772                    resp[1]);
00773 
00774         rlen = *buf_len;
00775         ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
00776         if (ret == SCARD_S_SUCCESS) {
00777                 *buf_len = resp[1] < rlen ? resp[1] : rlen;
00778                 return 0;
00779         }
00780 
00781         wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
00782         return -1;
00783 }
00784 
00785 
00786 static int scard_select_file(struct scard_data *scard, unsigned short file_id,
00787                              unsigned char *buf, size_t *buf_len)
00788 {
00789         return _scard_select_file(scard, file_id, buf, buf_len,
00790                                   scard->sim_type, NULL, 0);
00791 }
00792 
00793 
00794 static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
00795                                 unsigned char mode)
00796 {
00797         unsigned char buf[255];
00798         unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
00799         size_t blen;
00800         long ret;
00801 
00802         if (scard->sim_type == SCARD_USIM)
00803                 cmd[0] = USIM_CLA;
00804         cmd[2] = recnum;
00805         cmd[3] = mode;
00806         cmd[4] = sizeof(buf);
00807 
00808         blen = sizeof(buf);
00809         ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
00810         if (ret != SCARD_S_SUCCESS) {
00811                 wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
00812                            "length for record %d", recnum);
00813                 return -1;
00814         }
00815 
00816         wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
00817                     buf, blen);
00818 
00819         if (blen < 2 || buf[0] != 0x6c) {
00820                 wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
00821                            "length determination");
00822                 return -1;
00823         }
00824 
00825         return buf[1];
00826 }
00827 
00828 
00829 static int scard_read_record(struct scard_data *scard,
00830                              unsigned char *data, size_t len,
00831                              unsigned char recnum, unsigned char mode)
00832 {
00833         unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
00834         size_t blen = len + 3;
00835         unsigned char *buf;
00836         long ret;
00837 
00838         if (scard->sim_type == SCARD_USIM)
00839                 cmd[0] = USIM_CLA;
00840         cmd[2] = recnum;
00841         cmd[3] = mode;
00842         cmd[4] = len;
00843 
00844         buf = os_malloc(blen);
00845         if (buf == NULL)
00846                 return -1;
00847 
00848         ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
00849         if (ret != SCARD_S_SUCCESS) {
00850                 os_free(buf);
00851                 return -2;
00852         }
00853         if (blen != len + 2) {
00854                 wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
00855                            "length %ld (expected %ld)",
00856                            (long) blen, (long) len + 2);
00857                 os_free(buf);
00858                 return -3;
00859         }
00860 
00861         if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
00862                 wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
00863                            "status %02x %02x (expected 90 00)",
00864                            buf[len], buf[len + 1]);
00865                 os_free(buf);
00866                 return -4;
00867         }
00868 
00869         os_memcpy(data, buf, len);
00870         os_free(buf);
00871 
00872         return 0;
00873 }
00874 
00875 
00876 static int scard_read_file(struct scard_data *scard,
00877                            unsigned char *data, size_t len)
00878 {
00879         unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
00880         size_t blen = len + 3;
00881         unsigned char *buf;
00882         long ret;
00883 
00884         cmd[4] = len;
00885 
00886         buf = os_malloc(blen);
00887         if (buf == NULL)
00888                 return -1;
00889 
00890         if (scard->sim_type == SCARD_USIM)
00891                 cmd[0] = USIM_CLA;
00892         ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
00893         if (ret != SCARD_S_SUCCESS) {
00894                 os_free(buf);
00895                 return -2;
00896         }
00897         if (blen != len + 2) {
00898                 wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
00899                            "length %ld (expected %ld)",
00900                            (long) blen, (long) len + 2);
00901                 os_free(buf);
00902                 return -3;
00903         }
00904 
00905         if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
00906                 wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
00907                            "status %02x %02x (expected 90 00)",
00908                            buf[len], buf[len + 1]);
00909                 os_free(buf);
00910                 return -4;
00911         }
00912 
00913         os_memcpy(data, buf, len);
00914         os_free(buf);
00915 
00916         return 0;
00917 }
00918 
00919 
00920 static int scard_verify_pin(struct scard_data *scard, const char *pin)
00921 {
00922         long ret;
00923         unsigned char resp[3];
00924         unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
00925         size_t len;
00926 
00927         wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
00928 
00929         if (pin == NULL || os_strlen(pin) > 8)
00930                 return -1;
00931 
00932         if (scard->sim_type == SCARD_USIM)
00933                 cmd[0] = USIM_CLA;
00934         os_memcpy(cmd + 5, pin, os_strlen(pin));
00935         os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
00936 
00937         len = sizeof(resp);
00938         ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
00939         if (ret != SCARD_S_SUCCESS)
00940                 return -2;
00941 
00942         if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
00943                 wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
00944                 return -1;
00945         }
00946 
00947         wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
00948         return 0;
00949 }
00950 
00951 
00967 int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
00968 {
00969         unsigned char buf[100];
00970         size_t blen, imsilen, i;
00971         char *pos;
00972 
00973         wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
00974         blen = sizeof(buf);
00975         if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
00976                 return -1;
00977         if (blen < 4) {
00978                 wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
00979                            "header (len=%ld)", (long) blen);
00980                 return -2;
00981         }
00982 
00983         if (scard->sim_type == SCARD_GSM_SIM) {
00984                 blen = (buf[2] << 8) | buf[3];
00985         } else {
00986                 int file_size;
00987                 if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
00988                         return -3;
00989                 blen = file_size;
00990         }
00991         if (blen < 2 || blen > sizeof(buf)) {
00992                 wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%ld",
00993                            (long) blen);
00994                 return -3;
00995         }
00996 
00997         imsilen = (blen - 2) * 2 + 1;
00998         wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%ld imsilen=%ld",
00999                    (long) blen, (long) imsilen);
01000         if (blen < 2 || imsilen > *len) {
01001                 *len = imsilen;
01002                 return -4;
01003         }
01004 
01005         if (scard_read_file(scard, buf, blen))
01006                 return -5;
01007 
01008         pos = imsi;
01009         *pos++ = '0' + (buf[1] >> 4 & 0x0f);
01010         for (i = 2; i < blen; i++) {
01011                 unsigned char digit;
01012 
01013                 digit = buf[i] & 0x0f;
01014                 if (digit < 10)
01015                         *pos++ = '0' + digit;
01016                 else
01017                         imsilen--;
01018 
01019                 digit = buf[i] >> 4 & 0x0f;
01020                 if (digit < 10)
01021                         *pos++ = '0' + digit;
01022                 else
01023                         imsilen--;
01024         }
01025         *len = imsilen;
01026 
01027         return 0;
01028 }
01029 
01030 
01047 int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
01048                    unsigned char *sres, unsigned char *kc)
01049 {
01050         unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
01051         int cmdlen;
01052         unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
01053         unsigned char resp[3], buf[12 + 3 + 2];
01054         size_t len;
01055         long ret;
01056 
01057         if (scard == NULL)
01058                 return -1;
01059 
01060         wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
01061         if (scard->sim_type == SCARD_GSM_SIM) {
01062                 cmdlen = 5 + 16;
01063                 os_memcpy(cmd + 5, _rand, 16);
01064         } else {
01065                 cmdlen = 5 + 1 + 16;
01066                 cmd[0] = USIM_CLA;
01067                 cmd[3] = 0x80;
01068                 cmd[4] = 17;
01069                 cmd[5] = 16;
01070                 os_memcpy(cmd + 6, _rand, 16);
01071         }
01072         len = sizeof(resp);
01073         ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
01074         if (ret != SCARD_S_SUCCESS)
01075                 return -2;
01076 
01077         if ((scard->sim_type == SCARD_GSM_SIM &&
01078              (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
01079             (scard->sim_type == SCARD_USIM &&
01080              (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
01081                 wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
01082                            "auth request (len=%ld resp=%02x %02x)",
01083                            (long) len, resp[0], resp[1]);
01084                 return -3;
01085         }
01086         get_resp[4] = resp[1];
01087 
01088         len = sizeof(buf);
01089         ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
01090         if (ret != SCARD_S_SUCCESS)
01091                 return -4;
01092 
01093         if (scard->sim_type == SCARD_GSM_SIM) {
01094                 if (len != 4 + 8 + 2) {
01095                         wpa_printf(MSG_WARNING, "SCARD: unexpected data "
01096                                    "length for GSM auth (len=%ld, expected 14)",
01097                                    (long) len);
01098                         return -5;
01099                 }
01100                 os_memcpy(sres, buf, 4);
01101                 os_memcpy(kc, buf + 4, 8);
01102         } else {
01103                 if (len != 1 + 4 + 1 + 8 + 2) {
01104                         wpa_printf(MSG_WARNING, "SCARD: unexpected data "
01105                                    "length for USIM auth (len=%ld, "
01106                                    "expected 16)", (long) len);
01107                         return -5;
01108                 }
01109                 if (buf[0] != 4 || buf[5] != 8) {
01110                         wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
01111                                    "length (%d %d, expected 4 8)",
01112                                    buf[0], buf[5]);
01113                 }
01114                 os_memcpy(sres, buf + 1, 4);
01115                 os_memcpy(kc, buf + 6, 8);
01116         }
01117 
01118         wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
01119         wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
01120 
01121         return 0;
01122 }
01123 
01124 
01146 int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
01147                     const unsigned char *autn,
01148                     unsigned char *res, size_t *res_len,
01149                     unsigned char *ik, unsigned char *ck, unsigned char *auts)
01150 {
01151         unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
01152                 { USIM_CMD_RUN_UMTS_ALG };
01153         unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
01154         unsigned char resp[3], buf[64], *pos, *end;
01155         size_t len;
01156         long ret;
01157 
01158         if (scard == NULL)
01159                 return -1;
01160 
01161         if (scard->sim_type == SCARD_GSM_SIM) {
01162                 wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
01163                            "auth");
01164                 return -1;
01165         }
01166 
01167         wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
01168         wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
01169         cmd[5] = AKA_RAND_LEN;
01170         os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
01171         cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
01172         os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
01173 
01174         len = sizeof(resp);
01175         ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
01176         if (ret != SCARD_S_SUCCESS)
01177                 return -1;
01178 
01179         if (len <= sizeof(resp))
01180                 wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
01181 
01182         if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
01183                 wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
01184                            "MAC != XMAC");
01185                 return -1;
01186         } else if (len != 2 || resp[0] != 0x61) {
01187                 wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
01188                            "auth request (len=%ld resp=%02x %02x)",
01189                            (long) len, resp[0], resp[1]);
01190                 return -1;
01191         }
01192         get_resp[4] = resp[1];
01193 
01194         len = sizeof(buf);
01195         ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
01196         if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
01197                 return -1;
01198 
01199         wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
01200         if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
01201             buf[1] == AKA_AUTS_LEN) {
01202                 wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
01203                 os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
01204                 wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
01205                 return -2;
01206         } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
01207                 pos = buf + 1;
01208                 end = buf + len;
01209 
01210                 /* RES */
01211                 if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
01212                         wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
01213                         return -1;
01214                 }
01215                 *res_len = *pos++;
01216                 os_memcpy(res, pos, *res_len);
01217                 pos += *res_len;
01218                 wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
01219 
01220                 /* CK */
01221                 if (pos[0] != CK_LEN || pos + CK_LEN > end) {
01222                         wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
01223                         return -1;
01224                 }
01225                 pos++;
01226                 os_memcpy(ck, pos, CK_LEN);
01227                 pos += CK_LEN;
01228                 wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
01229 
01230                 /* IK */
01231                 if (pos[0] != IK_LEN || pos + IK_LEN > end) {
01232                         wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
01233                         return -1;
01234                 }
01235                 pos++;
01236                 os_memcpy(ik, pos, IK_LEN);
01237                 pos += IK_LEN;
01238                 wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
01239 
01240                 return 0;
01241         }
01242 
01243         wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
01244         return -1;
01245 }
01246 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:54 2009 for hostapd by  doxygen 1.6.1