diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c index a97f9fa22..4b43a3795 100644 --- a/src/utils/pcsc_funcs.c +++ b/src/utils/pcsc_funcs.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM - * Copyright (c) 2004-2007, Jouni Malinen + * Copyright (c) 2004-2007, 2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -417,6 +417,7 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid, /** * scard_init - Initialize SIM/USIM connection using PC/SC * @sim_type: Allowed SIM types (SIM, USIM, or both) + * @reader: Reader name prefix to search for * Returns: Pointer to private data structure, or %NULL on failure * * This function is used to initialize SIM/USIM connection. PC/SC is used to @@ -425,10 +426,10 @@ static int scard_get_aid(struct scard_data *scard, unsigned char *aid, * 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) +struct scard_data * scard_init(scard_sim_type sim_type, const char *reader) { long ret; - unsigned long len; + unsigned long len, pos; struct scard_data *scard; #ifdef CONFIG_NATIVE_WINDOWS TCHAR *readers = NULL; @@ -482,17 +483,39 @@ struct scard_data * scard_init(scard_sim_type sim_type) "available."); goto failed; } - /* readers is a list of available reader. Last entry is terminated with - * double NUL. - * TODO: add support for selecting the reader; now just use the first - * one.. */ + wpa_hexdump_ascii(MSG_DEBUG, "SCARD: Readers", (u8 *) readers, len); + /* + * readers is a list of available readers. The last entry is terminated + * with double null. + */ + pos = 0; #ifdef UNICODE - wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers); + /* TODO */ #else /* UNICODE */ - wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers); + while (pos < len) { + if (reader == NULL || + os_strncmp(&readers[pos], reader, os_strlen(reader)) == 0) + break; + while (pos < len && readers[pos]) + pos++; + pos++; /* skip separating null */ + if (pos < len && readers[pos] == '\0') + pos = len; /* double null terminates list */ + } +#endif /* UNICODE */ + if (pos >= len) { + wpa_printf(MSG_WARNING, "SCARD: No reader with prefix '%s' " + "found", reader); + goto failed; + } + +#ifdef UNICODE + wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", &readers[pos]); +#else /* UNICODE */ + wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", &readers[pos]); #endif /* UNICODE */ - ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED, + ret = SCardConnect(scard->ctx, &readers[pos], SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &scard->card, &scard->protocol); if (ret != SCARD_S_SUCCESS) { if (ret == (long) SCARD_E_NO_SMARTCARD) diff --git a/src/utils/pcsc_funcs.h b/src/utils/pcsc_funcs.h index 2fd361051..507dab316 100644 --- a/src/utils/pcsc_funcs.h +++ b/src/utils/pcsc_funcs.h @@ -37,7 +37,7 @@ typedef enum { #ifdef PCSC_FUNCS -struct scard_data * scard_init(scard_sim_type sim_type); +struct scard_data * scard_init(scard_sim_type sim_type, const char *reader); void scard_deinit(struct scard_data *scard); int scard_set_pin(struct scard_data *scard, const char *pin); diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 72387f85b..9fd2a7001 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration parser and common functions - * Copyright (c) 2003-2008, Jouni Malinen + * Copyright (c) 2003-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -1832,6 +1832,8 @@ void wpa_config_free(struct wpa_config *config) os_free(config->opensc_engine_path); os_free(config->pkcs11_engine_path); os_free(config->pkcs11_module_path); + os_free(config->pcsc_reader); + os_free(config->pcsc_pin); os_free(config->driver_param); os_free(config->device_name); os_free(config->manufacturer); @@ -2704,6 +2706,8 @@ static const struct global_parse_data global_fields[] = { { STR(opensc_engine_path), 0 }, { STR(pkcs11_engine_path), 0 }, { STR(pkcs11_module_path), 0 }, + { STR(pcsc_reader), 0 }, + { STR(pcsc_pin), 0 }, { STR(driver_param), 0 }, { INT(dot11RSNAConfigPMKLifetime), 0 }, { INT(dot11RSNAConfigPMKReauthThreshold), 0 }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 72906fb7f..0e654fc49 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration file structures - * Copyright (c) 2003-2005, Jouni Malinen + * Copyright (c) 2003-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -290,6 +290,23 @@ struct wpa_config { */ char *pkcs11_module_path; + /** + * pcsc_reader - PC/SC reader name prefix + * + * If not %NULL, PC/SC reader with a name that matches this prefix is + * initialized for SIM/USIM access. Empty string can be used to match + * the first available reader. + */ + char *pcsc_reader; + + /** + * pcsc_pin - PIN for USIM, GSM SIM, and smartcards + * + * This field is used to configure PIN for SIM/USIM for EAP-SIM and + * EAP-AKA. If left out, this will be asked through control interface. + */ + char *pcsc_pin; + /** * driver_param - Driver interface parameters * diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index f8f4ff14d..12e909ae4 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration backend: text file - * Copyright (c) 2003-2008, Jouni Malinen + * Copyright (c) 2003-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -716,6 +716,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->pkcs11_module_path) fprintf(f, "pkcs11_module_path=%s\n", config->pkcs11_module_path); + if (config->pcsc_reader) + fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader); + if (config->pcsc_pin) + fprintf(f, "pcsc_pin=%s\n", config->pcsc_pin); if (config->driver_param) fprintf(f, "driver_param=%s\n", config->driver_param); if (config->dot11RSNAConfigPMKLifetime) diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index 65e6742fe..e92dc12f9 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - test code - * Copyright (c) 2003-2011, Jouni Malinen + * Copyright (c) 2003-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -856,7 +856,7 @@ static int scard_test(void) unsigned char aka_ik[IK_LEN]; unsigned char aka_ck[CK_LEN]; - scard = scard_init(SCARD_TRY_BOTH); + scard = scard_init(SCARD_TRY_BOTH, NULL); if (scard == NULL) return -1; if (scard_set_pin(scard, "1234")) { @@ -956,7 +956,7 @@ static int scard_get_triplets(int argc, char *argv[]) wpa_debug_level = 99; } - scard = scard_init(SCARD_GSM_SIM_ONLY); + scard = scard_init(SCARD_GSM_SIM_ONLY, NULL); if (scard == NULL) { printf("Failed to open smartcard connection\n"); return -1; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index ec027020c..3af6dc1a8 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -266,7 +266,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, else type = SCARD_GSM_SIM_ONLY; - wpa_s->scard = scard_init(type); + wpa_s->scard = scard_init(type, NULL); if (wpa_s->scard == NULL) { wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM " "(pcsc-lite)"); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 4c365dd45..d02ce6ae5 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -2342,6 +2342,48 @@ void wpa_supplicant_apply_ht_overrides( #endif /* CONFIG_HT_OVERRIDES */ +static int pcsc_reader_init(struct wpa_supplicant *wpa_s) +{ +#ifdef PCSC_FUNCS + size_t len; + + if (!wpa_s->conf->pcsc_reader) + return 0; + + wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader); + if (!wpa_s->scard) + return 1; + + if (wpa_s->conf->pcsc_pin && + scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) { + scard_deinit(wpa_s->scard); + wpa_s->scard = NULL; + wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed"); + return -1; + } + + len = sizeof(wpa_s->imsi) - 1; + if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) { + scard_deinit(wpa_s->scard); + wpa_s->scard = NULL; + wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI"); + return -1; + } + wpa_s->imsi[len] = '\0'; + + wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard); + + wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)", + wpa_s->imsi, wpa_s->mnc_len); + + wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard); + eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard); +#endif /* PCSC_FUNCS */ + + return 0; +} + + static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, struct wpa_interface *iface) { @@ -2563,6 +2605,9 @@ next_driver: if (wpa_bss_init(wpa_s) < 0) return -1; + if (pcsc_reader_init(wpa_s) < 0) + return -1; + return 0; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 91e574186..cb9fd5290 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -334,6 +334,10 @@ struct wpa_supplicant { * previous association event */ struct scard_data *scard; +#ifdef PCSC_FUNCS + char imsi[20]; + int mnc_len; +#endif /* PCSC_FUNCS */ unsigned char last_eapol_src[ETH_ALEN];