diff options
author | sam <sam@FreeBSD.org> | 2007-07-11 15:48:36 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2007-07-11 15:48:36 +0000 |
commit | 35aef052ff21baa52c4cec68b512986c21f70a48 (patch) | |
tree | c3da7f33886a852f7dceb74373fbdeec49a48f77 /contrib/wpa_supplicant/pcsc_funcs.c | |
parent | 840099f34d8de1ca769f02fae379c4d8e5d6688a (diff) | |
download | FreeBSD-src-35aef052ff21baa52c4cec68b512986c21f70a48.zip FreeBSD-src-35aef052ff21baa52c4cec68b512986c21f70a48.tar.gz |
Import of WPA supplicant 0.5.8
Diffstat (limited to 'contrib/wpa_supplicant/pcsc_funcs.c')
-rw-r--r-- | contrib/wpa_supplicant/pcsc_funcs.c | 599 |
1 files changed, 524 insertions, 75 deletions
diff --git a/contrib/wpa_supplicant/pcsc_funcs.c b/contrib/wpa_supplicant/pcsc_funcs.c index 2ccfd00..cef8653 100644 --- a/contrib/wpa_supplicant/pcsc_funcs.c +++ b/contrib/wpa_supplicant/pcsc_funcs.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM - * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> + * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -10,15 +10,16 @@ * license. * * See README and COPYING for more details. + * + * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM + * cards through PC/SC smartcard library. These functions are used to implement + * authentication routines for EAP-SIM and EAP-AKA. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> +#include "includes.h" #include <winscard.h> #include "common.h" -#include "wpa_supplicant.h" #include "pcsc_funcs.h" @@ -38,6 +39,9 @@ * P1 = ID of alg in card * P2 = ID of secret key * READ BINARY: B0 <offset high> <offset low> <len> + * READ RECORD: B2 <record number> <mode> <len> + * P2 (mode) = '02' (next record), '03' (previous record), + * '04' (absolute mode) * VERIFY CHV: 20 00 <CHV number> 08 * CHANGE CHV: 24 00 <CHV number> 10 * DISABLE CHV: 26 00 01 08 @@ -51,6 +55,7 @@ #define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10 #define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00 #define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00 +#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00 #define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08 /* USIM commands */ @@ -58,6 +63,8 @@ #define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22 #define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00 +#define SIM_RECORD_MODE_ABSOLUTE 0x04 + #define USIM_FSP_TEMPL_TAG 0x62 #define USIM_TLV_FILE_DESC 0x82 @@ -83,20 +90,151 @@ typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types; struct scard_data { - long ctx; - long card; - unsigned long protocol; + SCARDCONTEXT ctx; + SCARDHANDLE card; + DWORD protocol; sim_types sim_type; int pin1_required; }; +#ifdef __MINGW32_VERSION +/* MinGW does not yet support WinScard, so load the needed functions + * dynamically from winscard.dll for now. */ + +static HINSTANCE dll = NULL; /* winscard.dll */ + +static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci; +#undef SCARD_PCI_T0 +#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci) +#undef SCARD_PCI_T1 +#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci) + + +static WINSCARDAPI LONG WINAPI +(*dll_SCardEstablishContext)(IN DWORD dwScope, + IN LPCVOID pvReserved1, + IN LPCVOID pvReserved2, + OUT LPSCARDCONTEXT phContext); +#define SCardEstablishContext dll_SCardEstablishContext + +static long (*dll_SCardReleaseContext)(long hContext); +#define SCardReleaseContext dll_SCardReleaseContext + +static WINSCARDAPI LONG WINAPI +(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext, + IN LPCSTR mszGroups, + OUT LPSTR mszReaders, + IN OUT LPDWORD pcchReaders); +#undef SCardListReaders +#define SCardListReaders dll_SCardListReadersA + +static WINSCARDAPI LONG WINAPI +(*dll_SCardConnectA)(IN SCARDCONTEXT hContext, + IN LPCSTR szReader, + IN DWORD dwShareMode, + IN DWORD dwPreferredProtocols, + OUT LPSCARDHANDLE phCard, + OUT LPDWORD pdwActiveProtocol); +#undef SCardConnect +#define SCardConnect dll_SCardConnectA + +static WINSCARDAPI LONG WINAPI +(*dll_SCardDisconnect)(IN SCARDHANDLE hCard, + IN DWORD dwDisposition); +#define SCardDisconnect dll_SCardDisconnect + +static WINSCARDAPI LONG WINAPI +(*dll_SCardTransmit)(IN SCARDHANDLE hCard, + IN LPCSCARD_IO_REQUEST pioSendPci, + IN LPCBYTE pbSendBuffer, + IN DWORD cbSendLength, + IN OUT LPSCARD_IO_REQUEST pioRecvPci, + OUT LPBYTE pbRecvBuffer, + IN OUT LPDWORD pcbRecvLength); +#define SCardTransmit dll_SCardTransmit + +static WINSCARDAPI LONG WINAPI +(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard); +#define SCardBeginTransaction dll_SCardBeginTransaction + +static WINSCARDAPI LONG WINAPI +(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition); +#define SCardEndTransaction dll_SCardEndTransaction + + +static int mingw_load_symbols(void) +{ + char *sym; + + if (dll) + return 0; + + dll = LoadLibrary("winscard"); + if (dll == NULL) { + wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll " + "library"); + return -1; + } + +#define LOADSYM(s) \ + sym = #s; \ + dll_ ## s = (void *) GetProcAddress(dll, sym); \ + if (dll_ ## s == NULL) \ + goto fail; + + LOADSYM(SCardEstablishContext); + LOADSYM(SCardReleaseContext); + LOADSYM(SCardListReadersA); + LOADSYM(SCardConnectA); + LOADSYM(SCardDisconnect); + LOADSYM(SCardTransmit); + LOADSYM(SCardBeginTransaction); + LOADSYM(SCardEndTransaction); + LOADSYM(g_rgSCardT0Pci); + LOADSYM(g_rgSCardT1Pci); + +#undef LOADSYM + + return 0; + +fail: + wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from " + "winscard.dll", sym); + FreeLibrary(dll); + dll = NULL; + return -1; +} + + +static void mingw_unload_symbols(void) +{ + if (dll == NULL) + return; + + FreeLibrary(dll); + dll = NULL; +} + +#else /* __MINGW32_VERSION */ + +#define mingw_load_symbols() 0 +#define mingw_unload_symbols() do { } while (0) + +#endif /* __MINGW32_VERSION */ + static int _scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len, - sim_types sim_type, unsigned char *aid); + sim_types sim_type, unsigned char *aid, + size_t aidlen); static int scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len); static int scard_verify_pin(struct scard_data *scard, const char *pin); +static int scard_get_record_len(struct scard_data *scard, + unsigned char recnum, unsigned char mode); +static int scard_read_record(struct scard_data *scard, + unsigned char *data, size_t len, + unsigned char recnum, unsigned char mode); static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len, @@ -175,27 +313,145 @@ static int scard_pin_needed(struct scard_data *scard, return -1; /* TODO: there could be more than one PS_DO entry because of * multiple PINs in key reference.. */ - if (ps_do) + if (ps_do > 0 && (ps_do & 0x80)) return 1; + return 0; } return -1; } +static int scard_get_aid(struct scard_data *scard, unsigned char *aid, + size_t maxlen) +{ + int rlen, rec; + struct efdir { + unsigned char appl_template_tag; /* 0x61 */ + unsigned char appl_template_len; + unsigned char appl_id_tag; /* 0x4f */ + unsigned char aid_len; + unsigned char rid[5]; + unsigned char appl_code[2]; /* 0x1002 for 3G USIM */ + } *efdir; + unsigned char buf[100]; + size_t blen; + + efdir = (struct efdir *) buf; + blen = sizeof(buf); + if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) { + wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR"); + return -1; + } + wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen); + + for (rec = 1; rec < 10; rec++) { + rlen = scard_get_record_len(scard, rec, + SIM_RECORD_MODE_ABSOLUTE); + if (rlen < 0) { + wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR " + "record length"); + return -1; + } + blen = sizeof(buf); + if (rlen > (int) blen) { + wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record"); + return -1; + } + if (scard_read_record(scard, buf, rlen, rec, + SIM_RECORD_MODE_ABSOLUTE) < 0) { + wpa_printf(MSG_DEBUG, "SCARD: Failed to read " + "EF_DIR record %d", rec); + return -1; + } + wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen); + + if (efdir->appl_template_tag != 0x61) { + wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " + "template tag 0x%x", + efdir->appl_template_tag); + continue; + } + + if (efdir->appl_template_len > rlen - 2) { + wpa_printf(MSG_DEBUG, "SCARD: Too long application " + "template (len=%d rlen=%d)", + efdir->appl_template_len, rlen); + continue; + } + + if (efdir->appl_id_tag != 0x4f) { + wpa_printf(MSG_DEBUG, "SCARD: Unexpected application " + "identifier tag 0x%x", efdir->appl_id_tag); + continue; + } + + if (efdir->aid_len < 1 || efdir->aid_len > 16) { + wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d", + efdir->aid_len); + continue; + } + + wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record", + efdir->rid, efdir->aid_len); + + if (efdir->appl_code[0] == 0x10 && + efdir->appl_code[1] == 0x02) { + wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from " + "EF_DIR record %d", rec); + break; + } + } + + if (rec >= 10) { + wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found " + "from EF_DIR records"); + return -1; + } + + if (efdir->aid_len > maxlen) { + wpa_printf(MSG_DEBUG, "SCARD: Too long AID"); + return -1; + } + + os_memcpy(aid, efdir->rid, efdir->aid_len); + + return efdir->aid_len; +} + + +/** + * scard_init - Initialize SIM/USIM connection using PC/SC + * @sim_type: Allowed SIM types (SIM, USIM, or both) + * Returns: Pointer to private data structure, or %NULL on failure + * + * This function is used to initialize SIM/USIM connection. PC/SC is used to + * open connection to the SIM/USIM card and the card is verified to support the + * selected sim_type. In addition, local flag is set if a PIN is needed to + * access some of the card functions. Once the connection is not needed + * anymore, scard_deinit() can be used to close it. + */ struct scard_data * scard_init(scard_sim_type sim_type) { - long ret, len; + long ret; + unsigned long len; struct scard_data *scard; +#ifdef CONFIG_NATIVE_WINDOWS + TCHAR *readers = NULL; +#else /* CONFIG_NATIVE_WINDOWS */ char *readers = NULL; - char buf[100]; +#endif /* CONFIG_NATIVE_WINDOWS */ + unsigned char buf[100]; size_t blen; + int transaction = 0; + int pin_needed; wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface"); - scard = malloc(sizeof(*scard)); + if (mingw_load_symbols()) + return NULL; + scard = os_zalloc(sizeof(*scard)); if (scard == NULL) return NULL; - memset(scard, 0, sizeof(*scard)); ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard->ctx); @@ -212,9 +468,12 @@ struct scard_data * scard_init(scard_sim_type sim_type) goto failed; } - readers = malloc(len); +#ifdef UNICODE + len *= 2; +#endif /* UNICODE */ + readers = os_malloc(len); if (readers == NULL) { - printf("malloc failed\n"); + wpa_printf(MSG_INFO, "SCARD: malloc failed\n"); goto failed; } @@ -233,23 +492,36 @@ struct scard_data * scard_init(scard_sim_type sim_type) * double NUL. * TODO: add support for selecting the reader; now just use the first * one.. */ +#ifdef UNICODE + wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); +#else /* UNICODE */ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); +#endif /* UNICODE */ ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &scard->card, &scard->protocol); if (ret != SCARD_S_SUCCESS) { - if (ret == SCARD_E_NO_SMARTCARD) + if (ret == (long) SCARD_E_NO_SMARTCARD) wpa_printf(MSG_INFO, "No smart card inserted."); else wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret); goto failed; } - free(readers); + os_free(readers); readers = NULL; - wpa_printf(MSG_DEBUG, "SCARD: card=%ld active_protocol=%lu", - scard->card, scard->protocol); + wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)", + (unsigned int) scard->card, scard->protocol, + scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1"); + + ret = SCardBeginTransaction(scard->card); + if (ret != SCARD_S_SUCCESS) { + wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: " + "0x%x", (unsigned int) ret); + goto failed; + } + transaction = 1; blen = sizeof(buf); @@ -257,7 +529,7 @@ struct scard_data * scard_init(scard_sim_type sim_type) if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) { wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support"); if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen, - SCARD_USIM, NULL)) { + SCARD_USIM, NULL, 0)) { wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported"); if (sim_type == SCARD_USIM_ONLY) goto failed; @@ -282,31 +554,66 @@ struct scard_data * scard_init(scard_sim_type sim_type) goto failed; } } else { - /* Select based on AID = 3G RID */ + unsigned char aid[32]; + int aid_len; + + aid_len = scard_get_aid(scard, aid, sizeof(aid)); + if (aid_len < 0) { + wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for " + "3G USIM app - try to use standard 3G RID"); + os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5); + aid_len = 5; + } + wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len); + + /* Select based on AID = 3G RID from EF_DIR. This is usually + * starting with A0 00 00 00 87. */ blen = sizeof(buf); if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type, - "\xA0\x00\x00\x00\x87")) { - wpa_printf(MSG_DEBUG, "SCARD: Failed to read 3G RID " - "AID"); + aid, aid_len)) { + wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM " + "app"); + wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID", + aid, aid_len); goto failed; } } /* Verify whether CHV1 (PIN1) is needed to access the card. */ - if (scard_pin_needed(scard, buf, blen)) { + pin_needed = scard_pin_needed(scard, buf, blen); + if (pin_needed < 0) { + wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN " + "is needed"); + goto failed; + } + if (pin_needed) { scard->pin1_required = 1; wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access"); } + ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); + if (ret != SCARD_S_SUCCESS) { + wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: " + "0x%x", (unsigned int) ret); + } + return scard; failed: - free(readers); + if (transaction) + SCardEndTransaction(scard->card, SCARD_LEAVE_CARD); + os_free(readers); scard_deinit(scard); return NULL; } +/** + * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands + * @scard: Pointer to private data from scard_init() + * pin: PIN code as an ASCII string (e.g., "1234") + * Returns: 0 on success, -1 on failure + */ int scard_set_pin(struct scard_data *scard, const char *pin) { if (scard == NULL) @@ -330,6 +637,12 @@ int scard_set_pin(struct scard_data *scard, const char *pin) } +/** + * scard_deinit - Deinitialize SIM/USIM connection + * @scard: Pointer to private data from scard_init() + * + * This function closes the SIM/USIM connect opened with scard_init(). + */ void scard_deinit(struct scard_data *scard) { long ret; @@ -353,29 +666,30 @@ void scard_deinit(struct scard_data *scard) "context (err=%ld)", ret); } } - free(scard); + os_free(scard); + mingw_unload_symbols(); } static long scard_transmit(struct scard_data *scard, - unsigned char *send, size_t send_len, - unsigned char *recv, size_t *recv_len) + unsigned char *_send, size_t send_len, + unsigned char *_recv, size_t *recv_len) { long ret; unsigned long rlen; wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send", - send, send_len); + _send, send_len); rlen = *recv_len; ret = SCardTransmit(scard->card, scard->protocol == SCARD_PROTOCOL_T1 ? SCARD_PCI_T1 : SCARD_PCI_T0, - send, (unsigned long) send_len, - NULL, recv, &rlen); + _send, (unsigned long) send_len, + NULL, _recv, &rlen); *recv_len = rlen; if (ret == SCARD_S_SUCCESS) { wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv", - recv, rlen); + _recv, rlen); } else { wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed " "(err=0x%lx)", ret); @@ -386,11 +700,12 @@ static long scard_transmit(struct scard_data *scard, static int _scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len, - sim_types sim_type, unsigned char *aid) + sim_types sim_type, unsigned char *aid, + size_t aidlen) { long ret; unsigned char resp[3]; - unsigned char cmd[10] = { SIM_CMD_SELECT }; + unsigned char cmd[50] = { SIM_CMD_SELECT }; int cmdlen; unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE }; size_t len, rlen; @@ -403,10 +718,14 @@ static int _scard_select_file(struct scard_data *scard, unsigned short file_id, wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id); if (aid) { + wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID", + aid, aidlen); + if (5 + aidlen > sizeof(cmd)) + return -1; cmd[2] = 0x04; /* Select by AID */ - cmd[4] = 5; /* len */ - memcpy(cmd + 5, aid, 5); - cmdlen = 10; + cmd[4] = aidlen; /* len */ + os_memcpy(cmd + 5, aid, aidlen); + cmdlen = 5 + aidlen; } else { cmd[5] = file_id >> 8; cmd[6] = file_id & 0xff; @@ -464,19 +783,102 @@ static int scard_select_file(struct scard_data *scard, unsigned short file_id, unsigned char *buf, size_t *buf_len) { return _scard_select_file(scard, file_id, buf, buf_len, - scard->sim_type, NULL); + scard->sim_type, NULL, 0); +} + + +static int scard_get_record_len(struct scard_data *scard, unsigned char recnum, + unsigned char mode) +{ + unsigned char buf[255]; + unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; + size_t blen; + long ret; + + if (scard->sim_type == SCARD_USIM) + cmd[0] = USIM_CLA; + cmd[2] = recnum; + cmd[3] = mode; + cmd[4] = sizeof(buf); + + blen = sizeof(buf); + ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); + if (ret != SCARD_S_SUCCESS) { + wpa_printf(MSG_DEBUG, "SCARD: failed to determine file " + "length for record %d", recnum); + return -1; + } + + wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response", + buf, blen); + + if (blen < 2 || buf[0] != 0x6c) { + wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file " + "length determination"); + return -1; + } + + return buf[1]; +} + + +static int scard_read_record(struct scard_data *scard, + unsigned char *data, size_t len, + unsigned char recnum, unsigned char mode) +{ + unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ }; + size_t blen = len + 3; + unsigned char *buf; + long ret; + + if (scard->sim_type == SCARD_USIM) + cmd[0] = USIM_CLA; + cmd[2] = recnum; + cmd[3] = mode; + cmd[4] = len; + + buf = os_malloc(blen); + if (buf == NULL) + return -1; + + ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); + if (ret != SCARD_S_SUCCESS) { + os_free(buf); + return -2; + } + if (blen != len + 2) { + wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " + "length %d (expected %d)", blen, len + 2); + os_free(buf); + return -3; + } + + if (buf[len] != 0x90 || buf[len + 1] != 0x00) { + wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected " + "status %02x %02x (expected 90 00)", + buf[len], buf[len + 1]); + os_free(buf); + return -4; + } + + os_memcpy(data, buf, len); + os_free(buf); + + return 0; } static int scard_read_file(struct scard_data *scard, unsigned char *data, size_t len) { - char cmd[5] = { SIM_CMD_READ_BIN, len }; + unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ }; size_t blen = len + 3; unsigned char *buf; long ret; - buf = malloc(blen); + cmd[4] = len; + + buf = os_malloc(blen); if (buf == NULL) return -1; @@ -484,13 +886,13 @@ static int scard_read_file(struct scard_data *scard, cmd[0] = USIM_CLA; ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen); if (ret != SCARD_S_SUCCESS) { - free(buf); + os_free(buf); return -2; } if (blen != len + 2) { wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " "length %d (expected %d)", blen, len + 2); - free(buf); + os_free(buf); return -3; } @@ -498,12 +900,12 @@ static int scard_read_file(struct scard_data *scard, wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected " "status %02x %02x (expected 90 00)", buf[len], buf[len + 1]); - free(buf); + os_free(buf); return -4; } - memcpy(data, buf, len); - free(buf); + os_memcpy(data, buf, len); + os_free(buf); return 0; } @@ -513,18 +915,18 @@ static int scard_verify_pin(struct scard_data *scard, const char *pin) { long ret; unsigned char resp[3]; - char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; + unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 }; size_t len; wpa_printf(MSG_DEBUG, "SCARD: verifying PIN"); - if (pin == NULL || strlen(pin) > 8) + if (pin == NULL || os_strlen(pin) > 8) return -1; if (scard->sim_type == SCARD_USIM) cmd[0] = USIM_CLA; - memcpy(cmd + 5, pin, strlen(pin)); - memset(cmd + 5 + strlen(pin), 0xff, 8 - strlen(pin)); + os_memcpy(cmd + 5, pin, os_strlen(pin)); + os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin)); len = sizeof(resp); ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); @@ -541,12 +943,25 @@ static int scard_verify_pin(struct scard_data *scard, const char *pin) } +/** + * scard_get_imsi - Read IMSI from SIM/USIM card + * @scard: Pointer to private data from scard_init() + * @imsi: Buffer for IMSI + * @len: Length of imsi buffer; set to IMSI length on success + * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file + * selection returns invalid result code, -3 if parsing FSP template file fails + * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set + * to needed length), -5 if reading IMSI file fails. + * + * This function can be used to read IMSI from the SIM/USIM card. If the IMSI + * file is PIN protected, scard_set_pin() must have been used to set the + * correct PIN code before calling scard_get_imsi(). + */ int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) { - char buf[100]; - size_t blen, imsilen; + unsigned char buf[100]; + size_t blen, imsilen, i; char *pos; - int i; wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI"); blen = sizeof(buf); @@ -606,7 +1021,22 @@ int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len) } -int scard_gsm_auth(struct scard_data *scard, unsigned char *rand, +/** + * scard_gsm_auth - Run GSM authentication command on SIM card + * @scard: Pointer to private data from scard_init() + * @_rand: 16-byte RAND value from HLR/AuC + * @sres: 4-byte buffer for SRES + * @kc: 8-byte buffer for Kc + * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized, + * -2 if authentication command execution fails, -3 if unknown response code + * for authentication command is received, -4 if reading of response fails, + * -5 if if response data is of unexpected length + * + * This function performs GSM authentication using SIM/USIM card and the + * provided RAND value from HLR/AuC. If authentication command can be completed + * successfully, SRES and Kc values will be written into sres and kc buffers. + */ +int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand, unsigned char *sres, unsigned char *kc) { unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG }; @@ -619,17 +1049,17 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand, if (scard == NULL) return -1; - wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", rand, 16); + wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16); if (scard->sim_type == SCARD_GSM_SIM) { cmdlen = 5 + 16; - memcpy(cmd + 5, rand, 16); + os_memcpy(cmd + 5, _rand, 16); } else { cmdlen = 5 + 1 + 16; cmd[0] = USIM_CLA; cmd[3] = 0x80; cmd[4] = 17; cmd[5] = 16; - memcpy(cmd + 6, rand, 16); + os_memcpy(cmd + 6, _rand, 16); } len = sizeof(resp); ret = scard_transmit(scard, cmd, cmdlen, resp, &len); @@ -659,8 +1089,8 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand, len); return -5; } - memcpy(sres, buf, 4); - memcpy(kc, buf + 4, 8); + os_memcpy(sres, buf, 4); + os_memcpy(kc, buf + 4, 8); } else { if (len != 1 + 4 + 1 + 8 + 2) { wpa_printf(MSG_WARNING, "SCARD: unexpected data " @@ -673,8 +1103,8 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand, "length (%d %d, expected 4 8)", buf[0], buf[5]); } - memcpy(sres, buf + 1, 4); - memcpy(kc, buf + 6, 8); + os_memcpy(sres, buf + 1, 4); + os_memcpy(kc, buf + 6, 8); } wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4); @@ -684,13 +1114,33 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand, } -int scard_umts_auth(struct scard_data *scard, unsigned char *rand, - unsigned char *autn, unsigned char *res, size_t *res_len, +/** + * scard_umts_auth - Run UMTS authentication command on USIM card + * @scard: Pointer to private data from scard_init() + * @_rand: 16-byte RAND value from HLR/AuC + * @autn: 16-byte AUTN value from HLR/AuC + * @res: 16-byte buffer for RES + * @res_len: Variable that will be set to RES length + * @ik: 16-byte buffer for IK + * @ck: 16-byte buffer for CK + * @auts: 14-byte buffer for AUTS + * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization + * failure + * + * This function performs AKA authentication using USIM card and the provided + * RAND and AUTN values from HLR/AuC. If authentication command can be + * completed successfully, RES, IK, and CK values will be written into provided + * buffers and res_len is set to length of received RES value. If USIM reports + * synchronization failure, the received AUTS value will be written into auts + * buffer. In this case, RES, IK, and CK are not valid. + */ +int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, + const unsigned char *autn, + unsigned char *res, size_t *res_len, unsigned char *ik, unsigned char *ck, unsigned char *auts) { unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] = { USIM_CMD_RUN_UMTS_ALG }; - int cmdlen; unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE }; unsigned char resp[3], buf[64], *pos, *end; size_t len; @@ -705,20 +1155,19 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand, return -1; } - wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", rand, AKA_RAND_LEN); + wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN); wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN); - cmdlen = 5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN; cmd[5] = AKA_RAND_LEN; - memcpy(cmd + 6, rand, AKA_RAND_LEN); + os_memcpy(cmd + 6, _rand, AKA_RAND_LEN); cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN; - memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); + os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN); len = sizeof(resp); ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len); if (ret != SCARD_S_SUCCESS) return -1; - if (len >= 0 && len <= sizeof(resp)) + if (len <= sizeof(resp)) wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len); if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) { @@ -735,14 +1184,14 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand, len = sizeof(buf); ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len); - if (ret != SCARD_S_SUCCESS || len < 0 || len > sizeof(buf)) + if (ret != SCARD_S_SUCCESS || len > sizeof(buf)) return -1; wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len); if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc && buf[1] == AKA_AUTS_LEN) { wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure"); - memcpy(auts, buf + 2, AKA_AUTS_LEN); + os_memcpy(auts, buf + 2, AKA_AUTS_LEN); wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN); return -2; } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) { @@ -755,7 +1204,7 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand, return -1; } *res_len = *pos++; - memcpy(res, pos, *res_len); + os_memcpy(res, pos, *res_len); pos += *res_len; wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len); @@ -765,7 +1214,7 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand, return -1; } pos++; - memcpy(ck, pos, CK_LEN); + os_memcpy(ck, pos, CK_LEN); pos += CK_LEN; wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN); @@ -775,7 +1224,7 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand, return -1; } pos++; - memcpy(ik, pos, IK_LEN); + os_memcpy(ik, pos, IK_LEN); pos += IK_LEN; wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); |