summaryrefslogtreecommitdiffstats
path: root/contrib/wpa_supplicant/pcsc_funcs.c
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2005-06-05 20:52:14 +0000
committersam <sam@FreeBSD.org>2005-06-05 20:52:14 +0000
commit2b0ba7bae5b60321ee7843871a2cf15ad6b3f65b (patch)
tree98be326632e2ea3857ee0d9f831c91ea0823bb0d /contrib/wpa_supplicant/pcsc_funcs.c
downloadFreeBSD-src-2b0ba7bae5b60321ee7843871a2cf15ad6b3f65b.zip
FreeBSD-src-2b0ba7bae5b60321ee7843871a2cf15ad6b3f65b.tar.gz
Stripped down import of wpa_supplicant v0.3.8
Diffstat (limited to 'contrib/wpa_supplicant/pcsc_funcs.c')
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.c776
1 files changed, 776 insertions, 0 deletions
diff --git a/contrib/wpa_supplicant/pcsc_funcs.c b/contrib/wpa_supplicant/pcsc_funcs.c
new file mode 100644
index 0000000..541661f
--- /dev/null
+++ b/contrib/wpa_supplicant/pcsc_funcs.c
@@ -0,0 +1,776 @@
+/*
+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <winscard.h>
+
+#include "common.h"
+#include "wpa_supplicant.h"
+#include "pcsc_funcs.h"
+
+
+/* See ETSI GSM 11.11 and ETSI TS 102 221 for details.
+ * SIM commands:
+ * Command APDU: CLA INS P1 P2 P3 Data
+ * CLA (class of instruction): A0 for GSM, 00 for USIM
+ * INS (instruction)
+ * P1 P2 P3 (parameters, P3 = length of Data)
+ * Response APDU: Data SW1 SW2
+ * SW1 SW2 (Status words)
+ * Commands (INS P1 P2 P3):
+ * SELECT: A4 00 00 02 <file_id, 2 bytes>
+ * GET RESPONSE: C0 00 00 <len>
+ * RUN GSM ALG: 88 00 00 00 <RAND len = 10>
+ * RUN UMTS ALG: 88 00 81 <len=0x22> data: 0x10 | RAND | 0x10 | AUTN
+ * P1 = ID of alg in card
+ * P2 = ID of secret key
+ * READ BINARY: B0 <offset high> <offset low> <len>
+ * VERIFY CHV: 20 00 <CHV number> 08
+ * CHANGE CHV: 24 00 <CHV number> 10
+ * DISABLE CHV: 26 00 01 08
+ * ENABLE CHV: 28 00 01 08
+ * UNBLOCK CHV: 2C 00 <00=CHV1, 02=CHV2> 10
+ * SLEEP: FA 00 00 00
+ */
+
+/* GSM SIM commands */
+#define SIM_CMD_SELECT 0xa0, 0xa4, 0x00, 0x00, 0x02
+#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_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08
+
+/* USIM commands */
+#define USIM_CLA 0x00
+#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22
+#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00
+
+#define USIM_FSP_TEMPL_TAG 0x62
+
+#define USIM_TLV_FILE_DESC 0x82
+#define USIM_TLV_FILE_ID 0x83
+#define USIM_TLV_DF_NAME 0x84
+#define USIM_TLV_PROPR_INFO 0xA5
+#define USIM_TLV_LIFE_CYCLE_STATUS 0x8A
+#define USIM_TLV_FILE_SIZE 0x80
+#define USIM_TLV_TOTAL_FILE_SIZE 0x81
+#define USIM_TLV_PIN_STATUS_TEMPLATE 0xC6
+#define USIM_TLV_SHORT_FILE_ID 0x88
+
+#define USIM_PS_DO_TAG 0x90
+
+#define AKA_RAND_LEN 16
+#define AKA_AUTN_LEN 16
+#define AKA_AUTS_LEN 14
+#define RES_MAX_LEN 16
+#define IK_LEN 16
+#define CK_LEN 16
+
+
+typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
+
+struct scard_data {
+ long ctx;
+ long card;
+ unsigned long protocol;
+ SCARD_IO_REQUEST recv_pci;
+ sim_types sim_type;
+};
+
+
+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);
+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, char *pin);
+
+
+static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
+ int *ps_do, int *file_len)
+{
+ unsigned char *pos, *end;
+
+ if (ps_do)
+ *ps_do = -1;
+ if (file_len)
+ *file_len = -1;
+
+ pos = buf;
+ end = pos + buf_len;
+ if (*pos != USIM_FSP_TEMPL_TAG) {
+ wpa_printf(MSG_DEBUG, "SCARD: file header did not "
+ "start with FSP template tag");
+ return -1;
+ }
+ pos++;
+ if (pos >= end)
+ return -1;
+ if ((pos + pos[0]) < end)
+ end = pos + 1 + pos[0];
+ pos++;
+ wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
+ pos, end - pos);
+
+ while (pos + 1 < end) {
+ wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV "
+ "0x%02x len=%d", pos[0], pos[1]);
+ if (pos + 2 + pos[1] > end)
+ break;
+
+ if (pos[0] == USIM_TLV_FILE_SIZE &&
+ (pos[1] == 1 || pos[1] == 2) && file_len) {
+ if (pos[1] == 1)
+ *file_len = (int) pos[2];
+ else
+ *file_len = ((int) pos[2] << 8) |
+ (int) pos[3];
+ wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
+ *file_len);
+ }
+
+ if (pos[0] == USIM_TLV_PIN_STATUS_TEMPLATE &&
+ pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
+ pos[3] >= 1 && ps_do) {
+ wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
+ pos[4]);
+ *ps_do = (int) pos[4];
+ }
+
+ pos += 2 + pos[1];
+
+ if (pos == end)
+ return 0;
+ }
+ return -1;
+}
+
+
+static int scard_pin_needed(struct scard_data *scard,
+ unsigned char *hdr, size_t hlen)
+{
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ if (hlen > SCARD_CHV1_OFFSET &&
+ !(hdr[SCARD_CHV1_OFFSET] & SCARD_CHV1_FLAG))
+ return 1;
+ return 0;
+ }
+
+ if (scard->sim_type == SCARD_USIM) {
+ int ps_do;
+ if (scard_parse_fsp_templ(hdr, hlen, &ps_do, NULL))
+ return -1;
+ /* TODO: there could be more than one PS_DO entry because of
+ * multiple PINs in key reference.. */
+ if (ps_do)
+ return 1;
+ }
+
+ return -1;
+}
+
+
+struct scard_data * scard_init(scard_sim_type sim_type, char *pin)
+{
+ long ret, len;
+ struct scard_data *scard;
+ char *readers = NULL;
+ char buf[100];
+ size_t blen;
+
+ wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
+ scard = malloc(sizeof(*scard));
+ if (scard == NULL)
+ return NULL;
+ memset(scard, 0, sizeof(*scard));
+
+ ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
+ &scard->ctx);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Could not establish smart card "
+ "context (err=%ld)", ret);
+ goto failed;
+ }
+
+ ret = SCardListReaders(scard->ctx, NULL, NULL, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed "
+ "(err=%ld)", ret);
+ goto failed;
+ }
+
+ readers = malloc(len);
+ if (readers == NULL) {
+ printf("malloc failed\n");
+ goto failed;
+ }
+
+ ret = SCardListReaders(scard->ctx, NULL, readers, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: SCardListReaders failed(2) "
+ "(err=%ld)", ret);
+ goto failed;
+ }
+ if (len < 3) {
+ wpa_printf(MSG_WARNING, "SCARD: No smart card readers "
+ "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_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
+
+ 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)
+ wpa_printf(MSG_INFO, "No smart card inserted.");
+ else
+ wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
+ goto failed;
+ }
+
+ free(readers);
+ readers = NULL;
+
+ wpa_printf(MSG_DEBUG, "SCARD: card=%ld active_protocol=%lu",
+ scard->card, scard->protocol);
+
+ blen = sizeof(buf);
+
+ scard->sim_type = SCARD_GSM_SIM;
+ 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)) {
+ wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
+ if (sim_type == SCARD_USIM_ONLY)
+ goto failed;
+ wpa_printf(MSG_DEBUG, "SCARD: Trying to use GSM SIM");
+ scard->sim_type = SCARD_GSM_SIM;
+ } else {
+ wpa_printf(MSG_DEBUG, "SCARD: USIM is supported");
+ scard->sim_type = SCARD_USIM;
+ }
+ }
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_MF, buf, &blen)) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read MF");
+ goto failed;
+ }
+
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_GSM_DF, buf, &blen)) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read GSM DF");
+ goto failed;
+ }
+ } else {
+ /* Select based on AID = 3G RID */
+ 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");
+ goto failed;
+ }
+ }
+
+ /* Verify whether CHV1 (PIN1) is needed to access the card. */
+ if (scard_pin_needed(scard, buf, blen)) {
+ wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
+ if (pin == NULL) {
+ wpa_printf(MSG_INFO, "No PIN configured for SIM "
+ "access");
+ /* TODO: ask PIN from user through a frontend (e.g.,
+ * wpa_cli) */
+ goto failed;
+ }
+ if (scard_verify_pin(scard, pin)) {
+ wpa_printf(MSG_INFO, "PIN verification failed for "
+ "SIM access");
+ /* TODO: what to do? */
+ goto failed;
+ }
+ }
+
+ return scard;
+
+failed:
+ free(readers);
+ scard_deinit(scard);
+ return NULL;
+}
+
+
+void scard_deinit(struct scard_data *scard)
+{
+ long ret;
+
+ if (scard == NULL)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SCARD: deinitializing smart card interface");
+ if (scard->card) {
+ ret = SCardDisconnect(scard->card, SCARD_UNPOWER_CARD);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to disconnect "
+ "smart card (err=%ld)", ret);
+ }
+ }
+
+ if (scard->ctx) {
+ ret = SCardReleaseContext(scard->ctx);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Failed to release smart card "
+ "context (err=%ld)", ret);
+ }
+ }
+ free(scard);
+}
+
+
+static long scard_transmit(struct scard_data *scard,
+ 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);
+ rlen = *recv_len;
+ ret = SCardTransmit(scard->card,
+ scard->protocol == SCARD_PROTOCOL_T1 ?
+ SCARD_PCI_T1 : SCARD_PCI_T0,
+ send, (unsigned long) send_len,
+ &scard->recv_pci, recv, &rlen);
+ *recv_len = rlen;
+ if (ret == SCARD_S_SUCCESS) {
+ wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
+ recv, rlen);
+ } else {
+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
+ "(err=0x%lx)", ret);
+ }
+ return ret;
+}
+
+
+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)
+{
+ long ret;
+ unsigned char resp[3];
+ unsigned char cmd[10] = { SIM_CMD_SELECT };
+ int cmdlen;
+ unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
+ size_t len, rlen;
+
+ if (sim_type == SCARD_USIM) {
+ cmd[0] = USIM_CLA;
+ cmd[3] = 0x04;
+ get_resp[0] = USIM_CLA;
+ }
+
+ wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
+ if (aid) {
+ cmd[2] = 0x04; /* Select by AID */
+ cmd[4] = 5; /* len */
+ memcpy(cmd + 5, aid, 5);
+ cmdlen = 10;
+ } else {
+ cmd[5] = file_id >> 8;
+ cmd[6] = file_id & 0xff;
+ cmdlen = 7;
+ }
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
+ "(err=0x%lx)", ret);
+ return -1;
+ }
+
+ if (len != 2) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected resp len "
+ "%d (expected 2)", (int) len);
+ return -1;
+ }
+
+ if (resp[0] == 0x98 && resp[1] == 0x04) {
+ /* Security status not satisfied (PIN_WLAN) */
+ wpa_printf(MSG_WARNING, "SCARD: Security status not satisfied "
+ "(PIN_WLAN)");
+ return -1;
+ }
+
+ if (resp[0] == 0x6e) {
+ wpa_printf(MSG_DEBUG, "SCARD: used CLA not supported");
+ return -1;
+ }
+
+ if (resp[0] != 0x6c && resp[0] != 0x9f && resp[0] != 0x61) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected response 0x%02x "
+ "(expected 0x61, 0x6c, or 0x9f)", resp[0]);
+ return -1;
+ }
+ /* Normal ending of command; resp[1] bytes available */
+ get_resp[4] = resp[1];
+ wpa_printf(MSG_DEBUG, "SCARD: trying to get response (%d bytes)",
+ resp[1]);
+
+ rlen = *buf_len;
+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &rlen);
+ if (ret == SCARD_S_SUCCESS) {
+ *buf_len = resp[1] < rlen ? resp[1] : rlen;
+ return 0;
+ }
+
+ wpa_printf(MSG_WARNING, "SCARD: SCardTransmit err=0x%lx\n", ret);
+ return -1;
+}
+
+
+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);
+}
+
+
+static int scard_read_file(struct scard_data *scard,
+ unsigned char *data, size_t len)
+{
+ char cmd[5] = { SIM_CMD_READ_BIN, len };
+ size_t blen = len + 3;
+ unsigned char *buf;
+ long ret;
+
+ buf = malloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ 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);
+ return -3;
+ }
+
+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+ wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
+ "status %02x %02x (expected 90 00)",
+ buf[len], buf[len + 1]);
+ free(buf);
+ return -4;
+ }
+
+ memcpy(data, buf, len);
+ free(buf);
+
+ return 0;
+}
+
+
+static int scard_verify_pin(struct scard_data *scard, char *pin)
+{
+ long ret;
+ unsigned char resp[3];
+ char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
+
+ if (pin == NULL || 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));
+
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -2;
+
+ if (len != 2 || resp[0] != 0x90 || resp[1] != 0x00) {
+ wpa_printf(MSG_WARNING, "SCARD: PIN verification failed");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "SCARD: PIN verified successfully");
+ return 0;
+}
+
+
+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
+{
+ char buf[100];
+ size_t blen, imsilen;
+ char *pos;
+ int i;
+
+ wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_GSM_EF_IMSI, buf, &blen))
+ return -1;
+ if (blen < 4) {
+ wpa_printf(MSG_WARNING, "SCARD: too short (GSM) EF-IMSI "
+ "header (len=%d)", blen);
+ return -2;
+ }
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ blen = (buf[2] << 8) | buf[3];
+ } else {
+ int file_size;
+ if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
+ return -3;
+ blen = file_size;
+ }
+ if (blen < 2 || blen > sizeof(buf)) {
+ wpa_printf(MSG_DEBUG, "SCARD: invalid IMSI file length=%d",
+ blen);
+ return -3;
+ }
+
+ imsilen = (blen - 2) * 2 + 1;
+ wpa_printf(MSG_DEBUG, "SCARD: IMSI file length=%d imsilen=%d",
+ blen, imsilen);
+ if (blen < 2 || imsilen > *len) {
+ *len = imsilen;
+ return -4;
+ }
+
+ if (scard_read_file(scard, buf, blen))
+ return -5;
+
+ pos = imsi;
+ *pos++ = '0' + (buf[1] >> 4 & 0x0f);
+ for (i = 2; i < blen; i++) {
+ unsigned char digit;
+
+ digit = buf[i] & 0x0f;
+ if (digit < 10)
+ *pos++ = '0' + digit;
+ else
+ imsilen--;
+
+ digit = buf[i] >> 4 & 0x0f;
+ if (digit < 10)
+ *pos++ = '0' + digit;
+ else
+ imsilen--;
+ }
+ *len = imsilen;
+
+ return 0;
+}
+
+
+int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
+ unsigned char *sres, unsigned char *kc)
+{
+ unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
+ int cmdlen;
+ unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
+ unsigned char resp[3], buf[12 + 3 + 2];
+ size_t len;
+ long ret;
+
+ if (scard == NULL)
+ return -1;
+
+ 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);
+ } else {
+ cmdlen = 5 + 1 + 16;
+ cmd[0] = USIM_CLA;
+ cmd[3] = 0x80;
+ cmd[4] = 17;
+ cmd[5] = 16;
+ memcpy(cmd + 6, rand, 16);
+ }
+ len = sizeof(resp);
+ ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -2;
+
+ if ((scard->sim_type == SCARD_GSM_SIM &&
+ (len != 2 || resp[0] != 0x9f || resp[1] != 0x0c)) ||
+ (scard->sim_type == SCARD_USIM &&
+ (len != 2 || resp[0] != 0x61 || resp[1] != 0x0e))) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected response for GSM "
+ "auth request (len=%d resp=%02x %02x)",
+ len, resp[0], resp[1]);
+ return -3;
+ }
+ get_resp[4] = resp[1];
+
+ len = sizeof(buf);
+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
+ if (ret != SCARD_S_SUCCESS)
+ return -4;
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ if (len != 4 + 8 + 2) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected data "
+ "length for GSM auth (len=%d, expected 14)",
+ len);
+ return -5;
+ }
+ memcpy(sres, buf, 4);
+ memcpy(kc, buf + 4, 8);
+ } else {
+ if (len != 1 + 4 + 1 + 8 + 2) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected data "
+ "length for USIM auth (len=%d, "
+ "expected 16)", len);
+ return -5;
+ }
+ if (buf[0] != 4 || buf[5] != 8) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected SREC/Kc "
+ "length (%d %d, expected 4 8)",
+ buf[0], buf[5]);
+ }
+ memcpy(sres, buf + 1, 4);
+ memcpy(kc, buf + 6, 8);
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - Kc", kc, 8);
+
+ return 0;
+}
+
+
+int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
+ 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;
+ long ret;
+
+ if (scard == NULL)
+ return -1;
+
+ if (scard->sim_type == SCARD_GSM_SIM) {
+ wpa_printf(MSG_ERROR, "SCARD: Non-USIM card - cannot do UMTS "
+ "auth");
+ return -1;
+ }
+
+ 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);
+ cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
+ 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))
+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
+
+ if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
+ wpa_printf(MSG_WARNING, "SCARD: UMTS auth failed - "
+ "MAC != XMAC");
+ return -1;
+ } else if (len != 2 || resp[0] != 0x61) {
+ wpa_printf(MSG_WARNING, "SCARD: unexpected response for UMTS "
+ "auth request (len=%d resp=%02x %02x)",
+ len, resp[0], resp[1]);
+ return -1;
+ }
+ get_resp[4] = resp[1];
+
+ len = sizeof(buf);
+ ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
+ if (ret != SCARD_S_SUCCESS || len < 0 || 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);
+ wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
+ return -2;
+ } else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
+ pos = buf + 1;
+ end = buf + len;
+
+ /* RES */
+ if (pos[0] > RES_MAX_LEN || pos + pos[0] > end) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid RES");
+ return -1;
+ }
+ *res_len = *pos++;
+ memcpy(res, pos, *res_len);
+ pos += *res_len;
+ wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
+
+ /* CK */
+ if (pos[0] != CK_LEN || pos + CK_LEN > end) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid CK");
+ return -1;
+ }
+ pos++;
+ memcpy(ck, pos, CK_LEN);
+ pos += CK_LEN;
+ wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
+
+ /* IK */
+ if (pos[0] != IK_LEN || pos + IK_LEN > end) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid IK");
+ return -1;
+ }
+ pos++;
+ memcpy(ik, pos, IK_LEN);
+ pos += IK_LEN;
+ wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
+
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "SCARD: Unrecognized response");
+ return -1;
+}
OpenPOWER on IntegriCloud