Let ACardEmulator provide installed AIDs

This commit is contained in:
Jan-Christopher Pien
2016-10-12 00:17:16 +02:00
committed by Frank Morgner
parent dae5622992
commit 3501843159
6 changed files with 118 additions and 45 deletions

View File

@@ -23,12 +23,6 @@
package com.vsmartcard.acardemulator; package com.vsmartcard.acardemulator;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
import java.util.Arrays;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@@ -37,13 +31,25 @@ import android.content.pm.Signature;
import android.os.Binder; import android.os.Binder;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.widget.Toast; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.Toast;
import com.samsung.android.sdk.SsdkUnsupportedException; import com.samsung.android.sdk.SsdkUnsupportedException;
import com.samsung.android.sdk.accessory.*; import com.samsung.android.sdk.accessory.SA;
import com.samsung.android.sdk.accessory.SAAgent;
import com.samsung.android.sdk.accessory.SAAuthenticationToken;
import com.samsung.android.sdk.accessory.SAPeerAgent;
import com.samsung.android.sdk.accessory.SASocket;
import com.vsmartcard.acardemulator.emulators.EmulatorSingleton; import com.vsmartcard.acardemulator.emulators.EmulatorSingleton;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import javax.security.cert.CertificateException;
import javax.security.cert.X509Certificate;
public class SmartcardProviderService extends SAAgent { public class SmartcardProviderService extends SAAgent {
private static final String TAG = "ACardEmulator"; private static final String TAG = "ACardEmulator";
private static final int ACCESSORY_CHANNEL_ID = 104; private static final int ACCESSORY_CHANNEL_ID = 104;
@@ -199,14 +205,34 @@ public class SmartcardProviderService extends SAAgent {
if (mConnectionHandler == null) { if (mConnectionHandler == null) {
return; return;
} }
final byte[] response = EmulatorSingleton.process(getApplicationContext(), data); final byte[] sendResponse;
if (data[0] == 'd') {
// APDU is sent
byte[] newData = new byte[data.length - 1];
System.arraycopy(data, 1, newData, 0, data.length - 1);
byte[] response = EmulatorSingleton.process(getApplicationContext(), newData);
sendResponse = new byte[response.length + 1];
sendResponse[0] = 'd';
System.arraycopy(response, 0, sendResponse, 1, response.length);
} else if (data[0] == 'a') {
// request for aids
String[] aidList = EmulatorSingleton.getRegisteredAids(getApplicationContext());
String aidListJoined = TextUtils.join(",", aidList);
sendResponse = new byte[aidListJoined.length() + 1];
sendResponse[0] = 'a';
byte[] aids = aidListJoined.getBytes();
System.arraycopy(aids, 0, sendResponse, 1, aids.length);
} else {
Log.e(TAG, "unknown message from consumer: " + new String(data));
return;
}
new Thread(new Runnable() { new Thread(new Runnable() {
public void run() { public void run() {
try { try {
mConnectionHandler.secureSend(ACCESSORY_CHANNEL_ID, response); mConnectionHandler.secureSend(ACCESSORY_CHANNEL_ID, sendResponse);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
}).start(); }).start();
} }

View File

@@ -22,13 +22,25 @@ package com.vsmartcard.acardemulator.emulators;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.nfc.NfcAdapter;
import android.nfc.cardemulation.CardEmulation;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.XmlRes;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.util.Log; import android.util.Log;
import com.vsmartcard.acardemulator.R; import com.vsmartcard.acardemulator.R;
import com.vsmartcard.acardemulator.Util; import com.vsmartcard.acardemulator.Util;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class EmulatorSingleton { public class EmulatorSingleton {
public static final String TAG = "com.vsmartcard.acardemulator.EmulatorService"; public static final String TAG = "com.vsmartcard.acardemulator.EmulatorService";
public static final String EXTRA_CAPDU = "MSG_CAPDU"; public static final String EXTRA_CAPDU = "MSG_CAPDU";
@@ -90,6 +102,32 @@ public class EmulatorSingleton {
return rapdu; return rapdu;
} }
public static String[] getRegisteredAids(Context context) {
List<String> aidList = new ArrayList<>();
XmlResourceParser aidXmlParser = context.getResources().getXml(R.xml.aid_list);
try {
while (aidXmlParser.getEventType() != XmlPullParser.END_DOCUMENT) {
if (aidXmlParser.getEventType() == XmlPullParser.START_TAG) {
if (aidXmlParser.getName().equals("aid-filter")) {
int aid = aidXmlParser.getAttributeResourceValue(0, -1);
if (aid != -1) {
aidList.add(context.getResources().getString(aid));
}
}
}
aidXmlParser.next();
}
aidXmlParser.close();
} catch (XmlPullParserException | IOException e) {
Log.e(TAG.substring(0, 23), "Couldn't parse aid xml list.");
}
return aidList.toArray(new String[0]);
}
public static void deactivate() { public static void deactivate() {
emulator.deactivate(); emulator.deactivate();
} }

View File

@@ -4,6 +4,7 @@
#include <nfc.h> #include <nfc.h>
void send_apdu_response(nfc_se_h handle, unsigned char *resp, unsigned int resp_len); void send_apdu_response(nfc_se_h handle, unsigned char *resp, unsigned int resp_len);
void install_aids(void *buffer, unsigned int buffer_size);
extern gboolean agent_connected; extern gboolean agent_connected;

View File

@@ -16,7 +16,6 @@ void initialize_sap();
gboolean find_peers(); gboolean find_peers();
gboolean request_service_connection(void); gboolean request_service_connection(void);
gboolean terminate_service_connection(void); gboolean terminate_service_connection(void);
gboolean send_data(nfc_se_h nfc_handle, void *message, unsigned int message_len); gboolean send_data(nfc_se_h nfc_handle, char* prefix, unsigned int prefix_len, void *message, unsigned int message_len);
GSList* request_installed_aids();
#endif /* __tcardemulator_H__ */ #endif /* __tcardemulator_H__ */

View File

@@ -25,8 +25,7 @@ static priv_s priv_data = { 0 };
void on_peer_agent_updated(sap_peer_agent_h peer_agent, void on_peer_agent_updated(sap_peer_agent_h peer_agent,
sap_peer_agent_status_e peer_status, sap_peer_agent_status_e peer_status,
sap_peer_agent_found_result_e result, sap_peer_agent_found_result_e result,
void *user_data) void *user_data) {
{
switch (result) { switch (result) {
case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED: case SAP_PEER_AGENT_FOUND_RESULT_DEVICE_NOT_CONNECTED:
dlog_print(DLOG_INFO, LOG_TAG, "device is not connected"); dlog_print(DLOG_INFO, LOG_TAG, "device is not connected");
@@ -61,8 +60,7 @@ void on_peer_agent_updated(sap_peer_agent_h peer_agent,
static void on_service_connection_terminated(sap_peer_agent_h peer_agent, static void on_service_connection_terminated(sap_peer_agent_h peer_agent,
sap_socket_h socket, sap_socket_h socket,
sap_service_connection_terminated_reason_e result, sap_service_connection_terminated_reason_e result,
void *user_data) void *user_data) {
{
switch (result) { switch (result) {
case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED: case SAP_CONNECTION_TERMINATED_REASON_PEER_DISCONNECTED:
dlog_print(DLOG_INFO, LOG_TAG, "disconnected because peer lost"); dlog_print(DLOG_INFO, LOG_TAG, "disconnected because peer lost");
@@ -92,26 +90,41 @@ static void on_data_recieved(sap_socket_h socket,
void *user_data) { void *user_data) {
dlog_print(DLOG_INFO, LOG_TAG, "received data: %p, len:%d", buffer, payload_length); dlog_print(DLOG_INFO, LOG_TAG, "received data: %p, len:%d", buffer, payload_length);
send_apdu_response(priv_data.nfc_handle, buffer, payload_length); char* string_buffer = (char*) buffer;
if (string_buffer[0] == 'a') {
install_aids(buffer + sizeof(char), payload_length - 1);
} else if (string_buffer[0] == 'd') {
send_apdu_response(priv_data.nfc_handle, buffer + sizeof(char), payload_length - 1);
}
} }
gboolean send_data(nfc_se_h nfc_handle, void *message, unsigned int message_len) { gboolean send_data(nfc_se_h nfc_handle, char* prefix, unsigned int prefix_len, void *message, unsigned int message_len) {
gboolean result; gboolean result;
priv_data.nfc_handle = nfc_handle; if (nfc_handle != NULL) {
priv_data.nfc_handle = nfc_handle;
}
void *final_message = malloc(prefix_len + message_len);
memcpy(final_message, prefix, prefix_len);
memcpy(final_message + prefix_len * sizeof(char), message, message_len);
result = sap_socket_send_secure_data(priv_data.socket, result = sap_socket_send_secure_data(priv_data.socket,
ACCESSORY_CHANNELID, message_len, message); ACCESSORY_CHANNELID, prefix_len + message_len, final_message);
if (result != SAP_RESULT_SUCCESS) { if (result != SAP_RESULT_SUCCESS) {
dlog_print(DLOG_INFO, LOG_TAG, "couldn't send sap message: %d", result); dlog_print(DLOG_INFO, LOG_TAG, "couldn't send sap message: %d", result);
} }
free(final_message);
return result; return result;
} }
gboolean request_installed_aids() {
return send_data(NULL, "a", 1, "", 0);
}
static void on_service_connection_created(sap_peer_agent_h peer_agent, static void on_service_connection_created(sap_peer_agent_h peer_agent,
sap_socket_h socket, sap_socket_h socket,
sap_service_connection_result_e result, sap_service_connection_result_e result,
void *user_data) void *user_data) {
{
switch (result) { switch (result) {
case SAP_CONNECTION_SUCCESS: case SAP_CONNECTION_SUCCESS:
dlog_print(DLOG_INFO, LOG_TAG, "peer agent connection is successful, pa :%u", peer_agent); dlog_print(DLOG_INFO, LOG_TAG, "peer agent connection is successful, pa :%u", peer_agent);
@@ -122,6 +135,8 @@ static void on_service_connection_created(sap_peer_agent_h peer_agent,
sap_socket_set_data_received_cb(socket, on_data_recieved, peer_agent); sap_socket_set_data_received_cb(socket, on_data_recieved, peer_agent);
priv_data.socket = socket; priv_data.socket = socket;
agent_connected = TRUE; agent_connected = TRUE;
request_installed_aids();
break; break;
case SAP_CONNECTION_IN_PROGRESS: case SAP_CONNECTION_IN_PROGRESS:
@@ -239,18 +254,6 @@ gboolean find_peers()
return TRUE; return TRUE;
} }
GSList* request_installed_aids() {
GSList* aid_list = g_slist_append(NULL, "A000000397425446590201");
aid_list = g_slist_append(aid_list, "A0000003974254465902");
aid_list = g_slist_append(aid_list, "A00000039742544659");
aid_list = g_slist_append(aid_list, "F276A288BCFBA69D34F31001");
aid_list = g_slist_append(aid_list, "F000000001");
aid_list = g_slist_append(aid_list, "D27600012401");
aid_list = g_slist_append(aid_list, "D2760001240102000000000000010000");
aid_list = g_slist_append(aid_list, "A000000527210101");
return aid_list;
}
static void on_agent_initialized(sap_agent_h agent, static void on_agent_initialized(sap_agent_h agent,
sap_agent_initialized_result_e result, sap_agent_initialized_result_e result,
void *user_data) void *user_data)

View File

@@ -27,7 +27,7 @@ static void hce_event_cb(nfc_se_h handle, nfc_hce_event_type_e event, unsigned c
case NFC_HCE_EVENT_APDU_RECEIVED: case NFC_HCE_EVENT_APDU_RECEIVED:
dlog_print(DLOG_DEBUG, LOG_TAG, "received NFC_HCE_EVENT_APDU_RECEIVED event on NFC handle %d", handle); dlog_print(DLOG_DEBUG, LOG_TAG, "received NFC_HCE_EVENT_APDU_RECEIVED event on NFC handle %d", handle);
if (agent_connected) { if (agent_connected) {
send_data(handle, apdu, apdu_len); send_data(handle, "d", 1, apdu, apdu_len);
} else { } else {
dlog_print(DLOG_INFO, LOG_TAG, "couldn't send message on SAP channel because agent is not connected"); dlog_print(DLOG_INFO, LOG_TAG, "couldn't send message on SAP channel because agent is not connected");
} }
@@ -39,7 +39,7 @@ static void hce_event_cb(nfc_se_h handle, nfc_hce_event_type_e event, unsigned c
} }
} }
void register_aid(gpointer data, gpointer user_data) { void register_aid(gpointer data) {
int result = nfc_se_register_aid(NFC_SE_TYPE_HCE, NFC_CARD_EMULATION_CATEGORY_OTHER, data); int result = nfc_se_register_aid(NFC_SE_TYPE_HCE, NFC_CARD_EMULATION_CATEGORY_OTHER, data);
if (result != NFC_ERROR_NONE) { if (result != NFC_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "nfc_se_register_aid for aid %s failed: %d", data, result); dlog_print(DLOG_ERROR, LOG_TAG, "nfc_se_register_aid for aid %s failed: %d", data, result);
@@ -48,9 +48,17 @@ void register_aid(gpointer data, gpointer user_data) {
} }
} }
void install_aids() { void install_aids(void *buffer, unsigned int buffer_size) {
GSList* aid_list = request_installed_aids(); gchar aid_string[buffer_size + 1];
g_slist_foreach(aid_list, register_aid, NULL); g_strlcpy(aid_string, (gchar *)buffer, buffer_size + 1);
gchar **aid_buffer = g_strsplit(aid_string, ",", 0);
int i;
int aid_len = g_strv_length(aid_buffer);
for (i = 0; i < aid_len; i++) {
register_aid((gpointer)aid_buffer[i]);
}
g_strfreev(aid_buffer);
} }
void send_apdu_response(nfc_se_h handle, unsigned char *resp, unsigned int resp_len) { void send_apdu_response(nfc_se_h handle, unsigned char *resp, unsigned int resp_len) {
@@ -98,8 +106,6 @@ bool service_app_create(void *data) {
find_peers(); find_peers();
install_aids();
r = true; r = true;
err: err: