Added SIM card backend based on pcsc-lite
authorDuncan Salerno <duncan.salerno@googlemail.com>
Mon, 4 Apr 2011 06:51:50 +0000 (08:51 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 4 Apr 2011 06:51:50 +0000 (08:51 +0200)
configure.in
src/libcharon/Makefile.am
src/libcharon/plugins/eap_sim_pcsc/Makefile.am [new file with mode: 0644]
src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_card.c [new file with mode: 0644]
src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_card.h [new file with mode: 0644]
src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_plugin.c [new file with mode: 0644]
src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_plugin.h [new file with mode: 0644]

index 5339e7d..4c0eed6 100644 (file)
@@ -112,6 +112,7 @@ ARG_ENABL_SET([unit-tests],     [enable unit tests on IKEv2 daemon startup.])
 ARG_ENABL_SET([load-tester],    [enable load testing plugin for IKEv2 daemon.])
 ARG_ENABL_SET([eap-sim],        [enable SIM authentication module for EAP.])
 ARG_ENABL_SET([eap-sim-file],   [enable EAP-SIM backend based on a triplet file.])
+ARG_ENABL_SET([eap-sim-pcsc],   [enable EAP-SIM backend based on a smartcard reader. Requires libpcsclite.])
 ARG_ENABL_SET([eap-simaka-sql], [enable EAP-SIM/AKA backend based on a triplet/quintuplet SQL database.])
 ARG_ENABL_SET([eap-simaka-pseudonym], [enable EAP-SIM/AKA pseudonym storage plugin.])
 ARG_ENABL_SET([eap-simaka-reauth],    [enable EAP-SIM/AKA reauthentication data storage plugin.])
@@ -632,6 +633,12 @@ if test x$maemo = xtrue; then
        AC_SUBST(dbusservicedir)
 fi
 
+if test x$eap_sim_pcsc = xtrue; then
+       PKG_CHECK_MODULES(pcsclite, [libpcsclite])
+       AC_SUBST(pcsclite_CFLAGS)
+       AC_SUBST(pcsclite_LIBS)
+fi
+
 if test x$nm = xtrue; then
        PKG_CHECK_EXISTS([libnm-glib],
                [PKG_CHECK_MODULES(nm, [NetworkManager gthread-2.0 libnm-glib libnm-glib-vpn])],
@@ -761,6 +768,7 @@ ADD_PLUGIN([updown],               [c libcharon])
 ADD_PLUGIN([eap-identity],         [c libcharon])
 ADD_PLUGIN([eap-sim],              [c libcharon])
 ADD_PLUGIN([eap-sim-file],         [c libcharon])
+ADD_PLUGIN([eap-sim-pcsc],         [c libcharon])
 ADD_PLUGIN([eap-simaka-sql],       [c libcharon])
 ADD_PLUGIN([eap-simaka-pseudonym], [c libcharon])
 ADD_PLUGIN([eap-simaka-reauth],    [c libcharon])
@@ -872,6 +880,7 @@ AM_CONDITIONAL(USE_DUPLICHECK, test x$duplicheck = xtrue)
 AM_CONDITIONAL(USE_COUPLING, test x$coupling = xtrue)
 AM_CONDITIONAL(USE_EAP_SIM, test x$eap_sim = xtrue)
 AM_CONDITIONAL(USE_EAP_SIM_FILE, test x$eap_sim_file = xtrue)
+AM_CONDITIONAL(USE_EAP_SIM_PCSC, test x$eap_sim_pcsc = xtrue)
 AM_CONDITIONAL(USE_EAP_SIMAKA_SQL, test x$eap_simaka_sql = xtrue)
 AM_CONDITIONAL(USE_EAP_SIMAKA_PSEUDONYM, test x$eap_simaka_pseudonym = xtrue)
 AM_CONDITIONAL(USE_EAP_SIMAKA_REAUTH, test x$eap_simaka_reauth = xtrue)
@@ -1027,6 +1036,7 @@ AC_OUTPUT(
        src/libcharon/plugins/eap_gtc/Makefile
        src/libcharon/plugins/eap_sim/Makefile
        src/libcharon/plugins/eap_sim_file/Makefile
+       src/libcharon/plugins/eap_sim_pcsc/Makefile
        src/libcharon/plugins/eap_simaka_sql/Makefile
        src/libcharon/plugins/eap_simaka_pseudonym/Makefile
        src/libcharon/plugins/eap_simaka_reauth/Makefile
index bfddb80..d72cb3a 100644 (file)
@@ -223,6 +223,13 @@ if MONOLITHIC
 endif
 endif
 
+if USE_EAP_SIM_PCSC
+  SUBDIRS += plugins/eap_sim_pcsc
+if MONOLITHIC
+  libcharon_la_LIBADD += plugins/eap_sim_pcsc/libstrongswan-eap-sim-pcsc.la
+endif
+endif
+
 if USE_EAP_SIMAKA_SQL
   SUBDIRS += plugins/eap_simaka_sql
 if MONOLITHIC
diff --git a/src/libcharon/plugins/eap_sim_pcsc/Makefile.am b/src/libcharon/plugins/eap_sim_pcsc/Makefile.am
new file mode 100644 (file)
index 0000000..a6b6964
--- /dev/null
@@ -0,0 +1,18 @@
+
+INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \
+       -I$(top_srcdir)/src/libcharon ${pcsclite_CFLAGS}
+
+AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${sysconfdir}\"
+
+if MONOLITHIC
+noinst_LTLIBRARIES = libstrongswan-eap-sim-pcsc.la
+else
+plugin_LTLIBRARIES = libstrongswan-eap-sim-pcsc.la
+endif
+
+libstrongswan_eap_sim_pcsc_la_SOURCES = \
+       eap_sim_pcsc_plugin.h eap_sim_pcsc_plugin.c \
+       eap_sim_pcsc_card.h eap_sim_pcsc_card.c
+
+libstrongswan_eap_sim_pcsc_la_LDFLAGS = -module -avoid-version
+libstrongswan_eap_sim_pcsc_la_LIBADD  = ${pcsclite_LIBS}
diff --git a/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_card.c b/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_card.c
new file mode 100644 (file)
index 0000000..2aa25a4
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2011 Duncan Salerno
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "eap_sim_pcsc_card.h"
+
+#include <PCSC/wintypes.h>
+#include <PCSC/winscard.h>
+#include <daemon.h>
+
+typedef struct private_eap_sim_pcsc_card_t private_eap_sim_pcsc_card_t;
+
+/**
+ * Private data of an eap_sim_pcsc_card_t object.
+ */
+struct private_eap_sim_pcsc_card_t {
+
+       /**
+        * Public eap_sim_pcsc_card_t interface.
+        */
+       eap_sim_pcsc_card_t public;
+};
+
+/**
+ * Maximum length for an IMSI.
+ */
+#define SIM_IMSI_MAX_LEN 15
+
+/**
+ * Length of the status at the end of response APDUs.
+ */
+#define APDU_STATUS_LEN 2
+
+/**
+ * First byte of status word indicating success.
+ */
+#define APDU_SW1_SUCCESS 0x90
+
+/**
+ * First byte of status word indicating there is response data to be read.
+ */
+#define APDU_SW1_RESPONSE_DATA 0x9f
+
+/**
+ * Decode IMSI EF (Elementary File) into an ASCII string
+ */
+static bool decode_imsi_ef(unsigned char *input, int input_len, char *output)
+{
+       /* Only digits 0-9 valid in IMSIs */
+       static const char bcd_num_digits[] = {
+               '0', '1', '2', '3', '4', '5', '6', '7',
+               '8', '9', '\0', '\0', '\0', '\0', '\0', '\0'
+       };
+       int i;
+
+       /* Check length byte matches how many bytes we have, and that input is correct length for an IMSI */
+       if (input[0] != input_len-1 || input_len < 2 || input_len > 9)
+       {
+               return FALSE;
+       }
+
+       /* Check type byte is IMSI */
+       if ((input[1] & 0xf) != 0x9)
+       {
+               return FALSE;
+       }
+       *output++ = bcd_num_digits[input[1] >> 4];
+
+       for (i = 2; i < input_len; i++)
+       {
+               *output++ = bcd_num_digits[input[i] & 0xf];
+               *output++ = bcd_num_digits[input[i] >> 4];
+       }
+
+       *output++ = '\0';
+       return TRUE;
+}
+
+/**
+ * Implementation of sim_card_t.get_triplet
+ */
+static bool get_triplet(private_eap_sim_pcsc_card_t *this,
+                                               identification_t *id, char *rand, char *sres, char *kc)
+{
+       status_t found = FALSE;
+       LONG rv;
+       SCARDCONTEXT hContext;
+       DWORD dwReaders;
+       LPSTR mszReaders;
+       char *cur_reader;
+       char full_nai[128];
+
+       snprintf(full_nai, sizeof(full_nai), "%Y", id);
+
+       DBG2(DBG_IKE, "looking for triplet: %Y rand %b", id, rand, SIM_RAND_LEN);
+
+       rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
+       if (rv != SCARD_S_SUCCESS)
+       {
+               DBG1(DBG_IKE, "SCardEstablishContext: %s", pcsc_stringify_error(rv));
+               return FALSE;
+       }
+       
+       rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
+       if (rv != SCARD_S_SUCCESS)
+       {
+               DBG1(DBG_IKE, "SCardListReaders: %s", pcsc_stringify_error(rv));
+               return FALSE;
+       }
+       mszReaders = malloc(sizeof(char)*dwReaders);
+
+       rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
+       if (rv != SCARD_S_SUCCESS)
+       {
+               DBG1(DBG_IKE, "SCardListReaders: %s", pcsc_stringify_error(rv));
+               return FALSE;
+       }               
+
+       /* mszReaders is a multi-string of readers, separated by '\0' and terminated by an additional '\0' */
+       for (cur_reader = mszReaders; *cur_reader != '\0' && found == FALSE; cur_reader += strlen(cur_reader)+1)
+       {
+               DWORD dwActiveProtocol = -1;
+               SCARDHANDLE hCard;
+               SCARD_IO_REQUEST *pioSendPci;
+               SCARD_IO_REQUEST pioRecvPci;
+               BYTE pbRecvBuffer[64];
+               DWORD dwRecvLength;
+               char imsi[SIM_IMSI_MAX_LEN+1];
+
+               /* See GSM 11.11 for SIM APDUs */
+               BYTE pbSelectMF[] = { 0xa0, 0xa4, 0x00, 0x00, 0x02, 0x3f, 0x00 };
+               BYTE pbSelectDFGSM[] = { 0xa0, 0xa4, 0x00, 0x00, 0x02, 0x7f, 0x20 };
+               BYTE pbSelectIMSI[] = { 0xa0, 0xa4, 0x00, 0x00, 0x02, 0x6f, 0x07 };
+               BYTE pbReadBinary[] = { 0xa0, 0xb0, 0x00, 0x00, 0x09 };
+               BYTE pbRunGSMAlgorithm[] = { 0xa0, 0x88, 0x00, 0x00, 0x10, /*RAND*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+               BYTE pbGetResponse[] = { 0xa0, 0xc0, 0x00, 0x00, 0x0c };
+
+               /* Copy RAND into APDU */
+               memcpy(pbRunGSMAlgorithm+5, rand, SIM_RAND_LEN);
+
+               rv = SCardConnect(hContext, cur_reader, SCARD_SHARE_SHARED,
+                       SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardConnect: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+
+               switch(dwActiveProtocol)
+               {
+                       case SCARD_PROTOCOL_T0:
+                               pioSendPci = SCARD_PCI_T0;
+                               break;
+                       case SCARD_PROTOCOL_T1:
+                               pioSendPci = SCARD_PCI_T1;
+                               break;
+                       default:
+                               DBG1(DBG_IKE, "Unknown SCARD_PROTOCOL");
+                               continue;
+               }
+
+               /* APDU: Select MF */
+               dwRecvLength = sizeof(pbRecvBuffer);
+               rv = SCardTransmit(hCard, pioSendPci, pbSelectMF, sizeof(pbSelectMF),
+                       &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+               if( dwRecvLength < APDU_STATUS_LEN || pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA )
+               {
+                       DBG1(DBG_IKE, "Select MF failed: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               /* APDU: Select DF GSM */
+               dwRecvLength = sizeof(pbRecvBuffer);
+               rv = SCardTransmit(hCard, pioSendPci, pbSelectDFGSM, sizeof(pbSelectDFGSM),
+                       &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+               if( dwRecvLength < APDU_STATUS_LEN || pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA )
+               {
+                       DBG1(DBG_IKE, "Select DF GSM failed: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               /* APDU: Select IMSI */
+               dwRecvLength = sizeof(pbRecvBuffer);
+               rv = SCardTransmit(hCard, pioSendPci, pbSelectIMSI, sizeof(pbSelectIMSI),
+                       &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+               if( dwRecvLength < APDU_STATUS_LEN || pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA )
+               {
+                       DBG1(DBG_IKE, "Select IMSI failed: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               /* APDU: Read Binary (of IMSI) */
+               dwRecvLength = sizeof(pbRecvBuffer);
+               rv = SCardTransmit(hCard, pioSendPci, pbReadBinary, sizeof(pbReadBinary),
+                       &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+               if( dwRecvLength < APDU_STATUS_LEN || pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_SUCCESS )
+               {
+                       DBG1(DBG_IKE, "Select IMSI failed: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               if (!decode_imsi_ef(pbRecvBuffer, dwRecvLength-APDU_STATUS_LEN, imsi) )
+               {
+                       DBG1(DBG_IKE, "Couldn't decode IMSI EF: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               /* The IMSI could be post/prefixed in the full NAI, so just make sure it's in there */
+               if( !(strlen(full_nai) && strstr(full_nai, imsi)) )
+               {
+                       DBG1(DBG_IKE, "Not the SIM we're looking for, IMSI: %s", imsi);
+                       continue;
+               }
+
+               /* APDU: Run GSM Algorithm */
+               dwRecvLength = sizeof(pbRecvBuffer);
+               rv = SCardTransmit(hCard, pioSendPci, pbRunGSMAlgorithm, sizeof(pbRunGSMAlgorithm),
+                       &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+               if( dwRecvLength < APDU_STATUS_LEN || pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_RESPONSE_DATA )
+               {
+                       DBG1(DBG_IKE, "Run GSM Algorithm failed: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               /* APDU: Get Response (of Run GSM Algorithm) */
+               dwRecvLength = sizeof(pbRecvBuffer);
+               rv = SCardTransmit(hCard, pioSendPci, pbGetResponse, sizeof(pbGetResponse),
+                       &pioRecvPci, pbRecvBuffer, &dwRecvLength);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardTransmit: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+
+               if( dwRecvLength < APDU_STATUS_LEN || pbRecvBuffer[dwRecvLength-APDU_STATUS_LEN] != APDU_SW1_SUCCESS )
+               {
+                       DBG1(DBG_IKE, "Get Response failed: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               /* Extract out Kc and SRES from response */
+               if( dwRecvLength == SIM_SRES_LEN + SIM_KC_LEN + APDU_STATUS_LEN )
+               {
+                       memcpy(sres, pbRecvBuffer, SIM_SRES_LEN);
+                       memcpy(kc, pbRecvBuffer+4, SIM_KC_LEN);
+                       /* This will also cause the loop to exit */
+                       found = TRUE;
+               }
+               else
+               {
+                       DBG1(DBG_IKE, "Get Response incorrect length: %b", pbRecvBuffer, dwRecvLength);
+                       continue;
+               }
+
+               rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
+               if (rv != SCARD_S_SUCCESS)
+               {
+                       DBG1(DBG_IKE, "SCardDisconnect: %s", pcsc_stringify_error(rv));
+                       continue;
+               }
+       }
+
+       rv = SCardReleaseContext(hContext);
+       if (rv != SCARD_S_SUCCESS)
+       {
+               DBG1(DBG_IKE, "SCardReleaseContext: %s", pcsc_stringify_error(rv));
+       }
+
+       free(mszReaders);
+       return found;
+}
+
+/**
+ * Implementation of sim_card_t.get_quintuplet
+ */
+static status_t get_quintuplet()
+{
+       return NOT_SUPPORTED;
+}
+
+/**
+ * Implementation of eap_sim_pcsc_card_t.destroy.
+ */
+static void destroy(private_eap_sim_pcsc_card_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+eap_sim_pcsc_card_t *eap_sim_pcsc_card_create()
+{
+       private_eap_sim_pcsc_card_t *this = malloc_thing(private_eap_sim_pcsc_card_t);
+
+       this->public.card.get_triplet = (bool(*)(sim_card_t*, identification_t *id, char rand[SIM_RAND_LEN], char sres[SIM_SRES_LEN], char kc[SIM_KC_LEN]))get_triplet;
+       this->public.card.get_quintuplet = (status_t(*)(sim_card_t*, identification_t *id, char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN], char ik[AKA_IK_LEN], char res[AKA_RES_MAX], int *res_len))get_quintuplet;
+       this->public.card.resync = (bool(*)(sim_card_t*, identification_t *id, char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]))return_false;
+       this->public.card.get_pseudonym = (identification_t*(*)(sim_card_t*, identification_t *perm))return_null;
+       this->public.card.set_pseudonym = (void(*)(sim_card_t*, identification_t *id, identification_t *pseudonym))nop;
+       this->public.card.get_reauth = (identification_t*(*)(sim_card_t*, identification_t *id, char mk[HASH_SIZE_SHA1], u_int16_t *counter))return_null;
+       this->public.card.set_reauth = (void(*)(sim_card_t*, identification_t *id, identification_t* next, char mk[HASH_SIZE_SHA1], u_int16_t counter))nop;
+       this->public.destroy = (void(*)(eap_sim_pcsc_card_t*))destroy;
+
+       return &this->public;
+}
+
diff --git a/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_card.h b/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_card.h
new file mode 100644 (file)
index 0000000..e765965
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 Duncan Salerno
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup eap_sim_pcsc_card eap_sim_pcsc_card
+ * @{ @ingroup eap_sim_pcsc
+ */
+
+#ifndef EAP_SIM_PCSC_CARD_H_
+#define EAP_SIM_PCSC_CARD_H_
+
+#include <sa/authenticators/eap/sim_manager.h>
+
+typedef struct eap_sim_pcsc_card_t eap_sim_pcsc_card_t;
+
+/**
+ * SIM card implementation using a PCSC reader.
+ */
+struct eap_sim_pcsc_card_t {
+
+       /**
+        * Implements sim_card_t interface
+        */
+       sim_card_t card;
+
+       /**
+        * Destroy a eap_sim_pcsc_card_t.
+        */
+       void (*destroy)(eap_sim_pcsc_card_t *this);
+};
+
+/**
+ * Create a eap_sim_pcsc_card instance.
+ */
+eap_sim_pcsc_card_t *eap_sim_pcsc_card_create();
+
+#endif /** EAP_SIM_PCSC_CARD_H_ @}*/
diff --git a/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_plugin.c b/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_plugin.c
new file mode 100644 (file)
index 0000000..42726a5
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Duncan Salerno
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "eap_sim_pcsc_plugin.h"
+#include "eap_sim_pcsc_card.h"
+
+#include <daemon.h>
+
+typedef struct private_eap_sim_pcsc_t private_eap_sim_pcsc_t;
+
+/**
+ * Private data of an eap_sim_pcsc_t object.
+ */
+struct private_eap_sim_pcsc_t {
+
+       /**
+        * Public eap_sim_pcsc_plugin_t interface.
+        */
+       eap_sim_pcsc_plugin_t public;
+
+       /**
+        * SIM card
+        */
+       eap_sim_pcsc_card_t *card;
+};
+
+/**
+ * Implementation of eap_sim_pcsc_t.destroy.
+ */
+static void destroy(private_eap_sim_pcsc_t *this)
+{
+       charon->sim->remove_card(charon->sim, &this->card->card);
+       this->card->destroy(this->card);
+       free(this);
+}
+
+/**
+ * See header
+ */
+plugin_t *eap_sim_pcsc_plugin_create()
+{
+       private_eap_sim_pcsc_t *this = malloc_thing(private_eap_sim_pcsc_t);
+
+       this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
+       this->card = eap_sim_pcsc_card_create();
+       charon->sim->add_card(charon->sim, &this->card->card);
+
+       return &this->public.plugin;
+}
+
diff --git a/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_plugin.h b/src/libcharon/plugins/eap_sim_pcsc/eap_sim_pcsc_plugin.h
new file mode 100644 (file)
index 0000000..a03ca1f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 Duncan Salerno
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup eap_sim_pcsc eap_sim_pcsc
+ * @ingroup cplugins
+ *
+ * @defgroup eap_sim_pcsc_plugin eap_sim_pcsc_plugin
+ * @{ @ingroup eap_sim_pcsc
+ */
+
+#ifndef EAP_SIM_PCSC_PLUGIN_H_
+#define EAP_SIM_PCSC_PLUGIN_H_
+
+#include <plugins/plugin.h>
+
+typedef struct eap_sim_pcsc_plugin_t eap_sim_pcsc_plugin_t;
+
+/**
+ * Plugin to provide a SIM card from a PCSC reader.
+ */
+struct eap_sim_pcsc_plugin_t {
+
+       /**
+        * implements plugin interface
+        */
+       plugin_t plugin;
+};
+
+#endif /** EAP_SIM_PCSC_PLUGIN_H_ @}*/